@roottale/cms-renderer-next 0.45.0 → 0.47.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,42 @@
1
1
  # @roottale/cms-renderer-next
2
2
 
3
+ ## 0.47.0
4
+
5
+ ### Minor Changes
6
+
7
+ - bfe0d14: 측정 계측 체계 v2(ADR-0038/ADR-0048 amend) 서버 수용 배선 — 유입 어트리뷰션에
8
+ utm_term/utm_content/광고 클릭 플래그/문의 직전 유입(last-touch) 필드를
9
+ 추가하고, 방문 여정(journey) JSON을 문의 제출에 함께 전달할 수 있게 했습니다.
10
+ - `@roottale/cms-client`: `InquiryAttribution`에 `utm_term`·`utm_content`·
11
+ `ad_click`·`last_touch_*` 필드 추가, `readAttribution()`/
12
+ `parseAttributionJson()`가 새 필드를 읽습니다. `SubmitInquiryFields`에
13
+ `journey?: string`를 추가해 방문 여정 원문을 `attr_journey` 폼 필드로 함께
14
+ 전송합니다.
15
+ - `@roottale/analytics-runtime`: 이벤트 사전(`TRACK_EVENTS`)에 `wireDims`
16
+ 필드를 추가해 `/collect` 비콘 payload의 실제 키 이름을 명시했습니다. 브라우저
17
+ 코드 없이 순수 이벤트 사전만 담은 `./events` 서브패스를 신설했습니다(서버
18
+ 런타임에서 안전하게 import).
19
+ - `@roottale/cms-renderer-next`: 위 cms-client 타입 변경에 따른 patch(연동
20
+ linked 그룹).
21
+
22
+ ### Patch Changes
23
+
24
+ - Updated dependencies [bfe0d14]
25
+ - @roottale/cms-client@0.47.0
26
+
27
+ ## 0.46.0
28
+
29
+ ### Minor Changes
30
+
31
+ - 69f7d52: 콘텐츠 유형(Collection)에 **주소 없는 유형**(`basePath: ""`)을 지원합니다(ADR-0060). 강사·리뷰처럼 페이지 안에서 불러와 쓰는 콘텐츠는 이제 라우트 없이 운영할 수 있습니다 — `resolvePostUrl`/`resolvePostPath`는 이런 유형의 글에 항상 `null`을 반환하고, `validateCollections`는 basePath 형식·중복 검사를 건너뜁니다(여러 개 공존 허용). 외부 사이트는 posts API의 `collectionKey` 필터로 내용만 가져다 페이지 안에서 렌더하면 됩니다(`RootTaleBlogList`를 임베디드로 쓸 때는 자체 `postHref` 제공 권장). 소속 판정(`resolvePostCollection`)은 영향 없음 — key만으로 소속이 성립합니다. 기존 유형(basePath 있는 유형)은 동작 변화가 없습니다.
32
+
33
+ ### Patch Changes
34
+
35
+ - bae4a65: `package.json`에 `sideEffects`를 선언합니다(`["*.css"]` — CSS는 명시적 side-effect import 예외, 나머지는 side-effect 없음을 확인). 소스 전수 감사(등록·전역 상태·DOM API 호출 없음)를 거쳤습니다. 실측 결과 현재 Next.js 16.2.6 Turbopack 빌드에서는 이 선언만으로 소비 사이트 번들이 줄지 않습니다 — `SiteRenderer`가 17종 빌트인 섹션을 런타임 문자열로 디스패치하는 단일 함수라 도달성이 항상 전체이고, `templates` 서브패스가 전 섹션을 named export로 공개해 tsup 빌드 산출물이 미리 하나의 공유 청크로 병합되기 때문입니다. 소비 사이트 측 `optimizePackageImports`도 효과가 없음을 확인했습니다(사전 병합된 산출물이라 재작성 대상이 없음). 이번 선언은 향후 번들러 개선이나 dynamic import 재도입 시 전제조건을 미리 충족해 두는 무해한 위생 변경입니다. 동작·export 표면 변경 없음.
36
+ - Updated dependencies [69f7d52]
37
+ - @roottale/cms-core@0.46.0
38
+ - @roottale/cms-client@0.46.0
39
+
3
40
  ## 0.45.0
4
41
 
5
42
  ### Minor Changes
