@mdxui/services 0.2.0 → 0.4.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/dist/components/index.d.ts +18 -3
- package/dist/components/index.js +163 -31
- package/dist/components/index.js.map +1 -1
- package/dist/{index-D2nWoFGI.d.ts → index-DNgc8Joy.d.ts} +33 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +340 -193
- package/dist/index.js.map +1 -1
- package/dist/schemas/index.d.ts +1 -1
- package/dist/schemas/index.js +14 -1
- package/dist/schemas/index.js.map +1 -1
- package/dist/shared/index.d.ts +7 -1
- package/dist/shared/index.js +3 -1
- package/dist/shared/index.js.map +1 -1
- package/dist/styles.css +363 -0
- package/package.json +8 -5
package/dist/schemas/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import 'zod/v4/core';
|
|
2
2
|
import 'zod';
|
|
3
3
|
import 'react';
|
|
4
|
-
export { B as Breadcrumb, n as BreadcrumbSchema, C as CatalogHero, o as CatalogHeroSchema, p as CatalogShape, q as CatalogShapeFull, r as CatalogShapeFullSchema, s as CatalogShapeSchema, t as CheckoutPanelPropsFromSchema, u as CheckoutPanelPropsSchema, v as Cta, w as CtaSchema, j as DefensibilityColumnFromSchema, x as DefensibilityColumnSchema, D as DefensibilityPropsFromSchema, y as DefensibilityPropsSchema, z as DeliveryShape, A as DeliveryShapeSchema, E as DeliveryUx, G as DeliveryUxSchema, l as FaqItem, I as FaqItemSchema, F as FaqPropsExtended, J as FaqPropsExtendedSchema, K as FieldRowProps, L as FieldRowPropsSchema,
|
|
4
|
+
export { B as Breadcrumb, n as BreadcrumbSchema, C as CatalogHero, o as CatalogHeroSchema, p as CatalogShape, q as CatalogShapeFull, r as CatalogShapeFullSchema, s as CatalogShapeSchema, t as CheckoutPanelPropsFromSchema, u as CheckoutPanelPropsSchema, v as Cta, w as CtaSchema, j as DefensibilityColumnFromSchema, x as DefensibilityColumnSchema, D as DefensibilityPropsFromSchema, y as DefensibilityPropsSchema, z as DeliveryShape, A as DeliveryShapeSchema, E as DeliveryUx, G as DeliveryUxSchema, l as FaqItem, I as FaqItemSchema, F as FaqPropsExtended, J as FaqPropsExtendedSchema, K as FieldRowProps, L as FieldRowPropsSchema, O as FileInput, Q as FileInputSchema, d as FinalCtaProps, R as FinalCtaPropsSchema, H as HeroPropsExtended, T as HeroPropsExtendedSchema, U as HeroVariantFromSchema, V as HeroVariantSchema, a as HowItWorksProps, X as HowItWorksPropsSchema, h as HowItWorksStep, Y as HowItWorksStepSchema, Z as ImageUploadFieldPropsFromSchema, _ as ImageUploadFieldPropsSchema, $ as LandingPricing, a0 as LandingPricingSchema, a1 as LandingPublicCopy, a2 as LandingPublicCopySchema, a3 as LogoUploadPropsFromSchema, a4 as LogoUploadPropsSchema, M as MastheadProps, a5 as MastheadPropsSchema, N as NavLink, a6 as NavLinkSchema, a7 as OrderField, a8 as OrderFieldSchema, a9 as OrderFlow, aa as OrderFlowSchema, ab as OrderGroup, ac as OrderGroupSchema, ad as OrderLegal, ae as OrderLegalSchema, af as OrderShape, ag as OrderShapeSchema, ah as OrderStep, ai as OrderStepSchema, aj as PortalAction, ak as PortalActionKind, al as PortalActionKindSchema, am as PortalActionSchema, an as PortalColumn, ao as PortalColumnSchema, ap as PortalColumnType, aq as PortalColumnTypeSchema, ar as PortalFilter, as as PortalFilterSchema, at as PortalShape, au as PortalShapeSchema, av as PreviewMode, aw as PreviewModeSchema, k as PriceTier, ax as PriceTierSchema, c as Pricing, b as PricingPropsExtended, ay as PricingPropsExtendedSchema, az as PricingSchema, aA as PricingSummary, aB as PricingSummarySchema, f as ProblemItem, aC as ProblemItemSchema, P as ProblemProps, aD as ProblemPropsSchema, aE as RadioGroupInput, aF as RadioGroupInputSchema, aG as RadioGroupOption, aH as RadioGroupOptionSchema, aI as RadioGroupProps, aJ as RadioGroupPropsSchema, aK as SelectFieldProps, aL as SelectFieldPropsSchema, aM as SelectInput, aN as SelectInputSchema, aO as ServiceArchetypeId, aP as ServiceArchetypeIdSchema, aQ as ServiceBranding, aR as ServiceBrandingSchema, aS as ServiceFormPropsFromSchema, aT as ServiceFormPropsSchema, aU as ServiceSchemaSpec, aV as ServiceSchemaSpecSchema, e as SiteAction, aW as SiteActionSchema, m as SiteFooterLink, aX as SiteFooterLinkSchema, S as SiteFooterProps, aY as SiteFooterPropsSchema, aZ as StepHeadingPropsFromSchema, a_ as StepHeadingPropsSchema, a$ as TextFieldProps, b0 as TextFieldPropsSchema, b1 as TextInput, b2 as TextInputSchema, b3 as UpsellBannerPropsFromSchema, b4 as UpsellBannerPropsSchema, b5 as UpsellCardPropsFromSchema, b6 as UpsellCardPropsSchema, g as WhatYouGetItem, b7 as WhatYouGetItemSchema, W as WhatYouGetProps, b8 as WhatYouGetPropsSchema } from '../index-DNgc8Joy.js';
|
package/dist/schemas/index.js
CHANGED
|
@@ -268,13 +268,25 @@ var FinalCtaPropsSchema = z.object({
|
|
|
268
268
|
primary: SiteActionSchema,
|
|
269
269
|
secondary: SiteActionSchema.optional()
|
|
270
270
|
});
|
|
271
|
+
var NavLinkSchema = z.object({
|
|
272
|
+
label: z.string(),
|
|
273
|
+
href: z.string()
|
|
274
|
+
});
|
|
271
275
|
var MastheadPropsSchema = z.object({
|
|
272
276
|
brand: z.object({
|
|
273
277
|
primary: z.string(),
|
|
274
278
|
secondary: z.string().optional(),
|
|
275
|
-
href: z.string()
|
|
279
|
+
href: z.string(),
|
|
280
|
+
/** Optional brand logo, shown to the LEFT of the wordmark. With it the
|
|
281
|
+
* navbar reads `[logo] <primary>`; without it the wordmark stands alone. */
|
|
282
|
+
logo: z.object({ src: z.string(), alt: z.string() }).optional()
|
|
276
283
|
}),
|
|
277
284
|
cta: z.object({ label: z.string(), href: z.string() }).optional(),
|
|
285
|
+
/** Page links shown centered on `md`+; collapsed into the mobile dropdown
|
|
286
|
+
* below `md`. 3–5 links — 5 is the hard cap (more crowds the centered nav +
|
|
287
|
+
* mobile overlay). Hrefs are typically in-page section anchors
|
|
288
|
+
* (`#how-it-works` / `#pricing` / `#faq`) but any route works. */
|
|
289
|
+
links: z.array(NavLinkSchema).max(5).optional(),
|
|
278
290
|
eyebrow: z.string().optional(),
|
|
279
291
|
narrow: z.boolean().optional()
|
|
280
292
|
});
|
|
@@ -549,6 +561,7 @@ export {
|
|
|
549
561
|
LandingPublicCopySchema,
|
|
550
562
|
LogoUploadPropsSchema,
|
|
551
563
|
MastheadPropsSchema,
|
|
564
|
+
NavLinkSchema,
|
|
552
565
|
OrderFieldSchema,
|
|
553
566
|
OrderFlowSchema,
|
|
554
567
|
OrderGroupSchema,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/schemas/index.ts"],"sourcesContent":["/**\n * @mdxui/services — the Services dialect prop contract (ADR 0003 §3).\n *\n * These Zod schemas ARE the Services dialect's public prop surface. They were\n * authored and battle-tested in carriage's `src/chassis/mdxui-bridge/extensions/`\n * (7 products + 4 example services + 26 snapshot baselines) by reframing each\n * carriage component prop interface against mdxui's nearest equivalent — every\n * `// upstream-proposal:` comment documents WHY the Services shape differs from\n * neo/mdxui's dev-first grammar. That delta IS the dialect. This package is the\n * upstream those proposals always pointed at: it promotes the shapes to a\n * published contract.\n *\n * The four base mdxui input schemas (Text/Select/RadioGroup/File) are the\n * dialect's base vocabulary for the intake-form field contract; the rest are\n * fresh Services-semantic objects. The landing narrative arc (Hero → Problem →\n * WhatYouGet → HowItWorks → Defensibility → ReportPricing → Faq → FinalCta)\n * does not depend on the mdxui input schemas.\n */\n\nimport type React from 'react'\nimport { z } from 'zod'\nimport {\n TextInputPropsSchema,\n SelectInputPropsSchema,\n RadioGroupInputPropsSchema,\n FileInputPropsSchema,\n} from 'mdxui'\n\n// =============================================================================\n// PR 2 extensions — derive* contract layer\n// =============================================================================\n\n// -----------------------------------------------------------------------------\n// CatalogShapeSchema\n//\n// Zod-validated form of Carriage's `CatalogShape` (the \"browse\" surface\n// that deriveCatalog produces). mdxui's LandingPagePropsSchema is a layout\n// container (`{ children: any }`) — it composes section-level schemas\n// (HeroPropsSchema, PricingPropsSchema, etc.) as children, not as a flat\n// data shape. deriveCatalog returns flat data (hero headline, pricingSummary)\n// that a renderer then maps to section-level components. The two shapes serve\n// different layers; forcing deriveCatalog's output into LandingPagePropsSchema\n// would be a meaningless structural fit.\n//\n// upstream-proposal: file against mdxui as CatalogShapeSchema alongside\n// DeliveryShapeSchema and PortalShapeSchema — all three are the Carriage-\n// proposed service-runtime data shapes that precede component rendering.\n// See docs/patterns/upstream-proposals.md §PR2-catalog (PR 5 will file this).\n// -----------------------------------------------------------------------------\n\nexport const CatalogHeroSchema = z.object({\n /** Main landing-page headline. Falls back to `service.name` when unset. */\n headline: z.string().optional(),\n /** Sub-headline. Falls back to `service.promise` when unset. */\n subheadline: z.string().optional(),\n /** Asset reference for a visual element resolved by the renderer.\n * Today Carriage uses per-product HeroGlyph SVGs keyed by slug. */\n visual: z.string().optional(),\n})\n\nexport type CatalogHero = z.infer<typeof CatalogHeroSchema>\n\n/**\n * Pricing summary hint for the catalog card. Drives which Pricing\n * layout variant the renderer selects.\n *\n * upstream-proposal: same as CatalogShapeSchema above.\n */\nexport const PricingSummarySchema = z.enum([\n 'starting-at',\n 'per-call',\n 'tier-comparison',\n 'contact-us',\n])\n\nexport type PricingSummary = z.infer<typeof PricingSummarySchema>\n\n/**\n * Browse-side catalog UI shape. Produced by deriveCatalog(svc).\n *\n * upstream-proposal: file against mdxui — see\n * docs/patterns/upstream-proposals.md §PR2-catalog.\n * The shape is the data layer; LandingPagePropsSchema (already in mdxui)\n * is the layout layer. Proposing CatalogShapeSchema as the data contract\n * that feeds the layout.\n */\nexport const CatalogShapeSchema = z.object({\n hero: CatalogHeroSchema.optional(),\n pricingSummary: PricingSummarySchema,\n})\n\nexport type CatalogShape = z.infer<typeof CatalogShapeSchema>\n\n// -----------------------------------------------------------------------------\n// Input field schemas with `source` made optional\n//\n// mdxui's BaseInputPropsSchema requires `source: string` (the\n// ReactAdmin/Platform.do data-binding field path). Carriage's form renderer\n// uses `name` (the JSON-schema property key) for data binding — `source` is\n// not applicable to the derive-layer output. We extend each input schema to\n// make `source` optional so derivOrder's field objects can conform without\n// carrying a meaningless value.\n//\n// upstream-proposal: file against mdxui — source should be optional (or moved\n// to a separate ReactAdmin-specific extension) since non-ReactAdmin consumers\n// don't use it. See docs/patterns/upstream-proposals.md §PR2-source-optional.\n// -----------------------------------------------------------------------------\n\n/**\n * TextInputPropsSchema with `source` optional.\n * Used for string fields without enum (plain text, email, date, etc.)\n */\nexport const TextInputSchema = TextInputPropsSchema.extend({\n source: z.string().optional(),\n})\n\nexport type TextInput = z.infer<typeof TextInputSchema>\n\n/**\n * SelectInputPropsSchema with `source` optional.\n * Used for string/number fields with `enum` constraint.\n */\nexport const SelectInputSchema = SelectInputPropsSchema.extend({\n source: z.string().optional(),\n})\n\nexport type SelectInput = z.infer<typeof SelectInputSchema>\n\n/**\n * RadioGroupInputPropsSchema with `source` optional.\n * Used for string/number fields with enum + `options` (rich label/sub display).\n */\nexport const RadioGroupInputSchema = RadioGroupInputPropsSchema.extend({\n source: z.string().optional(),\n})\n\nexport type RadioGroupInput = z.infer<typeof RadioGroupInputSchema>\n\n/**\n * FileInputPropsSchema with `source` optional.\n * Used for fields with `widget: 'image-upload'` or `format: 'uri'` + upload widget.\n */\nexport const FileInputSchema = FileInputPropsSchema.extend({\n source: z.string().optional(),\n})\n\nexport type FileInput = z.infer<typeof FileInputSchema>\n\n// -----------------------------------------------------------------------------\n// OrderShapeSchema\n//\n// Zod-validated form of Carriage's `OrderShape` (the \"buy / form\" surface\n// that deriveOrder produces). The individual field entries are validated at\n// the TEST layer against the dispatched input schemas (TextInputSchema,\n// SelectInputSchema, etc.) by widget kind — that validation is runtime-\n// contextual and lives in derive.mdxui-contract.test.ts.\n//\n// upstream-proposal: file against mdxui as OrderShapeSchema alongside\n// CatalogShapeSchema, DeliveryShapeSchema, and PortalShapeSchema.\n// See docs/patterns/upstream-proposals.md §PR2-order (PR 5 will file this).\n// -----------------------------------------------------------------------------\n\nexport const OrderFlowSchema = z.enum([\n 'instant',\n 'guided',\n 'consultation-first',\n])\n\nexport type OrderFlow = z.infer<typeof OrderFlowSchema>\n\n/**\n * One field in an order step — the data representation used by the\n * form renderer.\n *\n * upstream-proposal: same as OrderShapeSchema above.\n */\nexport const OrderFieldSchema = z.object({\n name: z.string(),\n type: z.enum(['string', 'number', 'integer', 'boolean']),\n required: z.boolean(),\n title: z.string().optional(),\n description: z.string().optional(),\n enum: z.array(z.union([z.string(), z.number(), z.boolean()])).readonly().optional(),\n pattern: z.string().optional(),\n format: z.enum(['date', 'date-time', 'email', 'uri']).optional(),\n minimum: z.number().optional(),\n maximum: z.number().optional(),\n widget: z.enum(['vin-decoder', 'image-upload']).optional(),\n row: z.number().optional(),\n placeholder: z.string().optional(),\n autocomplete: z.string().optional(),\n options: z.array(z.object({\n value: z.union([z.string(), z.number(), z.boolean()]),\n label: z.string().optional(),\n sub: z.string().optional(),\n })).readonly().optional(),\n tiers: z.array(z.string()).readonly().optional(),\n /** Phase 1b multi-substrate (Carriage Iter / master 2026-05-26):\n * forwarded from JSON Schema's `x-connect` vendor annotation. When\n * set, the chassis form renders `<ConnectFlow>` instead of a\n * TextField. upstream-proposal: §PR11-theme + §x-connect. */\n xConnect: z.object({\n providerId: z.string(),\n resourceType: z.enum([\n 'channel',\n 'crm-record',\n 'sequence',\n 'phone-number',\n 'voice-line',\n 'webhook-event',\n 'database-table',\n 'folder',\n 'mailbox',\n 'account',\n ]),\n }).optional(),\n /** Phase 1b multi-substrate: forwarded from JSON Schema's\n * `x-derived-from` vendor annotation. When set, the chassis form\n * suppresses input UI and auto-populates from connection metadata.\n * upstream-proposal: §PR11-theme + §x-derived-from. */\n xDerivedFrom: z.object({\n providerId: z.string(),\n metadataKey: z.string(),\n }).optional(),\n})\n\nexport type OrderField = z.infer<typeof OrderFieldSchema>\n\nexport const OrderGroupSchema = z.object({\n id: z.string(),\n title: z.string(),\n description: z.string().optional(),\n fields: z.array(OrderFieldSchema).readonly(),\n})\n\nexport type OrderGroup = z.infer<typeof OrderGroupSchema>\n\nexport const OrderStepSchema = z.object({\n id: z.string(),\n title: z.string().optional(),\n fields: z.array(OrderFieldSchema).readonly(),\n groups: z.array(OrderGroupSchema).readonly(),\n})\n\nexport type OrderStep = z.infer<typeof OrderStepSchema>\n\nexport const OrderLegalSchema = z.object({\n termsRequired: z.boolean(),\n privacyRequired: z.boolean(),\n})\n\nexport type OrderLegal = z.infer<typeof OrderLegalSchema>\n\n/**\n * Order-side UI shape. Produced by deriveOrder(svc).\n *\n * upstream-proposal: file against mdxui — see\n * docs/patterns/upstream-proposals.md §PR2-order.\n */\nexport const OrderShapeSchema = z.object({\n flow: OrderFlowSchema,\n steps: z.array(OrderStepSchema).readonly().optional(),\n legal: OrderLegalSchema.optional(),\n})\n\nexport type OrderShape = z.infer<typeof OrderShapeSchema>\n\n// -----------------------------------------------------------------------------\n// DeliveryShapeSchema\n//\n// mdxui has no delivery-shape schema — this is a Carriage proposal.\n// Produced by deriveDelivery(svc). Covers the post-checkout UX archetype,\n// preview mode, and optional SLA fields.\n//\n// upstream-proposal: file against mdxui as DeliveryShapeSchema. Covers the\n// \"what the buyer sees after payment\" surface — document download, async-batch\n// status, and sync-result-card. See docs/patterns/upstream-proposals.md\n// §PR2-delivery.\n// -----------------------------------------------------------------------------\n\n/**\n * Post-checkout UX archetype.\n *\n * sync-result-card — synchronous return, inline card\n * document-download — file deliverable + email link\n * async-batch-status — job-queue with polling status; download on completion\n */\nexport const DeliveryUxSchema = z.enum([\n 'sync-result-card',\n 'document-download',\n 'async-batch-status',\n])\n\nexport type DeliveryUx = z.infer<typeof DeliveryUxSchema>\n\n/**\n * Preview mode for the delivery surface.\n *\n * first-page — rendered PDF first page\n * first-row — first N rows of a spreadsheet\n * inline-summary — one-line text summary in the result card\n * none — no preview\n */\nexport const PreviewModeSchema = z.enum([\n 'first-page',\n 'first-row',\n 'inline-summary',\n 'none',\n])\n\nexport type PreviewMode = z.infer<typeof PreviewModeSchema>\n\n/**\n * Delivery-side UI shape. Produced by deriveDelivery(svc).\n *\n * upstream-proposal: file against mdxui — see\n * docs/patterns/upstream-proposals.md §PR2-delivery.\n */\nexport const DeliveryShapeSchema = z.object({\n ux: DeliveryUxSchema,\n previewMode: PreviewModeSchema,\n /** Whether to show a step-by-step progress timeline while the cascade runs. */\n progressTimeline: z.boolean(),\n /** Optional SLA echo — ISO 8601 duration (e.g. \"PT2M\"). */\n estimatedDelivery: z.string().optional(),\n /** Optional outcome predicate lifted from outcomeContract. */\n outcomePredicate: z.string().optional(),\n})\n\nexport type DeliveryShape = z.infer<typeof DeliveryShapeSchema>\n\n// -----------------------------------------------------------------------------\n// PortalShapeSchema\n//\n// mdxui has no portal-shape schema — this is a Carriage proposal.\n// Produced by derivePortal(svc). Covers the order-management table surface:\n// column set, filters, and row actions.\n//\n// upstream-proposal: file against mdxui as PortalShapeSchema. Covers the\n// operator/admin \"manage orders\" surface. See docs/patterns/upstream-proposals.md\n// §PR2-portal.\n// -----------------------------------------------------------------------------\n\n/**\n * Column type vocabulary for the portal table renderer.\n *\n * upstream-proposal: same as PortalShapeSchema above.\n */\nexport const PortalColumnTypeSchema = z.enum([\n 'identifier',\n 'timestamp',\n 'currency',\n 'duration',\n 'status',\n 'text',\n 'evaluator',\n])\n\nexport type PortalColumnType = z.infer<typeof PortalColumnTypeSchema>\n\nexport const PortalColumnSchema = z.object({\n id: z.string(),\n label: z.string(),\n type: PortalColumnTypeSchema,\n})\n\nexport type PortalColumn = z.infer<typeof PortalColumnSchema>\n\n/**\n * Row action vocabulary for the portal table renderer.\n *\n * upstream-proposal: same as PortalShapeSchema above.\n */\nexport const PortalActionKindSchema = z.enum([\n 'view-deliverable',\n 'reissue',\n 'refund',\n 'flag-for-review',\n])\n\nexport type PortalActionKind = z.infer<typeof PortalActionKindSchema>\n\nexport const PortalActionSchema = z.object({\n id: z.string(),\n label: z.string(),\n kind: PortalActionKindSchema,\n})\n\nexport type PortalAction = z.infer<typeof PortalActionSchema>\n\nexport const PortalFilterSchema = z.object({\n id: z.string(),\n field: z.string(),\n label: z.string(),\n})\n\nexport type PortalFilter = z.infer<typeof PortalFilterSchema>\n\n/**\n * Order-management UI shape. Produced by derivePortal(svc).\n *\n * upstream-proposal: file against mdxui — see\n * docs/patterns/upstream-proposals.md §PR2-portal.\n */\nexport const PortalShapeSchema = z.object({\n columns: z.array(PortalColumnSchema),\n filters: z.array(PortalFilterSchema).optional(),\n actions: z.array(PortalActionSchema).optional(),\n})\n\nexport type PortalShape = z.infer<typeof PortalShapeSchema>\n\n// =============================================================================\n// PR 3 extensions — Tier 1 component reframe\n// =============================================================================\n\n// -----------------------------------------------------------------------------\n// HeroPropsSchema extension\n//\n// mdxui's HeroPropsSchema uses `title` (string), `badge` (string), and\n// `callToAction` (string label only — no href). Carriage's Hero component uses:\n// - `eyebrow` (small uppercase label above the headline)\n// - `headline` (the h1 — distinct from mdxui's `title`)\n// - `body` (body paragraph — mdxui has `subtitle` but that's a sub-head, not prose)\n// - `primary` / `secondary` (action objects with `label` + `href` + `external`)\n// - `showGlyph` / `illustration` (presentational controls; no mdxui equivalent)\n//\n// mdxui's `actions.primary` accepts a string or `{ href, onClick, target }` —\n// Carriage's action object has `label` (string) + `href` + `external` (bool).\n// The shapes are structurally incompatible without adapter work. Extending here.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR3-hero\n// -----------------------------------------------------------------------------\n\n/** Inline action with label + href + optional new-tab flag.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-hero */\nexport const SiteActionSchema = z.object({\n label: z.string(),\n href: z.string(),\n external: z.boolean().optional(),\n})\n\nexport type SiteAction = z.infer<typeof SiteActionSchema>\n\n/**\n * Hero composition variant identifier. Drives the dispatcher in\n * `<Hero>` (chassis/components/landing/Hero.tsx) between `HeroSplit`\n * (default) and `HeroStacked`.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR12-hero-variant\n * (master 2026-05-26 — illustration abstraction Phase 3; see\n * docs/abstraction/illustrations.md §1.4 + §3).\n */\nexport const HeroVariantSchema = z.enum([\n 'split-illustration-right',\n 'stacked-illustration-below',\n])\n\nexport type HeroVariantFromSchema = z.infer<typeof HeroVariantSchema>\n\n/**\n * HeroPropsSchema extended for Carriage's landing-page Hero component.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-hero\n */\nexport const HeroPropsExtendedSchema = z.object({\n eyebrow: z.string(),\n headline: z.string(),\n body: z.string(),\n primary: SiteActionSchema,\n secondary: SiteActionSchema.optional(),\n showGlyph: z.boolean().optional(),\n /** When true, the glyph also renders below `lg` (stacked beneath\n * the hero text on mobile). When false (default), the glyph is\n * hidden below `lg`. Services opt in via `publicCopy.hero.glyphOnMobile`.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR11-theme */\n glyphOnMobile: z.boolean().optional(),\n illustration: z.any().optional(),\n /** Hero composition variant. Routes the `<Hero>` dispatcher to\n * `HeroSplit` (default) or `HeroStacked`. Sourced from\n * `ServiceDefinition.branding.heroVariant`.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR12-hero-variant */\n variant: HeroVariantSchema.optional(),\n})\n\nexport type HeroPropsExtended = z.infer<typeof HeroPropsExtendedSchema>\n\n// -----------------------------------------------------------------------------\n// PricingPropsSchema extension\n//\n// mdxui's PricingTierSchema uses `name` (Carriage uses `tier`), `callToAction`\n// as a plain string (Carriage uses `cta: { label, href }`), and `highlighted`\n// (Carriage uses `featured`). Carriage's tier also carries Stripe commerce\n// fields (`tierKey`, `sku`, `amountCents`, `currency`, `stripeName`) and a\n// distinct `audience` sub-headline. mdxui has no commerce fields — Carriage\n// adds them as the proposing substrate.\n//\n// mdxui's PricingPropsSchema also uses `title` not `eyebrow`/`heading`.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR3-pricing\n// -----------------------------------------------------------------------------\n\n/** One pricing tier with Stripe commerce fields.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-pricing */\nexport const PriceTierSchema = z.object({\n tierKey: z.string(),\n tier: z.string(),\n price: z.string(),\n audience: z.string(),\n features: z.array(z.string()),\n featured: z.boolean().optional(),\n cta: z.object({ label: z.string(), href: z.string() }),\n sku: z.string(),\n amountCents: z.number(),\n currency: z.enum(['usd', 'eur', 'gbp']),\n stripeName: z.string(),\n minimumAmountCents: z.number().optional(),\n priceSuffix: z.string().optional(),\n})\n\nexport type PriceTier = z.infer<typeof PriceTierSchema>\n\n/**\n * PricingPropsSchema extended for Carriage's Pricing component.\n *\n * `tiers` uses `.readonly()` (Zod v4+) so `z.infer<...>` produces\n * `readonly PriceTier[]` — matching `ServiceDefinition.pricing.tiers`.\n * The `Omit<...> & { tiers: readonly PriceTier[] }` workaround in\n * `Pricing.tsx` is retired; the component interface is now\n * `z.infer<typeof PricingPropsExtendedSchema>` directly.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-pricing\n */\nexport const PricingPropsExtendedSchema = z.object({\n eyebrow: z.string(),\n heading: z.string(),\n tiers: z.array(PriceTierSchema).readonly(),\n footnote: z.string().optional(),\n})\n\nexport type PricingPropsExtended = z.infer<typeof PricingPropsExtendedSchema>\n\n// -----------------------------------------------------------------------------\n// FAQPropsSchema extension\n//\n// mdxui's FAQPropsSchema uses `title` (optional) and items with `question` /\n// `answer`. Carriage's Faq uses `eyebrow` + `heading` (both required, distinct\n// typographic roles) and items with `q` / `a` (short keys used throughout\n// publicCopy JSON). The item-field rename (question→q, answer→a) is a naming\n// convention that predates mdxui adoption; the keys appear across all service\n// JSON files. Proposing mdxui accept `q`/`a` as aliases (or Carriage migrates\n// to `question`/`answer` in a follow-up once settled with Nathan).\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR3-faq\n// -----------------------------------------------------------------------------\n\n/** FAQ item using Carriage's short-key convention (q/a).\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-faq */\nexport const FaqItemSchema = z.object({\n q: z.string(),\n a: z.string(),\n})\n\nexport type FaqItem = z.infer<typeof FaqItemSchema>\n\n/**\n * FAQPropsSchema extended for Carriage's Faq component.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-faq\n */\nexport const FaqPropsExtendedSchema = z.object({\n eyebrow: z.string(),\n heading: z.string(),\n items: z.array(FaqItemSchema),\n})\n\nexport type FaqPropsExtended = z.infer<typeof FaqPropsExtendedSchema>\n\n// -----------------------------------------------------------------------------\n// HowItWorksPropsSchema (new — no mdxui equivalent)\n//\n// mdxui has no \"how it works\" numbered-step section schema. The closest is\n// FeaturesPropsSchema (title + description + features[]) but that takes\n// description + icon + actions per feature — not a numbered-step with a\n// large display numeral. Proposing HowItWorksPropsSchema to mdxui.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR3-howitworks\n// -----------------------------------------------------------------------------\n\n/** One numbered step in a HowItWorks section.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-howitworks */\nexport const HowItWorksStepSchema = z.object({\n n: z.string(),\n title: z.string(),\n body: z.string(),\n})\n\nexport type HowItWorksStep = z.infer<typeof HowItWorksStepSchema>\n\n/**\n * Props for the HowItWorks component. No mdxui base — proposed from scratch.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-howitworks\n */\nexport const HowItWorksPropsSchema = z.object({\n eyebrow: z.string(),\n heading: z.string(),\n steps: z.array(HowItWorksStepSchema),\n /** Optional mini-illustration per step. When provided and length\n * matches `steps.length`, each step renders its illustration in\n * a row above the number. All-or-none — if length doesn't match,\n * the prop is silently ignored and the text-only layout renders\n * (per opt-in-only semantics in illustrations.md §2).\n *\n * Sourced from the per-service illustration manifest at\n * `src/services/<slug>/illustration.tsx`.\n *\n * Each element is a React `ComponentType` (zero-arg renderer).\n * Zod can't validate component identity at runtime; type-level\n * contract carries via `z.custom`.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR12-step-illustrations\n * (master 2026-05-26 — illustration abstraction Phase 4). */\n stepIllustrations: z\n .array(z.custom<React.ComponentType>())\n .optional(),\n})\n\nexport type HowItWorksProps = z.infer<typeof HowItWorksPropsSchema>\n\n// -----------------------------------------------------------------------------\n// WhatYouGetPropsSchema (new — no mdxui equivalent)\n//\n// mdxui has no \"what you get\" numbered-feature grid schema. The section\n// renders a numbered grid of deliverable sections (n + title + body) — a\n// shape distinct from FeaturesPropsSchema's icon-based list. Proposing\n// WhatYouGetPropsSchema to mdxui.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR3-whatyouget\n// -----------------------------------------------------------------------------\n\n/** One numbered item in a WhatYouGet section.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-whatyouget */\nexport const WhatYouGetItemSchema = z.object({\n n: z.string(),\n title: z.string(),\n body: z.string(),\n})\n\nexport type WhatYouGetItem = z.infer<typeof WhatYouGetItemSchema>\n\n/**\n * Props for the WhatYouGet component. No mdxui base — proposed from scratch.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-whatyouget\n */\nexport const WhatYouGetPropsSchema = z.object({\n eyebrow: z.string(),\n heading: z.string(),\n sections: z.array(WhatYouGetItemSchema),\n})\n\nexport type WhatYouGetProps = z.infer<typeof WhatYouGetPropsSchema>\n\n// -----------------------------------------------------------------------------\n// CTASectionPropsSchema extension → FinalCtaPropsSchema\n//\n// mdxui's CTASectionPropsSchema uses `title` (string) and `callToAction`\n// (string label only). Carriage's FinalCta uses `eyebrow` + `headline`\n// (both required, distinct typographic roles) and `primary`/`secondary`\n// (action objects with label + href + external). The action objects are\n// incompatible with mdxui's string `callToAction` without an adapter.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR3-finalcta\n// -----------------------------------------------------------------------------\n\n/**\n * FinalCtaPropsSchema — CTASectionPropsSchema extended for Carriage.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-finalcta\n */\nexport const FinalCtaPropsSchema = z.object({\n eyebrow: z.string(),\n headline: z.string(),\n primary: SiteActionSchema,\n secondary: SiteActionSchema.optional(),\n})\n\nexport type FinalCtaProps = z.infer<typeof FinalCtaPropsSchema>\n\n// -----------------------------------------------------------------------------\n// HeaderPropsSchema extension → MastheadPropsSchema\n//\n// mdxui's HeaderPropsSchema uses `logo` (any), `nav: NavItem[]`, `cta.text`.\n// Carriage's Masthead uses `brand: { primary, secondary?, href }` (text-based\n// brand lockup — no image logo), `cta: { label, href }` (renamed `text`→`label`),\n// `eyebrow` (right-slot fallback when no CTA), and `narrow` (container width\n// toggle). mdxui has no `eyebrow` slot or narrow-layout concept.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR3-masthead\n// -----------------------------------------------------------------------------\n\n/**\n * MastheadPropsSchema — HeaderPropsSchema extended for Carriage's Masthead.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-masthead\n */\nexport const MastheadPropsSchema = z.object({\n brand: z.object({\n primary: z.string(),\n secondary: z.string().optional(),\n href: z.string(),\n }),\n cta: z.object({ label: z.string(), href: z.string() }).optional(),\n eyebrow: z.string().optional(),\n narrow: z.boolean().optional(),\n})\n\nexport type MastheadProps = z.infer<typeof MastheadPropsSchema>\n\n// -----------------------------------------------------------------------------\n// FooterPropsSchema extension → SiteFooterPropsSchema\n//\n// mdxui's FooterPropsSchema uses `logo` (any), `links: FooterLinkGroup[]`\n// (grouped by section title), `social[]`, `copyright`, `newsletter`. Carriage's\n// Footer is a minimal bar with a flat `text` attribution string and an optional\n// flat `links[]` (label + href only — no grouping, no social, no newsletter).\n// The structures are fundamentally different: mdxui's footer is a full-featured\n// multi-column layout; Carriage's is a single-row legal bar.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR3-footer\n// -----------------------------------------------------------------------------\n\n/** Flat footer link (no grouping).\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-footer */\nexport const SiteFooterLinkSchema = z.object({\n label: z.string(),\n href: z.string(),\n})\n\nexport type SiteFooterLink = z.infer<typeof SiteFooterLinkSchema>\n\n/**\n * SiteFooterPropsSchema — FooterPropsSchema extended for Carriage's Footer.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-footer\n */\nexport const SiteFooterPropsSchema = z.object({\n text: z.string(),\n links: z.array(SiteFooterLinkSchema).optional(),\n})\n\nexport type SiteFooterProps = z.infer<typeof SiteFooterPropsSchema>\n\n// =============================================================================\n// PR 4 extensions — form primitives\n// =============================================================================\n\n// -----------------------------------------------------------------------------\n// TextFieldPropsSchema\n//\n// mdxui's TextInputPropsSchema is a data-binding shape (ReactAdmin-style):\n// `source` (field path), `value`/`defaultValue` as optional, no `onChange`\n// callback. Carriage's TextField is a controlled React component:\n// `value: string` (required), `onChange: (v: string) => void` (required),\n// `type` includes 'number' and 'date' (not in mdxui's enum), `hint` (not\n// `helperText`), `inputRef` (Ref<HTMLInputElement>), `mono` and `invalid`\n// (presentational flags). The shapes are structurally incompatible for a\n// direct `.extend()` — proposing a Carriage-native schema that adopts\n// mdxui naming where possible (`label`, `placeholder`).\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR4-textfield\n// -----------------------------------------------------------------------------\n\n/**\n * TextFieldPropsSchema — controlled text-input component props.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR4-textfield\n */\nexport const TextFieldPropsSchema = z.object({\n label: z.string(),\n value: z.string(),\n onChange: z.custom<(v: string) => void>(),\n placeholder: z.string().optional(),\n /** Helper text shown below the field. `invalid=true` renders it in error colour. */\n hint: z.string().optional(),\n type: z.enum(['text', 'date', 'number', 'email']).optional(),\n /** Right-edge suffix label (e.g. \"miles\", \"%\"). */\n suffix: z.string().optional(),\n /** Renders the input in a monospace typeface (e.g. VIN, code). */\n mono: z.boolean().optional(),\n /** Renders the field in error state (red border + hint text). */\n invalid: z.boolean().optional(),\n inputRef: z.custom<React.Ref<HTMLInputElement>>().optional(),\n /** HTML `autocomplete` attribute for browser autofill. */\n autoComplete: z.string().optional(),\n})\n\nexport type TextFieldProps = z.infer<typeof TextFieldPropsSchema>\n\n// -----------------------------------------------------------------------------\n// SelectFieldPropsSchema\n//\n// mdxui's SelectInputPropsSchema is a data-binding shape: `source`, options\n// with `disabled`/`group`/`icon`/`description`, no `onChange` callback, no\n// `autoComplete`. Carriage's SelectField is a controlled dropdown:\n// `value: string` (required), `onChange: (v: string) => void` (required),\n// `options: Array<{ value: string; label: string }>` (string-only, no extras),\n// `autoComplete` for browser autofill.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR4-selectfield\n// -----------------------------------------------------------------------------\n\n/**\n * SelectFieldPropsSchema — controlled select-dropdown component props.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR4-selectfield\n */\nexport const SelectFieldPropsSchema = z.object({\n label: z.string(),\n value: z.string(),\n onChange: z.custom<(v: string) => void>(),\n options: z.array(z.object({ value: z.string(), label: z.string() })),\n /** HTML `autocomplete` attribute for browser autofill. */\n autoComplete: z.string().optional(),\n})\n\nexport type SelectFieldProps = z.infer<typeof SelectFieldPropsSchema>\n\n// -----------------------------------------------------------------------------\n// RadioGroupPropsSchema\n//\n// mdxui's RadioGroupInputPropsSchema is a data-binding shape: `source`,\n// options with `disabled`/`group`/`icon`/`description`, no `onChange`,\n// no `sub` per option. Carriage's RadioGroup is a generic controlled component:\n// the value type `T` extends `string`; options carry an optional `sub`\n// (secondary descriptor line inside the card). No mdxui equivalent for `sub`.\n// The generic `T` can't be expressed in Zod — the schema uses `z.string()` for\n// value/option value; callers narrow to `T` at the component level.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR4-radiogroup\n// -----------------------------------------------------------------------------\n\n/** One option in a RadioGroup card.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR4-radiogroup */\nexport const RadioGroupOptionSchema = z.object({\n value: z.string(),\n label: z.string(),\n /** Optional secondary descriptor line rendered inside the card. */\n sub: z.string().optional(),\n})\n\nexport type RadioGroupOption = z.infer<typeof RadioGroupOptionSchema>\n\n/**\n * RadioGroupPropsSchema — controlled radio-card-group component props.\n * Note: the generic type parameter `T extends string` from RadioGroup<T>\n * is represented as `z.string()` here; consumers narrow at call sites.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR4-radiogroup\n */\nexport const RadioGroupPropsSchema = z.object({\n label: z.string(),\n name: z.string(),\n value: z.string(),\n onChange: z.custom<(v: string) => void>(),\n options: z.array(RadioGroupOptionSchema),\n})\n\nexport type RadioGroupProps = z.infer<typeof RadioGroupPropsSchema>\n\n// -----------------------------------------------------------------------------\n// FieldRowPropsSchema (new — no mdxui equivalent)\n//\n// FieldRow is a 2-column layout shell (`display: grid; grid-template-columns:\n// 1fr 1fr`). mdxui has no layout-grid primitive for form field pairs.\n// The only prop is `children: ReactNode`. Proposing a minimal schema.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR4-fieldrow\n// -----------------------------------------------------------------------------\n\n/**\n * FieldRowPropsSchema — 2-column layout shell for side-by-side form fields.\n * No mdxui equivalent. Proposed from scratch.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR4-fieldrow\n */\nexport const FieldRowPropsSchema = z.object({\n children: z.custom<React.ReactNode>(),\n})\n\nexport type FieldRowProps = z.infer<typeof FieldRowPropsSchema>\n\n// -----------------------------------------------------------------------------\n// StepHeadingPropsSchema (new — no mdxui equivalent)\n//\n// StepHeading renders a numbered section header (index like \"01\"/\"02\",\n// eyebrow, title, body). mdxui has no multi-step form section header schema.\n// The closest mdxui primitive is HeroPropsSchema's eyebrow/headline/body\n// pattern, but HeroPropsSchema also carries CTAs and is a page-level section,\n// not a within-form step marker. Proposing StepHeadingPropsSchema as a\n// distinct lightweight schema.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR4-stepheading\n// -----------------------------------------------------------------------------\n\n/**\n * StepHeadingPropsSchema — numbered section header for multi-step flows.\n * No mdxui equivalent. Proposed from scratch.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR4-stepheading\n */\nexport const StepHeadingPropsSchema = z.object({\n /** Numeric step indicator, e.g. \"01\", \"02\". Rendered in tabular mono. */\n index: z.string(),\n /** Short action-verb eyebrow label. e.g. \"Connect\", \"Compose\". */\n eyebrow: z.string(),\n /** Primary section heading. */\n title: z.string(),\n /** Supporting body copy below the heading. */\n body: z.string(),\n className: z.string().optional(),\n})\n\nexport type StepHeadingPropsFromSchema = z.infer<typeof StepHeadingPropsSchema>\n\n// -----------------------------------------------------------------------------\n// LogoUploadPropsSchema (new — no mdxui equivalent)\n//\n// LogoUpload is a Vercel-Blob-backed logo upload widget. mdxui's\n// FileInputPropsSchema models file inputs as data-binding shapes (no\n// `uploading` state flag, no `onClear` callback, no `bodyText`). Carriage's\n// LogoUpload owns the visual preview + upload/clear/error state externally\n// (the parent form drives state; this component renders it). The shape is\n// fundamentally a controlled component with stateful flags, not a data-\n// binding primitive. Proposing LogoUploadPropsSchema as a Carriage-native\n// controlled-upload schema.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR4-logoupload\n// -----------------------------------------------------------------------------\n\n/**\n * LogoUploadPropsSchema — controlled logo-upload widget with preview.\n * No mdxui equivalent. Proposed from scratch.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR4-logoupload\n */\nexport const LogoUploadPropsSchema = z.object({\n /** Resolved Vercel-Blob URL, or null when no logo is set. */\n value: z.string().nullable(),\n /** True while the upload network call is in-flight. */\n uploading: z.boolean(),\n /** Error message from the last failed upload attempt, or null. */\n error: z.string().nullable(),\n onChange: z.custom<(file: File) => void>(),\n onClear: z.custom<() => void>(),\n /** Widget label override (default: \"Firm logo (optional)\"). */\n label: z.string().optional(),\n /** Body copy override below the preview thumbnail. */\n bodyText: z.string().optional(),\n})\n\nexport type LogoUploadPropsFromSchema = z.infer<typeof LogoUploadPropsSchema>\n\n// -----------------------------------------------------------------------------\n// ImageUploadFieldPropsSchema (new — no mdxui equivalent)\n//\n// ImageUploadField wraps LogoUpload for the JSON-driven form path. It owns\n// the upload state machine internally (uploading + error are local state),\n// exposing only label, description, value, and onChange to the form renderer.\n// mdxui's FileInputPropsSchema doesn't model Vercel-Blob uploads or the\n// controlled (url | null) value pattern. Proposing a Carriage-native schema.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR4-imageuploadfield\n// -----------------------------------------------------------------------------\n\n/**\n * ImageUploadFieldPropsSchema — form-renderer image-upload field.\n * Wraps LogoUpload with an internal upload state machine.\n * No mdxui equivalent. Proposed from scratch.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR4-imageuploadfield\n */\nexport const ImageUploadFieldPropsSchema = z.object({\n /** Renderer label — sourced from `OrderField.title`. */\n label: z.string(),\n /** Helper text — sourced from `OrderField.description`. */\n description: z.string().optional(),\n /** Current value (resolved Vercel-Blob URL, or null). */\n value: z.string().nullable(),\n /** Called with the new URL after a successful upload, or null on clear. */\n onChange: z.custom<(url: string | null) => void>(),\n})\n\nexport type ImageUploadFieldPropsFromSchema = z.infer<typeof ImageUploadFieldPropsSchema>\n\n// =============================================================================\n// PR 5 extensions — Tier 2 component prop reframes\n// =============================================================================\n\n// -----------------------------------------------------------------------------\n// ServiceFormPropsSchema\n//\n// ServiceForm is the chassis-driven intake form. Its prop interface merges\n// two already-registered shapes (OrderShape + Pricing) with per-page display\n// copy (formHeadline, formIntro, productName, paymentHeadline). mdxui has no\n// multi-step service-intake form schema. Proposing ServiceFormPropsSchema as\n// the canonical shape for service-intake form chrome, wrapping OrderShape and\n// Pricing as sub-shapes.\n//\n// OrderShape (§PR2-order) + PricingPropsExtended (§PR3-pricing) are already\n// in the extension registry. ServiceFormPropsSchema composes them + adds the\n// form-chrome copy fields that the page layer passes down.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR5-serviceform\n// -----------------------------------------------------------------------------\n\n/**\n * ServiceFormPropsSchema — chassis service-intake form component props.\n * Composes OrderShapeSchema + PricingPropsExtendedSchema with page-chrome copy.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR5-serviceform\n */\n/**\n * Section-chrome shared by every Pricing variant.\n * Mirrors `PricingSectionChrome` from `@/chassis/types`.\n */\nconst PricingSectionChromeSchema = z.object({\n eyebrow: z.string(),\n heading: z.string(),\n footnote: z.string().optional(),\n currency: z.enum(['usd', 'eur', 'gbp']),\n})\n\n/**\n * Tiered pricing variant — mirrors `PricingTiered` from `@/chassis/types`.\n */\nconst PricingTieredSchema = PricingSectionChromeSchema.extend({\n kind: z.literal('tiered'),\n tiers: z.array(PriceTierSchema).readonly(),\n})\n\n/**\n * Unit pricing variant — mirrors `PricingUnit` from `@/chassis/types`.\n */\nconst PricingUnitSchema = PricingSectionChromeSchema.extend({\n kind: z.literal('unit'),\n perUnit: z.number(),\n billingCadence: z.string(),\n})\n\n/**\n * Full Pricing discriminated union — mirrors `Pricing` from `@/chassis/types`.\n */\nexport const PricingSchema = z.union([PricingTieredSchema, PricingUnitSchema])\n\n/** Full Pricing discriminated union — the `ReportPricing` component reads this. */\nexport type Pricing = z.infer<typeof PricingSchema>\n\nexport const ServiceFormPropsSchema = z.object({\n /** Service slug — used in the `/api/checkout` body + return-URL construction. */\n slug: z.string(),\n /** Derived order shape from `deriveOrder(svc)`. */\n order: OrderShapeSchema,\n /** Service pricing — from `ServiceDefinition.pricing`. Mirrors the `Pricing` union. */\n pricing: PricingSchema,\n /** Form-phase headline (h1 above the fields). Optional — omit in unit tests. */\n formHeadline: z.string().optional(),\n /** Form-phase intro paragraph. Optional. */\n formIntro: z.string().optional(),\n /** Product-name eyebrow (e.g. \"Carriage Donation\") rendered above the h1. */\n productName: z.string().optional(),\n /** Payment-phase h1. Defaults to \"Generate your report\" when unset. */\n paymentHeadline: z.string().optional(),\n})\n\nexport type ServiceFormPropsFromSchema = z.infer<typeof ServiceFormPropsSchema>\n\n// -----------------------------------------------------------------------------\n// CheckoutPanelPropsSchema\n//\n// CheckoutPanel wraps Stripe Elements for Carriage's design tokens. mdxui has\n// no Stripe/payment abstraction — this is a Carriage-native from-scratch schema.\n// The shape is minimal: clientSecret + amountCents are required (the Stripe\n// session data); email, returnUrl, onSuccess, ctaSuffix, onCancel are the\n// caller-controlled options.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR5-checkoutpanel\n// -----------------------------------------------------------------------------\n\n/**\n * CheckoutPanelPropsSchema — Stripe Elements payment panel props.\n * No mdxui equivalent. Proposed from scratch.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR5-checkoutpanel\n */\nexport const CheckoutPanelPropsSchema = z.object({\n /** Stripe PaymentIntent client secret from /api/checkout. */\n clientSecret: z.string(),\n /** Payment amount in cents — displayed as \"Pay $X.XX & {ctaSuffix}\". */\n amountCents: z.number(),\n /** Email pre-fill passed to Stripe as receipt email. */\n email: z.string().optional(),\n /** Where Stripe redirects after a successful payment (redirect flow). */\n returnUrl: z.string().optional(),\n /** Optional inline-confirmation callback (inline flow — bulk products). */\n onSuccess: z.custom<() => Promise<void> | void>().optional(),\n /** Custom CTA suffix on the Pay button. Default: \"generate report\". */\n ctaSuffix: z.string().optional(),\n /** \"Edit details\" callback — re-shows the form. */\n onCancel: z.custom<() => void>(),\n})\n\nexport type CheckoutPanelPropsFromSchema = z.infer<typeof CheckoutPanelPropsSchema>\n\n// =============================================================================\n// PR 6 extensions — ReactNode-prop components\n// =============================================================================\n//\n// Components in this section carry `React.ReactNode` props (bullets[],\n// body, cta). Zod can't validate ReactNode contents at runtime, but\n// `z.custom<ReactNode>()` in Zod v4 preserves the correct TypeScript type\n// in `z.infer<...>` (the type param O flows through `ZodCustom<O, O>`).\n// Runtime validation is intentionally a no-op for these fields — the value\n// is: auditability (every Carriage component prop has a schema entry) and\n// type-level correctness (z.infer produces the same shape as the component\n// interface).\n//\n// See upstream-proposals.md §PR6-defensibility, §PR6-upsell.\n\n// -----------------------------------------------------------------------------\n// DefensibilityPropsSchema\n//\n// Defensibility renders a 2-column \"what it is / what it isn't\" block with\n// optional caveat. Its `bullets: ReactNode[]` and `caveat?: ReactNode` props\n// were deferred in PR 5 because Zod can't validate ReactNode arrays. Reframed\n// here using `z.custom<React.ReactNode>()` which satisfies the type-level\n// contract while treating runtime validation as pass-through.\n//\n// In practice, Carriage's service JSONs pass `string[]` as bullets — the\n// ReactNode type is load-bearing only for future rich-content upgrades (e.g.,\n// bullets with inline <strong> tags). The schema allows that upgrade path.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR6-defensibility\n// -----------------------------------------------------------------------------\n\n/** One column in a Defensibility two-up.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR6-defensibility */\nexport const DefensibilityColumnSchema = z.object({\n heading: z.string(),\n /** Array of bullet content. Each bullet is a ReactNode — strings in\n * practice today; rich content possible in future JSON upgrades. */\n bullets: z.array(z.custom<React.ReactNode>()),\n})\n\nexport type DefensibilityColumnFromSchema = z.infer<typeof DefensibilityColumnSchema>\n\n/**\n * DefensibilityPropsSchema — two-column scope-expectations block.\n * No mdxui equivalent. Proposed from scratch.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR6-defensibility\n */\nexport const DefensibilityPropsSchema = z.object({\n eyebrow: z.string(),\n heading: z.string(),\n /** Tuple of exactly two columns (left = \"what it is\", right = \"what it isn't\"). */\n columns: z.tuple([DefensibilityColumnSchema, DefensibilityColumnSchema]),\n /** Optional closing caveat paragraph. */\n caveat: z.custom<React.ReactNode>().optional(),\n})\n\nexport type DefensibilityPropsFromSchema = z.infer<typeof DefensibilityPropsSchema>\n\n// -----------------------------------------------------------------------------\n// UpsellBannerPropsSchema / UpsellCardPropsSchema\n//\n// UpsellBanner + UpsellCard are client-side upsell primitives. Both expose\n// `React.ReactNode` props: UpsellBanner.cta is a ReactNode (allows inline\n// price display like \"$29 → $99\"); UpsellCard.body is a ReactNode.\n// Both use `z.custom<ReactNode>()` for the same reasons as Defensibility above.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR6-upsell\n// -----------------------------------------------------------------------------\n\n/**\n * UpsellBannerPropsSchema — single-line upsell nudge component props.\n * No mdxui equivalent. Proposed from scratch.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR6-upsell\n */\nexport const UpsellBannerPropsSchema = z.object({\n /** Display-serif hook line. Often phrased as a question. */\n headline: z.string(),\n /** Optional one-line explanation below the headline. */\n body: z.string().optional(),\n /** Activation pill content — ReactNode for inline price transitions. */\n cta: z.custom<React.ReactNode>(),\n onActivate: z.custom<() => void>(),\n})\n\nexport type UpsellBannerPropsFromSchema = z.infer<typeof UpsellBannerPropsSchema>\n\n/**\n * UpsellCardPropsSchema — richer upsell card with body paragraph.\n * No mdxui equivalent. Proposed from scratch.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR6-upsell\n */\nexport const UpsellCardPropsSchema = z.object({\n eyebrow: z.string(),\n /** Card body — ReactNode for future rich-text upgrades. */\n body: z.custom<React.ReactNode>(),\n ctaLabel: z.string(),\n onActivate: z.custom<() => void>(),\n})\n\nexport type UpsellCardPropsFromSchema = z.infer<typeof UpsellCardPropsSchema>\n\n// =============================================================================\n// PR 7 extensions — landing route wire-up\n// =============================================================================\n//\n// These additions widen CatalogShapeSchema to carry everything the\n// /[slug]/page.tsx landing route needs from a ServiceDefinition:\n//\n// publicCopy — all landing-page section props (Hero, Problem, WhatYouGet,\n// HowItWorks, Defensibility, Faq, FinalCta, SEO metadata)\n// branding — product name + hero glyph + brand colours\n// pricing — tiered pricing (section chrome + tiers)\n// archetype — service archetype id (drives MIME / totalTime defaults)\n//\n// Why CatalogShape and not a new top-level shape:\n// CatalogShape is the derive layer's output for the landing surface; it is\n// the natural home for \"everything the landing page needs\". Widening it here\n// keeps the 1:1 mapping: deriveCatalog → landing page props, no intermediate.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n// =============================================================================\n\n// -----------------------------------------------------------------------------\n// CtaSchema — shared label+href action\n//\n// Reuses SiteActionSchema's shape but without the `external` flag since\n// header/footer CTAs are always internal navigation.\n// -----------------------------------------------------------------------------\n\n/**\n * Inline call-to-action used by header/footer chrome.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n */\nexport const CtaSchema = z.object({\n label: z.string(),\n href: z.string(),\n})\n\nexport type Cta = z.infer<typeof CtaSchema>\n\n// -----------------------------------------------------------------------------\n// BreadcrumbSchema\n// -----------------------------------------------------------------------------\n\n/**\n * One breadcrumb entry for the landing-page JSON-LD BreadcrumbList.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n */\nexport const BreadcrumbSchema = z.object({\n name: z.string(),\n href: z.string(),\n})\n\nexport type Breadcrumb = z.infer<typeof BreadcrumbSchema>\n\n// -----------------------------------------------------------------------------\n// ServiceSchemaSpecSchema — static JSON-LD Service fields\n// -----------------------------------------------------------------------------\n\n/**\n * Static fields for the Service JSON-LD block. Dynamic fields (description,\n * offers) are filled at render time.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n */\nexport const ServiceSchemaSpecSchema = z.object({\n name: z.string(),\n serviceType: z.string(),\n url: z.string(),\n areaServed: z.string(),\n})\n\nexport type ServiceSchemaSpec = z.infer<typeof ServiceSchemaSpecSchema>\n\n// -----------------------------------------------------------------------------\n// ProblemPropsSchema — three-card problem section\n//\n// mdxui has no \"problem framing\" section schema. The section renders three\n// cards with a category label, cost line, outcome verdict, and body paragraph.\n// Proposing ProblemPropsSchema to mdxui.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n// -----------------------------------------------------------------------------\n\n/** One problem card.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening */\nexport const ProblemItemSchema = z.object({\n label: z.string(),\n cost: z.string(),\n outcome: z.string(),\n body: z.string(),\n})\n\nexport type ProblemItem = z.infer<typeof ProblemItemSchema>\n\n/**\n * ProblemPropsSchema — three-card problem-framing section.\n * No mdxui equivalent. Proposed from scratch.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n */\nexport const ProblemPropsSchema = z.object({\n eyebrow: z.string(),\n heading: z.string(),\n items: z.array(ProblemItemSchema),\n})\n\nexport type ProblemProps = z.infer<typeof ProblemPropsSchema>\n\n// -----------------------------------------------------------------------------\n// ServiceBrandingSchema — product name + hero glyph + brand colours\n//\n// The fields needed by the landing route from ServiceDefinition.branding.\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n// -----------------------------------------------------------------------------\n\n/**\n * Subset of ServiceBranding needed by the landing route.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n */\nexport const ServiceBrandingSchema = z.object({\n primary: z.string(),\n secondary: z.string().optional(),\n productName: z.string(),\n /** SERP title default for the landing page. */\n defaultTitle: z.string(),\n /** OG/SERP description default. */\n defaultDescription: z.string(),\n heroGlyph: z.string().optional(),\n showHeroGlyph: z.boolean().optional(),\n og: z.object({ headline: z.string() }),\n})\n\nexport type ServiceBranding = z.infer<typeof ServiceBrandingSchema>\n\n// -----------------------------------------------------------------------------\n// LandingPublicCopySchema — all landing-page section props in one schema\n//\n// Composes all the section-level prop schemas already registered in this file\n// into the flat content bag that /[slug]/page.tsx consumes.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n// -----------------------------------------------------------------------------\n\n/**\n * All landing-page section content in one flat schema.\n * Corresponds to ServicePublicCopy minus the pricing sub-object (pricing lives\n * on Pricing directly as of iter 7f.2).\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n */\nexport const LandingPublicCopySchema = z.object({\n pageTitle: z.string(),\n pageDescription: z.string(),\n headerCta: CtaSchema,\n hero: HeroPropsExtendedSchema,\n problem: ProblemPropsSchema,\n whatYouGet: WhatYouGetPropsSchema,\n howItWorks: HowItWorksPropsSchema,\n defensibility: DefensibilityPropsSchema,\n faq: FaqPropsExtendedSchema,\n finalCta: FinalCtaPropsSchema,\n footerText: z.string(),\n serviceSchema: ServiceSchemaSpecSchema,\n breadcrumbs: z.array(BreadcrumbSchema).optional(),\n})\n\nexport type LandingPublicCopy = z.infer<typeof LandingPublicCopySchema>\n\n// -----------------------------------------------------------------------------\n// LandingPricingSchema — unified pricing prop bag for the landing route\n//\n// Mirrors the `Pricing` discriminated union from chassis/types.ts but as a\n// Zod schema. The landing route currently only renders `tiered` pricing, so\n// the schema validates the tiered variant's fields; `kind` is kept so the\n// route can guard against future non-tiered kinds.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n// -----------------------------------------------------------------------------\n\n/**\n * Pricing prop bag for the landing-route Pricing component.\n *\n * `eyebrow` and `heading` are optional here because test fixtures and\n * example services may carry partial pricing objects. The landing route\n * guards on `pricing.kind === 'tiered'` before rendering and reads the\n * chrome fields directly.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n */\nexport const LandingPricingSchema = z.object({\n kind: z.enum(['tiered', 'unit']),\n eyebrow: z.string(),\n heading: z.string(),\n footnote: z.string().optional(),\n currency: z.enum(['usd', 'eur', 'gbp']).optional(),\n tiers: z.array(PriceTierSchema).readonly().optional(),\n /** unit pricing fields — optional; only present when kind='unit' */\n perUnit: z.number().optional(),\n billingCadence: z.string().optional(),\n})\n\nexport type LandingPricing = z.infer<typeof LandingPricingSchema>\n\n// -----------------------------------------------------------------------------\n// ServiceArchetypeIdSchema\n// -----------------------------------------------------------------------------\n\n/**\n * ServiceArchetype $id vocabulary — the 8-member frozen set from upstream.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n */\nexport const ServiceArchetypeIdSchema = z.enum([\n 'service-archetype-document-extraction',\n 'service-archetype-data-enrichment',\n 'service-archetype-transactional-action',\n 'service-archetype-sourced-comparative-analysis',\n 'service-archetype-form-preparation',\n 'service-archetype-compliance-check',\n 'service-archetype-market-intelligence',\n 'service-archetype-communication-automation',\n])\n\nexport type ServiceArchetypeId = z.infer<typeof ServiceArchetypeIdSchema>\n\n// -----------------------------------------------------------------------------\n// CatalogShapeSchema widening (PR 7)\n//\n// CatalogShapeSchema was introduced in PR 2 with two fields: hero + pricingSummary.\n// PR 7 widens it to carry the full landing-route data so deriveCatalog(svc)\n// becomes the single call the landing route makes, replacing the split between\n// getRenderData(slug) + the legacy listings/render-data.ts bridge for absorbed\n// products.\n//\n// The widening is ADDITIVE and ALL NEW FIELDS ARE OPTIONAL — this preserves\n// backwards-compat for callers that constructed a bare CatalogShape (e.g. tests\n// and example services that only populate hero + pricingSummary).\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n// -----------------------------------------------------------------------------\n\n/**\n * CatalogShapeSchema widened for PR 7 — carries everything /[slug]/page.tsx needs.\n *\n * PR 2 fields (hero, pricingSummary) unchanged; PR 7 adds optional\n * publicCopy + branding + pricing + archetype. The landing route reads from\n * `catalogShape.publicCopy` when present; falls back to getRenderData for\n * non-absorbed products.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n */\nexport const CatalogShapeFullSchema = CatalogShapeSchema.extend({\n /** Full landing-page section copy. Present for all fully-absorbed services. */\n publicCopy: LandingPublicCopySchema.optional(),\n /** Product branding (wordmark + heroGlyph + og headline). */\n branding: ServiceBrandingSchema.optional(),\n /** Commercial pricing — section chrome + tiers. */\n pricing: LandingPricingSchema.optional(),\n /** Service archetype id — drives MIME/totalTime defaults at render time. */\n archetype: ServiceArchetypeIdSchema.optional(),\n})\n\nexport type CatalogShapeFull = z.infer<typeof CatalogShapeFullSchema>\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/schemas/index.ts"],"sourcesContent":["/**\n * @mdxui/services — the Services dialect prop contract (ADR 0003 §3).\n *\n * These Zod schemas ARE the Services dialect's public prop surface. They were\n * authored and battle-tested in carriage's `src/chassis/mdxui-bridge/extensions/`\n * (7 products + 4 example services + 26 snapshot baselines) by reframing each\n * carriage component prop interface against mdxui's nearest equivalent — every\n * `// upstream-proposal:` comment documents WHY the Services shape differs from\n * neo/mdxui's dev-first grammar. That delta IS the dialect. This package is the\n * upstream those proposals always pointed at: it promotes the shapes to a\n * published contract.\n *\n * The four base mdxui input schemas (Text/Select/RadioGroup/File) are the\n * dialect's base vocabulary for the intake-form field contract; the rest are\n * fresh Services-semantic objects. The landing narrative arc (Hero → Problem →\n * WhatYouGet → HowItWorks → Defensibility → ReportPricing → Faq → FinalCta)\n * does not depend on the mdxui input schemas.\n */\n\nimport type React from 'react'\nimport { z } from 'zod'\nimport {\n TextInputPropsSchema,\n SelectInputPropsSchema,\n RadioGroupInputPropsSchema,\n FileInputPropsSchema,\n} from 'mdxui'\n\n// =============================================================================\n// PR 2 extensions — derive* contract layer\n// =============================================================================\n\n// -----------------------------------------------------------------------------\n// CatalogShapeSchema\n//\n// Zod-validated form of Carriage's `CatalogShape` (the \"browse\" surface\n// that deriveCatalog produces). mdxui's LandingPagePropsSchema is a layout\n// container (`{ children: any }`) — it composes section-level schemas\n// (HeroPropsSchema, PricingPropsSchema, etc.) as children, not as a flat\n// data shape. deriveCatalog returns flat data (hero headline, pricingSummary)\n// that a renderer then maps to section-level components. The two shapes serve\n// different layers; forcing deriveCatalog's output into LandingPagePropsSchema\n// would be a meaningless structural fit.\n//\n// upstream-proposal: file against mdxui as CatalogShapeSchema alongside\n// DeliveryShapeSchema and PortalShapeSchema — all three are the Carriage-\n// proposed service-runtime data shapes that precede component rendering.\n// See docs/patterns/upstream-proposals.md §PR2-catalog (PR 5 will file this).\n// -----------------------------------------------------------------------------\n\nexport const CatalogHeroSchema = z.object({\n /** Main landing-page headline. Falls back to `service.name` when unset. */\n headline: z.string().optional(),\n /** Sub-headline. Falls back to `service.promise` when unset. */\n subheadline: z.string().optional(),\n /** Asset reference for a visual element resolved by the renderer.\n * Today Carriage uses per-product HeroGlyph SVGs keyed by slug. */\n visual: z.string().optional(),\n})\n\nexport type CatalogHero = z.infer<typeof CatalogHeroSchema>\n\n/**\n * Pricing summary hint for the catalog card. Drives which Pricing\n * layout variant the renderer selects.\n *\n * upstream-proposal: same as CatalogShapeSchema above.\n */\nexport const PricingSummarySchema = z.enum([\n 'starting-at',\n 'per-call',\n 'tier-comparison',\n 'contact-us',\n])\n\nexport type PricingSummary = z.infer<typeof PricingSummarySchema>\n\n/**\n * Browse-side catalog UI shape. Produced by deriveCatalog(svc).\n *\n * upstream-proposal: file against mdxui — see\n * docs/patterns/upstream-proposals.md §PR2-catalog.\n * The shape is the data layer; LandingPagePropsSchema (already in mdxui)\n * is the layout layer. Proposing CatalogShapeSchema as the data contract\n * that feeds the layout.\n */\nexport const CatalogShapeSchema = z.object({\n hero: CatalogHeroSchema.optional(),\n pricingSummary: PricingSummarySchema,\n})\n\nexport type CatalogShape = z.infer<typeof CatalogShapeSchema>\n\n// -----------------------------------------------------------------------------\n// Input field schemas with `source` made optional\n//\n// mdxui's BaseInputPropsSchema requires `source: string` (the\n// ReactAdmin/Platform.do data-binding field path). Carriage's form renderer\n// uses `name` (the JSON-schema property key) for data binding — `source` is\n// not applicable to the derive-layer output. We extend each input schema to\n// make `source` optional so derivOrder's field objects can conform without\n// carrying a meaningless value.\n//\n// upstream-proposal: file against mdxui — source should be optional (or moved\n// to a separate ReactAdmin-specific extension) since non-ReactAdmin consumers\n// don't use it. See docs/patterns/upstream-proposals.md §PR2-source-optional.\n// -----------------------------------------------------------------------------\n\n/**\n * TextInputPropsSchema with `source` optional.\n * Used for string fields without enum (plain text, email, date, etc.)\n */\nexport const TextInputSchema = TextInputPropsSchema.extend({\n source: z.string().optional(),\n})\n\nexport type TextInput = z.infer<typeof TextInputSchema>\n\n/**\n * SelectInputPropsSchema with `source` optional.\n * Used for string/number fields with `enum` constraint.\n */\nexport const SelectInputSchema = SelectInputPropsSchema.extend({\n source: z.string().optional(),\n})\n\nexport type SelectInput = z.infer<typeof SelectInputSchema>\n\n/**\n * RadioGroupInputPropsSchema with `source` optional.\n * Used for string/number fields with enum + `options` (rich label/sub display).\n */\nexport const RadioGroupInputSchema = RadioGroupInputPropsSchema.extend({\n source: z.string().optional(),\n})\n\nexport type RadioGroupInput = z.infer<typeof RadioGroupInputSchema>\n\n/**\n * FileInputPropsSchema with `source` optional.\n * Used for fields with `widget: 'image-upload'` or `format: 'uri'` + upload widget.\n */\nexport const FileInputSchema = FileInputPropsSchema.extend({\n source: z.string().optional(),\n})\n\nexport type FileInput = z.infer<typeof FileInputSchema>\n\n// -----------------------------------------------------------------------------\n// OrderShapeSchema\n//\n// Zod-validated form of Carriage's `OrderShape` (the \"buy / form\" surface\n// that deriveOrder produces). The individual field entries are validated at\n// the TEST layer against the dispatched input schemas (TextInputSchema,\n// SelectInputSchema, etc.) by widget kind — that validation is runtime-\n// contextual and lives in derive.mdxui-contract.test.ts.\n//\n// upstream-proposal: file against mdxui as OrderShapeSchema alongside\n// CatalogShapeSchema, DeliveryShapeSchema, and PortalShapeSchema.\n// See docs/patterns/upstream-proposals.md §PR2-order (PR 5 will file this).\n// -----------------------------------------------------------------------------\n\nexport const OrderFlowSchema = z.enum([\n 'instant',\n 'guided',\n 'consultation-first',\n])\n\nexport type OrderFlow = z.infer<typeof OrderFlowSchema>\n\n/**\n * One field in an order step — the data representation used by the\n * form renderer.\n *\n * upstream-proposal: same as OrderShapeSchema above.\n */\nexport const OrderFieldSchema = z.object({\n name: z.string(),\n type: z.enum(['string', 'number', 'integer', 'boolean']),\n required: z.boolean(),\n title: z.string().optional(),\n description: z.string().optional(),\n enum: z.array(z.union([z.string(), z.number(), z.boolean()])).readonly().optional(),\n pattern: z.string().optional(),\n format: z.enum(['date', 'date-time', 'email', 'uri']).optional(),\n minimum: z.number().optional(),\n maximum: z.number().optional(),\n widget: z.enum(['vin-decoder', 'image-upload']).optional(),\n row: z.number().optional(),\n placeholder: z.string().optional(),\n autocomplete: z.string().optional(),\n options: z.array(z.object({\n value: z.union([z.string(), z.number(), z.boolean()]),\n label: z.string().optional(),\n sub: z.string().optional(),\n })).readonly().optional(),\n tiers: z.array(z.string()).readonly().optional(),\n /** Phase 1b multi-substrate (Carriage Iter / master 2026-05-26):\n * forwarded from JSON Schema's `x-connect` vendor annotation. When\n * set, the chassis form renders `<ConnectFlow>` instead of a\n * TextField. upstream-proposal: §PR11-theme + §x-connect. */\n xConnect: z.object({\n providerId: z.string(),\n resourceType: z.enum([\n 'channel',\n 'crm-record',\n 'sequence',\n 'phone-number',\n 'voice-line',\n 'webhook-event',\n 'database-table',\n 'folder',\n 'mailbox',\n 'account',\n ]),\n }).optional(),\n /** Phase 1b multi-substrate: forwarded from JSON Schema's\n * `x-derived-from` vendor annotation. When set, the chassis form\n * suppresses input UI and auto-populates from connection metadata.\n * upstream-proposal: §PR11-theme + §x-derived-from. */\n xDerivedFrom: z.object({\n providerId: z.string(),\n metadataKey: z.string(),\n }).optional(),\n})\n\nexport type OrderField = z.infer<typeof OrderFieldSchema>\n\nexport const OrderGroupSchema = z.object({\n id: z.string(),\n title: z.string(),\n description: z.string().optional(),\n fields: z.array(OrderFieldSchema).readonly(),\n})\n\nexport type OrderGroup = z.infer<typeof OrderGroupSchema>\n\nexport const OrderStepSchema = z.object({\n id: z.string(),\n title: z.string().optional(),\n fields: z.array(OrderFieldSchema).readonly(),\n groups: z.array(OrderGroupSchema).readonly(),\n})\n\nexport type OrderStep = z.infer<typeof OrderStepSchema>\n\nexport const OrderLegalSchema = z.object({\n termsRequired: z.boolean(),\n privacyRequired: z.boolean(),\n})\n\nexport type OrderLegal = z.infer<typeof OrderLegalSchema>\n\n/**\n * Order-side UI shape. Produced by deriveOrder(svc).\n *\n * upstream-proposal: file against mdxui — see\n * docs/patterns/upstream-proposals.md §PR2-order.\n */\nexport const OrderShapeSchema = z.object({\n flow: OrderFlowSchema,\n steps: z.array(OrderStepSchema).readonly().optional(),\n legal: OrderLegalSchema.optional(),\n})\n\nexport type OrderShape = z.infer<typeof OrderShapeSchema>\n\n// -----------------------------------------------------------------------------\n// DeliveryShapeSchema\n//\n// mdxui has no delivery-shape schema — this is a Carriage proposal.\n// Produced by deriveDelivery(svc). Covers the post-checkout UX archetype,\n// preview mode, and optional SLA fields.\n//\n// upstream-proposal: file against mdxui as DeliveryShapeSchema. Covers the\n// \"what the buyer sees after payment\" surface — document download, async-batch\n// status, and sync-result-card. See docs/patterns/upstream-proposals.md\n// §PR2-delivery.\n// -----------------------------------------------------------------------------\n\n/**\n * Post-checkout UX archetype.\n *\n * sync-result-card — synchronous return, inline card\n * document-download — file deliverable + email link\n * async-batch-status — job-queue with polling status; download on completion\n */\nexport const DeliveryUxSchema = z.enum([\n 'sync-result-card',\n 'document-download',\n 'async-batch-status',\n])\n\nexport type DeliveryUx = z.infer<typeof DeliveryUxSchema>\n\n/**\n * Preview mode for the delivery surface.\n *\n * first-page — rendered PDF first page\n * first-row — first N rows of a spreadsheet\n * inline-summary — one-line text summary in the result card\n * none — no preview\n */\nexport const PreviewModeSchema = z.enum([\n 'first-page',\n 'first-row',\n 'inline-summary',\n 'none',\n])\n\nexport type PreviewMode = z.infer<typeof PreviewModeSchema>\n\n/**\n * Delivery-side UI shape. Produced by deriveDelivery(svc).\n *\n * upstream-proposal: file against mdxui — see\n * docs/patterns/upstream-proposals.md §PR2-delivery.\n */\nexport const DeliveryShapeSchema = z.object({\n ux: DeliveryUxSchema,\n previewMode: PreviewModeSchema,\n /** Whether to show a step-by-step progress timeline while the cascade runs. */\n progressTimeline: z.boolean(),\n /** Optional SLA echo — ISO 8601 duration (e.g. \"PT2M\"). */\n estimatedDelivery: z.string().optional(),\n /** Optional outcome predicate lifted from outcomeContract. */\n outcomePredicate: z.string().optional(),\n})\n\nexport type DeliveryShape = z.infer<typeof DeliveryShapeSchema>\n\n// -----------------------------------------------------------------------------\n// PortalShapeSchema\n//\n// mdxui has no portal-shape schema — this is a Carriage proposal.\n// Produced by derivePortal(svc). Covers the order-management table surface:\n// column set, filters, and row actions.\n//\n// upstream-proposal: file against mdxui as PortalShapeSchema. Covers the\n// operator/admin \"manage orders\" surface. See docs/patterns/upstream-proposals.md\n// §PR2-portal.\n// -----------------------------------------------------------------------------\n\n/**\n * Column type vocabulary for the portal table renderer.\n *\n * upstream-proposal: same as PortalShapeSchema above.\n */\nexport const PortalColumnTypeSchema = z.enum([\n 'identifier',\n 'timestamp',\n 'currency',\n 'duration',\n 'status',\n 'text',\n 'evaluator',\n])\n\nexport type PortalColumnType = z.infer<typeof PortalColumnTypeSchema>\n\nexport const PortalColumnSchema = z.object({\n id: z.string(),\n label: z.string(),\n type: PortalColumnTypeSchema,\n})\n\nexport type PortalColumn = z.infer<typeof PortalColumnSchema>\n\n/**\n * Row action vocabulary for the portal table renderer.\n *\n * upstream-proposal: same as PortalShapeSchema above.\n */\nexport const PortalActionKindSchema = z.enum([\n 'view-deliverable',\n 'reissue',\n 'refund',\n 'flag-for-review',\n])\n\nexport type PortalActionKind = z.infer<typeof PortalActionKindSchema>\n\nexport const PortalActionSchema = z.object({\n id: z.string(),\n label: z.string(),\n kind: PortalActionKindSchema,\n})\n\nexport type PortalAction = z.infer<typeof PortalActionSchema>\n\nexport const PortalFilterSchema = z.object({\n id: z.string(),\n field: z.string(),\n label: z.string(),\n})\n\nexport type PortalFilter = z.infer<typeof PortalFilterSchema>\n\n/**\n * Order-management UI shape. Produced by derivePortal(svc).\n *\n * upstream-proposal: file against mdxui — see\n * docs/patterns/upstream-proposals.md §PR2-portal.\n */\nexport const PortalShapeSchema = z.object({\n columns: z.array(PortalColumnSchema),\n filters: z.array(PortalFilterSchema).optional(),\n actions: z.array(PortalActionSchema).optional(),\n})\n\nexport type PortalShape = z.infer<typeof PortalShapeSchema>\n\n// =============================================================================\n// PR 3 extensions — Tier 1 component reframe\n// =============================================================================\n\n// -----------------------------------------------------------------------------\n// HeroPropsSchema extension\n//\n// mdxui's HeroPropsSchema uses `title` (string), `badge` (string), and\n// `callToAction` (string label only — no href). Carriage's Hero component uses:\n// - `eyebrow` (small uppercase label above the headline)\n// - `headline` (the h1 — distinct from mdxui's `title`)\n// - `body` (body paragraph — mdxui has `subtitle` but that's a sub-head, not prose)\n// - `primary` / `secondary` (action objects with `label` + `href` + `external`)\n// - `showGlyph` / `illustration` (presentational controls; no mdxui equivalent)\n//\n// mdxui's `actions.primary` accepts a string or `{ href, onClick, target }` —\n// Carriage's action object has `label` (string) + `href` + `external` (bool).\n// The shapes are structurally incompatible without adapter work. Extending here.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR3-hero\n// -----------------------------------------------------------------------------\n\n/** Inline action with label + href + optional new-tab flag.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-hero */\nexport const SiteActionSchema = z.object({\n label: z.string(),\n href: z.string(),\n external: z.boolean().optional(),\n})\n\nexport type SiteAction = z.infer<typeof SiteActionSchema>\n\n/**\n * Hero composition variant identifier. Drives the dispatcher in\n * `<Hero>` (chassis/components/landing/Hero.tsx) between `HeroSplit`\n * (default) and `HeroStacked`.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR12-hero-variant\n * (master 2026-05-26 — illustration abstraction Phase 3; see\n * docs/abstraction/illustrations.md §1.4 + §3).\n */\nexport const HeroVariantSchema = z.enum([\n 'split-illustration-right',\n 'stacked-illustration-below',\n])\n\nexport type HeroVariantFromSchema = z.infer<typeof HeroVariantSchema>\n\n/**\n * HeroPropsSchema extended for Carriage's landing-page Hero component.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-hero\n */\nexport const HeroPropsExtendedSchema = z.object({\n eyebrow: z.string(),\n headline: z.string(),\n body: z.string(),\n primary: SiteActionSchema,\n secondary: SiteActionSchema.optional(),\n showGlyph: z.boolean().optional(),\n /** When true, the glyph also renders below `lg` (stacked beneath\n * the hero text on mobile). When false (default), the glyph is\n * hidden below `lg`. Services opt in via `publicCopy.hero.glyphOnMobile`.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR11-theme */\n glyphOnMobile: z.boolean().optional(),\n illustration: z.any().optional(),\n /** Hero composition variant. Routes the `<Hero>` dispatcher to\n * `HeroSplit` (default) or `HeroStacked`. Sourced from\n * `ServiceDefinition.branding.heroVariant`.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR12-hero-variant */\n variant: HeroVariantSchema.optional(),\n})\n\nexport type HeroPropsExtended = z.infer<typeof HeroPropsExtendedSchema>\n\n// -----------------------------------------------------------------------------\n// PricingPropsSchema extension\n//\n// mdxui's PricingTierSchema uses `name` (Carriage uses `tier`), `callToAction`\n// as a plain string (Carriage uses `cta: { label, href }`), and `highlighted`\n// (Carriage uses `featured`). Carriage's tier also carries Stripe commerce\n// fields (`tierKey`, `sku`, `amountCents`, `currency`, `stripeName`) and a\n// distinct `audience` sub-headline. mdxui has no commerce fields — Carriage\n// adds them as the proposing substrate.\n//\n// mdxui's PricingPropsSchema also uses `title` not `eyebrow`/`heading`.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR3-pricing\n// -----------------------------------------------------------------------------\n\n/** One pricing tier with Stripe commerce fields.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-pricing */\nexport const PriceTierSchema = z.object({\n tierKey: z.string(),\n tier: z.string(),\n price: z.string(),\n audience: z.string(),\n features: z.array(z.string()),\n featured: z.boolean().optional(),\n cta: z.object({ label: z.string(), href: z.string() }),\n sku: z.string(),\n amountCents: z.number(),\n currency: z.enum(['usd', 'eur', 'gbp']),\n stripeName: z.string(),\n minimumAmountCents: z.number().optional(),\n priceSuffix: z.string().optional(),\n})\n\nexport type PriceTier = z.infer<typeof PriceTierSchema>\n\n/**\n * PricingPropsSchema extended for Carriage's Pricing component.\n *\n * `tiers` uses `.readonly()` (Zod v4+) so `z.infer<...>` produces\n * `readonly PriceTier[]` — matching `ServiceDefinition.pricing.tiers`.\n * The `Omit<...> & { tiers: readonly PriceTier[] }` workaround in\n * `Pricing.tsx` is retired; the component interface is now\n * `z.infer<typeof PricingPropsExtendedSchema>` directly.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-pricing\n */\nexport const PricingPropsExtendedSchema = z.object({\n eyebrow: z.string(),\n heading: z.string(),\n tiers: z.array(PriceTierSchema).readonly(),\n footnote: z.string().optional(),\n})\n\nexport type PricingPropsExtended = z.infer<typeof PricingPropsExtendedSchema>\n\n// -----------------------------------------------------------------------------\n// FAQPropsSchema extension\n//\n// mdxui's FAQPropsSchema uses `title` (optional) and items with `question` /\n// `answer`. Carriage's Faq uses `eyebrow` + `heading` (both required, distinct\n// typographic roles) and items with `q` / `a` (short keys used throughout\n// publicCopy JSON). The item-field rename (question→q, answer→a) is a naming\n// convention that predates mdxui adoption; the keys appear across all service\n// JSON files. Proposing mdxui accept `q`/`a` as aliases (or Carriage migrates\n// to `question`/`answer` in a follow-up once settled with Nathan).\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR3-faq\n// -----------------------------------------------------------------------------\n\n/** FAQ item using Carriage's short-key convention (q/a).\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-faq */\nexport const FaqItemSchema = z.object({\n q: z.string(),\n a: z.string(),\n})\n\nexport type FaqItem = z.infer<typeof FaqItemSchema>\n\n/**\n * FAQPropsSchema extended for Carriage's Faq component.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-faq\n */\nexport const FaqPropsExtendedSchema = z.object({\n eyebrow: z.string(),\n heading: z.string(),\n items: z.array(FaqItemSchema),\n})\n\nexport type FaqPropsExtended = z.infer<typeof FaqPropsExtendedSchema>\n\n// -----------------------------------------------------------------------------\n// HowItWorksPropsSchema (new — no mdxui equivalent)\n//\n// mdxui has no \"how it works\" numbered-step section schema. The closest is\n// FeaturesPropsSchema (title + description + features[]) but that takes\n// description + icon + actions per feature — not a numbered-step with a\n// large display numeral. Proposing HowItWorksPropsSchema to mdxui.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR3-howitworks\n// -----------------------------------------------------------------------------\n\n/** One numbered step in a HowItWorks section.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-howitworks */\nexport const HowItWorksStepSchema = z.object({\n n: z.string(),\n title: z.string(),\n body: z.string(),\n})\n\nexport type HowItWorksStep = z.infer<typeof HowItWorksStepSchema>\n\n/**\n * Props for the HowItWorks component. No mdxui base — proposed from scratch.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-howitworks\n */\nexport const HowItWorksPropsSchema = z.object({\n eyebrow: z.string(),\n heading: z.string(),\n steps: z.array(HowItWorksStepSchema),\n /** Optional mini-illustration per step. When provided and length\n * matches `steps.length`, each step renders its illustration in\n * a row above the number. All-or-none — if length doesn't match,\n * the prop is silently ignored and the text-only layout renders\n * (per opt-in-only semantics in illustrations.md §2).\n *\n * Sourced from the per-service illustration manifest at\n * `src/services/<slug>/illustration.tsx`.\n *\n * Each element is a React `ComponentType` (zero-arg renderer).\n * Zod can't validate component identity at runtime; type-level\n * contract carries via `z.custom`.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR12-step-illustrations\n * (master 2026-05-26 — illustration abstraction Phase 4). */\n stepIllustrations: z\n .array(z.custom<React.ComponentType>())\n .optional(),\n})\n\nexport type HowItWorksProps = z.infer<typeof HowItWorksPropsSchema>\n\n// -----------------------------------------------------------------------------\n// WhatYouGetPropsSchema (new — no mdxui equivalent)\n//\n// mdxui has no \"what you get\" numbered-feature grid schema. The section\n// renders a numbered grid of deliverable sections (n + title + body) — a\n// shape distinct from FeaturesPropsSchema's icon-based list. Proposing\n// WhatYouGetPropsSchema to mdxui.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR3-whatyouget\n// -----------------------------------------------------------------------------\n\n/** One numbered item in a WhatYouGet section.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-whatyouget */\nexport const WhatYouGetItemSchema = z.object({\n n: z.string(),\n title: z.string(),\n body: z.string(),\n})\n\nexport type WhatYouGetItem = z.infer<typeof WhatYouGetItemSchema>\n\n/**\n * Props for the WhatYouGet component. No mdxui base — proposed from scratch.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-whatyouget\n */\nexport const WhatYouGetPropsSchema = z.object({\n eyebrow: z.string(),\n heading: z.string(),\n sections: z.array(WhatYouGetItemSchema),\n})\n\nexport type WhatYouGetProps = z.infer<typeof WhatYouGetPropsSchema>\n\n// -----------------------------------------------------------------------------\n// CTASectionPropsSchema extension → FinalCtaPropsSchema\n//\n// mdxui's CTASectionPropsSchema uses `title` (string) and `callToAction`\n// (string label only). Carriage's FinalCta uses `eyebrow` + `headline`\n// (both required, distinct typographic roles) and `primary`/`secondary`\n// (action objects with label + href + external). The action objects are\n// incompatible with mdxui's string `callToAction` without an adapter.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR3-finalcta\n// -----------------------------------------------------------------------------\n\n/**\n * FinalCtaPropsSchema — CTASectionPropsSchema extended for Carriage.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-finalcta\n */\nexport const FinalCtaPropsSchema = z.object({\n eyebrow: z.string(),\n headline: z.string(),\n primary: SiteActionSchema,\n secondary: SiteActionSchema.optional(),\n})\n\nexport type FinalCtaProps = z.infer<typeof FinalCtaPropsSchema>\n\n// -----------------------------------------------------------------------------\n// HeaderPropsSchema extension → MastheadPropsSchema\n//\n// mdxui's HeaderPropsSchema uses `logo` (any), `nav: NavItem[]`, `cta.text`.\n// Carriage's Masthead uses `brand: { primary, secondary?, href }` (text-based\n// brand lockup — no image logo), `cta: { label, href }` (renamed `text`→`label`),\n// `eyebrow` (right-slot fallback when no CTA), and `narrow` (container width\n// toggle). mdxui has no `eyebrow` slot or narrow-layout concept.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR3-masthead\n// -----------------------------------------------------------------------------\n\n/**\n * One masthead nav link (centered nav on `md`+, mobile dropdown below).\n * Mirrors carriage's `NavLink` (Masthead.tsx, origin/master a8700e6).\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-masthead §24\n */\nexport const NavLinkSchema = z.object({\n label: z.string(),\n href: z.string(),\n})\n\nexport type NavLink = z.infer<typeof NavLinkSchema>\n\n/**\n * MastheadPropsSchema — HeaderPropsSchema extended for Carriage's Masthead.\n *\n * carriage parity (origin/master): the masthead is a three-zone lockup — brand\n * (left, with an optional `brand.logo` to the LEFT of the wordmark, fda6fb6),\n * an optional centered nav of 3–5 page `links` (middle, `md`+ only), and the\n * right-side CTA/eyebrow. Below `md` the centered nav collapses into a hamburger\n * (`MobileNav`) that opens a dropdown overlay carrying the same links.\n *\n * The `.max(5)` link cap IS the schema/contract layer carriage lacks — carriage\n * enforces `navLinks ≤ 5` in a `verify-service` gate at the service-definition\n * level; here the contract encodes it directly.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-masthead §24\n */\nexport const MastheadPropsSchema = z.object({\n brand: z.object({\n primary: z.string(),\n secondary: z.string().optional(),\n href: z.string(),\n /** Optional brand logo, shown to the LEFT of the wordmark. With it the\n * navbar reads `[logo] <primary>`; without it the wordmark stands alone. */\n logo: z.object({ src: z.string(), alt: z.string() }).optional(),\n }),\n cta: z.object({ label: z.string(), href: z.string() }).optional(),\n /** Page links shown centered on `md`+; collapsed into the mobile dropdown\n * below `md`. 3–5 links — 5 is the hard cap (more crowds the centered nav +\n * mobile overlay). Hrefs are typically in-page section anchors\n * (`#how-it-works` / `#pricing` / `#faq`) but any route works. */\n links: z.array(NavLinkSchema).max(5).optional(),\n eyebrow: z.string().optional(),\n narrow: z.boolean().optional(),\n})\n\nexport type MastheadProps = z.infer<typeof MastheadPropsSchema>\n\n// -----------------------------------------------------------------------------\n// FooterPropsSchema extension → SiteFooterPropsSchema\n//\n// mdxui's FooterPropsSchema uses `logo` (any), `links: FooterLinkGroup[]`\n// (grouped by section title), `social[]`, `copyright`, `newsletter`. Carriage's\n// Footer is a minimal bar with a flat `text` attribution string and an optional\n// flat `links[]` (label + href only — no grouping, no social, no newsletter).\n// The structures are fundamentally different: mdxui's footer is a full-featured\n// multi-column layout; Carriage's is a single-row legal bar.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR3-footer\n// -----------------------------------------------------------------------------\n\n/** Flat footer link (no grouping).\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-footer */\nexport const SiteFooterLinkSchema = z.object({\n label: z.string(),\n href: z.string(),\n})\n\nexport type SiteFooterLink = z.infer<typeof SiteFooterLinkSchema>\n\n/**\n * SiteFooterPropsSchema — FooterPropsSchema extended for Carriage's Footer.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR3-footer\n */\nexport const SiteFooterPropsSchema = z.object({\n text: z.string(),\n links: z.array(SiteFooterLinkSchema).optional(),\n})\n\nexport type SiteFooterProps = z.infer<typeof SiteFooterPropsSchema>\n\n// =============================================================================\n// PR 4 extensions — form primitives\n// =============================================================================\n\n// -----------------------------------------------------------------------------\n// TextFieldPropsSchema\n//\n// mdxui's TextInputPropsSchema is a data-binding shape (ReactAdmin-style):\n// `source` (field path), `value`/`defaultValue` as optional, no `onChange`\n// callback. Carriage's TextField is a controlled React component:\n// `value: string` (required), `onChange: (v: string) => void` (required),\n// `type` includes 'number' and 'date' (not in mdxui's enum), `hint` (not\n// `helperText`), `inputRef` (Ref<HTMLInputElement>), `mono` and `invalid`\n// (presentational flags). The shapes are structurally incompatible for a\n// direct `.extend()` — proposing a Carriage-native schema that adopts\n// mdxui naming where possible (`label`, `placeholder`).\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR4-textfield\n// -----------------------------------------------------------------------------\n\n/**\n * TextFieldPropsSchema — controlled text-input component props.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR4-textfield\n */\nexport const TextFieldPropsSchema = z.object({\n label: z.string(),\n value: z.string(),\n onChange: z.custom<(v: string) => void>(),\n placeholder: z.string().optional(),\n /** Helper text shown below the field. `invalid=true` renders it in error colour. */\n hint: z.string().optional(),\n type: z.enum(['text', 'date', 'number', 'email']).optional(),\n /** Right-edge suffix label (e.g. \"miles\", \"%\"). */\n suffix: z.string().optional(),\n /** Renders the input in a monospace typeface (e.g. VIN, code). */\n mono: z.boolean().optional(),\n /** Renders the field in error state (red border + hint text). */\n invalid: z.boolean().optional(),\n inputRef: z.custom<React.Ref<HTMLInputElement>>().optional(),\n /** HTML `autocomplete` attribute for browser autofill. */\n autoComplete: z.string().optional(),\n})\n\nexport type TextFieldProps = z.infer<typeof TextFieldPropsSchema>\n\n// -----------------------------------------------------------------------------\n// SelectFieldPropsSchema\n//\n// mdxui's SelectInputPropsSchema is a data-binding shape: `source`, options\n// with `disabled`/`group`/`icon`/`description`, no `onChange` callback, no\n// `autoComplete`. Carriage's SelectField is a controlled dropdown:\n// `value: string` (required), `onChange: (v: string) => void` (required),\n// `options: Array<{ value: string; label: string }>` (string-only, no extras),\n// `autoComplete` for browser autofill.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR4-selectfield\n// -----------------------------------------------------------------------------\n\n/**\n * SelectFieldPropsSchema — controlled select-dropdown component props.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR4-selectfield\n */\nexport const SelectFieldPropsSchema = z.object({\n label: z.string(),\n value: z.string(),\n onChange: z.custom<(v: string) => void>(),\n options: z.array(z.object({ value: z.string(), label: z.string() })),\n /** HTML `autocomplete` attribute for browser autofill. */\n autoComplete: z.string().optional(),\n})\n\nexport type SelectFieldProps = z.infer<typeof SelectFieldPropsSchema>\n\n// -----------------------------------------------------------------------------\n// RadioGroupPropsSchema\n//\n// mdxui's RadioGroupInputPropsSchema is a data-binding shape: `source`,\n// options with `disabled`/`group`/`icon`/`description`, no `onChange`,\n// no `sub` per option. Carriage's RadioGroup is a generic controlled component:\n// the value type `T` extends `string`; options carry an optional `sub`\n// (secondary descriptor line inside the card). No mdxui equivalent for `sub`.\n// The generic `T` can't be expressed in Zod — the schema uses `z.string()` for\n// value/option value; callers narrow to `T` at the component level.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR4-radiogroup\n// -----------------------------------------------------------------------------\n\n/** One option in a RadioGroup card.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR4-radiogroup */\nexport const RadioGroupOptionSchema = z.object({\n value: z.string(),\n label: z.string(),\n /** Optional secondary descriptor line rendered inside the card. */\n sub: z.string().optional(),\n})\n\nexport type RadioGroupOption = z.infer<typeof RadioGroupOptionSchema>\n\n/**\n * RadioGroupPropsSchema — controlled radio-card-group component props.\n * Note: the generic type parameter `T extends string` from RadioGroup<T>\n * is represented as `z.string()` here; consumers narrow at call sites.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR4-radiogroup\n */\nexport const RadioGroupPropsSchema = z.object({\n label: z.string(),\n name: z.string(),\n value: z.string(),\n onChange: z.custom<(v: string) => void>(),\n options: z.array(RadioGroupOptionSchema),\n})\n\nexport type RadioGroupProps = z.infer<typeof RadioGroupPropsSchema>\n\n// -----------------------------------------------------------------------------\n// FieldRowPropsSchema (new — no mdxui equivalent)\n//\n// FieldRow is a 2-column layout shell (`display: grid; grid-template-columns:\n// 1fr 1fr`). mdxui has no layout-grid primitive for form field pairs.\n// The only prop is `children: ReactNode`. Proposing a minimal schema.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR4-fieldrow\n// -----------------------------------------------------------------------------\n\n/**\n * FieldRowPropsSchema — 2-column layout shell for side-by-side form fields.\n * No mdxui equivalent. Proposed from scratch.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR4-fieldrow\n */\nexport const FieldRowPropsSchema = z.object({\n children: z.custom<React.ReactNode>(),\n})\n\nexport type FieldRowProps = z.infer<typeof FieldRowPropsSchema>\n\n// -----------------------------------------------------------------------------\n// StepHeadingPropsSchema (new — no mdxui equivalent)\n//\n// StepHeading renders a numbered section header (index like \"01\"/\"02\",\n// eyebrow, title, body). mdxui has no multi-step form section header schema.\n// The closest mdxui primitive is HeroPropsSchema's eyebrow/headline/body\n// pattern, but HeroPropsSchema also carries CTAs and is a page-level section,\n// not a within-form step marker. Proposing StepHeadingPropsSchema as a\n// distinct lightweight schema.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR4-stepheading\n// -----------------------------------------------------------------------------\n\n/**\n * StepHeadingPropsSchema — numbered section header for multi-step flows.\n * No mdxui equivalent. Proposed from scratch.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR4-stepheading\n */\nexport const StepHeadingPropsSchema = z.object({\n /** Numeric step indicator, e.g. \"01\", \"02\". Rendered in tabular mono. */\n index: z.string(),\n /** Short action-verb eyebrow label. e.g. \"Connect\", \"Compose\". */\n eyebrow: z.string(),\n /** Primary section heading. */\n title: z.string(),\n /** Supporting body copy below the heading. */\n body: z.string(),\n className: z.string().optional(),\n})\n\nexport type StepHeadingPropsFromSchema = z.infer<typeof StepHeadingPropsSchema>\n\n// -----------------------------------------------------------------------------\n// LogoUploadPropsSchema (new — no mdxui equivalent)\n//\n// LogoUpload is a Vercel-Blob-backed logo upload widget. mdxui's\n// FileInputPropsSchema models file inputs as data-binding shapes (no\n// `uploading` state flag, no `onClear` callback, no `bodyText`). Carriage's\n// LogoUpload owns the visual preview + upload/clear/error state externally\n// (the parent form drives state; this component renders it). The shape is\n// fundamentally a controlled component with stateful flags, not a data-\n// binding primitive. Proposing LogoUploadPropsSchema as a Carriage-native\n// controlled-upload schema.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR4-logoupload\n// -----------------------------------------------------------------------------\n\n/**\n * LogoUploadPropsSchema — controlled logo-upload widget with preview.\n * No mdxui equivalent. Proposed from scratch.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR4-logoupload\n */\nexport const LogoUploadPropsSchema = z.object({\n /** Resolved Vercel-Blob URL, or null when no logo is set. */\n value: z.string().nullable(),\n /** True while the upload network call is in-flight. */\n uploading: z.boolean(),\n /** Error message from the last failed upload attempt, or null. */\n error: z.string().nullable(),\n onChange: z.custom<(file: File) => void>(),\n onClear: z.custom<() => void>(),\n /** Widget label override (default: \"Firm logo (optional)\"). */\n label: z.string().optional(),\n /** Body copy override below the preview thumbnail. */\n bodyText: z.string().optional(),\n})\n\nexport type LogoUploadPropsFromSchema = z.infer<typeof LogoUploadPropsSchema>\n\n// -----------------------------------------------------------------------------\n// ImageUploadFieldPropsSchema (new — no mdxui equivalent)\n//\n// ImageUploadField wraps LogoUpload for the JSON-driven form path. It owns\n// the upload state machine internally (uploading + error are local state),\n// exposing only label, description, value, and onChange to the form renderer.\n// mdxui's FileInputPropsSchema doesn't model Vercel-Blob uploads or the\n// controlled (url | null) value pattern. Proposing a Carriage-native schema.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR4-imageuploadfield\n// -----------------------------------------------------------------------------\n\n/**\n * ImageUploadFieldPropsSchema — form-renderer image-upload field.\n * Wraps LogoUpload with an internal upload state machine.\n * No mdxui equivalent. Proposed from scratch.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR4-imageuploadfield\n */\nexport const ImageUploadFieldPropsSchema = z.object({\n /** Renderer label — sourced from `OrderField.title`. */\n label: z.string(),\n /** Helper text — sourced from `OrderField.description`. */\n description: z.string().optional(),\n /** Current value (resolved Vercel-Blob URL, or null). */\n value: z.string().nullable(),\n /** Called with the new URL after a successful upload, or null on clear. */\n onChange: z.custom<(url: string | null) => void>(),\n})\n\nexport type ImageUploadFieldPropsFromSchema = z.infer<typeof ImageUploadFieldPropsSchema>\n\n// =============================================================================\n// PR 5 extensions — Tier 2 component prop reframes\n// =============================================================================\n\n// -----------------------------------------------------------------------------\n// ServiceFormPropsSchema\n//\n// ServiceForm is the chassis-driven intake form. Its prop interface merges\n// two already-registered shapes (OrderShape + Pricing) with per-page display\n// copy (formHeadline, formIntro, productName, paymentHeadline). mdxui has no\n// multi-step service-intake form schema. Proposing ServiceFormPropsSchema as\n// the canonical shape for service-intake form chrome, wrapping OrderShape and\n// Pricing as sub-shapes.\n//\n// OrderShape (§PR2-order) + PricingPropsExtended (§PR3-pricing) are already\n// in the extension registry. ServiceFormPropsSchema composes them + adds the\n// form-chrome copy fields that the page layer passes down.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR5-serviceform\n// -----------------------------------------------------------------------------\n\n/**\n * ServiceFormPropsSchema — chassis service-intake form component props.\n * Composes OrderShapeSchema + PricingPropsExtendedSchema with page-chrome copy.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR5-serviceform\n */\n/**\n * Section-chrome shared by every Pricing variant.\n * Mirrors `PricingSectionChrome` from `@/chassis/types`.\n */\nconst PricingSectionChromeSchema = z.object({\n eyebrow: z.string(),\n heading: z.string(),\n footnote: z.string().optional(),\n currency: z.enum(['usd', 'eur', 'gbp']),\n})\n\n/**\n * Tiered pricing variant — mirrors `PricingTiered` from `@/chassis/types`.\n */\nconst PricingTieredSchema = PricingSectionChromeSchema.extend({\n kind: z.literal('tiered'),\n tiers: z.array(PriceTierSchema).readonly(),\n})\n\n/**\n * Unit pricing variant — mirrors `PricingUnit` from `@/chassis/types`.\n */\nconst PricingUnitSchema = PricingSectionChromeSchema.extend({\n kind: z.literal('unit'),\n perUnit: z.number(),\n billingCadence: z.string(),\n})\n\n/**\n * Full Pricing discriminated union — mirrors `Pricing` from `@/chassis/types`.\n */\nexport const PricingSchema = z.union([PricingTieredSchema, PricingUnitSchema])\n\n/** Full Pricing discriminated union — the `ReportPricing` component reads this. */\nexport type Pricing = z.infer<typeof PricingSchema>\n\nexport const ServiceFormPropsSchema = z.object({\n /** Service slug — used in the `/api/checkout` body + return-URL construction. */\n slug: z.string(),\n /** Derived order shape from `deriveOrder(svc)`. */\n order: OrderShapeSchema,\n /** Service pricing — from `ServiceDefinition.pricing`. Mirrors the `Pricing` union. */\n pricing: PricingSchema,\n /** Form-phase headline (h1 above the fields). Optional — omit in unit tests. */\n formHeadline: z.string().optional(),\n /** Form-phase intro paragraph. Optional. */\n formIntro: z.string().optional(),\n /** Product-name eyebrow (e.g. \"Carriage Donation\") rendered above the h1. */\n productName: z.string().optional(),\n /** Payment-phase h1. Defaults to \"Generate your report\" when unset. */\n paymentHeadline: z.string().optional(),\n})\n\nexport type ServiceFormPropsFromSchema = z.infer<typeof ServiceFormPropsSchema>\n\n// -----------------------------------------------------------------------------\n// CheckoutPanelPropsSchema\n//\n// CheckoutPanel wraps Stripe Elements for Carriage's design tokens. mdxui has\n// no Stripe/payment abstraction — this is a Carriage-native from-scratch schema.\n// The shape is minimal: clientSecret + amountCents are required (the Stripe\n// session data); email, returnUrl, onSuccess, ctaSuffix, onCancel are the\n// caller-controlled options.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR5-checkoutpanel\n// -----------------------------------------------------------------------------\n\n/**\n * CheckoutPanelPropsSchema — Stripe Elements payment panel props.\n * No mdxui equivalent. Proposed from scratch.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR5-checkoutpanel\n */\nexport const CheckoutPanelPropsSchema = z.object({\n /** Stripe PaymentIntent client secret from /api/checkout. */\n clientSecret: z.string(),\n /** Payment amount in cents — displayed as \"Pay $X.XX & {ctaSuffix}\". */\n amountCents: z.number(),\n /** Email pre-fill passed to Stripe as receipt email. */\n email: z.string().optional(),\n /** Where Stripe redirects after a successful payment (redirect flow). */\n returnUrl: z.string().optional(),\n /** Optional inline-confirmation callback (inline flow — bulk products). */\n onSuccess: z.custom<() => Promise<void> | void>().optional(),\n /** Custom CTA suffix on the Pay button. Default: \"generate report\". */\n ctaSuffix: z.string().optional(),\n /** \"Edit details\" callback — re-shows the form. */\n onCancel: z.custom<() => void>(),\n})\n\nexport type CheckoutPanelPropsFromSchema = z.infer<typeof CheckoutPanelPropsSchema>\n\n// =============================================================================\n// PR 6 extensions — ReactNode-prop components\n// =============================================================================\n//\n// Components in this section carry `React.ReactNode` props (bullets[],\n// body, cta). Zod can't validate ReactNode contents at runtime, but\n// `z.custom<ReactNode>()` in Zod v4 preserves the correct TypeScript type\n// in `z.infer<...>` (the type param O flows through `ZodCustom<O, O>`).\n// Runtime validation is intentionally a no-op for these fields — the value\n// is: auditability (every Carriage component prop has a schema entry) and\n// type-level correctness (z.infer produces the same shape as the component\n// interface).\n//\n// See upstream-proposals.md §PR6-defensibility, §PR6-upsell.\n\n// -----------------------------------------------------------------------------\n// DefensibilityPropsSchema\n//\n// Defensibility renders a 2-column \"what it is / what it isn't\" block with\n// optional caveat. Its `bullets: ReactNode[]` and `caveat?: ReactNode` props\n// were deferred in PR 5 because Zod can't validate ReactNode arrays. Reframed\n// here using `z.custom<React.ReactNode>()` which satisfies the type-level\n// contract while treating runtime validation as pass-through.\n//\n// In practice, Carriage's service JSONs pass `string[]` as bullets — the\n// ReactNode type is load-bearing only for future rich-content upgrades (e.g.,\n// bullets with inline <strong> tags). The schema allows that upgrade path.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR6-defensibility\n// -----------------------------------------------------------------------------\n\n/** One column in a Defensibility two-up.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR6-defensibility */\nexport const DefensibilityColumnSchema = z.object({\n heading: z.string(),\n /** Array of bullet content. Each bullet is a ReactNode — strings in\n * practice today; rich content possible in future JSON upgrades. */\n bullets: z.array(z.custom<React.ReactNode>()),\n})\n\nexport type DefensibilityColumnFromSchema = z.infer<typeof DefensibilityColumnSchema>\n\n/**\n * DefensibilityPropsSchema — two-column scope-expectations block.\n * No mdxui equivalent. Proposed from scratch.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR6-defensibility\n */\nexport const DefensibilityPropsSchema = z.object({\n eyebrow: z.string(),\n heading: z.string(),\n /** Tuple of exactly two columns (left = \"what it is\", right = \"what it isn't\"). */\n columns: z.tuple([DefensibilityColumnSchema, DefensibilityColumnSchema]),\n /** Optional closing caveat paragraph. */\n caveat: z.custom<React.ReactNode>().optional(),\n})\n\nexport type DefensibilityPropsFromSchema = z.infer<typeof DefensibilityPropsSchema>\n\n// -----------------------------------------------------------------------------\n// UpsellBannerPropsSchema / UpsellCardPropsSchema\n//\n// UpsellBanner + UpsellCard are client-side upsell primitives. Both expose\n// `React.ReactNode` props: UpsellBanner.cta is a ReactNode (allows inline\n// price display like \"$29 → $99\"); UpsellCard.body is a ReactNode.\n// Both use `z.custom<ReactNode>()` for the same reasons as Defensibility above.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR6-upsell\n// -----------------------------------------------------------------------------\n\n/**\n * UpsellBannerPropsSchema — single-line upsell nudge component props.\n * No mdxui equivalent. Proposed from scratch.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR6-upsell\n */\nexport const UpsellBannerPropsSchema = z.object({\n /** Display-serif hook line. Often phrased as a question. */\n headline: z.string(),\n /** Optional one-line explanation below the headline. */\n body: z.string().optional(),\n /** Activation pill content — ReactNode for inline price transitions. */\n cta: z.custom<React.ReactNode>(),\n onActivate: z.custom<() => void>(),\n})\n\nexport type UpsellBannerPropsFromSchema = z.infer<typeof UpsellBannerPropsSchema>\n\n/**\n * UpsellCardPropsSchema — richer upsell card with body paragraph.\n * No mdxui equivalent. Proposed from scratch.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR6-upsell\n */\nexport const UpsellCardPropsSchema = z.object({\n eyebrow: z.string(),\n /** Card body — ReactNode for future rich-text upgrades. */\n body: z.custom<React.ReactNode>(),\n ctaLabel: z.string(),\n onActivate: z.custom<() => void>(),\n})\n\nexport type UpsellCardPropsFromSchema = z.infer<typeof UpsellCardPropsSchema>\n\n// =============================================================================\n// PR 7 extensions — landing route wire-up\n// =============================================================================\n//\n// These additions widen CatalogShapeSchema to carry everything the\n// /[slug]/page.tsx landing route needs from a ServiceDefinition:\n//\n// publicCopy — all landing-page section props (Hero, Problem, WhatYouGet,\n// HowItWorks, Defensibility, Faq, FinalCta, SEO metadata)\n// branding — product name + hero glyph + brand colours\n// pricing — tiered pricing (section chrome + tiers)\n// archetype — service archetype id (drives MIME / totalTime defaults)\n//\n// Why CatalogShape and not a new top-level shape:\n// CatalogShape is the derive layer's output for the landing surface; it is\n// the natural home for \"everything the landing page needs\". Widening it here\n// keeps the 1:1 mapping: deriveCatalog → landing page props, no intermediate.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n// =============================================================================\n\n// -----------------------------------------------------------------------------\n// CtaSchema — shared label+href action\n//\n// Reuses SiteActionSchema's shape but without the `external` flag since\n// header/footer CTAs are always internal navigation.\n// -----------------------------------------------------------------------------\n\n/**\n * Inline call-to-action used by header/footer chrome.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n */\nexport const CtaSchema = z.object({\n label: z.string(),\n href: z.string(),\n})\n\nexport type Cta = z.infer<typeof CtaSchema>\n\n// -----------------------------------------------------------------------------\n// BreadcrumbSchema\n// -----------------------------------------------------------------------------\n\n/**\n * One breadcrumb entry for the landing-page JSON-LD BreadcrumbList.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n */\nexport const BreadcrumbSchema = z.object({\n name: z.string(),\n href: z.string(),\n})\n\nexport type Breadcrumb = z.infer<typeof BreadcrumbSchema>\n\n// -----------------------------------------------------------------------------\n// ServiceSchemaSpecSchema — static JSON-LD Service fields\n// -----------------------------------------------------------------------------\n\n/**\n * Static fields for the Service JSON-LD block. Dynamic fields (description,\n * offers) are filled at render time.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n */\nexport const ServiceSchemaSpecSchema = z.object({\n name: z.string(),\n serviceType: z.string(),\n url: z.string(),\n areaServed: z.string(),\n})\n\nexport type ServiceSchemaSpec = z.infer<typeof ServiceSchemaSpecSchema>\n\n// -----------------------------------------------------------------------------\n// ProblemPropsSchema — three-card problem section\n//\n// mdxui has no \"problem framing\" section schema. The section renders three\n// cards with a category label, cost line, outcome verdict, and body paragraph.\n// Proposing ProblemPropsSchema to mdxui.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n// -----------------------------------------------------------------------------\n\n/** One problem card.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening */\nexport const ProblemItemSchema = z.object({\n label: z.string(),\n cost: z.string(),\n outcome: z.string(),\n body: z.string(),\n})\n\nexport type ProblemItem = z.infer<typeof ProblemItemSchema>\n\n/**\n * ProblemPropsSchema — three-card problem-framing section.\n * No mdxui equivalent. Proposed from scratch.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n */\nexport const ProblemPropsSchema = z.object({\n eyebrow: z.string(),\n heading: z.string(),\n items: z.array(ProblemItemSchema),\n})\n\nexport type ProblemProps = z.infer<typeof ProblemPropsSchema>\n\n// -----------------------------------------------------------------------------\n// ServiceBrandingSchema — product name + hero glyph + brand colours\n//\n// The fields needed by the landing route from ServiceDefinition.branding.\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n// -----------------------------------------------------------------------------\n\n/**\n * Subset of ServiceBranding needed by the landing route.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n */\nexport const ServiceBrandingSchema = z.object({\n primary: z.string(),\n secondary: z.string().optional(),\n productName: z.string(),\n /** SERP title default for the landing page. */\n defaultTitle: z.string(),\n /** OG/SERP description default. */\n defaultDescription: z.string(),\n heroGlyph: z.string().optional(),\n showHeroGlyph: z.boolean().optional(),\n og: z.object({ headline: z.string() }),\n})\n\nexport type ServiceBranding = z.infer<typeof ServiceBrandingSchema>\n\n// -----------------------------------------------------------------------------\n// LandingPublicCopySchema — all landing-page section props in one schema\n//\n// Composes all the section-level prop schemas already registered in this file\n// into the flat content bag that /[slug]/page.tsx consumes.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n// -----------------------------------------------------------------------------\n\n/**\n * All landing-page section content in one flat schema.\n * Corresponds to ServicePublicCopy minus the pricing sub-object (pricing lives\n * on Pricing directly as of iter 7f.2).\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n */\nexport const LandingPublicCopySchema = z.object({\n pageTitle: z.string(),\n pageDescription: z.string(),\n headerCta: CtaSchema,\n hero: HeroPropsExtendedSchema,\n problem: ProblemPropsSchema,\n whatYouGet: WhatYouGetPropsSchema,\n howItWorks: HowItWorksPropsSchema,\n defensibility: DefensibilityPropsSchema,\n faq: FaqPropsExtendedSchema,\n finalCta: FinalCtaPropsSchema,\n footerText: z.string(),\n serviceSchema: ServiceSchemaSpecSchema,\n breadcrumbs: z.array(BreadcrumbSchema).optional(),\n})\n\nexport type LandingPublicCopy = z.infer<typeof LandingPublicCopySchema>\n\n// -----------------------------------------------------------------------------\n// LandingPricingSchema — unified pricing prop bag for the landing route\n//\n// Mirrors the `Pricing` discriminated union from chassis/types.ts but as a\n// Zod schema. The landing route currently only renders `tiered` pricing, so\n// the schema validates the tiered variant's fields; `kind` is kept so the\n// route can guard against future non-tiered kinds.\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n// -----------------------------------------------------------------------------\n\n/**\n * Pricing prop bag for the landing-route Pricing component.\n *\n * `eyebrow` and `heading` are optional here because test fixtures and\n * example services may carry partial pricing objects. The landing route\n * guards on `pricing.kind === 'tiered'` before rendering and reads the\n * chrome fields directly.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n */\nexport const LandingPricingSchema = z.object({\n kind: z.enum(['tiered', 'unit']),\n eyebrow: z.string(),\n heading: z.string(),\n footnote: z.string().optional(),\n currency: z.enum(['usd', 'eur', 'gbp']).optional(),\n tiers: z.array(PriceTierSchema).readonly().optional(),\n /** unit pricing fields — optional; only present when kind='unit' */\n perUnit: z.number().optional(),\n billingCadence: z.string().optional(),\n})\n\nexport type LandingPricing = z.infer<typeof LandingPricingSchema>\n\n// -----------------------------------------------------------------------------\n// ServiceArchetypeIdSchema\n// -----------------------------------------------------------------------------\n\n/**\n * ServiceArchetype $id vocabulary — the 8-member frozen set from upstream.\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n */\nexport const ServiceArchetypeIdSchema = z.enum([\n 'service-archetype-document-extraction',\n 'service-archetype-data-enrichment',\n 'service-archetype-transactional-action',\n 'service-archetype-sourced-comparative-analysis',\n 'service-archetype-form-preparation',\n 'service-archetype-compliance-check',\n 'service-archetype-market-intelligence',\n 'service-archetype-communication-automation',\n])\n\nexport type ServiceArchetypeId = z.infer<typeof ServiceArchetypeIdSchema>\n\n// -----------------------------------------------------------------------------\n// CatalogShapeSchema widening (PR 7)\n//\n// CatalogShapeSchema was introduced in PR 2 with two fields: hero + pricingSummary.\n// PR 7 widens it to carry the full landing-route data so deriveCatalog(svc)\n// becomes the single call the landing route makes, replacing the split between\n// getRenderData(slug) + the legacy listings/render-data.ts bridge for absorbed\n// products.\n//\n// The widening is ADDITIVE and ALL NEW FIELDS ARE OPTIONAL — this preserves\n// backwards-compat for callers that constructed a bare CatalogShape (e.g. tests\n// and example services that only populate hero + pricingSummary).\n//\n// upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n// -----------------------------------------------------------------------------\n\n/**\n * CatalogShapeSchema widened for PR 7 — carries everything /[slug]/page.tsx needs.\n *\n * PR 2 fields (hero, pricingSummary) unchanged; PR 7 adds optional\n * publicCopy + branding + pricing + archetype. The landing route reads from\n * `catalogShape.publicCopy` when present; falls back to getRenderData for\n * non-absorbed products.\n *\n * upstream-proposal: docs/patterns/upstream-proposals.md §PR7-catalog-widening\n */\nexport const CatalogShapeFullSchema = CatalogShapeSchema.extend({\n /** Full landing-page section copy. Present for all fully-absorbed services. */\n publicCopy: LandingPublicCopySchema.optional(),\n /** Product branding (wordmark + heroGlyph + og headline). */\n branding: ServiceBrandingSchema.optional(),\n /** Commercial pricing — section chrome + tiers. */\n pricing: LandingPricingSchema.optional(),\n /** Service archetype id — drives MIME/totalTime defaults at render time. */\n archetype: ServiceArchetypeIdSchema.optional(),\n})\n\nexport type CatalogShapeFull = z.infer<typeof CatalogShapeFullSchema>\n"],"mappings":"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","names":[]}
|
package/dist/shared/index.d.ts
CHANGED
|
@@ -25,8 +25,14 @@ declare function SectionEyebrow({ children }: {
|
|
|
25
25
|
*/
|
|
26
26
|
interface ScrollRevealProps {
|
|
27
27
|
children: React.ReactNode;
|
|
28
|
+
/** Optional anchor id so masthead `links` can deep-link to this section.
|
|
29
|
+
* Pair with a `scroll-mt-*` className so the fixed ScrollHeader doesn't
|
|
30
|
+
* overlap the scroll target. */
|
|
31
|
+
id?: string;
|
|
32
|
+
/** Extra classes on the wrapper (e.g. `scroll-mt-24` for anchors). */
|
|
33
|
+
className?: string;
|
|
28
34
|
}
|
|
29
|
-
declare function ScrollReveal({ children }: ScrollRevealProps): react_jsx_runtime.JSX.Element;
|
|
35
|
+
declare function ScrollReveal({ id, className, children }: ScrollRevealProps): react_jsx_runtime.JSX.Element;
|
|
30
36
|
|
|
31
37
|
/**
|
|
32
38
|
* SvgInline — render a raw SVG markup string inside a sized container.
|
package/dist/shared/index.js
CHANGED
|
@@ -7,7 +7,7 @@ function SectionEyebrow({ children }) {
|
|
|
7
7
|
// src/shared/scroll-reveal.tsx
|
|
8
8
|
import { useEffect, useRef, useState } from "react";
|
|
9
9
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
10
|
-
function ScrollReveal({ children }) {
|
|
10
|
+
function ScrollReveal({ id, className, children }) {
|
|
11
11
|
const ref = useRef(null);
|
|
12
12
|
const [visible, setVisible] = useState(false);
|
|
13
13
|
useEffect(() => {
|
|
@@ -33,6 +33,8 @@ function ScrollReveal({ children }) {
|
|
|
33
33
|
"div",
|
|
34
34
|
{
|
|
35
35
|
ref,
|
|
36
|
+
id,
|
|
37
|
+
className,
|
|
36
38
|
"data-scroll-reveal": true,
|
|
37
39
|
"data-visible": visible,
|
|
38
40
|
style: {
|
package/dist/shared/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/shared/section-eyebrow.tsx","../../src/shared/scroll-reveal.tsx","../../src/shared/svg-inline.tsx"],"sourcesContent":["/** Small uppercase label that anchors a section heading. */\n\nexport function SectionEyebrow({ children }: { children: React.ReactNode }) {\n return (\n <p className=\"text-[11px] uppercase tracking-[0.18em] text-ink3\">\n {children}\n </p>\n )\n}\n","'use client'\n\nimport { useEffect, useRef, useState } from 'react'\n\n/**\n * ScrollReveal — dialect-wide scroll-driven fade-in wrapper.\n *\n * Each landing section fades in once when it enters the viewport. ONE fixed\n * duration + ONE fixed easing for every section across every service — motion\n * is package-owned, NOT theme-controllable.\n *\n * Duration + easing read from `--motion-fade-duration` +\n * `--motion-fade-easing` CSS variables (the host's globals define them; under\n * `prefers-reduced-motion: reduce` the duration token collapses to `0ms` so the\n * fade becomes instant with zero JS branching here).\n *\n * Behavior:\n * • One-shot — once `data-visible=\"true\"` flips, the observer disconnects.\n * • SSR-safe — if `IntersectionObserver` isn't defined, the wrapper reveals\n * immediately rather than trapping content invisible.\n * • Threshold 0.1 — section starts revealing as ~10% crosses the viewport edge.\n */\nexport interface ScrollRevealProps {\n children: React.ReactNode\n}\n\nexport function ScrollReveal({ children }: ScrollRevealProps) {\n const ref = useRef<HTMLDivElement>(null)\n const [visible, setVisible] = useState(false)\n\n useEffect(() => {\n const el = ref.current\n if (!el) return\n\n // SSR-safe fallback: in environments without IntersectionObserver,\n // reveal immediately so content isn't trapped invisible.\n if (typeof IntersectionObserver === 'undefined') {\n setVisible(true)\n return\n }\n\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (entry.isIntersecting) {\n setVisible(true)\n observer.disconnect()\n }\n },\n { threshold: 0.1 },\n )\n\n observer.observe(el)\n return () => observer.disconnect()\n }, [])\n\n return (\n <div\n ref={ref}\n data-scroll-reveal\n data-visible={visible}\n style={{\n opacity: visible ? 1 : 0,\n transition:\n 'opacity var(--motion-fade-duration) var(--motion-fade-easing)',\n }}\n >\n {children}\n </div>\n )\n}\n","/**\n * SvgInline — render a raw SVG markup string inside a sized container.\n *\n * Used to consume `ServiceBranding.heroGlyph` — JSON-driven services author\n * their hero illustration as an inline SVG string.\n *\n * Trust model: the SVG markup originates from a service-definition JSON file\n * authored by the service generator or a human at absorption time. It is NOT\n * untrusted user input; treat it as trusted asset content rendered via\n * `dangerouslySetInnerHTML`.\n *\n * Authoring rules (enforced at JSON-write time, not runtime):\n * - Single `<svg>` root element with a `viewBox` attribute.\n * - No `<script>` tags, no event handlers, no external references.\n * - Use theme tokens (`oklch(var(--accent))`, `oklch(var(--ink3) / 0.55)`,\n * etc.) for stroke + fill — the glyph picks up the current theme.\n */\n\nexport interface SvgInlineProps {\n /** Raw SVG markup (`<svg>...</svg>`). */\n svg: string\n}\n\nexport function SvgInline({ svg }: SvgInlineProps) {\n return (\n <div\n className=\"h-auto w-full\"\n // eslint-disable-next-line react/no-danger\n dangerouslySetInnerHTML={{ __html: svg }}\n />\n )\n}\n"],"mappings":";AAII;AAFG,SAAS,eAAe,EAAE,SAAS,GAAkC;AAC1E,SACE,oBAAC,OAAE,WAAU,qDACV,UACH;AAEJ;;;ACNA,SAAS,WAAW,QAAQ,gBAAgB;
|
|
1
|
+
{"version":3,"sources":["../../src/shared/section-eyebrow.tsx","../../src/shared/scroll-reveal.tsx","../../src/shared/svg-inline.tsx"],"sourcesContent":["/** Small uppercase label that anchors a section heading. */\n\nexport function SectionEyebrow({ children }: { children: React.ReactNode }) {\n return (\n <p className=\"text-[11px] uppercase tracking-[0.18em] text-ink3\">\n {children}\n </p>\n )\n}\n","'use client'\n\nimport { useEffect, useRef, useState } from 'react'\n\n/**\n * ScrollReveal — dialect-wide scroll-driven fade-in wrapper.\n *\n * Each landing section fades in once when it enters the viewport. ONE fixed\n * duration + ONE fixed easing for every section across every service — motion\n * is package-owned, NOT theme-controllable.\n *\n * Duration + easing read from `--motion-fade-duration` +\n * `--motion-fade-easing` CSS variables (the host's globals define them; under\n * `prefers-reduced-motion: reduce` the duration token collapses to `0ms` so the\n * fade becomes instant with zero JS branching here).\n *\n * Behavior:\n * • One-shot — once `data-visible=\"true\"` flips, the observer disconnects.\n * • SSR-safe — if `IntersectionObserver` isn't defined, the wrapper reveals\n * immediately rather than trapping content invisible.\n * • Threshold 0.1 — section starts revealing as ~10% crosses the viewport edge.\n */\nexport interface ScrollRevealProps {\n children: React.ReactNode\n /** Optional anchor id so masthead `links` can deep-link to this section.\n * Pair with a `scroll-mt-*` className so the fixed ScrollHeader doesn't\n * overlap the scroll target. */\n id?: string\n /** Extra classes on the wrapper (e.g. `scroll-mt-24` for anchors). */\n className?: string\n}\n\nexport function ScrollReveal({ id, className, children }: ScrollRevealProps) {\n const ref = useRef<HTMLDivElement>(null)\n const [visible, setVisible] = useState(false)\n\n useEffect(() => {\n const el = ref.current\n if (!el) return\n\n // SSR-safe fallback: in environments without IntersectionObserver,\n // reveal immediately so content isn't trapped invisible.\n if (typeof IntersectionObserver === 'undefined') {\n setVisible(true)\n return\n }\n\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (entry.isIntersecting) {\n setVisible(true)\n observer.disconnect()\n }\n },\n { threshold: 0.1 },\n )\n\n observer.observe(el)\n return () => observer.disconnect()\n }, [])\n\n return (\n <div\n ref={ref}\n id={id}\n className={className}\n data-scroll-reveal\n data-visible={visible}\n style={{\n opacity: visible ? 1 : 0,\n transition:\n 'opacity var(--motion-fade-duration) var(--motion-fade-easing)',\n }}\n >\n {children}\n </div>\n )\n}\n","/**\n * SvgInline — render a raw SVG markup string inside a sized container.\n *\n * Used to consume `ServiceBranding.heroGlyph` — JSON-driven services author\n * their hero illustration as an inline SVG string.\n *\n * Trust model: the SVG markup originates from a service-definition JSON file\n * authored by the service generator or a human at absorption time. It is NOT\n * untrusted user input; treat it as trusted asset content rendered via\n * `dangerouslySetInnerHTML`.\n *\n * Authoring rules (enforced at JSON-write time, not runtime):\n * - Single `<svg>` root element with a `viewBox` attribute.\n * - No `<script>` tags, no event handlers, no external references.\n * - Use theme tokens (`oklch(var(--accent))`, `oklch(var(--ink3) / 0.55)`,\n * etc.) for stroke + fill — the glyph picks up the current theme.\n */\n\nexport interface SvgInlineProps {\n /** Raw SVG markup (`<svg>...</svg>`). */\n svg: string\n}\n\nexport function SvgInline({ svg }: SvgInlineProps) {\n return (\n <div\n className=\"h-auto w-full\"\n // eslint-disable-next-line react/no-danger\n dangerouslySetInnerHTML={{ __html: svg }}\n />\n )\n}\n"],"mappings":";AAII;AAFG,SAAS,eAAe,EAAE,SAAS,GAAkC;AAC1E,SACE,oBAAC,OAAE,WAAU,qDACV,UACH;AAEJ;;;ACNA,SAAS,WAAW,QAAQ,gBAAgB;AA4DxC,gBAAAA,YAAA;AA9BG,SAAS,aAAa,EAAE,IAAI,WAAW,SAAS,GAAsB;AAC3E,QAAM,MAAM,OAAuB,IAAI;AACvC,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAE5C,YAAU,MAAM;AACd,UAAM,KAAK,IAAI;AACf,QAAI,CAAC,GAAI;AAIT,QAAI,OAAO,yBAAyB,aAAa;AAC/C,iBAAW,IAAI;AACf;AAAA,IACF;AAEA,UAAM,WAAW,IAAI;AAAA,MACnB,CAAC,CAAC,KAAK,MAAM;AACX,YAAI,MAAM,gBAAgB;AACxB,qBAAW,IAAI;AACf,mBAAS,WAAW;AAAA,QACtB;AAAA,MACF;AAAA,MACA,EAAE,WAAW,IAAI;AAAA,IACnB;AAEA,aAAS,QAAQ,EAAE;AACnB,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,CAAC;AAEL,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA,sBAAkB;AAAA,MAClB,gBAAc;AAAA,MACd,OAAO;AAAA,QACL,SAAS,UAAU,IAAI;AAAA,QACvB,YACE;AAAA,MACJ;AAAA,MAEC;AAAA;AAAA,EACH;AAEJ;;;ACpDI,gBAAAC,YAAA;AAFG,SAAS,UAAU,EAAE,IAAI,GAAmB;AACjD,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MAEV,yBAAyB,EAAE,QAAQ,IAAI;AAAA;AAAA,EACzC;AAEJ;","names":["jsx","jsx"]}
|