{"version":3,"sources":["/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-KIQNMCOO.cjs","../src/components/faq/faq-section.tsx","../src/components/faq-accordion.tsx","../src/components/faq/json-ld.ts","../src/components/faq/faq-document-page.tsx"],"names":["useState","jsx"],"mappings":"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","file":"/home/runner/work/openframe-oss-lib/openframe-oss-lib/openframe-frontend-core/dist/chunk-KIQNMCOO.cjs","sourcesContent":[null,"'use client';\n\nimport type React from 'react';\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useScrollToHash } from '../../hooks/use-scroll-to-hash';\nimport { useSelfFetch } from '../../hooks/use-self-fetch';\nimport type { Faq } from '../../types/faq';\nimport { cn } from '../../utils/cn';\nimport { serializeJsonLd } from '../../utils/common';\nimport { faqSectionSlug, parseFaqHash, type FaqHashTarget } from '../../utils/faq-anchor';\nimport { navigateSamePageHash, STICKY_HEADER_OFFSET_PX } from '../../utils/same-page-hash-nav';\nimport { buildSuggestionUrl } from '../../utils/suggestion-url';\nimport { FaqAccordion, type FaqItem } from '../faq-accordion';\nimport { SECTION_HEADING_CLASS } from '../layout/page-heading';\nimport { buildFaqJsonLdFromFaqs, type FaqSchemaOptions } from './json-ld';\n\nexport interface FaqSectionProps {\n  /**\n   * SSR hydrate. When provided, the hook skips the first client fetch (per\n   * useSelfFetch contract). The consuming server page resolves FAQs then drills\n   * them into this prop — the lib never re-fetches what the host already gated on.\n   */\n  initialFaqs?: Faq[];\n  /** Both required together for entity-attached FAQs; partial → bare /api/faqs. */\n  entityType?: string;\n  entityId?: number | string;\n  /**\n   * Heading node above the grouped list. `undefined` → default\n   * `<h2>`\"Frequently Asked Questions\". `null` → no heading (the host page\n   * owns the `<h1>`, as the standalone /faqs surface does). A React node lets a\n   * platform drill its own <PageHeading> without the lib referencing platform\n   * state. Also drives category nesting so the document outline stays correct:\n   * `null` → categories render `<h2>` (directly under the page `<h1>`);\n   * otherwise categories render `<h3>` beneath this heading.\n   */\n  heading?: React.ReactNode | null;\n  /** Inject FAQPage schema.org JSON-LD as a <script>. Off by default so embeds\n   *  don't emit duplicate schema. */\n  emitJsonLd?: boolean;\n  /** Overrides for the JSON-LD's name/description/url. */\n  jsonLd?: FaqSchemaOptions;\n  className?: string;\n  /** Maps to /api/faqs `?count=` (the 5-tier fill target). Absent → param\n   *  not sent (server default applies). */\n  minResults?: number;\n  /** Fetch-URL prefix for third-party embeds / reverse proxies\n   *  ('' = same-origin relative). */\n  apiBaseUrl?: string;\n}\n\nconst DEFAULT_HEADING_TEXT = 'Frequently Asked Questions';\n\n/** URL composition shared with RelatedContentSection (`buildSuggestionUrl`)\n *  — byte-identical to the historical `buildFaqsUrl` output when\n *  `minResults`/`apiBaseUrl` are absent. */\nfunction buildFaqsUrl(entityType?: string, entityId?: number | string, minResults?: number, apiBaseUrl = ''): string {\n  return buildSuggestionUrl('/api/faqs', { apiBaseUrl, entityType, entityId, count: minResults });\n}\n\ninterface FaqGroup {\n  /** null → the uncategorized bucket: no heading, no jump pill, rendered last. */\n  section: string | null;\n  slug: string | null;\n  items: FaqItem[];\n}\n\n/** Group FAQs by `faq.section`, preserving the server's first-seen\n *  (display_order) order for BOTH the section order and the rows within each\n *  section. The uncategorized bucket (blank/missing section) sinks to the end\n *  since it renders without a heading. Items carry NO badge here — the `<h2>`\n *  IS the category, so a per-row chip would be redundant. */\nfunction groupFaqsBySection(faqs: Faq[]): FaqGroup[] {\n  // A Map iterates in insertion order, which is exactly the first-seen section\n  // order this function promises — so the Map IS the ordering, and no parallel\n  // array of names (plus a lookup that has to assert the key back) is needed.\n  const byName = new Map<string, FaqGroup>();\n  let uncategorized: FaqGroup | null = null;\n  for (const faq of faqs) {\n    const item: FaqItem = { id: faq.id, question: faq.question, answer: faq.answer };\n    const name = faq.section?.trim();\n    if (!name) {\n      if (!uncategorized) uncategorized = { section: null, slug: null, items: [] };\n      uncategorized.items.push(item);\n      continue;\n    }\n    let group = byName.get(name);\n    if (!group) {\n      group = { section: name, slug: faqSectionSlug(name), items: [] };\n      byName.set(name, group);\n    }\n    group.items.push(item);\n  }\n  const groups = [...byName.values()];\n  if (uncategorized) groups.push(uncategorized);\n  return groups;\n}\n\n/** Map key for the uncategorized bucket — `group.slug` is null for it, so\n *  every per-group map (default-open ids, accordion keys) uses this sentinel\n *  to keep the lookup typed. */\nconst UNCATEGORIZED_KEY = '__uncategorized__';\nconst groupKey = (g: FaqGroup): string => g.slug ?? UNCATEGORIZED_KEY;\n\n/**\n * Grouped FAQ layout: a category jump-nav above stacked `<h2>` category\n * sections (each its own accordion). Isolated into its own component so the\n * scroll-spy hooks only mount in grouped mode — `FaqSection`'s own hooks stay\n * unconditional.\n *\n * The pills are real `<a href=\"#slug\">` anchors (crawlable in-page links,\n * deep-linkable, work without JS); the click handler upgrades the jump to the\n * cancellation-proof `scrollElementIntoView` tween and syncs the URL hash.\n */\nfunction GroupedFaqList({\n  groups,\n  categoryHeadingAs,\n}: {\n  groups: FaqGroup[];\n  /** Heading tag for each category, so the document outline nests correctly\n   *  under whatever owns the heading above this block: `h2` on the standalone\n   *  page (the page owns the `<h1>`), `h3` beneath an embed's `<h2>` title.\n   *  The VISUAL is `SECTION_HEADING_CLASS` either way, so categories look\n   *  identical on every surface. */\n  categoryHeadingAs: 'h2' | 'h3';\n}) {\n  const CategoryHeading = categoryHeadingAs;\n  const navGroups = useMemo(() => groups.filter(g => g.slug), [groups]);\n  const [activeSlug, setActiveSlug] = useState<string | null>(navGroups[0]?.slug ?? null);\n  // Identity-stable key for the section set so the observer re-binds only when\n  // the categories actually change (not on every parent re-render).\n  const slugKey = navGroups.map(g => g.slug).join('|');\n  // Latest `navGroups` for the scroll-spy observer below, which re-observes on\n  // `slugKey` (the section SET) and must not re-run when the array is merely\n  // rebuilt with the same slugs.\n  const navGroupsRef = useRef(navGroups);\n  useEffect(() => {\n    navGroupsRef.current = navGroups;\n  });\n\n  // Scroll-spy: mark the pill for the category currently at the top of the\n  // viewport. rootMargin drops the trigger line just below the sticky header\n  // and ignores the bottom ~55% so \"active\" is the section being read, not the\n  // next one peeking in.\n  useEffect(() => {\n    if (navGroupsRef.current.length < 2) return undefined;\n    const tops = new Map<string, number>();\n    const observer = new IntersectionObserver(\n      entries => {\n        for (const entry of entries) {\n          const id = (entry.target as HTMLElement).id;\n          if (entry.isIntersecting) tops.set(id, entry.boundingClientRect.top);\n          else tops.delete(id);\n        }\n        let bestId: string | null = null;\n        let bestTop = Number.POSITIVE_INFINITY;\n        for (const [id, top] of tops) {\n          if (top < bestTop) {\n            bestTop = top;\n            bestId = id;\n          }\n        }\n        if (bestId) setActiveSlug(bestId);\n      },\n      { rootMargin: `-${STICKY_HEADER_OFFSET_PX}px 0px -55% 0px`, threshold: 0 },\n    );\n    for (const group of navGroupsRef.current) {\n      const el = group.slug ? document.getElementById(group.slug) : null;\n      if (el) observer.observe(el);\n    }\n    return () => observer.disconnect();\n    // slugKey encodes the section set; re-observe only when it changes.\n  }, [slugKey]);\n\n  // ─── Hash dispatch — `/faqs#faq-item-<id>` or `/faqs#faq-<section-slug>` ──\n  // Tracks the current hash so:\n  //   1. an item-kind hash seeds `defaultOpenIds` on the matching accordion\n  //      (auto-expands the cited question);\n  //   2. either kind triggers the cancellation-proof tween scroll with the\n  //      sticky-header offset (native browser hash scroll runs once, ignores\n  //      our offset — re-running the tween puts the target in the right spot).\n  // Listens to `hashchange` so back/forward replays the same behavior. SSR-\n  // safe: initial null state matches the server render; the first effect\n  // tick on the client updates it.\n  const [hashTarget, setHashTarget] = useState<FaqHashTarget | null>(null);\n  useEffect(() => {\n    const refresh = () => setHashTarget(parseFaqHash(window.location.hash));\n    refresh();\n    window.addEventListener('hashchange', refresh);\n    return () => window.removeEventListener('hashchange', refresh);\n  }, []);\n\n  // Per-group default-open set when the hash points at an item. The map key\n  // matches `groupKey(group)` so the render-time lookup is O(1) per group.\n  const defaultOpenByGroupKey = useMemo(() => {\n    if (hashTarget?.kind !== 'item') return null;\n    const targetId = hashTarget.rawId;\n    const result = new Map<string, (string | number)[]>();\n    for (const group of groups) {\n      const hit = group.items.find(i => String(i.id) === targetId);\n      if (hit) result.set(groupKey(group), [hit.id]);\n    }\n    return result.size > 0 ? result : null;\n  }, [groups, hashTarget]);\n\n  // Accordion is uncontrolled — `defaultOpenIds` is only consumed at mount,\n  // so a new item hash needs a remount to honor it. Keying off the item-id\n  // suffix triggers exactly the remount we need (and stays stable when the\n  // hash points at a section, so category navigation never disturbs the\n  // accordion's open state).\n  const accordionKeySuffix = hashTarget?.kind === 'item' ? `item:${hashTarget.rawId}` : 'default';\n\n  // Unified scroll-to-hash: rAF-polls for the target row (outlasts the SWR self-fetch\n  // + Radix accordion expand) and re-fires on `hashchange` — including the synthetic\n  // event `navigateSamePageHash` dispatches for a SOFT same-page chat-card nav (a\n  // host-router `pushState` fires no `hashchange`). The ready-dep keys off BOTH the\n  // loaded `groups` (so a deep-link / refresh scrolls once the self-fetched list\n  // mounts) AND `hashTarget` (so a soft nav re-runs the scroll AFTER the re-render\n  // that remounts + opens the cited row, landing on its FINAL expanded position\n  // instead of racing the uncontrolled accordion's key-remount — the bare-`hashchange`\n  // listener alone fires before the remount and lands on the stale closed position).\n  const scrollDep =\n    `${groups.length}|` +\n    (hashTarget?.kind === 'item'\n      ? `item:${hashTarget.rawId}`\n      : hashTarget?.kind === 'section'\n        ? `section:${hashTarget.slug}`\n        : 'none');\n  useScrollToHash(scrollDep, { headerOffset: STICKY_HEADER_OFFSET_PX });\n\n  // A section hash also lights up its category pill; item hashes leave the pills\n  // untouched so deep-linking a question never disturbs scroll-spy state.\n  //\n  // Adjusted while rendering (React's prop-sync pattern) rather than from an\n  // effect: the pills below read `activeSlug` in THIS render, so an effect\n  // painted the OLD pill lit and then re-rendered to move the highlight. The\n  // initial value matches `hashTarget`'s own initial `null`, so a mount is a\n  // no-op here exactly as the effect's first run was.\n  const [pillSyncedHash, setPillSyncedHash] = useState(hashTarget);\n  if (pillSyncedHash !== hashTarget) {\n    setPillSyncedHash(hashTarget);\n    if (hashTarget?.kind === 'section') setActiveSlug(hashTarget.slug);\n  }\n\n  // Category pill click. `navigateSamePageHash` owns the entire transition:\n  // replaceState → synthetic `hashchange` → `scrollElementIntoView` tween\n  // with `STICKY_HEADER_OFFSET_PX` so the section heading lands BELOW the\n  // sticky category nav on the FIRST tween (covers the same-target\n  // re-click case, where the `hashTarget` effect at L214 is a no-op\n  // because the state reference is equal). For DIFFERENT-target clicks\n  // the helper's synthetic `hashchange` re-fires that effect, which\n  // re-scrolls with the same offset and cancels this tween (singleton)\n  // — both paths land at the same position. The effect is still\n  // required for back/forward + direct URL edits, where the helper\n  // isn't in the call chain.\n  //\n  // `history: 'replace'` matches the pre-helper behavior: category pills\n  // are a TOC, not a navigation step, so the Back button leaves the\n  // FAQ page in one step regardless of how many categories the user\n  // clicked through.\n  const handleJump = useCallback((e: React.MouseEvent<HTMLAnchorElement>, slug: string) => {\n    e.preventDefault();\n    navigateSamePageHash('#' + slug, {\n      headerOffset: STICKY_HEADER_OFFSET_PX,\n      history: 'replace',\n    });\n  }, []);\n\n  return (\n    <div className=\"space-y-8\">\n      {navGroups.length > 1 && (\n        <nav aria-label=\"FAQ categories\" className=\"flex flex-wrap gap-2\">\n          {navGroups.map(group => {\n            const isActive = group.slug === activeSlug;\n            return (\n              <a\n                key={group.slug}\n                href={`#${group.slug}`}\n                aria-current={isActive ? 'true' : undefined}\n                onClick={e => handleJump(e, group.slug as string)}\n                className={cn(\n                  'rounded-full border px-4 py-2 transition-colors text-h6',\n                  isActive\n                    ? 'border-ods-text-primary bg-ods-card text-ods-text-primary'\n                    : 'border-ods-border bg-ods-card text-ods-text-secondary hover:border-ods-text-secondary hover:text-ods-text-primary',\n                )}\n              >\n                {group.section}\n              </a>\n            );\n          })}\n        </nav>\n      )}\n      <div className=\"space-y-10\">\n        {groups.map(group => {\n          const key = groupKey(group);\n          return (\n            <section key={key} id={group.slug ?? undefined} className=\"scroll-mt-24 space-y-4\">\n              {group.section && <CategoryHeading className={SECTION_HEADING_CLASS}>{group.section}</CategoryHeading>}\n              <FaqAccordion\n                // Re-key on item-hash changes so the remount picks up the new\n                // `defaultOpenIds` (the accordion is uncontrolled). Stable for\n                // section hashes — category navigation doesn't disturb state.\n                key={`${key}:${accordionKeySuffix}`}\n                items={group.items}\n                defaultOpenIds={defaultOpenByGroupKey?.get(key)}\n              />\n            </section>\n          );\n        })}\n      </div>\n    </div>\n  );\n}\n\nfunction FaqSkeleton() {\n  return (\n    <div className=\"animate-pulse space-y-8\">\n      <div className=\"h-12 w-2/3 rounded bg-ods-border md:h-14\" />\n      <div className=\"w-full divide-y divide-ods-border overflow-hidden rounded-md border border-ods-border bg-transparent\">\n        {Array.from({ length: 8 }).map((_, idx) => (\n          <div key={idx} className=\"flex items-center justify-between gap-6 px-6 py-4 md:gap-10\">\n            <div className=\"h-6 w-5/6 rounded bg-ods-border\" />\n            <div className=\"size-6 rounded bg-ods-border\" />\n          </div>\n        ))}\n      </div>\n    </div>\n  );\n}\n\ninterface FaqsResponse {\n  faqs: Faq[];\n}\n\n/**\n * The FAQ display surface — ONE rendering on every host: the list grouped by\n * `faq.section` (each category a heading + its own accordion, with a category\n * jump-nav once there are 2+ categories). There is no flat/ungrouped mode and\n * no page-vs-embedded shell fork; the standalone /faqs page and every embed\n * render through this single path, so they cannot drift.\n *\n * - Standalone /faqs page: pass `initialFaqs` (SSR) + `heading={null}` (the\n *   page owns the <h1>) + `emitJsonLd` with `jsonLd` overrides for SEO.\n * - Per-entity embed: pass `entityType` + `entityId` (no `initialFaqs`); the\n *   hook self-fetches `GET /api/faqs`, and `heading` is this block's own <h2>.\n *\n * CONTRACT: the consuming app MUST implement `GET /api/faqs`. On a fetch error\n * (or zero FAQs) the component renders nothing so the host page isn't\n * disfigured. The host always supplies the page shell — this renders a bare\n * <section>.\n */\nexport function FaqSection({\n  initialFaqs,\n  entityType,\n  entityId,\n  heading,\n  emitJsonLd = false,\n  jsonLd,\n  className,\n  minResults,\n  apiBaseUrl = '',\n}: FaqSectionProps) {\n  const url = buildFaqsUrl(entityType, entityId, minResults, apiBaseUrl);\n  // Memoized — useSelfFetch re-syncs on [initialData]; a fresh per-render\n  // wrapper object would setState-loop under re-rendering parents.\n  const initialData = useMemo<FaqsResponse | undefined>(\n    () => (initialFaqs ? { faqs: initialFaqs } : undefined),\n    [initialFaqs],\n  );\n  const { data, isLoading, error } = useSelfFetch<FaqsResponse>(url, { initialData });\n\n  // Memoised because the `??` fallback minted a NEW array on every\n  // render, which made the memo below re-run every time — i.e. do nothing.\n  const faqs = useMemo(() => data?.faqs ?? [], [data?.faqs]);\n  // Grouped before the early returns so the hook order stays stable.\n  const groups = useMemo(() => (faqs.length > 0 ? groupFaqsBySection(faqs) : []), [faqs]);\n\n  // `undefined` → default <h2> title; `null` → the host page owns the <h1>, so\n  // no title renders here. `heading === null` also makes the category headings\n  // <h2> (directly under the page <h1>); otherwise they nest as <h3>.\n  const headingNode =\n    heading === undefined ? <h2 className={SECTION_HEADING_CLASS}>{DEFAULT_HEADING_TEXT}</h2> : heading;\n\n  // Degrade silently — never show an error banner or an empty section shell\n  // where FAQs would be (host pages and the standalone surface both rely on it).\n  if (error) return null;\n  if (!isLoading && faqs.length === 0) return null;\n  if (isLoading && faqs.length === 0) {\n    return (\n      <div className={className}>\n        <FaqSkeleton />\n      </div>\n    );\n  }\n\n  const schema = emitJsonLd ? buildFaqJsonLdFromFaqs(faqs, jsonLd) : null;\n\n  return (\n    <>\n      <section className={className ?? 'space-y-10'}>\n        {headingNode}\n        <GroupedFaqList groups={groups} categoryHeadingAs={heading === null ? 'h2' : 'h3'} />\n      </section>\n      {schema && (\n        <script\n          type=\"application/ld+json\"\n          // serializeJsonLd, NOT raw JSON.stringify — FAQ answers are\n          // admin-entered; an embedded \"</script>\" must not break the tag.\n          dangerouslySetInnerHTML={{ __html: serializeJsonLd(schema) }}\n        />\n      )}\n    </>\n  );\n}\n","'use client';\n\nimport { useState } from 'react';\nimport { cn } from '../utils/cn';\nimport { faqItemAnchor } from '../utils/faq-anchor';\nimport { Chevron02DownIcon } from './icons-v2-generated/arrows/chevron-02-down-icon';\n\nexport interface FaqItem {\n  id: number | string;\n  question: string;\n  answer: string;\n}\n\ninterface FaqAccordionProps {\n  items: FaqItem[];\n  defaultOpenIds?: (number | string)[];\n}\n\nexport function FaqAccordion({ items, defaultOpenIds = [] }: FaqAccordionProps) {\n  const [openSet, setOpenSet] = useState<Set<string | number>>(new Set(defaultOpenIds));\n\n  const toggle = (id: string | number) => {\n    setOpenSet(prev => {\n      const next = new Set(prev);\n      if (next.has(id)) next.delete(id);\n      else next.add(id);\n      return next;\n    });\n  };\n\n  return (\n    <div className=\"divide-y divide-ods-border overflow-hidden rounded-md border border-ods-border bg-transparent\">\n      {items.map(item => {\n        const isOpen = openSet.has(item.id);\n\n        return (\n          <div\n            key={item.id}\n            // Per-row anchor — chat citation chips (`/faqs#faq-item-<id>`) land\n            // here via native browser hash scroll AND via `FaqSection`'s tween\n            // dispatch. `scroll-mt-24` keeps the row header below the 96px\n            // sticky nav offset (matches `<section>`'s scroll-margin for\n            // category anchors).\n            id={faqItemAnchor(item.id)}\n            className=\"scroll-mt-24 transition-colors hover:bg-ods-bg-hover\"\n          >\n            {/* Header */}\n            <div\n              role=\"button\"\n              tabIndex={0}\n              onClick={() => toggle(item.id)}\n              onKeyDown={e => {\n                if (e.key === 'Enter' || e.key === ' ') {\n                  e.preventDefault();\n                  toggle(item.id);\n                }\n              }}\n              aria-expanded={isOpen}\n              className=\"flex w-full cursor-pointer items-center gap-6 px-6 py-4 text-left transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ods-focus md:gap-10\"\n            >\n              <h3 className=\"min-w-0 flex-1 break-words\">{item.question}</h3>\n              <Chevron02DownIcon\n                aria-hidden=\"true\"\n                size={24}\n                className={cn(\n                  'shrink-0 text-ods-text-primary transition-transform duration-300',\n                  isOpen && 'rotate-180',\n                )}\n              />\n            </div>\n            {/* Content wrapper. Collapses with the grid 1fr->0fr transition the\n                rest of the design system uses (see AnnouncementBar) rather than\n                an animated max-height: measuring `scrollHeight` needed a hook\n                PER ROW, which meant calling hooks inside `items.map` — the hook\n                order then changed whenever `items` did. Grid needs no\n                measurement, and it animates correctly when an answer's height\n                changes after mount. */}\n            <div\n              className=\"grid transition-[grid-template-rows,opacity] duration-300 ease-in-out motion-reduce:transition-none\"\n              style={{ gridTemplateRows: isOpen ? '1fr' : '0fr', opacity: isOpen ? 1 : 0 }}\n            >\n              {/* break-words: FAQ answers render as plain text, so a long URL or\n                  token has no wrap opportunity — and the row is overflow-hidden,\n                  which would CLIP it past the viewport on mobile. Mirrors the\n                  markdown-renderer overflow-wrap fix. */}\n              <div className=\"overflow-hidden\">\n                <div className=\"break-words px-6 pb-4 text-ods-text-primary text-h4\">{item.answer}</div>\n              </div>\n            </div>\n          </div>\n        );\n      })}\n    </div>\n  );\n}\n","/**\n * Pure FAQ JSON-LD builder. No React, no client-only deps — safe to import from\n * Server Components via the `./components/faq` subpath export. (Do NOT import\n * through the root `./components` barrel — that barrel is `\"use client\"` and\n * dragging it into a Server Component would force the client graph into the\n * server.)\n *\n * The hub used to harcode `name`/`description` here for OpenMSP; in the lib we\n * accept overrides so every embedder can supply its own platform branding.\n */\nimport type { Faq } from '../../types/faq';\n\nexport interface FaqSchemaOptions {\n  name?: string;\n  description?: string;\n  url?: string;\n}\n\nconst DEFAULT_NAME = 'Frequently Asked Questions';\nconst DEFAULT_DESCRIPTION = 'Answers to common questions.';\n\nexport function baseFaqSchema(opts: FaqSchemaOptions = {}) {\n  return {\n    '@context': 'https://schema.org',\n    '@type': 'FAQPage',\n    name: opts.name ?? DEFAULT_NAME,\n    description: opts.description ?? DEFAULT_DESCRIPTION,\n    ...(opts.url ? { url: opts.url } : {}),\n  } as const;\n}\n\nexport function buildFaqJsonLdFromFaqs(faqs: Faq[], opts: FaqSchemaOptions = {}) {\n  return {\n    ...baseFaqSchema(opts),\n    mainEntity: faqs.map(faq => ({\n      '@type': 'Question',\n      name: faq.question,\n      acceptedAnswer: {\n        '@type': 'Answer',\n        text: faq.answer,\n      },\n    })),\n  } as const;\n}\n","'use client';\n\n/**\n * FaqDocumentPage — the full `/faqs` page with chrome, so embedders drop in\n * ONE component instead of hand-assembling `PageShell` + `PageLayout` around\n * the bare `<FaqSection>`. Mirrors `LegalDocumentPage` / `DevSectionPage`: the\n * page-level layout lives in the lib, the host page is a thin wrapper that\n * passes only config + the SSR-resolved data.\n *\n * HERO: the title + subtitle route through the canonical (frozen) `PageLayout`\n * `TitleBlock` with `titleSize=\"h1\"` — the unified Help Center header (the\n * `TitleBlock` element is always an `<h1>`; `titleSize` only sets its typography,\n * here `text-h1`). The page owns that `<h1>`, so `<FaqSection heading={null}>`\n * nests its category headings as `<h2>`/`<h3>` (the SEO-recommended FAQ document\n * outline).\n *\n * DATA: pass `initialFaqs` (SSR-resolved, platform-scoped) so `FaqSection`\n * skips its client self-fetch — the standalone page's static platform-only\n * contract. Omit it for embeds that want the self-fetching `/api/faqs`\n * suggestion-fill instead.\n */\n\nimport { useRouter } from '../../embed-shims/next-navigation';\nimport type { Faq } from '../../types/faq';\nimport { PageShell, PageLayout } from '../ui';\nimport { FaqSection } from './faq-section';\nimport type { FaqSchemaOptions } from './json-ld';\n\nexport interface FaqDocumentPageProps {\n  /** Page title (frozen `PageLayout` `TitleBlock`). Default \"Frequently Asked Questions\". */\n  title?: string;\n  /** Subtitle under the title. */\n  subtitle?: string;\n  /** Back-button config — same pattern as `DevSectionPage` / `LegalDocumentPage`.\n   *  Pass `false` to hide. Default `{ label: 'Back to home', href: '/' }`. */\n  backButton?: { label?: string; href?: string } | false;\n  /** Render the standalone `<PageShell>` (own `<main>` + bg + max-width). Default\n   *  true. Pass false when the host layout already provides the page container\n   *  (e.g. openframe-frontend's `AppLayout` `<main>`) — only the padding box\n   *  renders, avoiding a nested `<main>`. */\n  shell?: boolean;\n  /** SSR-hydrate `FaqSection` (skips the client fetch — the platform-only\n   *  contract for the standalone page). Omit for self-fetching embeds. */\n  initialFaqs?: Faq[];\n  /** Emit FAQPage schema.org JSON-LD (forwarded to `FaqSection`). Off by\n   *  default so embeds don't emit duplicate schema. */\n  emitJsonLd?: boolean;\n  /** JSON-LD name/description/url overrides (forwarded to `FaqSection`). */\n  jsonLd?: FaqSchemaOptions;\n  /** Base URL `FaqSection` appends `/api/faqs` to (reverse-proxy embedders). */\n  apiBaseUrl?: string;\n  /** Optional entity scoping forwarded to `FaqSection`. */\n  entityType?: string;\n  entityId?: number | string;\n  /** Minimum FAQ count before the section renders (forwarded to `FaqSection`). */\n  minResults?: number;\n}\n\nexport function FaqDocumentPage({\n  title = 'Frequently Asked Questions',\n  subtitle,\n  backButton,\n  initialFaqs,\n  emitJsonLd,\n  jsonLd,\n  apiBaseUrl,\n  entityType,\n  entityId,\n  minResults,\n  shell = true,\n}: FaqDocumentPageProps) {\n  const router = useRouter();\n\n  // Back-button config — mirrors LegalDocumentPage / DevSectionPage. Hide\n  // entirely when the caller passes `false` (embed-mode where the host owns\n  // nav chrome).\n  const backCfg =\n    backButton === false\n      ? undefined\n      : {\n          label: backButton?.label ?? 'Back to home',\n          onClick: () => router.push(backButton?.href ?? '/'),\n        };\n\n  const inner = (\n    <PageLayout title={title} subtitle={subtitle} backButton={backCfg} titleSize=\"h1\" titleWrap>\n      <FaqSection\n        initialFaqs={initialFaqs}\n        heading={null}\n        emitJsonLd={emitJsonLd}\n        jsonLd={jsonLd}\n        apiBaseUrl={apiBaseUrl}\n        entityType={entityType}\n        entityId={entityId}\n        minResults={minResults}\n      />\n    </PageLayout>\n  );\n\n  return shell ? <PageShell>{inner}</PageShell> : <div className=\"page-shell-content\">{inner}</div>;\n}\n"]}