@roottale/cms-renderer-next 0.47.0 → 0.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/dist/blog-filter-BKCGM0qd.d.ts +29 -0
  3. package/dist/{chunk-6MFHA555.js → chunk-27RT6B3O.js} +1 -1
  4. package/dist/chunk-27RT6B3O.js.map +1 -0
  5. package/dist/chunk-2QU4JU46.js +3927 -0
  6. package/dist/chunk-2QU4JU46.js.map +1 -0
  7. package/dist/chunk-4RQ3SEDL.js +106 -0
  8. package/dist/chunk-4RQ3SEDL.js.map +1 -0
  9. package/dist/{chunk-OMXEU4LS.js → chunk-QYNEOFL7.js} +140 -136
  10. package/dist/chunk-QYNEOFL7.js.map +1 -0
  11. package/dist/{chunk-FUA5H6JE.js → chunk-U2IM6OCQ.js} +46 -2
  12. package/dist/chunk-U2IM6OCQ.js.map +1 -0
  13. package/dist/cms-public.css +137 -18
  14. package/dist/concerns-client.d.ts +1 -1
  15. package/dist/expertise-client.d.ts +1 -1
  16. package/dist/expertise-client.js +1 -1
  17. package/dist/hero-carousel-client.js +1 -1
  18. package/dist/routes.d.ts +377 -21
  19. package/dist/routes.js +273 -106
  20. package/dist/routes.js.map +1 -1
  21. package/dist/seo-asset-hosts.d.ts +36 -0
  22. package/dist/seo-asset-hosts.js +391 -0
  23. package/dist/seo-asset-hosts.js.map +1 -0
  24. package/dist/server.d.ts +34 -216
  25. package/dist/server.js +7 -7
  26. package/dist/{site-config-Dicv57oY.d.ts → site-config-DNpvlqA5.d.ts} +201 -201
  27. package/dist/spaces-client.d.ts +1 -1
  28. package/dist/team-expanding-stage-client.d.ts +1 -1
  29. package/dist/team-expanding-stage-client.js +1 -1
  30. package/dist/templates.d.ts +64 -25
  31. package/dist/templates.js +14 -7
  32. package/dist/templates.js.map +1 -1
  33. package/package.json +7 -2
  34. package/dist/chunk-6MFHA555.js.map +0 -1
  35. package/dist/chunk-FUA5H6JE.js.map +0 -1
  36. package/dist/chunk-FZK3EXYZ.js +0 -103
  37. package/dist/chunk-FZK3EXYZ.js.map +0 -1
  38. package/dist/chunk-OMXEU4LS.js.map +0 -1
  39. package/dist/chunk-ZHXYCABN.js +0 -3584
  40. package/dist/chunk-ZHXYCABN.js.map +0 -1
