{{-- 문서 미리보기 공통 모달 + 렌더링 함수 --}}
{{-- 사용법: @include('document-templates.partials.preview-modal') --}}
{{-- JS: buildDocumentPreviewHtml(data) 호출하여 HTML 생성 --}}

<!-- 미리보기 모달 -->
<div id="preview-modal" class="fixed inset-0 z-50 hidden overflow-y-auto">
    <div class="flex items-center justify-center min-h-screen p-4">
        <div class="fixed inset-0 bg-black bg-opacity-50" onclick="closePreviewModal()"></div>
        <div class="relative bg-white rounded-lg shadow-xl max-w-5xl w-full max-h-[90vh] overflow-hidden">
            <div class="flex justify-between items-center p-4 border-b">
                <h3 class="text-lg font-bold text-gray-800">문서 미리보기</h3>
                <button onclick="closePreviewModal()" class="text-gray-400 hover:text-gray-600">
                    <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
                    </svg>
                </button>
            </div>
            <div id="preview-content" class="p-4 overflow-auto max-h-[calc(90vh-120px)]">
                <!-- 미리보기 내용 -->
            </div>
        </div>
    </div>
</div>

@push('scripts')
<script>
    // ===== 공통 미리보기 함수 =====

    function closePreviewModal() {
        document.getElementById('preview-modal').classList.add('hidden');
    }

    // ESC로 모달 닫기
    document.addEventListener('keydown', function(e) {
        if (e.key === 'Escape') closePreviewModal();
    });

    // 이미지 URL 헬퍼 (API tenant storage vs MNG local storage)
    function _previewImageUrl(imagePath) {
        if (!imagePath) return '';
        if (imagePath.startsWith('http://') || imagePath.startsWith('https://')) return imagePath;
        // 새 API 업로드 형식 (tenant path: 1/temp/2026/02/xxx.jpg)
        if (/^\d+\//.test(imagePath)) {
            return 'http://api.sam.kr/storage/tenants/' + imagePath;
        }
        // 레거시 형식 (document-templates/xxx.jpg)
        return '/storage/' + imagePath;
    }

    // HTML 이스케이프
    function _previewEsc(text) {
        if (!text) return '';
        const div = document.createElement('div');
        div.textContent = text;
        return div.innerHTML;
    }

    // 공차 포맷팅
    function _previewFormatTolerance(tol) {
        if (!tol) return '-';
        // 문자열인 경우 (Index API 응답)
        if (typeof tol === 'string') return tol || '-';
        // 객체인 경우 (Edit templateState)
        if (!tol.type) return '-';
        switch (tol.type) {
            case 'symmetric':
                return tol.value != null ? `\u00B1${tol.value}` : '-';
            case 'asymmetric':
                return (tol.plus != null || tol.minus != null)
                    ? `+${tol.plus ?? 0} / -${tol.minus ?? 0}` : '-';
            case 'range':
                return (tol.min != null || tol.max != null)
                    ? `${tol.min ?? ''} ~ ${tol.max ?? ''}` : '-';
            case 'limit': {
                const opSymbol = { lte: '\u2264', lt: '<', gte: '\u2265', gt: '>' };
                return tol.value != null ? `${opSymbol[tol.op] || '\u2264'}${tol.value}` : '-';
            }
            default: return '-';
        }
    }

    // 검사기준 포맷팅
    function _previewFormatStandard(item) {
        const c = item.standard_criteria;
        if (c && (c.min != null || c.max != null)) {
            const opLabel = { gte: '이상', gt: '초과', lte: '이하', lt: '미만' };
            const parts = [];
            if (c.min != null) parts.push(`${c.min} ${opLabel[c.min_op || 'gte']}`);
            if (c.max != null) parts.push(`${c.max} ${opLabel[c.max_op || 'lte']}`);
            return parts.join(' ~ ');
        }
        let std = item.standard || '-';
        const tolStr = _previewFormatTolerance(item.tolerance);
        if (tolStr !== '-') std += ' (' + tolStr + ')';
        return _previewEsc(std);
    }

    // 주기 포맷팅
    function _previewFormatFrequency(item) {
        const parts = [];
        if (item.frequency_n != null && item.frequency_n !== '') {
            let nc = `n=${item.frequency_n}`;
            if (item.frequency_c != null && item.frequency_c !== '') nc += `, c=${item.frequency_c}`;
            parts.push(nc);
        }
        if (item.frequency) parts.push(_previewEsc(item.frequency));
        return parts.length > 0 ? parts.join(' / ') : '-';
    }

    /**
     * 문서 미리보기 HTML 생성 (공통)
     *
     * @param {Object} data - 미리보기 데이터
     * @param {string} data.title - 문서 제목
     * @param {string} data.company_name - 회사명
     * @param {string} data.footer_remark_label - 비고 라벨
     * @param {string} data.footer_judgement_label - 종합판정 라벨
     * @param {Array}  data.footer_judgement_options - 판정 옵션
     * @param {Array}  data.approval_lines - 결재라인 [{name, dept}]
     * @param {Array}  data.basic_fields - 기본필드 [{label, default_value}]
     * @param {Array}  data.sections - 검사 섹션 [{title, image_path, items}]
     * @param {Array}  data.columns - 테이블 컬럼
     * @param {Function} [data.methodResolver] - 검사방법 코드→이름 변환 함수 (선택)
     */
    function buildDocumentPreviewHtml(data) {
        const title = data.title || '문서 양식';
        const companyName = data.company_name || '';
        const remarkLabel = data.footer_remark_label || '비고';
        const judgementLabel = data.footer_judgement_label || '종합판정';
        const judgementOptions = (data.footer_judgement_options || []).filter(o => (o || '').trim());
        const approvalLines = data.approval_lines || [];
        const basicFields = data.basic_fields || [];
        const sections = data.sections || [];
        const columns = data.columns || [];
        const methodResolver = data.methodResolver || function(code) { return code || '-'; };

        // 결재란
        const approvalHtml = approvalLines.length === 0
            ? '<span class="text-xs text-gray-400">결재라인 미설정</span>'
            : `<table class="border-collapse text-xs">
                <tr>${approvalLines.map(l => `<td class="border border-gray-400 px-3 py-1 bg-gray-100 text-center font-medium">${_previewEsc(l.name || '-')}</td>`).join('')}</tr>
                <tr>${approvalLines.map(l => `<td class="border border-gray-400 px-3 py-1 text-center"><div class="text-gray-400 text-xs">${_previewEsc(l.dept || '')}</div><div class="h-6"></div></td>`).join('')}</tr>
               </table>`;

        // 기본필드 (15:35:15:35 비율)
        let basicHtml = '';
        if (basicFields.length > 0) {
            const rows = [];
            for (let i = 0; i < basicFields.length; i += 2) {
                const f1 = basicFields[i], f2 = basicFields[i + 1];
                rows.push(`<tr>
                    <td class="border border-gray-400 px-2 py-1.5 bg-gray-100 font-medium text-center" style="width:15%">${_previewEsc(f1.label || '-')}</td>
                    <td class="border border-gray-400 px-2 py-1.5 text-gray-400" style="width:35%">${_previewEsc(f1.default_value || '(입력)')}</td>
                    ${f2 ? `<td class="border border-gray-400 px-2 py-1.5 bg-gray-100 font-medium text-center" style="width:15%">${_previewEsc(f2.label || '-')}</td>
                    <td class="border border-gray-400 px-2 py-1.5 text-gray-400" style="width:35%">${_previewEsc(f2.default_value || '(입력)')}</td>` : '<td class="border border-gray-400 px-2 py-1.5" colspan="2"></td>'}
                </tr>`);
            }
            basicHtml = `<table class="w-full border-collapse text-xs mb-4" style="table-layout:fixed">${rows.join('')}</table>`;
        }

        // 컬럼의 실제 colspan 계산
        function _colSpan(col) {
            if (col.column_type === 'complex' && col.sub_labels && col.sub_labels.length > 0) return col.sub_labels.length;
            const label = (col.label || '').trim();
            if (label.includes('검사항목') || label.includes('항목') ||
                label.includes('검사기준') || label.includes('기준')) return 2;
            return 1;
        }

        // check 컬럼의 체크박스 라벨 추출
        function _getCheckLabels(col) {
            if (col.sub_labels && col.sub_labels.length >= 2) {
                const [a, b] = col.sub_labels.map(s => (s || '').trim());
                if (a && b && !/^n?\d+$/i.test(a)) return `☐${a} ☐${b}`;
            }
            return '☐OK ☐NG';
        }

        // 컬럼 헤더 (다단계 group_name "/" 구분자 지원)
        const renderHeaders = () => {
            if (columns.length === 0) return '';

            // 1) 각 컬럼의 group_name을 "/" 로 split → levels 배열
            const colGroups = columns.map(col => {
                const gn = (col.group_name || '').trim();
                return gn ? gn.split('/').map(s => s.trim()) : [];
            });
            // "/" 없는 단일 레벨 group_name은 그룹 행 생성 안 함 (하위 호환)
            const maxDepth = Math.max(0, ...colGroups.map(g => g.length > 1 ? g.length : 0));

            // sub_labels 존재 여부
            const hasSubLabels = columns.some(c =>
                c.column_type === 'complex' && c.sub_labels && c.sub_labels.length > 0
            );
            // check 타입 + sub_labels도 sub_labels 행에 포함
            const hasCheckSub = columns.some(c =>
                c.column_type === 'check' && c.sub_labels && c.sub_labels.length >= 2
            );
            const needSubRow = hasSubLabels; // sub_labels 행 필요 여부

            const totalHeaderRows = maxDepth + 1 + (needSubRow ? 1 : 0);
            const thClass = 'border border-gray-400 px-2 py-1.5 bg-gray-100 text-center';
            const thSubClass = 'border border-gray-400 px-1 py-1 bg-gray-100 text-center';
            let html = '';

            // 2) 그룹 행들 (depth 0 ~ maxDepth-1)
            for (let depth = 0; depth < maxDepth; depth++) {
                html += '<tr>';
                let ci = 0;
                while (ci < columns.length) {
                    const levels = colGroups[ci];
                    if (levels.length <= depth) {
                        // 이 컬럼은 이 depth에 그룹이 없음 → 이미 상위에서 rowspan 처리됨
                        ci++;
                        continue;
                    }
                    if (depth < levels.length - 1 || (depth === 0 && levels.length > 0)) {
                        // 실제로 이 depth에 그룹 라벨이 있는 경우
                        const groupLabel = levels[depth];

                        // 같은 prefix를 가진 연속 컬럼 찾기
                        const prefix = levels.slice(0, depth + 1).join('/');
                        let span = _colSpan(columns[ci]);
                        let cj = ci + 1;
                        while (cj < columns.length) {
                            const otherLevels = colGroups[cj];
                            const otherPrefix = otherLevels.slice(0, depth + 1).join('/');
                            if (otherPrefix === prefix) {
                                span += _colSpan(columns[cj]);
                                cj++;
                            } else {
                                break;
                            }
                        }

                        // 이 depth가 이 컬럼그룹의 마지막 depth인지 확인
                        // (하위 depth가 더 있으면 rowspan 불필요)
                        const allSameMaxDepth = (() => {
                            for (let k = ci; k < cj; k++) {
                                if (colGroups[k].length > depth + 1) return false;
                            }
                            return true;
                        })();

                        if (depth === levels.length - 1 && allSameMaxDepth && maxDepth > depth + 1) {
                            // 하위 그룹이 없는데 다른 컬럼에 하위 그룹 있음 → rowspan으로 확장
                            const rs = maxDepth - depth;
                            html += `<th class="${thClass}" colspan="${span}" rowspan="${rs}">${_previewEsc(groupLabel)}</th>`;
                        } else {
                            html += `<th class="${thClass}" colspan="${span}">${_previewEsc(groupLabel)}</th>`;
                        }
                        ci = cj;
                    } else {
                        ci++;
                    }
                }
                html += '</tr>';
            }

            // 그룹이 없는 컬럼(group_name = null)은 첫 번째 그룹 행에서 전체 rowspan
            // → 위 로직에서 skip 되었으므로, 첫 그룹 행에 삽입해야 함
            // 재구성: 완전한 행 빌드 방식으로 변경
            if (maxDepth > 0) {
                // 첫 번째 행을 재빌드하여 group_name=null 컬럼의 rowspan 포함
                html = ''; // 리셋
                for (let depth = 0; depth < maxDepth; depth++) {
                    html += '<tr>';
                    let ci = 0;
                    while (ci < columns.length) {
                        const levels = colGroups[ci];

                        // 그룹 없는 컬럼 또는 단일 레벨 그룹: depth=0에서만 rowspan으로 렌더
                        if (levels.length <= 1) {
                            if (depth === 0) {
                                const cs = _colSpan(columns[ci]);
                                const rs = totalHeaderRows;
                                html += `<th class="${thClass}" ${cs > 1 ? `colspan="${cs}"` : ''} rowspan="${rs}" style="width:${columns[ci].width || '80px'}">${_previewEsc(columns[ci].label)}</th>`;
                            }
                            ci++;
                            continue;
                        }

                        // 이 컬럼의 그룹 depth가 현재 depth보다 작음 → 이미 상위에서 처리됨
                        if (levels.length <= depth) {
                            ci++;
                            continue;
                        }

                        // 같은 prefix 연속 컬럼 모으기
                        const prefix = levels.slice(0, depth + 1).join('/');
                        let span = _colSpan(columns[ci]);
                        let cj = ci + 1;
                        while (cj < columns.length) {
                            const otherLevels = colGroups[cj];
                            if (otherLevels.length > depth) {
                                const otherPrefix = otherLevels.slice(0, depth + 1).join('/');
                                if (otherPrefix === prefix) {
                                    span += _colSpan(columns[cj]);
                                    cj++;
                                    continue;
                                }
                            }
                            break;
                        }

                        // 이 depth에서 이미 렌더된 prefix인지 확인 (중복 방지)
                        const firstInPrefix = (() => {
                            for (let k = 0; k < ci; k++) {
                                const kLevels = colGroups[k];
                                if (kLevels.length > depth && kLevels.slice(0, depth + 1).join('/') === prefix) return false;
                            }
                            return true;
                        })();

                        if (!firstInPrefix) {
                            ci++;
                            continue;
                        }

                        const groupLabel = levels[depth];

                        // 하위 그룹이 더 있는지 확인
                        const hasDeeper = (() => {
                            for (let k = ci; k < cj; k++) {
                                if (colGroups[k].length > depth + 1) return true;
                            }
                            return false;
                        })();

                        if (!hasDeeper && depth < maxDepth - 1) {
                            // 이 그룹은 여기서 끝나지만 다른 그룹은 더 깊음 → rowspan
                            const rs = maxDepth - depth;
                            html += `<th class="${thClass}" colspan="${span}" rowspan="${rs}">${_previewEsc(groupLabel)}</th>`;
                        } else {
                            html += `<th class="${thClass}" colspan="${span}">${_previewEsc(groupLabel)}</th>`;
                        }
                        ci = cj;
                    }
                    html += '</tr>';
                }
            }

            // 3) 컬럼 라벨 행
            html += '<tr>';
            columns.forEach(col => {
                const levels = colGroups[columns.indexOf(col)];
                // 그룹 없는 컬럼 또는 단일 레벨 그룹은 이미 rowspan으로 처리됨 → skip
                if (maxDepth > 0 && levels.length <= 1) return;

                const cs = _colSpan(col);
                if (needSubRow && (col.column_type === 'complex' && col.sub_labels && col.sub_labels.length > 0)) {
                    // complex: colspan만, rowspan 없음 (다음 행에 sub_labels)
                    html += `<th class="${thClass}" colspan="${cs}">${_previewEsc(col.label)}</th>`;
                } else if (needSubRow) {
                    // sub_labels 행이 있지만 이 컬럼은 sub_labels 없음 → rowspan=2
                    html += `<th class="${thClass}" ${cs > 1 ? `colspan="${cs}"` : ''} rowspan="2" style="width:${col.width || '80px'}">${_previewEsc(col.label)}</th>`;
                } else {
                    html += `<th class="${thClass}" ${cs > 1 ? `colspan="${cs}"` : ''} style="width:${col.width || '80px'}">${_previewEsc(col.label)}</th>`;
                }
            });
            html += '</tr>';

            // 4) sub_labels 행 (필요시)
            if (needSubRow) {
                html += '<tr>';
                columns.forEach(col => {
                    if (col.column_type === 'complex' && col.sub_labels && col.sub_labels.length > 0) {
                        col.sub_labels.forEach(sl => {
                            const slName = (sl || '').trim();
                            const isBasis = slName.includes('도면') || slName.includes('기준');
                            const bgClass = isBasis ? ' background:#f3f4f6;' : '';
                            html += `<th class="${thSubClass}" style="width:40px;font-size:10px;${bgClass}">${_previewEsc(slName)}</th>`;
                        });
                    }
                    // check 타입이나 다른 컬럼은 sub_labels 행에서 skip (rowspan으로 처리됨)
                });
                html += '</tr>';
            }

            return html;
        };

        // 측정치 셀 (sub_label 이름 기반 의미 구분)
        const mCell = (col, mType, frequencyN) => {
            const total = _colSpan(col);
            if (mType === 'single_value') return `<td class="border border-gray-400 px-1 py-1.5 text-center" colspan="${total}"><span style="color:#ccc;font-size:10px">( 입력 )</span></td>`;
            if (mType === 'substitute') return `<td class="border border-gray-400 px-1 py-1.5 text-center text-gray-500" colspan="${total}" style="font-size:10px">성적서로 대체</td>`;

            if (col.column_type === 'check') {
                const checkLabel = _getCheckLabels(col);
                return `<td class="border border-gray-400 px-1 py-1.5 text-center"><span style="font-size:11px">${checkLabel}</span></td>`;
            }

            if (col.sub_labels && col.sub_labels.length > 0) {
                if (mType === 'checkbox') {
                    // complex 컬럼은 기본 OK/NG, check 컬럼만 커스텀 라벨
                    const checkText = col.column_type === 'check' ? _getCheckLabels(col) : '☐OK ☐NG';
                    return col.sub_labels.map(() => `<td class="border border-gray-400 px-1 py-1.5 text-center"><span style="font-size:11px">${checkText}</span></td>`).join('');
                }
                return col.sub_labels.map(sl => {
                    const slName = (sl || '').trim().toLowerCase();
                    if (slName.includes('도면') || slName.includes('기준')) {
                        return '<td class="border border-gray-400 px-1 py-1.5 text-center" style="background:#f0f4f8"><span style="color:#6b7280;font-size:10px">(기준값)</span></td>';
                    }
                    if (slName.includes('point') || slName.includes('포인트')) {
                        return '<td class="border border-gray-400 px-1 py-1.5 text-center"><span style="color:#9ca3af;font-size:10px;font-style:italic">(n)</span></td>';
                    }
                    // 측정값 등 입력 셀
                    return '<td class="border border-gray-400 px-1 py-1.5 text-center"><span style="color:#9ca3af;font-size:10px">[입력]</span></td>';
                }).join('');
            }

            return Array(total).fill('').map(() => '<td class="border border-gray-400 px-1 py-1.5 text-center text-gray-300">-</td>').join('');
        };

        // 검사항목 행
        const renderRows = () => {
            const allItems = [];
            sections.forEach(s => (s.items || []).forEach(item => allItems.push(item)));
            if (allItems.length === 0) {
                const cs = columns.reduce((sum, c) => sum + _colSpan(c), 0) || 1;
                return `<tr><td colspan="${cs}" class="text-center py-4 text-gray-400 border border-gray-400">검사항목이 없습니다.</td></tr>`;
            }

            // 카테고리별 그룹핑
            const groups = [];
            let i = 0;
            while (i < allItems.length) {
                const item = allItems[i], cat = (item.category || '').trim();
                if (cat) {
                    const g = [item];
                    while (i + 1 < allItems.length && (allItems[i + 1].category || '').trim() === cat) { i++; g.push(allItems[i]); }
                    groups.push({ type: 'group', category: cat, items: g });
                } else {
                    groups.push({ type: 'single', item });
                }
                i++;
            }

            let rowNum = 0;
            return groups.map(row => {
                rowNum++;
                if (row.type === 'single') {
                    const item = row.item;
                    return '<tr>' + columns.map(col => {
                        if ((col.column_type === 'complex' || col.column_type === 'check') && col.sub_labels && col.sub_labels.length > 0) return mCell(col, item.measurement_type || col.column_type, item.frequency_n);
                        const label = (col.label || '').trim();
                        if (label === 'NO' || label === 'no') return `<td class="border border-gray-400 px-2 py-1.5 text-center">${rowNum}</td>`;
                        if (label.includes('검사항목') || label.includes('항목')) return `<td class="border border-gray-400 px-2 py-1.5 text-center" colspan="2">${_previewEsc(item.item || '-')}</td>`;
                        if (label.includes('검사기준') || label.includes('기준')) return `<td class="border border-gray-400 px-2 py-1.5 text-center" colspan="2">${_previewFormatStandard(item)}</td>`;
                        if (label.includes('검사방')) return `<td class="border border-gray-400 px-2 py-1.5 text-center">${_previewEsc(methodResolver(item.method))}</td>`;
                        if (label.includes('주기')) return `<td class="border border-gray-400 px-2 py-1.5 text-center">${_previewFormatFrequency(item)}</td>`;
                        if (label.includes('판정')) return '<td class="border border-gray-400 px-2 py-1.5 text-center">☐</td>';
                        if (col.column_type === 'check') return `<td class="border border-gray-400 px-1 py-1.5 text-center"><span style="font-size:11px">${_getCheckLabels(col)}</span></td>`;
                        return '<td class="border border-gray-400 px-2 py-1.5 text-center">-</td>';
                    }).join('') + '</tr>';
                }

                // 그룹 항목
                const n = row.items.length;
                return row.items.map((item, idx) => {
                    return '<tr>' + columns.map(col => {
                        if ((col.column_type === 'complex' || col.column_type === 'check') && col.sub_labels && col.sub_labels.length > 0) return mCell(col, item.measurement_type || col.column_type, item.frequency_n);
                        const label = (col.label || '').trim();
                        const rs = idx === 0 ? ` rowspan="${n}"` : '';
                        if (label === 'NO' || label === 'no') return idx === 0 ? `<td class="border border-gray-400 px-2 py-1.5 text-center"${rs}>${rowNum}</td>` : '';
                        if (label.includes('검사항목') || label.includes('항목')) {
                            let catCell = idx === 0 ? `<td class="border border-gray-400 px-2 py-1.5 text-center font-medium"${rs}>${_previewEsc(row.category)}</td>` : '';
                            return catCell + `<td class="border border-gray-400 px-2 py-1.5 text-center">${_previewEsc(item.item || '-')}</td>`;
                        }
                        if (label.includes('검사기준') || label.includes('기준')) return `<td class="border border-gray-400 px-2 py-1.5 text-center">${_previewFormatStandard(item)}</td><td class="border border-gray-400 px-2 py-1.5 text-center">${_previewEsc(_previewFormatTolerance(item.tolerance))}</td>`;
                        if (label.includes('검사방')) return `<td class="border border-gray-400 px-2 py-1.5 text-center">${_previewEsc(methodResolver(item.method))}</td>`;
                        if (label.includes('주기')) return `<td class="border border-gray-400 px-2 py-1.5 text-center">${_previewFormatFrequency(item)}</td>`;
                        if (label.includes('판정')) return '<td class="border border-gray-400 px-2 py-1.5 text-center">☐</td>';
                        if (col.column_type === 'check') return `<td class="border border-gray-400 px-1 py-1.5 text-center"><span style="font-size:11px">${_getCheckLabels(col)}</span></td>`;
                        return '<td class="border border-gray-400 px-2 py-1.5 text-center">-</td>';
                    }).join('') + '</tr>';
                }).join('');
            }).join('');
        };

        // 섹션을 이미지 섹션(items 없음)과 데이터 섹션(items 있음)으로 분리
        const imageSections = sections.filter(s => (s.items || []).length === 0);
        const dataSections = sections.filter(s => (s.items || []).length > 0);

        // 이미지 섹션: ■ 타이틀 + 이미지 또는 플레이스홀더
        const imageSectionsHtml = imageSections.map(s => `
            <div class="mb-3">
                <p class="text-sm font-bold mb-1">■ ${_previewEsc(s.title)}</p>
                ${s.image_path
                    ? `<img src="${_previewImageUrl(s.image_path)}" alt="${_previewEsc(s.title)}" class="max-h-48 mx-auto border rounded">`
                    : `<div class="border border-dashed border-gray-300 rounded p-6 text-center text-gray-400 text-xs">이미지 미등록 (편집에서 업로드)</div>`
                }
            </div>
        `).join('');

        // 데이터 섹션 타이틀
        const dataSectionTitle = dataSections.length > 0
            ? `<p class="text-sm font-bold mb-1 mt-3">■ ${_previewEsc(dataSections[0].title)}</p>`
            : '';

        return `
            <div class="bg-white p-6" style="font-family: 'Malgun Gothic', sans-serif; font-size: 12px; max-width: 900px; margin: 0 auto;">
                <div class="flex justify-between items-start mb-4">
                    <div class="text-center" style="width: 80px;">
                        <div class="text-2xl font-bold">KD</div>
                        <div class="text-xs">${_previewEsc(companyName)}</div>
                    </div>
                    <div class="flex-1 text-center">
                        <h1 class="text-xl font-bold tracking-widest">${_previewEsc(title)}</h1>
                    </div>
                    <div>${approvalHtml}</div>
                </div>
                ${basicHtml}
                ${imageSectionsHtml}
                ${columns.length > 0 ? `
                    ${dataSectionTitle}
                    <table class="w-full border-collapse text-xs">
                        <thead>${renderHeaders()}</thead>
                        <tbody>${renderRows()}</tbody>
                    </table>
                ` : '<p class="text-xs text-gray-400 text-center py-4">테이블 컬럼이 설정되지 않았습니다.</p>'}
                <div class="mt-4 flex gap-4">
                    <div class="flex-1">
                        <table class="w-full border-collapse text-xs">
                            <tr>
                                <td class="border border-gray-400 px-3 py-2 bg-gray-100 font-medium" style="width:100px">${_previewEsc(remarkLabel)}</td>
                                <td class="border border-gray-400 px-3 py-2 text-gray-400">(내용 입력)</td>
                            </tr>
                        </table>
                    </div>
                    <div>
                        <table class="border-collapse text-xs">
                            <tr><td class="border border-gray-400 px-4 py-2 bg-gray-100 font-medium">${_previewEsc(judgementLabel)}</td></tr>
                            <tr><td class="border border-gray-400 px-4 py-3 text-center">
                                ${judgementOptions.length > 0 ? judgementOptions.map(o => `<span class="inline-block mx-1 px-2 py-0.5 border border-gray-300 rounded text-gray-500">${_previewEsc(o)}</span>`).join('') : '<span class="text-gray-400">옵션 미설정</span>'}
                            </td></tr>
                        </table>
                    </div>
                </div>
            </div>
        `;
    }
</script>
@endpush