@@ -904,6 +904,17 @@ var SiteConfigSchema = z.object({
904
904
  collections: z.array(CollectionSchema).default([]),
905
905
  /** 사이트 전역 토큰 override (`--rt-*` CSS 변수 → 값). 비우면 admin /design SSoT. */
906
906
  theme: z.record(z.string()).default({}),
907
+ /**
908
+ * 테마 방향(Theme Directions, `@roottale/tokens` 프리셋 id — 예: "d1-editorial").
909
+ * root layout 이 `<html data-rt-direction="…">` 로 부여해
910
+ * `@roottale/tokens/theme-directions.css` 의 `[data-rt-direction="…"]` 규칙을
911
+ * 활성화한다(roottale-docs `docs/design/theme-directions.md`). 값은 문자열로만
912
+ * 검증한다 — `@roottale/cms-renderer-next` 는 `@roottale/tokens` 를 직접
913
+ * 의존하지 않으므로 유효 id 집합은 `@roottale/tokens/theme-directions` 의
914
+ * `ThemeDirectionId` 를 참조해 `site.config.ts` 작성 시점에 타입으로 좁힌다.
915
+ * 미지정 시 속성 자체가 안 붙어 완전히 무변화(기존 동작).
916
+ */
917
+ direction: z.string().optional(),
907
918
  nav: z.array(NavItemSchema).default([]),
908
919
  /** path("/", "/services", …) → 섹션 배열. */
909
920
  pages: z.record(z.array(SectionSchema))
@@ -947,4 +958,4 @@ export {
947
958
  parseSiteConfig,
948
959
  defineSiteConfig
949
960
  };
950
- //# sourceMappingURL=chunk-GUV5WHD5.js.map
961
+ //# sourceMappingURL=chunk-UM37DOIK.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/templates/site-config-version.ts","../src/templates/site-config.ts"],"sourcesContent":["/**\n * `SiteConfig` 계약 버전 (ADR-0086 D2 — 팩 ↔ renderer 호환성 계약).\n *\n * `site-config.ts` 는 이미 SIZE_OK 상한 근처(canonical SectionSchema\n * registry)라 버전 해석 로직은 별도 모듈에 두고 `site-config.ts` 에서\n * re-export 한다.\n *\n * 팩 manifest(`packages/assembly/src/pack-manifest.ts`)의\n * `siteConfigVersion` 필드가 이 버전과 비교 대상 — 팩이 요구하는 버전이\n * renderer 가 실제로 해석하는 버전보다 높으면 조립 전 fail-fast 해야 한다.\n */\n\n/** 현재 `SiteConfig` 스키마 버전. 계약 필드 추가 등 breaking 변경 시에만 올린다. */\nexport const SITE_CONFIG_SCHEMA_VERSION = 1;\n\n/** `schemaVersion` 도입(버전 1) 이전에 작성된 config 가 갖는 암묵 버전. 불변. */\nconst LEGACY_SITE_CONFIG_SCHEMA_VERSION = 1;\n\n/**\n * `config.schemaVersion` 해석 헬퍼 — 필드 미지정(기존 고객\n * `site.config.ts`, `schemaVersion` 도입 이전 작성분)은 버전 1 로 해석한다\n * (하위 호환, ADR-0086 D2). 현재 버전 상수가 아니라 리터럴 1 — 후일\n * `SITE_CONFIG_SCHEMA_VERSION` 이 올라도 미지정 config 는 계속 1 이다.\n */\nexport function resolveSiteConfigSchemaVersion(config: {\n schemaVersion?: number;\n}): number {\n return config.schemaVersion ?? LEGACY_SITE_CONFIG_SCHEMA_VERSION;\n}\n","/**\n * `@roottale/cms-renderer-next/templates` — canonical `SiteConfig` 스키마.\n *\n * ADR-0040 P2 + P0.5 RFC §① (`roottale-docs/docs/services/external-site-blockification.md`).\n *\n * 설계 원칙 (codex consult #1 반영):\n * - **계약 = `section type + variant + renderer registry`.** tier 는 스키마 필드가\n * 아니라 문서/거버넌스용 성숙도 메타데이터.\n * - **100% serializable** — 함수/JSX 금지 (Astro parity + admin preview 동일 경로).\n * escape hatch 는 config 안 함수가 아니라 `customSections` registry\n * (`SiteRenderer` 에 빌드 시 type→컴포넌트 주입).\n * - CMS-bound 섹션(`blog-list`/`lead-form`)은 `RootTaleBlogList`/`RootTaleLeadForm`\n * 으로 위임 — templates 는 cms-renderer 코어를 단방향 의존 (RFC §②).\n *\n * RFC §① 대비 구현 정정:\n * - `site.url` 은 optional — 스타터/외부 사이트가 `SITE_URL` env 로 런타임 해석하는\n * 기존 패턴(P4 스타터)과 충돌하므로 config 강제 대신 env fallback 허용.\n * - 빌트인에 `rich-text` 추가 (P4 스타터 기 운영 섹션 — \"동일 패턴\" 군).\n * allow: SIZE_OK — canonical SectionSchema registry이며 W1-2 계약이 이 파일 수정을 요구한다.\n */\nimport { z } from \"zod\";\n\nexport {\n SITE_CONFIG_SCHEMA_VERSION,\n resolveSiteConfigSchemaVersion,\n} from \"./site-config-version.js\";\n\nconst JsonValue: z.ZodType<unknown> = z.lazy(() =>\n z.union([\n z.string(),\n z.number(),\n z.boolean(),\n z.null(),\n z.array(JsonValue),\n z.record(JsonValue),\n ]),\n);\n\nexport const NavItemSchema = z.object({\n label: z.string(),\n href: z.string(),\n children: z\n .array(z.object({ label: z.string(), href: z.string() }))\n .optional(),\n});\nexport type NavItem = z.infer<typeof NavItemSchema>;\n\nconst CtaSchema = z.object({ label: z.string(), href: z.string() });\nexport type SectionCta = z.infer<typeof CtaSchema>;\n\nconst MetricSchema = z.object({\n value: z.string(),\n unit: z.string().optional(),\n label: z.string(),\n source: z.string().optional(),\n imageSrc: z.string().optional(),\n imageAlt: z.string().optional(),\n});\n\n/**\n * 모든 섹션 공통 필드. `theme` 는 섹션 스코프 CSS 변수 override —\n * key 는 `--rt-*` custom property 이름, 값은 CSS 값.\n * 예) `{ \"--rt-color-primary\": \"#0B1F49\" }`\n */\nconst SectionBase = z.object({\n /** 안정적 anchor·dedup·preview 매핑용. 페이지 내 유일. */\n id: z.string().optional(),\n /** 빌트인 또는 customSections registry 키. kebab-case. */\n type: z.string(),\n /** 같은 type 의 비주얼 변형. 빌트인 type 은 enum 으로 좁힘. */\n variant: z.string().optional(),\n /** 섹션 스코프 토큰 override (`--rt-*` CSS 변수 → 값). */\n theme: z.record(z.string()).optional(),\n /** 섹션별 직렬화 props. */\n props: z.record(JsonValue).default({}),\n});\n\n// ── 빌트인 섹션 (props 좁힘 — 런타임 + 타입) ────────────────────────────────\n\nexport const SECTION_VARIANTS = {\n hero: [\"split\", \"image\", \"minimal\", \"carousel\", \"overlay-panel\"],\n services: [\n \"grid\",\n \"list\",\n \"index-rows\",\n \"split-featured\",\n \"action-rail\",\n \"photo-cards\",\n ],\n faq: [\"default\", \"two-column\", \"with-contact\", \"content-accordion\"],\n \"cta-banner\": [\"default\", \"photo-overlay\"],\n trust: [\n \"stat-band\",\n \"logo-cloud\",\n \"feature-grid\",\n \"logo-marquee\",\n \"credential-list\",\n \"dashboard\",\n ],\n contact: [\"form-map-5050\", \"split\", \"channel-cards\", \"visit-band\"],\n hours: [\"table\", \"compact\"],\n pricing: [\"table\", \"cards\"],\n process: [\"horizontal\", \"vertical\", \"timeline-marked\"],\n \"before-after\": [\"slider\", \"side-by-side\"],\n testimonials: [\"editorial-quote\", \"quote-rail\", \"star-compact\"],\n team: [\"grid\", \"spotlight\", \"expanding-stage\", \"row\"],\n expertise: [\"tab-stage\", \"cards\"],\n spaces: [\"stage\", \"mosaic\"],\n concerns: [\"figure-map\", \"list\"],\n footer: [\"columns\", \"minimal\"],\n} as const;\n\n/**\n * `carousel` variant 슬라이드 — 카피는 슬라이드마다 바뀌지 않는다(고정 오버레이).\n * 슬라이드는 배경 사진 전환만 담당 — `alt`/`caption` 모두 h1 이 아니다\n * (publish-gate h1 모델은 `props.title` 만 본다, W6-1).\n */\nconst HeroCarouselSlideSchema = z.object({\n image: z.string(),\n alt: z.string(),\n caption: z.string().optional(),\n eyebrow: z.string().optional(),\n title: z.string().optional(),\n subtitle: z.string().optional(),\n description: z.string().optional(),\n primaryCta: CtaSchema.optional(),\n secondaryCta: CtaSchema.optional(),\n tabLabel: z.string().optional(),\n tabMeta: z.string().optional(),\n metrics: z.array(MetricSchema).max(4).optional(),\n});\n\nconst HeroProofMetricsSchema = z.object({\n items: z.array(MetricSchema).min(1).max(4),\n position: z.enum([\"inline\", \"overlay\"]).default(\"inline\"),\n});\n\nexport const HeroSectionSchema = SectionBase.extend({\n type: z.literal(\"hero\"),\n variant: z.enum(SECTION_VARIANTS.hero).default(\"split\"),\n props: z.object({\n eyebrow: z.string().optional(),\n /** `\\n` 으로 줄바꿈. */\n title: z.string(),\n description: z.string().optional(),\n imageSrc: z.string().optional(),\n imageAlt: z.string().optional(),\n cta: CtaSchema.optional(),\n /** `carousel` 전용 — 고정 카피 아래 배경만 전환되는 슬라이드. 2-8개. */\n slides: z.array(HeroCarouselSlideSchema).min(2).max(8).optional(),\n /** `carousel` 전용 — 부제(슬라이드와 무관한 고정 카피). */\n subtitle: z.string().optional(),\n /** `carousel` 전용. 기본 true — `useReducedMotion` 시 렌더러가 강제 off. */\n autoplay: z.boolean().optional(),\n /** `carousel` 전용, ms. 기본 6000. */\n intervalMs: z.number().min(3000).max(10000).optional(),\n /**\n * `carousel` 전용 배경 전환 모션(ADR-0086 P2 D3). 기본 \"slide\"(기존 embla\n * 가로 스크롤). \"curtain\" = clip-path 와이프 + 신 스윕(chambarun 이식).\n * variant 는 그대로 \"carousel\" — 신규 variant 아님(\"variant=구조,\n * motion=인상\" 규칙).\n */\n transition: z.enum([\"slide\", \"curtain\"]).optional(),\n proofMetrics: HeroProofMetricsSchema.optional(),\n scrim: z.enum([\"none\", \"soft\", \"strong\"]).optional(),\n }),\n}).superRefine((section, ctx) => {\n if (section.variant === \"overlay-panel\") {\n if (!section.props.imageSrc) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"imageSrc\"],\n message: \"overlay-panel hero 는 imageSrc 가 필수입니다.\",\n });\n }\n if (!section.props.imageAlt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"imageAlt\"],\n message: \"overlay-panel hero 는 imageAlt 가 필수입니다.\",\n });\n }\n }\n if (section.variant !== \"carousel\") return;\n if (section.props.title.length < 1 || section.props.title.length > 80) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"title\"],\n message: \"carousel hero 제목은 1-80자여야 합니다.\",\n });\n }\n if (!section.props.slides || section.props.slides.length < 2) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"slides\"],\n message: \"carousel hero 는 slides 2-8개가 필요합니다.\",\n });\n }\n});\n\nexport const RichTextSectionSchema = SectionBase.extend({\n type: z.literal(\"rich-text\"),\n props: z.object({\n heading: z.string().optional(),\n /** `\\n\\n` 으로 문단 분리. */\n body: z.string(),\n }),\n});\n\nexport const ServicesSectionSchema = SectionBase.extend({\n type: z.literal(\"services\"),\n /**\n * C10 §1-2 — `index-rows`(hairline 인덱스 행) · `split-featured`(비대칭\n * 5/7, 대표 서비스 1개 + 나머지 컴팩트 리스트) 추가. AI-slop 금지 #1/#2\n * (아이콘 그리드·균등 카드) 대체 문법.\n */\n variant: z.enum(SECTION_VARIANTS.services).default(\"grid\"),\n props: z.object({\n heading: z.string().optional(),\n description: z.string().optional(),\n items: z\n .array(\n z.object({\n title: z.string(),\n subtitle: z.string().optional(),\n description: z.string().optional(),\n href: z.string().optional(),\n iconSrc: z.string().optional(),\n iconAlt: z.string().optional(),\n imageSrc: z.string().optional(),\n imageAlt: z.string().optional(),\n kind: z.string().optional(),\n ctaLabel: z.string().optional(),\n chips: z.array(z.string()).max(6).optional(),\n meta: z.array(z.string()).max(8).optional(),\n }),\n )\n .min(1)\n .max(12),\n }),\n}).superRefine((section, ctx) => {\n if (section.variant === \"split-featured\" && section.props.items.length < 2) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"items\"],\n message:\n \"split-featured 는 대표 서비스 1개 + 나머지 최소 1개, 총 2개 이상의 items 가 필요합니다.\",\n });\n }\n section.props.items.forEach((item, index) => {\n if (item.iconSrc && !item.iconAlt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"items\", index, \"iconAlt\"],\n message: \"iconSrc 가 있으면 iconAlt 가 필요합니다.\",\n });\n }\n if (section.variant === \"photo-cards\" && !item.imageSrc) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"items\", index, \"imageSrc\"],\n message: \"photo-cards 서비스 항목은 imageSrc 가 필요합니다.\",\n });\n }\n if (section.variant === \"photo-cards\" && !item.imageAlt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"items\", index, \"imageAlt\"],\n message: \"photo-cards 서비스 항목은 imageAlt 가 필요합니다.\",\n });\n }\n });\n});\n\nconst FooterLogoSchema = z.object({\n src: z.string(),\n alt: z.string(),\n});\n\nconst FooterLinkSchema = z.object({\n label: z.string(),\n href: z.string(),\n});\n\nconst FooterColumnSchema = z.object({\n title: z.string(),\n links: z.array(FooterLinkSchema).min(1).max(12),\n});\n\nconst FooterContactInfoSchema = z.object({\n address: z.string().optional(),\n phone: z.string().optional(),\n email: z.string().optional(),\n});\n\nconst FooterSocialLinkSchema = z.object({\n kind: z.string(),\n href: z.string(),\n});\n\nexport const FooterSectionSchema = SectionBase.extend({\n type: z.literal(\"footer\"),\n variant: z.enum(SECTION_VARIANTS.footer).default(\"columns\"),\n props: z.object({\n businessName: z.string(),\n logo: FooterLogoSchema.optional(),\n description: z.string().optional(),\n columns: z.array(FooterColumnSchema).max(6).optional(),\n contactInfo: FooterContactInfoSchema.optional(),\n legalInfo: z.string().optional(),\n privacyHref: z.string().optional(),\n termsHref: z.string().optional(),\n socialLinks: z.array(FooterSocialLinkSchema).max(8).optional(),\n copyright: z.string().optional(),\n /** 'hidden' 은 화이트라벨 plan gate 통과 시만 유효 (미지정 = 'default' 렌더). tenant 커스터마이즈 대상 아님 — 에디터 폼에 노출하지 않는다. */\n credit: z.enum([\"default\", \"hidden\"]).optional(),\n }),\n}).superRefine((section, ctx) => {\n if (\n section.variant === \"columns\" &&\n (!section.props.columns || section.props.columns.length === 0)\n ) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"columns\"],\n message: \"columns footer 는 columns 1개 이상이 필요합니다.\",\n });\n }\n});\n\nconst FaqItemSchema = z.object({ question: z.string(), answer: z.string() });\n\nconst FaqGroupSchema = z.object({\n title: z.string(),\n items: z.array(FaqItemSchema).min(1).max(12),\n});\n\nconst FaqContactSchema = z.object({\n title: z.string(),\n description: z.string().optional(),\n phone: z.string().optional(),\n cta: CtaSchema.optional(),\n});\n\nconst FaqContentItemSchema = z.object({\n title: z.string(),\n summary: z.string().optional(),\n body: z.string(),\n signs: z.array(z.string()).max(8).optional(),\n href: z.string().optional(),\n});\n\nconst FaqContentGroupSchema = z.object({\n title: z.string(),\n items: z.array(FaqContentItemSchema).min(1).max(12),\n});\n\nexport const FaqSectionSchema = SectionBase.extend({\n type: z.literal(\"faq\"),\n variant: z.enum(SECTION_VARIANTS.faq).default(\"default\"),\n props: z.object({\n heading: z.string().optional(),\n items: z.array(FaqItemSchema).min(1).max(20).optional(),\n /** `two-column` 전용 — 그룹 헤더 + 항목. 없으면 기존 flat items 를 사용한다. */\n groups: z.array(FaqGroupSchema).min(1).max(6).optional(),\n /** `with-contact` 전용 — 우측 sticky 상담 유도 카드. */\n contact: FaqContactSchema.optional(),\n /** `content-accordion` 전용 — FAQPage가 아닌 질환/서비스 설명 accordion. */\n contentGroups: z.array(FaqContentGroupSchema).min(1).max(6).optional(),\n /** FAQPage JSON-LD 주입 (기본 true — SEO 3 pillars). 페이지에 FAQ 섹션이 여럿이면 하나만 true 로. */\n jsonLd: z.boolean().default(true),\n }),\n}).superRefine((section, ctx) => {\n const hasContentGroups = Boolean(\n section.props.contentGroups && section.props.contentGroups.length > 0,\n );\n if (section.variant === \"content-accordion\") {\n if (!hasContentGroups) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"contentGroups\"],\n message: \"content-accordion faq sections require contentGroups\",\n });\n }\n return;\n }\n const hasItems = Boolean(section.props.items && section.props.items.length > 0);\n const hasGroups = Boolean(section.props.groups && section.props.groups.length > 0);\n if (!hasItems && !hasGroups) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"items\"],\n message: \"faq sections require items or groups\",\n });\n }\n if (section.variant === \"with-contact\" && !section.props.contact) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"contact\"],\n message: \"with-contact faq sections require contact\",\n });\n }\n});\n\nexport const CtaBannerSectionSchema = SectionBase.extend({\n type: z.literal(\"cta-banner\"),\n /** C10 §1-5 — `photo-overlay`: 풀블리드 사진 + 다크 오버레이 극단 대비 CTA. */\n variant: z.enum(SECTION_VARIANTS[\"cta-banner\"]).default(\"default\"),\n props: z.object({\n title: z.string(),\n description: z.string().optional(),\n cta: CtaSchema.optional(),\n /** `photo-overlay` 전용 — 필수(사진 없으면 렌더 거부). */\n image: z.string().optional(),\n imageAlt: z.string().optional(),\n }),\n}).superRefine((section, ctx) => {\n if (section.variant !== \"photo-overlay\") return;\n if (!section.props.image) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"image\"],\n message: \"photo-overlay cta-banner 는 image 가 필수입니다.\",\n });\n }\n if (!section.props.imageAlt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"imageAlt\"],\n message: \"photo-overlay cta-banner 는 imageAlt 가 필수입니다.\",\n });\n }\n});\n\n/** → `RootTaleBlogList` 위임 (cms-bound). */\nexport const BlogListSectionSchema = SectionBase.extend({\n type: z.literal(\"blog-list\"),\n props: z.object({\n heading: z.string().optional(),\n limit: z.number().int().positive().optional(),\n /** 포스트 링크 베이스. 기본 `/blog`. */\n blogBasePath: z.string().optional(),\n emptyMessage: z.string().optional(),\n }),\n});\n\n/** → `RootTaleLeadForm` 위임 (cms-bound). */\nexport const LeadFormSectionSchema = SectionBase.extend({\n type: z.literal(\"lead-form\"),\n props: z.object({\n /** 사이트 자체 server 엔드포인트 (예: `/api/inquiry`). intake API 직접 지정 금지. */\n action: z.string(),\n vertical: z.enum([\"consulting\", \"medical\", \"tax\", \"legal\"]).optional(),\n heading: z.string().optional(),\n description: z.string().optional(),\n submitLabel: z.string().optional(),\n }),\n});\n\nconst TrustMetricSchema = MetricSchema;\n\nconst TrustCredentialSchema = z.object({\n name: z.string(),\n issuer: z.string().optional(),\n kind: z.enum([\"license\", \"education\", \"association\"]).optional(),\n image: z.string().optional(),\n /** `credential-list` 전용 — hairline 행의 tabular 연도. */\n year: z.string().optional(),\n});\n\nconst TrustLogoSchema = z.object({\n src: z.string(),\n alt: z.string(),\n href: z.string().optional(),\n});\n\nconst LegacyTrustLogoSchema = z\n .object({\n image: z.string(),\n alt: z.string(),\n href: z.string().optional(),\n })\n .transform((logo) => ({\n src: logo.image,\n alt: logo.alt,\n ...(logo.href ? { href: logo.href } : {}),\n }));\n\n/** logo-cloud/logo-marquee 공통 슬롯. legacy `{image, alt, href?}` 도 `{src, alt, href?}` 로 정규화한다. */\nconst TrustLogoSlotSchema = z.union([TrustLogoSchema, LegacyTrustLogoSchema]);\n\nconst TrustChartSchema = z.object({\n type: z.enum([\"bar\", \"line\"]).default(\"bar\"),\n title: z.string(),\n description: z.string().optional(),\n points: z\n .array(\n z.object({\n label: z.string(),\n value: z.number(),\n display: z.string().optional(),\n }),\n )\n .min(1)\n .max(12),\n});\n\nexport const TrustSectionSchema = SectionBase.extend({\n type: z.literal(\"trust\"),\n /**\n * C10 §1-3/1-4 — `logo-marquee`(C8 Marquee 소비, 흑백/저채도 로고 스트립) ·\n * `credential-list`(연도 tabular + hairline 자격 리스트) 추가.\n */\n variant: z.enum(SECTION_VARIANTS.trust).default(\"stat-band\"),\n props: z.object({\n heading: z.string().optional(),\n metrics: z.array(TrustMetricSchema).min(2).max(4).optional(),\n credentials: z.array(TrustCredentialSchema).max(8).optional(),\n logos: z.array(TrustLogoSlotSchema).max(8).optional(),\n /** `logo-marquee` 전용 — logo-cloud 와 동일한 `{src, alt, href?}` 슬롯. 최소 3개. */\n marqueeLogos: z.array(TrustLogoSlotSchema).min(3).max(16).optional(),\n chart: TrustChartSchema.optional(),\n disclaimer: z.string().optional(),\n }),\n}).superRefine((section, ctx) => {\n if (section.variant === \"stat-band\" && !section.props.metrics) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"metrics\"],\n message: \"stat-band trust sections require 2-4 metrics\",\n });\n }\n if (section.variant === \"logo-cloud\" && !section.props.logos) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"logos\"],\n message: \"logo-cloud trust sections require logos\",\n });\n }\n if (\n (section.variant === \"feature-grid\" || section.variant === \"credential-list\") &&\n !section.props.credentials\n ) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"credentials\"],\n message: `${section.variant} trust sections require credentials`,\n });\n }\n if (section.variant === \"logo-marquee\" && !section.props.marqueeLogos) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"marqueeLogos\"],\n message: \"logo-marquee trust sections require marqueeLogos (min 3)\",\n });\n }\n if (section.variant === \"dashboard\" && !section.props.chart) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"chart\"],\n message: \"dashboard trust sections require chart\",\n });\n }\n});\n\nconst ContactHoursSchema = z.object({\n day: z.string(),\n open: z.string(),\n close: z.string(),\n note: z.string().optional(),\n});\n\nconst ContactChannelSchema = z.object({\n label: z.string(),\n description: z.string().optional(),\n value: z.string().optional(),\n href: z.string().optional(),\n actionLabel: z.string().optional(),\n iconSrc: z.string().optional(),\n iconAlt: z.string().optional(),\n kind: z.string().optional(),\n});\n\nconst ContactMapSchema = z.object({\n facadeImageSrc: z.string().optional(),\n facadeImageAlt: z.string().optional(),\n provider: z.string().optional(),\n embedUrl: z.string().optional(),\n externalUrl: z.string().optional(),\n lat: z.number().optional(),\n lng: z.number().optional(),\n /**\n * 지도 로드 모드(ADR-0086 P2 D3, chambarun `.map-facade` 클릭-투-로드 이식).\n * 기본 \"lazy\"(기존 동작 그대로 — 실지도면 즉시 iframe `loading=\"lazy\"`).\n * \"click\" 은 정적 프리뷰(주소·지도 열기 버튼)만 먼저 그리고, 클릭 시에만\n * iframe 을 마운트한다(외부 지도 스크립트/네트워크 요청을 사용자 의도\n * 전까지 미루는 성능·프라이버시 절충 — additive, 기존 사이트는 영향 없음).\n */\n mapLoad: z.enum([\"lazy\", \"click\"]).optional(),\n});\n\nconst ContactActionSchema = z.object({\n label: z.string(),\n href: z.string(),\n kind: z.string().optional(),\n});\n\nexport const ContactSectionSchema = SectionBase.extend({\n type: z.literal(\"contact\"),\n variant: z.enum(SECTION_VARIANTS.contact).default(\"form-map-5050\"),\n props: z.object({\n heading: z.string().optional(),\n form: z.object({\n enabled: z.boolean(),\n vertical: z.enum([\"medical\", \"tax\", \"legal\", \"consulting\"]).optional(),\n }),\n phone: z.string().optional(),\n address: z.string().optional(),\n hours: z.array(ContactHoursSchema).max(8).optional(),\n mapEmbedUrl: z.string().optional(),\n map: ContactMapSchema.optional(),\n actions: z.array(ContactActionSchema).max(6).optional(),\n /** `channel-cards` 전용 — 카드당 하나의 행동. */\n channels: z.array(ContactChannelSchema).min(3).max(6).optional(),\n }),\n}).superRefine((section, ctx) => {\n if (section.variant !== \"channel-cards\") return;\n if (!section.props.channels) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"channels\"],\n message: \"channel-cards contact sections require 3-6 channels\",\n });\n }\n section.props.channels?.forEach((channel, index) => {\n if (channel.iconSrc && !channel.iconAlt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"channels\", index, \"iconAlt\"],\n message: \"iconSrc 가 있으면 iconAlt 가 필요합니다.\",\n });\n }\n });\n});\n\nconst PracticeDaySchema = z.enum([\n \"monday\",\n \"tuesday\",\n \"wednesday\",\n \"thursday\",\n \"friday\",\n \"saturday\",\n \"sunday\",\n]);\n\nconst HoursBadgeSlotsSchema = z.object({\n lunch: z.string().optional(),\n evening: z.string().optional(),\n closed: z.string().optional(),\n extra: z.array(z.string()).max(4).optional(),\n});\n\nconst HoursRowSchema = z.object({\n day: PracticeDaySchema,\n label: z.string(),\n hours: z.string(),\n lunchHours: z.string().optional(),\n badges: HoursBadgeSlotsSchema.optional(),\n note: z.string().optional(),\n});\n\nexport const HoursSectionSchema = SectionBase.extend({\n type: z.literal(\"hours\"),\n variant: z.enum(SECTION_VARIANTS.hours).default(\"table\"),\n props: z.object({\n eyebrow: z.string().optional(),\n heading: z.string().optional(),\n description: z.string().optional(),\n rows: z.array(HoursRowSchema).min(1).max(14),\n note: z.string().optional(),\n disclaimer: z.string().optional(),\n }),\n});\n\nconst PricingItemSchema = z.object({\n name: z.string(),\n description: z.string().optional(),\n price: z.string(),\n condition: z.string().optional(),\n});\n\nconst PricingGroupSchema = z.object({\n label: z.string(),\n items: z.array(PricingItemSchema).min(1).max(12),\n});\n\nexport const PricingSectionSchema = SectionBase.extend({\n type: z.literal(\"pricing\"),\n variant: z.enum(SECTION_VARIANTS.pricing).default(\"table\"),\n props: z.object({\n eyebrow: z.string().optional(),\n heading: z.string().optional(),\n description: z.string().optional(),\n groups: z.array(PricingGroupSchema).min(1).max(6),\n disclaimer: z.string().min(1),\n }),\n});\n\nconst ProcessTimelineItemSchema = z.object({\n eyebrow: z.string().optional(),\n title: z.string(),\n description: z.string(),\n duration: z.string().optional(),\n status: z.enum([\"complete\", \"current\", \"pending\"]).optional(),\n statusLabel: z.string().optional(),\n mark: z.enum([\"check\", \"dot\", \"none\"]).optional(),\n imageSrc: z.string().optional(),\n imageAlt: z.string().optional(),\n});\n\nexport const ProcessSectionSchema = SectionBase.extend({\n type: z.literal(\"process\"),\n variant: z.enum(SECTION_VARIANTS.process).default(\"horizontal\"),\n props: z.object({\n eyebrow: z.string().optional(),\n heading: z.string().optional(),\n description: z.string().optional(),\n items: z.array(ProcessTimelineItemSchema).min(2).max(8),\n connector: z.enum([\"line\", \"rail\"]).optional(),\n disclaimer: z.string().optional(),\n }),\n}).superRefine((section, ctx) => {\n section.props.items.forEach((item, index) => {\n if (item.imageSrc && !item.imageAlt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"items\", index, \"imageAlt\"],\n message: \"imageSrc 가 있으면 imageAlt 가 필요합니다.\",\n });\n }\n });\n});\n\nconst BeforeAfterImageSchema = z.object({\n src: z.string(),\n alt: z.string(),\n});\n\nexport const BeforeAfterSectionSchema = SectionBase.extend({\n type: z.literal(\"before-after\"),\n variant: z.enum(SECTION_VARIANTS[\"before-after\"]).default(\"slider\"),\n props: z.object({\n beforeImage: BeforeAfterImageSchema,\n afterImage: BeforeAfterImageSchema,\n beforeLabel: z.string().default(\"시공 전\"),\n afterLabel: z.string().default(\"시공 후\"),\n heading: z.string().optional(),\n description: z.string().optional(),\n disclaimer: z.string().optional(),\n }),\n});\n\n/** `quote-rail` 전용 hairline 인용 카드 하한 — 스크롤 레일이 자연스러운 최소치. */\nconst TestimonialItemSchema = z.object({\n quote: z.string().min(1).max(280),\n author: z.string().min(1),\n /** 케이스 라벨(예: \"허리디스크 · 비수술 치료 3개월\"). */\n context: z.string().optional(),\n rating: z.number().min(0).max(5).optional(),\n source: z.string().optional(),\n visitedAt: z.string().optional(),\n item: z.string().optional(),\n reply: z.string().optional(),\n});\n\n/**\n * C11 — 후기(testimonials) 섹션. 의료 vertical 치료경험담 광고는 규제 대상\n * (의료법 §56 ②4, `@roottale/audit-medical` MED-007) — `disclaimer` 슬롯은\n * 법정 고지문 전용, 스토리 fixture 카피는 심의-안전 톤으로 작성 의무\n * (roottale-docs `premium-component-backlog.md` C11).\n */\nexport const TestimonialsSectionSchema = SectionBase.extend({\n type: z.literal(\"testimonials\"),\n /**\n * `editorial-quote`(기본): 대형 인용 타이포 에디토리얼 — 1개면 중앙 정렬\n * 스테이지, 2개 이상이면 세로 스택(hairline 구분). `quote-rail`: 가로\n * 스크롤 레일(hairline 좌측 보더 컬럼, 균등 그림자 카드 금지).\n * `star-compact`(W8-7): 별점 중심 컴팩트 그리드 — 평균 별점 요약 밴드 +\n * hairline 행. 별점은 CSS 타이포 글리프(이모지·이미지 금지), 색은 전부\n * 토큰(variant×토큰 직교, 채움 폭만 데이터 주도 커스텀 프로퍼티).\n */\n variant: z.enum(SECTION_VARIANTS.testimonials).default(\"editorial-quote\"),\n props: z.object({\n heading: z.string(),\n description: z.string().optional(),\n items: z.array(TestimonialItemSchema).min(1).max(12),\n marquee: z.boolean().optional(),\n /** 법정 고지 슬롯(\"개인 경험이며 효과는 다를 수 있습니다\" 류). */\n disclaimer: z.string().optional(),\n }),\n});\n\nconst TeamMemberSchema = z\n .object({\n name: z.string().min(1),\n title: z.string().min(1),\n photoSrc: z.string().optional(),\n photoAlt: z.string().optional(),\n specialties: z.array(z.string().min(1)).min(1).max(6).optional(),\n credentials: z.array(z.string().min(1)).min(1).max(8).optional(),\n bio: z.string().max(360).optional(),\n href: z.string().optional(),\n ctaLabel: z.string().optional(),\n })\n .superRefine((member, ctx) => {\n if (member.photoSrc && !member.photoAlt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"photoAlt\"],\n message: \"photoSrc 가 있으면 photoAlt 가 필요합니다.\",\n });\n }\n });\n\nexport const TeamSectionSchema = SectionBase.extend({\n type: z.literal(\"team\"),\n variant: z.enum(SECTION_VARIANTS.team).default(\"grid\"),\n props: z.object({\n heading: z.string().optional(),\n description: z.string().optional(),\n members: z.array(TeamMemberSchema).min(2).max(8),\n }),\n});\n\nconst ExpertiseItemSchema = z\n .object({\n id: z.string().min(1),\n label: z.string().min(1),\n kicker: z.string().optional(),\n title: z.string().min(1),\n body: z.string().min(1),\n imageSrc: z.string().optional(),\n imageAlt: z.string().optional(),\n tags: z.array(z.string().min(1)).max(8).optional(),\n href: z.string().optional(),\n ctaLabel: z.string().optional(),\n })\n .superRefine((item, ctx) => {\n if (item.imageSrc && !item.imageAlt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"imageAlt\"],\n message: \"imageSrc 가 있으면 imageAlt 가 필요합니다.\",\n });\n }\n });\n\nexport const ExpertiseSectionSchema = SectionBase.extend({\n type: z.literal(\"expertise\"),\n variant: z.enum(SECTION_VARIANTS.expertise).default(\"tab-stage\"),\n props: z.object({\n heading: z.string().optional(),\n description: z.string().optional(),\n items: z.array(ExpertiseItemSchema).min(2).max(6),\n }),\n});\n\nconst SpaceItemSchema = z.object({\n id: z.string().min(1),\n label: z.string().min(1),\n kicker: z.string().optional(),\n title: z.string().optional(),\n description: z.string().optional(),\n imageSrc: z.string().min(1),\n imageAlt: z.string().min(1),\n tags: z.array(z.string().min(1)).max(8).optional(),\n});\n\nexport const SpacesSectionSchema = SectionBase.extend({\n type: z.literal(\"spaces\"),\n variant: z.enum(SECTION_VARIANTS.spaces).default(\"stage\"),\n props: z.object({\n heading: z.string().optional(),\n description: z.string().optional(),\n spaces: z.array(SpaceItemSchema).min(2).max(8),\n disclaimer: z.string().optional(),\n }),\n});\n\nconst ConcernRegionSchema = z.object({\n id: z.string().min(1),\n label: z.string().min(1),\n x: z.number().min(0).max(100).optional(),\n y: z.number().min(0).max(100).optional(),\n title: z.string().min(1),\n description: z.string().min(1),\n items: z.array(z.string().min(1)).max(8).optional(),\n href: z.string().optional(),\n ctaLabel: z.string().optional(),\n});\n\nexport const ConcernsSectionSchema = SectionBase.extend({\n type: z.literal(\"concerns\"),\n variant: z.enum(SECTION_VARIANTS.concerns).default(\"figure-map\"),\n props: z.object({\n heading: z.string().optional(),\n description: z.string().optional(),\n figureImage: z.string().optional(),\n figureAlt: z.string().optional(),\n regions: z.array(ConcernRegionSchema).min(3).max(10),\n disclaimer: z.string().min(1),\n }),\n}).superRefine((section, ctx) => {\n if (section.variant !== \"figure-map\") return;\n if (!section.props.figureImage) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"figureImage\"],\n message: \"figure-map concerns 는 figureImage 가 필요합니다.\",\n });\n }\n if (!section.props.figureAlt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"figureAlt\"],\n message: \"figure-map concerns 는 figureAlt 가 필요합니다.\",\n });\n }\n section.props.regions.forEach((region, index) => {\n if (typeof region.x !== \"number\") {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"regions\", index, \"x\"],\n message: \"figure-map concerns region 은 x 좌표가 필요합니다.\",\n });\n }\n if (typeof region.y !== \"number\") {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"regions\", index, \"y\"],\n message: \"figure-map concerns region 은 y 좌표가 필요합니다.\",\n });\n }\n });\n});\n\n/** customSections 용 fallback — `type` 자유, props 는 직렬화만 강제. */\nexport const CustomSectionSchema = SectionBase;\n\nexport const BUILTIN_SECTION_SCHEMAS: Record<string, z.ZodTypeAny> = {\n hero: HeroSectionSchema,\n \"rich-text\": RichTextSectionSchema,\n services: ServicesSectionSchema,\n faq: FaqSectionSchema,\n \"cta-banner\": CtaBannerSectionSchema,\n \"blog-list\": BlogListSectionSchema,\n \"lead-form\": LeadFormSectionSchema,\n trust: TrustSectionSchema,\n contact: ContactSectionSchema,\n hours: HoursSectionSchema,\n pricing: PricingSectionSchema,\n process: ProcessSectionSchema,\n \"before-after\": BeforeAfterSectionSchema,\n testimonials: TestimonialsSectionSchema,\n team: TeamSectionSchema,\n expertise: ExpertiseSectionSchema,\n spaces: SpacesSectionSchema,\n concerns: ConcernsSectionSchema,\n footer: FooterSectionSchema,\n};\n\n/** 빌트인 type 목록 (renderer registry 와 1:1). */\nexport const BUILTIN_SECTION_TYPES = Object.keys(\n BUILTIN_SECTION_SCHEMAS,\n) as readonly string[];\n\nexport type HeroSection = z.output<typeof HeroSectionSchema>;\nexport type RichTextSection = z.output<typeof RichTextSectionSchema>;\nexport type ServicesSection = z.output<typeof ServicesSectionSchema>;\nexport type FaqSection = z.output<typeof FaqSectionSchema>;\nexport type CtaBannerSection = z.output<typeof CtaBannerSectionSchema>;\nexport type BlogListSection = z.output<typeof BlogListSectionSchema>;\nexport type LeadFormSection = z.output<typeof LeadFormSectionSchema>;\nexport type TrustSection = z.output<typeof TrustSectionSchema>;\nexport type ContactSection = z.output<typeof ContactSectionSchema>;\nexport type HoursSection = z.output<typeof HoursSectionSchema>;\nexport type PricingSection = z.output<typeof PricingSectionSchema>;\nexport type ProcessSection = z.output<typeof ProcessSectionSchema>;\nexport type BeforeAfterSection = z.output<typeof BeforeAfterSectionSchema>;\nexport type TestimonialsSection = z.output<typeof TestimonialsSectionSchema>;\nexport type TeamSection = z.output<typeof TeamSectionSchema>;\nexport type ExpertiseSection = z.output<typeof ExpertiseSectionSchema>;\nexport type SpacesSection = z.output<typeof SpacesSectionSchema>;\nexport type ConcernsSection = z.output<typeof ConcernsSectionSchema>;\nexport type FooterSection = z.output<typeof FooterSectionSchema>;\nexport type CustomSection = z.output<typeof CustomSectionSchema>;\n\n/** 파싱 결과 섹션 (defaults 적용 후). */\nexport type Section =\n | HeroSection\n | RichTextSection\n | ServicesSection\n | FaqSection\n | CtaBannerSection\n | BlogListSection\n | LeadFormSection\n | TrustSection\n | ContactSection\n | HoursSection\n | PricingSection\n | ProcessSection\n | BeforeAfterSection\n | TestimonialsSection\n | TeamSection\n | ExpertiseSection\n | SpacesSection\n | ConcernsSection\n | FooterSection\n | CustomSection;\n\n/** config 작성용 섹션 (defaults 생략 가능). `site.config.ts` 에서 이 타입 사용. */\nexport type SectionInput =\n | z.input<typeof HeroSectionSchema>\n | z.input<typeof RichTextSectionSchema>\n | z.input<typeof ServicesSectionSchema>\n | z.input<typeof FaqSectionSchema>\n | z.input<typeof CtaBannerSectionSchema>\n | z.input<typeof BlogListSectionSchema>\n | z.input<typeof LeadFormSectionSchema>\n | z.input<typeof TrustSectionSchema>\n | z.input<typeof ContactSectionSchema>\n | z.input<typeof HoursSectionSchema>\n | z.input<typeof PricingSectionSchema>\n | z.input<typeof ProcessSectionSchema>\n | z.input<typeof BeforeAfterSectionSchema>\n | z.input<typeof TestimonialsSectionSchema>\n | z.input<typeof TeamSectionSchema>\n | z.input<typeof ExpertiseSectionSchema>\n | z.input<typeof SpacesSectionSchema>\n | z.input<typeof ConcernsSectionSchema>\n | z.input<typeof FooterSectionSchema>\n | z.input<typeof CustomSectionSchema>;\n\n/**\n * 섹션 스키마 — 빌트인 type 이면 해당 스키마로 *강제* 검증 (union fallthrough 로\n * 빌트인 오타이핑이 CustomSection 으로 조용히 통과하는 것을 차단), 미지 type 은\n * CustomSection 으로 통과 (렌더러가 customSections registry 로 해석).\n */\nexport const SectionSchema: z.ZodType<Section, z.ZodTypeDef, SectionInput> = z\n .object({ type: z.string() })\n .passthrough()\n .transform((section, ctx) => {\n const schema = BUILTIN_SECTION_SCHEMAS[section.type] ?? CustomSectionSchema;\n const result = schema.safeParse(section);\n if (!result.success) {\n for (const issue of result.error.issues) ctx.addIssue(issue);\n return z.NEVER;\n }\n return result.data as Section;\n }) as unknown as z.ZodType<Section, z.ZodTypeDef, SectionInput>;\n\n/**\n * 콘텐츠 Collection (ADR-0060) — 같은 글 풀(post)을 스트림으로 분리(공지 게시판 /\n * 블로그 그리드 등). `routes.ts` 의 `RouteCollection` 의 타입드·직렬화 상위집합 —\n * 한 category slug 는 정확히 하나의 collection 에 속해야 한다(다대일 = 라우팅 모호).\n * `layout` 은 레지스트리 키(open string) — 신규 레이아웃 추가 시 스키마 불변.\n * 선언 순서 = 라우팅 우선순위(`resolvePostCollection`).\n */\nexport const CollectionSchema = z.object({\n /** 안정 식별자 (라우트/가드/파생 키). */\n key: z.string(),\n /** 작성자 카드·nav 라벨. */\n label: z.string(),\n /** 라우트 base path (예: \"/notice\" | \"/blog\"). 앞 슬래시 포함. */\n basePath: z.string(),\n /** 레이아웃 레지스트리 키 (board=게시판, grid=카드 그리드, …). 미지 키는 렌더러 fallback. */\n layout: z.string().default(\"grid\"),\n /** 이 스트림에 속하는 category slug 들. */\n categories: z.array(z.string()).default([]),\n /** RSS 피드 포함. */\n feed: z.boolean().default(false),\n /** `${basePath}/categories/{slug}` 아카이브 생성. */\n archives: z.boolean().default(false),\n /** 글별 동적 OG. */\n og: z.boolean().default(false),\n /** 작성 UX: 하위 카테고리 1개 필수(미선택 발행 차단). */\n requireSubcategory: z.boolean().default(false),\n /** 작성 UX: 상단고정 토글 노출. */\n pinning: z.boolean().default(false),\n /** nav/카드 아이콘 키 (선택). */\n icon: z.string().optional(),\n});\nexport type Collection = z.output<typeof CollectionSchema>;\n\nexport const SiteConfigSchema = z.object({\n /**\n * `SiteConfig` 계약 버전 (ADR-0086 D2) — 팩 manifest 의 `siteConfigVersion`\n * 과 비교해 팩↔renderer 호환성을 표현한다. optional — 하위 호환(기존 고객\n * `site.config.ts` 에는 이 필드가 없다). 미지정은 버전 1 로 해석한다\n * (`resolveSiteConfigSchemaVersion`).\n */\n schemaVersion: z.number().int().positive().optional(),\n site: z.object({\n /** canonical origin. 생략 시 소비측이 `SITE_URL` env 등으로 해석. */\n url: z.string().url().optional(),\n title: z.string(),\n description: z.string().optional(),\n locale: z.string().default(\"ko-KR\"),\n og: z.object({ image: z.string().optional() }).optional(),\n }),\n /**\n * 콘텐츠 스트림 분리 (ADR-0060). 비우면 단일 /blog(레거시 동작). 선언 순서 =\n * 라우팅 우선순위. `routes.ts` 팩토리에 `collections` 로 전달해 sitemap/feed/\n * 아카이브를 스트림별로 파생.\n */\n collections: z.array(CollectionSchema).default([]),\n /** 사이트 전역 토큰 override (`--rt-*` CSS 변수 → 값). 비우면 admin /design SSoT. */\n theme: z.record(z.string()).default({}),\n nav: z.array(NavItemSchema).default([]),\n /** path(\"/\", \"/services\", …) → 섹션 배열. */\n pages: z.record(z.array(SectionSchema)),\n});\n\nexport type SiteConfig = z.output<typeof SiteConfigSchema>;\n/** config 작성용 (defaults 생략 가능). */\nexport type SiteConfigInput = Omit<\n z.input<typeof SiteConfigSchema>,\n \"pages\"\n> & { pages: Record<string, SectionInput[]> };\n\n/** config 검증 + defaults 적용. 실패 시 ZodError throw (빌드 타임 fail-fast 용). */\nexport function parseSiteConfig(input: unknown): SiteConfig {\n return SiteConfigSchema.parse(input);\n}\n\n/**\n * `site.config.ts` 작성 헬퍼 — 타입 추론 + 즉시 검증.\n *\n * ```ts\n * import { defineSiteConfig } from \"@roottale/cms-renderer-next/templates\";\n * export default defineSiteConfig({ site: { title: \"…\" }, pages: { \"/\": [ … ] } });\n * ```\n */\nexport function defineSiteConfig(input: SiteConfigInput): SiteConfig {\n return parseSiteConfig(input);\n}\n"],"mappings":";AAaO,IAAM,6BAA6B;AAG1C,IAAM,oCAAoC;AAQnC,SAAS,+BAA+B,QAEpC;AACT,SAAO,OAAO,iBAAiB;AACjC;;;ACRA,SAAS,SAAS;AAOlB,IAAM,YAAgC,EAAE;AAAA,EAAK,MAC3C,EAAE,MAAM;AAAA,IACN,EAAE,OAAO;AAAA,IACT,EAAE,OAAO;AAAA,IACT,EAAE,QAAQ;AAAA,IACV,EAAE,KAAK;AAAA,IACP,EAAE,MAAM,SAAS;AAAA,IACjB,EAAE,OAAO,SAAS;AAAA,EACpB,CAAC;AACH;AAEO,IAAM,gBAAgB,EAAE,OAAO;AAAA,EACpC,OAAO,EAAE,OAAO;AAAA,EAChB,MAAM,EAAE,OAAO;AAAA,EACf,UAAU,EACP,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,EACvD,SAAS;AACd,CAAC;AAGD,IAAM,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,EAAE,OAAO,EAAE,CAAC;AAGlE,IAAM,eAAe,EAAE,OAAO;AAAA,EAC5B,OAAO,EAAE,OAAO;AAAA,EAChB,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,OAAO,EAAE,OAAO;AAAA,EAChB,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,UAAU,EAAE,OAAO,EAAE,SAAS;AAChC,CAAC;AAOD,IAAM,cAAc,EAAE,OAAO;AAAA;AAAA,EAE3B,IAAI,EAAE,OAAO,EAAE,SAAS;AAAA;AAAA,EAExB,MAAM,EAAE,OAAO;AAAA;AAAA,EAEf,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA;AAAA,EAE7B,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,SAAS;AAAA;AAAA,EAErC,OAAO,EAAE,OAAO,SAAS,EAAE,QAAQ,CAAC,CAAC;AACvC,CAAC;AAIM,IAAM,mBAAmB;AAAA,EAC9B,MAAM,CAAC,SAAS,SAAS,WAAW,YAAY,eAAe;AAAA,EAC/D,UAAU;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,KAAK,CAAC,WAAW,cAAc,gBAAgB,mBAAmB;AAAA,EAClE,cAAc,CAAC,WAAW,eAAe;AAAA,EACzC,OAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAS,CAAC,iBAAiB,SAAS,iBAAiB,YAAY;AAAA,EACjE,OAAO,CAAC,SAAS,SAAS;AAAA,EAC1B,SAAS,CAAC,SAAS,OAAO;AAAA,EAC1B,SAAS,CAAC,cAAc,YAAY,iBAAiB;AAAA,EACrD,gBAAgB,CAAC,UAAU,cAAc;AAAA,EACzC,cAAc,CAAC,mBAAmB,cAAc,cAAc;AAAA,EAC9D,MAAM,CAAC,QAAQ,aAAa,mBAAmB,KAAK;AAAA,EACpD,WAAW,CAAC,aAAa,OAAO;AAAA,EAChC,QAAQ,CAAC,SAAS,QAAQ;AAAA,EAC1B,UAAU,CAAC,cAAc,MAAM;AAAA,EAC/B,QAAQ,CAAC,WAAW,SAAS;AAC/B;AAOA,IAAM,0BAA0B,EAAE,OAAO;AAAA,EACvC,OAAO,EAAE,OAAO;AAAA,EAChB,KAAK,EAAE,OAAO;AAAA,EACd,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,YAAY,UAAU,SAAS;AAAA,EAC/B,cAAc,UAAU,SAAS;AAAA,EACjC,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,SAAS,EAAE,MAAM,YAAY,EAAE,IAAI,CAAC,EAAE,SAAS;AACjD,CAAC;AAED,IAAM,yBAAyB,EAAE,OAAO;AAAA,EACtC,OAAO,EAAE,MAAM,YAAY,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC;AAAA,EACzC,UAAU,EAAE,KAAK,CAAC,UAAU,SAAS,CAAC,EAAE,QAAQ,QAAQ;AAC1D,CAAC;AAEM,IAAM,oBAAoB,YAAY,OAAO;AAAA,EAClD,MAAM,EAAE,QAAQ,MAAM;AAAA,EACtB,SAAS,EAAE,KAAK,iBAAiB,IAAI,EAAE,QAAQ,OAAO;AAAA,EACtD,OAAO,EAAE,OAAO;AAAA,IACd,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA;AAAA,IAE7B,OAAO,EAAE,OAAO;AAAA,IAChB,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,IACjC,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,IAC9B,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,IAC9B,KAAK,UAAU,SAAS;AAAA;AAAA,IAExB,QAAQ,EAAE,MAAM,uBAAuB,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA;AAAA,IAEhE,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA;AAAA,IAE9B,UAAU,EAAE,QAAQ,EAAE,SAAS;AAAA;AAAA,IAE/B,YAAY,EAAE,OAAO,EAAE,IAAI,GAAI,EAAE,IAAI,GAAK,EAAE,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOrD,YAAY,EAAE,KAAK,CAAC,SAAS,SAAS,CAAC,EAAE,SAAS;AAAA,IAClD,cAAc,uBAAuB,SAAS;AAAA,IAC9C,OAAO,EAAE,KAAK,CAAC,QAAQ,QAAQ,QAAQ,CAAC,EAAE,SAAS;AAAA,EACrD,CAAC;AACH,CAAC,EAAE,YAAY,CAAC,SAAS,QAAQ;AAC/B,MAAI,QAAQ,YAAY,iBAAiB;AACvC,QAAI,CAAC,QAAQ,MAAM,UAAU;AAC3B,UAAI,SAAS;AAAA,QACX,MAAM,EAAE,aAAa;AAAA,QACrB,MAAM,CAAC,SAAS,UAAU;AAAA,QAC1B,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AACA,QAAI,CAAC,QAAQ,MAAM,UAAU;AAC3B,UAAI,SAAS;AAAA,QACX,MAAM,EAAE,aAAa;AAAA,QACrB,MAAM,CAAC,SAAS,UAAU;AAAA,QAC1B,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF;AACA,MAAI,QAAQ,YAAY,WAAY;AACpC,MAAI,QAAQ,MAAM,MAAM,SAAS,KAAK,QAAQ,MAAM,MAAM,SAAS,IAAI;AACrE,QAAI,SAAS;AAAA,MACX,MAAM,EAAE,aAAa;AAAA,MACrB,MAAM,CAAC,SAAS,OAAO;AAAA,MACvB,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACA,MAAI,CAAC,QAAQ,MAAM,UAAU,QAAQ,MAAM,OAAO,SAAS,GAAG;AAC5D,QAAI,SAAS;AAAA,MACX,MAAM,EAAE,aAAa;AAAA,MACrB,MAAM,CAAC,SAAS,QAAQ;AAAA,MACxB,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACF,CAAC;AAEM,IAAM,wBAAwB,YAAY,OAAO;AAAA,EACtD,MAAM,EAAE,QAAQ,WAAW;AAAA,EAC3B,OAAO,EAAE,OAAO;AAAA,IACd,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA;AAAA,IAE7B,MAAM,EAAE,OAAO;AAAA,EACjB,CAAC;AACH,CAAC;AAEM,IAAM,wBAAwB,YAAY,OAAO;AAAA,EACtD,MAAM,EAAE,QAAQ,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM1B,SAAS,EAAE,KAAK,iBAAiB,QAAQ,EAAE,QAAQ,MAAM;AAAA,EACzD,OAAO,EAAE,OAAO;AAAA,IACd,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,IACjC,OAAO,EACJ;AAAA,MACC,EAAE,OAAO;AAAA,QACP,OAAO,EAAE,OAAO;AAAA,QAChB,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,QAC9B,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,QACjC,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,QAC1B,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,QAC7B,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,QAC7B,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,QAC9B,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,QAC9B,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,QAC1B,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,QAC9B,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,QAC3C,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,MAC5C,CAAC;AAAA,IACH,EACC,IAAI,CAAC,EACL,IAAI,EAAE;AAAA,EACX,CAAC;AACH,CAAC,EAAE,YAAY,CAAC,SAAS,QAAQ;AAC/B,MAAI,QAAQ,YAAY,oBAAoB,QAAQ,MAAM,MAAM,SAAS,GAAG;AAC1E,QAAI,SAAS;AAAA,MACX,MAAM,EAAE,aAAa;AAAA,MACrB,MAAM,CAAC,SAAS,OAAO;AAAA,MACvB,SACE;AAAA,IACJ,CAAC;AAAA,EACH;AACA,UAAQ,MAAM,MAAM,QAAQ,CAAC,MAAM,UAAU;AAC3C,QAAI,KAAK,WAAW,CAAC,KAAK,SAAS;AACjC,UAAI,SAAS;AAAA,QACX,MAAM,EAAE,aAAa;AAAA,QACrB,MAAM,CAAC,SAAS,SAAS,OAAO,SAAS;AAAA,QACzC,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AACA,QAAI,QAAQ,YAAY,iBAAiB,CAAC,KAAK,UAAU;AACvD,UAAI,SAAS;AAAA,QACX,MAAM,EAAE,aAAa;AAAA,QACrB,MAAM,CAAC,SAAS,SAAS,OAAO,UAAU;AAAA,QAC1C,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AACA,QAAI,QAAQ,YAAY,iBAAiB,CAAC,KAAK,UAAU;AACvD,UAAI,SAAS;AAAA,QACX,MAAM,EAAE,aAAa;AAAA,QACrB,MAAM,CAAC,SAAS,SAAS,OAAO,UAAU;AAAA,QAC1C,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACH,CAAC;AAED,IAAM,mBAAmB,EAAE,OAAO;AAAA,EAChC,KAAK,EAAE,OAAO;AAAA,EACd,KAAK,EAAE,OAAO;AAChB,CAAC;AAED,IAAM,mBAAmB,EAAE,OAAO;AAAA,EAChC,OAAO,EAAE,OAAO;AAAA,EAChB,MAAM,EAAE,OAAO;AACjB,CAAC;AAED,IAAM,qBAAqB,EAAE,OAAO;AAAA,EAClC,OAAO,EAAE,OAAO;AAAA,EAChB,OAAO,EAAE,MAAM,gBAAgB,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAChD,CAAC;AAED,IAAM,0BAA0B,EAAE,OAAO;AAAA,EACvC,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,OAAO,EAAE,OAAO,EAAE,SAAS;AAC7B,CAAC;AAED,IAAM,yBAAyB,EAAE,OAAO;AAAA,EACtC,MAAM,EAAE,OAAO;AAAA,EACf,MAAM,EAAE,OAAO;AACjB,CAAC;AAEM,IAAM,sBAAsB,YAAY,OAAO;AAAA,EACpD,MAAM,EAAE,QAAQ,QAAQ;AAAA,EACxB,SAAS,EAAE,KAAK,iBAAiB,MAAM,EAAE,QAAQ,SAAS;AAAA,EAC1D,OAAO,EAAE,OAAO;AAAA,IACd,cAAc,EAAE,OAAO;AAAA,IACvB,MAAM,iBAAiB,SAAS;AAAA,IAChC,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,IACjC,SAAS,EAAE,MAAM,kBAAkB,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,IACrD,aAAa,wBAAwB,SAAS;AAAA,IAC9C,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,IAC/B,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,IACjC,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,IAC/B,aAAa,EAAE,MAAM,sBAAsB,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,IAC7D,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA;AAAA,IAE/B,QAAQ,EAAE,KAAK,CAAC,WAAW,QAAQ,CAAC,EAAE,SAAS;AAAA,EACjD,CAAC;AACH,CAAC,EAAE,YAAY,CAAC,SAAS,QAAQ;AAC/B,MACE,QAAQ,YAAY,cACnB,CAAC,QAAQ,MAAM,WAAW,QAAQ,MAAM,QAAQ,WAAW,IAC5D;AACA,QAAI,SAAS;AAAA,MACX,MAAM,EAAE,aAAa;AAAA,MACrB,MAAM,CAAC,SAAS,SAAS;AAAA,MACzB,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACF,CAAC;AAED,IAAM,gBAAgB,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,GAAG,QAAQ,EAAE,OAAO,EAAE,CAAC;AAE3E,IAAM,iBAAiB,EAAE,OAAO;AAAA,EAC9B,OAAO,EAAE,OAAO;AAAA,EAChB,OAAO,EAAE,MAAM,aAAa,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAC7C,CAAC;AAED,IAAM,mBAAmB,EAAE,OAAO;AAAA,EAChC,OAAO,EAAE,OAAO;AAAA,EAChB,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,KAAK,UAAU,SAAS;AAC1B,CAAC;AAED,IAAM,uBAAuB,EAAE,OAAO;AAAA,EACpC,OAAO,EAAE,OAAO;AAAA,EAChB,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,MAAM,EAAE,OAAO;AAAA,EACf,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EAC3C,MAAM,EAAE,OAAO,EAAE,SAAS;AAC5B,CAAC;AAED,IAAM,wBAAwB,EAAE,OAAO;AAAA,EACrC,OAAO,EAAE,OAAO;AAAA,EAChB,OAAO,EAAE,MAAM,oBAAoB,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AACpD,CAAC;AAEM,IAAM,mBAAmB,YAAY,OAAO;AAAA,EACjD,MAAM,EAAE,QAAQ,KAAK;AAAA,EACrB,SAAS,EAAE,KAAK,iBAAiB,GAAG,EAAE,QAAQ,SAAS;AAAA,EACvD,OAAO,EAAE,OAAO;AAAA,IACd,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,OAAO,EAAE,MAAM,aAAa,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS;AAAA;AAAA,IAEtD,QAAQ,EAAE,MAAM,cAAc,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA;AAAA,IAEvD,SAAS,iBAAiB,SAAS;AAAA;AAAA,IAEnC,eAAe,EAAE,MAAM,qBAAqB,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA;AAAA,IAErE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,EAClC,CAAC;AACH,CAAC,EAAE,YAAY,CAAC,SAAS,QAAQ;AAC/B,QAAM,mBAAmB;AAAA,IACvB,QAAQ,MAAM,iBAAiB,QAAQ,MAAM,cAAc,SAAS;AAAA,EACtE;AACA,MAAI,QAAQ,YAAY,qBAAqB;AAC3C,QAAI,CAAC,kBAAkB;AACrB,UAAI,SAAS;AAAA,QACX,MAAM,EAAE,aAAa;AAAA,QACrB,MAAM,CAAC,SAAS,eAAe;AAAA,QAC/B,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AACA;AAAA,EACF;AACA,QAAM,WAAW,QAAQ,QAAQ,MAAM,SAAS,QAAQ,MAAM,MAAM,SAAS,CAAC;AAC9E,QAAM,YAAY,QAAQ,QAAQ,MAAM,UAAU,QAAQ,MAAM,OAAO,SAAS,CAAC;AACjF,MAAI,CAAC,YAAY,CAAC,WAAW;AAC3B,QAAI,SAAS;AAAA,MACX,MAAM,EAAE,aAAa;AAAA,MACrB,MAAM,CAAC,SAAS,OAAO;AAAA,MACvB,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACA,MAAI,QAAQ,YAAY,kBAAkB,CAAC,QAAQ,MAAM,SAAS;AAChE,QAAI,SAAS;AAAA,MACX,MAAM,EAAE,aAAa;AAAA,MACrB,MAAM,CAAC,SAAS,SAAS;AAAA,MACzB,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACF,CAAC;AAEM,IAAM,yBAAyB,YAAY,OAAO;AAAA,EACvD,MAAM,EAAE,QAAQ,YAAY;AAAA;AAAA,EAE5B,SAAS,EAAE,KAAK,iBAAiB,YAAY,CAAC,EAAE,QAAQ,SAAS;AAAA,EACjE,OAAO,EAAE,OAAO;AAAA,IACd,OAAO,EAAE,OAAO;AAAA,IAChB,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,IACjC,KAAK,UAAU,SAAS;AAAA;AAAA,IAExB,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,IAC3B,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAChC,CAAC;AACH,CAAC,EAAE,YAAY,CAAC,SAAS,QAAQ;AAC/B,MAAI,QAAQ,YAAY,gBAAiB;AACzC,MAAI,CAAC,QAAQ,MAAM,OAAO;AACxB,QAAI,SAAS;AAAA,MACX,MAAM,EAAE,aAAa;AAAA,MACrB,MAAM,CAAC,SAAS,OAAO;AAAA,MACvB,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACA,MAAI,CAAC,QAAQ,MAAM,UAAU;AAC3B,QAAI,SAAS;AAAA,MACX,MAAM,EAAE,aAAa;AAAA,MACrB,MAAM,CAAC,SAAS,UAAU;AAAA,MAC1B,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACF,CAAC;AAGM,IAAM,wBAAwB,YAAY,OAAO;AAAA,EACtD,MAAM,EAAE,QAAQ,WAAW;AAAA,EAC3B,OAAO,EAAE,OAAO;AAAA,IACd,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA;AAAA,IAE5C,cAAc,EAAE,OAAO,EAAE,SAAS;AAAA,IAClC,cAAc,EAAE,OAAO,EAAE,SAAS;AAAA,EACpC,CAAC;AACH,CAAC;AAGM,IAAM,wBAAwB,YAAY,OAAO;AAAA,EACtD,MAAM,EAAE,QAAQ,WAAW;AAAA,EAC3B,OAAO,EAAE,OAAO;AAAA;AAAA,IAEd,QAAQ,EAAE,OAAO;AAAA,IACjB,UAAU,EAAE,KAAK,CAAC,cAAc,WAAW,OAAO,OAAO,CAAC,EAAE,SAAS;AAAA,IACrE,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,IACjC,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACnC,CAAC;AACH,CAAC;AAED,IAAM,oBAAoB;AAE1B,IAAM,wBAAwB,EAAE,OAAO;AAAA,EACrC,MAAM,EAAE,OAAO;AAAA,EACf,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,MAAM,EAAE,KAAK,CAAC,WAAW,aAAa,aAAa,CAAC,EAAE,SAAS;AAAA,EAC/D,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA;AAAA,EAE3B,MAAM,EAAE,OAAO,EAAE,SAAS;AAC5B,CAAC;AAED,IAAM,kBAAkB,EAAE,OAAO;AAAA,EAC/B,KAAK,EAAE,OAAO;AAAA,EACd,KAAK,EAAE,OAAO;AAAA,EACd,MAAM,EAAE,OAAO,EAAE,SAAS;AAC5B,CAAC;AAED,IAAM,wBAAwB,EAC3B,OAAO;AAAA,EACN,OAAO,EAAE,OAAO;AAAA,EAChB,KAAK,EAAE,OAAO;AAAA,EACd,MAAM,EAAE,OAAO,EAAE,SAAS;AAC5B,CAAC,EACA,UAAU,CAAC,UAAU;AAAA,EACpB,KAAK,KAAK;AAAA,EACV,KAAK,KAAK;AAAA,EACV,GAAI,KAAK,OAAO,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;AACzC,EAAE;AAGJ,IAAM,sBAAsB,EAAE,MAAM,CAAC,iBAAiB,qBAAqB,CAAC;AAE5E,IAAM,mBAAmB,EAAE,OAAO;AAAA,EAChC,MAAM,EAAE,KAAK,CAAC,OAAO,MAAM,CAAC,EAAE,QAAQ,KAAK;AAAA,EAC3C,OAAO,EAAE,OAAO;AAAA,EAChB,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,QAAQ,EACL;AAAA,IACC,EAAE,OAAO;AAAA,MACP,OAAO,EAAE,OAAO;AAAA,MAChB,OAAO,EAAE,OAAO;AAAA,MAChB,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,IAC/B,CAAC;AAAA,EACH,EACC,IAAI,CAAC,EACL,IAAI,EAAE;AACX,CAAC;AAEM,IAAM,qBAAqB,YAAY,OAAO;AAAA,EACnD,MAAM,EAAE,QAAQ,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,EAKvB,SAAS,EAAE,KAAK,iBAAiB,KAAK,EAAE,QAAQ,WAAW;AAAA,EAC3D,OAAO,EAAE,OAAO;AAAA,IACd,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,SAAS,EAAE,MAAM,iBAAiB,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,IAC3D,aAAa,EAAE,MAAM,qBAAqB,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,IAC5D,OAAO,EAAE,MAAM,mBAAmB,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA;AAAA,IAEpD,cAAc,EAAE,MAAM,mBAAmB,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS;AAAA,IACnE,OAAO,iBAAiB,SAAS;AAAA,IACjC,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,EAClC,CAAC;AACH,CAAC,EAAE,YAAY,CAAC,SAAS,QAAQ;AAC/B,MAAI,QAAQ,YAAY,eAAe,CAAC,QAAQ,MAAM,SAAS;AAC7D,QAAI,SAAS;AAAA,MACX,MAAM,EAAE,aAAa;AAAA,MACrB,MAAM,CAAC,SAAS,SAAS;AAAA,MACzB,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACA,MAAI,QAAQ,YAAY,gBAAgB,CAAC,QAAQ,MAAM,OAAO;AAC5D,QAAI,SAAS;AAAA,MACX,MAAM,EAAE,aAAa;AAAA,MACrB,MAAM,CAAC,SAAS,OAAO;AAAA,MACvB,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACA,OACG,QAAQ,YAAY,kBAAkB,QAAQ,YAAY,sBAC3D,CAAC,QAAQ,MAAM,aACf;AACA,QAAI,SAAS;AAAA,MACX,MAAM,EAAE,aAAa;AAAA,MACrB,MAAM,CAAC,SAAS,aAAa;AAAA,MAC7B,SAAS,GAAG,QAAQ,OAAO;AAAA,IAC7B,CAAC;AAAA,EACH;AACA,MAAI,QAAQ,YAAY,kBAAkB,CAAC,QAAQ,MAAM,cAAc;AACrE,QAAI,SAAS;AAAA,MACX,MAAM,EAAE,aAAa;AAAA,MACrB,MAAM,CAAC,SAAS,cAAc;AAAA,MAC9B,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACA,MAAI,QAAQ,YAAY,eAAe,CAAC,QAAQ,MAAM,OAAO;AAC3D,QAAI,SAAS;AAAA,MACX,MAAM,EAAE,aAAa;AAAA,MACrB,MAAM,CAAC,SAAS,OAAO;AAAA,MACvB,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACF,CAAC;AAED,IAAM,qBAAqB,EAAE,OAAO;AAAA,EAClC,KAAK,EAAE,OAAO;AAAA,EACd,MAAM,EAAE,OAAO;AAAA,EACf,OAAO,EAAE,OAAO;AAAA,EAChB,MAAM,EAAE,OAAO,EAAE,SAAS;AAC5B,CAAC;AAED,IAAM,uBAAuB,EAAE,OAAO;AAAA,EACpC,OAAO,EAAE,OAAO;AAAA,EAChB,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,MAAM,EAAE,OAAO,EAAE,SAAS;AAC5B,CAAC;AAED,IAAM,mBAAmB,EAAE,OAAO;AAAA,EAChC,gBAAgB,EAAE,OAAO,EAAE,SAAS;AAAA,EACpC,gBAAgB,EAAE,OAAO,EAAE,SAAS;AAAA,EACpC,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,KAAK,EAAE,OAAO,EAAE,SAAS;AAAA,EACzB,KAAK,EAAE,OAAO,EAAE,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQzB,SAAS,EAAE,KAAK,CAAC,QAAQ,OAAO,CAAC,EAAE,SAAS;AAC9C,CAAC;AAED,IAAM,sBAAsB,EAAE,OAAO;AAAA,EACnC,OAAO,EAAE,OAAO;AAAA,EAChB,MAAM,EAAE,OAAO;AAAA,EACf,MAAM,EAAE,OAAO,EAAE,SAAS;AAC5B,CAAC;AAEM,IAAM,uBAAuB,YAAY,OAAO;AAAA,EACrD,MAAM,EAAE,QAAQ,SAAS;AAAA,EACzB,SAAS,EAAE,KAAK,iBAAiB,OAAO,EAAE,QAAQ,eAAe;AAAA,EACjE,OAAO,EAAE,OAAO;AAAA,IACd,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,MAAM,EAAE,OAAO;AAAA,MACb,SAAS,EAAE,QAAQ;AAAA,MACnB,UAAU,EAAE,KAAK,CAAC,WAAW,OAAO,SAAS,YAAY,CAAC,EAAE,SAAS;AAAA,IACvE,CAAC;AAAA,IACD,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,IAC3B,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,OAAO,EAAE,MAAM,kBAAkB,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,IACnD,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,IACjC,KAAK,iBAAiB,SAAS;AAAA,IAC/B,SAAS,EAAE,MAAM,mBAAmB,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA;AAAA,IAEtD,UAAU,EAAE,MAAM,oBAAoB,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EACjE,CAAC;AACH,CAAC,EAAE,YAAY,CAAC,SAAS,QAAQ;AAC/B,MAAI,QAAQ,YAAY,gBAAiB;AACzC,MAAI,CAAC,QAAQ,MAAM,UAAU;AAC3B,QAAI,SAAS;AAAA,MACX,MAAM,EAAE,aAAa;AAAA,MACrB,MAAM,CAAC,SAAS,UAAU;AAAA,MAC1B,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACA,UAAQ,MAAM,UAAU,QAAQ,CAAC,SAAS,UAAU;AAClD,QAAI,QAAQ,WAAW,CAAC,QAAQ,SAAS;AACvC,UAAI,SAAS;AAAA,QACX,MAAM,EAAE,aAAa;AAAA,QACrB,MAAM,CAAC,SAAS,YAAY,OAAO,SAAS;AAAA,QAC5C,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACH,CAAC;AAED,IAAM,oBAAoB,EAAE,KAAK;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,IAAM,wBAAwB,EAAE,OAAO;AAAA,EACrC,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAC7C,CAAC;AAED,IAAM,iBAAiB,EAAE,OAAO;AAAA,EAC9B,KAAK;AAAA,EACL,OAAO,EAAE,OAAO;AAAA,EAChB,OAAO,EAAE,OAAO;AAAA,EAChB,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,EAChC,QAAQ,sBAAsB,SAAS;AAAA,EACvC,MAAM,EAAE,OAAO,EAAE,SAAS;AAC5B,CAAC;AAEM,IAAM,qBAAqB,YAAY,OAAO;AAAA,EACnD,MAAM,EAAE,QAAQ,OAAO;AAAA,EACvB,SAAS,EAAE,KAAK,iBAAiB,KAAK,EAAE,QAAQ,OAAO;AAAA,EACvD,OAAO,EAAE,OAAO;AAAA,IACd,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,IACjC,MAAM,EAAE,MAAM,cAAc,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,IAC3C,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,IAC1B,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,EAClC,CAAC;AACH,CAAC;AAED,IAAM,oBAAoB,EAAE,OAAO;AAAA,EACjC,MAAM,EAAE,OAAO;AAAA,EACf,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,OAAO,EAAE,OAAO;AAAA,EAChB,WAAW,EAAE,OAAO,EAAE,SAAS;AACjC,CAAC;AAED,IAAM,qBAAqB,EAAE,OAAO;AAAA,EAClC,OAAO,EAAE,OAAO;AAAA,EAChB,OAAO,EAAE,MAAM,iBAAiB,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AACjD,CAAC;AAEM,IAAM,uBAAuB,YAAY,OAAO;AAAA,EACrD,MAAM,EAAE,QAAQ,SAAS;AAAA,EACzB,SAAS,EAAE,KAAK,iBAAiB,OAAO,EAAE,QAAQ,OAAO;AAAA,EACzD,OAAO,EAAE,OAAO;AAAA,IACd,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,IACjC,QAAQ,EAAE,MAAM,kBAAkB,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC;AAAA,IAChD,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC9B,CAAC;AACH,CAAC;AAED,IAAM,4BAA4B,EAAE,OAAO;AAAA,EACzC,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,OAAO,EAAE,OAAO;AAAA,EAChB,aAAa,EAAE,OAAO;AAAA,EACtB,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,QAAQ,EAAE,KAAK,CAAC,YAAY,WAAW,SAAS,CAAC,EAAE,SAAS;AAAA,EAC5D,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,MAAM,EAAE,KAAK,CAAC,SAAS,OAAO,MAAM,CAAC,EAAE,SAAS;AAAA,EAChD,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,UAAU,EAAE,OAAO,EAAE,SAAS;AAChC,CAAC;AAEM,IAAM,uBAAuB,YAAY,OAAO;AAAA,EACrD,MAAM,EAAE,QAAQ,SAAS;AAAA,EACzB,SAAS,EAAE,KAAK,iBAAiB,OAAO,EAAE,QAAQ,YAAY;AAAA,EAC9D,OAAO,EAAE,OAAO;AAAA,IACd,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,IACjC,OAAO,EAAE,MAAM,yBAAyB,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC;AAAA,IACtD,WAAW,EAAE,KAAK,CAAC,QAAQ,MAAM,CAAC,EAAE,SAAS;AAAA,IAC7C,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,EAClC,CAAC;AACH,CAAC,EAAE,YAAY,CAAC,SAAS,QAAQ;AAC/B,UAAQ,MAAM,MAAM,QAAQ,CAAC,MAAM,UAAU;AAC3C,QAAI,KAAK,YAAY,CAAC,KAAK,UAAU;AACnC,UAAI,SAAS;AAAA,QACX,MAAM,EAAE,aAAa;AAAA,QACrB,MAAM,CAAC,SAAS,SAAS,OAAO,UAAU;AAAA,QAC1C,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACH,CAAC;AAED,IAAM,yBAAyB,EAAE,OAAO;AAAA,EACtC,KAAK,EAAE,OAAO;AAAA,EACd,KAAK,EAAE,OAAO;AAChB,CAAC;AAEM,IAAM,2BAA2B,YAAY,OAAO;AAAA,EACzD,MAAM,EAAE,QAAQ,cAAc;AAAA,EAC9B,SAAS,EAAE,KAAK,iBAAiB,cAAc,CAAC,EAAE,QAAQ,QAAQ;AAAA,EAClE,OAAO,EAAE,OAAO;AAAA,IACd,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,aAAa,EAAE,OAAO,EAAE,QAAQ,qBAAM;AAAA,IACtC,YAAY,EAAE,OAAO,EAAE,QAAQ,qBAAM;AAAA,IACrC,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,IACjC,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,EAClC,CAAC;AACH,CAAC;AAGD,IAAM,wBAAwB,EAAE,OAAO;AAAA,EACrC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG;AAAA,EAChC,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,EAExB,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,EAC7B,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EAC1C,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,OAAO,EAAE,OAAO,EAAE,SAAS;AAC7B,CAAC;AAQM,IAAM,4BAA4B,YAAY,OAAO;AAAA,EAC1D,MAAM,EAAE,QAAQ,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAS9B,SAAS,EAAE,KAAK,iBAAiB,YAAY,EAAE,QAAQ,iBAAiB;AAAA,EACxE,OAAO,EAAE,OAAO;AAAA,IACd,SAAS,EAAE,OAAO;AAAA,IAClB,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,IACjC,OAAO,EAAE,MAAM,qBAAqB,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,IACnD,SAAS,EAAE,QAAQ,EAAE,SAAS;AAAA;AAAA,IAE9B,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,EAClC,CAAC;AACH,CAAC;AAED,IAAM,mBAAmB,EACtB,OAAO;AAAA,EACN,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtB,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACvB,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EAC/D,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EAC/D,KAAK,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,SAAS;AAAA,EAClC,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,UAAU,EAAE,OAAO,EAAE,SAAS;AAChC,CAAC,EACA,YAAY,CAAC,QAAQ,QAAQ;AAC5B,MAAI,OAAO,YAAY,CAAC,OAAO,UAAU;AACvC,QAAI,SAAS;AAAA,MACX,MAAM,EAAE,aAAa;AAAA,MACrB,MAAM,CAAC,UAAU;AAAA,MACjB,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACF,CAAC;AAEI,IAAM,oBAAoB,YAAY,OAAO;AAAA,EAClD,MAAM,EAAE,QAAQ,MAAM;AAAA,EACtB,SAAS,EAAE,KAAK,iBAAiB,IAAI,EAAE,QAAQ,MAAM;AAAA,EACrD,OAAO,EAAE,OAAO;AAAA,IACd,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,IACjC,SAAS,EAAE,MAAM,gBAAgB,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC;AAAA,EACjD,CAAC;AACH,CAAC;AAED,IAAM,sBAAsB,EACzB,OAAO;AAAA,EACN,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACpB,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACvB,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACvB,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACtB,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EACjD,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,UAAU,EAAE,OAAO,EAAE,SAAS;AAChC,CAAC,EACA,YAAY,CAAC,MAAM,QAAQ;AAC1B,MAAI,KAAK,YAAY,CAAC,KAAK,UAAU;AACnC,QAAI,SAAS;AAAA,MACX,MAAM,EAAE,aAAa;AAAA,MACrB,MAAM,CAAC,UAAU;AAAA,MACjB,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACF,CAAC;AAEI,IAAM,yBAAyB,YAAY,OAAO;AAAA,EACvD,MAAM,EAAE,QAAQ,WAAW;AAAA,EAC3B,SAAS,EAAE,KAAK,iBAAiB,SAAS,EAAE,QAAQ,WAAW;AAAA,EAC/D,OAAO,EAAE,OAAO;AAAA,IACd,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,IACjC,OAAO,EAAE,MAAM,mBAAmB,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC;AAAA,EAClD,CAAC;AACH,CAAC;AAED,IAAM,kBAAkB,EAAE,OAAO;AAAA,EAC/B,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACpB,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACvB,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC1B,UAAU,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC1B,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AACnD,CAAC;AAEM,IAAM,sBAAsB,YAAY,OAAO;AAAA,EACpD,MAAM,EAAE,QAAQ,QAAQ;AAAA,EACxB,SAAS,EAAE,KAAK,iBAAiB,MAAM,EAAE,QAAQ,OAAO;AAAA,EACxD,OAAO,EAAE,OAAO;AAAA,IACd,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,IACjC,QAAQ,EAAE,MAAM,eAAe,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC;AAAA,IAC7C,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,EAClC,CAAC;AACH,CAAC;AAED,IAAM,sBAAsB,EAAE,OAAO;AAAA,EACnC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACpB,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACvB,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS;AAAA,EACvC,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS;AAAA,EACvC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EACvB,aAAa,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC7B,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAAA,EAClD,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,UAAU,EAAE,OAAO,EAAE,SAAS;AAChC,CAAC;AAEM,IAAM,wBAAwB,YAAY,OAAO;AAAA,EACtD,MAAM,EAAE,QAAQ,UAAU;AAAA,EAC1B,SAAS,EAAE,KAAK,iBAAiB,QAAQ,EAAE,QAAQ,YAAY;AAAA,EAC/D,OAAO,EAAE,OAAO;AAAA,IACd,SAAS,EAAE,OAAO,EAAE,SAAS;AAAA,IAC7B,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,IACjC,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,IACjC,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,IAC/B,SAAS,EAAE,MAAM,mBAAmB,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,IACnD,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC;AAAA,EAC9B,CAAC;AACH,CAAC,EAAE,YAAY,CAAC,SAAS,QAAQ;AAC/B,MAAI,QAAQ,YAAY,aAAc;AACtC,MAAI,CAAC,QAAQ,MAAM,aAAa;AAC9B,QAAI,SAAS;AAAA,MACX,MAAM,EAAE,aAAa;AAAA,MACrB,MAAM,CAAC,SAAS,aAAa;AAAA,MAC7B,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACA,MAAI,CAAC,QAAQ,MAAM,WAAW;AAC5B,QAAI,SAAS;AAAA,MACX,MAAM,EAAE,aAAa;AAAA,MACrB,MAAM,CAAC,SAAS,WAAW;AAAA,MAC3B,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACA,UAAQ,MAAM,QAAQ,QAAQ,CAAC,QAAQ,UAAU;AAC/C,QAAI,OAAO,OAAO,MAAM,UAAU;AAChC,UAAI,SAAS;AAAA,QACX,MAAM,EAAE,aAAa;AAAA,QACrB,MAAM,CAAC,SAAS,WAAW,OAAO,GAAG;AAAA,QACrC,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AACA,QAAI,OAAO,OAAO,MAAM,UAAU;AAChC,UAAI,SAAS;AAAA,QACX,MAAM,EAAE,aAAa;AAAA,QACrB,MAAM,CAAC,SAAS,WAAW,OAAO,GAAG;AAAA,QACrC,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACH,CAAC;AAGM,IAAM,sBAAsB;AAE5B,IAAM,0BAAwD;AAAA,EACnE,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,KAAK;AAAA,EACL,cAAc;AAAA,EACd,aAAa;AAAA,EACb,aAAa;AAAA,EACb,OAAO;AAAA,EACP,SAAS;AAAA,EACT,OAAO;AAAA,EACP,SAAS;AAAA,EACT,SAAS;AAAA,EACT,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,MAAM;AAAA,EACN,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,QAAQ;AACV;AAGO,IAAM,wBAAwB,OAAO;AAAA,EAC1C;AACF;AA0EO,IAAM,gBAAgE,EAC1E,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAC3B,YAAY,EACZ,UAAU,CAAC,SAAS,QAAQ;AAC3B,QAAM,SAAS,wBAAwB,QAAQ,IAAI,KAAK;AACxD,QAAM,SAAS,OAAO,UAAU,OAAO;AACvC,MAAI,CAAC,OAAO,SAAS;AACnB,eAAW,SAAS,OAAO,MAAM,OAAQ,KAAI,SAAS,KAAK;AAC3D,WAAO,EAAE;AAAA,EACX;AACA,SAAO,OAAO;AAChB,CAAC;AASI,IAAM,mBAAmB,EAAE,OAAO;AAAA;AAAA,EAEvC,KAAK,EAAE,OAAO;AAAA;AAAA,EAEd,OAAO,EAAE,OAAO;AAAA;AAAA,EAEhB,UAAU,EAAE,OAAO;AAAA;AAAA,EAEnB,QAAQ,EAAE,OAAO,EAAE,QAAQ,MAAM;AAAA;AAAA,EAEjC,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA;AAAA,EAE1C,MAAM,EAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA;AAAA,EAE/B,UAAU,EAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA;AAAA,EAEnC,IAAI,EAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA;AAAA,EAE7B,oBAAoB,EAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA;AAAA,EAE7C,SAAS,EAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA;AAAA,EAElC,MAAM,EAAE,OAAO,EAAE,SAAS;AAC5B,CAAC;AAGM,IAAM,mBAAmB,EAAE,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOvC,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,EACpD,MAAM,EAAE,OAAO;AAAA;AAAA,IAEb,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,IAC/B,OAAO,EAAE,OAAO;AAAA,IAChB,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,IACjC,QAAQ,EAAE,OAAO,EAAE,QAAQ,OAAO;AAAA,IAClC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS;AAAA,EAC1D,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMD,aAAa,EAAE,MAAM,gBAAgB,EAAE,QAAQ,CAAC,CAAC;AAAA;AAAA,EAEjD,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC;AAAA,EACtC,KAAK,EAAE,MAAM,aAAa,EAAE,QAAQ,CAAC,CAAC;AAAA;AAAA,EAEtC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACxC,CAAC;AAUM,SAAS,gBAAgB,OAA4B;AAC1D,SAAO,iBAAiB,MAAM,KAAK;AACrC;AAUO,SAAS,iBAAiB,OAAoC;AACnE,SAAO,gBAAgB,KAAK;AAC9B;","names":[]}
1
+ {"version":3,"sources":["../src/templates/site-config-version.ts","../src/templates/site-config.ts"],"sourcesContent":["/**\n * `SiteConfig` 계약 버전 (ADR-0086 D2 — 팩 ↔ renderer 호환성 계약).\n *\n * `site-config.ts` 는 이미 SIZE_OK 상한 근처(canonical SectionSchema\n * registry)라 버전 해석 로직은 별도 모듈에 두고 `site-config.ts` 에서\n * re-export 한다.\n *\n * 팩 manifest(`packages/assembly/src/pack-manifest.ts`)의\n * `siteConfigVersion` 필드가 이 버전과 비교 대상 — 팩이 요구하는 버전이\n * renderer 가 실제로 해석하는 버전보다 높으면 조립 전 fail-fast 해야 한다.\n */\n\n/** 현재 `SiteConfig` 스키마 버전. 계약 필드 추가 등 breaking 변경 시에만 올린다. */\nexport const SITE_CONFIG_SCHEMA_VERSION = 1;\n\n/** `schemaVersion` 도입(버전 1) 이전에 작성된 config 가 갖는 암묵 버전. 불변. */\nconst LEGACY_SITE_CONFIG_SCHEMA_VERSION = 1;\n\n/**\n * `config.schemaVersion` 해석 헬퍼 — 필드 미지정(기존 고객\n * `site.config.ts`, `schemaVersion` 도입 이전 작성분)은 버전 1 로 해석한다\n * (하위 호환, ADR-0086 D2). 현재 버전 상수가 아니라 리터럴 1 — 후일\n * `SITE_CONFIG_SCHEMA_VERSION` 이 올라도 미지정 config 는 계속 1 이다.\n */\nexport function resolveSiteConfigSchemaVersion(config: {\n schemaVersion?: number;\n}): number {\n return config.schemaVersion ?? LEGACY_SITE_CONFIG_SCHEMA_VERSION;\n}\n","/**\n * `@roottale/cms-renderer-next/templates` — canonical `SiteConfig` 스키마.\n *\n * ADR-0040 P2 + P0.5 RFC §① (`roottale-docs/docs/services/external-site-blockification.md`).\n *\n * 설계 원칙 (codex consult #1 반영):\n * - **계약 = `section type + variant + renderer registry`.** tier 는 스키마 필드가\n * 아니라 문서/거버넌스용 성숙도 메타데이터.\n * - **100% serializable** — 함수/JSX 금지 (Astro parity + admin preview 동일 경로).\n * escape hatch 는 config 안 함수가 아니라 `customSections` registry\n * (`SiteRenderer` 에 빌드 시 type→컴포넌트 주입).\n * - CMS-bound 섹션(`blog-list`/`lead-form`)은 `RootTaleBlogList`/`RootTaleLeadForm`\n * 으로 위임 — templates 는 cms-renderer 코어를 단방향 의존 (RFC §②).\n *\n * RFC §① 대비 구현 정정:\n * - `site.url` 은 optional — 스타터/외부 사이트가 `SITE_URL` env 로 런타임 해석하는\n * 기존 패턴(P4 스타터)과 충돌하므로 config 강제 대신 env fallback 허용.\n * - 빌트인에 `rich-text` 추가 (P4 스타터 기 운영 섹션 — \"동일 패턴\" 군).\n * allow: SIZE_OK — canonical SectionSchema registry이며 W1-2 계약이 이 파일 수정을 요구한다.\n */\nimport { z } from \"zod\";\n\nexport {\n SITE_CONFIG_SCHEMA_VERSION,\n resolveSiteConfigSchemaVersion,\n} from \"./site-config-version.js\";\n\nconst JsonValue: z.ZodType<unknown> = z.lazy(() =>\n z.union([\n z.string(),\n z.number(),\n z.boolean(),\n z.null(),\n z.array(JsonValue),\n z.record(JsonValue),\n ]),\n);\n\nexport const NavItemSchema = z.object({\n label: z.string(),\n href: z.string(),\n children: z\n .array(z.object({ label: z.string(), href: z.string() }))\n .optional(),\n});\nexport type NavItem = z.infer<typeof NavItemSchema>;\n\nconst CtaSchema = z.object({ label: z.string(), href: z.string() });\nexport type SectionCta = z.infer<typeof CtaSchema>;\n\nconst MetricSchema = z.object({\n value: z.string(),\n unit: z.string().optional(),\n label: z.string(),\n source: z.string().optional(),\n imageSrc: z.string().optional(),\n imageAlt: z.string().optional(),\n});\n\n/**\n * 모든 섹션 공통 필드. `theme` 는 섹션 스코프 CSS 변수 override —\n * key 는 `--rt-*` custom property 이름, 값은 CSS 값.\n * 예) `{ \"--rt-color-primary\": \"#0B1F49\" }`\n */\nconst SectionBase = z.object({\n /** 안정적 anchor·dedup·preview 매핑용. 페이지 내 유일. */\n id: z.string().optional(),\n /** 빌트인 또는 customSections registry 키. kebab-case. */\n type: z.string(),\n /** 같은 type 의 비주얼 변형. 빌트인 type 은 enum 으로 좁힘. */\n variant: z.string().optional(),\n /** 섹션 스코프 토큰 override (`--rt-*` CSS 변수 → 값). */\n theme: z.record(z.string()).optional(),\n /** 섹션별 직렬화 props. */\n props: z.record(JsonValue).default({}),\n});\n\n// ── 빌트인 섹션 (props 좁힘 — 런타임 + 타입) ────────────────────────────────\n\nexport const SECTION_VARIANTS = {\n hero: [\"split\", \"image\", \"minimal\", \"carousel\", \"overlay-panel\"],\n services: [\n \"grid\",\n \"list\",\n \"index-rows\",\n \"split-featured\",\n \"action-rail\",\n \"photo-cards\",\n ],\n faq: [\"default\", \"two-column\", \"with-contact\", \"content-accordion\"],\n \"cta-banner\": [\"default\", \"photo-overlay\"],\n trust: [\n \"stat-band\",\n \"logo-cloud\",\n \"feature-grid\",\n \"logo-marquee\",\n \"credential-list\",\n \"dashboard\",\n ],\n contact: [\"form-map-5050\", \"split\", \"channel-cards\", \"visit-band\"],\n hours: [\"table\", \"compact\"],\n pricing: [\"table\", \"cards\"],\n process: [\"horizontal\", \"vertical\", \"timeline-marked\"],\n \"before-after\": [\"slider\", \"side-by-side\"],\n testimonials: [\"editorial-quote\", \"quote-rail\", \"star-compact\"],\n team: [\"grid\", \"spotlight\", \"expanding-stage\", \"row\"],\n expertise: [\"tab-stage\", \"cards\"],\n spaces: [\"stage\", \"mosaic\"],\n concerns: [\"figure-map\", \"list\"],\n footer: [\"columns\", \"minimal\"],\n} as const;\n\n/**\n * `carousel` variant 슬라이드 — 카피는 슬라이드마다 바뀌지 않는다(고정 오버레이).\n * 슬라이드는 배경 사진 전환만 담당 — `alt`/`caption` 모두 h1 이 아니다\n * (publish-gate h1 모델은 `props.title` 만 본다, W6-1).\n */\nconst HeroCarouselSlideSchema = z.object({\n image: z.string(),\n alt: z.string(),\n caption: z.string().optional(),\n eyebrow: z.string().optional(),\n title: z.string().optional(),\n subtitle: z.string().optional(),\n description: z.string().optional(),\n primaryCta: CtaSchema.optional(),\n secondaryCta: CtaSchema.optional(),\n tabLabel: z.string().optional(),\n tabMeta: z.string().optional(),\n metrics: z.array(MetricSchema).max(4).optional(),\n});\n\nconst HeroProofMetricsSchema = z.object({\n items: z.array(MetricSchema).min(1).max(4),\n position: z.enum([\"inline\", \"overlay\"]).default(\"inline\"),\n});\n\nexport const HeroSectionSchema = SectionBase.extend({\n type: z.literal(\"hero\"),\n variant: z.enum(SECTION_VARIANTS.hero).default(\"split\"),\n props: z.object({\n eyebrow: z.string().optional(),\n /** `\\n` 으로 줄바꿈. */\n title: z.string(),\n description: z.string().optional(),\n imageSrc: z.string().optional(),\n imageAlt: z.string().optional(),\n cta: CtaSchema.optional(),\n /** `carousel` 전용 — 고정 카피 아래 배경만 전환되는 슬라이드. 2-8개. */\n slides: z.array(HeroCarouselSlideSchema).min(2).max(8).optional(),\n /** `carousel` 전용 — 부제(슬라이드와 무관한 고정 카피). */\n subtitle: z.string().optional(),\n /** `carousel` 전용. 기본 true — `useReducedMotion` 시 렌더러가 강제 off. */\n autoplay: z.boolean().optional(),\n /** `carousel` 전용, ms. 기본 6000. */\n intervalMs: z.number().min(3000).max(10000).optional(),\n /**\n * `carousel` 전용 배경 전환 모션(ADR-0086 P2 D3). 기본 \"slide\"(기존 embla\n * 가로 스크롤). \"curtain\" = clip-path 와이프 + 신 스윕(chambarun 이식).\n * variant 는 그대로 \"carousel\" — 신규 variant 아님(\"variant=구조,\n * motion=인상\" 규칙).\n */\n transition: z.enum([\"slide\", \"curtain\"]).optional(),\n proofMetrics: HeroProofMetricsSchema.optional(),\n scrim: z.enum([\"none\", \"soft\", \"strong\"]).optional(),\n }),\n}).superRefine((section, ctx) => {\n if (section.variant === \"overlay-panel\") {\n if (!section.props.imageSrc) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"imageSrc\"],\n message: \"overlay-panel hero 는 imageSrc 가 필수입니다.\",\n });\n }\n if (!section.props.imageAlt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"imageAlt\"],\n message: \"overlay-panel hero 는 imageAlt 가 필수입니다.\",\n });\n }\n }\n if (section.variant !== \"carousel\") return;\n if (section.props.title.length < 1 || section.props.title.length > 80) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"title\"],\n message: \"carousel hero 제목은 1-80자여야 합니다.\",\n });\n }\n if (!section.props.slides || section.props.slides.length < 2) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"slides\"],\n message: \"carousel hero 는 slides 2-8개가 필요합니다.\",\n });\n }\n});\n\nexport const RichTextSectionSchema = SectionBase.extend({\n type: z.literal(\"rich-text\"),\n props: z.object({\n heading: z.string().optional(),\n /** `\\n\\n` 으로 문단 분리. */\n body: z.string(),\n }),\n});\n\nexport const ServicesSectionSchema = SectionBase.extend({\n type: z.literal(\"services\"),\n /**\n * C10 §1-2 — `index-rows`(hairline 인덱스 행) · `split-featured`(비대칭\n * 5/7, 대표 서비스 1개 + 나머지 컴팩트 리스트) 추가. AI-slop 금지 #1/#2\n * (아이콘 그리드·균등 카드) 대체 문법.\n */\n variant: z.enum(SECTION_VARIANTS.services).default(\"grid\"),\n props: z.object({\n heading: z.string().optional(),\n description: z.string().optional(),\n items: z\n .array(\n z.object({\n title: z.string(),\n subtitle: z.string().optional(),\n description: z.string().optional(),\n href: z.string().optional(),\n iconSrc: z.string().optional(),\n iconAlt: z.string().optional(),\n imageSrc: z.string().optional(),\n imageAlt: z.string().optional(),\n kind: z.string().optional(),\n ctaLabel: z.string().optional(),\n chips: z.array(z.string()).max(6).optional(),\n meta: z.array(z.string()).max(8).optional(),\n }),\n )\n .min(1)\n .max(12),\n }),\n}).superRefine((section, ctx) => {\n if (section.variant === \"split-featured\" && section.props.items.length < 2) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"items\"],\n message:\n \"split-featured 는 대표 서비스 1개 + 나머지 최소 1개, 총 2개 이상의 items 가 필요합니다.\",\n });\n }\n section.props.items.forEach((item, index) => {\n if (item.iconSrc && !item.iconAlt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"items\", index, \"iconAlt\"],\n message: \"iconSrc 가 있으면 iconAlt 가 필요합니다.\",\n });\n }\n if (section.variant === \"photo-cards\" && !item.imageSrc) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"items\", index, \"imageSrc\"],\n message: \"photo-cards 서비스 항목은 imageSrc 가 필요합니다.\",\n });\n }\n if (section.variant === \"photo-cards\" && !item.imageAlt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"items\", index, \"imageAlt\"],\n message: \"photo-cards 서비스 항목은 imageAlt 가 필요합니다.\",\n });\n }\n });\n});\n\nconst FooterLogoSchema = z.object({\n src: z.string(),\n alt: z.string(),\n});\n\nconst FooterLinkSchema = z.object({\n label: z.string(),\n href: z.string(),\n});\n\nconst FooterColumnSchema = z.object({\n title: z.string(),\n links: z.array(FooterLinkSchema).min(1).max(12),\n});\n\nconst FooterContactInfoSchema = z.object({\n address: z.string().optional(),\n phone: z.string().optional(),\n email: z.string().optional(),\n});\n\nconst FooterSocialLinkSchema = z.object({\n kind: z.string(),\n href: z.string(),\n});\n\nexport const FooterSectionSchema = SectionBase.extend({\n type: z.literal(\"footer\"),\n variant: z.enum(SECTION_VARIANTS.footer).default(\"columns\"),\n props: z.object({\n businessName: z.string(),\n logo: FooterLogoSchema.optional(),\n description: z.string().optional(),\n columns: z.array(FooterColumnSchema).max(6).optional(),\n contactInfo: FooterContactInfoSchema.optional(),\n legalInfo: z.string().optional(),\n privacyHref: z.string().optional(),\n termsHref: z.string().optional(),\n socialLinks: z.array(FooterSocialLinkSchema).max(8).optional(),\n copyright: z.string().optional(),\n /** 'hidden' 은 화이트라벨 plan gate 통과 시만 유효 (미지정 = 'default' 렌더). tenant 커스터마이즈 대상 아님 — 에디터 폼에 노출하지 않는다. */\n credit: z.enum([\"default\", \"hidden\"]).optional(),\n }),\n}).superRefine((section, ctx) => {\n if (\n section.variant === \"columns\" &&\n (!section.props.columns || section.props.columns.length === 0)\n ) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"columns\"],\n message: \"columns footer 는 columns 1개 이상이 필요합니다.\",\n });\n }\n});\n\nconst FaqItemSchema = z.object({ question: z.string(), answer: z.string() });\n\nconst FaqGroupSchema = z.object({\n title: z.string(),\n items: z.array(FaqItemSchema).min(1).max(12),\n});\n\nconst FaqContactSchema = z.object({\n title: z.string(),\n description: z.string().optional(),\n phone: z.string().optional(),\n cta: CtaSchema.optional(),\n});\n\nconst FaqContentItemSchema = z.object({\n title: z.string(),\n summary: z.string().optional(),\n body: z.string(),\n signs: z.array(z.string()).max(8).optional(),\n href: z.string().optional(),\n});\n\nconst FaqContentGroupSchema = z.object({\n title: z.string(),\n items: z.array(FaqContentItemSchema).min(1).max(12),\n});\n\nexport const FaqSectionSchema = SectionBase.extend({\n type: z.literal(\"faq\"),\n variant: z.enum(SECTION_VARIANTS.faq).default(\"default\"),\n props: z.object({\n heading: z.string().optional(),\n items: z.array(FaqItemSchema).min(1).max(20).optional(),\n /** `two-column` 전용 — 그룹 헤더 + 항목. 없으면 기존 flat items 를 사용한다. */\n groups: z.array(FaqGroupSchema).min(1).max(6).optional(),\n /** `with-contact` 전용 — 우측 sticky 상담 유도 카드. */\n contact: FaqContactSchema.optional(),\n /** `content-accordion` 전용 — FAQPage가 아닌 질환/서비스 설명 accordion. */\n contentGroups: z.array(FaqContentGroupSchema).min(1).max(6).optional(),\n /** FAQPage JSON-LD 주입 (기본 true — SEO 3 pillars). 페이지에 FAQ 섹션이 여럿이면 하나만 true 로. */\n jsonLd: z.boolean().default(true),\n }),\n}).superRefine((section, ctx) => {\n const hasContentGroups = Boolean(\n section.props.contentGroups && section.props.contentGroups.length > 0,\n );\n if (section.variant === \"content-accordion\") {\n if (!hasContentGroups) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"contentGroups\"],\n message: \"content-accordion faq sections require contentGroups\",\n });\n }\n return;\n }\n const hasItems = Boolean(section.props.items && section.props.items.length > 0);\n const hasGroups = Boolean(section.props.groups && section.props.groups.length > 0);\n if (!hasItems && !hasGroups) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"items\"],\n message: \"faq sections require items or groups\",\n });\n }\n if (section.variant === \"with-contact\" && !section.props.contact) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"contact\"],\n message: \"with-contact faq sections require contact\",\n });\n }\n});\n\nexport const CtaBannerSectionSchema = SectionBase.extend({\n type: z.literal(\"cta-banner\"),\n /** C10 §1-5 — `photo-overlay`: 풀블리드 사진 + 다크 오버레이 극단 대비 CTA. */\n variant: z.enum(SECTION_VARIANTS[\"cta-banner\"]).default(\"default\"),\n props: z.object({\n title: z.string(),\n description: z.string().optional(),\n cta: CtaSchema.optional(),\n /** `photo-overlay` 전용 — 필수(사진 없으면 렌더 거부). */\n image: z.string().optional(),\n imageAlt: z.string().optional(),\n }),\n}).superRefine((section, ctx) => {\n if (section.variant !== \"photo-overlay\") return;\n if (!section.props.image) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"image\"],\n message: \"photo-overlay cta-banner 는 image 가 필수입니다.\",\n });\n }\n if (!section.props.imageAlt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"imageAlt\"],\n message: \"photo-overlay cta-banner 는 imageAlt 가 필수입니다.\",\n });\n }\n});\n\n/** → `RootTaleBlogList` 위임 (cms-bound). */\nexport const BlogListSectionSchema = SectionBase.extend({\n type: z.literal(\"blog-list\"),\n props: z.object({\n heading: z.string().optional(),\n limit: z.number().int().positive().optional(),\n /** 포스트 링크 베이스. 기본 `/blog`. */\n blogBasePath: z.string().optional(),\n emptyMessage: z.string().optional(),\n }),\n});\n\n/** → `RootTaleLeadForm` 위임 (cms-bound). */\nexport const LeadFormSectionSchema = SectionBase.extend({\n type: z.literal(\"lead-form\"),\n props: z.object({\n /** 사이트 자체 server 엔드포인트 (예: `/api/inquiry`). intake API 직접 지정 금지. */\n action: z.string(),\n vertical: z.enum([\"consulting\", \"medical\", \"tax\", \"legal\"]).optional(),\n heading: z.string().optional(),\n description: z.string().optional(),\n submitLabel: z.string().optional(),\n }),\n});\n\nconst TrustMetricSchema = MetricSchema;\n\nconst TrustCredentialSchema = z.object({\n name: z.string(),\n issuer: z.string().optional(),\n kind: z.enum([\"license\", \"education\", \"association\"]).optional(),\n image: z.string().optional(),\n /** `credential-list` 전용 — hairline 행의 tabular 연도. */\n year: z.string().optional(),\n});\n\nconst TrustLogoSchema = z.object({\n src: z.string(),\n alt: z.string(),\n href: z.string().optional(),\n});\n\nconst LegacyTrustLogoSchema = z\n .object({\n image: z.string(),\n alt: z.string(),\n href: z.string().optional(),\n })\n .transform((logo) => ({\n src: logo.image,\n alt: logo.alt,\n ...(logo.href ? { href: logo.href } : {}),\n }));\n\n/** logo-cloud/logo-marquee 공통 슬롯. legacy `{image, alt, href?}` 도 `{src, alt, href?}` 로 정규화한다. */\nconst TrustLogoSlotSchema = z.union([TrustLogoSchema, LegacyTrustLogoSchema]);\n\nconst TrustChartSchema = z.object({\n type: z.enum([\"bar\", \"line\"]).default(\"bar\"),\n title: z.string(),\n description: z.string().optional(),\n points: z\n .array(\n z.object({\n label: z.string(),\n value: z.number(),\n display: z.string().optional(),\n }),\n )\n .min(1)\n .max(12),\n});\n\nexport const TrustSectionSchema = SectionBase.extend({\n type: z.literal(\"trust\"),\n /**\n * C10 §1-3/1-4 — `logo-marquee`(C8 Marquee 소비, 흑백/저채도 로고 스트립) ·\n * `credential-list`(연도 tabular + hairline 자격 리스트) 추가.\n */\n variant: z.enum(SECTION_VARIANTS.trust).default(\"stat-band\"),\n props: z.object({\n heading: z.string().optional(),\n metrics: z.array(TrustMetricSchema).min(2).max(4).optional(),\n credentials: z.array(TrustCredentialSchema).max(8).optional(),\n logos: z.array(TrustLogoSlotSchema).max(8).optional(),\n /** `logo-marquee` 전용 — logo-cloud 와 동일한 `{src, alt, href?}` 슬롯. 최소 3개. */\n marqueeLogos: z.array(TrustLogoSlotSchema).min(3).max(16).optional(),\n chart: TrustChartSchema.optional(),\n disclaimer: z.string().optional(),\n }),\n}).superRefine((section, ctx) => {\n if (section.variant === \"stat-band\" && !section.props.metrics) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"metrics\"],\n message: \"stat-band trust sections require 2-4 metrics\",\n });\n }\n if (section.variant === \"logo-cloud\" && !section.props.logos) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"logos\"],\n message: \"logo-cloud trust sections require logos\",\n });\n }\n if (\n (section.variant === \"feature-grid\" || section.variant === \"credential-list\") &&\n !section.props.credentials\n ) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"credentials\"],\n message: `${section.variant} trust sections require credentials`,\n });\n }\n if (section.variant === \"logo-marquee\" && !section.props.marqueeLogos) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"marqueeLogos\"],\n message: \"logo-marquee trust sections require marqueeLogos (min 3)\",\n });\n }\n if (section.variant === \"dashboard\" && !section.props.chart) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"chart\"],\n message: \"dashboard trust sections require chart\",\n });\n }\n});\n\nconst ContactHoursSchema = z.object({\n day: z.string(),\n open: z.string(),\n close: z.string(),\n note: z.string().optional(),\n});\n\nconst ContactChannelSchema = z.object({\n label: z.string(),\n description: z.string().optional(),\n value: z.string().optional(),\n href: z.string().optional(),\n actionLabel: z.string().optional(),\n iconSrc: z.string().optional(),\n iconAlt: z.string().optional(),\n kind: z.string().optional(),\n});\n\nconst ContactMapSchema = z.object({\n facadeImageSrc: z.string().optional(),\n facadeImageAlt: z.string().optional(),\n provider: z.string().optional(),\n embedUrl: z.string().optional(),\n externalUrl: z.string().optional(),\n lat: z.number().optional(),\n lng: z.number().optional(),\n /**\n * 지도 로드 모드(ADR-0086 P2 D3, chambarun `.map-facade` 클릭-투-로드 이식).\n * 기본 \"lazy\"(기존 동작 그대로 — 실지도면 즉시 iframe `loading=\"lazy\"`).\n * \"click\" 은 정적 프리뷰(주소·지도 열기 버튼)만 먼저 그리고, 클릭 시에만\n * iframe 을 마운트한다(외부 지도 스크립트/네트워크 요청을 사용자 의도\n * 전까지 미루는 성능·프라이버시 절충 — additive, 기존 사이트는 영향 없음).\n */\n mapLoad: z.enum([\"lazy\", \"click\"]).optional(),\n});\n\nconst ContactActionSchema = z.object({\n label: z.string(),\n href: z.string(),\n kind: z.string().optional(),\n});\n\nexport const ContactSectionSchema = SectionBase.extend({\n type: z.literal(\"contact\"),\n variant: z.enum(SECTION_VARIANTS.contact).default(\"form-map-5050\"),\n props: z.object({\n heading: z.string().optional(),\n form: z.object({\n enabled: z.boolean(),\n vertical: z.enum([\"medical\", \"tax\", \"legal\", \"consulting\"]).optional(),\n }),\n phone: z.string().optional(),\n address: z.string().optional(),\n hours: z.array(ContactHoursSchema).max(8).optional(),\n mapEmbedUrl: z.string().optional(),\n map: ContactMapSchema.optional(),\n actions: z.array(ContactActionSchema).max(6).optional(),\n /** `channel-cards` 전용 — 카드당 하나의 행동. */\n channels: z.array(ContactChannelSchema).min(3).max(6).optional(),\n }),\n}).superRefine((section, ctx) => {\n if (section.variant !== \"channel-cards\") return;\n if (!section.props.channels) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"channels\"],\n message: \"channel-cards contact sections require 3-6 channels\",\n });\n }\n section.props.channels?.forEach((channel, index) => {\n if (channel.iconSrc && !channel.iconAlt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"channels\", index, \"iconAlt\"],\n message: \"iconSrc 가 있으면 iconAlt 가 필요합니다.\",\n });\n }\n });\n});\n\nconst PracticeDaySchema = z.enum([\n \"monday\",\n \"tuesday\",\n \"wednesday\",\n \"thursday\",\n \"friday\",\n \"saturday\",\n \"sunday\",\n]);\n\nconst HoursBadgeSlotsSchema = z.object({\n lunch: z.string().optional(),\n evening: z.string().optional(),\n closed: z.string().optional(),\n extra: z.array(z.string()).max(4).optional(),\n});\n\nconst HoursRowSchema = z.object({\n day: PracticeDaySchema,\n label: z.string(),\n hours: z.string(),\n lunchHours: z.string().optional(),\n badges: HoursBadgeSlotsSchema.optional(),\n note: z.string().optional(),\n});\n\nexport const HoursSectionSchema = SectionBase.extend({\n type: z.literal(\"hours\"),\n variant: z.enum(SECTION_VARIANTS.hours).default(\"table\"),\n props: z.object({\n eyebrow: z.string().optional(),\n heading: z.string().optional(),\n description: z.string().optional(),\n rows: z.array(HoursRowSchema).min(1).max(14),\n note: z.string().optional(),\n disclaimer: z.string().optional(),\n }),\n});\n\nconst PricingItemSchema = z.object({\n name: z.string(),\n description: z.string().optional(),\n price: z.string(),\n condition: z.string().optional(),\n});\n\nconst PricingGroupSchema = z.object({\n label: z.string(),\n items: z.array(PricingItemSchema).min(1).max(12),\n});\n\nexport const PricingSectionSchema = SectionBase.extend({\n type: z.literal(\"pricing\"),\n variant: z.enum(SECTION_VARIANTS.pricing).default(\"table\"),\n props: z.object({\n eyebrow: z.string().optional(),\n heading: z.string().optional(),\n description: z.string().optional(),\n groups: z.array(PricingGroupSchema).min(1).max(6),\n disclaimer: z.string().min(1),\n }),\n});\n\nconst ProcessTimelineItemSchema = z.object({\n eyebrow: z.string().optional(),\n title: z.string(),\n description: z.string(),\n duration: z.string().optional(),\n status: z.enum([\"complete\", \"current\", \"pending\"]).optional(),\n statusLabel: z.string().optional(),\n mark: z.enum([\"check\", \"dot\", \"none\"]).optional(),\n imageSrc: z.string().optional(),\n imageAlt: z.string().optional(),\n});\n\nexport const ProcessSectionSchema = SectionBase.extend({\n type: z.literal(\"process\"),\n variant: z.enum(SECTION_VARIANTS.process).default(\"horizontal\"),\n props: z.object({\n eyebrow: z.string().optional(),\n heading: z.string().optional(),\n description: z.string().optional(),\n items: z.array(ProcessTimelineItemSchema).min(2).max(8),\n connector: z.enum([\"line\", \"rail\"]).optional(),\n disclaimer: z.string().optional(),\n }),\n}).superRefine((section, ctx) => {\n section.props.items.forEach((item, index) => {\n if (item.imageSrc && !item.imageAlt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"items\", index, \"imageAlt\"],\n message: \"imageSrc 가 있으면 imageAlt 가 필요합니다.\",\n });\n }\n });\n});\n\nconst BeforeAfterImageSchema = z.object({\n src: z.string(),\n alt: z.string(),\n});\n\nexport const BeforeAfterSectionSchema = SectionBase.extend({\n type: z.literal(\"before-after\"),\n variant: z.enum(SECTION_VARIANTS[\"before-after\"]).default(\"slider\"),\n props: z.object({\n beforeImage: BeforeAfterImageSchema,\n afterImage: BeforeAfterImageSchema,\n beforeLabel: z.string().default(\"시공 전\"),\n afterLabel: z.string().default(\"시공 후\"),\n heading: z.string().optional(),\n description: z.string().optional(),\n disclaimer: z.string().optional(),\n }),\n});\n\n/** `quote-rail` 전용 hairline 인용 카드 하한 — 스크롤 레일이 자연스러운 최소치. */\nconst TestimonialItemSchema = z.object({\n quote: z.string().min(1).max(280),\n author: z.string().min(1),\n /** 케이스 라벨(예: \"허리디스크 · 비수술 치료 3개월\"). */\n context: z.string().optional(),\n rating: z.number().min(0).max(5).optional(),\n source: z.string().optional(),\n visitedAt: z.string().optional(),\n item: z.string().optional(),\n reply: z.string().optional(),\n});\n\n/**\n * C11 — 후기(testimonials) 섹션. 의료 vertical 치료경험담 광고는 규제 대상\n * (의료법 §56 ②4, `@roottale/audit-medical` MED-007) — `disclaimer` 슬롯은\n * 법정 고지문 전용, 스토리 fixture 카피는 심의-안전 톤으로 작성 의무\n * (roottale-docs `premium-component-backlog.md` C11).\n */\nexport const TestimonialsSectionSchema = SectionBase.extend({\n type: z.literal(\"testimonials\"),\n /**\n * `editorial-quote`(기본): 대형 인용 타이포 에디토리얼 — 1개면 중앙 정렬\n * 스테이지, 2개 이상이면 세로 스택(hairline 구분). `quote-rail`: 가로\n * 스크롤 레일(hairline 좌측 보더 컬럼, 균등 그림자 카드 금지).\n * `star-compact`(W8-7): 별점 중심 컴팩트 그리드 — 평균 별점 요약 밴드 +\n * hairline 행. 별점은 CSS 타이포 글리프(이모지·이미지 금지), 색은 전부\n * 토큰(variant×토큰 직교, 채움 폭만 데이터 주도 커스텀 프로퍼티).\n */\n variant: z.enum(SECTION_VARIANTS.testimonials).default(\"editorial-quote\"),\n props: z.object({\n heading: z.string(),\n description: z.string().optional(),\n items: z.array(TestimonialItemSchema).min(1).max(12),\n marquee: z.boolean().optional(),\n /** 법정 고지 슬롯(\"개인 경험이며 효과는 다를 수 있습니다\" 류). */\n disclaimer: z.string().optional(),\n }),\n});\n\nconst TeamMemberSchema = z\n .object({\n name: z.string().min(1),\n title: z.string().min(1),\n photoSrc: z.string().optional(),\n photoAlt: z.string().optional(),\n specialties: z.array(z.string().min(1)).min(1).max(6).optional(),\n credentials: z.array(z.string().min(1)).min(1).max(8).optional(),\n bio: z.string().max(360).optional(),\n href: z.string().optional(),\n ctaLabel: z.string().optional(),\n })\n .superRefine((member, ctx) => {\n if (member.photoSrc && !member.photoAlt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"photoAlt\"],\n message: \"photoSrc 가 있으면 photoAlt 가 필요합니다.\",\n });\n }\n });\n\nexport const TeamSectionSchema = SectionBase.extend({\n type: z.literal(\"team\"),\n variant: z.enum(SECTION_VARIANTS.team).default(\"grid\"),\n props: z.object({\n heading: z.string().optional(),\n description: z.string().optional(),\n members: z.array(TeamMemberSchema).min(2).max(8),\n }),\n});\n\nconst ExpertiseItemSchema = z\n .object({\n id: z.string().min(1),\n label: z.string().min(1),\n kicker: z.string().optional(),\n title: z.string().min(1),\n body: z.string().min(1),\n imageSrc: z.string().optional(),\n imageAlt: z.string().optional(),\n tags: z.array(z.string().min(1)).max(8).optional(),\n href: z.string().optional(),\n ctaLabel: z.string().optional(),\n })\n .superRefine((item, ctx) => {\n if (item.imageSrc && !item.imageAlt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"imageAlt\"],\n message: \"imageSrc 가 있으면 imageAlt 가 필요합니다.\",\n });\n }\n });\n\nexport const ExpertiseSectionSchema = SectionBase.extend({\n type: z.literal(\"expertise\"),\n variant: z.enum(SECTION_VARIANTS.expertise).default(\"tab-stage\"),\n props: z.object({\n heading: z.string().optional(),\n description: z.string().optional(),\n items: z.array(ExpertiseItemSchema).min(2).max(6),\n }),\n});\n\nconst SpaceItemSchema = z.object({\n id: z.string().min(1),\n label: z.string().min(1),\n kicker: z.string().optional(),\n title: z.string().optional(),\n description: z.string().optional(),\n imageSrc: z.string().min(1),\n imageAlt: z.string().min(1),\n tags: z.array(z.string().min(1)).max(8).optional(),\n});\n\nexport const SpacesSectionSchema = SectionBase.extend({\n type: z.literal(\"spaces\"),\n variant: z.enum(SECTION_VARIANTS.spaces).default(\"stage\"),\n props: z.object({\n heading: z.string().optional(),\n description: z.string().optional(),\n spaces: z.array(SpaceItemSchema).min(2).max(8),\n disclaimer: z.string().optional(),\n }),\n});\n\nconst ConcernRegionSchema = z.object({\n id: z.string().min(1),\n label: z.string().min(1),\n x: z.number().min(0).max(100).optional(),\n y: z.number().min(0).max(100).optional(),\n title: z.string().min(1),\n description: z.string().min(1),\n items: z.array(z.string().min(1)).max(8).optional(),\n href: z.string().optional(),\n ctaLabel: z.string().optional(),\n});\n\nexport const ConcernsSectionSchema = SectionBase.extend({\n type: z.literal(\"concerns\"),\n variant: z.enum(SECTION_VARIANTS.concerns).default(\"figure-map\"),\n props: z.object({\n heading: z.string().optional(),\n description: z.string().optional(),\n figureImage: z.string().optional(),\n figureAlt: z.string().optional(),\n regions: z.array(ConcernRegionSchema).min(3).max(10),\n disclaimer: z.string().min(1),\n }),\n}).superRefine((section, ctx) => {\n if (section.variant !== \"figure-map\") return;\n if (!section.props.figureImage) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"figureImage\"],\n message: \"figure-map concerns 는 figureImage 가 필요합니다.\",\n });\n }\n if (!section.props.figureAlt) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"figureAlt\"],\n message: \"figure-map concerns 는 figureAlt 가 필요합니다.\",\n });\n }\n section.props.regions.forEach((region, index) => {\n if (typeof region.x !== \"number\") {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"regions\", index, \"x\"],\n message: \"figure-map concerns region 은 x 좌표가 필요합니다.\",\n });\n }\n if (typeof region.y !== \"number\") {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"props\", \"regions\", index, \"y\"],\n message: \"figure-map concerns region 은 y 좌표가 필요합니다.\",\n });\n }\n });\n});\n\n/** customSections 용 fallback — `type` 자유, props 는 직렬화만 강제. */\nexport const CustomSectionSchema = SectionBase;\n\nexport const BUILTIN_SECTION_SCHEMAS: Record<string, z.ZodTypeAny> = {\n hero: HeroSectionSchema,\n \"rich-text\": RichTextSectionSchema,\n services: ServicesSectionSchema,\n faq: FaqSectionSchema,\n \"cta-banner\": CtaBannerSectionSchema,\n \"blog-list\": BlogListSectionSchema,\n \"lead-form\": LeadFormSectionSchema,\n trust: TrustSectionSchema,\n contact: ContactSectionSchema,\n hours: HoursSectionSchema,\n pricing: PricingSectionSchema,\n process: ProcessSectionSchema,\n \"before-after\": BeforeAfterSectionSchema,\n testimonials: TestimonialsSectionSchema,\n team: TeamSectionSchema,\n expertise: ExpertiseSectionSchema,\n spaces: SpacesSectionSchema,\n concerns: ConcernsSectionSchema,\n footer: FooterSectionSchema,\n};\n\n/** 빌트인 type 목록 (renderer registry 와 1:1). */\nexport const BUILTIN_SECTION_TYPES = Object.keys(\n BUILTIN_SECTION_SCHEMAS,\n) as readonly string[];\n\nexport type HeroSection = z.output<typeof HeroSectionSchema>;\nexport type RichTextSection = z.output<typeof RichTextSectionSchema>;\nexport type ServicesSection = z.output<typeof ServicesSectionSchema>;\nexport type FaqSection = z.output<typeof FaqSectionSchema>;\nexport type CtaBannerSection = z.output<typeof CtaBannerSectionSchema>;\nexport type BlogListSection = z.output<typeof BlogListSectionSchema>;\nexport type LeadFormSection = z.output<typeof LeadFormSectionSchema>;\nexport type TrustSection = z.output<typeof TrustSectionSchema>;\nexport type ContactSection = z.output<typeof ContactSectionSchema>;\nexport type HoursSection = z.output<typeof HoursSectionSchema>;\nexport type PricingSection = z.output<typeof PricingSectionSchema>;\nexport type ProcessSection = z.output<typeof ProcessSectionSchema>;\nexport type BeforeAfterSection = z.output<typeof BeforeAfterSectionSchema>;\nexport type TestimonialsSection = z.output<typeof TestimonialsSectionSchema>;\nexport type TeamSection = z.output<typeof TeamSectionSchema>;\nexport type ExpertiseSection = z.output<typeof ExpertiseSectionSchema>;\nexport type SpacesSection = z.output<typeof SpacesSectionSchema>;\nexport type ConcernsSection = z.output<typeof ConcernsSectionSchema>;\nexport type FooterSection = z.output<typeof FooterSectionSchema>;\nexport type CustomSection = z.output<typeof CustomSectionSchema>;\n\n/** 파싱 결과 섹션 (defaults 적용 후). */\nexport type Section =\n | HeroSection\n | RichTextSection\n | ServicesSection\n | FaqSection\n | CtaBannerSection\n | BlogListSection\n | LeadFormSection\n | TrustSection\n | ContactSection\n | HoursSection\n | PricingSection\n | ProcessSection\n | BeforeAfterSection\n | TestimonialsSection\n | TeamSection\n | ExpertiseSection\n | SpacesSection\n | ConcernsSection\n | FooterSection\n | CustomSection;\n\n/** config 작성용 섹션 (defaults 생략 가능). `site.config.ts` 에서 이 타입 사용. */\nexport type SectionInput =\n | z.input<typeof HeroSectionSchema>\n | z.input<typeof RichTextSectionSchema>\n | z.input<typeof ServicesSectionSchema>\n | z.input<typeof FaqSectionSchema>\n | z.input<typeof CtaBannerSectionSchema>\n | z.input<typeof BlogListSectionSchema>\n | z.input<typeof LeadFormSectionSchema>\n | z.input<typeof TrustSectionSchema>\n | z.input<typeof ContactSectionSchema>\n | z.input<typeof HoursSectionSchema>\n | z.input<typeof PricingSectionSchema>\n | z.input<typeof ProcessSectionSchema>\n | z.input<typeof BeforeAfterSectionSchema>\n | z.input<typeof TestimonialsSectionSchema>\n | z.input<typeof TeamSectionSchema>\n | z.input<typeof ExpertiseSectionSchema>\n | z.input<typeof SpacesSectionSchema>\n | z.input<typeof ConcernsSectionSchema>\n | z.input<typeof FooterSectionSchema>\n | z.input<typeof CustomSectionSchema>;\n\n/**\n * 섹션 스키마 — 빌트인 type 이면 해당 스키마로 *강제* 검증 (union fallthrough 로\n * 빌트인 오타이핑이 CustomSection 으로 조용히 통과하는 것을 차단), 미지 type 은\n * CustomSection 으로 통과 (렌더러가 customSections registry 로 해석).\n */\nexport const SectionSchema: z.ZodType<Section, z.ZodTypeDef, SectionInput> = z\n .object({ type: z.string() })\n .passthrough()\n .transform((section, ctx) => {\n const schema = BUILTIN_SECTION_SCHEMAS[section.type] ?? CustomSectionSchema;\n const result = schema.safeParse(section);\n if (!result.success) {\n for (const issue of result.error.issues) ctx.addIssue(issue);\n return z.NEVER;\n }\n return result.data as Section;\n }) as unknown as z.ZodType<Section, z.ZodTypeDef, SectionInput>;\n\n/**\n * 콘텐츠 Collection (ADR-0060) — 같은 글 풀(post)을 스트림으로 분리(공지 게시판 /\n * 블로그 그리드 등). `routes.ts` 의 `RouteCollection` 의 타입드·직렬화 상위집합 —\n * 한 category slug 는 정확히 하나의 collection 에 속해야 한다(다대일 = 라우팅 모호).\n * `layout` 은 레지스트리 키(open string) — 신규 레이아웃 추가 시 스키마 불변.\n * 선언 순서 = 라우팅 우선순위(`resolvePostCollection`).\n */\nexport const CollectionSchema = z.object({\n /** 안정 식별자 (라우트/가드/파생 키). */\n key: z.string(),\n /** 작성자 카드·nav 라벨. */\n label: z.string(),\n /** 라우트 base path (예: \"/notice\" | \"/blog\"). 앞 슬래시 포함. */\n basePath: z.string(),\n /** 레이아웃 레지스트리 키 (board=게시판, grid=카드 그리드, …). 미지 키는 렌더러 fallback. */\n layout: z.string().default(\"grid\"),\n /** 이 스트림에 속하는 category slug 들. */\n categories: z.array(z.string()).default([]),\n /** RSS 피드 포함. */\n feed: z.boolean().default(false),\n /** `${basePath}/categories/{slug}` 아카이브 생성. */\n archives: z.boolean().default(false),\n /** 글별 동적 OG. */\n og: z.boolean().default(false),\n /** 작성 UX: 하위 카테고리 1개 필수(미선택 발행 차단). */\n requireSubcategory: z.boolean().default(false),\n /** 작성 UX: 상단고정 토글 노출. */\n pinning: z.boolean().default(false),\n /** nav/카드 아이콘 키 (선택). */\n icon: z.string().optional(),\n});\nexport type Collection = z.output<typeof CollectionSchema>;\n\nexport const SiteConfigSchema = z.object({\n /**\n * `SiteConfig` 계약 버전 (ADR-0086 D2) — 팩 manifest 의 `siteConfigVersion`\n * 과 비교해 팩↔renderer 호환성을 표현한다. optional — 하위 호환(기존 고객\n * `site.config.ts` 에는 이 필드가 없다). 미지정은 버전 1 로 해석한다\n * (`resolveSiteConfigSchemaVersion`).\n */\n schemaVersion: z.number().int().positive().optional(),\n site: z.object({\n /** canonical origin. 생략 시 소비측이 `SITE_URL` env 등으로 해석. */\n url: z.string().url().optional(),\n title: z.string(),\n description: z.string().optional(),\n locale: z.string().default(\"ko-KR\"),\n og: z.object({ image: z.string().optional() }).optional(),\n }),\n /**\n * 콘텐츠 스트림 분리 (ADR-0060). 비우면 단일 /blog(레거시 동작). 선언 순서 =\n * 라우팅 우선순위. `routes.ts` 팩토리에 `collections` 로 전달해 sitemap/feed/\n * 아카이브를 스트림별로 파생.\n */\n collections: z.array(CollectionSchema).default([]),\n /** 사이트 전역 토큰 override (`--rt-*` CSS 변수 → 값). 비우면 admin /design SSoT. */\n theme: z.record(z.string()).default({}),\n /**\n * 테마 방향(Theme Directions, `@roottale/tokens` 프리셋 id — 예: \"d1-editorial\").\n * root layout 이 `<html data-rt-direction=\"…\">` 로 부여해\n * `@roottale/tokens/theme-directions.css` 의 `[data-rt-direction=\"…\"]` 규칙을\n * 활성화한다(roottale-docs `docs/design/theme-directions.md`). 값은 문자열로만\n * 검증한다 — `@roottale/cms-renderer-next` 는 `@roottale/tokens` 를 직접\n * 의존하지 않으므로 유효 id 집합은 `@roottale/tokens/theme-directions` 의\n * `ThemeDirectionId` 를 참조해 `site.config.ts` 작성 시점에 타입으로 좁힌다.\n * 미지정 시 속성 자체가 안 붙어 완전히 무변화(기존 동작).\n */\n direction: z.string().optional(),\n nav: z.array(NavItemSchema).default([]),\n /** path(\"/\", \"/services\", …) → 섹션 배열. */\n pages: z.record(z.array(SectionSchema)),\n});\n\nexport type SiteConfig = z.output<typeof SiteConfigSchema>;\n/** config 작성용 (defaults 생략 가능). */\nexport type SiteConfigInput = Omit<\n z.input<typeof SiteConfigSchema>,\n \"pages\"\n> & { pages: Record<string, SectionInput[]> };\n\n/** config 검증 + defaults 적용. 실패 시 ZodError throw (빌드 타임 fail-fast 용). */\nexport function parseSiteConfig(input: unknown): SiteConfig {\n return SiteConfigSchema.parse(input);\n}\n\n/**\n * `site.config.ts` 작성 헬퍼 — 타입 추론 + 즉시 검증.\n *\n * ```ts\n * import { defineSiteConfig } from \"@roottale/cms-renderer-next/templates\";\n * export default defineSiteConfig({ site: { title: \"…\" }, pages: { \"/\": [ … ] } });\n * ```\n */\nexport function defineSiteConfig(input: SiteConfigInput): SiteConfig {\n return parseSiteConfig(input);\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,55 @@
1
+ "use client";
2
+
3
+ // src/lead-form-meta.client.tsx
4
+ import { useEffect, useRef } from "react";
5
+ import { readAttribution } from "@roottale/cms-client/attribution";
6
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+ var JOURNEY_STORAGE_KEY = "_rt_journey";
8
+ function LeadFormMeta({ formId }) {
9
+ const attributionRef = useRef(null);
10
+ const journeyRef = useRef(null);
11
+ const startedRef = useRef(false);
12
+ useEffect(() => {
13
+ try {
14
+ const attribution = readAttribution();
15
+ if (attribution && attributionRef.current) {
16
+ attributionRef.current.value = JSON.stringify(attribution);
17
+ }
18
+ } catch {
19
+ }
20
+ const form = attributionRef.current?.form ?? journeyRef.current?.form;
21
+ if (!form) return;
22
+ const handleFocusIn = () => {
23
+ if (startedRef.current) return;
24
+ startedRef.current = true;
25
+ window.__rtTrack?.("form_start", { form_id: formId });
26
+ };
27
+ const handleFormData = (event) => {
28
+ try {
29
+ const raw = window.sessionStorage.getItem(JOURNEY_STORAGE_KEY);
30
+ event.formData.set("journey", raw ?? "");
31
+ } catch {
32
+ }
33
+ };
34
+ const handleSubmit = () => {
35
+ window.__rtTrack?.("form_submit_attempt", { form_id: formId });
36
+ };
37
+ form.addEventListener("focusin", handleFocusIn);
38
+ form.addEventListener("formdata", handleFormData);
39
+ form.addEventListener("submit", handleSubmit);
40
+ return () => {
41
+ form.removeEventListener("focusin", handleFocusIn);
42
+ form.removeEventListener("formdata", handleFormData);
43
+ form.removeEventListener("submit", handleSubmit);
44
+ };
45
+ }, [formId]);
46
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
47
+ /* @__PURE__ */ jsx("input", { type: "hidden", name: "attribution", ref: attributionRef, defaultValue: "" }),
48
+ /* @__PURE__ */ jsx("input", { type: "hidden", name: "journey", ref: journeyRef, defaultValue: "" })
49
+ ] });
50
+ }
51
+
52
+ export {
53
+ LeadFormMeta
54
+ };
55
+ //# sourceMappingURL=chunk-VG6UUF4D.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lead-form-meta.client.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * `LeadFormMeta` — `RootTaleLeadForm`(RSC, `LeadForm.tsx`) 내부에 심는\n * 어트리뷰션·여정 hidden input 배선 + 폼 계측 발화 island (측정 설계 v2 §2/§3/§5\n * — `measurement-design-draft.md`, 워커 브리프 B). \"LeadForm 어트리뷰션 배선\n * 복구\" — starter `/api/inquiry` 가 지금까지 `attribution`/`journey` 를 전혀\n * 동반하지 않던 끊긴 고리를 여기서 다시 잇는다.\n *\n * RSC 경계(설계 §5): `LeadForm.tsx` 는 계속 서버 컴포넌트로 남고, 이 파일만\n * \"use client\" — form 태그 **내부** 자식으로 삽입한다. tsup 독립 entry\n * (`lead-form-meta-client`, tsup.config.ts) + `esbuild-plugin-preserve-directives`\n * 가 이 청크만 \"use client\" 지시어를 보존한다 — `hero-carousel-client.tsx` 가\n * `templates.js` 에서 격리되는 것과 동일한 관행을 `server.js`(LeadForm 이\n * 속한 entry)에 적용한다.\n *\n * 배선:\n * - `attribution` hidden input — `@roottale/cms-client/attribution` 의\n * `readAttribution()` 으로 localStorage `_rt_attr` first-touch 를 마운트\n * 시 1회 판독해 채운다. first-touch 봉투는 제출 시점까지 안정적이므로\n * 마운트 스냅샷으로 충분하다(설계 §2). `readAttribution()` 을 쓰는 이유 —\n * 비콘이 저장하는 압축 키(`lp/rs/us/um/uc/rf`)를 서버 `parseAttributionJson()`\n * 이 기대하는 확장 키(`landing_path/rt_src/...`)로 변환하는 매핑이 이미\n * 이 함수에 있다(파일 헤더 JSDoc 사용례와 동일 패턴) — 압축 원문을 그대로\n * 넘기면 서버가 못 읽는다.\n * - `journey` hidden input — sessionStorage `_rt_journey` 를 **마운트가\n * 아니라 `formdata` 이벤트 시점에 재직렬화**한다(설계 §3 — 방문 중 계속\n * 쌓이는 값이라 마운트 스냅샷은 진부해진다). hidden input 의 DOM `value`\n * 는 항상 빈 문자열로 SSR/초기 클라 렌더가 일치(hydration-safe) — 실제\n * 전송값은 `formdata` 이벤트에서 `event.formData.set()` 으로 직접 주입해\n * DOM 갱신·리렌더가 필요 없다. `_rt_journey` 키 자체는\n * analytics-runtime(별도 워커가 동시 작업 중이라 이 패키지를 import 하지\n * 않는다)과의 공유 계약 — 값 자체가 계약(문자열 중복은 beacon.ts\n * `ATTRIBUTION_STORAGE_KEY` 를 cms-client `attribution.ts` 가 이미 중복\n * 선언하는 기존 관행과 동일).\n * - `form_start` — form 내 첫 focusin 1회.\n * - `form_submit_attempt` — form `submit` 이벤트(제출 버튼 클릭·Enter 제출\n * 공통 — 브라우저 스펙상 `submit` 이 `formdata` 보다 먼저 fire 한다).\n *\n * `window.__rtTrack` 은 `@roottale/analytics-runtime` 의 비콘 런타임(beacon.ts)\n * 이 노출하는 전역 — 이 패키지가 그 패키지를 직접 import 하지 않고 전역\n * 계약만 소비한다(빌드 의존 최소화 + 비콘 미설정 사이트에서 자동 no-op,\n * `not-found.tsx` `trackCustomEvent` 관행과 동일 계약, 다만 여기선 전역을\n * 직접 optional-chain 호출한다).\n */\nimport { useEffect, useRef } from \"react\";\nimport type { ReactElement } from \"react\";\nimport { readAttribution } from \"@roottale/cms-client/attribution\";\n\n/** sessionStorage 여정 로그 키 — analytics-runtime 관측자와의 공유 계약(설계 §3). */\nconst JOURNEY_STORAGE_KEY = \"_rt_journey\";\n\ndeclare global {\n interface Window {\n /** beacon.ts RUNTIME 이 노출하는 `send()` — 비콘 미설정 사이트에선 undefined. */\n __rtTrack?: (ev: string, extra?: Record<string, unknown>) => void;\n }\n}\n\nexport interface LeadFormMetaProps {\n /** `form_start`/`form_submit_attempt` 차원(form_id). 예: `\"contact\"`. */\n formId: string;\n}\n\n/**\n * `RootTaleLeadForm` 의 `<form>` 내부에 렌더 — hidden input 2개(어트리뷰션·\n * 여정) + 폼 계측 리스너. 시각 출력 없음(레이아웃 영향 0).\n */\nexport function LeadFormMeta({ formId }: LeadFormMetaProps): ReactElement {\n const attributionRef = useRef<HTMLInputElement>(null);\n const journeyRef = useRef<HTMLInputElement>(null);\n const startedRef = useRef(false);\n\n useEffect(() => {\n try {\n const attribution = readAttribution();\n if (attribution && attributionRef.current) {\n attributionRef.current.value = JSON.stringify(attribution);\n }\n } catch {\n /* storage 접근 불가(프라이빗 모드 등) — 무동반 제출, 폼 자체는 정상 동작 */\n }\n\n const form = attributionRef.current?.form ?? journeyRef.current?.form;\n if (!form) return;\n\n const handleFocusIn = (): void => {\n if (startedRef.current) return;\n startedRef.current = true;\n window.__rtTrack?.(\"form_start\", { form_id: formId });\n };\n\n const handleFormData = (event: FormDataEvent): void => {\n // 설계 §3 — 마운트 스냅샷이 아니라 제출 시점 재직렬화. FormData 엔트리를\n // 직접 덮어써 hidden input 의 실제 DOM value 갱신 없이 최신값을 싣는다.\n try {\n const raw = window.sessionStorage.getItem(JOURNEY_STORAGE_KEY);\n event.formData.set(\"journey\", raw ?? \"\");\n } catch {\n /* noop — journey 없이 제출(문의 저장 자체는 서버에서 계속 진행) */\n }\n };\n\n const handleSubmit = (): void => {\n window.__rtTrack?.(\"form_submit_attempt\", { form_id: formId });\n };\n\n form.addEventListener(\"focusin\", handleFocusIn);\n form.addEventListener(\"formdata\", handleFormData as EventListener);\n form.addEventListener(\"submit\", handleSubmit);\n\n return () => {\n form.removeEventListener(\"focusin\", handleFocusIn);\n form.removeEventListener(\"formdata\", handleFormData as EventListener);\n form.removeEventListener(\"submit\", handleSubmit);\n };\n }, [formId]);\n\n return (\n <>\n <input type=\"hidden\" name=\"attribution\" ref={attributionRef} defaultValue=\"\" />\n <input type=\"hidden\" name=\"journey\" ref={journeyRef} defaultValue=\"\" />\n </>\n );\n}\n"],"mappings":";AA6CA,SAAS,WAAW,cAAc;AAElC,SAAS,uBAAuB;AAwE5B,mBACE,KADF;AArEJ,IAAM,sBAAsB;AAkBrB,SAAS,aAAa,EAAE,OAAO,GAAoC;AACxE,QAAM,iBAAiB,OAAyB,IAAI;AACpD,QAAM,aAAa,OAAyB,IAAI;AAChD,QAAM,aAAa,OAAO,KAAK;AAE/B,YAAU,MAAM;AACd,QAAI;AACF,YAAM,cAAc,gBAAgB;AACpC,UAAI,eAAe,eAAe,SAAS;AACzC,uBAAe,QAAQ,QAAQ,KAAK,UAAU,WAAW;AAAA,MAC3D;AAAA,IACF,QAAQ;AAAA,IAER;AAEA,UAAM,OAAO,eAAe,SAAS,QAAQ,WAAW,SAAS;AACjE,QAAI,CAAC,KAAM;AAEX,UAAM,gBAAgB,MAAY;AAChC,UAAI,WAAW,QAAS;AACxB,iBAAW,UAAU;AACrB,aAAO,YAAY,cAAc,EAAE,SAAS,OAAO,CAAC;AAAA,IACtD;AAEA,UAAM,iBAAiB,CAAC,UAA+B;AAGrD,UAAI;AACF,cAAM,MAAM,OAAO,eAAe,QAAQ,mBAAmB;AAC7D,cAAM,SAAS,IAAI,WAAW,OAAO,EAAE;AAAA,MACzC,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,UAAM,eAAe,MAAY;AAC/B,aAAO,YAAY,uBAAuB,EAAE,SAAS,OAAO,CAAC;AAAA,IAC/D;AAEA,SAAK,iBAAiB,WAAW,aAAa;AAC9C,SAAK,iBAAiB,YAAY,cAA+B;AACjE,SAAK,iBAAiB,UAAU,YAAY;AAE5C,WAAO,MAAM;AACX,WAAK,oBAAoB,WAAW,aAAa;AACjD,WAAK,oBAAoB,YAAY,cAA+B;AACpE,WAAK,oBAAoB,UAAU,YAAY;AAAA,IACjD;AAAA,EACF,GAAG,CAAC,MAAM,CAAC;AAEX,SACE,iCACE;AAAA,wBAAC,WAAM,MAAK,UAAS,MAAK,eAAc,KAAK,gBAAgB,cAAa,IAAG;AAAA,IAC7E,oBAAC,WAAM,MAAK,UAAS,MAAK,WAAU,KAAK,YAAY,cAAa,IAAG;AAAA,KACvE;AAEJ;","names":[]}