@@ -0,0 +1,3927 @@
1
+ import {
2
+ LeadFormMeta
3
+ } from "./chunk-VG6UUF4D.js";
4
+ import {
5
+ HeroCarouselViewport
6
+ } from "./chunk-QYNEOFL7.js";
7
+ import {
8
+ BeforeAfterSlider
9
+ } from "./chunk-U5AKACPN.js";
10
+ import {
11
+ ContactMapClickToLoad
12
+ } from "./chunk-LEHHSI6G.js";
13
+ import {
14
+ ExpertiseTabStage
15
+ } from "./chunk-27RT6B3O.js";
16
+ import {
17
+ TeamExpandingStageClient
18
+ } from "./chunk-4RQ3SEDL.js";
19
+ import {
20
+ SpacesStage
21
+ } from "./chunk-K62RR4UQ.js";
22
+ import {
23
+ ConcernsFigureMap
24
+ } from "./chunk-H46JUIHZ.js";
25
+ import {
26
+ AnimateOnScroll,
27
+ CountUpStat,
28
+ Marquee,
29
+ StaggerGroup,
30
+ StaggerItem
31
+ } from "./chunk-ZL2NA3QT.js";
32
+ import {
33
+ collectCategories,
34
+ collectCategoriesWithCounts,
35
+ collectCollectionCategories,
36
+ defaultCategoryHref,
37
+ filterPostsByCategory,
38
+ trimSlash
39
+ } from "./chunk-U2IM6OCQ.js";
40
+ import {
41
+ SectionSchema
42
+ } from "./chunk-UM37DOIK.js";
43
+
44
+ // src/PostCard.tsx
45
+ import { jsx, jsxs } from "react/jsx-runtime";
46
+ function firstCategoryName(terms) {
47
+ if (!terms) return null;
48
+ const cat = terms.find((t2) => t2.taxonomy === "category");
49
+ return cat ? cat.name : null;
50
+ }
51
+ function RootTalePostCard(props) {
52
+ const { post, href = defaultHref, display } = props;
53
+ const showDate = display ? display.showDate : true;
54
+ const showAuthor = display ? display.showAuthor : false;
55
+ const showImage = display?.showImage !== false;
56
+ const showCategory = display?.showCategory !== false;
57
+ const authorName = post.authorName;
58
+ const publishedDate = showDate ? formatPublishedDate(post.publishedAt) : "";
59
+ const views = typeof post.viewCount === "number" ? post.viewCount : null;
60
+ const imageUrl = showImage ? post.featuredImageUrl : null;
61
+ const category = showCategory ? firstCategoryName(post.terms) : null;
62
+ return /* @__PURE__ */ jsx("article", { "data-roottale-cms": "card", className: "rt-cms-card", children: /* @__PURE__ */ jsxs("a", { className: "rt-cms-card-link", href: href(post), children: [
63
+ imageUrl ? /* @__PURE__ */ jsx(
64
+ "img",
65
+ {
66
+ className: "rt-cms-card-image",
67
+ src: imageUrl,
68
+ alt: "",
69
+ loading: "lazy",
70
+ decoding: "async"
71
+ }
72
+ ) : null,
73
+ category ? /* @__PURE__ */ jsx("span", { className: "rt-cms-card-category", children: category }) : null,
74
+ publishedDate || showAuthor && authorName || views !== null ? /* @__PURE__ */ jsxs("p", { className: "rt-cms-meta", children: [
75
+ publishedDate ? /* @__PURE__ */ jsx("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "date", children: publishedDate }) : null,
76
+ showAuthor && authorName ? /* @__PURE__ */ jsxs("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "author", children: [
77
+ "\uC791\uC131\uC790 ",
78
+ authorName
79
+ ] }) : null,
80
+ views !== null ? /* @__PURE__ */ jsxs("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "views", children: [
81
+ "\uC870\uD68C ",
82
+ views.toLocaleString("ko-KR")
83
+ ] }) : null
84
+ ] }) : null,
85
+ /* @__PURE__ */ jsx("h2", { className: "rt-cms-title", children: post.title }),
86
+ post.excerpt ? /* @__PURE__ */ jsx("p", { className: "rt-cms-excerpt", children: post.excerpt }) : null,
87
+ /* @__PURE__ */ jsx("span", { className: "rt-cms-card-action", "aria-hidden": "true", children: "\uC77D\uAE30" })
88
+ ] }) });
89
+ }
90
+ function defaultHref(post) {
91
+ return `/blog/${post.slug}`;
92
+ }
93
+ function formatPublishedDate(iso) {
94
+ const d = new Date(iso);
95
+ if (Number.isNaN(d.getTime())) return "";
96
+ return new Intl.DateTimeFormat("ko-KR", {
97
+ year: "numeric",
98
+ month: "2-digit",
99
+ day: "2-digit"
100
+ }).format(d);
101
+ }
102
+
103
+ // ../cms-i18n/src/index.ts
104
+ var DICTS = {
105
+ ko: {
106
+ blogListEmpty: "\uC544\uC9C1 \uBC1C\uD589\uB41C \uAE00\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.",
107
+ blogCategoriesEmpty: "\uC544\uC9C1 \uCE74\uD14C\uACE0\uB9AC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
108
+ allCategoriesLabel: "\uC804\uCCB4",
109
+ relatedPostsTitle: "\uAD00\uB828 \uAE00",
110
+ postNotFound: "\uAE00\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
111
+ pageNotFound: "\uD398\uC774\uC9C0\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
112
+ tableOfContentsTitle: "\uBAA9\uCC28"
113
+ },
114
+ en: {
115
+ blogListEmpty: "No posts published yet.",
116
+ blogCategoriesEmpty: "No categories yet.",
117
+ allCategoriesLabel: "All",
118
+ relatedPostsTitle: "Related posts",
119
+ postNotFound: "Post not found.",
120
+ pageNotFound: "Page not found.",
121
+ tableOfContentsTitle: "Table of contents"
122
+ }
123
+ };
124
+ function resolveLocale(locale) {
125
+ return locale === "en" ? "en" : "ko";
126
+ }
127
+ function t(locale, key) {
128
+ return DICTS[resolveLocale(locale)][key];
129
+ }
130
+
131
+ // src/TableOfContents.tsx
132
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
133
+ function RootTaleTableOfContents(props) {
134
+ const { entries, locale, title = t(locale, "tableOfContentsTitle") } = props;
135
+ if (entries.length === 0) return null;
136
+ return /* @__PURE__ */ jsx2("nav", { "data-roottale-cms": "toc", className: "rt-cms-toc", "aria-label": title, children: /* @__PURE__ */ jsxs2("details", { className: "rt-cms-toc-details", open: true, children: [
137
+ /* @__PURE__ */ jsxs2("summary", { className: "rt-cms-toc-summary", children: [
138
+ title ? /* @__PURE__ */ jsx2("span", { className: "rt-cms-toc-title", children: title }) : null,
139
+ /* @__PURE__ */ jsx2("span", { className: "rt-cms-toc-toggle", "aria-hidden": "true" })
140
+ ] }),
141
+ /* @__PURE__ */ jsx2("ol", { className: "rt-cms-toc-list", children: entries.map((entry) => /* @__PURE__ */ jsx2(
142
+ "li",
143
+ {
144
+ className: `rt-cms-toc-item rt-cms-toc-level-${entry.level}`,
145
+ children: /* @__PURE__ */ jsx2("a", { href: `#${entry.id}`, children: entry.text })
146
+ },
147
+ entry.id
148
+ )) })
149
+ ] }) });
150
+ }
151
+
152
+ // ../ui-react/dist/theme/index.js
153
+ import { jsx as _jsx } from "react/jsx-runtime";
154
+ function themeToCssVars(theme) {
155
+ return {
156
+ ...theme.colors?.primary ? { "--rt-color-primary": theme.colors.primary } : {},
157
+ ...theme.colors?.primaryForeground ? { "--rt-color-primary-foreground": theme.colors.primaryForeground } : {},
158
+ ...theme.colors?.secondary ? { "--rt-color-secondary": theme.colors.secondary } : {},
159
+ ...theme.colors?.secondaryForeground ? { "--rt-color-secondary-foreground": theme.colors.secondaryForeground } : {},
160
+ ...theme.colors?.accent ? { "--rt-color-accent": theme.colors.accent } : {},
161
+ ...theme.colors?.accentForeground ? { "--rt-color-accent-foreground": theme.colors.accentForeground } : {},
162
+ ...theme.colors?.background ? { "--rt-color-background": theme.colors.background } : {},
163
+ ...theme.colors?.foreground ? { "--rt-color-foreground": theme.colors.foreground } : {},
164
+ ...theme.colors?.muted ? { "--rt-color-muted": theme.colors.muted } : {},
165
+ ...theme.colors?.mutedForeground ? { "--rt-color-muted-foreground": theme.colors.mutedForeground } : {},
166
+ ...theme.colors?.destructive ? { "--rt-color-destructive": theme.colors.destructive } : {},
167
+ ...theme.colors?.destructiveForeground ? { "--rt-color-destructive-foreground": theme.colors.destructiveForeground } : {},
168
+ ...theme.colors?.border ? { "--rt-color-border": theme.colors.border } : {},
169
+ ...theme.colors?.input ? { "--rt-color-input": theme.colors.input } : {},
170
+ ...theme.colors?.ring ? { "--rt-color-ring": theme.colors.ring } : {},
171
+ ...theme.fonts?.body ? { "--rt-font-body": theme.fonts.body } : {},
172
+ ...theme.fonts?.display ? { "--rt-font-display": theme.fonts.display } : {},
173
+ ...theme.radius?.sm ? { "--rt-radius-sm": theme.radius.sm } : {},
174
+ ...theme.radius?.md ? { "--rt-radius-md": theme.radius.md } : {},
175
+ ...theme.radius?.lg ? { "--rt-radius-lg": theme.radius.lg } : {},
176
+ ...theme.radius?.xl ? { "--rt-radius-xl": theme.radius.xl } : {}
177
+ };
178
+ }
179
+
180
+ // src/theme-css-vars.ts
181
+ function themeToCssVars2(theme) {
182
+ if (!theme) return null;
183
+ const vars = themeToCssVars(theme);
184
+ if (Object.keys(vars).length === 0) return null;
185
+ return vars;
186
+ }
187
+
188
+ // src/FloatingCta.tsx
189
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
190
+ function RootTaleFloatingCta(props) {
191
+ const { buttons, position = "bottom-right" } = props;
192
+ if (!buttons || buttons.length === 0) return null;
193
+ return /* @__PURE__ */ jsx3(
194
+ "div",
195
+ {
196
+ "data-roottale-cms": "floating-cta",
197
+ className: `rt-cms-floating-cta rt-cms-floating-cta--${position}`,
198
+ children: buttons.map((btn, idx) => {
199
+ const isExternal = btn.type === "kakao" || btn.type === "custom";
200
+ return /* @__PURE__ */ jsxs3(
201
+ "a",
202
+ {
203
+ href: btn.href,
204
+ className: `rt-cms-floating-cta__btn rt-cms-floating-cta__btn--${btn.type}`,
205
+ target: isExternal ? "_blank" : void 0,
206
+ rel: isExternal ? "noopener noreferrer" : void 0,
207
+ children: [
208
+ /* @__PURE__ */ jsx3("span", { "aria-hidden": "true", className: "rt-cms-floating-cta__icon", children: btn.icon ?? defaultIcon(btn.type) }),
209
+ /* @__PURE__ */ jsx3("span", { className: "rt-cms-floating-cta__label", children: btn.label })
210
+ ]
211
+ },
212
+ `${btn.type}-${idx}`
213
+ );
214
+ })
215
+ }
216
+ );
217
+ }
218
+ function defaultIcon(type) {
219
+ switch (type) {
220
+ case "phone":
221
+ return "\u260E";
222
+ case "contact":
223
+ return "\u2709";
224
+ case "kakao":
225
+ return "\u{1F4AC}";
226
+ case "custom":
227
+ return "\u2192";
228
+ }
229
+ }
230
+
231
+ // src/LeadForm.tsx
232
+ import { Fragment, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
233
+ var VERTICAL_LABEL = {
234
+ consulting: "\uCEE8\uC124\uD305",
235
+ medical: "\uC758\uB8CC",
236
+ tax: "\uC138\uBB34",
237
+ legal: "\uBC95\uB960"
238
+ };
239
+ var VERTICAL_OPTIONS = [
240
+ { value: "consulting", label: "\uCEE8\uC124\uD305 / \uC77C\uBC18" },
241
+ { value: "medical", label: "\uC758\uB8CC (\uBCD1\uC758\uC6D0\xB7\uCE58\uACFC\xB7\uD55C\uC758\uC6D0)" },
242
+ { value: "tax", label: "\uC138\uBB34 (\uC138\uBB34\uC0AC\xB7\uD68C\uACC4\uC0AC)" },
243
+ { value: "legal", label: "\uBC95\uB960 (\uBC95\uBB34\uBC95\uC778\xB7\uBCC0\uD638\uC0AC)" }
244
+ ];
245
+ function RootTaleLeadForm(props) {
246
+ const {
247
+ action,
248
+ vertical,
249
+ redirectUrl,
250
+ heading,
251
+ description,
252
+ submitLabel = "\uC9C4\uB2E8 \uC2E0\uCCAD",
253
+ turnstileSiteKey,
254
+ className
255
+ } = props;
256
+ const formClass = ["rt-cms-lead-form", className].filter(Boolean).join(" ");
257
+ const isMedical = vertical === "medical";
258
+ return /* @__PURE__ */ jsxs4(
259
+ "form",
260
+ {
261
+ method: "post",
262
+ action,
263
+ "data-roottale-cms": "lead-form",
264
+ className: formClass,
265
+ children: [
266
+ /* @__PURE__ */ jsx4(LeadFormMeta, { formId: "contact" }),
267
+ heading ? /* @__PURE__ */ jsx4("h2", { className: "rt-cms-lead-heading", children: heading }) : null,
268
+ description ? /* @__PURE__ */ jsx4("p", { className: "rt-cms-lead-description", children: description }) : null,
269
+ redirectUrl ? /* @__PURE__ */ jsx4("input", { type: "hidden", name: "_redirect_url", value: redirectUrl }) : null,
270
+ vertical ? /* @__PURE__ */ jsxs4(Fragment, { children: [
271
+ /* @__PURE__ */ jsx4("input", { type: "hidden", name: "vertical", value: vertical }),
272
+ /* @__PURE__ */ jsxs4("p", { className: "rt-cms-lead-vertical-label", children: [
273
+ "\uBD84\uC57C: ",
274
+ /* @__PURE__ */ jsx4("strong", { children: VERTICAL_LABEL[vertical] })
275
+ ] })
276
+ ] }) : /* @__PURE__ */ jsxs4("label", { className: "rt-cms-field", children: [
277
+ /* @__PURE__ */ jsxs4("span", { className: "rt-cms-field-label", children: [
278
+ "\uBD84\uC57C ",
279
+ /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", children: "*" })
280
+ ] }),
281
+ /* @__PURE__ */ jsxs4(
282
+ "select",
283
+ {
284
+ name: "vertical",
285
+ required: true,
286
+ className: "rt-cms-field-input rt-cms-field-select",
287
+ defaultValue: "",
288
+ children: [
289
+ /* @__PURE__ */ jsx4("option", { value: "", disabled: true, children: "\uC120\uD0DD\uD558\uC138\uC694" }),
290
+ VERTICAL_OPTIONS.map((opt) => /* @__PURE__ */ jsx4("option", { value: opt.value, children: opt.label }, opt.value))
291
+ ]
292
+ }
293
+ )
294
+ ] }),
295
+ /* @__PURE__ */ jsxs4("label", { className: "rt-cms-field", children: [
296
+ /* @__PURE__ */ jsxs4("span", { className: "rt-cms-field-label", children: [
297
+ "\uC774\uB984 ",
298
+ /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", children: "*" })
299
+ ] }),
300
+ /* @__PURE__ */ jsx4(
301
+ "input",
302
+ {
303
+ type: "text",
304
+ name: "contact_name",
305
+ required: true,
306
+ autoComplete: "name",
307
+ className: "rt-cms-field-input"
308
+ }
309
+ )
310
+ ] }),
311
+ isMedical ? (
312
+ // 환자 문의에는 "사업체명" 개념이 없다 — 화면에는 노출하지 않되,
313
+ // intake 가 vertical 불문 hard-required 로 검증하는 계약(위 파일
314
+ // 헤더 코멘트 참조)을 만족시키기 위해 자리표시자만 hidden 전송.
315
+ /* @__PURE__ */ jsx4("input", { type: "hidden", name: "business_name", value: "-" })
316
+ ) : /* @__PURE__ */ jsxs4("label", { className: "rt-cms-field", children: [
317
+ /* @__PURE__ */ jsxs4("span", { className: "rt-cms-field-label", children: [
318
+ "\uC0AC\uC5C5\uCCB4\uBA85 ",
319
+ /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", children: "*" })
320
+ ] }),
321
+ /* @__PURE__ */ jsx4(
322
+ "input",
323
+ {
324
+ type: "text",
325
+ name: "business_name",
326
+ required: true,
327
+ autoComplete: "organization",
328
+ className: "rt-cms-field-input"
329
+ }
330
+ )
331
+ ] }),
332
+ /* @__PURE__ */ jsxs4("label", { className: "rt-cms-field", children: [
333
+ /* @__PURE__ */ jsxs4("span", { className: "rt-cms-field-label", children: [
334
+ "\uC804\uD654\uBC88\uD638 ",
335
+ /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", children: "*" })
336
+ ] }),
337
+ /* @__PURE__ */ jsx4(
338
+ "input",
339
+ {
340
+ type: "tel",
341
+ name: "phone",
342
+ required: true,
343
+ autoComplete: "tel",
344
+ inputMode: "tel",
345
+ pattern: "0\\d{1,2}-?\\d{3,4}-?\\d{4}",
346
+ placeholder: "010-1234-5678",
347
+ className: "rt-cms-field-input"
348
+ }
349
+ )
350
+ ] }),
351
+ /* @__PURE__ */ jsxs4("label", { className: "rt-cms-field", children: [
352
+ /* @__PURE__ */ jsxs4("span", { className: "rt-cms-field-label", children: [
353
+ "\uC774\uBA54\uC77C ",
354
+ /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", children: "*" })
355
+ ] }),
356
+ /* @__PURE__ */ jsx4(
357
+ "input",
358
+ {
359
+ type: "email",
360
+ name: "email",
361
+ required: true,
362
+ autoComplete: "email",
363
+ className: "rt-cms-field-input"
364
+ }
365
+ )
366
+ ] }),
367
+ isMedical ? /* @__PURE__ */ jsxs4(Fragment, { children: [
368
+ /* @__PURE__ */ jsxs4("label", { className: "rt-cms-field", children: [
369
+ /* @__PURE__ */ jsx4("span", { className: "rt-cms-field-label", children: "\uC0C1\uB2F4 \uD76C\uB9DD \uBD84\uC57C\xB7\uC99D\uC0C1 (\uC120\uD0DD)" }),
370
+ /* @__PURE__ */ jsx4(
371
+ "input",
372
+ {
373
+ type: "text",
374
+ name: "consultation_field",
375
+ placeholder: "\uC608: \uBB34\uB98E \uD1B5\uC99D, \uC815\uAE30\uAC80\uC9C4",
376
+ className: "rt-cms-field-input"
377
+ }
378
+ )
379
+ ] }),
380
+ /* @__PURE__ */ jsxs4("label", { className: "rt-cms-field", children: [
381
+ /* @__PURE__ */ jsx4("span", { className: "rt-cms-field-label", children: "\uBB38\uC758 \uB0B4\uC6A9 (\uC120\uD0DD)" }),
382
+ /* @__PURE__ */ jsx4(
383
+ "textarea",
384
+ {
385
+ name: "message",
386
+ rows: 4,
387
+ placeholder: "\uC99D\uC0C1\uC774 \uC5B8\uC81C\uBD80\uD130 \uC788\uC5C8\uB294\uC9C0, \uAD81\uAE08\uD558\uC2E0 \uC810\uC744 \uC790\uC720\uB86D\uAC8C \uC801\uC5B4\uC8FC\uC138\uC694.",
388
+ className: "rt-cms-field-input rt-cms-field-textarea"
389
+ }
390
+ )
391
+ ] })
392
+ ] }) : /* @__PURE__ */ jsxs4("label", { className: "rt-cms-field", children: [
393
+ /* @__PURE__ */ jsx4("span", { className: "rt-cms-field-label", children: "\uD604\uC7AC \uC0AC\uC774\uD2B8 URL (\uC120\uD0DD)" }),
394
+ /* @__PURE__ */ jsx4(
395
+ "input",
396
+ {
397
+ type: "url",
398
+ name: "current_site_url",
399
+ placeholder: "https://",
400
+ className: "rt-cms-field-input"
401
+ }
402
+ ),
403
+ /* @__PURE__ */ jsx4("span", { className: "rt-cms-field-hint", children: "\uC5C6\uC73C\uBA74 \uBE44\uC6CC\uB450\uC138\uC694." })
404
+ ] }),
405
+ /* @__PURE__ */ jsxs4("label", { className: "rt-cms-lead-consent", children: [
406
+ /* @__PURE__ */ jsx4("input", { type: "checkbox", name: "privacy_consent", required: true }),
407
+ /* @__PURE__ */ jsxs4("span", { children: [
408
+ /* @__PURE__ */ jsx4("strong", { children: "(\uD544\uC218)" }),
409
+ " \uAC1C\uC778\uC815\uBCF4 \uC218\uC9D1\xB7\uC774\uC6A9\uC5D0 \uB3D9\uC758\uD569\uB2C8\uB2E4. (\uC218\uC9D1 \uD56D\uBAA9:",
410
+ " ",
411
+ isMedical ? "\uC774\uB984\xB7\uC5F0\uB77D\uCC98\xB7\uC774\uBA54\uC77C\xB7\uC0C1\uB2F4 \uB0B4\uC6A9(\uC791\uC131 \uC2DC)\xB7\uC0AC\uC774\uD2B8 \uC774\uC6A9 \uAE30\uB85D(\uBC29\uBB38 \uD398\uC774\uC9C0\xB7\uC0C1\uD638\uC791\uC6A9)" : "\uC774\uB984\xB7\uC5F0\uB77D\uCC98\xB7\uC774\uBA54\uC77C\xB7\uC0AC\uC5C5\uCCB4\uBA85\xB7\uC0AC\uC774\uD2B8 \uC774\uC6A9 \uAE30\uB85D(\uBC29\uBB38 \uD398\uC774\uC9C0\xB7\uC0C1\uD638\uC791\uC6A9)",
412
+ ". \uBCF4\uAD00 \uAE30\uAC04: \uBB38\uC758 \uC885\uB8CC \uD6C4 3\uB144)"
413
+ ] })
414
+ ] }),
415
+ vertical === "medical" ? /* @__PURE__ */ jsxs4("label", { className: "rt-cms-lead-consent", children: [
416
+ /* @__PURE__ */ jsx4(
417
+ "input",
418
+ {
419
+ type: "checkbox",
420
+ name: "overseas_transfer_consent",
421
+ required: true
422
+ }
423
+ ),
424
+ /* @__PURE__ */ jsxs4("span", { children: [
425
+ /* @__PURE__ */ jsx4("strong", { children: "(\uD544\uC218, \uC758\uB8CC)" }),
426
+ " \uC758\uB8CC PII \uC758 \uAD6D\uC678\uC774\uC804(\uBCF4\uAD00\xB7\uCC98\uB9AC)\uC5D0 \uB3D9\uC758\uD569\uB2C8\uB2E4. (\uC758\uB8CC\uBC95 \xA721\xB7\uAC1C\uC778\uC815\uBCF4\uBCF4\uD638\uBC95 \xA728 \u2014 ADR-0018)"
427
+ ] })
428
+ ] }) : null,
429
+ turnstileSiteKey ? /* @__PURE__ */ jsxs4(Fragment, { children: [
430
+ /* @__PURE__ */ jsx4(
431
+ "script",
432
+ {
433
+ src: "https://challenges.cloudflare.com/turnstile/v0/api.js",
434
+ async: true,
435
+ defer: true
436
+ }
437
+ ),
438
+ /* @__PURE__ */ jsx4(
439
+ "div",
440
+ {
441
+ className: "cf-turnstile",
442
+ "data-sitekey": turnstileSiteKey,
443
+ "data-action": "turnstile-spin-v1"
444
+ }
445
+ )
446
+ ] }) : null,
447
+ /* @__PURE__ */ jsx4("div", { className: "rt-cms-lead-actions", children: /* @__PURE__ */ jsx4("button", { type: "submit", className: "rt-cms-lead-submit", children: submitLabel }) })
448
+ ]
449
+ }
450
+ );
451
+ }
452
+
453
+ // src/block-to-react.tsx
454
+ import {
455
+ applyBlockBindings,
456
+ createFieldBindingResolver,
457
+ sanitizeHtml
458
+ } from "@roottale/cms-core";
459
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
460
+ function isString(value) {
461
+ return typeof value === "string";
462
+ }
463
+ function htmlContent(html) {
464
+ return { __html: sanitizeHtml(html) };
465
+ }
466
+ function renderInner(blocks) {
467
+ return blocks.map((b, i) => renderBlock(b, i));
468
+ }
469
+ function renderBlock(block, key = 0) {
470
+ const dataBlockId = block._id;
471
+ switch (block.name) {
472
+ case "core/paragraph": {
473
+ const text = isString(block.attributes.content) ? block.attributes.content : block.rawHtml ?? "";
474
+ return /* @__PURE__ */ jsx5(
475
+ "p",
476
+ {
477
+ "data-block-id": dataBlockId,
478
+ dangerouslySetInnerHTML: htmlContent(text)
479
+ },
480
+ key
481
+ );
482
+ }
483
+ case "core/heading": {
484
+ const levelRaw = block.attributes.level;
485
+ const level = typeof levelRaw === "number" && levelRaw >= 2 && levelRaw <= 4 ? levelRaw : 2;
486
+ const text = isString(block.attributes.content) ? block.attributes.content : block.rawHtml ?? "";
487
+ const props = {
488
+ "data-block-id": dataBlockId,
489
+ dangerouslySetInnerHTML: htmlContent(text)
490
+ };
491
+ if (level === 2) return /* @__PURE__ */ jsx5("h2", { ...props }, key);
492
+ if (level === 3) return /* @__PURE__ */ jsx5("h3", { ...props }, key);
493
+ return /* @__PURE__ */ jsx5("h4", { ...props }, key);
494
+ }
495
+ case "core/image": {
496
+ const src = isString(block.attributes.url) ? block.attributes.url : "";
497
+ const alt = isString(block.attributes.alt) ? block.attributes.alt : "";
498
+ const caption = isString(block.attributes.caption) ? block.attributes.caption : null;
499
+ return /* @__PURE__ */ jsxs5("figure", { "data-block-id": dataBlockId, children: [
500
+ /* @__PURE__ */ jsx5("img", { src, alt, loading: "lazy" }),
501
+ caption && /* @__PURE__ */ jsx5("figcaption", { children: caption })
502
+ ] }, key);
503
+ }
504
+ case "core/list": {
505
+ const ordered = block.attributes.ordered === true;
506
+ const items = (block.innerBlocks ?? []).map(
507
+ (item, i) => item.rawHtml ? /* @__PURE__ */ jsx5(
508
+ "li",
509
+ {
510
+ dangerouslySetInnerHTML: htmlContent(item.rawHtml)
511
+ },
512
+ i
513
+ ) : /* @__PURE__ */ jsx5("li", { children: renderInner(item.innerBlocks ?? []) }, i)
514
+ );
515
+ return ordered ? /* @__PURE__ */ jsx5("ol", { "data-block-id": dataBlockId, children: items }, key) : /* @__PURE__ */ jsx5("ul", { "data-block-id": dataBlockId, children: items }, key);
516
+ }
517
+ case "core/quote": {
518
+ const inner = renderInner(block.innerBlocks ?? []);
519
+ const citation = isString(block.attributes.citation) ? block.attributes.citation : null;
520
+ return /* @__PURE__ */ jsxs5("blockquote", { "data-block-id": dataBlockId, children: [
521
+ inner,
522
+ citation && /* @__PURE__ */ jsx5("cite", { children: citation })
523
+ ] }, key);
524
+ }
525
+ case "core/code": {
526
+ const code = isString(block.attributes.content) ? block.attributes.content : block.rawHtml ?? "";
527
+ const lang = isString(block.attributes.language) ? block.attributes.language : void 0;
528
+ return /* @__PURE__ */ jsx5(
529
+ "pre",
530
+ {
531
+ "data-block-id": dataBlockId,
532
+ "data-language": lang,
533
+ children: /* @__PURE__ */ jsx5("code", { children: code })
534
+ },
535
+ key
536
+ );
537
+ }
538
+ case "core/columns": {
539
+ return /* @__PURE__ */ jsx5(
540
+ "div",
541
+ {
542
+ className: "rt-columns",
543
+ "data-block-id": dataBlockId,
544
+ children: renderInner(block.innerBlocks ?? [])
545
+ },
546
+ key
547
+ );
548
+ }
549
+ case "core/separator":
550
+ return /* @__PURE__ */ jsx5("hr", { "data-block-id": dataBlockId }, key);
551
+ case "core/spacer": {
552
+ const heightRaw = block.attributes.height;
553
+ const height = isString(heightRaw) ? heightRaw : "32px";
554
+ return /* @__PURE__ */ jsx5(
555
+ "div",
556
+ {
557
+ className: "rt-spacer",
558
+ "data-block-id": dataBlockId,
559
+ style: { height }
560
+ },
561
+ key
562
+ );
563
+ }
564
+ case "core/group": {
565
+ return /* @__PURE__ */ jsx5(
566
+ "div",
567
+ {
568
+ className: "rt-group",
569
+ "data-block-id": dataBlockId,
570
+ children: renderInner(block.innerBlocks ?? [])
571
+ },
572
+ key
573
+ );
574
+ }
575
+ default: {
576
+ const rawHtml = block.rawHtml;
577
+ return /* @__PURE__ */ jsx5(
578
+ "div",
579
+ {
580
+ className: "rt-unknown-block",
581
+ "data-block-id": dataBlockId,
582
+ "data-block-name": block.name,
583
+ "data-rawhtml-suppressed": rawHtml ? "true" : void 0,
584
+ children: renderInner(block.innerBlocks ?? [])
585
+ },
586
+ key
587
+ );
588
+ }
589
+ }
590
+ }
591
+ function renderBlocks(blocks) {
592
+ return blocks.map((b, i) => renderBlock(b, i));
593
+ }
594
+ function renderBoundBlocks(blocks, opts = {}) {
595
+ const resolver = opts.resolver ?? createFieldBindingResolver(opts.fields);
596
+ return renderBlocks(applyBlockBindings(blocks, resolver));
597
+ }
598
+
599
+ // src/toc.ts
600
+ function tocLevel(rawLevel) {
601
+ if (rawLevel < 1 || rawLevel > 4) return null;
602
+ if (rawLevel < 3) return 2;
603
+ return rawLevel === 3 ? 3 : 4;
604
+ }
605
+ function headingToId(text) {
606
+ return text.trim().toLowerCase().replace(/[^\p{L}\p{N}\s-]/gu, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
607
+ }
608
+ function textOf(node) {
609
+ if (typeof node.text === "string") return node.text;
610
+ if (!Array.isArray(node.content)) return "";
611
+ return node.content.map(textOf).join("");
612
+ }
613
+ function extractToc(doc) {
614
+ const root = doc;
615
+ const content = Array.isArray(root.content) ? root.content : [];
616
+ const entries = [];
617
+ const idCounts = /* @__PURE__ */ new Map();
618
+ for (const node of content) {
619
+ if (node?.type !== "heading") continue;
620
+ const rawLevel = Number(node.attrs?.level ?? 2);
621
+ const level = tocLevel(rawLevel);
622
+ if (level === null) continue;
623
+ const text = textOf(node).trim();
624
+ if (!text) continue;
625
+ const base = headingToId(text) || "heading";
626
+ const count = idCounts.get(base) ?? 0;
627
+ const id = count === 0 ? base : `${base}-${count}`;
628
+ idCounts.set(base, count + 1);
629
+ entries.push({ level, text, id });
630
+ }
631
+ return entries;
632
+ }
633
+ function attachHeadingIds(doc, entries) {
634
+ const root = doc;
635
+ const content = Array.isArray(root.content) ? root.content : [];
636
+ let cursor = 0;
637
+ const nextContent = content.map((node) => {
638
+ if (node?.type !== "heading") return node;
639
+ const rawLevel = Number(node.attrs?.level ?? 2);
640
+ if (rawLevel < 1 || rawLevel > 4) return node;
641
+ if (!textOf(node).trim()) return node;
642
+ const entry = entries[cursor++];
643
+ if (!entry) return node;
644
+ return {
645
+ ...node,
646
+ attrs: { ...node.attrs ?? {}, id: entry.id }
647
+ };
648
+ });
649
+ return { ...root, content: nextContent };
650
+ }
651
+
652
+ // src/server/blog-list.tsx
653
+ import {
654
+ fetchPosts,
655
+ resolvePostDisplay
656
+ } from "@roottale/cms-client/server";
657
+ import {
658
+ postsForCollection,
659
+ postsNotInAnyCollection
660
+ } from "@roottale/cms-core";
661
+
662
+ // src/server/blog-settings.ts
663
+ import {
664
+ DEFAULT_BLOG_SETTINGS,
665
+ fetchBlogSettings
666
+ } from "@roottale/cms-client/server";
667
+ async function fetchBlogSettingsFailSoft(input) {
668
+ return fetchBlogSettings(input).catch(() => DEFAULT_BLOG_SETTINGS);
669
+ }
670
+
671
+ // src/server/post-links.ts
672
+ import {
673
+ resolvePostCollection,
674
+ resolvePostPath
675
+ } from "@roottale/cms-core";
676
+ function defaultPostHref(post) {
677
+ return `/blog/${post.slug}`;
678
+ }
679
+ function defaultAuthorHref(slug) {
680
+ return `/blog/author/${slug}`;
681
+ }
682
+ function makeCollectionPostHref(collections) {
683
+ return (post) => {
684
+ const path = resolvePostPath(post, collections);
685
+ if (path) return path;
686
+ const collection = resolvePostCollection(post, collections);
687
+ if (collection?.detail === false && collection.basePath) {
688
+ return collection.basePath;
689
+ }
690
+ return defaultPostHref(post);
691
+ };
692
+ }
693
+
694
+ // src/server/theme.tsx
695
+ import {
696
+ fetchTheme
697
+ } from "@roottale/cms-client/server";
698
+ import { Fragment as Fragment2, jsx as jsx6 } from "react/jsx-runtime";
699
+ async function resolveThemeStyleFailSoft(input) {
700
+ const { themeProp, apiKey, baseUrl } = input;
701
+ if (themeProp === null) return null;
702
+ if (themeProp !== void 0) return themeToCssVars2(themeProp);
703
+ const fetched = await fetchTheme({ apiKey, baseUrl }).catch(() => null);
704
+ return themeToCssVars2(fetched);
705
+ }
706
+ function RootTaleThemeProvider(props) {
707
+ const style = themeToCssVars2(props.theme ?? null);
708
+ if (!style) return /* @__PURE__ */ jsx6(Fragment2, { children: props.children });
709
+ return /* @__PURE__ */ jsx6("div", { "data-roottale-cms": "theme-root", "data-rt-theme": "", style, children: props.children });
710
+ }
711
+
712
+ // src/server/blog-list.tsx
713
+ import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
714
+ function validateCollectionScope(props) {
715
+ if (props.collection && props.excludeCollections) {
716
+ throw new Error(
717
+ "RootTaleBlogList: `collection` \uACFC `excludeCollections` \uB97C \uB3D9\uC2DC\uC5D0 \uC904 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4 \u2014 \uD3EC\uC9C0\uD2F0\uBE0C/\uB124\uAC70\uD2F0\uBE0C \uC2A4\uCF54\uD504\uB294 \uBC30\uD0C0\uC801\uC785\uB2C8\uB2E4."
718
+ );
719
+ }
720
+ if (props.excludeCollections && !props.collections) {
721
+ throw new Error(
722
+ "RootTaleBlogList: `excludeCollections` \uB294 `collections` \uC640 \uD568\uAED8 \uC918\uC57C \uD569\uB2C8\uB2E4."
723
+ );
724
+ }
725
+ }
726
+ function scopePosts(input) {
727
+ const { posts, collection, collections, excludeCollections } = input;
728
+ if (collection && collections) {
729
+ return postsForCollection(posts, collections, collection);
730
+ }
731
+ if (excludeCollections && collections) {
732
+ return postsNotInAnyCollection(posts, collections);
733
+ }
734
+ return posts;
735
+ }
736
+ async function RootTaleBlogList(props) {
737
+ validateCollectionScope(props);
738
+ const {
739
+ apiKey,
740
+ baseUrl,
741
+ limit,
742
+ type = "post",
743
+ collection,
744
+ collections,
745
+ excludeCollections = false,
746
+ locale,
747
+ emptyMessage = t(locale, "blogListEmpty"),
748
+ showCategoryFilter = false,
749
+ activeCategory,
750
+ categoryHref = defaultCategoryHref,
751
+ allCategoriesLabel = t(locale, "allCategoriesLabel"),
752
+ author,
753
+ theme: themeProp
754
+ } = props;
755
+ const postHref = props.postHref ?? (collections ? makeCollectionPostHref(collections) : defaultPostHref);
756
+ const [page, themeStyle, blogSettings] = await Promise.all([
757
+ fetchPosts({
758
+ apiKey,
759
+ baseUrl,
760
+ limit,
761
+ type,
762
+ ...author ? { author } : {},
763
+ ...collection && collections ? { collectionKey: collection } : {},
764
+ ...excludeCollections && collections ? { excludeCollections: true } : {},
765
+ ...locale ? { locale } : {}
766
+ }),
767
+ resolveThemeStyleFailSoft({ themeProp, apiKey, baseUrl }),
768
+ fetchBlogSettingsFailSoft({ apiKey, baseUrl })
769
+ ]);
770
+ const items = scopePosts({
771
+ posts: page.items,
772
+ collection,
773
+ collections,
774
+ excludeCollections
775
+ });
776
+ if (items.length === 0) {
777
+ return /* @__PURE__ */ jsx7("div", { "data-roottale-cms": "list", style: themeStyle ?? void 0, children: /* @__PURE__ */ jsx7("p", { className: "rt-cms-empty", children: emptyMessage }) });
778
+ }
779
+ const categories = showCategoryFilter ? collectCategories(items) : [];
780
+ const visiblePosts = showCategoryFilter ? filterPostsByCategory(items, activeCategory) : items;
781
+ const isAllCategoriesActive = !activeCategory;
782
+ return /* @__PURE__ */ jsxs6("div", { "data-roottale-cms": "list", style: themeStyle ?? void 0, children: [
783
+ showCategoryFilter && categories.length > 0 ? /* @__PURE__ */ jsxs6("nav", { className: "rt-cms-filter", "aria-label": "\uCE74\uD14C\uACE0\uB9AC \uD544\uD130", children: [
784
+ /* @__PURE__ */ jsx7(
785
+ "a",
786
+ {
787
+ className: "rt-cms-filter-chip",
788
+ href: categoryHref(null),
789
+ "data-active": isAllCategoriesActive ? "" : void 0,
790
+ "aria-current": isAllCategoriesActive ? "true" : void 0,
791
+ children: allCategoriesLabel
792
+ }
793
+ ),
794
+ categories.map((category) => /* @__PURE__ */ jsx7(
795
+ "a",
796
+ {
797
+ className: "rt-cms-filter-chip",
798
+ href: categoryHref(category.slug),
799
+ "data-active": activeCategory === category.slug ? "" : void 0,
800
+ "aria-current": activeCategory === category.slug ? "true" : void 0,
801
+ children: category.name
802
+ },
803
+ category.slug
804
+ ))
805
+ ] }) : null,
806
+ visiblePosts.length === 0 ? /* @__PURE__ */ jsx7("p", { className: "rt-cms-empty", children: emptyMessage }) : /* @__PURE__ */ jsx7("ul", { className: "rt-cms-list", children: visiblePosts.map((post) => /* @__PURE__ */ jsx7("li", { className: "rt-cms-list-item", children: /* @__PURE__ */ jsx7(
807
+ RootTalePostCard,
808
+ {
809
+ post,
810
+ href: postHref,
811
+ display: resolvePostDisplay(post, blogSettings)
812
+ }
813
+ ) }, post.id)) })
814
+ ] });
815
+ }
816
+
817
+ // src/server/blog-categories.tsx
818
+ import {
819
+ fetchPosts as fetchPosts2
820
+ } from "@roottale/cms-client/server";
821
+ import { jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
822
+ async function RootTaleBlogCategories(props) {
823
+ const {
824
+ apiKey,
825
+ baseUrl,
826
+ limit,
827
+ collection,
828
+ collections,
829
+ categoryHref = defaultCategoryHref,
830
+ locale,
831
+ emptyMessage = t(locale, "blogCategoriesEmpty"),
832
+ theme: themeProp
833
+ } = props;
834
+ const [page, themeStyle] = await Promise.all([
835
+ fetchPosts2({
836
+ apiKey,
837
+ baseUrl,
838
+ limit,
839
+ type: "post",
840
+ ...locale ? { locale } : {}
841
+ }),
842
+ resolveThemeStyleFailSoft({ themeProp, apiKey, baseUrl })
843
+ ]);
844
+ const categories = collection && collections ? collectCollectionCategories(page.items, collections, collection) : collectCategoriesWithCounts(page.items);
845
+ return /* @__PURE__ */ jsx8(
846
+ "nav",
847
+ {
848
+ "data-roottale-cms": "categories",
849
+ className: "rt-cms-categories",
850
+ "aria-label": "\uBE14\uB85C\uADF8 \uCE74\uD14C\uACE0\uB9AC",
851
+ style: themeStyle ?? void 0,
852
+ children: categories.length === 0 ? /* @__PURE__ */ jsx8("p", { className: "rt-cms-empty", children: emptyMessage }) : /* @__PURE__ */ jsx8("ul", { className: "rt-cms-category-list", children: categories.map((category) => /* @__PURE__ */ jsx8("li", { className: "rt-cms-category-list-item", children: /* @__PURE__ */ jsxs7(
853
+ "a",
854
+ {
855
+ className: "rt-cms-category-link",
856
+ href: categoryHref(category.slug),
857
+ children: [
858
+ /* @__PURE__ */ jsx8("span", { className: "rt-cms-category-name", children: category.name }),
859
+ /* @__PURE__ */ jsx8("span", { className: "rt-cms-category-count", children: category.count })
860
+ ]
861
+ }
862
+ ) }, category.slug)) })
863
+ }
864
+ );
865
+ }
866
+
867
+ // src/server/blog-post.tsx
868
+ import {
869
+ fetchPost,
870
+ fetchPosts as fetchPosts3,
871
+ resolvePostDisplay as resolvePostDisplay2,
872
+ selectRelatedPosts
873
+ } from "@roottale/cms-client/server";
874
+
875
+ // src/server/blog-post-archive.tsx
876
+ import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
877
+ var FIELD_FACT_TYPES = /* @__PURE__ */ new Set([
878
+ "text",
879
+ "textarea",
880
+ "email",
881
+ "url",
882
+ "select",
883
+ "radio",
884
+ "button_group",
885
+ "number",
886
+ "range"
887
+ ]);
888
+ function archiveGroupTitle(group) {
889
+ if (group.collectionKey === "conditions") {
890
+ return `\uC774 \uC99D\uC0C1\uACFC \uAD00\uB828\uB41C \uC9C8\uD658 ${group.items.length}`;
891
+ }
892
+ if (group.collectionKey === "treatments") {
893
+ return `\uAD00\uB828 \uCE58\uB8CC\uBC95 ${group.items.length}`;
894
+ }
895
+ if (group.collectionKey === "symptoms") {
896
+ return `\uAD00\uB828 \uC99D\uC0C1 ${group.items.length}`;
897
+ }
898
+ return `${group.label} ${group.items.length}`;
899
+ }
900
+ function defaultArchiveBasePath(collectionKey) {
901
+ if (collectionKey === "symptoms") return "/symptoms";
902
+ if (collectionKey === "conditions") return "/conditions";
903
+ if (collectionKey === "treatments") return "/treatments";
904
+ return "/blog";
905
+ }
906
+ function archivePostHref(collectionKey, slug, collections) {
907
+ const collection = collections?.find((item) => item.key === collectionKey);
908
+ const basePath = collection?.basePath || defaultArchiveBasePath(collectionKey);
909
+ const trimmedBase = basePath.replace(/\/+$/, "");
910
+ if (collection?.detail === false) return trimmedBase;
911
+ return `${trimmedBase}/${slug}`;
912
+ }
913
+ function renderArchiveRelated(groups, collections) {
914
+ const visibleGroups = groups.filter((group) => group.items.length > 0);
915
+ if (visibleGroups.length === 0) return null;
916
+ return /* @__PURE__ */ jsx9("aside", { className: "rt-archive-related", "aria-label": "\uC5F0\uAD00 \uC815\uBCF4", children: visibleGroups.map((group) => /* @__PURE__ */ jsxs8("section", { className: "rt-archive-related__group", children: [
917
+ /* @__PURE__ */ jsx9("h2", { className: "rt-archive-related__title", children: archiveGroupTitle(group) }),
918
+ /* @__PURE__ */ jsx9("ul", { className: "rt-archive-related__list", children: group.items.map((item) => /* @__PURE__ */ jsx9("li", { className: "rt-archive-related__item", children: /* @__PURE__ */ jsxs8(
919
+ "a",
920
+ {
921
+ className: "rt-archive-related__link",
922
+ href: archivePostHref(
923
+ item.collectionKey,
924
+ item.slug,
925
+ collections
926
+ ),
927
+ children: [
928
+ /* @__PURE__ */ jsx9("span", { className: "rt-archive-related__item-title", children: item.title }),
929
+ item.excerpt ? /* @__PURE__ */ jsx9("span", { className: "rt-archive-related__item-excerpt", children: item.excerpt }) : null
930
+ ]
931
+ }
932
+ ) }, item.id)) })
933
+ ] }, group.collectionKey)) });
934
+ }
935
+ function fieldFactValue(raw, meta) {
936
+ if (raw === null || raw === void 0) return null;
937
+ if (typeof raw === "number") return raw.toLocaleString("ko-KR");
938
+ if (typeof raw !== "string" || raw.trim() === "") return null;
939
+ if (!meta.choices) return raw;
940
+ const choice = meta.choices.find((item) => item.value === raw);
941
+ return choice ? choice.label : raw;
942
+ }
943
+ function renderFieldFacts(post) {
944
+ if (!post.fields) return null;
945
+ const rows = post.fieldsMeta.filter((meta) => FIELD_FACT_TYPES.has(meta.type)).flatMap((meta) => {
946
+ const value = fieldFactValue(post.fields?.[meta.name], meta);
947
+ return value === null ? [] : [{ meta, value }];
948
+ });
949
+ if (rows.length === 0) return null;
950
+ return /* @__PURE__ */ jsx9("aside", { className: "rt-archive-facts", "aria-label": "\uC0C1\uC138 \uC815\uBCF4", children: /* @__PURE__ */ jsx9("dl", { className: "rt-archive-facts__list", children: rows.map(({ meta, value }) => /* @__PURE__ */ jsxs8("div", { className: "rt-archive-facts__row", children: [
951
+ /* @__PURE__ */ jsx9("dt", { className: "rt-archive-facts__label", children: meta.label }),
952
+ /* @__PURE__ */ jsx9(
953
+ "dd",
954
+ {
955
+ className: meta.type === "textarea" ? "rt-archive-facts__value rt-archive-facts__value--multiline" : "rt-archive-facts__value",
956
+ children: value
957
+ }
958
+ )
959
+ ] }, meta.name)) }) });
960
+ }
961
+
962
+ // src/server/tiptap-node-renderer.tsx
963
+ import {
964
+ bindingSrcValue,
965
+ bindingTextValue,
966
+ boundFieldValue
967
+ } from "@roottale/cms-core";
968
+
969
+ // src/section-render-context.ts
970
+ var sectionNodeRenderer = null;
971
+ function setSectionNodeRenderer(renderer) {
972
+ sectionNodeRenderer = renderer;
973
+ }
974
+ function getSectionNodeRenderer() {
975
+ return sectionNodeRenderer;
976
+ }
977
+
978
+ // src/server/tiptap-embed-renderer.tsx
979
+ import { isAllowedEmbedSrc } from "@roottale/cms-core";
980
+ import { jsx as jsx10 } from "react/jsx-runtime";
981
+ function isSafeFallbackHref(value) {
982
+ if (typeof value !== "string") return false;
983
+ const href = value.trim();
984
+ if (href.length === 0) return false;
985
+ if (href.startsWith("/") || href.startsWith("#") || href.startsWith("?")) {
986
+ return true;
987
+ }
988
+ return /^(https?:|mailto:|tel:)/i.test(href);
989
+ }
990
+ function renderEmbedNode(node, key) {
991
+ const src = node.attrs?.src;
992
+ if (isAllowedEmbedSrc(src)) {
993
+ const provider = typeof node.attrs?.provider === "string" ? node.attrs.provider : void 0;
994
+ return /* @__PURE__ */ jsx10(
995
+ "div",
996
+ {
997
+ className: "rt-embed",
998
+ "data-provider": provider,
999
+ style: { aspectRatio: "16 / 9" },
1000
+ children: /* @__PURE__ */ jsx10(
1001
+ "iframe",
1002
+ {
1003
+ src,
1004
+ title: "\uC784\uBCA0\uB4DC\uB41C \uC601\uC0C1",
1005
+ loading: "lazy",
1006
+ allowFullScreen: true,
1007
+ referrerPolicy: "strict-origin-when-cross-origin",
1008
+ allow: "accelerometer; clipboard-write; encrypted-media; picture-in-picture; web-share",
1009
+ style: { width: "100%", height: "100%", border: 0 }
1010
+ }
1011
+ )
1012
+ },
1013
+ key
1014
+ );
1015
+ }
1016
+ const originalUrl = node.attrs?.originalUrl;
1017
+ if (!isSafeFallbackHref(originalUrl)) return null;
1018
+ return /* @__PURE__ */ jsx10("p", { className: "rt-embed-fallback", children: /* @__PURE__ */ jsx10("a", { href: originalUrl, rel: "noopener noreferrer", target: "_blank", children: originalUrl }) }, key);
1019
+ }
1020
+
1021
+ // src/server/tiptap-types.ts
1022
+ function isRecord(value) {
1023
+ return typeof value === "object" && value !== null;
1024
+ }
1025
+ function parseTiptapNode(value) {
1026
+ if (!isRecord(value)) return null;
1027
+ return {
1028
+ type: typeof value.type === "string" ? value.type : void 0,
1029
+ text: typeof value.text === "string" ? value.text : void 0,
1030
+ attrs: isRecord(value.attrs) ? value.attrs : void 0,
1031
+ content: Array.isArray(value.content) ? value.content : void 0,
1032
+ marks: Array.isArray(value.marks) ? value.marks : void 0
1033
+ };
1034
+ }
1035
+ function parseTiptapMark(value) {
1036
+ if (!isRecord(value)) return null;
1037
+ return {
1038
+ type: typeof value.type === "string" ? value.type : void 0,
1039
+ attrs: isRecord(value.attrs) ? value.attrs : void 0
1040
+ };
1041
+ }
1042
+
1043
+ // src/server/tiptap-inline-renderer.tsx
1044
+ import { Fragment as Fragment3, jsx as jsx11 } from "react/jsx-runtime";
1045
+ function isSafeHref(value) {
1046
+ if (typeof value !== "string") return false;
1047
+ const href = value.trim();
1048
+ if (href.length === 0) return false;
1049
+ if (href.startsWith("/") || href.startsWith("#") || href.startsWith("?")) {
1050
+ return true;
1051
+ }
1052
+ return /^(https?:|mailto:|tel:)/i.test(href);
1053
+ }
1054
+ function applyMark(mark, child) {
1055
+ switch (mark.type) {
1056
+ case "bold":
1057
+ return /* @__PURE__ */ jsx11("strong", { children: child });
1058
+ case "italic":
1059
+ return /* @__PURE__ */ jsx11("em", { children: child });
1060
+ case "underline":
1061
+ return /* @__PURE__ */ jsx11("u", { children: child });
1062
+ case "strike":
1063
+ return /* @__PURE__ */ jsx11("s", { children: child });
1064
+ case "code":
1065
+ return /* @__PURE__ */ jsx11("code", { children: child });
1066
+ case "highlight": {
1067
+ const color = mark.attrs?.color;
1068
+ const style = typeof color === "string" && color.length > 0 ? { background: color } : void 0;
1069
+ return /* @__PURE__ */ jsx11("mark", { style, children: child });
1070
+ }
1071
+ case "textStyle": {
1072
+ const color = mark.attrs?.color;
1073
+ if (typeof color !== "string" || color.length === 0) {
1074
+ return /* @__PURE__ */ jsx11(Fragment3, { children: child });
1075
+ }
1076
+ return /* @__PURE__ */ jsx11("span", { style: { color }, children: child });
1077
+ }
1078
+ case "link": {
1079
+ const rawHref = mark.attrs?.href;
1080
+ const href = isSafeHref(rawHref) ? rawHref : "#";
1081
+ return /* @__PURE__ */ jsx11("a", { href, rel: "noopener noreferrer", target: "_blank", children: child });
1082
+ }
1083
+ default:
1084
+ return /* @__PURE__ */ jsx11("span", { children: child });
1085
+ }
1086
+ }
1087
+ function renderTextNode(node, key) {
1088
+ const text = node.text ?? "";
1089
+ const marks = (node.marks ?? []).flatMap((value) => {
1090
+ const mark = parseTiptapMark(value);
1091
+ return mark ? [mark] : [];
1092
+ });
1093
+ if (marks.length === 0) return text;
1094
+ let element = text;
1095
+ for (const mark of marks) {
1096
+ element = applyMark(mark, element);
1097
+ }
1098
+ return /* @__PURE__ */ jsx11("span", { children: element }, key);
1099
+ }
1100
+
1101
+ // src/server/tiptap-node-renderer.tsx
1102
+ import { jsx as jsx12 } from "react/jsx-runtime";
1103
+ function boundContentText(node, fields) {
1104
+ return bindingTextValue(
1105
+ boundFieldValue(node.attrs?.bindings, "content", fields)
1106
+ );
1107
+ }
1108
+ function alignStyle(node) {
1109
+ const align = node.attrs?.textAlign;
1110
+ if (typeof align !== "string" || align === "" || align === "left") {
1111
+ return void 0;
1112
+ }
1113
+ if (align === "center" || align === "right" || align === "justify") {
1114
+ return { textAlign: align };
1115
+ }
1116
+ return void 0;
1117
+ }
1118
+ function tableCellSpans(node) {
1119
+ const colspan = Number(node.attrs?.colspan);
1120
+ const rowspan = Number(node.attrs?.rowspan);
1121
+ return {
1122
+ colSpan: Number.isFinite(colspan) && colspan > 1 ? colspan : void 0,
1123
+ rowSpan: Number.isFinite(rowspan) && rowspan > 1 ? rowspan : void 0
1124
+ };
1125
+ }
1126
+ function renderTiptapNode(value, key, context) {
1127
+ const node = parseTiptapNode(value);
1128
+ if (!node) return null;
1129
+ const children = node.content?.map(
1130
+ (child, index) => renderTiptapNode(child, index, context)
1131
+ );
1132
+ switch (node.type) {
1133
+ case "paragraph": {
1134
+ const bound = boundContentText(node, context.fields);
1135
+ return /* @__PURE__ */ jsx12("p", { style: alignStyle(node), children: bound ?? children }, key);
1136
+ }
1137
+ case "heading": {
1138
+ const rawLevel = Number(node.attrs?.level ?? 2);
1139
+ const finiteLevel = Number.isFinite(rawLevel) ? rawLevel : 2;
1140
+ const level = Math.min(Math.max(finiteLevel, 2), 4);
1141
+ const rawId = node.attrs?.id;
1142
+ const id = typeof rawId === "string" && rawId.length > 0 ? rawId : void 0;
1143
+ const style = alignStyle(node);
1144
+ const inner = boundContentText(node, context.fields) ?? children;
1145
+ if (level === 2) {
1146
+ return /* @__PURE__ */ jsx12("h2", { id, style, children: inner }, key);
1147
+ }
1148
+ if (level === 3) {
1149
+ return /* @__PURE__ */ jsx12("h3", { id, style, children: inner }, key);
1150
+ }
1151
+ return /* @__PURE__ */ jsx12("h4", { id, style, children: inner }, key);
1152
+ }
1153
+ case "bulletList":
1154
+ return /* @__PURE__ */ jsx12("ul", { children }, key);
1155
+ case "orderedList":
1156
+ return /* @__PURE__ */ jsx12("ol", { children }, key);
1157
+ case "listItem":
1158
+ return /* @__PURE__ */ jsx12("li", { children }, key);
1159
+ case "blockquote":
1160
+ return /* @__PURE__ */ jsx12("blockquote", { children }, key);
1161
+ case "codeBlock":
1162
+ return /* @__PURE__ */ jsx12("pre", { children: /* @__PURE__ */ jsx12("code", { children }) }, key);
1163
+ case "horizontalRule":
1164
+ return /* @__PURE__ */ jsx12("hr", {}, key);
1165
+ case "hardBreak":
1166
+ return /* @__PURE__ */ jsx12("br", {}, key);
1167
+ case "image": {
1168
+ const boundSrc = bindingSrcValue(
1169
+ boundFieldValue(node.attrs?.bindings, "src", context.fields)
1170
+ );
1171
+ const src = boundSrc ?? node.attrs?.src;
1172
+ if (typeof src !== "string" || src.length === 0) return null;
1173
+ const alt = typeof node.attrs?.alt === "string" ? node.attrs.alt : "";
1174
+ const title = typeof node.attrs?.title === "string" ? node.attrs.title : void 0;
1175
+ const width = typeof node.attrs?.width === "number" && node.attrs.width > 0 ? node.attrs.width : void 0;
1176
+ const height = typeof node.attrs?.height === "number" && node.attrs.height > 0 ? node.attrs.height : void 0;
1177
+ return /* @__PURE__ */ jsx12(
1178
+ "img",
1179
+ {
1180
+ src,
1181
+ alt,
1182
+ title,
1183
+ width,
1184
+ height,
1185
+ loading: "lazy"
1186
+ },
1187
+ key
1188
+ );
1189
+ }
1190
+ case "columns":
1191
+ return /* @__PURE__ */ jsx12("div", { className: "rt-columns", children }, key);
1192
+ case "column":
1193
+ return /* @__PURE__ */ jsx12("div", { className: "rt-column", children }, key);
1194
+ case "table":
1195
+ return /* @__PURE__ */ jsx12("div", { className: "rt-table-wrap", children: /* @__PURE__ */ jsx12("table", { className: "rt-table", children: /* @__PURE__ */ jsx12("tbody", { children }) }) }, key);
1196
+ case "tableRow":
1197
+ return /* @__PURE__ */ jsx12("tr", { children }, key);
1198
+ case "tableHeader": {
1199
+ const { colSpan, rowSpan } = tableCellSpans(node);
1200
+ return /* @__PURE__ */ jsx12("th", { colSpan, rowSpan, children }, key);
1201
+ }
1202
+ case "tableCell": {
1203
+ const { colSpan, rowSpan } = tableCellSpans(node);
1204
+ return /* @__PURE__ */ jsx12("td", { colSpan, rowSpan, children }, key);
1205
+ }
1206
+ case "embed":
1207
+ return renderEmbedNode(node, key);
1208
+ case "faq":
1209
+ return /* @__PURE__ */ jsx12("div", { "data-roottale-cms": "faq", className: "rt-cms-faq", children }, key);
1210
+ case "faqItem":
1211
+ return /* @__PURE__ */ jsx12("details", { className: "rt-cms-faq-item", children }, key);
1212
+ case "faqQuestion":
1213
+ return /* @__PURE__ */ jsx12("summary", { className: "rt-cms-faq-q", children }, key);
1214
+ case "faqAnswer":
1215
+ return /* @__PURE__ */ jsx12("div", { className: "rt-cms-faq-a", children }, key);
1216
+ case "tableOfContents":
1217
+ return null;
1218
+ case "section": {
1219
+ const renderSection = getSectionNodeRenderer();
1220
+ if (!renderSection) {
1221
+ if (context.section.isDev()) {
1222
+ console.warn(
1223
+ '[cms-renderer-next] section \uB178\uB4DC\uB97C \uADF8\uB9B4 \uD15C\uD50C\uB9BF\uC774 \uB4F1\uB85D\uB418\uC9C0 \uC54A\uC558\uB2E4 \u2014 \uB80C\uB354 skip. `import "@roottale/cms-renderer-next/templates"` \uAC00 \uD544\uC694\uD558\uB2E4.'
1224
+ );
1225
+ }
1226
+ return null;
1227
+ }
1228
+ return renderSection(node, key, context.section);
1229
+ }
1230
+ case "text":
1231
+ return renderTextNode(node, key);
1232
+ default:
1233
+ return children ? /* @__PURE__ */ jsx12("span", { children }, key) : null;
1234
+ }
1235
+ }
1236
+
1237
+ // src/server/render-tiptap.tsx
1238
+ import { Fragment as Fragment4, jsx as jsx13 } from "react/jsx-runtime";
1239
+ function isDevelopmentRuntime() {
1240
+ const processValue = Reflect.get(globalThis, "process");
1241
+ if (!isRecord(processValue)) return true;
1242
+ const env = processValue.env;
1243
+ if (!isRecord(env)) return true;
1244
+ return env.NODE_ENV !== "production";
1245
+ }
1246
+ function createSectionContextWithBlogListNetworkFetch(apiKey, baseUrl) {
1247
+ const cms = apiKey ? { apiKey, baseUrl } : null;
1248
+ return {
1249
+ cms,
1250
+ isDev: isDevelopmentRuntime,
1251
+ renderBlogList: (props) => /* @__PURE__ */ jsx13(RootTaleBlogList, { ...props })
1252
+ };
1253
+ }
1254
+ function contentNodes(doc) {
1255
+ return Array.isArray(doc.content) ? doc.content : [];
1256
+ }
1257
+ function RenderTiptap({
1258
+ doc,
1259
+ fields,
1260
+ apiKey,
1261
+ baseUrl
1262
+ }) {
1263
+ const content = contentNodes(doc);
1264
+ const hasTableOfContents = content.some(
1265
+ (value) => parseTiptapNode(value)?.type === "tableOfContents"
1266
+ );
1267
+ const entries = hasTableOfContents ? extractToc(doc) : [];
1268
+ const renderDoc = hasTableOfContents && entries.length > 0 ? attachHeadingIds(doc, entries) : doc;
1269
+ const context = {
1270
+ fields: fields ?? null,
1271
+ section: createSectionContextWithBlogListNetworkFetch(apiKey, baseUrl)
1272
+ };
1273
+ return /* @__PURE__ */ jsx13(Fragment4, { children: contentNodes(renderDoc).map((value, index) => {
1274
+ const node = parseTiptapNode(value);
1275
+ if (node?.type !== "tableOfContents") {
1276
+ return renderTiptapNode(value, index, context);
1277
+ }
1278
+ const title = node.attrs?.title;
1279
+ return /* @__PURE__ */ jsx13(
1280
+ RootTaleTableOfContents,
1281
+ {
1282
+ entries,
1283
+ title: typeof title === "string" ? title : "\uBAA9\uCC28"
1284
+ },
1285
+ index
1286
+ );
1287
+ }) });
1288
+ }
1289
+
1290
+ // src/server/blog-post-body.tsx
1291
+ import { Fragment as Fragment5, jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
1292
+ function BlogPostBody(props) {
1293
+ const {
1294
+ doc,
1295
+ fields,
1296
+ apiKey,
1297
+ baseUrl,
1298
+ toc,
1299
+ tocTitle,
1300
+ tocPosition
1301
+ } = props;
1302
+ const tableOfContents = toc.length > 0 ? /* @__PURE__ */ jsx14(RootTaleTableOfContents, { entries: toc, title: tocTitle }) : null;
1303
+ const body = /* @__PURE__ */ jsx14("div", { "data-roottale-cms": "body", className: "rt-cms-body", children: /* @__PURE__ */ jsx14(
1304
+ RenderTiptap,
1305
+ {
1306
+ doc,
1307
+ fields,
1308
+ apiKey,
1309
+ baseUrl
1310
+ }
1311
+ ) });
1312
+ if (tocPosition === "sidebar" && tableOfContents) {
1313
+ return /* @__PURE__ */ jsxs9("div", { className: "rt-cms-layout rt-cms-layout--toc-side", children: [
1314
+ body,
1315
+ /* @__PURE__ */ jsx14("aside", { className: "rt-cms-toc-side", children: tableOfContents })
1316
+ ] });
1317
+ }
1318
+ return /* @__PURE__ */ jsxs9(Fragment5, { children: [
1319
+ tableOfContents,
1320
+ body
1321
+ ] });
1322
+ }
1323
+
1324
+ // src/server/blog-post-breadcrumb.tsx
1325
+ import {
1326
+ breadcrumbSchema,
1327
+ jsonLdJson
1328
+ } from "@roottale/cms-client/server";
1329
+ import {
1330
+ resolvePostCollection as resolvePostCollection2
1331
+ } from "@roottale/cms-core";
1332
+ import { Fragment as Fragment6, jsx as jsx15, jsxs as jsxs10 } from "react/jsx-runtime";
1333
+ function absoluteUrl(siteUrl, path) {
1334
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
1335
+ return `${trimSlash(siteUrl)}${normalizedPath}`;
1336
+ }
1337
+ function renderBlogPostBreadcrumb(input) {
1338
+ const { post, collections, postHref, options } = input;
1339
+ if (!options) return null;
1340
+ const {
1341
+ siteUrl,
1342
+ homeLabel = "\uD648",
1343
+ homeHref = "/",
1344
+ listLabel = "\uBE14\uB85C\uADF8",
1345
+ showCategory = true,
1346
+ categoryHref = defaultCategoryHref
1347
+ } = options;
1348
+ const listHref = options.listHref ?? (collections ? resolvePostCollection2(post, collections)?.basePath || "/blog" : "/blog");
1349
+ const categoryTerm = showCategory ? post.terms.find((term) => term.taxonomy === "category") : void 0;
1350
+ const crumbs = [
1351
+ { label: homeLabel, href: homeHref },
1352
+ { label: listLabel, href: listHref }
1353
+ ];
1354
+ if (categoryTerm) {
1355
+ crumbs.push({
1356
+ label: categoryTerm.name,
1357
+ href: categoryHref(categoryTerm.slug)
1358
+ });
1359
+ }
1360
+ crumbs.push({ label: post.title, href: postHref(post) });
1361
+ const jsonLd = siteUrl ? breadcrumbSchema(
1362
+ crumbs.map((crumb) => ({
1363
+ name: crumb.label,
1364
+ url: absoluteUrl(siteUrl, crumb.href)
1365
+ }))
1366
+ ) : null;
1367
+ return /* @__PURE__ */ jsxs10(Fragment6, { children: [
1368
+ /* @__PURE__ */ jsx15("nav", { "aria-label": "\uBE0C\uB808\uB4DC\uD06C\uB7FC", className: "rt-cms-breadcrumb", children: /* @__PURE__ */ jsx15("ol", { children: crumbs.map(
1369
+ (crumb, index) => index === crumbs.length - 1 ? /* @__PURE__ */ jsx15("li", { "aria-current": "page", children: crumb.label }, index) : /* @__PURE__ */ jsx15("li", { children: /* @__PURE__ */ jsx15("a", { href: crumb.href, children: crumb.label }) }, index)
1370
+ ) }) }),
1371
+ jsonLd ? /* @__PURE__ */ jsx15(
1372
+ "script",
1373
+ {
1374
+ type: "application/ld+json",
1375
+ dangerouslySetInnerHTML: { __html: jsonLdJson(jsonLd) }
1376
+ }
1377
+ ) : null
1378
+ ] });
1379
+ }
1380
+
1381
+ // src/server/blog-post-footer.tsx
1382
+ import {
1383
+ jsonLdJson as jsonLdJson2
1384
+ } from "@roottale/cms-client/server";
1385
+ import { extractFaqEntries, faqPageJsonLd } from "@roottale/cms-core";
1386
+ import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
1387
+ function renderPostCta(cta) {
1388
+ if (!cta) return null;
1389
+ const href = cta.buttonHref.trim();
1390
+ const isSafeHref2 = href.startsWith("/") || href.startsWith("#") || /^(https?:|mailto:|tel:)/i.test(href);
1391
+ if (!isSafeHref2) return null;
1392
+ const isExternal = /^https?:/i.test(href);
1393
+ return /* @__PURE__ */ jsxs11("aside", { "data-roottale-cms": "post-cta", className: "rt-cms-post-cta", children: [
1394
+ cta.title ? /* @__PURE__ */ jsx16("p", { className: "rt-cms-post-cta__title", children: cta.title }) : null,
1395
+ cta.description ? /* @__PURE__ */ jsx16("p", { className: "rt-cms-post-cta__desc", children: cta.description }) : null,
1396
+ /* @__PURE__ */ jsx16(
1397
+ "a",
1398
+ {
1399
+ className: "rt-cms-post-cta__btn",
1400
+ href,
1401
+ target: isExternal ? "_blank" : void 0,
1402
+ rel: isExternal ? "noopener noreferrer" : void 0,
1403
+ children: cta.buttonLabel
1404
+ }
1405
+ )
1406
+ ] });
1407
+ }
1408
+ function renderRelatedPosts(posts, href, title) {
1409
+ if (posts.length === 0) return null;
1410
+ return /* @__PURE__ */ jsxs11("nav", { "data-roottale-cms": "related", className: "rt-cms-related", "aria-label": title, children: [
1411
+ /* @__PURE__ */ jsx16("h2", { className: "rt-cms-related-title", children: title }),
1412
+ /* @__PURE__ */ jsx16("ul", { className: "rt-cms-related-list", children: posts.map((post) => /* @__PURE__ */ jsx16("li", { className: "rt-cms-related-item", children: /* @__PURE__ */ jsxs11("a", { className: "rt-cms-related-link", href: href(post), children: [
1413
+ post.featuredImageUrl ? /* @__PURE__ */ jsx16(
1414
+ "img",
1415
+ {
1416
+ className: "rt-cms-related-thumb",
1417
+ src: post.featuredImageUrl,
1418
+ alt: "",
1419
+ loading: "lazy"
1420
+ }
1421
+ ) : null,
1422
+ /* @__PURE__ */ jsx16("span", { className: "rt-cms-related-post-title", children: post.title })
1423
+ ] }) }, post.id)) })
1424
+ ] });
1425
+ }
1426
+ function renderFaqJsonLd(doc) {
1427
+ const jsonLd = faqPageJsonLd(extractFaqEntries(doc));
1428
+ if (!jsonLd) return null;
1429
+ return /* @__PURE__ */ jsx16(
1430
+ "script",
1431
+ {
1432
+ type: "application/ld+json",
1433
+ dangerouslySetInnerHTML: { __html: jsonLdJson2(jsonLd) }
1434
+ }
1435
+ );
1436
+ }
1437
+ function RootTaleFaqJsonLd({
1438
+ doc
1439
+ }) {
1440
+ return renderFaqJsonLd(doc);
1441
+ }
1442
+
1443
+ // src/server/blog-post.tsx
1444
+ import { jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
1445
+ async function fetchRelatedPostsFailSoft(input) {
1446
+ if (input.count <= 0) return [];
1447
+ const candidates = await fetchPosts3({
1448
+ apiKey: input.apiKey,
1449
+ baseUrl: input.baseUrl,
1450
+ type: "post",
1451
+ limit: 30,
1452
+ ...input.locale ? { locale: input.locale } : {}
1453
+ }).catch(() => null);
1454
+ if (!candidates) return [];
1455
+ return selectRelatedPosts(input.post, candidates.items, input.count);
1456
+ }
1457
+ function authorInitials(name) {
1458
+ const trimmed = name.trim();
1459
+ if (!trimmed) return "";
1460
+ const parts = trimmed.split(/\s+/).filter(Boolean);
1461
+ if (parts.length >= 2) {
1462
+ return `${parts[0]?.[0] ?? ""}${parts[1]?.[0] ?? ""}`.toUpperCase();
1463
+ }
1464
+ return [...trimmed].slice(0, 2).join("").toUpperCase();
1465
+ }
1466
+ function formatPublishedDate2(iso) {
1467
+ const date = new Date(iso);
1468
+ if (Number.isNaN(date.getTime())) return "";
1469
+ return new Intl.DateTimeFormat("ko-KR", {
1470
+ year: "numeric",
1471
+ month: "2-digit",
1472
+ day: "2-digit"
1473
+ }).format(date);
1474
+ }
1475
+ function authorImageRadiusCss(radius) {
1476
+ if (radius === "circle") return "999px";
1477
+ if (radius === "rounded") return "0.875rem";
1478
+ return "0";
1479
+ }
1480
+ async function RootTaleBlogPost(props) {
1481
+ const {
1482
+ apiKey,
1483
+ slugOrId,
1484
+ baseUrl,
1485
+ notFoundElement,
1486
+ showTitle = true,
1487
+ showTableOfContents,
1488
+ tableOfContentsTitle,
1489
+ relatedPostsCount = 0,
1490
+ locale,
1491
+ relatedPostsTitle = t(locale, "relatedPostsTitle"),
1492
+ collections,
1493
+ showFieldFacts = false,
1494
+ theme: themeProp,
1495
+ authorHref = defaultAuthorHref,
1496
+ breadcrumb
1497
+ } = props;
1498
+ const [post, themeStyle, blogSettings] = await Promise.all([
1499
+ fetchPost({ apiKey, slugOrId, baseUrl, ...locale ? { locale } : {} }),
1500
+ resolveThemeStyleFailSoft({ themeProp, apiKey, baseUrl }),
1501
+ fetchBlogSettingsFailSoft({ apiKey, baseUrl })
1502
+ ]);
1503
+ if (!post) {
1504
+ return notFoundElement ?? /* @__PURE__ */ jsx17("div", { "data-roottale-cms": "post-missing", style: themeStyle ?? void 0, children: /* @__PURE__ */ jsx17("p", { className: "rt-cms-empty", children: t(locale, "postNotFound") }) });
1505
+ }
1506
+ const display = resolvePostDisplay2(post, blogSettings, {
1507
+ showTableOfContents,
1508
+ tableOfContentsTitle
1509
+ });
1510
+ const toc = display.showTableOfContents ? extractToc(post.bodyJson) : [];
1511
+ const renderDoc = toc.length > 0 ? attachHeadingIds(post.bodyJson, toc) : post.bodyJson;
1512
+ const related = await fetchRelatedPostsFailSoft({
1513
+ post,
1514
+ apiKey,
1515
+ baseUrl,
1516
+ count: relatedPostsCount,
1517
+ locale
1518
+ });
1519
+ const relatedHref = props.postHref ?? (collections ? makeCollectionPostHref(collections) : defaultPostHref);
1520
+ const authorName = post.authorName;
1521
+ const authorSlug = post.authorSlug;
1522
+ const views = typeof post.viewCount === "number" ? post.viewCount : null;
1523
+ const publishedDate = display.showDate ? formatPublishedDate2(post.publishedAt) : "";
1524
+ const showTopAuthor = display.showAuthor && Boolean(authorName);
1525
+ const displayAuthorName = authorName ?? display.authorProfileName;
1526
+ const authorBio = post.authorBio ?? display.authorProfileBio ?? display.authorCardDescription;
1527
+ const authorImageUrl = post.authorImageUrl ?? display.authorProfileImageUrl;
1528
+ const authorImageAlt = `${displayAuthorName ?? ""} \uD504\uB85C\uD544 \uC0AC\uC9C4`.trim();
1529
+ const authorImageStyle = {
1530
+ borderRadius: authorImageRadiusCss(display.authorProfileImageRadius),
1531
+ objectPosition: `${display.authorProfileImagePositionX}% ${display.authorProfileImagePositionY}%`
1532
+ };
1533
+ const showAuthorCard = display.showAuthorCard && Boolean(displayAuthorName);
1534
+ return /* @__PURE__ */ jsxs12(
1535
+ "article",
1536
+ {
1537
+ "data-roottale-cms": "post",
1538
+ className: "rt-cms-article",
1539
+ style: themeStyle ?? void 0,
1540
+ children: [
1541
+ renderBlogPostBreadcrumb({
1542
+ post,
1543
+ collections,
1544
+ postHref: relatedHref,
1545
+ options: breadcrumb
1546
+ }),
1547
+ /* @__PURE__ */ jsxs12("header", { className: "rt-cms-post-header", children: [
1548
+ showTitle ? /* @__PURE__ */ jsx17("h1", { className: "rt-cms-title", children: post.title }) : null,
1549
+ post.excerpt ? /* @__PURE__ */ jsx17("p", { className: "rt-cms-excerpt", children: post.excerpt }) : null,
1550
+ publishedDate || showTopAuthor || views !== null ? /* @__PURE__ */ jsxs12("p", { className: "rt-cms-meta", children: [
1551
+ publishedDate ? /* @__PURE__ */ jsx17(
1552
+ "time",
1553
+ {
1554
+ dateTime: post.publishedAt ?? void 0,
1555
+ className: "rt-cms-meta-item",
1556
+ "data-rt-cms-meta": "date",
1557
+ children: publishedDate
1558
+ }
1559
+ ) : null,
1560
+ showTopAuthor ? /* @__PURE__ */ jsxs12("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "author", children: [
1561
+ "\uC791\uC131\uC790",
1562
+ " ",
1563
+ authorSlug ? /* @__PURE__ */ jsx17("a", { className: "rt-cms-author-link", href: authorHref(authorSlug), children: authorName }) : authorName
1564
+ ] }) : null,
1565
+ views !== null ? /* @__PURE__ */ jsxs12("span", { className: "rt-cms-meta-item", "data-rt-cms-meta": "views", children: [
1566
+ "\uC870\uD68C ",
1567
+ views.toLocaleString("ko-KR")
1568
+ ] }) : null
1569
+ ] }) : null
1570
+ ] }),
1571
+ renderArchiveRelated(post.archiveRelated, collections),
1572
+ showFieldFacts ? renderFieldFacts(post) : null,
1573
+ /* @__PURE__ */ jsx17(
1574
+ BlogPostBody,
1575
+ {
1576
+ doc: renderDoc,
1577
+ fields: post.fields,
1578
+ apiKey,
1579
+ baseUrl,
1580
+ toc,
1581
+ tocTitle: display.tocTitle,
1582
+ tocPosition: display.tocPosition
1583
+ }
1584
+ ),
1585
+ showAuthorCard && displayAuthorName ? /* @__PURE__ */ jsxs12("section", { className: "rt-cms-author-card", "aria-label": "\uC791\uC131\uC790", children: [
1586
+ authorImageUrl ? /* @__PURE__ */ jsx17(
1587
+ "img",
1588
+ {
1589
+ className: "rt-cms-author-card__image",
1590
+ src: authorImageUrl,
1591
+ alt: authorImageAlt,
1592
+ loading: "lazy",
1593
+ style: authorImageStyle
1594
+ }
1595
+ ) : /* @__PURE__ */ jsx17("div", { className: "rt-cms-author-card__avatar", "aria-hidden": "true", children: authorInitials(displayAuthorName) }),
1596
+ /* @__PURE__ */ jsxs12("div", { className: "rt-cms-author-card__body", children: [
1597
+ /* @__PURE__ */ jsx17("p", { className: "rt-cms-author-card__eyebrow", children: display.authorCardEyebrow }),
1598
+ /* @__PURE__ */ jsx17("p", { className: "rt-cms-author-card__name", children: authorSlug ? /* @__PURE__ */ jsx17("a", { className: "rt-cms-author-link", href: authorHref(authorSlug), children: displayAuthorName }) : displayAuthorName }),
1599
+ authorBio ? /* @__PURE__ */ jsx17("p", { className: "rt-cms-author-card__description", children: authorBio }) : null
1600
+ ] })
1601
+ ] }) : null,
1602
+ renderRelatedPosts(related, relatedHref, relatedPostsTitle),
1603
+ renderPostCta(blogSettings.postCta),
1604
+ renderFaqJsonLd(post.bodyJson)
1605
+ ]
1606
+ }
1607
+ );
1608
+ }
1609
+
1610
+ // src/server/page.tsx
1611
+ import { fetchPost as fetchPost2 } from "@roottale/cms-client/server";
1612
+ import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
1613
+ async function RootTalePage(props) {
1614
+ const {
1615
+ apiKey,
1616
+ slugOrId,
1617
+ baseUrl,
1618
+ notFoundElement,
1619
+ showTitle = true,
1620
+ theme: themeProp,
1621
+ locale
1622
+ } = props;
1623
+ const [post, themeStyle] = await Promise.all([
1624
+ fetchPost2({ apiKey, slugOrId, baseUrl, ...locale ? { locale } : {} }),
1625
+ resolveThemeStyleFailSoft({ themeProp, apiKey, baseUrl })
1626
+ ]);
1627
+ if (!post) {
1628
+ return notFoundElement ?? /* @__PURE__ */ jsx18("div", { "data-roottale-cms": "page-missing", style: themeStyle ?? void 0, children: /* @__PURE__ */ jsx18("p", { className: "rt-cms-empty", children: t(locale, "pageNotFound") }) });
1629
+ }
1630
+ return /* @__PURE__ */ jsxs13(
1631
+ "article",
1632
+ {
1633
+ "data-roottale-cms": "page",
1634
+ className: "rt-cms-article",
1635
+ style: themeStyle ?? void 0,
1636
+ children: [
1637
+ showTitle ? /* @__PURE__ */ jsx18("header", { className: "rt-cms-post-header", children: /* @__PURE__ */ jsx18("h1", { className: "rt-cms-title", children: post.title }) }) : null,
1638
+ /* @__PURE__ */ jsx18("div", { "data-roottale-cms": "body", className: "rt-cms-body", children: /* @__PURE__ */ jsx18(
1639
+ RenderTiptap,
1640
+ {
1641
+ doc: post.bodyJson,
1642
+ fields: post.fields,
1643
+ apiKey,
1644
+ baseUrl
1645
+ }
1646
+ ) })
1647
+ ]
1648
+ }
1649
+ );
1650
+ }
1651
+
1652
+ // src/templates/section-templates/shared.tsx
1653
+ import { jsx as jsx19 } from "react/jsx-runtime";
1654
+ function sectionThemeStyle(theme) {
1655
+ if (!theme) return void 0;
1656
+ const style = {};
1657
+ for (const [key, value] of Object.entries(theme)) {
1658
+ if (key.startsWith("--")) style[key] = value;
1659
+ }
1660
+ return Object.keys(style).length > 0 ? style : void 0;
1661
+ }
1662
+ function CtaLink({
1663
+ cta,
1664
+ className,
1665
+ track
1666
+ }) {
1667
+ return /* @__PURE__ */ jsx19(
1668
+ "a",
1669
+ {
1670
+ className: className ?? "rt-tpl-btn rt-tpl-btn--primary",
1671
+ href: cta.href,
1672
+ "data-track": track,
1673
+ children: cta.label
1674
+ }
1675
+ );
1676
+ }
1677
+ function ctaTrackForHref(href) {
1678
+ return href.startsWith("tel:") ? "cta_banner" : "cta_hero";
1679
+ }
1680
+ function contactHrefTrack(href) {
1681
+ if (href.startsWith("tel:")) return "phone_click";
1682
+ if (href.startsWith("mailto:")) return "email_click";
1683
+ return void 0;
1684
+ }
1685
+ function telHref(phone) {
1686
+ return `tel:${phone.replace(/[^\d+]/g, "")}`;
1687
+ }
1688
+
1689
+ // src/templates/section-templates/hero.tsx
1690
+ import { jsx as jsx20, jsxs as jsxs14 } from "react/jsx-runtime";
1691
+ function TemplateHeroProof({
1692
+ proofMetrics
1693
+ }) {
1694
+ if (!proofMetrics || proofMetrics.items.length === 0) return null;
1695
+ return /* @__PURE__ */ jsx20(
1696
+ "div",
1697
+ {
1698
+ className: "rt-tpl-hero-proof",
1699
+ "data-position": proofMetrics.position,
1700
+ "aria-label": "\uC2E0\uB8B0 \uC9C0\uD45C",
1701
+ children: proofMetrics.items.map((metric) => /* @__PURE__ */ jsxs14("div", { className: "rt-tpl-hero-proof-item", children: [
1702
+ metric.imageSrc ? /* @__PURE__ */ jsx20(
1703
+ "img",
1704
+ {
1705
+ className: "rt-tpl-hero-proof-icon",
1706
+ src: metric.imageSrc,
1707
+ alt: metric.imageAlt ?? "",
1708
+ loading: "lazy"
1709
+ }
1710
+ ) : null,
1711
+ /* @__PURE__ */ jsxs14("span", { className: "rt-tpl-hero-proof-value", children: [
1712
+ metric.value,
1713
+ metric.unit ? /* @__PURE__ */ jsx20("span", { children: metric.unit }) : null
1714
+ ] }),
1715
+ /* @__PURE__ */ jsx20("span", { className: "rt-tpl-hero-proof-label", children: metric.label }),
1716
+ metric.source ? /* @__PURE__ */ jsx20("span", { className: "rt-tpl-hero-proof-source", children: metric.source }) : null
1717
+ ] }, `${metric.value}-${metric.label}`))
1718
+ }
1719
+ );
1720
+ }
1721
+ function TemplateHeroCarousel(section) {
1722
+ const {
1723
+ eyebrow,
1724
+ title,
1725
+ subtitle,
1726
+ cta,
1727
+ slides,
1728
+ autoplay,
1729
+ intervalMs,
1730
+ transition,
1731
+ proofMetrics,
1732
+ scrim
1733
+ } = section.props;
1734
+ const safeSlides = slides ?? [];
1735
+ return /* @__PURE__ */ jsxs14(
1736
+ "section",
1737
+ {
1738
+ "data-roottale-tpl": "hero",
1739
+ "data-variant": "carousel",
1740
+ id: section.id,
1741
+ className: "rt-tpl-section rt-tpl-hero rt-tpl-hero--carousel",
1742
+ style: sectionThemeStyle(section.theme),
1743
+ children: [
1744
+ safeSlides.length >= 2 ? /* @__PURE__ */ jsx20(
1745
+ HeroCarouselViewport,
1746
+ {
1747
+ slides: safeSlides,
1748
+ autoplay: autoplay ?? true,
1749
+ intervalMs: intervalMs ?? 6e3,
1750
+ scrim,
1751
+ transition
1752
+ }
1753
+ ) : null,
1754
+ /* @__PURE__ */ jsxs14("div", { className: "rt-tpl-container rt-tpl-hero-carousel-overlay", children: [
1755
+ eyebrow ? /* @__PURE__ */ jsx20("p", { className: "rt-tpl-hero-eyebrow", children: eyebrow }) : null,
1756
+ /* @__PURE__ */ jsx20("h1", { className: "rt-tpl-hero-title rt-tpl-hero-carousel-title", children: title.split("\n").map((line, i) => /* @__PURE__ */ jsx20("span", { className: "rt-tpl-hero-title-line", children: line }, i)) }),
1757
+ subtitle ? /* @__PURE__ */ jsx20("p", { className: "rt-tpl-hero-desc rt-tpl-hero-carousel-subtitle", children: subtitle }) : null,
1758
+ cta ? /* @__PURE__ */ jsx20(
1759
+ CtaLink,
1760
+ {
1761
+ cta,
1762
+ track: "cta_hero",
1763
+ className: "rt-tpl-btn rt-tpl-btn--primary rt-tpl-hero-carousel-cta"
1764
+ }
1765
+ ) : null,
1766
+ /* @__PURE__ */ jsx20(TemplateHeroProof, { proofMetrics })
1767
+ ] })
1768
+ ]
1769
+ }
1770
+ );
1771
+ }
1772
+ function TemplateHeroOverlayPanel(section) {
1773
+ const { eyebrow, title, description, imageSrc, imageAlt, cta, proofMetrics } = section.props;
1774
+ return /* @__PURE__ */ jsxs14(
1775
+ "section",
1776
+ {
1777
+ "data-roottale-tpl": "hero",
1778
+ "data-variant": "overlay-panel",
1779
+ id: section.id,
1780
+ className: "rt-tpl-section rt-tpl-hero rt-tpl-hero--overlay-panel",
1781
+ style: sectionThemeStyle(section.theme),
1782
+ children: [
1783
+ /* @__PURE__ */ jsx20(
1784
+ "img",
1785
+ {
1786
+ className: "rt-tpl-hero-overlay-img",
1787
+ src: imageSrc ?? "",
1788
+ alt: imageAlt ?? "",
1789
+ loading: "eager"
1790
+ }
1791
+ ),
1792
+ /* @__PURE__ */ jsx20("div", { className: "rt-tpl-hero-overlay-scrim", "aria-hidden": "true" }),
1793
+ /* @__PURE__ */ jsx20("div", { className: "rt-tpl-container rt-tpl-hero-overlay-inner", children: /* @__PURE__ */ jsxs14("div", { className: "rt-tpl-hero-overlay-panel", children: [
1794
+ eyebrow ? /* @__PURE__ */ jsx20("p", { className: "rt-tpl-hero-eyebrow", children: eyebrow }) : null,
1795
+ /* @__PURE__ */ jsx20("h1", { className: "rt-tpl-hero-title", children: title.split("\n").map((line, i) => /* @__PURE__ */ jsx20("span", { className: "rt-tpl-hero-title-line", children: line }, i)) }),
1796
+ description ? /* @__PURE__ */ jsx20("p", { className: "rt-tpl-hero-desc", children: description }) : null,
1797
+ cta ? /* @__PURE__ */ jsx20(CtaLink, { cta, track: "cta_hero" }) : null,
1798
+ /* @__PURE__ */ jsx20(TemplateHeroProof, { proofMetrics })
1799
+ ] }) })
1800
+ ]
1801
+ }
1802
+ );
1803
+ }
1804
+ function TemplateHero(section) {
1805
+ switch (section.variant) {
1806
+ case "carousel":
1807
+ return TemplateHeroCarousel(section);
1808
+ case "overlay-panel":
1809
+ return TemplateHeroOverlayPanel(section);
1810
+ default:
1811
+ break;
1812
+ }
1813
+ const { eyebrow, title, description, imageSrc, imageAlt, cta, proofMetrics } = section.props;
1814
+ const variant = section.variant;
1815
+ const showImage = variant !== "minimal" && imageSrc;
1816
+ return /* @__PURE__ */ jsx20(
1817
+ "section",
1818
+ {
1819
+ "data-roottale-tpl": "hero",
1820
+ "data-variant": variant,
1821
+ id: section.id,
1822
+ className: "rt-tpl-section rt-tpl-hero",
1823
+ style: sectionThemeStyle(section.theme),
1824
+ children: /* @__PURE__ */ jsxs14("div", { className: "rt-tpl-container rt-tpl-hero-inner", children: [
1825
+ /* @__PURE__ */ jsxs14("div", { className: "rt-tpl-hero-copy", children: [
1826
+ eyebrow ? /* @__PURE__ */ jsx20("p", { className: "rt-tpl-hero-eyebrow", children: eyebrow }) : null,
1827
+ /* @__PURE__ */ jsx20("h1", { className: "rt-tpl-hero-title", children: title.split("\n").map((line, i) => /* @__PURE__ */ jsx20("span", { className: "rt-tpl-hero-title-line", children: line }, i)) }),
1828
+ description ? /* @__PURE__ */ jsx20("p", { className: "rt-tpl-hero-desc", children: description }) : null,
1829
+ cta ? /* @__PURE__ */ jsx20(CtaLink, { cta, track: "cta_hero" }) : null,
1830
+ /* @__PURE__ */ jsx20(TemplateHeroProof, { proofMetrics })
1831
+ ] }),
1832
+ showImage ? /* @__PURE__ */ jsx20("div", { className: "rt-tpl-hero-media", children: /* @__PURE__ */ jsx20(
1833
+ "img",
1834
+ {
1835
+ className: "rt-tpl-hero-img",
1836
+ src: imageSrc,
1837
+ alt: imageAlt ?? "",
1838
+ loading: "eager"
1839
+ }
1840
+ ) }) : null
1841
+ ] })
1842
+ }
1843
+ );
1844
+ }
1845
+
1846
+ // src/templates/section-templates/rich-text.tsx
1847
+ import { jsx as jsx21, jsxs as jsxs15 } from "react/jsx-runtime";
1848
+ function TemplateRichText(section) {
1849
+ const { heading, body } = section.props;
1850
+ return /* @__PURE__ */ jsx21(
1851
+ "section",
1852
+ {
1853
+ "data-roottale-tpl": "rich-text",
1854
+ id: section.id,
1855
+ className: "rt-tpl-section rt-tpl-rich-text",
1856
+ style: sectionThemeStyle(section.theme),
1857
+ children: /* @__PURE__ */ jsxs15("div", { className: "rt-tpl-container", children: [
1858
+ heading ? /* @__PURE__ */ jsx21("h2", { className: "rt-tpl-heading", children: heading }) : null,
1859
+ body.split("\n\n").map((para, i) => /* @__PURE__ */ jsx21("p", { className: "rt-tpl-rich-text-p", children: para }, i))
1860
+ ] })
1861
+ }
1862
+ );
1863
+ }
1864
+
1865
+ // src/templates/section-templates/services-base.tsx
1866
+ import { Fragment as Fragment7, jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
1867
+ function ServicesItemMeta({
1868
+ item
1869
+ }) {
1870
+ const hasChips = Boolean(item.chips && item.chips.length > 0);
1871
+ const hasMeta = Boolean(item.meta && item.meta.length > 0);
1872
+ if (!hasChips && !hasMeta) return null;
1873
+ return /* @__PURE__ */ jsxs16("div", { className: "rt-tpl-services-meta-block", children: [
1874
+ hasChips ? /* @__PURE__ */ jsx22("ul", { className: "rt-tpl-services-chips", "aria-label": `${item.title} \uD0DC\uADF8`, children: (item.chips ?? []).map((chip) => /* @__PURE__ */ jsx22("li", { children: chip }, chip)) }) : null,
1875
+ hasMeta ? /* @__PURE__ */ jsx22("ul", { className: "rt-tpl-services-meta", "aria-label": `${item.title} \uBA54\uD0C0`, children: (item.meta ?? []).map((meta) => /* @__PURE__ */ jsx22("li", { children: meta }, meta)) }) : null
1876
+ ] });
1877
+ }
1878
+ function ServicesIcon({
1879
+ item
1880
+ }) {
1881
+ if (!item.iconSrc) return null;
1882
+ return /* @__PURE__ */ jsx22(
1883
+ "img",
1884
+ {
1885
+ className: "rt-tpl-services-icon",
1886
+ src: item.iconSrc,
1887
+ alt: item.iconAlt ?? "",
1888
+ loading: "lazy"
1889
+ }
1890
+ );
1891
+ }
1892
+ function TemplateServicesActionRail(section) {
1893
+ const { heading, description, items } = section.props;
1894
+ return /* @__PURE__ */ jsx22(
1895
+ "section",
1896
+ {
1897
+ "data-roottale-tpl": "services",
1898
+ "data-variant": "action-rail",
1899
+ id: section.id,
1900
+ className: "rt-tpl-section rt-tpl-services",
1901
+ style: sectionThemeStyle(section.theme),
1902
+ children: /* @__PURE__ */ jsxs16("div", { className: "rt-tpl-container", children: [
1903
+ heading ? /* @__PURE__ */ jsx22("h2", { className: "rt-tpl-heading", children: heading }) : null,
1904
+ description ? /* @__PURE__ */ jsx22("p", { className: "rt-tpl-section-desc", children: description }) : null,
1905
+ /* @__PURE__ */ jsx22("ul", { className: "rt-tpl-services-action-rail", children: items.map((item, i) => {
1906
+ const body = /* @__PURE__ */ jsxs16(Fragment7, { children: [
1907
+ /* @__PURE__ */ jsx22(ServicesIcon, { item }),
1908
+ /* @__PURE__ */ jsxs16("span", { className: "rt-tpl-services-action-body", children: [
1909
+ /* @__PURE__ */ jsx22("span", { className: "rt-tpl-services-title", children: item.title }),
1910
+ item.subtitle ? /* @__PURE__ */ jsx22("span", { className: "rt-tpl-services-subtitle", children: item.subtitle }) : null,
1911
+ item.description ? /* @__PURE__ */ jsx22("span", { className: "rt-tpl-services-desc", children: item.description }) : null,
1912
+ /* @__PURE__ */ jsx22(ServicesItemMeta, { item }),
1913
+ item.ctaLabel ? /* @__PURE__ */ jsx22("span", { className: "rt-tpl-services-action-label", children: item.ctaLabel }) : null
1914
+ ] })
1915
+ ] });
1916
+ return /* @__PURE__ */ jsx22("li", { "data-kind": item.kind, children: item.href ? /* @__PURE__ */ jsx22(
1917
+ "a",
1918
+ {
1919
+ className: "rt-tpl-services-action-card",
1920
+ href: item.href,
1921
+ "data-track": "service_card",
1922
+ children: body
1923
+ }
1924
+ ) : /* @__PURE__ */ jsx22("div", { className: "rt-tpl-services-action-card", children: body }) }, `${item.title}-${i}`);
1925
+ }) })
1926
+ ] })
1927
+ }
1928
+ );
1929
+ }
1930
+ function TemplateServicesPhotoCards(section) {
1931
+ const { heading, description, items } = section.props;
1932
+ return /* @__PURE__ */ jsx22(
1933
+ "section",
1934
+ {
1935
+ "data-roottale-tpl": "services",
1936
+ "data-variant": "photo-cards",
1937
+ id: section.id,
1938
+ className: "rt-tpl-section rt-tpl-services",
1939
+ style: sectionThemeStyle(section.theme),
1940
+ children: /* @__PURE__ */ jsxs16("div", { className: "rt-tpl-container", children: [
1941
+ heading ? /* @__PURE__ */ jsx22("h2", { className: "rt-tpl-heading", children: heading }) : null,
1942
+ description ? /* @__PURE__ */ jsx22("p", { className: "rt-tpl-section-desc", children: description }) : null,
1943
+ /* @__PURE__ */ jsx22("ul", { className: "rt-tpl-services-photo-list", children: items.map((item, i) => {
1944
+ const card = /* @__PURE__ */ jsxs16("article", { className: "rt-tpl-services-photo-card", children: [
1945
+ /* @__PURE__ */ jsx22(
1946
+ "img",
1947
+ {
1948
+ className: "rt-tpl-services-photo-img",
1949
+ src: item.imageSrc ?? "",
1950
+ alt: item.imageAlt ?? "",
1951
+ loading: "lazy"
1952
+ }
1953
+ ),
1954
+ /* @__PURE__ */ jsxs16("div", { className: "rt-tpl-services-photo-body", children: [
1955
+ /* @__PURE__ */ jsx22("h3", { className: "rt-tpl-services-title", children: item.title }),
1956
+ item.description ? /* @__PURE__ */ jsx22("p", { className: "rt-tpl-services-desc", children: item.description }) : null,
1957
+ item.ctaLabel ? /* @__PURE__ */ jsx22("span", { className: "rt-tpl-services-action-label", children: item.ctaLabel }) : null
1958
+ ] })
1959
+ ] });
1960
+ return /* @__PURE__ */ jsx22("li", { children: item.href ? /* @__PURE__ */ jsx22(
1961
+ "a",
1962
+ {
1963
+ className: "rt-tpl-services-photo-link",
1964
+ href: item.href,
1965
+ "data-track": "service_card",
1966
+ children: card
1967
+ }
1968
+ ) : card }, `${item.title}-${i}`);
1969
+ }) })
1970
+ ] })
1971
+ }
1972
+ );
1973
+ }
1974
+
1975
+ // src/templates/section-templates/services-variants.tsx
1976
+ import { Fragment as Fragment8, jsx as jsx23, jsxs as jsxs17 } from "react/jsx-runtime";
1977
+ function servicesIndexNum(i) {
1978
+ return String(i + 1).padStart(2, "0");
1979
+ }
1980
+ function TemplateServicesIndexRows(section) {
1981
+ const { heading, description, items } = section.props;
1982
+ return /* @__PURE__ */ jsx23(
1983
+ "section",
1984
+ {
1985
+ "data-roottale-tpl": "services",
1986
+ "data-variant": "index-rows",
1987
+ id: section.id,
1988
+ className: "rt-tpl-section rt-tpl-services",
1989
+ style: sectionThemeStyle(section.theme),
1990
+ children: /* @__PURE__ */ jsxs17("div", { className: "rt-tpl-container", children: [
1991
+ heading ? /* @__PURE__ */ jsx23("h2", { className: "rt-tpl-heading", children: heading }) : null,
1992
+ description ? /* @__PURE__ */ jsx23("p", { className: "rt-tpl-section-desc", children: description }) : null,
1993
+ /* @__PURE__ */ jsx23(StaggerGroup, { as: "ol", className: "rt-tpl-services-index-list", children: items.map((item, i) => {
1994
+ const body = /* @__PURE__ */ jsxs17(Fragment8, { children: [
1995
+ /* @__PURE__ */ jsx23("span", { className: "rt-tpl-services-index-num", "aria-hidden": "true", children: servicesIndexNum(i) }),
1996
+ /* @__PURE__ */ jsxs17("div", { className: "rt-tpl-services-index-body", children: [
1997
+ /* @__PURE__ */ jsx23("h3", { className: "rt-tpl-services-index-title", children: item.title }),
1998
+ item.description ? /* @__PURE__ */ jsx23("p", { className: "rt-tpl-services-index-desc", children: item.description }) : null
1999
+ ] })
2000
+ ] });
2001
+ return /* @__PURE__ */ jsx23(StaggerItem, { as: "li", className: "rt-tpl-services-index-row", children: item.href ? /* @__PURE__ */ jsx23(
2002
+ "a",
2003
+ {
2004
+ className: "rt-tpl-services-index-link",
2005
+ href: item.href,
2006
+ "data-track": "service_card",
2007
+ children: body
2008
+ }
2009
+ ) : /* @__PURE__ */ jsx23("div", { className: "rt-tpl-services-index-link", children: body }) }, i);
2010
+ }) })
2011
+ ] })
2012
+ }
2013
+ );
2014
+ }
2015
+ function TemplateServicesSplitFeatured(section) {
2016
+ const { heading, description, items } = section.props;
2017
+ const [featured, ...rest] = items;
2018
+ return /* @__PURE__ */ jsx23(
2019
+ "section",
2020
+ {
2021
+ "data-roottale-tpl": "services",
2022
+ "data-variant": "split-featured",
2023
+ id: section.id,
2024
+ className: "rt-tpl-section rt-tpl-services",
2025
+ style: sectionThemeStyle(section.theme),
2026
+ children: /* @__PURE__ */ jsxs17("div", { className: "rt-tpl-container", children: [
2027
+ heading ? /* @__PURE__ */ jsx23("h2", { className: "rt-tpl-heading", children: heading }) : null,
2028
+ description ? /* @__PURE__ */ jsx23("p", { className: "rt-tpl-section-desc", children: description }) : null,
2029
+ /* @__PURE__ */ jsxs17("div", { className: "rt-tpl-services-split", children: [
2030
+ /* @__PURE__ */ jsx23(
2031
+ AnimateOnScroll,
2032
+ {
2033
+ as: "div",
2034
+ variant: "fade-up",
2035
+ className: "rt-tpl-services-split-featured",
2036
+ children: featured ? /* @__PURE__ */ jsxs17(Fragment8, { children: [
2037
+ /* @__PURE__ */ jsx23("h3", { className: "rt-tpl-services-split-featured-title", children: featured.title }),
2038
+ featured.subtitle ? /* @__PURE__ */ jsx23("p", { className: "rt-tpl-services-subtitle", children: featured.subtitle }) : null,
2039
+ featured.description ? /* @__PURE__ */ jsx23("p", { className: "rt-tpl-services-split-featured-desc", children: featured.description }) : null,
2040
+ /* @__PURE__ */ jsx23(ServicesItemMeta, { item: featured }),
2041
+ featured.href ? /* @__PURE__ */ jsx23(
2042
+ "a",
2043
+ {
2044
+ className: "rt-tpl-btn rt-tpl-btn--primary rt-tpl-services-split-featured-cta",
2045
+ href: featured.href,
2046
+ "data-track": "service_card",
2047
+ children: featured.ctaLabel ?? "\uC790\uC138\uD788 \uBCF4\uAE30"
2048
+ }
2049
+ ) : null
2050
+ ] }) : null
2051
+ }
2052
+ ),
2053
+ /* @__PURE__ */ jsx23(StaggerGroup, { as: "ol", className: "rt-tpl-services-split-list", children: rest.map((item, i) => {
2054
+ const body = /* @__PURE__ */ jsxs17(Fragment8, { children: [
2055
+ /* @__PURE__ */ jsx23("h4", { className: "rt-tpl-services-split-item-title", children: item.title }),
2056
+ item.description ? /* @__PURE__ */ jsx23("p", { className: "rt-tpl-services-split-item-desc", children: item.description }) : null,
2057
+ /* @__PURE__ */ jsx23(ServicesItemMeta, { item })
2058
+ ] });
2059
+ return /* @__PURE__ */ jsx23(
2060
+ StaggerItem,
2061
+ {
2062
+ as: "li",
2063
+ className: "rt-tpl-services-split-item",
2064
+ children: item.href ? /* @__PURE__ */ jsx23(
2065
+ "a",
2066
+ {
2067
+ className: "rt-tpl-services-split-item-link",
2068
+ href: item.href,
2069
+ "data-track": "service_card",
2070
+ children: body
2071
+ }
2072
+ ) : body
2073
+ },
2074
+ i
2075
+ );
2076
+ }) })
2077
+ ] })
2078
+ ] })
2079
+ }
2080
+ );
2081
+ }
2082
+
2083
+ // src/templates/section-templates/services.tsx
2084
+ import { Fragment as Fragment9, jsx as jsx24, jsxs as jsxs18 } from "react/jsx-runtime";
2085
+ function TemplateServices(section) {
2086
+ switch (section.variant) {
2087
+ case "index-rows":
2088
+ return TemplateServicesIndexRows(section);
2089
+ case "split-featured":
2090
+ return TemplateServicesSplitFeatured(section);
2091
+ case "action-rail":
2092
+ return TemplateServicesActionRail(section);
2093
+ case "photo-cards":
2094
+ return TemplateServicesPhotoCards(section);
2095
+ default:
2096
+ break;
2097
+ }
2098
+ const { heading, description, items } = section.props;
2099
+ return /* @__PURE__ */ jsx24(
2100
+ "section",
2101
+ {
2102
+ "data-roottale-tpl": "services",
2103
+ "data-variant": section.variant,
2104
+ id: section.id,
2105
+ className: "rt-tpl-section rt-tpl-services",
2106
+ style: sectionThemeStyle(section.theme),
2107
+ children: /* @__PURE__ */ jsxs18("div", { className: "rt-tpl-container", children: [
2108
+ heading ? /* @__PURE__ */ jsx24("h2", { className: "rt-tpl-heading", children: heading }) : null,
2109
+ description ? /* @__PURE__ */ jsx24("p", { className: "rt-tpl-section-desc", children: description }) : null,
2110
+ /* @__PURE__ */ jsx24(StaggerGroup, { as: "ul", className: "rt-tpl-services-list", children: items.map((item, i) => {
2111
+ const body = /* @__PURE__ */ jsxs18(Fragment9, { children: [
2112
+ /* @__PURE__ */ jsx24("h3", { className: "rt-tpl-services-title", children: item.title }),
2113
+ item.subtitle ? /* @__PURE__ */ jsx24("p", { className: "rt-tpl-services-subtitle", children: item.subtitle }) : null,
2114
+ item.description ? /* @__PURE__ */ jsx24("p", { className: "rt-tpl-services-desc", children: item.description }) : null,
2115
+ /* @__PURE__ */ jsx24(ServicesItemMeta, { item }),
2116
+ item.ctaLabel ? /* @__PURE__ */ jsx24("span", { className: "rt-tpl-services-action-label", children: item.ctaLabel }) : null
2117
+ ] });
2118
+ return /* @__PURE__ */ jsx24(StaggerItem, { as: "li", className: "rt-tpl-services-item", children: item.href ? /* @__PURE__ */ jsxs18(
2119
+ "a",
2120
+ {
2121
+ className: "rt-tpl-services-link",
2122
+ href: item.href,
2123
+ "data-track": "service_card",
2124
+ children: [
2125
+ /* @__PURE__ */ jsx24(ServicesIcon, { item }),
2126
+ body
2127
+ ]
2128
+ }
2129
+ ) : /* @__PURE__ */ jsxs18(Fragment9, { children: [
2130
+ /* @__PURE__ */ jsx24(ServicesIcon, { item }),
2131
+ body
2132
+ ] }) }, i);
2133
+ }) })
2134
+ ] })
2135
+ }
2136
+ );
2137
+ }
2138
+
2139
+ // src/templates/section-templates/footer.tsx
2140
+ import { jsx as jsx25, jsxs as jsxs19 } from "react/jsx-runtime";
2141
+ function FooterBrand(section) {
2142
+ const { businessName, logo, description } = section.props;
2143
+ return /* @__PURE__ */ jsxs19("div", { className: "rt-tpl-footer-brand", children: [
2144
+ logo ? /* @__PURE__ */ jsx25(
2145
+ "img",
2146
+ {
2147
+ className: "rt-tpl-footer-logo",
2148
+ src: logo.src,
2149
+ alt: logo.alt,
2150
+ loading: "lazy"
2151
+ }
2152
+ ) : null,
2153
+ /* @__PURE__ */ jsx25("p", { className: "rt-tpl-footer-name", children: businessName }),
2154
+ description ? /* @__PURE__ */ jsx25("p", { className: "rt-tpl-footer-description", children: description }) : null
2155
+ ] });
2156
+ }
2157
+ function FooterContact({
2158
+ contactInfo
2159
+ }) {
2160
+ if (!contactInfo?.address && !contactInfo?.phone && !contactInfo?.email) {
2161
+ return null;
2162
+ }
2163
+ return /* @__PURE__ */ jsxs19("address", { className: "rt-tpl-footer-contact", children: [
2164
+ contactInfo.address ? /* @__PURE__ */ jsx25("span", { children: contactInfo.address }) : null,
2165
+ contactInfo.phone ? /* @__PURE__ */ jsx25(
2166
+ "a",
2167
+ {
2168
+ href: telHref(contactInfo.phone),
2169
+ "data-track": "phone_click",
2170
+ "data-track-placement": "footer",
2171
+ children: contactInfo.phone
2172
+ }
2173
+ ) : null,
2174
+ contactInfo.email ? /* @__PURE__ */ jsx25(
2175
+ "a",
2176
+ {
2177
+ href: `mailto:${contactInfo.email}`,
2178
+ "data-track": "email_click",
2179
+ "data-track-placement": "footer",
2180
+ children: contactInfo.email
2181
+ }
2182
+ ) : null
2183
+ ] });
2184
+ }
2185
+ function FooterLegal(section) {
2186
+ const { legalInfo, privacyHref, termsHref, copyright, socialLinks, credit } = section.props;
2187
+ return /* @__PURE__ */ jsxs19("div", { className: "rt-tpl-footer-bottom", children: [
2188
+ /* @__PURE__ */ jsxs19("div", { className: "rt-tpl-footer-legal", children: [
2189
+ legalInfo ? /* @__PURE__ */ jsx25("p", { children: legalInfo }) : null,
2190
+ copyright ? /* @__PURE__ */ jsx25("p", { children: copyright }) : null
2191
+ ] }),
2192
+ /* @__PURE__ */ jsxs19("nav", { className: "rt-tpl-footer-policy", "aria-label": "\uBC95\uC801 \uACE0\uC9C0", children: [
2193
+ privacyHref ? /* @__PURE__ */ jsx25("a", { href: privacyHref, children: "\uAC1C\uC778\uC815\uBCF4\uCC98\uB9AC\uBC29\uCE68" }) : null,
2194
+ termsHref ? /* @__PURE__ */ jsx25("a", { href: termsHref, children: "\uC774\uC6A9\uC57D\uAD00" }) : null,
2195
+ socialLinks?.map((link) => /* @__PURE__ */ jsx25("a", { href: link.href, children: link.kind }, `${link.kind}-${link.href}`))
2196
+ ] }),
2197
+ credit === "hidden" ? null : /* @__PURE__ */ jsxs19("p", { className: "rt-tpl-footer-credit", children: [
2198
+ "Website by",
2199
+ " ",
2200
+ /* @__PURE__ */ jsx25("a", { href: "https://roottale.com", target: "_blank", rel: "noopener", children: "RootTale" })
2201
+ ] })
2202
+ ] });
2203
+ }
2204
+ function TemplateFooterColumns(section) {
2205
+ const { columns, contactInfo } = section.props;
2206
+ return /* @__PURE__ */ jsx25(
2207
+ "footer",
2208
+ {
2209
+ role: "contentinfo",
2210
+ "data-roottale-tpl": "footer",
2211
+ "data-variant": "columns",
2212
+ id: section.id,
2213
+ className: "rt-tpl-footer",
2214
+ style: sectionThemeStyle(section.theme),
2215
+ children: /* @__PURE__ */ jsxs19("div", { className: "rt-tpl-container", children: [
2216
+ /* @__PURE__ */ jsxs19("div", { className: "rt-tpl-footer-columns", children: [
2217
+ /* @__PURE__ */ jsx25(FooterBrand, { ...section }),
2218
+ /* @__PURE__ */ jsx25("nav", { className: "rt-tpl-footer-nav", "aria-label": "\uD478\uD130 \uB9C1\uD06C", children: (columns ?? []).map((column) => /* @__PURE__ */ jsxs19("div", { className: "rt-tpl-footer-column", children: [
2219
+ /* @__PURE__ */ jsx25("p", { className: "rt-tpl-footer-column-title", children: column.title }),
2220
+ /* @__PURE__ */ jsx25("ul", { children: column.links.map((link) => /* @__PURE__ */ jsx25("li", { children: /* @__PURE__ */ jsx25("a", { href: link.href, children: link.label }) }, `${column.title}-${link.label}-${link.href}`)) })
2221
+ ] }, column.title)) }),
2222
+ /* @__PURE__ */ jsx25(FooterContact, { contactInfo })
2223
+ ] }),
2224
+ /* @__PURE__ */ jsx25(FooterLegal, { ...section })
2225
+ ] })
2226
+ }
2227
+ );
2228
+ }
2229
+ function TemplateFooterMinimal(section) {
2230
+ return /* @__PURE__ */ jsx25(
2231
+ "footer",
2232
+ {
2233
+ role: "contentinfo",
2234
+ "data-roottale-tpl": "footer",
2235
+ "data-variant": "minimal",
2236
+ id: section.id,
2237
+ className: "rt-tpl-footer rt-tpl-footer--minimal",
2238
+ style: sectionThemeStyle(section.theme),
2239
+ children: /* @__PURE__ */ jsxs19("div", { className: "rt-tpl-container", children: [
2240
+ /* @__PURE__ */ jsxs19("div", { className: "rt-tpl-footer-minimal-row", children: [
2241
+ /* @__PURE__ */ jsx25(FooterBrand, { ...section }),
2242
+ /* @__PURE__ */ jsx25(FooterContact, { contactInfo: section.props.contactInfo })
2243
+ ] }),
2244
+ /* @__PURE__ */ jsx25(FooterLegal, { ...section })
2245
+ ] })
2246
+ }
2247
+ );
2248
+ }
2249
+ function TemplateFooter(section) {
2250
+ if (section.variant === "minimal") return TemplateFooterMinimal(section);
2251
+ return TemplateFooterColumns(section);
2252
+ }
2253
+
2254
+ // src/templates/section-templates/faq.tsx
2255
+ import { Fragment as Fragment10, jsx as jsx26, jsxs as jsxs20 } from "react/jsx-runtime";
2256
+ function faqItemsForJsonLd(section) {
2257
+ if (section.props.groups && section.props.groups.length > 0) {
2258
+ return section.props.groups.flatMap((group) => group.items);
2259
+ }
2260
+ return section.props.items ?? [];
2261
+ }
2262
+ function TemplateFaqAccordion(section) {
2263
+ const { heading, items, contact } = section.props;
2264
+ const list = items ?? [];
2265
+ return /* @__PURE__ */ jsxs20(
2266
+ "div",
2267
+ {
2268
+ className: section.variant === "with-contact" ? "rt-tpl-faq-with-contact" : void 0,
2269
+ children: [
2270
+ /* @__PURE__ */ jsxs20("div", { children: [
2271
+ heading ? /* @__PURE__ */ jsx26("h2", { className: "rt-tpl-heading", children: heading }) : null,
2272
+ /* @__PURE__ */ jsx26("div", { className: "rt-tpl-faq-list", children: list.map((item, i) => /* @__PURE__ */ jsxs20("details", { className: "rt-tpl-faq-item", children: [
2273
+ /* @__PURE__ */ jsx26("summary", { className: "rt-tpl-faq-q", children: item.question }),
2274
+ /* @__PURE__ */ jsx26("p", { className: "rt-tpl-faq-a", children: item.answer })
2275
+ ] }, i)) })
2276
+ ] }),
2277
+ section.variant === "with-contact" && contact ? /* @__PURE__ */ jsxs20("aside", { className: "rt-tpl-faq-contact", "aria-label": "\uC0C1\uB2F4 \uBB38\uC758", children: [
2278
+ /* @__PURE__ */ jsx26("h3", { className: "rt-tpl-faq-contact-title", children: contact.title }),
2279
+ contact.description ? /* @__PURE__ */ jsx26("p", { className: "rt-tpl-faq-contact-desc", children: contact.description }) : null,
2280
+ contact.phone ? /* @__PURE__ */ jsx26(
2281
+ "a",
2282
+ {
2283
+ className: "rt-tpl-faq-contact-phone",
2284
+ href: telHref(contact.phone),
2285
+ "data-track": "cta_call",
2286
+ children: contact.phone
2287
+ }
2288
+ ) : null,
2289
+ contact.cta ? /* @__PURE__ */ jsx26(
2290
+ CtaLink,
2291
+ {
2292
+ cta: contact.cta,
2293
+ track: ctaTrackForHref(contact.cta.href),
2294
+ className: "rt-tpl-btn rt-tpl-btn--primary rt-tpl-faq-contact-cta"
2295
+ }
2296
+ ) : null
2297
+ ] }) : null
2298
+ ]
2299
+ }
2300
+ );
2301
+ }
2302
+ function TemplateFaqTwoColumn(section) {
2303
+ const { heading, items, groups } = section.props;
2304
+ const hasGroups = Boolean(groups && groups.length > 0);
2305
+ return /* @__PURE__ */ jsxs20(Fragment10, { children: [
2306
+ heading ? /* @__PURE__ */ jsx26("h2", { className: "rt-tpl-heading", children: heading }) : null,
2307
+ hasGroups ? /* @__PURE__ */ jsx26("div", { className: "rt-tpl-faq-groups", children: (groups ?? []).map((group) => /* @__PURE__ */ jsxs20("section", { className: "rt-tpl-faq-group", children: [
2308
+ /* @__PURE__ */ jsx26("h3", { className: "rt-tpl-faq-group-title", children: group.title }),
2309
+ /* @__PURE__ */ jsx26("div", { className: "rt-tpl-faq-two-column-list", children: group.items.map((item, i) => /* @__PURE__ */ jsxs20("article", { className: "rt-tpl-faq-open-item", children: [
2310
+ /* @__PURE__ */ jsx26("h4", { className: "rt-tpl-faq-open-q", children: item.question }),
2311
+ /* @__PURE__ */ jsx26("p", { className: "rt-tpl-faq-open-a", children: item.answer })
2312
+ ] }, `${group.title}-${i}`)) })
2313
+ ] }, group.title)) }) : /* @__PURE__ */ jsx26("div", { className: "rt-tpl-faq-two-column-list", children: (items ?? []).map((item, i) => /* @__PURE__ */ jsxs20("article", { className: "rt-tpl-faq-open-item", children: [
2314
+ /* @__PURE__ */ jsx26("h3", { className: "rt-tpl-faq-open-q", children: item.question }),
2315
+ /* @__PURE__ */ jsx26("p", { className: "rt-tpl-faq-open-a", children: item.answer })
2316
+ ] }, i)) })
2317
+ ] });
2318
+ }
2319
+ function TemplateFaqContentAccordion(section) {
2320
+ const { heading, contentGroups } = section.props;
2321
+ return /* @__PURE__ */ jsxs20(Fragment10, { children: [
2322
+ heading ? /* @__PURE__ */ jsx26("h2", { className: "rt-tpl-heading", children: heading }) : null,
2323
+ /* @__PURE__ */ jsx26("div", { className: "rt-tpl-faq-content-groups", children: (contentGroups ?? []).map((group) => /* @__PURE__ */ jsxs20("section", { className: "rt-tpl-faq-content-group", children: [
2324
+ /* @__PURE__ */ jsx26("h3", { className: "rt-tpl-faq-group-title", children: group.title }),
2325
+ /* @__PURE__ */ jsx26("div", { className: "rt-tpl-faq-list", children: group.items.map((item) => /* @__PURE__ */ jsxs20("details", { className: "rt-tpl-faq-item", children: [
2326
+ /* @__PURE__ */ jsxs20("summary", { className: "rt-tpl-faq-q", children: [
2327
+ /* @__PURE__ */ jsx26("span", { children: item.title }),
2328
+ item.summary ? /* @__PURE__ */ jsx26("small", { children: item.summary }) : null
2329
+ ] }),
2330
+ /* @__PURE__ */ jsxs20("div", { className: "rt-tpl-faq-a rt-tpl-faq-content-body", children: [
2331
+ /* @__PURE__ */ jsx26("p", { children: item.body }),
2332
+ item.signs && item.signs.length > 0 ? /* @__PURE__ */ jsx26("ul", { className: "rt-tpl-faq-content-signs", children: item.signs.map((sign) => /* @__PURE__ */ jsx26("li", { children: sign }, sign)) }) : null,
2333
+ item.href ? /* @__PURE__ */ jsx26("a", { className: "rt-tpl-faq-content-link", href: item.href, children: "\uC790\uC138\uD788 \uBCF4\uAE30" }) : null
2334
+ ] })
2335
+ ] }, item.title)) })
2336
+ ] }, group.title)) })
2337
+ ] });
2338
+ }
2339
+ function TemplateFaq(section) {
2340
+ const { jsonLd } = section.props;
2341
+ const jsonLdItems = faqItemsForJsonLd(section);
2342
+ return /* @__PURE__ */ jsxs20(
2343
+ "section",
2344
+ {
2345
+ "data-roottale-tpl": "faq",
2346
+ "data-variant": section.variant,
2347
+ id: section.id,
2348
+ className: "rt-tpl-section rt-tpl-faq",
2349
+ style: sectionThemeStyle(section.theme),
2350
+ children: [
2351
+ /* @__PURE__ */ jsx26("div", { className: "rt-tpl-container", children: section.variant === "content-accordion" ? TemplateFaqContentAccordion(section) : section.variant === "two-column" ? TemplateFaqTwoColumn(section) : TemplateFaqAccordion(section) }),
2352
+ section.variant !== "content-accordion" && jsonLd && jsonLdItems.length > 0 ? /* @__PURE__ */ jsx26(
2353
+ "script",
2354
+ {
2355
+ type: "application/ld+json",
2356
+ dangerouslySetInnerHTML: {
2357
+ __html: JSON.stringify({
2358
+ "@context": "https://schema.org",
2359
+ "@type": "FAQPage",
2360
+ mainEntity: jsonLdItems.map((item) => ({
2361
+ "@type": "Question",
2362
+ name: item.question,
2363
+ acceptedAnswer: { "@type": "Answer", text: item.answer }
2364
+ }))
2365
+ })
2366
+ }
2367
+ }
2368
+ ) : null
2369
+ ]
2370
+ }
2371
+ );
2372
+ }
2373
+
2374
+ // src/templates/section-templates/cta-banner.tsx
2375
+ import { jsx as jsx27, jsxs as jsxs21 } from "react/jsx-runtime";
2376
+ function TemplateCtaBannerPhotoOverlay(section) {
2377
+ const { title, description, cta, image, imageAlt } = section.props;
2378
+ return /* @__PURE__ */ jsx27(
2379
+ "section",
2380
+ {
2381
+ "data-roottale-tpl": "cta-banner",
2382
+ "data-variant": "photo-overlay",
2383
+ id: section.id,
2384
+ className: "rt-tpl-section rt-tpl-cta-banner rt-tpl-cta-banner--photo-overlay",
2385
+ style: sectionThemeStyle(section.theme),
2386
+ children: /* @__PURE__ */ jsxs21("div", { className: "rt-tpl-cta-banner-photo", children: [
2387
+ /* @__PURE__ */ jsx27(
2388
+ "img",
2389
+ {
2390
+ className: "rt-tpl-cta-banner-photo-img",
2391
+ src: image ?? "",
2392
+ alt: imageAlt ?? "",
2393
+ loading: "lazy"
2394
+ }
2395
+ ),
2396
+ /* @__PURE__ */ jsx27("div", { className: "rt-tpl-cta-banner-photo-scrim", "aria-hidden": "true" }),
2397
+ /* @__PURE__ */ jsxs21("div", { className: "rt-tpl-container rt-tpl-cta-banner-photo-inner", children: [
2398
+ /* @__PURE__ */ jsx27("h2", { className: "rt-tpl-cta-banner-photo-title", children: title }),
2399
+ description ? /* @__PURE__ */ jsx27("p", { className: "rt-tpl-cta-banner-photo-desc", children: description }) : null,
2400
+ cta ? /* @__PURE__ */ jsx27(
2401
+ CtaLink,
2402
+ {
2403
+ cta,
2404
+ track: "cta_banner",
2405
+ className: "rt-tpl-btn rt-tpl-btn--primary rt-tpl-cta-banner-photo-cta"
2406
+ }
2407
+ ) : null
2408
+ ] })
2409
+ ] })
2410
+ }
2411
+ );
2412
+ }
2413
+ function TemplateCtaBanner(section) {
2414
+ if (section.variant === "photo-overlay")
2415
+ return TemplateCtaBannerPhotoOverlay(section);
2416
+ const { title, description, cta } = section.props;
2417
+ return /* @__PURE__ */ jsx27(
2418
+ "section",
2419
+ {
2420
+ "data-roottale-tpl": "cta-banner",
2421
+ "data-variant": section.variant,
2422
+ id: section.id,
2423
+ className: "rt-tpl-section rt-tpl-cta-banner",
2424
+ style: sectionThemeStyle(section.theme),
2425
+ children: /* @__PURE__ */ jsxs21("div", { className: "rt-tpl-container rt-tpl-cta-banner-inner", children: [
2426
+ /* @__PURE__ */ jsx27("h2", { className: "rt-tpl-cta-banner-title", children: title }),
2427
+ description ? /* @__PURE__ */ jsx27("p", { className: "rt-tpl-cta-banner-desc", children: description }) : null,
2428
+ cta ? /* @__PURE__ */ jsx27(CtaLink, { cta, track: "cta_banner" }) : null
2429
+ ] })
2430
+ }
2431
+ );
2432
+ }
2433
+
2434
+ // src/templates/metric-value.ts
2435
+ var LEADING_NUMBER_PATTERN = /^(\d[\d,]*)(\.(\d+))?/;
2436
+ function parseMetricValue(raw) {
2437
+ const match = LEADING_NUMBER_PATTERN.exec(raw);
2438
+ if (!match) {
2439
+ return null;
2440
+ }
2441
+ const [matched, integerPart, , fractionPart] = match;
2442
+ const integerLiteral = (integerPart ?? "").replace(/,/g, "");
2443
+ const numericLiteral = fractionPart ? `${integerLiteral}.${fractionPart}` : integerLiteral;
2444
+ const value = Number(numericLiteral);
2445
+ if (!Number.isFinite(value)) {
2446
+ return null;
2447
+ }
2448
+ return {
2449
+ value,
2450
+ decimals: fractionPart?.length ?? 0,
2451
+ suffix: raw.slice(matched.length)
2452
+ };
2453
+ }
2454
+
2455
+ // src/templates/section-templates/trust.tsx
2456
+ import { Fragment as Fragment11, jsx as jsx28, jsxs as jsxs22 } from "react/jsx-runtime";
2457
+ function TrustMetricValue({ value }) {
2458
+ const parsed = parseMetricValue(value);
2459
+ if (!parsed) {
2460
+ return /* @__PURE__ */ jsx28(Fragment11, { children: value });
2461
+ }
2462
+ return /* @__PURE__ */ jsx28(
2463
+ CountUpStat,
2464
+ {
2465
+ value: parsed.value,
2466
+ decimals: parsed.decimals,
2467
+ suffix: parsed.suffix
2468
+ }
2469
+ );
2470
+ }
2471
+ function TrustCredentialIcon() {
2472
+ return /* @__PURE__ */ jsxs22(
2473
+ "svg",
2474
+ {
2475
+ className: "rt-cred__icon",
2476
+ viewBox: "0 0 16 16",
2477
+ "aria-hidden": "true",
2478
+ focusable: "false",
2479
+ children: [
2480
+ /* @__PURE__ */ jsx28("path", { d: "M8 1.75 13 3.5v3.75c0 3-2 5.45-5 7-3-1.55-5-4-5-7V3.5z" }),
2481
+ /* @__PURE__ */ jsx28("path", { d: "m5.75 8 1.45 1.45 3.2-3.4" })
2482
+ ]
2483
+ }
2484
+ );
2485
+ }
2486
+ function TemplateTrust(section) {
2487
+ const { heading, metrics, credentials, logos, marqueeLogos, chart, disclaimer } = section.props;
2488
+ const chartMax = chart?.points.reduce((max, point) => Math.max(max, point.value), 0) ?? 0;
2489
+ return /* @__PURE__ */ jsx28(
2490
+ "section",
2491
+ {
2492
+ "data-roottale-tpl": "trust",
2493
+ "data-variant": section.variant,
2494
+ id: section.id,
2495
+ className: "rt-tpl-section rt-tpl-trust",
2496
+ style: sectionThemeStyle(section.theme),
2497
+ children: /* @__PURE__ */ jsxs22("div", { className: "rt-tpl-container rt-tpl-trust-inner", children: [
2498
+ heading ? /* @__PURE__ */ jsx28("h2", { className: "rt-tpl-heading", children: heading }) : null,
2499
+ section.variant === "stat-band" ? (
2500
+ // 수치 밴드 진입 시 fade-up(C8) + 지표 숫자 카운트업(ADR-0086 D3로
2501
+ // 채택(구 룰 supersede, 2026-07-17)). reduce·SSR 시 <div> 그대로
2502
+ // (마크업 불변) + CountUpStat 자체도 mount 전엔 최종값 정적 표시.
2503
+ /* @__PURE__ */ jsx28(AnimateOnScroll, { as: "div", variant: "fade-up", className: "rt-tpl-trust-stat-band", children: (metrics ?? []).map((metric) => /* @__PURE__ */ jsxs22(
2504
+ "div",
2505
+ {
2506
+ className: "rt-stat",
2507
+ "data-variant": "band-item",
2508
+ children: [
2509
+ /* @__PURE__ */ jsxs22("span", { className: "rt-stat__value", children: [
2510
+ /* @__PURE__ */ jsx28(TrustMetricValue, { value: metric.value }),
2511
+ metric.unit ? /* @__PURE__ */ jsx28("span", { className: "rt-stat__unit", children: metric.unit }) : null
2512
+ ] }),
2513
+ /* @__PURE__ */ jsx28("span", { className: "rt-stat__label", children: metric.label }),
2514
+ metric.source ? /* @__PURE__ */ jsx28("span", { className: "rt-stat__source", children: metric.source }) : null
2515
+ ]
2516
+ },
2517
+ `${metric.value}-${metric.label}`
2518
+ )) })
2519
+ ) : null,
2520
+ section.variant === "logo-cloud" ? /* @__PURE__ */ jsx28("ul", { className: "rt-tpl-trust-logo-list", children: (logos ?? []).map((logo) => /* @__PURE__ */ jsx28("li", { className: "rt-tpl-trust-logo-item", children: logo.href ? /* @__PURE__ */ jsx28("a", { className: "rt-tpl-trust-logo-link", href: logo.href, children: /* @__PURE__ */ jsx28(
2521
+ "img",
2522
+ {
2523
+ className: "rt-tpl-trust-logo",
2524
+ src: logo.src,
2525
+ alt: logo.alt,
2526
+ loading: "lazy"
2527
+ }
2528
+ ) }) : /* @__PURE__ */ jsx28(
2529
+ "img",
2530
+ {
2531
+ className: "rt-tpl-trust-logo",
2532
+ src: logo.src,
2533
+ alt: logo.alt,
2534
+ loading: "lazy"
2535
+ }
2536
+ ) }, `${logo.src}-${logo.alt}`)) }) : null,
2537
+ section.variant === "feature-grid" ? /* @__PURE__ */ jsx28("ul", { className: "rt-tpl-trust-cred-list", children: (credentials ?? []).map((credential) => /* @__PURE__ */ jsx28("li", { children: /* @__PURE__ */ jsxs22("span", { className: "rt-cred", "data-kind": credential.kind, children: [
2538
+ /* @__PURE__ */ jsx28(TrustCredentialIcon, {}),
2539
+ /* @__PURE__ */ jsx28("span", { className: "rt-cred__label", children: credential.name }),
2540
+ credential.issuer ? /* @__PURE__ */ jsx28("span", { className: "rt-cred__issuer", children: credential.issuer }) : null
2541
+ ] }) }, `${credential.name}-${credential.issuer ?? ""}`)) }) : null,
2542
+ section.variant === "logo-marquee" ? (
2543
+ // C8 Marquee 소비(직접 재구현 금지, C10 §1-3). 로고는 흑백/저채도
2544
+ // 처리(CSS filter) — hover 시에만 원색 복원.
2545
+ /* @__PURE__ */ jsx28(
2546
+ Marquee,
2547
+ {
2548
+ className: "rt-tpl-trust-marquee",
2549
+ ariaLabel: heading ?? "\uD30C\uD2B8\uB108/\uC778\uC99D \uB85C\uACE0",
2550
+ children: (marqueeLogos ?? []).map(
2551
+ (logo, i) => logo.href ? /* @__PURE__ */ jsx28(
2552
+ "a",
2553
+ {
2554
+ className: "rt-tpl-trust-marquee-link",
2555
+ href: logo.href,
2556
+ children: /* @__PURE__ */ jsx28(
2557
+ "img",
2558
+ {
2559
+ className: "rt-tpl-trust-marquee-logo",
2560
+ src: logo.src,
2561
+ alt: logo.alt,
2562
+ loading: "lazy"
2563
+ }
2564
+ )
2565
+ },
2566
+ `${logo.alt}-${i}`
2567
+ ) : /* @__PURE__ */ jsx28(
2568
+ "img",
2569
+ {
2570
+ className: "rt-tpl-trust-marquee-logo",
2571
+ src: logo.src,
2572
+ alt: logo.alt,
2573
+ loading: "lazy"
2574
+ },
2575
+ `${logo.alt}-${i}`
2576
+ )
2577
+ )
2578
+ }
2579
+ )
2580
+ ) : null,
2581
+ section.variant === "credential-list" ? (
2582
+ // hairline 자격·이력·수상 리스트 — 연도는 tabular-nums, 위계는
2583
+ // 작은 크기로(AI-slop #3 대체: 장식용 큰 숫자 금지).
2584
+ /* @__PURE__ */ jsx28("ol", { className: "rt-tpl-trust-credential-list", children: (credentials ?? []).map((credential, i) => /* @__PURE__ */ jsxs22(
2585
+ "li",
2586
+ {
2587
+ className: "rt-tpl-trust-credential-row",
2588
+ children: [
2589
+ credential.year ? /* @__PURE__ */ jsx28("span", { className: "rt-tpl-trust-credential-year", children: credential.year }) : null,
2590
+ /* @__PURE__ */ jsx28("span", { className: "rt-tpl-trust-credential-name", children: credential.name }),
2591
+ credential.issuer ? /* @__PURE__ */ jsx28("span", { className: "rt-tpl-trust-credential-issuer", children: credential.issuer }) : null
2592
+ ]
2593
+ },
2594
+ `${credential.name}-${credential.year ?? i}`
2595
+ )) })
2596
+ ) : null,
2597
+ section.variant === "dashboard" && chart ? /* @__PURE__ */ jsxs22("div", { className: "rt-tpl-trust-dashboard", children: [
2598
+ /* @__PURE__ */ jsxs22("div", { className: "rt-tpl-trust-dashboard-chart", children: [
2599
+ /* @__PURE__ */ jsxs22("div", { children: [
2600
+ /* @__PURE__ */ jsx28("h3", { className: "rt-tpl-trust-dashboard-title", children: chart.title }),
2601
+ chart.description ? /* @__PURE__ */ jsx28("p", { className: "rt-tpl-trust-dashboard-desc", children: chart.description }) : null
2602
+ ] }),
2603
+ /* @__PURE__ */ jsx28(
2604
+ "ul",
2605
+ {
2606
+ className: "rt-tpl-trust-dashboard-bars",
2607
+ "data-chart-type": chart.type,
2608
+ children: chart.points.map((point) => {
2609
+ const percent = chartMax > 0 ? `${Math.max(4, Math.round(point.value / chartMax * 100))}%` : "4%";
2610
+ return /* @__PURE__ */ jsxs22("li", { children: [
2611
+ /* @__PURE__ */ jsx28("span", { children: point.label }),
2612
+ /* @__PURE__ */ jsx28("span", { className: "rt-tpl-trust-dashboard-track", children: /* @__PURE__ */ jsx28(
2613
+ "span",
2614
+ {
2615
+ className: "rt-tpl-trust-dashboard-bar",
2616
+ style: { inlineSize: percent }
2617
+ }
2618
+ ) }),
2619
+ /* @__PURE__ */ jsx28("strong", { children: point.display ?? String(point.value) })
2620
+ ] }, point.label);
2621
+ })
2622
+ }
2623
+ )
2624
+ ] }),
2625
+ /* @__PURE__ */ jsx28("ul", { className: "rt-tpl-trust-dashboard-metrics", children: (metrics ?? []).map((metric) => /* @__PURE__ */ jsxs22("li", { className: "rt-stat", children: [
2626
+ metric.imageSrc ? /* @__PURE__ */ jsx28(
2627
+ "img",
2628
+ {
2629
+ className: "rt-tpl-trust-dashboard-icon",
2630
+ src: metric.imageSrc,
2631
+ alt: metric.imageAlt ?? "",
2632
+ loading: "lazy"
2633
+ }
2634
+ ) : null,
2635
+ /* @__PURE__ */ jsxs22("span", { className: "rt-stat__value", children: [
2636
+ /* @__PURE__ */ jsx28(TrustMetricValue, { value: metric.value }),
2637
+ metric.unit ? /* @__PURE__ */ jsx28("span", { className: "rt-stat__unit", children: metric.unit }) : null
2638
+ ] }),
2639
+ /* @__PURE__ */ jsx28("span", { className: "rt-stat__label", children: metric.label }),
2640
+ metric.source ? /* @__PURE__ */ jsx28("span", { className: "rt-stat__source", children: metric.source }) : null
2641
+ ] }, `${metric.value}-${metric.label}`)) })
2642
+ ] }) : null,
2643
+ disclaimer ? /* @__PURE__ */ jsx28("p", { className: "rt-tpl-trust-disclaimer", children: disclaimer }) : null
2644
+ ] })
2645
+ }
2646
+ );
2647
+ }
2648
+
2649
+ // src/templates/section-templates/testimonials-editorial.tsx
2650
+ import { jsx as jsx29, jsxs as jsxs23 } from "react/jsx-runtime";
2651
+ function TemplateTestimonialsEditorialQuote(section) {
2652
+ const { heading, description, items, disclaimer } = section.props;
2653
+ const layout = items.length > 1 ? "stack" : "single";
2654
+ return /* @__PURE__ */ jsx29(
2655
+ "section",
2656
+ {
2657
+ "data-roottale-tpl": "testimonials",
2658
+ "data-variant": "editorial-quote",
2659
+ id: section.id,
2660
+ className: "rt-tpl-section rt-tpl-testimonials",
2661
+ style: sectionThemeStyle(section.theme),
2662
+ children: /* @__PURE__ */ jsxs23("div", { className: "rt-tpl-container", children: [
2663
+ /* @__PURE__ */ jsx29("h2", { className: "rt-tpl-heading", children: heading }),
2664
+ description ? /* @__PURE__ */ jsx29("p", { className: "rt-tpl-section-desc", children: description }) : null,
2665
+ /* @__PURE__ */ jsx29(
2666
+ StaggerGroup,
2667
+ {
2668
+ as: "ul",
2669
+ className: `rt-tpl-testimonials-editorial-list rt-tpl-testimonials-editorial-list--${layout}`,
2670
+ children: items.map((item, i) => /* @__PURE__ */ jsx29(
2671
+ StaggerItem,
2672
+ {
2673
+ as: "li",
2674
+ className: "rt-tpl-testimonials-editorial-item",
2675
+ children: /* @__PURE__ */ jsxs23("blockquote", { className: "rt-tpl-testimonials-editorial-quote", children: [
2676
+ /* @__PURE__ */ jsx29("p", { className: "rt-tpl-testimonials-editorial-text", children: item.quote }),
2677
+ /* @__PURE__ */ jsxs23("footer", { className: "rt-tpl-testimonials-editorial-footer", children: [
2678
+ /* @__PURE__ */ jsx29("cite", { className: "rt-tpl-testimonials-editorial-author", children: item.author }),
2679
+ item.context ? /* @__PURE__ */ jsx29("span", { className: "rt-tpl-testimonials-editorial-context", children: item.context }) : null,
2680
+ /* @__PURE__ */ jsx29(TestimonialMeta, { item })
2681
+ ] }),
2682
+ item.reply ? /* @__PURE__ */ jsx29("p", { className: "rt-tpl-testimonials-reply", children: item.reply }) : null
2683
+ ] })
2684
+ },
2685
+ `${item.author}-${i}`
2686
+ ))
2687
+ }
2688
+ ),
2689
+ disclaimer ? /* @__PURE__ */ jsx29("p", { className: "rt-tpl-testimonials-disclaimer", children: disclaimer }) : null
2690
+ ] })
2691
+ }
2692
+ );
2693
+ }
2694
+ function TestimonialMeta({
2695
+ item
2696
+ }) {
2697
+ const values = [
2698
+ typeof item.rating === "number" ? `\uD3C9\uC810 ${item.rating.toFixed(1)}` : void 0,
2699
+ item.source,
2700
+ item.visitedAt,
2701
+ item.item
2702
+ ].filter((value) => Boolean(value));
2703
+ if (values.length === 0) return null;
2704
+ return /* @__PURE__ */ jsx29("span", { className: "rt-tpl-testimonials-meta", children: values.map((value) => /* @__PURE__ */ jsx29("span", { children: value }, value)) });
2705
+ }
2706
+
2707
+ // src/templates/section-templates/testimonials-rail.tsx
2708
+ import { jsx as jsx30, jsxs as jsxs24 } from "react/jsx-runtime";
2709
+ function TemplateTestimonialsQuoteRail(section) {
2710
+ const { heading, description, items, marquee, disclaimer } = section.props;
2711
+ return /* @__PURE__ */ jsx30(
2712
+ "section",
2713
+ {
2714
+ "data-roottale-tpl": "testimonials",
2715
+ "data-variant": "quote-rail",
2716
+ id: section.id,
2717
+ className: "rt-tpl-section rt-tpl-testimonials",
2718
+ style: sectionThemeStyle(section.theme),
2719
+ children: /* @__PURE__ */ jsxs24("div", { className: "rt-tpl-container", children: [
2720
+ /* @__PURE__ */ jsx30("h2", { className: "rt-tpl-heading", children: heading }),
2721
+ description ? /* @__PURE__ */ jsx30("p", { className: "rt-tpl-section-desc", children: description }) : null,
2722
+ /* @__PURE__ */ jsx30(
2723
+ AnimateOnScroll,
2724
+ {
2725
+ as: "div",
2726
+ variant: "fade-up",
2727
+ className: "rt-tpl-testimonials-rail-viewport",
2728
+ children: /* @__PURE__ */ jsx30(
2729
+ "ul",
2730
+ {
2731
+ className: marquee ? "rt-tpl-testimonials-rail rt-tpl-testimonials-rail--marquee" : "rt-tpl-testimonials-rail",
2732
+ "data-marquee": marquee ? "true" : void 0,
2733
+ children: items.map((item, i) => /* @__PURE__ */ jsx30(
2734
+ "li",
2735
+ {
2736
+ className: "rt-tpl-testimonials-rail-item",
2737
+ children: /* @__PURE__ */ jsxs24("blockquote", { className: "rt-tpl-testimonials-rail-quote", children: [
2738
+ /* @__PURE__ */ jsx30("p", { className: "rt-tpl-testimonials-rail-text", children: item.quote }),
2739
+ /* @__PURE__ */ jsxs24("footer", { className: "rt-tpl-testimonials-rail-footer", children: [
2740
+ /* @__PURE__ */ jsx30("cite", { className: "rt-tpl-testimonials-rail-author", children: item.author }),
2741
+ item.context ? /* @__PURE__ */ jsx30("span", { className: "rt-tpl-testimonials-rail-context", children: item.context }) : null,
2742
+ /* @__PURE__ */ jsx30(TestimonialMeta, { item })
2743
+ ] }),
2744
+ item.reply ? /* @__PURE__ */ jsx30("p", { className: "rt-tpl-testimonials-reply", children: item.reply }) : null
2745
+ ] })
2746
+ },
2747
+ `${item.author}-${i}`
2748
+ ))
2749
+ }
2750
+ )
2751
+ }
2752
+ ),
2753
+ disclaimer ? /* @__PURE__ */ jsx30("p", { className: "rt-tpl-testimonials-disclaimer", children: disclaimer }) : null
2754
+ ] })
2755
+ }
2756
+ );
2757
+ }
2758
+
2759
+ // src/templates/section-templates/testimonials-star.tsx
2760
+ import { jsx as jsx31, jsxs as jsxs25 } from "react/jsx-runtime";
2761
+ function StarRating({ rating }) {
2762
+ const clamped = Math.min(5, Math.max(0, rating));
2763
+ const fill = `${(clamped / 5 * 100).toFixed(0)}%`;
2764
+ return /* @__PURE__ */ jsxs25(
2765
+ "span",
2766
+ {
2767
+ className: "rt-tpl-testimonials-stars",
2768
+ role: "img",
2769
+ "aria-label": `\uD3C9\uC810 5\uC810 \uB9CC\uC810\uC5D0 ${clamped.toFixed(1)}\uC810`,
2770
+ style: { "--rt-testimonials-star-fill": fill },
2771
+ children: [
2772
+ /* @__PURE__ */ jsx31("span", { "aria-hidden": "true", className: "rt-tpl-testimonials-stars-base", children: "\u2605\u2605\u2605\u2605\u2605" }),
2773
+ /* @__PURE__ */ jsx31("span", { "aria-hidden": "true", className: "rt-tpl-testimonials-stars-fill", children: "\u2605\u2605\u2605\u2605\u2605" })
2774
+ ]
2775
+ }
2776
+ );
2777
+ }
2778
+ function TemplateTestimonialsStarCompact(section) {
2779
+ const { heading, description, items, disclaimer } = section.props;
2780
+ const rated = items.filter(
2781
+ (item) => typeof item.rating === "number"
2782
+ );
2783
+ const average = rated.length > 0 ? rated.reduce((sum, item) => sum + item.rating, 0) / rated.length : void 0;
2784
+ return /* @__PURE__ */ jsx31(
2785
+ "section",
2786
+ {
2787
+ "data-roottale-tpl": "testimonials",
2788
+ "data-variant": "star-compact",
2789
+ id: section.id,
2790
+ className: "rt-tpl-section rt-tpl-testimonials",
2791
+ style: sectionThemeStyle(section.theme),
2792
+ children: /* @__PURE__ */ jsxs25("div", { className: "rt-tpl-container", children: [
2793
+ /* @__PURE__ */ jsx31("h2", { className: "rt-tpl-heading", children: heading }),
2794
+ description ? /* @__PURE__ */ jsx31("p", { className: "rt-tpl-section-desc", children: description }) : null,
2795
+ average !== void 0 ? /* @__PURE__ */ jsxs25("div", { className: "rt-tpl-testimonials-star-summary", children: [
2796
+ /* @__PURE__ */ jsx31("span", { className: "rt-tpl-testimonials-star-average", children: average.toFixed(1) }),
2797
+ /* @__PURE__ */ jsx31(StarRating, { rating: average }),
2798
+ /* @__PURE__ */ jsxs25("span", { className: "rt-tpl-testimonials-star-count", children: [
2799
+ "\uD6C4\uAE30 ",
2800
+ items.length,
2801
+ "\uAC74"
2802
+ ] })
2803
+ ] }) : null,
2804
+ /* @__PURE__ */ jsx31(StaggerGroup, { as: "ul", className: "rt-tpl-testimonials-star-list", children: items.map((item, i) => /* @__PURE__ */ jsx31(
2805
+ StaggerItem,
2806
+ {
2807
+ as: "li",
2808
+ className: "rt-tpl-testimonials-star-item",
2809
+ children: /* @__PURE__ */ jsxs25("blockquote", { className: "rt-tpl-testimonials-star-quote", children: [
2810
+ typeof item.rating === "number" ? /* @__PURE__ */ jsxs25("div", { className: "rt-tpl-testimonials-star-head", children: [
2811
+ /* @__PURE__ */ jsx31(StarRating, { rating: item.rating }),
2812
+ /* @__PURE__ */ jsx31("span", { className: "rt-tpl-testimonials-star-value", children: item.rating.toFixed(1) })
2813
+ ] }) : null,
2814
+ /* @__PURE__ */ jsx31("p", { className: "rt-tpl-testimonials-star-text", children: item.quote }),
2815
+ /* @__PURE__ */ jsxs25("footer", { className: "rt-tpl-testimonials-star-footer", children: [
2816
+ /* @__PURE__ */ jsx31("cite", { className: "rt-tpl-testimonials-star-author", children: item.author }),
2817
+ item.context ? /* @__PURE__ */ jsx31("span", { className: "rt-tpl-testimonials-star-context", children: item.context }) : null,
2818
+ /* @__PURE__ */ jsx31(StarCompactMeta, { item })
2819
+ ] }),
2820
+ item.reply ? /* @__PURE__ */ jsx31("p", { className: "rt-tpl-testimonials-reply", children: item.reply }) : null
2821
+ ] })
2822
+ },
2823
+ `${item.author}-${i}`
2824
+ )) }),
2825
+ disclaimer ? /* @__PURE__ */ jsx31("p", { className: "rt-tpl-testimonials-disclaimer", children: disclaimer }) : null
2826
+ ] })
2827
+ }
2828
+ );
2829
+ }
2830
+ function StarCompactMeta({
2831
+ item
2832
+ }) {
2833
+ const values = [item.source, item.visitedAt, item.item].filter(
2834
+ (value) => Boolean(value)
2835
+ );
2836
+ if (values.length === 0) return null;
2837
+ return /* @__PURE__ */ jsx31("span", { className: "rt-tpl-testimonials-star-meta", children: values.map((value) => /* @__PURE__ */ jsx31("span", { children: value }, value)) });
2838
+ }
2839
+
2840
+ // src/templates/section-templates/testimonials.tsx
2841
+ function TemplateTestimonials(section) {
2842
+ switch (section.variant) {
2843
+ case "quote-rail":
2844
+ return TemplateTestimonialsQuoteRail(section);
2845
+ case "star-compact":
2846
+ return TemplateTestimonialsStarCompact(section);
2847
+ default:
2848
+ return TemplateTestimonialsEditorialQuote(section);
2849
+ }
2850
+ }
2851
+
2852
+ // src/templates/section-templates/team.tsx
2853
+ import { jsx as jsx32, jsxs as jsxs26 } from "react/jsx-runtime";
2854
+ function memberInitials(name) {
2855
+ const parts = name.trim().split(/\s+/).filter(Boolean);
2856
+ if (parts.length === 0) return "?";
2857
+ const initials = parts.slice(0, 2).map((part) => part.at(0) ?? "").join("");
2858
+ return initials || "?";
2859
+ }
2860
+ function TeamMemberPhoto({
2861
+ member,
2862
+ featured = false
2863
+ }) {
2864
+ if (member.photoSrc) {
2865
+ return /* @__PURE__ */ jsx32(
2866
+ "img",
2867
+ {
2868
+ className: featured ? "rt-tpl-team-photo rt-tpl-team-photo--featured" : "rt-tpl-team-photo",
2869
+ src: member.photoSrc,
2870
+ alt: member.photoAlt ?? "",
2871
+ loading: "lazy"
2872
+ }
2873
+ );
2874
+ }
2875
+ return /* @__PURE__ */ jsx32(
2876
+ "div",
2877
+ {
2878
+ className: featured ? "rt-tpl-team-initials rt-tpl-team-initials--featured" : "rt-tpl-team-initials",
2879
+ "aria-hidden": "true",
2880
+ children: memberInitials(member.name)
2881
+ }
2882
+ );
2883
+ }
2884
+ function TeamMemberBody({
2885
+ member
2886
+ }) {
2887
+ return /* @__PURE__ */ jsxs26("div", { className: "rt-tpl-team-body", children: [
2888
+ /* @__PURE__ */ jsx32("h3", { className: "rt-tpl-team-name", children: member.name }),
2889
+ /* @__PURE__ */ jsx32("p", { className: "rt-tpl-team-title", children: member.title }),
2890
+ member.specialties ? /* @__PURE__ */ jsx32("ul", { className: "rt-tpl-team-specialties", "aria-label": `${member.name} \uC804\uBB38 \uBD84\uC57C`, children: member.specialties.map((specialty) => /* @__PURE__ */ jsx32("li", { children: specialty }, specialty)) }) : null,
2891
+ member.credentials ? /* @__PURE__ */ jsx32("ul", { className: "rt-tpl-team-credentials", children: member.credentials.map((credential) => /* @__PURE__ */ jsx32("li", { children: credential }, credential)) }) : null,
2892
+ member.bio ? /* @__PURE__ */ jsx32("p", { className: "rt-tpl-team-bio", children: member.bio }) : null,
2893
+ member.href ? /* @__PURE__ */ jsx32("a", { className: "rt-tpl-team-cta", href: member.href, children: member.ctaLabel ?? "\uD504\uB85C\uD544 \uBCF4\uAE30" }) : null
2894
+ ] });
2895
+ }
2896
+ function TemplateTeamGrid(section) {
2897
+ const { heading, description, members } = section.props;
2898
+ return /* @__PURE__ */ jsx32(
2899
+ "section",
2900
+ {
2901
+ "data-roottale-tpl": "team",
2902
+ "data-variant": "grid",
2903
+ id: section.id,
2904
+ className: "rt-tpl-section rt-tpl-team",
2905
+ style: sectionThemeStyle(section.theme),
2906
+ children: /* @__PURE__ */ jsxs26("div", { className: "rt-tpl-container", children: [
2907
+ heading ? /* @__PURE__ */ jsx32("h2", { className: "rt-tpl-heading", children: heading }) : null,
2908
+ description ? /* @__PURE__ */ jsx32("p", { className: "rt-tpl-section-desc", children: description }) : null,
2909
+ /* @__PURE__ */ jsx32(StaggerGroup, { as: "ul", className: "rt-tpl-team-grid", children: members.map((member) => /* @__PURE__ */ jsxs26(StaggerItem, { as: "li", className: "rt-tpl-team-card", children: [
2910
+ /* @__PURE__ */ jsx32(TeamMemberPhoto, { member }),
2911
+ /* @__PURE__ */ jsx32(TeamMemberBody, { member })
2912
+ ] }, member.name)) })
2913
+ ] })
2914
+ }
2915
+ );
2916
+ }
2917
+ function TemplateTeamSpotlight(section) {
2918
+ const { heading, description, members } = section.props;
2919
+ const [featured, ...rest] = members;
2920
+ return /* @__PURE__ */ jsx32(
2921
+ "section",
2922
+ {
2923
+ "data-roottale-tpl": "team",
2924
+ "data-variant": "spotlight",
2925
+ id: section.id,
2926
+ className: "rt-tpl-section rt-tpl-team",
2927
+ style: sectionThemeStyle(section.theme),
2928
+ children: /* @__PURE__ */ jsxs26("div", { className: "rt-tpl-container", children: [
2929
+ heading ? /* @__PURE__ */ jsx32("h2", { className: "rt-tpl-heading", children: heading }) : null,
2930
+ description ? /* @__PURE__ */ jsx32("p", { className: "rt-tpl-section-desc", children: description }) : null,
2931
+ /* @__PURE__ */ jsxs26("div", { className: "rt-tpl-team-spotlight", children: [
2932
+ featured ? /* @__PURE__ */ jsxs26("article", { className: "rt-tpl-team-card rt-tpl-team-card--featured", children: [
2933
+ /* @__PURE__ */ jsx32(TeamMemberPhoto, { member: featured, featured: true }),
2934
+ /* @__PURE__ */ jsx32(TeamMemberBody, { member: featured })
2935
+ ] }) : null,
2936
+ /* @__PURE__ */ jsx32(StaggerGroup, { as: "ul", className: "rt-tpl-team-spotlight-list", children: rest.map((member) => /* @__PURE__ */ jsxs26(StaggerItem, { as: "li", className: "rt-tpl-team-card", children: [
2937
+ /* @__PURE__ */ jsx32(TeamMemberPhoto, { member }),
2938
+ /* @__PURE__ */ jsx32(TeamMemberBody, { member })
2939
+ ] }, member.name)) })
2940
+ ] })
2941
+ ] })
2942
+ }
2943
+ );
2944
+ }
2945
+ function TemplateTeamExpandingStage(section) {
2946
+ const { heading, description, members } = section.props;
2947
+ return /* @__PURE__ */ jsx32(
2948
+ "section",
2949
+ {
2950
+ "data-roottale-tpl": "team",
2951
+ "data-variant": "expanding-stage",
2952
+ id: section.id,
2953
+ className: "rt-tpl-section rt-tpl-team",
2954
+ style: sectionThemeStyle(section.theme),
2955
+ children: /* @__PURE__ */ jsxs26("div", { className: "rt-tpl-container", children: [
2956
+ heading ? /* @__PURE__ */ jsx32("h2", { className: "rt-tpl-heading", children: heading }) : null,
2957
+ description ? /* @__PURE__ */ jsx32("p", { className: "rt-tpl-section-desc", children: description }) : null,
2958
+ /* @__PURE__ */ jsx32(TeamExpandingStageClient, { members })
2959
+ ] })
2960
+ }
2961
+ );
2962
+ }
2963
+ function TemplateTeamRow(section) {
2964
+ const { heading, description, members } = section.props;
2965
+ return /* @__PURE__ */ jsx32(
2966
+ "section",
2967
+ {
2968
+ "data-roottale-tpl": "team",
2969
+ "data-variant": "row",
2970
+ id: section.id,
2971
+ className: "rt-tpl-section rt-tpl-team",
2972
+ style: sectionThemeStyle(section.theme),
2973
+ children: /* @__PURE__ */ jsxs26("div", { className: "rt-tpl-container", children: [
2974
+ heading ? /* @__PURE__ */ jsx32("h2", { className: "rt-tpl-heading", children: heading }) : null,
2975
+ description ? /* @__PURE__ */ jsx32("p", { className: "rt-tpl-section-desc", children: description }) : null,
2976
+ /* @__PURE__ */ jsx32(StaggerGroup, { as: "ul", className: "rt-tpl-team-row-list", children: members.map((member) => /* @__PURE__ */ jsx32(StaggerItem, { as: "li", className: "rt-tpl-team-row-item", children: /* @__PURE__ */ jsxs26("article", { className: "rt-tpl-team-card rt-tpl-team-card--row", children: [
2977
+ /* @__PURE__ */ jsx32(TeamMemberPhoto, { member }),
2978
+ /* @__PURE__ */ jsx32(TeamMemberBody, { member })
2979
+ ] }) }, member.name)) })
2980
+ ] })
2981
+ }
2982
+ );
2983
+ }
2984
+ function TemplateTeam(section) {
2985
+ if (section.variant === "expanding-stage")
2986
+ return TemplateTeamExpandingStage(section);
2987
+ if (section.variant === "row") return TemplateTeamRow(section);
2988
+ if (section.variant === "spotlight") return TemplateTeamSpotlight(section);
2989
+ return TemplateTeamGrid(section);
2990
+ }
2991
+
2992
+ // src/templates/section-templates/contact-shared.tsx
2993
+ import { isAllowedEmbedSrc as isAllowedEmbedSrc2, isAllowedMapEmbedSrc } from "@roottale/cms-core";
2994
+ import { jsx as jsx33, jsxs as jsxs27 } from "react/jsx-runtime";
2995
+ function ContactMap({ url }) {
2996
+ if (isAllowedMapEmbedSrc(url) || isAllowedEmbedSrc2(url)) {
2997
+ return /* @__PURE__ */ jsx33("div", { className: "rt-tpl-contact-map", children: /* @__PURE__ */ jsx33(
2998
+ "iframe",
2999
+ {
3000
+ src: url,
3001
+ title: "\uC624\uC2DC\uB294\uAE38 \uC9C0\uB3C4",
3002
+ loading: "lazy",
3003
+ referrerPolicy: "no-referrer-when-downgrade"
3004
+ }
3005
+ ) });
3006
+ }
3007
+ return /* @__PURE__ */ jsx33("p", { className: "rt-tpl-contact-map-fallback", children: /* @__PURE__ */ jsx33("a", { href: url, rel: "noopener noreferrer", target: "_blank", children: "\uAE38\uCC3E\uAE30" }) });
3008
+ }
3009
+ function ContactMapBlock({
3010
+ map,
3011
+ mapEmbedUrl
3012
+ }) {
3013
+ const embedUrl = map?.embedUrl ?? mapEmbedUrl;
3014
+ const externalUrl = map?.externalUrl ?? embedUrl;
3015
+ if (!embedUrl && !map?.facadeImageSrc && !externalUrl) return null;
3016
+ const liveMap = Boolean(
3017
+ embedUrl && (isAllowedMapEmbedSrc(embedUrl) || isAllowedEmbedSrc2(embedUrl))
3018
+ );
3019
+ const clickToLoad = liveMap && embedUrl && (map?.mapLoad ?? "lazy") === "click";
3020
+ return /* @__PURE__ */ jsxs27("div", { className: "rt-tpl-contact-map-block", "data-provider": map?.provider, children: [
3021
+ map?.facadeImageSrc && !liveMap ? /* @__PURE__ */ jsxs27("figure", { className: "rt-tpl-contact-map-facade", children: [
3022
+ /* @__PURE__ */ jsx33(
3023
+ "img",
3024
+ {
3025
+ src: map.facadeImageSrc,
3026
+ alt: map.facadeImageAlt ?? "",
3027
+ loading: "lazy"
3028
+ }
3029
+ ),
3030
+ externalUrl ? /* @__PURE__ */ jsx33("figcaption", { children: /* @__PURE__ */ jsx33("a", { href: externalUrl, target: "_blank", rel: "noopener noreferrer", children: "\uC9C0\uB3C4 \uD06C\uAC8C \uBCF4\uAE30" }) }) : null
3031
+ ] }) : null,
3032
+ clickToLoad ? /* @__PURE__ */ jsx33(
3033
+ ContactMapClickToLoad,
3034
+ {
3035
+ embedUrl,
3036
+ externalUrl,
3037
+ facadeImageSrc: map?.facadeImageSrc,
3038
+ facadeImageAlt: map?.facadeImageAlt
3039
+ }
3040
+ ) : embedUrl ? /* @__PURE__ */ jsx33(ContactMap, { url: embedUrl }) : null
3041
+ ] });
3042
+ }
3043
+ function ContactActions({
3044
+ actions
3045
+ }) {
3046
+ if (!actions || actions.length === 0) return null;
3047
+ return /* @__PURE__ */ jsx33("ul", { className: "rt-tpl-contact-actions", children: actions.map((action) => {
3048
+ const track = contactHrefTrack(action.href);
3049
+ return /* @__PURE__ */ jsx33("li", { "data-kind": action.kind, children: /* @__PURE__ */ jsx33(
3050
+ "a",
3051
+ {
3052
+ href: action.href,
3053
+ "data-track": track,
3054
+ "data-track-placement": track ? "contact_actions" : void 0,
3055
+ children: action.label
3056
+ }
3057
+ ) }, `${action.label}-${action.href}`);
3058
+ }) });
3059
+ }
3060
+
3061
+ // src/templates/section-templates/contact-channels.tsx
3062
+ import { Fragment as Fragment12, jsx as jsx34, jsxs as jsxs28 } from "react/jsx-runtime";
3063
+ function contactChannelTracking(href) {
3064
+ if (href.startsWith("tel:")) {
3065
+ return { track: "cta_call" };
3066
+ }
3067
+ if (href.startsWith("mailto:")) {
3068
+ return { track: "email_click", placement: "contact_channels" };
3069
+ }
3070
+ return { track: "cta_banner" };
3071
+ }
3072
+ function TemplateContactChannelCards(section) {
3073
+ const { heading, channels, map, mapEmbedUrl, actions } = section.props;
3074
+ return /* @__PURE__ */ jsx34(
3075
+ "section",
3076
+ {
3077
+ "data-roottale-tpl": "contact",
3078
+ "data-variant": "channel-cards",
3079
+ id: section.id,
3080
+ className: "rt-tpl-section rt-tpl-contact",
3081
+ style: sectionThemeStyle(section.theme),
3082
+ children: /* @__PURE__ */ jsxs28("div", { className: "rt-tpl-container", children: [
3083
+ heading ? /* @__PURE__ */ jsx34("h2", { className: "rt-tpl-heading", children: heading }) : null,
3084
+ /* @__PURE__ */ jsxs28("div", { className: "rt-tpl-contact-channel-layout", children: [
3085
+ /* @__PURE__ */ jsx34("ul", { className: "rt-tpl-contact-channel-list", children: (channels ?? []).map((channel) => {
3086
+ const tracking = channel.href ? contactChannelTracking(channel.href) : void 0;
3087
+ const content = /* @__PURE__ */ jsxs28(Fragment12, { children: [
3088
+ /* @__PURE__ */ jsxs28("span", { className: "rt-tpl-contact-channel-label", children: [
3089
+ channel.iconSrc ? /* @__PURE__ */ jsx34(
3090
+ "img",
3091
+ {
3092
+ className: "rt-tpl-contact-channel-icon",
3093
+ src: channel.iconSrc,
3094
+ alt: channel.iconAlt ?? "",
3095
+ loading: "lazy"
3096
+ }
3097
+ ) : null,
3098
+ channel.label
3099
+ ] }),
3100
+ channel.value ? /* @__PURE__ */ jsx34("span", { className: "rt-tpl-contact-channel-value", children: channel.value }) : null,
3101
+ channel.description ? /* @__PURE__ */ jsx34("span", { className: "rt-tpl-contact-channel-desc", children: channel.description }) : null,
3102
+ channel.href && channel.actionLabel ? /* @__PURE__ */ jsx34("span", { className: "rt-tpl-contact-channel-action", children: channel.actionLabel }) : null
3103
+ ] });
3104
+ return /* @__PURE__ */ jsx34(
3105
+ "li",
3106
+ {
3107
+ "data-kind": channel.kind,
3108
+ children: channel.href ? /* @__PURE__ */ jsx34(
3109
+ "a",
3110
+ {
3111
+ className: "rt-tpl-contact-channel-card",
3112
+ href: channel.href,
3113
+ "data-track": tracking?.track,
3114
+ "data-track-placement": tracking?.placement,
3115
+ children: content
3116
+ }
3117
+ ) : /* @__PURE__ */ jsx34("div", { className: "rt-tpl-contact-channel-card", children: content })
3118
+ },
3119
+ `${channel.label}-${channel.value ?? channel.href ?? ""}`
3120
+ );
3121
+ }) }),
3122
+ /* @__PURE__ */ jsxs28("div", { className: "rt-tpl-contact-channel-side", children: [
3123
+ /* @__PURE__ */ jsx34(ContactMapBlock, { map, mapEmbedUrl }),
3124
+ /* @__PURE__ */ jsx34(ContactActions, { actions })
3125
+ ] })
3126
+ ] })
3127
+ ] })
3128
+ }
3129
+ );
3130
+ }
3131
+
3132
+ // src/templates/section-templates/contact-visit.tsx
3133
+ import { jsx as jsx35, jsxs as jsxs29 } from "react/jsx-runtime";
3134
+ function ContactHoursSummary({
3135
+ hours
3136
+ }) {
3137
+ if (!hours || hours.length === 0) return null;
3138
+ return /* @__PURE__ */ jsxs29("table", { className: "rt-tpl-contact-visit-hours", children: [
3139
+ /* @__PURE__ */ jsx35("caption", { className: "rt-tpl-sr-only", children: "\uC9C4\uB8CC\uC2DC\uAC04" }),
3140
+ /* @__PURE__ */ jsx35("tbody", { children: hours.map((row) => /* @__PURE__ */ jsxs29("tr", { children: [
3141
+ /* @__PURE__ */ jsx35("th", { scope: "row", children: row.day }),
3142
+ /* @__PURE__ */ jsxs29("td", { children: [
3143
+ /* @__PURE__ */ jsx35("span", { children: row.open }),
3144
+ /* @__PURE__ */ jsx35("span", { "aria-hidden": "true", children: "-" }),
3145
+ /* @__PURE__ */ jsx35("span", { children: row.close }),
3146
+ row.note ? /* @__PURE__ */ jsx35("span", { className: "rt-tpl-contact-hours-note", children: row.note }) : null
3147
+ ] })
3148
+ ] }, `${row.day}-${row.open}-${row.close}`)) })
3149
+ ] });
3150
+ }
3151
+ function TemplateContactVisitBand(section) {
3152
+ const { heading, phone, address, hours, map, mapEmbedUrl, actions } = section.props;
3153
+ const mapAction = actions?.find((action) => action.kind === "map") ?? actions?.[0];
3154
+ const ctaAction = actions?.find((action) => action.kind === "reserve" || action.kind === "call") ?? actions?.[1] ?? mapAction;
3155
+ const phoneAction = phone ? { label: phone, href: telHref(phone) } : void 0;
3156
+ return /* @__PURE__ */ jsx35(
3157
+ "section",
3158
+ {
3159
+ "data-roottale-tpl": "contact",
3160
+ "data-variant": "visit-band",
3161
+ id: section.id,
3162
+ className: "rt-tpl-section rt-tpl-contact",
3163
+ style: sectionThemeStyle(section.theme),
3164
+ children: /* @__PURE__ */ jsxs29("div", { className: "rt-tpl-container", children: [
3165
+ heading ? /* @__PURE__ */ jsx35("h2", { className: "rt-tpl-heading", children: heading }) : null,
3166
+ /* @__PURE__ */ jsxs29("div", { className: "rt-tpl-contact-visit-band", children: [
3167
+ /* @__PURE__ */ jsxs29("section", { className: "rt-tpl-contact-visit-panel", "aria-label": "\uC9C4\uB8CC\uC2DC\uAC04", children: [
3168
+ /* @__PURE__ */ jsx35("h3", { className: "rt-tpl-contact-visit-title", children: "\uC9C4\uB8CC\uC2DC\uAC04" }),
3169
+ /* @__PURE__ */ jsx35(ContactHoursSummary, { hours })
3170
+ ] }),
3171
+ /* @__PURE__ */ jsxs29("section", { className: "rt-tpl-contact-visit-panel", "aria-label": "\uC624\uC2DC\uB294 \uAE38", children: [
3172
+ /* @__PURE__ */ jsx35("h3", { className: "rt-tpl-contact-visit-title", children: "\uC624\uC2DC\uB294 \uAE38" }),
3173
+ /* @__PURE__ */ jsx35(ContactMapBlock, { map, mapEmbedUrl }),
3174
+ address ? /* @__PURE__ */ jsx35("address", { className: "rt-tpl-contact-visit-address", children: address }) : null,
3175
+ mapAction ? /* @__PURE__ */ jsx35(
3176
+ "a",
3177
+ {
3178
+ className: "rt-tpl-contact-visit-link",
3179
+ href: mapAction.href,
3180
+ "data-track": contactHrefTrack(mapAction.href),
3181
+ "data-track-placement": contactHrefTrack(mapAction.href) ? "visit" : void 0,
3182
+ children: mapAction.label
3183
+ }
3184
+ ) : null
3185
+ ] }),
3186
+ /* @__PURE__ */ jsxs29("section", { className: "rt-tpl-contact-visit-panel", "aria-label": "\uC804\uD654", children: [
3187
+ /* @__PURE__ */ jsx35("h3", { className: "rt-tpl-contact-visit-title", children: "\uC804\uD654" }),
3188
+ phoneAction ? /* @__PURE__ */ jsx35(
3189
+ "a",
3190
+ {
3191
+ className: "rt-tpl-contact-visit-phone",
3192
+ href: phoneAction.href,
3193
+ "data-track": "cta_call",
3194
+ children: phoneAction.label
3195
+ }
3196
+ ) : null,
3197
+ hours ? /* @__PURE__ */ jsx35(ContactHoursSummary, { hours: hours.slice(0, 2) }) : null,
3198
+ ctaAction ? /* @__PURE__ */ jsx35(
3199
+ "a",
3200
+ {
3201
+ className: "rt-tpl-btn rt-tpl-btn--primary",
3202
+ href: ctaAction.href,
3203
+ "data-track": contactHrefTrack(ctaAction.href),
3204
+ "data-track-placement": contactHrefTrack(ctaAction.href) ? "visit" : void 0,
3205
+ children: ctaAction.label
3206
+ }
3207
+ ) : null
3208
+ ] })
3209
+ ] })
3210
+ ] })
3211
+ }
3212
+ );
3213
+ }
3214
+
3215
+ // src/templates/section-templates/contact.tsx
3216
+ import { jsx as jsx36, jsxs as jsxs30 } from "react/jsx-runtime";
3217
+ function TemplateContact(section) {
3218
+ switch (section.variant) {
3219
+ case "channel-cards":
3220
+ return TemplateContactChannelCards(section);
3221
+ case "visit-band":
3222
+ return TemplateContactVisitBand(section);
3223
+ default:
3224
+ break;
3225
+ }
3226
+ const { heading, form, phone, address, hours, map, mapEmbedUrl, actions } = section.props;
3227
+ return /* @__PURE__ */ jsx36(
3228
+ "section",
3229
+ {
3230
+ "data-roottale-tpl": "contact",
3231
+ "data-variant": section.variant,
3232
+ id: section.id,
3233
+ className: "rt-tpl-section rt-tpl-contact",
3234
+ style: sectionThemeStyle(section.theme),
3235
+ children: /* @__PURE__ */ jsxs30("div", { className: "rt-tpl-container rt-tpl-contact-inner", children: [
3236
+ /* @__PURE__ */ jsxs30("div", { className: "rt-tpl-contact-info", children: [
3237
+ heading ? /* @__PURE__ */ jsx36("h2", { className: "rt-tpl-heading", children: heading }) : null,
3238
+ phone ? /* @__PURE__ */ jsx36("a", { className: "rt-tpl-contact-phone", href: telHref(phone), "data-track": "cta_call", children: phone }) : null,
3239
+ address ? /* @__PURE__ */ jsx36("address", { className: "rt-tpl-contact-address", children: address }) : null,
3240
+ hours ? /* @__PURE__ */ jsxs30("table", { className: "rt-tpl-contact-hours", children: [
3241
+ /* @__PURE__ */ jsx36("caption", { className: "rt-tpl-sr-only", children: "\uC9C4\uB8CC\uC2DC\uAC04" }),
3242
+ /* @__PURE__ */ jsx36("tbody", { children: hours.map((row) => /* @__PURE__ */ jsxs30("tr", { children: [
3243
+ /* @__PURE__ */ jsx36("th", { scope: "row", children: row.day }),
3244
+ /* @__PURE__ */ jsxs30("td", { children: [
3245
+ /* @__PURE__ */ jsx36("span", { children: row.open }),
3246
+ /* @__PURE__ */ jsx36("span", { "aria-hidden": "true", children: "-" }),
3247
+ /* @__PURE__ */ jsx36("span", { children: row.close }),
3248
+ row.note ? /* @__PURE__ */ jsx36("span", { className: "rt-tpl-contact-hours-note", children: row.note }) : null
3249
+ ] })
3250
+ ] }, `${row.day}-${row.open}-${row.close}`)) })
3251
+ ] }) : null,
3252
+ /* @__PURE__ */ jsx36(ContactMapBlock, { map, mapEmbedUrl }),
3253
+ /* @__PURE__ */ jsx36(ContactActions, { actions })
3254
+ ] }),
3255
+ form.enabled ? /* @__PURE__ */ jsx36("div", { className: "rt-tpl-contact-form", children: /* @__PURE__ */ jsx36(RootTaleLeadForm, { action: "/api/inquiry", vertical: form.vertical }) }) : null
3256
+ ] })
3257
+ }
3258
+ );
3259
+ }
3260
+
3261
+ // src/templates/section-templates/practice-shared.tsx
3262
+ import { jsx as jsx37, jsxs as jsxs31 } from "react/jsx-runtime";
3263
+ function renderPracticeHeader({
3264
+ eyebrow,
3265
+ heading,
3266
+ description
3267
+ }) {
3268
+ if (!eyebrow && !heading && !description) return null;
3269
+ return /* @__PURE__ */ jsxs31("header", { className: "rt-tpl-practice-header", children: [
3270
+ eyebrow ? /* @__PURE__ */ jsx37("p", { className: "rt-tpl-practice-eyebrow", children: eyebrow }) : null,
3271
+ heading ? /* @__PURE__ */ jsx37("h2", { className: "rt-tpl-heading", children: heading }) : null,
3272
+ description ? /* @__PURE__ */ jsx37("p", { className: "rt-tpl-section-desc", children: description }) : null
3273
+ ] });
3274
+ }
3275
+ function renderPracticeDisclaimer(disclaimer) {
3276
+ return disclaimer ? /* @__PURE__ */ jsx37("aside", { className: "rt-tpl-practice-disclaimer", children: disclaimer }) : null;
3277
+ }
3278
+
3279
+ // src/templates/section-templates/hours.tsx
3280
+ import { jsx as jsx38, jsxs as jsxs32 } from "react/jsx-runtime";
3281
+ function renderHoursBadges(badges) {
3282
+ if (!badges) return null;
3283
+ const values = [
3284
+ badges.lunch,
3285
+ badges.evening,
3286
+ badges.closed,
3287
+ ...badges.extra ?? []
3288
+ ].filter((value) => Boolean(value));
3289
+ if (values.length === 0) return null;
3290
+ return /* @__PURE__ */ jsx38("span", { className: "rt-tpl-practice-badges", children: values.map((value) => /* @__PURE__ */ jsx38("span", { className: "rt-tpl-practice-badge", children: value }, value)) });
3291
+ }
3292
+ function TemplateHoursCompact(section) {
3293
+ const { eyebrow, heading, description, rows, note, disclaimer } = section.props;
3294
+ return /* @__PURE__ */ jsx38(
3295
+ "section",
3296
+ {
3297
+ "data-roottale-tpl": "hours",
3298
+ "data-variant": "compact",
3299
+ id: section.id,
3300
+ className: "rt-tpl-section rt-tpl-practice rt-tpl-hours",
3301
+ style: sectionThemeStyle(section.theme),
3302
+ children: /* @__PURE__ */ jsxs32("div", { className: "rt-tpl-container", children: [
3303
+ renderPracticeHeader({ eyebrow, heading, description }),
3304
+ /* @__PURE__ */ jsx38("dl", { className: "rt-tpl-hours-compact-list", children: rows.map((row) => /* @__PURE__ */ jsxs32("div", { className: "rt-tpl-hours-compact-row", children: [
3305
+ /* @__PURE__ */ jsx38("dt", { className: "rt-tpl-hours-compact-day", children: row.label }),
3306
+ /* @__PURE__ */ jsxs32("dd", { className: "rt-tpl-hours-compact-body", children: [
3307
+ /* @__PURE__ */ jsx38("span", { className: "rt-tpl-hours-time", children: row.hours }),
3308
+ row.lunchHours ? /* @__PURE__ */ jsx38("span", { className: "rt-tpl-hours-muted", children: row.lunchHours }) : null,
3309
+ renderHoursBadges(row.badges),
3310
+ row.note ? /* @__PURE__ */ jsx38("span", { className: "rt-tpl-hours-muted", children: row.note }) : null
3311
+ ] })
3312
+ ] }, row.day)) }),
3313
+ note ? /* @__PURE__ */ jsx38("p", { className: "rt-tpl-practice-note", children: note }) : null,
3314
+ renderPracticeDisclaimer(disclaimer)
3315
+ ] })
3316
+ }
3317
+ );
3318
+ }
3319
+ function TemplateHours(section) {
3320
+ if (section.variant === "compact") return TemplateHoursCompact(section);
3321
+ const { eyebrow, heading, description, rows, note, disclaimer } = section.props;
3322
+ return /* @__PURE__ */ jsx38(
3323
+ "section",
3324
+ {
3325
+ "data-roottale-tpl": "hours",
3326
+ "data-variant": section.variant,
3327
+ id: section.id,
3328
+ className: "rt-tpl-section rt-tpl-practice rt-tpl-hours",
3329
+ style: sectionThemeStyle(section.theme),
3330
+ children: /* @__PURE__ */ jsxs32("div", { className: "rt-tpl-container", children: [
3331
+ renderPracticeHeader({ eyebrow, heading, description }),
3332
+ /* @__PURE__ */ jsx38("div", { className: "rt-tpl-practice-table-wrap", children: /* @__PURE__ */ jsxs32("table", { className: "rt-tpl-practice-table", children: [
3333
+ /* @__PURE__ */ jsx38("caption", { className: "rt-tpl-sr-only", children: "\uC601\uC5C5\uC2DC\uAC04" }),
3334
+ /* @__PURE__ */ jsx38("thead", { children: /* @__PURE__ */ jsxs32("tr", { children: [
3335
+ /* @__PURE__ */ jsx38("th", { scope: "col", children: "\uC694\uC77C" }),
3336
+ /* @__PURE__ */ jsx38("th", { scope: "col", children: "\uC2DC\uAC04" }),
3337
+ /* @__PURE__ */ jsx38("th", { scope: "col", children: "\uC810\uC2EC/\uD734\uAC8C" }),
3338
+ /* @__PURE__ */ jsx38("th", { scope: "col", children: "\uC548\uB0B4" })
3339
+ ] }) }),
3340
+ /* @__PURE__ */ jsxs32("tbody", { children: [
3341
+ rows.map((row) => /* @__PURE__ */ jsxs32("tr", { children: [
3342
+ /* @__PURE__ */ jsx38("th", { scope: "row", className: "rt-tpl-practice-primary", children: row.label }),
3343
+ /* @__PURE__ */ jsx38("td", { children: row.hours }),
3344
+ /* @__PURE__ */ jsx38("td", { className: "rt-tpl-practice-muted", children: row.lunchHours ?? "\uBCC4\uB3C4 \uC548\uB0B4" }),
3345
+ /* @__PURE__ */ jsxs32("td", { children: [
3346
+ renderHoursBadges(row.badges),
3347
+ row.note ? /* @__PURE__ */ jsx38("p", { className: "rt-tpl-practice-muted", children: row.note }) : null
3348
+ ] })
3349
+ ] }, row.day)),
3350
+ note ? /* @__PURE__ */ jsx38("tr", { className: "rt-tpl-practice-table-note", children: /* @__PURE__ */ jsx38("td", { colSpan: 4, children: note }) }) : null
3351
+ ] })
3352
+ ] }) }),
3353
+ renderPracticeDisclaimer(disclaimer)
3354
+ ] })
3355
+ }
3356
+ );
3357
+ }
3358
+
3359
+ // src/templates/section-templates/pricing.tsx
3360
+ import { jsx as jsx39, jsxs as jsxs33 } from "react/jsx-runtime";
3361
+ function TemplatePricingCards(section) {
3362
+ const { eyebrow, heading, description, groups, disclaimer } = section.props;
3363
+ return /* @__PURE__ */ jsx39(
3364
+ "section",
3365
+ {
3366
+ "data-roottale-tpl": "pricing",
3367
+ "data-variant": "cards",
3368
+ id: section.id,
3369
+ className: "rt-tpl-section rt-tpl-practice rt-tpl-pricing",
3370
+ style: sectionThemeStyle(section.theme),
3371
+ children: /* @__PURE__ */ jsxs33("div", { className: "rt-tpl-container", children: [
3372
+ renderPracticeHeader({ eyebrow, heading, description }),
3373
+ /* @__PURE__ */ jsx39("div", { className: "rt-tpl-pricing-card-groups", children: groups.map((group) => /* @__PURE__ */ jsxs33("section", { className: "rt-tpl-pricing-card-group", children: [
3374
+ /* @__PURE__ */ jsx39("h3", { className: "rt-tpl-pricing-group-title", children: group.label }),
3375
+ /* @__PURE__ */ jsx39("ul", { className: "rt-tpl-pricing-card-list", children: group.items.map((item) => /* @__PURE__ */ jsxs33("li", { className: "rt-tpl-pricing-card", children: [
3376
+ /* @__PURE__ */ jsxs33("div", { children: [
3377
+ /* @__PURE__ */ jsx39("h4", { className: "rt-tpl-pricing-name", children: item.name }),
3378
+ item.description ? /* @__PURE__ */ jsx39("p", { className: "rt-tpl-pricing-desc", children: item.description }) : null
3379
+ ] }),
3380
+ /* @__PURE__ */ jsx39("p", { className: "rt-tpl-pricing-price", children: item.price }),
3381
+ /* @__PURE__ */ jsx39("p", { className: "rt-tpl-pricing-condition", children: item.condition ?? "\uC790\uB8CC \uD655\uC778 \uD6C4 \uD655\uC815" })
3382
+ ] }, `${group.label}-${item.name}`)) })
3383
+ ] }, group.label)) }),
3384
+ /* @__PURE__ */ jsx39("aside", { className: "rt-tpl-practice-disclaimer", children: disclaimer })
3385
+ ] })
3386
+ }
3387
+ );
3388
+ }
3389
+ function TemplatePricing(section) {
3390
+ if (section.variant === "cards") return TemplatePricingCards(section);
3391
+ const { eyebrow, heading, description, groups, disclaimer } = section.props;
3392
+ return /* @__PURE__ */ jsx39(
3393
+ "section",
3394
+ {
3395
+ "data-roottale-tpl": "pricing",
3396
+ "data-variant": section.variant,
3397
+ id: section.id,
3398
+ className: "rt-tpl-section rt-tpl-practice rt-tpl-pricing",
3399
+ style: sectionThemeStyle(section.theme),
3400
+ children: /* @__PURE__ */ jsxs33("div", { className: "rt-tpl-container", children: [
3401
+ renderPracticeHeader({ eyebrow, heading, description }),
3402
+ /* @__PURE__ */ jsx39("div", { className: "rt-tpl-practice-table-wrap", children: /* @__PURE__ */ jsxs33("table", { className: "rt-tpl-practice-table", children: [
3403
+ /* @__PURE__ */ jsx39("caption", { className: "rt-tpl-sr-only", children: "\uC694\uAE08 \uC548\uB0B4" }),
3404
+ /* @__PURE__ */ jsx39("thead", { children: /* @__PURE__ */ jsxs33("tr", { children: [
3405
+ /* @__PURE__ */ jsx39("th", { scope: "col", children: "\uD56D\uBAA9" }),
3406
+ /* @__PURE__ */ jsx39("th", { scope: "col", children: "\uC124\uBA85" }),
3407
+ /* @__PURE__ */ jsx39("th", { scope: "col", children: "\uAC00\uACA9" }),
3408
+ /* @__PURE__ */ jsx39("th", { scope: "col", children: "\uC870\uAC74" })
3409
+ ] }) }),
3410
+ /* @__PURE__ */ jsx39("tbody", { children: groups.flatMap((group) => [
3411
+ /* @__PURE__ */ jsx39("tr", { className: "rt-tpl-pricing-group-row", children: /* @__PURE__ */ jsx39("td", { colSpan: 4, children: group.label }) }, `${group.label}-group`),
3412
+ ...group.items.map((item) => /* @__PURE__ */ jsxs33("tr", { children: [
3413
+ /* @__PURE__ */ jsx39("th", { scope: "row", className: "rt-tpl-practice-primary", children: item.name }),
3414
+ /* @__PURE__ */ jsx39("td", { className: "rt-tpl-practice-muted", children: item.description ?? "\uC0C1\uB2F4 \uD6C4 \uBC94\uC704 \uD655\uC778" }),
3415
+ /* @__PURE__ */ jsx39("td", { className: "rt-tpl-pricing-price", children: item.price }),
3416
+ /* @__PURE__ */ jsx39("td", { className: "rt-tpl-practice-muted", children: item.condition ?? "\uC790\uB8CC \uD655\uC778 \uD6C4 \uD655\uC815" })
3417
+ ] }, `${group.label}-${item.name}`))
3418
+ ]) })
3419
+ ] }) }),
3420
+ /* @__PURE__ */ jsx39("aside", { className: "rt-tpl-practice-disclaimer", children: disclaimer })
3421
+ ] })
3422
+ }
3423
+ );
3424
+ }
3425
+
3426
+ // src/templates/section-templates/process.tsx
3427
+ import { jsx as jsx40, jsxs as jsxs34 } from "react/jsx-runtime";
3428
+ function TemplateProcess(section) {
3429
+ const { eyebrow, heading, description, items, connector, disclaimer } = section.props;
3430
+ if (section.variant === "timeline-marked") {
3431
+ return /* @__PURE__ */ jsx40(
3432
+ "section",
3433
+ {
3434
+ "data-roottale-tpl": "process",
3435
+ "data-variant": "timeline-marked",
3436
+ id: section.id,
3437
+ className: "rt-tpl-section rt-tpl-practice rt-tpl-process",
3438
+ style: sectionThemeStyle(section.theme),
3439
+ children: /* @__PURE__ */ jsxs34("div", { className: "rt-tpl-container", children: [
3440
+ renderPracticeHeader({ eyebrow, heading, description }),
3441
+ /* @__PURE__ */ jsx40("ol", { className: "rt-tpl-process-marked-list", children: items.map((item, index) => {
3442
+ const status = item.status ?? "complete";
3443
+ const mark = item.mark ?? (status === "complete" ? "check" : "dot");
3444
+ return /* @__PURE__ */ jsx40(
3445
+ "li",
3446
+ {
3447
+ className: "rt-tpl-process-marked-item",
3448
+ "data-status": status,
3449
+ children: /* @__PURE__ */ jsxs34("article", { className: "rt-tpl-process-marked-card", children: [
3450
+ /* @__PURE__ */ jsx40("div", { className: "rt-tpl-process-marked-icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx40("span", { "data-mark": mark }) }),
3451
+ /* @__PURE__ */ jsxs34("div", { className: "rt-tpl-process-marked-body", children: [
3452
+ /* @__PURE__ */ jsx40("p", { className: "rt-tpl-process-marked-step", children: item.eyebrow ?? `step ${String(index + 1).padStart(2, "0")}` }),
3453
+ /* @__PURE__ */ jsx40("h3", { className: "rt-tpl-process-title", children: item.title }),
3454
+ /* @__PURE__ */ jsx40("p", { className: "rt-tpl-process-desc", children: item.description }),
3455
+ item.duration || item.statusLabel ? /* @__PURE__ */ jsx40("p", { className: "rt-tpl-process-duration", children: item.statusLabel ?? item.duration }) : null
3456
+ ] })
3457
+ ] })
3458
+ },
3459
+ `${index}-${item.title}`
3460
+ );
3461
+ }) }),
3462
+ renderPracticeDisclaimer(disclaimer)
3463
+ ] })
3464
+ }
3465
+ );
3466
+ }
3467
+ return /* @__PURE__ */ jsx40(
3468
+ "section",
3469
+ {
3470
+ "data-roottale-tpl": "process",
3471
+ "data-variant": section.variant,
3472
+ id: section.id,
3473
+ className: "rt-tpl-section rt-tpl-practice rt-tpl-process",
3474
+ style: sectionThemeStyle(section.theme),
3475
+ children: /* @__PURE__ */ jsxs34("div", { className: "rt-tpl-container", children: [
3476
+ renderPracticeHeader({ eyebrow, heading, description }),
3477
+ /* @__PURE__ */ jsx40(
3478
+ "ol",
3479
+ {
3480
+ className: "rt-tpl-process-list",
3481
+ "data-connector": connector ?? "line",
3482
+ children: items.map((item, index) => /* @__PURE__ */ jsx40("li", { className: "rt-tpl-process-item", children: /* @__PURE__ */ jsxs34("article", { className: "rt-tpl-process-content", children: [
3483
+ item.imageSrc ? /* @__PURE__ */ jsx40(
3484
+ "img",
3485
+ {
3486
+ className: "rt-tpl-process-image",
3487
+ src: item.imageSrc,
3488
+ alt: item.imageAlt ?? "",
3489
+ loading: "lazy"
3490
+ }
3491
+ ) : null,
3492
+ /* @__PURE__ */ jsx40("p", { className: "rt-tpl-process-step", children: item.eyebrow ?? `step ${String(index + 1).padStart(2, "0")}` }),
3493
+ /* @__PURE__ */ jsx40("h3", { className: "rt-tpl-process-title", children: item.title }),
3494
+ /* @__PURE__ */ jsx40("p", { className: "rt-tpl-process-desc", children: item.description }),
3495
+ item.duration ? /* @__PURE__ */ jsx40("p", { className: "rt-tpl-process-duration", children: item.duration }) : null
3496
+ ] }) }, `${index}-${item.title}`))
3497
+ }
3498
+ ),
3499
+ renderPracticeDisclaimer(disclaimer)
3500
+ ] })
3501
+ }
3502
+ );
3503
+ }
3504
+
3505
+ // src/templates/section-templates/before-after.tsx
3506
+ import { jsx as jsx41, jsxs as jsxs35 } from "react/jsx-runtime";
3507
+ function TemplateBeforeAfterSideBySide(section) {
3508
+ const { beforeImage, afterImage, beforeLabel, afterLabel } = section.props;
3509
+ return /* @__PURE__ */ jsxs35("div", { className: "rt-tpl-before-after-pair", children: [
3510
+ /* @__PURE__ */ jsxs35("figure", { className: "rt-tpl-before-after-figure", children: [
3511
+ /* @__PURE__ */ jsx41(
3512
+ "img",
3513
+ {
3514
+ className: "rt-tpl-before-after-img",
3515
+ src: beforeImage.src,
3516
+ alt: beforeImage.alt,
3517
+ loading: "lazy"
3518
+ }
3519
+ ),
3520
+ /* @__PURE__ */ jsx41("figcaption", { className: "rt-tpl-before-after-caption", children: beforeLabel })
3521
+ ] }),
3522
+ /* @__PURE__ */ jsxs35("figure", { className: "rt-tpl-before-after-figure", children: [
3523
+ /* @__PURE__ */ jsx41(
3524
+ "img",
3525
+ {
3526
+ className: "rt-tpl-before-after-img",
3527
+ src: afterImage.src,
3528
+ alt: afterImage.alt,
3529
+ loading: "lazy"
3530
+ }
3531
+ ),
3532
+ /* @__PURE__ */ jsx41("figcaption", { className: "rt-tpl-before-after-caption", children: afterLabel })
3533
+ ] })
3534
+ ] });
3535
+ }
3536
+ function TemplateBeforeAfter(section) {
3537
+ const {
3538
+ heading,
3539
+ description,
3540
+ beforeImage,
3541
+ afterImage,
3542
+ beforeLabel,
3543
+ afterLabel,
3544
+ disclaimer
3545
+ } = section.props;
3546
+ return /* @__PURE__ */ jsx41(
3547
+ "section",
3548
+ {
3549
+ "data-roottale-tpl": "before-after",
3550
+ "data-variant": section.variant,
3551
+ id: section.id,
3552
+ className: "rt-tpl-section rt-tpl-practice rt-tpl-before-after",
3553
+ style: sectionThemeStyle(section.theme),
3554
+ children: /* @__PURE__ */ jsxs35("div", { className: "rt-tpl-container", children: [
3555
+ renderPracticeHeader({ heading, description }),
3556
+ section.variant === "side-by-side" ? /* @__PURE__ */ jsx41(TemplateBeforeAfterSideBySide, { ...section }) : /* @__PURE__ */ jsx41(
3557
+ BeforeAfterSlider,
3558
+ {
3559
+ beforeImage,
3560
+ afterImage,
3561
+ beforeLabel,
3562
+ afterLabel
3563
+ }
3564
+ ),
3565
+ renderPracticeDisclaimer(disclaimer)
3566
+ ] })
3567
+ }
3568
+ );
3569
+ }
3570
+
3571
+ // src/templates/professional-sections.tsx
3572
+ import { jsx as jsx42, jsxs as jsxs36 } from "react/jsx-runtime";
3573
+ function SectionHeader({
3574
+ heading,
3575
+ description
3576
+ }) {
3577
+ if (!heading && !description) return null;
3578
+ return /* @__PURE__ */ jsxs36("header", { className: "rt-tpl-client-section-header", children: [
3579
+ heading ? /* @__PURE__ */ jsx42("h2", { className: "rt-tpl-heading", children: heading }) : null,
3580
+ description ? /* @__PURE__ */ jsx42("p", { className: "rt-tpl-section-desc", children: description }) : null
3581
+ ] });
3582
+ }
3583
+ function TagList({
3584
+ tags,
3585
+ label
3586
+ }) {
3587
+ if (!tags || tags.length === 0) return null;
3588
+ return /* @__PURE__ */ jsx42("ul", { className: "rt-tpl-client-tags", "aria-label": label, children: tags.map((tag) => /* @__PURE__ */ jsx42("li", { children: tag }, tag)) });
3589
+ }
3590
+ function TemplateExpertiseCards(section) {
3591
+ const { heading, description, items } = section.props;
3592
+ return /* @__PURE__ */ jsx42(
3593
+ "section",
3594
+ {
3595
+ "data-roottale-tpl": "expertise",
3596
+ "data-variant": "cards",
3597
+ id: section.id,
3598
+ className: "rt-tpl-section rt-tpl-expertise",
3599
+ style: sectionThemeStyle(section.theme),
3600
+ children: /* @__PURE__ */ jsxs36("div", { className: "rt-tpl-container", children: [
3601
+ /* @__PURE__ */ jsx42(SectionHeader, { heading, description }),
3602
+ /* @__PURE__ */ jsx42("ul", { className: "rt-tpl-expertise-card-grid", children: items.map((item) => /* @__PURE__ */ jsxs36("li", { className: "rt-tpl-expertise-card", children: [
3603
+ item.imageSrc ? /* @__PURE__ */ jsx42(
3604
+ "img",
3605
+ {
3606
+ className: "rt-tpl-expertise-card-img",
3607
+ src: item.imageSrc,
3608
+ alt: item.imageAlt ?? "",
3609
+ loading: "lazy"
3610
+ }
3611
+ ) : null,
3612
+ /* @__PURE__ */ jsxs36("div", { className: "rt-tpl-expertise-card-body", children: [
3613
+ item.kicker ? /* @__PURE__ */ jsx42("p", { className: "rt-tpl-expertise-kicker", children: item.kicker }) : null,
3614
+ /* @__PURE__ */ jsx42("h3", { className: "rt-tpl-expertise-title", children: item.title }),
3615
+ /* @__PURE__ */ jsx42("p", { className: "rt-tpl-expertise-body", children: item.body }),
3616
+ /* @__PURE__ */ jsx42(TagList, { tags: item.tags, label: `${item.title} \uD0DC\uADF8` }),
3617
+ item.href ? /* @__PURE__ */ jsx42("a", { className: "rt-tpl-expertise-cta", href: item.href, children: item.ctaLabel ?? "\uC790\uC138\uD788 \uBCF4\uAE30" }) : null
3618
+ ] })
3619
+ ] }, item.id)) })
3620
+ ] })
3621
+ }
3622
+ );
3623
+ }
3624
+ function TemplateExpertise(section) {
3625
+ const { heading, description, items } = section.props;
3626
+ if (section.variant === "cards") return TemplateExpertiseCards(section);
3627
+ return /* @__PURE__ */ jsx42(
3628
+ "section",
3629
+ {
3630
+ "data-roottale-tpl": "expertise",
3631
+ "data-variant": "tab-stage",
3632
+ id: section.id,
3633
+ className: "rt-tpl-section rt-tpl-expertise",
3634
+ style: sectionThemeStyle(section.theme),
3635
+ children: /* @__PURE__ */ jsxs36("div", { className: "rt-tpl-container", children: [
3636
+ /* @__PURE__ */ jsx42(SectionHeader, { heading, description }),
3637
+ /* @__PURE__ */ jsx42(ExpertiseTabStage, { items })
3638
+ ] })
3639
+ }
3640
+ );
3641
+ }
3642
+ function TemplateSpacesMosaic(section) {
3643
+ const { heading, description, spaces, disclaimer } = section.props;
3644
+ return /* @__PURE__ */ jsx42(
3645
+ "section",
3646
+ {
3647
+ "data-roottale-tpl": "spaces",
3648
+ "data-variant": "mosaic",
3649
+ id: section.id,
3650
+ className: "rt-tpl-section rt-tpl-spaces",
3651
+ style: sectionThemeStyle(section.theme),
3652
+ children: /* @__PURE__ */ jsxs36("div", { className: "rt-tpl-container", children: [
3653
+ /* @__PURE__ */ jsx42(SectionHeader, { heading, description }),
3654
+ /* @__PURE__ */ jsx42("ul", { className: "rt-tpl-spaces-mosaic", children: spaces.map((space) => /* @__PURE__ */ jsxs36("li", { className: "rt-tpl-spaces-tile", children: [
3655
+ /* @__PURE__ */ jsx42("img", { src: space.imageSrc, alt: space.imageAlt, loading: "lazy" }),
3656
+ /* @__PURE__ */ jsxs36("div", { className: "rt-tpl-spaces-tile-caption", children: [
3657
+ space.kicker ? /* @__PURE__ */ jsx42("span", { className: "rt-tpl-spaces-kicker", children: space.kicker }) : null,
3658
+ /* @__PURE__ */ jsx42("h3", { children: space.title ?? space.label }),
3659
+ space.description ? /* @__PURE__ */ jsx42("p", { children: space.description }) : null,
3660
+ /* @__PURE__ */ jsx42(TagList, { tags: space.tags, label: `${space.label} \uD0DC\uADF8` })
3661
+ ] })
3662
+ ] }, space.id)) }),
3663
+ disclaimer ? /* @__PURE__ */ jsx42("aside", { className: "rt-tpl-client-disclaimer", children: disclaimer }) : null
3664
+ ] })
3665
+ }
3666
+ );
3667
+ }
3668
+ function TemplateSpaces(section) {
3669
+ const { heading, description, spaces, disclaimer } = section.props;
3670
+ if (section.variant === "mosaic") return TemplateSpacesMosaic(section);
3671
+ return /* @__PURE__ */ jsx42(
3672
+ "section",
3673
+ {
3674
+ "data-roottale-tpl": "spaces",
3675
+ "data-variant": "stage",
3676
+ id: section.id,
3677
+ className: "rt-tpl-section rt-tpl-spaces",
3678
+ style: sectionThemeStyle(section.theme),
3679
+ children: /* @__PURE__ */ jsxs36("div", { className: "rt-tpl-container", children: [
3680
+ /* @__PURE__ */ jsx42(SectionHeader, { heading, description }),
3681
+ /* @__PURE__ */ jsx42(SpacesStage, { spaces }),
3682
+ disclaimer ? /* @__PURE__ */ jsx42("aside", { className: "rt-tpl-client-disclaimer", children: disclaimer }) : null
3683
+ ] })
3684
+ }
3685
+ );
3686
+ }
3687
+ function TemplateConcernsList(section) {
3688
+ const { heading, description, regions, disclaimer } = section.props;
3689
+ return /* @__PURE__ */ jsx42(
3690
+ "section",
3691
+ {
3692
+ "data-roottale-tpl": "concerns",
3693
+ "data-variant": "list",
3694
+ id: section.id,
3695
+ className: "rt-tpl-section rt-tpl-concerns",
3696
+ style: sectionThemeStyle(section.theme),
3697
+ children: /* @__PURE__ */ jsxs36("div", { className: "rt-tpl-container", children: [
3698
+ /* @__PURE__ */ jsx42(SectionHeader, { heading, description }),
3699
+ /* @__PURE__ */ jsx42("ul", { className: "rt-tpl-concerns-list", children: regions.map((region) => /* @__PURE__ */ jsxs36("li", { className: "rt-tpl-concerns-card", children: [
3700
+ /* @__PURE__ */ jsx42("p", { className: "rt-tpl-concerns-label", children: region.label }),
3701
+ /* @__PURE__ */ jsx42("h3", { className: "rt-tpl-concerns-title", children: region.title }),
3702
+ /* @__PURE__ */ jsx42("p", { className: "rt-tpl-concerns-desc", children: region.description }),
3703
+ region.items ? /* @__PURE__ */ jsx42("ul", { className: "rt-tpl-concerns-items", children: region.items.map((item) => /* @__PURE__ */ jsx42("li", { children: item }, item)) }) : null,
3704
+ region.href ? /* @__PURE__ */ jsx42("a", { className: "rt-tpl-concerns-cta", href: region.href, children: region.ctaLabel ?? "\uC790\uC138\uD788 \uBCF4\uAE30" }) : null
3705
+ ] }, region.id)) }),
3706
+ /* @__PURE__ */ jsx42("aside", { className: "rt-tpl-client-disclaimer", children: disclaimer })
3707
+ ] })
3708
+ }
3709
+ );
3710
+ }
3711
+ function TemplateConcerns(section) {
3712
+ const {
3713
+ heading,
3714
+ description,
3715
+ figureImage,
3716
+ figureAlt,
3717
+ regions,
3718
+ disclaimer
3719
+ } = section.props;
3720
+ if (section.variant === "list") return TemplateConcernsList(section);
3721
+ return /* @__PURE__ */ jsx42(
3722
+ "section",
3723
+ {
3724
+ "data-roottale-tpl": "concerns",
3725
+ "data-variant": "figure-map",
3726
+ id: section.id,
3727
+ className: "rt-tpl-section rt-tpl-concerns",
3728
+ style: sectionThemeStyle(section.theme),
3729
+ children: /* @__PURE__ */ jsxs36("div", { className: "rt-tpl-container", children: [
3730
+ /* @__PURE__ */ jsx42(SectionHeader, { heading, description }),
3731
+ /* @__PURE__ */ jsx42(
3732
+ ConcernsFigureMap,
3733
+ {
3734
+ figureImage: figureImage ?? "",
3735
+ figureAlt: figureAlt ?? "",
3736
+ regions
3737
+ }
3738
+ ),
3739
+ /* @__PURE__ */ jsx42("aside", { className: "rt-tpl-client-disclaimer", children: disclaimer })
3740
+ ] })
3741
+ }
3742
+ );
3743
+ }
3744
+
3745
+ // src/templates/render-section-node.tsx
3746
+ import { jsx as jsx43, jsxs as jsxs37 } from "react/jsx-runtime";
3747
+ function warnSkippedCmsBound(sectionType, isDev) {
3748
+ if (isDev()) {
3749
+ console.warn(
3750
+ `[cms-renderer-next] section \uB178\uB4DC sectionType=${sectionType} \uB294 apiKey \uCEE8\uD14D\uC2A4\uD2B8\uAC00 \uC5C6\uC5B4 \uB80C\uB354 skip`
3751
+ );
3752
+ }
3753
+ }
3754
+ function renderSectionNode(node, key, context) {
3755
+ const attrs = node.attrs ?? {};
3756
+ const input = {
3757
+ type: typeof attrs.sectionType === "string" ? attrs.sectionType : "",
3758
+ variant: attrs.variant ?? void 0,
3759
+ theme: attrs.theme ?? void 0,
3760
+ props: attrs.props ?? {}
3761
+ };
3762
+ const parsed = SectionSchema.safeParse(input);
3763
+ if (!parsed.success) {
3764
+ if (context.isDev()) {
3765
+ console.warn(
3766
+ `[cms-renderer-next] section \uB178\uB4DC parse \uC2E4\uD328 (sectionType=${input.type}) \u2014 \uB80C\uB354 skip:`,
3767
+ parsed.error.issues
3768
+ );
3769
+ }
3770
+ return null;
3771
+ }
3772
+ const section = parsed.data;
3773
+ switch (section.type) {
3774
+ case "hero":
3775
+ return /* @__PURE__ */ jsx43(TemplateHero, { ...section }, key);
3776
+ case "rich-text":
3777
+ return /* @__PURE__ */ jsx43(TemplateRichText, { ...section }, key);
3778
+ case "services":
3779
+ return /* @__PURE__ */ jsx43(TemplateServices, { ...section }, key);
3780
+ case "faq":
3781
+ return /* @__PURE__ */ jsx43(TemplateFaq, { ...section }, key);
3782
+ case "footer":
3783
+ return /* @__PURE__ */ jsx43(TemplateFooter, { ...section }, key);
3784
+ case "cta-banner":
3785
+ return /* @__PURE__ */ jsx43(TemplateCtaBanner, { ...section }, key);
3786
+ case "trust":
3787
+ return /* @__PURE__ */ jsx43(TemplateTrust, { ...section }, key);
3788
+ case "hours":
3789
+ return /* @__PURE__ */ jsx43(TemplateHours, { ...section }, key);
3790
+ case "pricing":
3791
+ return /* @__PURE__ */ jsx43(TemplatePricing, { ...section }, key);
3792
+ case "process":
3793
+ return /* @__PURE__ */ jsx43(TemplateProcess, { ...section }, key);
3794
+ case "before-after":
3795
+ return /* @__PURE__ */ jsx43(TemplateBeforeAfter, { ...section }, key);
3796
+ case "testimonials":
3797
+ return /* @__PURE__ */ jsx43(TemplateTestimonials, { ...section }, key);
3798
+ case "team":
3799
+ return /* @__PURE__ */ jsx43(TemplateTeam, { ...section }, key);
3800
+ case "expertise":
3801
+ return /* @__PURE__ */ jsx43(TemplateExpertise, { ...section }, key);
3802
+ case "spaces":
3803
+ return /* @__PURE__ */ jsx43(TemplateSpaces, { ...section }, key);
3804
+ case "concerns":
3805
+ return /* @__PURE__ */ jsx43(TemplateConcerns, { ...section }, key);
3806
+ case "contact":
3807
+ if (!context.cms) {
3808
+ warnSkippedCmsBound(section.type, context.isDev);
3809
+ return null;
3810
+ }
3811
+ return /* @__PURE__ */ jsx43(TemplateContact, { ...section }, key);
3812
+ case "blog-list": {
3813
+ if (!context.cms) {
3814
+ warnSkippedCmsBound(section.type, context.isDev);
3815
+ return null;
3816
+ }
3817
+ const s = section;
3818
+ const base = s.props.blogBasePath ?? "/blog";
3819
+ return /* @__PURE__ */ jsx43(
3820
+ "section",
3821
+ {
3822
+ "data-roottale-tpl": "blog-list",
3823
+ "data-roottale-cms": "list",
3824
+ id: s.id,
3825
+ className: "rt-tpl-section rt-tpl-blog-list",
3826
+ style: sectionThemeStyle(s.theme),
3827
+ children: /* @__PURE__ */ jsxs37("div", { className: "rt-tpl-container", children: [
3828
+ s.props.heading ? /* @__PURE__ */ jsx43("h2", { className: "rt-tpl-heading", children: s.props.heading }) : null,
3829
+ context.renderBlogList({
3830
+ apiKey: context.cms.apiKey,
3831
+ baseUrl: context.cms.baseUrl,
3832
+ limit: s.props.limit,
3833
+ emptyMessage: s.props.emptyMessage,
3834
+ postHref: (post) => `${base}/${post.slug}`
3835
+ })
3836
+ ] })
3837
+ },
3838
+ key
3839
+ );
3840
+ }
3841
+ case "lead-form": {
3842
+ if (!context.cms) {
3843
+ warnSkippedCmsBound(section.type, context.isDev);
3844
+ return null;
3845
+ }
3846
+ const s = section;
3847
+ return /* @__PURE__ */ jsx43(
3848
+ "section",
3849
+ {
3850
+ "data-roottale-tpl": "lead-form",
3851
+ "data-roottale-cms": "lead-form",
3852
+ id: s.id,
3853
+ className: "rt-tpl-section rt-tpl-lead-form",
3854
+ style: sectionThemeStyle(s.theme),
3855
+ children: /* @__PURE__ */ jsx43("div", { className: "rt-tpl-container", children: /* @__PURE__ */ jsx43(
3856
+ RootTaleLeadForm,
3857
+ {
3858
+ action: s.props.action,
3859
+ vertical: s.props.vertical,
3860
+ heading: s.props.heading,
3861
+ description: s.props.description,
3862
+ submitLabel: s.props.submitLabel
3863
+ }
3864
+ ) })
3865
+ },
3866
+ key
3867
+ );
3868
+ }
3869
+ default:
3870
+ if (context.isDev()) {
3871
+ console.warn(
3872
+ `[cms-renderer-next] section \uB178\uB4DC sectionType=${section.type} \uB294 renderNode \uC704\uC784 \uB300\uC0C1\uC774 \uC544\uB2D8(cms-bound/\uBBF8\uC9C0) \u2014 skip`
3873
+ );
3874
+ }
3875
+ return null;
3876
+ }
3877
+ }
3878
+
3879
+ // src/templates/register.ts
3880
+ function registerSectionTemplates() {
3881
+ setSectionNodeRenderer(renderSectionNode);
3882
+ }
3883
+
3884
+ // src/server.tsx
3885
+ registerSectionTemplates();
3886
+
3887
+ export {
3888
+ RootTalePostCard,
3889
+ RootTaleTableOfContents,
3890
+ themeToCssVars2 as themeToCssVars,
3891
+ RootTaleFloatingCta,
3892
+ RootTaleLeadForm,
3893
+ renderBlock,
3894
+ renderBlocks,
3895
+ renderBoundBlocks,
3896
+ headingToId,
3897
+ extractToc,
3898
+ attachHeadingIds,
3899
+ RootTaleThemeProvider,
3900
+ RootTaleBlogList,
3901
+ RootTaleBlogCategories,
3902
+ RenderTiptap,
3903
+ RootTaleFaqJsonLd,
3904
+ RootTaleBlogPost,
3905
+ RootTalePage,
3906
+ sectionThemeStyle,
3907
+ TemplateHero,
3908
+ TemplateRichText,
3909
+ TemplateServices,
3910
+ TemplateFooter,
3911
+ TemplateFaq,
3912
+ TemplateCtaBanner,
3913
+ TemplateTrust,
3914
+ TemplateTestimonials,
3915
+ TemplateTeam,
3916
+ TemplateContact,
3917
+ TemplateHours,
3918
+ TemplatePricing,
3919
+ TemplateProcess,
3920
+ TemplateBeforeAfter,
3921
+ TemplateExpertise,
3922
+ TemplateSpaces,
3923
+ TemplateConcerns,
3924
+ renderSectionNode,
3925
+ registerSectionTemplates
3926
+ };
3927
+ //# sourceMappingURL=chunk-2QU4JU46.js.map