@dataimago/interview 0.2.0-alpha.2 → 0.2.0-alpha.4

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/index.cjs CHANGED
@@ -42,7 +42,7 @@ function ProgressBar({ current, total, estimatedMinutesRemaining }) {
42
42
  " of ",
43
43
  total
44
44
  ] }),
45
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "font-mono text-xs text-stone-500", children: [
45
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { className: "font-mono text-xs text-stone-700", children: [
46
46
  "~",
47
47
  estimatedMinutesRemaining,
48
48
  " min remaining"
@@ -134,7 +134,7 @@ function QuestionCard({
134
134
  "\u201D"
135
135
  ] }, i)) })
136
136
  ] }),
137
- !question.required && question.skipConsequence && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "mt-6 text-sm text-stone-500", children: [
137
+ !question.required && question.skipConsequence && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "mt-6 text-sm text-stone-700", children: [
138
138
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-medium", children: "If you skip this:" }),
139
139
  " ",
140
140
  question.skipConsequence
@@ -172,7 +172,7 @@ function InputForType({ question, value, onChange }) {
172
172
  case "scale":
173
173
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ScaleInput, { question, value, onChange });
174
174
  case "date":
175
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(DateInput, { value, onChange });
175
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(DateInput, { value, onChange, ariaLabel: question.prompt });
176
176
  case "composite":
177
177
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(CompositeInput, { question, value: value ?? {}, onChange });
178
178
  case "repeater":
@@ -298,18 +298,23 @@ function ScaleInput({
298
298
  className: "h-4 w-4 text-forest-700"
299
299
  }
300
300
  ),
301
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-mono text-sm text-stone-500", children: opt.value }),
301
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "font-mono text-sm text-stone-700", children: opt.value }),
302
302
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "text-stone-900", children: opt.label })
303
303
  ]
304
304
  },
305
305
  opt.value
306
306
  )) });
307
307
  }
308
- function DateInput({ value, onChange }) {
308
+ function DateInput({
309
+ value,
310
+ onChange,
311
+ ariaLabel
312
+ }) {
309
313
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
310
314
  "input",
311
315
  {
312
316
  type: "date",
317
+ "aria-label": ariaLabel,
313
318
  value: value ?? "",
314
319
  onChange: (e) => onChange(e.target.value),
315
320
  autoFocus: true,
@@ -340,7 +345,7 @@ function ListInput({
340
345
  const validCount = items.filter((v) => v.trim().length > 0).length;
341
346
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
342
347
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { className: "space-y-2", children: items.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { className: "flex items-center gap-2", children: [
343
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "w-6 text-right font-mono text-xs text-stone-400", children: [
348
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "w-6 text-right font-mono text-xs text-stone-600", children: [
344
349
  i + 1,
345
350
  "."
346
351
  ] }),
@@ -360,7 +365,7 @@ function ListInput({
360
365
  type: "button",
361
366
  onClick: () => removeItem(i),
362
367
  disabled: items.length <= 1,
363
- className: "btn-ghost text-stone-500 disabled:opacity-30",
368
+ className: "btn-ghost text-stone-700 disabled:opacity-30",
364
369
  "aria-label": `Remove item ${i + 1}`,
365
370
  children: "\xD7"
366
371
  }
@@ -377,7 +382,7 @@ function ListInput({
377
382
  children: "+ Add item"
378
383
  }
379
384
  ),
380
- listRange && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "font-mono text-xs text-stone-500", children: [
385
+ listRange && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "font-mono text-xs text-stone-700", children: [
381
386
  validCount,
382
387
  " / ",
383
388
  min,
@@ -430,7 +435,7 @@ function RepeaterInput({
430
435
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "space-y-4", children: [
431
436
  rows.map((row, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "rounded-lg border-2 border-stone-200 bg-stone-50 p-4", children: [
432
437
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "mb-3 flex items-center justify-between", children: [
433
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "font-mono text-xs uppercase tracking-wider text-stone-500", children: [
438
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "font-mono text-xs uppercase tracking-wider text-stone-700", children: [
434
439
  "Item ",
435
440
  i + 1
436
441
  ] }),
@@ -440,7 +445,7 @@ function RepeaterInput({
440
445
  type: "button",
441
446
  onClick: () => removeRow(i),
442
447
  disabled: rows.length <= min,
443
- className: "btn-ghost text-xs text-stone-500 disabled:opacity-30",
448
+ className: "btn-ghost text-xs text-stone-700 disabled:opacity-30",
444
449
  "aria-label": `Remove item ${i + 1}`,
445
450
  children: "Remove"
446
451
  }
@@ -520,7 +525,7 @@ function FileUploadInput({
520
525
  )
521
526
  ] })
522
527
  ] }),
523
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "mt-1 text-xs text-stone-500", children: "You'll add a title, author, and description for each file below." })
528
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "mt-1 text-xs text-stone-700", children: "You'll add a title, author, and description for each file below." })
524
529
  ]
525
530
  }
526
531
  ),
@@ -531,7 +536,7 @@ function FileUploadInput({
531
536
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex items-center justify-between", children: [
532
537
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
533
538
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "font-medium text-stone-900", children: name }),
534
- typeof size === "number" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "font-mono text-xs text-stone-500", children: [
539
+ typeof size === "number" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "font-mono text-xs text-stone-700", children: [
535
540
  (size / 1024).toFixed(1),
536
541
  " KB"
537
542
  ] })
@@ -541,7 +546,7 @@ function FileUploadInput({
541
546
  {
542
547
  type: "button",
543
548
  onClick: () => removeEntry(i),
544
- className: "btn-ghost text-xs text-stone-500",
549
+ className: "btn-ghost text-xs text-stone-700",
545
550
  "aria-label": `Remove ${name}`,
546
551
  children: "Remove"
547
552
  }
@@ -563,7 +568,7 @@ function FileUploadInput({
563
568
  ] });
564
569
  }
565
570
  function UnknownTypeFallback({ inputType }) {
566
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "rounded-lg border-2 border-stone-300 bg-stone-50 p-4 text-sm text-stone-500", children: [
571
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "rounded-lg border-2 border-stone-300 bg-stone-50 p-4 text-sm text-stone-700", children: [
567
572
  "Unsupported question input type:",
568
573
  " ",
569
574
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { className: "font-mono", children: String(inputType) })
@@ -690,7 +695,7 @@ function AnswerSidebar({ questions, currentIndex, answers, onSelectQuestion }) {
690
695
  className: "sticky top-24 hidden max-h-[calc(100vh-6rem)] overflow-y-auto lg:block",
691
696
  "aria-label": "Completed answers",
692
697
  children: [
693
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "mb-3 font-mono text-xs uppercase tracking-wider text-stone-500", children: "Your answers" }),
698
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { className: "mb-3 font-mono text-xs uppercase tracking-wider text-stone-700", children: "Your answers" }),
694
699
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("ol", { className: "space-y-3", children: questions.map((q, i) => {
695
700
  const answer = answers[q.id];
696
701
  const answered = isAnswered(answer);
@@ -706,7 +711,7 @@ function AnswerSidebar({ questions, currentIndex, answers, onSelectQuestion }) {
706
711
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
707
712
  "span",
708
713
  {
709
- className: `mt-0.5 font-mono text-xs ${isCurrent ? "text-forest-700" : answered ? "text-stone-500" : "text-stone-400"}`,
714
+ className: `mt-0.5 font-mono text-xs ${isCurrent ? "text-forest-700" : answered ? "text-stone-700" : "text-stone-600"}`,
710
715
  children: [
711
716
  String(i + 1).padStart(2, "0"),
712
717
  "."
@@ -717,11 +722,11 @@ function AnswerSidebar({ questions, currentIndex, answers, onSelectQuestion }) {
717
722
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
718
723
  "div",
719
724
  {
720
- className: `text-xs font-medium ${answered ? "text-stone-900" : "text-stone-500"}`,
725
+ className: `text-xs font-medium ${answered ? "text-stone-900" : "text-stone-700"}`,
721
726
  children: q.prompt.length > 50 ? q.prompt.slice(0, 50) + "\u2026" : q.prompt
722
727
  }
723
728
  ),
724
- answered && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mt-1 text-xs italic text-stone-500 line-clamp-1", children: preview })
729
+ answered && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "mt-1 text-xs italic text-stone-700 line-clamp-1", children: preview })
725
730
  ] })
726
731
  ] })
727
732
  }
@@ -742,22 +747,36 @@ function ReviewSummary({ questions, answers, onGenerate, onEdit, generating }) {
742
747
  const answer = answers[q.id];
743
748
  const answered = isAnswered(answer);
744
749
  const display = answered ? summarizeLong(q, answer) : "";
745
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex gap-4 border-b border-stone-200 pb-6", children: [
746
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "font-mono text-sm text-stone-400 pt-1", children: String(i + 1).padStart(2, "0") }),
747
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex-grow", children: [
748
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("dt", { className: "text-sm font-medium text-stone-900", children: q.prompt }),
749
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("dd", { className: "mt-2 text-stone-900 whitespace-pre-wrap", children: answered ? display : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "italic text-stone-400", children: "Not answered" }) })
750
- ] }),
751
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
752
- "button",
750
+ return (
751
+ // A <div> child of <dl> may contain ONLY dt/dd groups (HTML spec;
752
+ // axe definition-list), so the index + Edit button live INSIDE
753
+ // <dt>. Subgrid keeps all three columns aligned across dt and dd
754
+ // without extra wrappers.
755
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
756
+ "div",
753
757
  {
754
- type: "button",
755
- onClick: () => onEdit(i),
756
- className: "btn-ghost text-sm self-start",
757
- children: "Edit"
758
- }
758
+ className: "grid grid-cols-[auto_1fr_auto] gap-x-4 border-b border-stone-200 pb-6",
759
+ children: [
760
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("dt", { className: "col-span-3 grid grid-cols-subgrid", children: [
761
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { "aria-hidden": "true", className: "pt-1 font-mono text-sm text-stone-600", children: String(i + 1).padStart(2, "0") }),
762
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-sm font-medium text-stone-900", children: q.prompt }),
763
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
764
+ "button",
765
+ {
766
+ type: "button",
767
+ onClick: () => onEdit(i),
768
+ "aria-label": `Edit: ${q.prompt}`,
769
+ className: "btn-ghost self-start text-sm",
770
+ children: "Edit"
771
+ }
772
+ )
773
+ ] }),
774
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("dd", { className: "col-span-3 mt-2 grid grid-cols-subgrid", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "col-start-2 whitespace-pre-wrap text-stone-900", children: answered ? display : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "italic text-stone-600", children: "Not answered" }) }) })
775
+ ]
776
+ },
777
+ q.id
759
778
  )
760
- ] }, q.id);
779
+ );
761
780
  }) }),
762
781
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "mt-10 rounded-lg border border-copper-300 bg-copper-50 p-6", children: [
763
782
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { className: "font-display text-xl text-stone-900", children: "What happens next" }),
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/ProgressBar.tsx","../src/QuestionCard.tsx","../src/summarize.ts","../src/AnswerSidebar.tsx","../src/ReviewSummary.tsx"],"sourcesContent":["/**\n * @dataimago/interview — public surface barrel.\n *\n * Components (named exports — note the original apps/hub components\n * were default exports; the package exposes them as named exports for\n * tree-shaking and to make the import surface symmetric with @dataimago/ui):\n */\nexport { ProgressBar } from './ProgressBar';\nexport { QuestionCard } from './QuestionCard';\nexport { AnswerSidebar } from './AnswerSidebar';\nexport { ReviewSummary } from './ReviewSummary';\n\n/**\n * Schema contract — the public type surface that consumers populate with\n * their domain-specific question content.\n */\nexport type {\n QuestionInputType,\n InterviewQuestion,\n InterviewAnswers,\n AnswerValue,\n AnswerComposite,\n AnswerRepeater,\n AnswerFileUpload,\n FileEntry,\n} from './types';\n\n/**\n * Answer-rendering helpers — useful for consumers who want to display\n * answer previews outside the package's sidebar/review components.\n */\nexport { isAnswered, summarizeShort, summarizeLong } from './summarize';\n","'use client';\n\ninterface Props {\n current: number;\n total: number;\n estimatedMinutesRemaining: number;\n}\n\n/**\n * Linear progress indicator for the interview flow. Renders the\n * \"Question N of M\" caption, the estimated minutes remaining, and a\n * forest-700 fill bar at `(current / total) * 100%`.\n *\n * Iteration-1 visual identity (Phase B.2, 2026-05-06):\n * stone-100 surface with stone-200 border; forest-700 fill bar; stone-700\n * caption text. Pure-render component — no state-management dependency.\n *\n * Extracted from `apps/hub/src/components/interview/ProgressBar.tsx`\n * during iteration-3-B.1 (2026-05-07). No prop API change.\n */\nexport function ProgressBar({ current, total, estimatedMinutesRemaining }: Props) {\n const percent = Math.round((current / total) * 100);\n\n return (\n <div className=\"border-b border-stone-200 bg-stone-100 py-3 px-6\">\n <div className=\"mx-auto max-w-3xl\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"font-mono text-xs uppercase tracking-wider text-stone-700\">\n Question {current} of {total}\n </span>\n <span className=\"font-mono text-xs text-stone-500\">\n ~{estimatedMinutesRemaining} min remaining\n </span>\n </div>\n <div\n className=\"mt-2 h-1 w-full overflow-hidden rounded-full bg-stone-200\"\n role=\"progressbar\"\n aria-valuenow={percent}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={`Interview progress: ${percent}% complete`}\n >\n <div\n className=\"h-full bg-forest-700 transition-all duration-300 ease-out\"\n style={{ width: `${percent}%` }}\n />\n </div>\n </div>\n </div>\n );\n}\n","'use client';\n\nimport { useState, useEffect } from 'react';\nimport type {\n InterviewQuestion,\n AnswerValue,\n AnswerComposite,\n AnswerRepeater,\n AnswerFileUpload,\n FileEntry,\n} from './types';\n\ninterface Props {\n question: InterviewQuestion;\n /**\n * The currently-saved answer for this question (from the consumer's\n * state container). The component initializes its local form state\n * from this value and re-syncs when the question id changes.\n */\n existingAnswer?: AnswerValue;\n /**\n * Called when the user submits an answer. The consumer is expected to\n * persist the answer into its state container and then advance via\n * `onNext`.\n */\n onAnswerSubmit: (questionId: string, value: AnswerValue) => void;\n /** Called after `onAnswerSubmit` to advance to the next question. */\n onNext: () => void;\n /** Called when the user clicks the Back button. */\n onBack: () => void;\n isFirst: boolean;\n isLast: boolean;\n}\n\n/**\n * Default value to use when no `existingAnswer` is supplied. Depends on\n * the question's `inputType`.\n */\nfunction defaultValueFor(question: InterviewQuestion): AnswerValue {\n switch (question.inputType) {\n case 'multi-select':\n case 'list':\n return [];\n case 'composite':\n return {} as AnswerComposite;\n case 'repeater':\n case 'file-upload':\n return [];\n default:\n return '';\n }\n}\n\n/**\n * Whether the user's current local value satisfies the required check\n * for the question.\n */\nfunction canAdvanceWith(question: InterviewQuestion, value: AnswerValue): boolean {\n if (!question.required) return true;\n if (value === undefined || value === null) return false;\n if (typeof value === 'string') return value.trim().length > 0;\n if (Array.isArray(value)) return value.length > 0;\n if (typeof value === 'object') return Object.keys(value).length > 0;\n return true;\n}\n\n/**\n * Single question renderer. Handles all input types: short-text, long-text,\n * single-select, multi-select, scale, list, date, composite, repeater,\n * file-upload. Keyboard-navigable and screen-reader safe.\n *\n * **Decoupled from any state-management library.** Consumers receive the\n * existing answer + change handler as props.\n *\n * Iteration-1 visual identity: form input fields use stone-50 elevated\n * surface + stone-200 default border + forest-700 focus border. Selected\n * radio/checkbox option states use forest-700 border + forest-50 background.\n * The examples disclosure has border-l-2 frame in border-copper-200 —\n * preserved-decorative-copper role per iteration-2-blue-accent.md.\n */\nexport function QuestionCard({\n question,\n existingAnswer,\n onAnswerSubmit,\n onNext,\n onBack,\n isFirst,\n isLast,\n}: Props) {\n const [localValue, setLocalValue] = useState<AnswerValue>(\n existingAnswer ?? defaultValueFor(question),\n );\n\n // Sync when question changes (consumer flipped to a different question;\n // local form state should reflect that question's existing answer).\n useEffect(() => {\n setLocalValue(existingAnswer ?? defaultValueFor(question));\n }, [question.id, existingAnswer, question.inputType]);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n onAnswerSubmit(question.id, localValue);\n onNext();\n };\n\n const canAdvance = canAdvanceWith(question, localValue);\n\n return (\n <form onSubmit={handleSubmit} className=\"animate-slide-up\">\n {/* Prompt */}\n <h2 className=\"font-display text-3xl font-medium text-stone-900 sm:text-4xl\">\n {question.prompt}\n </h2>\n {question.subprompt && (\n <p className=\"mt-4 text-lg text-stone-700\">{question.subprompt}</p>\n )}\n\n {/* Input — dispatched per type */}\n <div className=\"mt-8\">\n <InputForType\n question={question}\n value={localValue}\n onChange={setLocalValue}\n />\n </div>\n\n {/* Examples */}\n {question.examples && question.examples.length > 0 && (\n <details className=\"mt-8\">\n <summary className=\"cursor-pointer text-sm font-medium text-forest-700 hover:text-forest-800\">\n Show examples from different fields\n </summary>\n {/* border-copper-200 PRESERVED: decorative-emphasis frame around\n illustrative content, same role as HeroSection's etymology box. */}\n <ul className=\"mt-4 space-y-3 border-l-2 border-copper-200 pl-5\">\n {question.examples.map((ex, i) => (\n <li key={i} className=\"text-sm italic text-stone-700\">\n “{ex}”\n </li>\n ))}\n </ul>\n </details>\n )}\n\n {/* Skip consequence (if applicable) */}\n {!question.required && question.skipConsequence && (\n <p className=\"mt-6 text-sm text-stone-500\">\n <span className=\"font-medium\">If you skip this:</span> {question.skipConsequence}\n </p>\n )}\n\n {/* Nav */}\n <div className=\"mt-10 flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={onBack}\n disabled={isFirst}\n className=\"btn-ghost disabled:opacity-40\"\n >\n ← Back\n </button>\n <div className=\"flex gap-3\">\n {!question.required && (\n <button type=\"button\" onClick={onNext} className=\"btn-ghost\">\n Skip\n </button>\n )}\n <button type=\"submit\" disabled={!canAdvance} className=\"btn-primary\">\n {isLast ? 'Review answers' : 'Continue →'}\n </button>\n </div>\n </div>\n </form>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Per-input-type renderers\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface InputProps {\n question: InterviewQuestion;\n value: AnswerValue;\n onChange: (next: AnswerValue) => void;\n}\n\nfunction InputForType({ question, value, onChange }: InputProps) {\n switch (question.inputType) {\n case 'short-text':\n return <ShortTextInput value={value as string} onChange={onChange} />;\n case 'long-text':\n return <LongTextInput value={value as string} onChange={onChange} />;\n case 'single-select':\n return <SingleSelectInput question={question} value={value as string} onChange={onChange} />;\n case 'multi-select':\n return <MultiSelectInput question={question} value={(value as string[]) ?? []} onChange={onChange} />;\n case 'list':\n return <ListInput value={(value as string[]) ?? []} onChange={onChange} listRange={question.listRange} />;\n case 'scale':\n return <ScaleInput question={question} value={value as string} onChange={onChange} />;\n case 'date':\n return <DateInput value={value as string} onChange={onChange} />;\n case 'composite':\n return <CompositeInput question={question} value={(value as AnswerComposite) ?? {}} onChange={onChange} />;\n case 'repeater':\n return <RepeaterInput question={question} value={(value as AnswerRepeater) ?? []} onChange={onChange} />;\n case 'file-upload':\n return <FileUploadInput question={question} value={(value as AnswerFileUpload) ?? []} onChange={onChange} />;\n default: {\n const _exhaustive: never = question.inputType;\n return <UnknownTypeFallback inputType={_exhaustive} />;\n }\n }\n}\n\nfunction ShortTextInput({ value, onChange }: { value: string; onChange: (v: string) => void }) {\n return (\n <input\n type=\"text\"\n value={value ?? ''}\n onChange={(e) => onChange(e.target.value)}\n autoFocus\n className=\"w-full rounded-lg border-2 border-stone-200 bg-stone-50 px-4 py-3 text-lg text-stone-900 focus:border-forest-700 focus:outline-none\"\n placeholder=\"Type your answer…\"\n />\n );\n}\n\nfunction LongTextInput({ value, onChange }: { value: string; onChange: (v: string) => void }) {\n return (\n <textarea\n value={value ?? ''}\n onChange={(e) => onChange(e.target.value)}\n autoFocus\n rows={5}\n className=\"w-full rounded-lg border-2 border-stone-200 bg-stone-50 px-4 py-3 text-lg text-stone-900 focus:border-forest-700 focus:outline-none\"\n placeholder=\"Type your answer…\"\n />\n );\n}\n\nfunction SingleSelectInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: string;\n onChange: (v: string) => void;\n}) {\n return (\n <div className=\"space-y-3\" role=\"radiogroup\" aria-labelledby={`q-${question.id}`}>\n {(question.options ?? []).map((opt) => (\n <label\n key={opt.value}\n className={`flex cursor-pointer items-start gap-3 rounded-lg border-2 p-4 transition-colors ${\n value === opt.value\n ? 'border-forest-700 bg-forest-50'\n : 'border-stone-200 bg-stone-50 hover:border-stone-400'\n }`}\n >\n <input\n type=\"radio\"\n name={question.id}\n value={opt.value}\n checked={value === opt.value}\n onChange={(e) => onChange(e.target.value)}\n className=\"mt-1 h-4 w-4 text-forest-700\"\n />\n <div>\n <div className=\"font-medium text-stone-900\">{opt.label}</div>\n {opt.description && (\n <div className=\"mt-1 text-sm text-stone-700\">{opt.description}</div>\n )}\n </div>\n </label>\n ))}\n </div>\n );\n}\n\nfunction MultiSelectInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: string[];\n onChange: (v: string[]) => void;\n}) {\n return (\n <div className=\"space-y-2\" role=\"group\" aria-labelledby={`q-${question.id}`}>\n {(question.options ?? []).map((opt) => {\n const checked = value.includes(opt.value);\n return (\n <label\n key={opt.value}\n className={`flex cursor-pointer items-start gap-3 rounded-lg border-2 p-4 transition-colors ${\n checked\n ? 'border-forest-700 bg-forest-50'\n : 'border-stone-200 bg-stone-50 hover:border-stone-400'\n }`}\n >\n <input\n type=\"checkbox\"\n value={opt.value}\n checked={checked}\n onChange={(e) => {\n if (e.target.checked) onChange([...value, opt.value]);\n else onChange(value.filter((v) => v !== opt.value));\n }}\n className=\"mt-1 h-4 w-4 text-forest-700\"\n />\n <div>\n <div className=\"font-medium text-stone-900\">{opt.label}</div>\n {opt.description && (\n <div className=\"mt-1 text-sm text-stone-700\">{opt.description}</div>\n )}\n </div>\n </label>\n );\n })}\n </div>\n );\n}\n\nfunction ScaleInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: string;\n onChange: (v: string) => void;\n}) {\n const options = question.options ?? [];\n return (\n <div className=\"space-y-3\" role=\"radiogroup\" aria-labelledby={`q-${question.id}`}>\n {options.map((opt) => (\n <label\n key={opt.value}\n className={`flex cursor-pointer items-center gap-3 rounded-lg border-2 p-3 transition-colors ${\n value === opt.value\n ? 'border-forest-700 bg-forest-50'\n : 'border-stone-200 bg-stone-50 hover:border-stone-400'\n }`}\n >\n <input\n type=\"radio\"\n name={question.id}\n value={opt.value}\n checked={value === opt.value}\n onChange={(e) => onChange(e.target.value)}\n className=\"h-4 w-4 text-forest-700\"\n />\n <span className=\"font-mono text-sm text-stone-500\">{opt.value}</span>\n <span className=\"text-stone-900\">{opt.label}</span>\n </label>\n ))}\n </div>\n );\n}\n\nfunction DateInput({ value, onChange }: { value: string; onChange: (v: string) => void }) {\n return (\n <input\n type=\"date\"\n value={value ?? ''}\n onChange={(e) => onChange(e.target.value)}\n autoFocus\n className=\"rounded-lg border-2 border-stone-200 bg-stone-50 px-4 py-3 text-lg text-stone-900 focus:border-forest-700 focus:outline-none\"\n />\n );\n}\n\nfunction ListInput({\n value,\n onChange,\n listRange,\n}: {\n value: string[];\n onChange: (v: string[]) => void;\n listRange?: { min: number; max: number };\n}) {\n const items = value.length > 0 ? value : [''];\n const min = listRange?.min ?? 0;\n const max = listRange?.max ?? Infinity;\n\n const setItem = (i: number, v: string) => {\n const next = [...items];\n next[i] = v;\n onChange(next);\n };\n const addItem = () => {\n if (items.length < max) onChange([...items, '']);\n };\n const removeItem = (i: number) => {\n if (items.length <= 1) return;\n onChange(items.filter((_, idx) => idx !== i));\n };\n const validCount = items.filter((v) => v.trim().length > 0).length;\n\n return (\n <div>\n <ul className=\"space-y-2\">\n {items.map((item, i) => (\n <li key={i} className=\"flex items-center gap-2\">\n <span className=\"w-6 text-right font-mono text-xs text-stone-400\">{i + 1}.</span>\n <input\n type=\"text\"\n value={item}\n onChange={(e) => setItem(i, e.target.value)}\n className=\"flex-grow rounded-lg border-2 border-stone-200 bg-stone-50 px-3 py-2 text-stone-900 focus:border-forest-700 focus:outline-none\"\n placeholder={`Item ${i + 1}`}\n />\n <button\n type=\"button\"\n onClick={() => removeItem(i)}\n disabled={items.length <= 1}\n className=\"btn-ghost text-stone-500 disabled:opacity-30\"\n aria-label={`Remove item ${i + 1}`}\n >\n ×\n </button>\n </li>\n ))}\n </ul>\n <div className=\"mt-3 flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={addItem}\n disabled={items.length >= max}\n className=\"text-sm font-medium text-forest-700 hover:text-forest-800 disabled:opacity-40\"\n >\n + Add item\n </button>\n {listRange && (\n <span className=\"font-mono text-xs text-stone-500\">\n {validCount} / {min}–{max === Infinity ? '∞' : max}\n </span>\n )}\n </div>\n </div>\n );\n}\n\nfunction CompositeInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: AnswerComposite;\n onChange: (v: AnswerComposite) => void;\n}) {\n const subQuestions = question.subQuestions ?? [];\n return (\n <div className=\"space-y-6 rounded-lg border-2 border-stone-200 bg-stone-50 p-4\">\n {subQuestions.map((sub) => (\n <div key={sub.id}>\n <div className=\"text-sm font-medium text-stone-900\">{sub.prompt}</div>\n {sub.subprompt && <div className=\"mt-1 text-xs text-stone-700\">{sub.subprompt}</div>}\n <div className=\"mt-2\">\n <InputForType\n question={sub}\n value={value[sub.id]}\n onChange={(next) => onChange({ ...value, [sub.id]: next })}\n />\n </div>\n </div>\n ))}\n </div>\n );\n}\n\nfunction RepeaterInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: AnswerRepeater;\n onChange: (v: AnswerRepeater) => void;\n}) {\n const rows = value.length > 0 ? value : [{} as Record<string, AnswerValue>];\n const itemSchema = question.itemSchema ?? [];\n const min = question.listRange?.min ?? 1;\n const max = question.listRange?.max ?? Infinity;\n\n const updateRow = (i: number, patch: Record<string, AnswerValue>) => {\n const next = [...rows];\n next[i] = { ...next[i], ...patch };\n onChange(next);\n };\n const addRow = () => {\n if (rows.length < max) onChange([...rows, {} as Record<string, AnswerValue>]);\n };\n const removeRow = (i: number) => {\n if (rows.length <= 1) return;\n onChange(rows.filter((_, idx) => idx !== i));\n };\n\n return (\n <div className=\"space-y-4\">\n {rows.map((row, i) => (\n <div key={i} className=\"rounded-lg border-2 border-stone-200 bg-stone-50 p-4\">\n <div className=\"mb-3 flex items-center justify-between\">\n <span className=\"font-mono text-xs uppercase tracking-wider text-stone-500\">\n Item {i + 1}\n </span>\n <button\n type=\"button\"\n onClick={() => removeRow(i)}\n disabled={rows.length <= min}\n className=\"btn-ghost text-xs text-stone-500 disabled:opacity-30\"\n aria-label={`Remove item ${i + 1}`}\n >\n Remove\n </button>\n </div>\n <div className=\"space-y-4\">\n {itemSchema.map((sub) => (\n <div key={sub.id}>\n <div className=\"text-sm font-medium text-stone-900\">{sub.prompt}</div>\n {sub.subprompt && (\n <div className=\"mt-1 text-xs text-stone-700\">{sub.subprompt}</div>\n )}\n <div className=\"mt-2\">\n <InputForType\n question={sub}\n value={row[sub.id]}\n onChange={(next) => updateRow(i, { [sub.id]: next })}\n />\n </div>\n </div>\n ))}\n </div>\n </div>\n ))}\n <button\n type=\"button\"\n onClick={addRow}\n disabled={rows.length >= max}\n className=\"text-sm font-medium text-forest-700 hover:text-forest-800 disabled:opacity-40\"\n >\n + Add another\n </button>\n </div>\n );\n}\n\nfunction FileUploadInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: AnswerFileUpload;\n onChange: (v: AnswerFileUpload) => void;\n}) {\n const itemSchema = question.itemSchema ?? [];\n\n const onFiles = (files: FileList | null) => {\n if (!files || files.length === 0) return;\n const entries: FileEntry[] = Array.from(files).map((f) => ({\n file: f,\n metadata: {},\n }));\n onChange([...value, ...entries]);\n };\n\n const updateMetadata = (i: number, patch: Record<string, AnswerValue>) => {\n const next = [...value];\n next[i] = { ...next[i], metadata: { ...next[i].metadata, ...patch } };\n onChange(next);\n };\n const removeEntry = (i: number) => onChange(value.filter((_, idx) => idx !== i));\n\n const onDrop = (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n onFiles(e.dataTransfer.files);\n };\n const onDragOver = (e: React.DragEvent<HTMLDivElement>) => e.preventDefault();\n\n return (\n <div className=\"space-y-4\">\n <div\n onDrop={onDrop}\n onDragOver={onDragOver}\n className=\"rounded-lg border-2 border-dashed border-stone-300 bg-stone-50 p-6 text-center\"\n >\n <p className=\"text-sm text-stone-700\">\n Drag PDFs or other files here, or{' '}\n <label className=\"cursor-pointer font-medium text-forest-700 hover:text-forest-800\">\n browse\n <input\n type=\"file\"\n multiple\n className=\"sr-only\"\n onChange={(e) => onFiles(e.target.files)}\n />\n </label>\n </p>\n <p className=\"mt-1 text-xs text-stone-500\">\n You'll add a title, author, and description for each file below.\n </p>\n </div>\n\n {value.length > 0 && (\n <ul className=\"space-y-4\">\n {value.map((entry, i) => {\n const name = entry.file.name;\n const size = 'size' in entry.file ? entry.file.size : undefined;\n return (\n <li key={i} className=\"rounded-lg border-2 border-stone-200 bg-stone-50 p-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"font-medium text-stone-900\">{name}</div>\n {typeof size === 'number' && (\n <div className=\"font-mono text-xs text-stone-500\">\n {(size / 1024).toFixed(1)} KB\n </div>\n )}\n </div>\n <button\n type=\"button\"\n onClick={() => removeEntry(i)}\n className=\"btn-ghost text-xs text-stone-500\"\n aria-label={`Remove ${name}`}\n >\n Remove\n </button>\n </div>\n {itemSchema.length > 0 && (\n <div className=\"mt-4 space-y-3\">\n {itemSchema.map((sub) => (\n <div key={sub.id}>\n <div className=\"text-xs font-medium text-stone-900\">{sub.prompt}</div>\n <div className=\"mt-1\">\n <InputForType\n question={sub}\n value={entry.metadata[sub.id]}\n onChange={(next) => updateMetadata(i, { [sub.id]: next })}\n />\n </div>\n </div>\n ))}\n </div>\n )}\n </li>\n );\n })}\n </ul>\n )}\n </div>\n );\n}\n\nfunction UnknownTypeFallback({ inputType }: { inputType: never }) {\n // Render-time defensive guard for runtime values that bypass TS (e.g.,\n // YAML-loaded interview schemas with typos). Visible to dev; user sees a\n // muted \"unsupported\" notice.\n return (\n <div className=\"rounded-lg border-2 border-stone-300 bg-stone-50 p-4 text-sm text-stone-500\">\n Unsupported question input type:{' '}\n <code className=\"font-mono\">{String(inputType)}</code>\n </div>\n );\n}\n","/**\n * Helpers for rendering one-line / summary previews of answer values in\n * `AnswerSidebar` and `ReviewSummary`. Centralized so the two components\n * stay consistent when new answer shapes are added.\n */\nimport type { AnswerValue, FileEntry, InterviewQuestion } from './types';\n\nexport function isAnswered(value: AnswerValue): boolean {\n if (value === undefined || value === null) return false;\n if (typeof value === 'string') return value.trim().length > 0;\n if (Array.isArray(value)) return value.length > 0;\n if (typeof value === 'object') return Object.keys(value).length > 0;\n return true;\n}\n\n/**\n * A short, single-line preview suitable for sidebar items. Truncates\n * long content. Returns the empty string for unanswered values.\n */\nexport function summarizeShort(question: InterviewQuestion, value: AnswerValue, maxLen = 80): string {\n if (!isAnswered(value)) return '';\n switch (question.inputType) {\n case 'short-text':\n case 'long-text':\n case 'date':\n case 'scale':\n return truncate(String(value), maxLen);\n case 'single-select': {\n const v = String(value);\n const label = question.options?.find((o) => o.value === v)?.label;\n return truncate(label ?? v, maxLen);\n }\n case 'multi-select':\n case 'list': {\n const arr = value as string[];\n const labels = arr.map((v) => {\n const found = question.options?.find((o) => o.value === v)?.label;\n return found ?? v;\n });\n return truncate(labels.join(', '), maxLen);\n }\n case 'composite': {\n // Show the first sub-answer's preview if any.\n const obj = value as { [k: string]: AnswerValue };\n const subs = question.subQuestions ?? [];\n for (const sub of subs) {\n const subVal = obj[sub.id];\n if (isAnswered(subVal)) {\n return truncate(summarizeShort(sub, subVal, maxLen), maxLen);\n }\n }\n return '';\n }\n case 'repeater': {\n const rows = value as Array<{ [k: string]: AnswerValue }>;\n return `${rows.length} item${rows.length === 1 ? '' : 's'}`;\n }\n case 'file-upload': {\n const files = value as FileEntry[];\n return `${files.length} file${files.length === 1 ? '' : 's'}`;\n }\n default:\n return '';\n }\n}\n\n/**\n * A richer multi-line summary suitable for the ReviewSummary list. May\n * contain newlines; consumers should render in a `whitespace-pre-wrap`\n * container.\n */\nexport function summarizeLong(question: InterviewQuestion, value: AnswerValue): string {\n if (!isAnswered(value)) return '';\n switch (question.inputType) {\n case 'short-text':\n case 'long-text':\n case 'date':\n case 'scale':\n return String(value);\n case 'single-select': {\n const v = String(value);\n const label = question.options?.find((o) => o.value === v)?.label;\n return label ?? v;\n }\n case 'multi-select':\n case 'list': {\n const arr = value as string[];\n const labels = arr.map((v) => question.options?.find((o) => o.value === v)?.label ?? v);\n return labels.join('\\n• ').replace(/^/, '• ');\n }\n case 'composite': {\n const obj = value as { [k: string]: AnswerValue };\n const subs = question.subQuestions ?? [];\n const lines: string[] = [];\n for (const sub of subs) {\n const subVal = obj[sub.id];\n if (isAnswered(subVal)) {\n lines.push(`${sub.prompt}: ${summarizeShort(sub, subVal, 200)}`);\n }\n }\n return lines.join('\\n');\n }\n case 'repeater': {\n const rows = value as Array<{ [k: string]: AnswerValue }>;\n const itemSchema = question.itemSchema ?? [];\n const summary = rows.map((row, i) => {\n const parts: string[] = [`Item ${i + 1}:`];\n for (const sub of itemSchema) {\n const subVal = row[sub.id];\n if (isAnswered(subVal)) {\n parts.push(` ${sub.prompt}: ${summarizeShort(sub, subVal, 100)}`);\n }\n }\n return parts.join('\\n');\n });\n return summary.join('\\n');\n }\n case 'file-upload': {\n const files = value as FileEntry[];\n return files\n .map((f, i) => `${i + 1}. ${f.file.name}`)\n .join('\\n');\n }\n default:\n return '';\n }\n}\n\nfunction truncate(s: string, maxLen: number): string {\n return s.length > maxLen ? s.slice(0, maxLen - 1) + '…' : s;\n}\n","'use client';\n\nimport type { InterviewAnswers, InterviewQuestion } from './types';\nimport { isAnswered, summarizeShort } from './summarize';\n\ninterface Props {\n questions: InterviewQuestion[];\n currentIndex: number;\n /** Consumer's current answer record (read-only — engine doesn't write). */\n answers: InterviewAnswers;\n /** Called when the user clicks a sidebar item to jump to that question. */\n onSelectQuestion: (index: number) => void;\n}\n\n/**\n * Sidebar showing all answered questions. Clicking any returns to edit that\n * question without losing later answers. Implements the wiki's pattern:\n * \"Edit any prior answer — a sidebar shows all answered questions.\"\n *\n * **Decoupled from any state-management library.** Consumers receive the\n * answers + jump handler as props.\n *\n * Iteration-1 visual identity (Phase B.2, 2026-05-06):\n * Three item states with distinct token tiers:\n * - current → forest-700 border + forest-50 bg (interactive primary)\n * - answered → stone-200 border + stone-50 bg (default, hover stone-400)\n * - unanswered → stone-200/50 + stone-50/50 (muted via opacity preservation)\n *\n * D.2.1.b extension: previews for composite/repeater/file-upload answers\n * delegated to `summarize.ts` so all eight scalar + three compound types\n * render consistently.\n */\nexport function AnswerSidebar({ questions, currentIndex, answers, onSelectQuestion }: Props) {\n return (\n <aside\n className=\"sticky top-24 hidden max-h-[calc(100vh-6rem)] overflow-y-auto lg:block\"\n aria-label=\"Completed answers\"\n >\n <h3 className=\"mb-3 font-mono text-xs uppercase tracking-wider text-stone-500\">\n Your answers\n </h3>\n <ol className=\"space-y-3\">\n {questions.map((q, i) => {\n const answer = answers[q.id];\n const answered = isAnswered(answer);\n const isCurrent = i === currentIndex;\n const preview = answered ? summarizeShort(q, answer) : '';\n\n return (\n <li key={q.id}>\n <button\n type=\"button\"\n onClick={() => onSelectQuestion(i)}\n className={`w-full rounded-lg border p-3 text-left transition-colors ${\n isCurrent\n ? 'border-forest-700 bg-forest-50'\n : answered\n ? 'border-stone-200 bg-stone-50 hover:border-stone-400'\n : 'border-stone-200/50 bg-stone-50/50 hover:border-stone-300'\n }`}\n >\n <div className=\"flex items-start gap-2\">\n <span\n className={`mt-0.5 font-mono text-xs ${\n isCurrent\n ? 'text-forest-700'\n : answered\n ? 'text-stone-500'\n : 'text-stone-400'\n }`}\n >\n {String(i + 1).padStart(2, '0')}.\n </span>\n <div className=\"flex-grow\">\n <div\n className={`text-xs font-medium ${\n answered ? 'text-stone-900' : 'text-stone-500'\n }`}\n >\n {q.prompt.length > 50 ? q.prompt.slice(0, 50) + '…' : q.prompt}\n </div>\n {answered && (\n <div className=\"mt-1 text-xs italic text-stone-500 line-clamp-1\">\n {preview}\n </div>\n )}\n </div>\n </div>\n </button>\n </li>\n );\n })}\n </ol>\n </aside>\n );\n}\n","'use client';\n\nimport type { InterviewAnswers, InterviewQuestion } from './types';\nimport { isAnswered, summarizeLong } from './summarize';\n\ninterface Props {\n questions: InterviewQuestion[];\n /** Consumer's current answer record (read-only — engine doesn't write). */\n answers: InterviewAnswers;\n onGenerate: () => void;\n onEdit: (questionIndex: number) => void;\n generating: boolean;\n}\n\n/**\n * Final review screen — the penultimate step before generation.\n * Shows all answers so the user can confirm ownership of the output before\n * committing.\n *\n * **Decoupled from any state-management library.** Consumers receive the\n * answer record as a prop.\n *\n * Iteration-1 visual identity (Phase B.2, 2026-05-06):\n * Editorial Josefin display family on the heading and the \"What happens next\"\n * callout title. Stone-tier surfaces and content text throughout. The\n * \"What happens next\" callout box preserves border-copper-300 + bg-copper-50 —\n * preserved-decorative-copper role per iteration-2-blue-accent.md.\n *\n * D.2.1.b extension: rendering of composite/repeater/file-upload answers\n * delegated to `summarize.ts` so all answer types display consistently.\n */\nexport function ReviewSummary({ questions, answers, onGenerate, onEdit, generating }: Props) {\n return (\n <div className=\"animate-slide-up\">\n <h2 className=\"font-display text-3xl font-medium text-stone-900 sm:text-4xl\">\n Review your answers\n </h2>\n <p className=\"mt-4 text-lg text-stone-700\">\n These become the seed content of your project. You can edit anything now, or continue and\n edit later through the platform.\n </p>\n\n <dl className=\"mt-10 space-y-6 border-t border-stone-200 pt-6\">\n {questions.map((q, i) => {\n const answer = answers[q.id];\n const answered = isAnswered(answer);\n const display = answered ? summarizeLong(q, answer) : '';\n\n return (\n <div key={q.id} className=\"flex gap-4 border-b border-stone-200 pb-6\">\n <span className=\"font-mono text-sm text-stone-400 pt-1\">\n {String(i + 1).padStart(2, '0')}\n </span>\n <div className=\"flex-grow\">\n <dt className=\"text-sm font-medium text-stone-900\">{q.prompt}</dt>\n <dd className=\"mt-2 text-stone-900 whitespace-pre-wrap\">\n {answered ? (\n display\n ) : (\n <span className=\"italic text-stone-400\">Not answered</span>\n )}\n </dd>\n </div>\n <button\n type=\"button\"\n onClick={() => onEdit(i)}\n className=\"btn-ghost text-sm self-start\"\n >\n Edit\n </button>\n </div>\n );\n })}\n </dl>\n\n {/* \"What happens next\" callout — copper PRESERVED as decorative\n informational frame, same role as HeroSection's etymology box.\n Per iteration-1 §5.2's preserved-decorative-copper governance. */}\n <div className=\"mt-10 rounded-lg border border-copper-300 bg-copper-50 p-6\">\n <h3 className=\"font-display text-xl text-stone-900\">What happens next</h3>\n <p className=\"mt-2 text-stone-900\">\n When you click Generate, the platform will create a GitHub repository in your account,\n populate it with your personalized CLAUDE.md, KNOWLEDGE.md, and wiki, and give you the\n URL. This takes about 30–90 seconds. You can edit everything afterward through the\n platform or through your repo.\n </p>\n <p className=\"mt-3 text-sm text-stone-700\">\n <span className=\"font-medium\">MVP note:</span> In this phase, GitHub repo creation is\n mocked for demonstration. Once OAuth credentials are configured, real repos will be\n created on your behalf.\n </p>\n </div>\n\n <div className=\"mt-8 flex justify-end\">\n <button\n type=\"button\"\n onClick={onGenerate}\n disabled={generating}\n className=\"btn-primary text-lg\"\n >\n {generating ? 'Generating your project…' : 'Generate my platform'}\n </button>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/ProgressBar.tsx","../src/QuestionCard.tsx","../src/summarize.ts","../src/AnswerSidebar.tsx","../src/ReviewSummary.tsx"],"sourcesContent":["/**\n * @dataimago/interview — public surface barrel.\n *\n * Components (named exports — note the original apps/hub components\n * were default exports; the package exposes them as named exports for\n * tree-shaking and to make the import surface symmetric with @dataimago/ui):\n */\nexport { ProgressBar } from './ProgressBar';\nexport { QuestionCard } from './QuestionCard';\nexport { AnswerSidebar } from './AnswerSidebar';\nexport { ReviewSummary } from './ReviewSummary';\n\n/**\n * Schema contract — the public type surface that consumers populate with\n * their domain-specific question content.\n */\nexport type {\n QuestionInputType,\n InterviewQuestion,\n InterviewAnswers,\n AnswerValue,\n AnswerComposite,\n AnswerRepeater,\n AnswerFileUpload,\n FileEntry,\n} from './types';\n\n/**\n * Answer-rendering helpers — useful for consumers who want to display\n * answer previews outside the package's sidebar/review components.\n */\nexport { isAnswered, summarizeShort, summarizeLong } from './summarize';\n","'use client';\n\ninterface Props {\n current: number;\n total: number;\n estimatedMinutesRemaining: number;\n}\n\n/**\n * Linear progress indicator for the interview flow. Renders the\n * \"Question N of M\" caption, the estimated minutes remaining, and a\n * forest-700 fill bar at `(current / total) * 100%`.\n *\n * Iteration-1 visual identity (Phase B.2, 2026-05-06):\n * stone-100 surface with stone-200 border; forest-700 fill bar; stone-700\n * caption text. Pure-render component — no state-management dependency.\n *\n * Extracted from `apps/hub/src/components/interview/ProgressBar.tsx`\n * during iteration-3-B.1 (2026-05-07). No prop API change.\n */\nexport function ProgressBar({ current, total, estimatedMinutesRemaining }: Props) {\n const percent = Math.round((current / total) * 100);\n\n return (\n <div className=\"border-b border-stone-200 bg-stone-100 py-3 px-6\">\n <div className=\"mx-auto max-w-3xl\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"font-mono text-xs uppercase tracking-wider text-stone-700\">\n Question {current} of {total}\n </span>\n <span className=\"font-mono text-xs text-stone-700\">\n ~{estimatedMinutesRemaining} min remaining\n </span>\n </div>\n <div\n className=\"mt-2 h-1 w-full overflow-hidden rounded-full bg-stone-200\"\n role=\"progressbar\"\n aria-valuenow={percent}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={`Interview progress: ${percent}% complete`}\n >\n <div\n className=\"h-full bg-forest-700 transition-all duration-300 ease-out\"\n style={{ width: `${percent}%` }}\n />\n </div>\n </div>\n </div>\n );\n}\n","'use client';\n\nimport { useState, useEffect } from 'react';\nimport type {\n InterviewQuestion,\n AnswerValue,\n AnswerComposite,\n AnswerRepeater,\n AnswerFileUpload,\n FileEntry,\n} from './types';\n\ninterface Props {\n question: InterviewQuestion;\n /**\n * The currently-saved answer for this question (from the consumer's\n * state container). The component initializes its local form state\n * from this value and re-syncs when the question id changes.\n */\n existingAnswer?: AnswerValue;\n /**\n * Called when the user submits an answer. The consumer is expected to\n * persist the answer into its state container and then advance via\n * `onNext`.\n */\n onAnswerSubmit: (questionId: string, value: AnswerValue) => void;\n /** Called after `onAnswerSubmit` to advance to the next question. */\n onNext: () => void;\n /** Called when the user clicks the Back button. */\n onBack: () => void;\n isFirst: boolean;\n isLast: boolean;\n}\n\n/**\n * Default value to use when no `existingAnswer` is supplied. Depends on\n * the question's `inputType`.\n */\nfunction defaultValueFor(question: InterviewQuestion): AnswerValue {\n switch (question.inputType) {\n case 'multi-select':\n case 'list':\n return [];\n case 'composite':\n return {} as AnswerComposite;\n case 'repeater':\n case 'file-upload':\n return [];\n default:\n return '';\n }\n}\n\n/**\n * Whether the user's current local value satisfies the required check\n * for the question.\n */\nfunction canAdvanceWith(question: InterviewQuestion, value: AnswerValue): boolean {\n if (!question.required) return true;\n if (value === undefined || value === null) return false;\n if (typeof value === 'string') return value.trim().length > 0;\n if (Array.isArray(value)) return value.length > 0;\n if (typeof value === 'object') return Object.keys(value).length > 0;\n return true;\n}\n\n/**\n * Single question renderer. Handles all input types: short-text, long-text,\n * single-select, multi-select, scale, list, date, composite, repeater,\n * file-upload. Keyboard-navigable and screen-reader safe.\n *\n * **Decoupled from any state-management library.** Consumers receive the\n * existing answer + change handler as props.\n *\n * Iteration-1 visual identity: form input fields use stone-50 elevated\n * surface + stone-200 default border + forest-700 focus border. Selected\n * radio/checkbox option states use forest-700 border + forest-50 background.\n * The examples disclosure has border-l-2 frame in border-copper-200 —\n * preserved-decorative-copper role per iteration-2-blue-accent.md.\n */\nexport function QuestionCard({\n question,\n existingAnswer,\n onAnswerSubmit,\n onNext,\n onBack,\n isFirst,\n isLast,\n}: Props) {\n const [localValue, setLocalValue] = useState<AnswerValue>(\n existingAnswer ?? defaultValueFor(question),\n );\n\n // Sync when question changes (consumer flipped to a different question;\n // local form state should reflect that question's existing answer).\n useEffect(() => {\n setLocalValue(existingAnswer ?? defaultValueFor(question));\n }, [question.id, existingAnswer, question.inputType]);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n onAnswerSubmit(question.id, localValue);\n onNext();\n };\n\n const canAdvance = canAdvanceWith(question, localValue);\n\n return (\n <form onSubmit={handleSubmit} className=\"animate-slide-up\">\n {/* Prompt */}\n <h2 className=\"font-display text-3xl font-medium text-stone-900 sm:text-4xl\">\n {question.prompt}\n </h2>\n {question.subprompt && (\n <p className=\"mt-4 text-lg text-stone-700\">{question.subprompt}</p>\n )}\n\n {/* Input — dispatched per type */}\n <div className=\"mt-8\">\n <InputForType\n question={question}\n value={localValue}\n onChange={setLocalValue}\n />\n </div>\n\n {/* Examples */}\n {question.examples && question.examples.length > 0 && (\n <details className=\"mt-8\">\n <summary className=\"cursor-pointer text-sm font-medium text-forest-700 hover:text-forest-800\">\n Show examples from different fields\n </summary>\n {/* border-copper-200 PRESERVED: decorative-emphasis frame around\n illustrative content, same role as HeroSection's etymology box. */}\n <ul className=\"mt-4 space-y-3 border-l-2 border-copper-200 pl-5\">\n {question.examples.map((ex, i) => (\n <li key={i} className=\"text-sm italic text-stone-700\">\n “{ex}”\n </li>\n ))}\n </ul>\n </details>\n )}\n\n {/* Skip consequence (if applicable) */}\n {!question.required && question.skipConsequence && (\n <p className=\"mt-6 text-sm text-stone-700\">\n <span className=\"font-medium\">If you skip this:</span> {question.skipConsequence}\n </p>\n )}\n\n {/* Nav */}\n <div className=\"mt-10 flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={onBack}\n disabled={isFirst}\n className=\"btn-ghost disabled:opacity-40\"\n >\n ← Back\n </button>\n <div className=\"flex gap-3\">\n {!question.required && (\n <button type=\"button\" onClick={onNext} className=\"btn-ghost\">\n Skip\n </button>\n )}\n <button type=\"submit\" disabled={!canAdvance} className=\"btn-primary\">\n {isLast ? 'Review answers' : 'Continue →'}\n </button>\n </div>\n </div>\n </form>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Per-input-type renderers\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface InputProps {\n question: InterviewQuestion;\n value: AnswerValue;\n onChange: (next: AnswerValue) => void;\n}\n\nfunction InputForType({ question, value, onChange }: InputProps) {\n switch (question.inputType) {\n case 'short-text':\n return <ShortTextInput value={value as string} onChange={onChange} />;\n case 'long-text':\n return <LongTextInput value={value as string} onChange={onChange} />;\n case 'single-select':\n return <SingleSelectInput question={question} value={value as string} onChange={onChange} />;\n case 'multi-select':\n return <MultiSelectInput question={question} value={(value as string[]) ?? []} onChange={onChange} />;\n case 'list':\n return <ListInput value={(value as string[]) ?? []} onChange={onChange} listRange={question.listRange} />;\n case 'scale':\n return <ScaleInput question={question} value={value as string} onChange={onChange} />;\n case 'date':\n return <DateInput value={value as string} onChange={onChange} ariaLabel={question.prompt} />;\n case 'composite':\n return <CompositeInput question={question} value={(value as AnswerComposite) ?? {}} onChange={onChange} />;\n case 'repeater':\n return <RepeaterInput question={question} value={(value as AnswerRepeater) ?? []} onChange={onChange} />;\n case 'file-upload':\n return <FileUploadInput question={question} value={(value as AnswerFileUpload) ?? []} onChange={onChange} />;\n default: {\n const _exhaustive: never = question.inputType;\n return <UnknownTypeFallback inputType={_exhaustive} />;\n }\n }\n}\n\nfunction ShortTextInput({ value, onChange }: { value: string; onChange: (v: string) => void }) {\n return (\n <input\n type=\"text\"\n value={value ?? ''}\n onChange={(e) => onChange(e.target.value)}\n autoFocus\n className=\"w-full rounded-lg border-2 border-stone-200 bg-stone-50 px-4 py-3 text-lg text-stone-900 focus:border-forest-700 focus:outline-none\"\n placeholder=\"Type your answer…\"\n />\n );\n}\n\nfunction LongTextInput({ value, onChange }: { value: string; onChange: (v: string) => void }) {\n return (\n <textarea\n value={value ?? ''}\n onChange={(e) => onChange(e.target.value)}\n autoFocus\n rows={5}\n className=\"w-full rounded-lg border-2 border-stone-200 bg-stone-50 px-4 py-3 text-lg text-stone-900 focus:border-forest-700 focus:outline-none\"\n placeholder=\"Type your answer…\"\n />\n );\n}\n\nfunction SingleSelectInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: string;\n onChange: (v: string) => void;\n}) {\n return (\n <div className=\"space-y-3\" role=\"radiogroup\" aria-labelledby={`q-${question.id}`}>\n {(question.options ?? []).map((opt) => (\n <label\n key={opt.value}\n className={`flex cursor-pointer items-start gap-3 rounded-lg border-2 p-4 transition-colors ${\n value === opt.value\n ? 'border-forest-700 bg-forest-50'\n : 'border-stone-200 bg-stone-50 hover:border-stone-400'\n }`}\n >\n <input\n type=\"radio\"\n name={question.id}\n value={opt.value}\n checked={value === opt.value}\n onChange={(e) => onChange(e.target.value)}\n className=\"mt-1 h-4 w-4 text-forest-700\"\n />\n <div>\n <div className=\"font-medium text-stone-900\">{opt.label}</div>\n {opt.description && (\n <div className=\"mt-1 text-sm text-stone-700\">{opt.description}</div>\n )}\n </div>\n </label>\n ))}\n </div>\n );\n}\n\nfunction MultiSelectInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: string[];\n onChange: (v: string[]) => void;\n}) {\n return (\n <div className=\"space-y-2\" role=\"group\" aria-labelledby={`q-${question.id}`}>\n {(question.options ?? []).map((opt) => {\n const checked = value.includes(opt.value);\n return (\n <label\n key={opt.value}\n className={`flex cursor-pointer items-start gap-3 rounded-lg border-2 p-4 transition-colors ${\n checked\n ? 'border-forest-700 bg-forest-50'\n : 'border-stone-200 bg-stone-50 hover:border-stone-400'\n }`}\n >\n <input\n type=\"checkbox\"\n value={opt.value}\n checked={checked}\n onChange={(e) => {\n if (e.target.checked) onChange([...value, opt.value]);\n else onChange(value.filter((v) => v !== opt.value));\n }}\n className=\"mt-1 h-4 w-4 text-forest-700\"\n />\n <div>\n <div className=\"font-medium text-stone-900\">{opt.label}</div>\n {opt.description && (\n <div className=\"mt-1 text-sm text-stone-700\">{opt.description}</div>\n )}\n </div>\n </label>\n );\n })}\n </div>\n );\n}\n\nfunction ScaleInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: string;\n onChange: (v: string) => void;\n}) {\n const options = question.options ?? [];\n return (\n <div className=\"space-y-3\" role=\"radiogroup\" aria-labelledby={`q-${question.id}`}>\n {options.map((opt) => (\n <label\n key={opt.value}\n className={`flex cursor-pointer items-center gap-3 rounded-lg border-2 p-3 transition-colors ${\n value === opt.value\n ? 'border-forest-700 bg-forest-50'\n : 'border-stone-200 bg-stone-50 hover:border-stone-400'\n }`}\n >\n <input\n type=\"radio\"\n name={question.id}\n value={opt.value}\n checked={value === opt.value}\n onChange={(e) => onChange(e.target.value)}\n className=\"h-4 w-4 text-forest-700\"\n />\n <span className=\"font-mono text-sm text-stone-700\">{opt.value}</span>\n <span className=\"text-stone-900\">{opt.label}</span>\n </label>\n ))}\n </div>\n );\n}\n\nfunction DateInput({\n value,\n onChange,\n ariaLabel,\n}: {\n value: string;\n onChange: (v: string) => void;\n ariaLabel: string;\n}) {\n return (\n <input\n type=\"date\"\n aria-label={ariaLabel}\n value={value ?? ''}\n onChange={(e) => onChange(e.target.value)}\n autoFocus\n className=\"rounded-lg border-2 border-stone-200 bg-stone-50 px-4 py-3 text-lg text-stone-900 focus:border-forest-700 focus:outline-none\"\n />\n );\n}\n\nfunction ListInput({\n value,\n onChange,\n listRange,\n}: {\n value: string[];\n onChange: (v: string[]) => void;\n listRange?: { min: number; max: number };\n}) {\n const items = value.length > 0 ? value : [''];\n const min = listRange?.min ?? 0;\n const max = listRange?.max ?? Infinity;\n\n const setItem = (i: number, v: string) => {\n const next = [...items];\n next[i] = v;\n onChange(next);\n };\n const addItem = () => {\n if (items.length < max) onChange([...items, '']);\n };\n const removeItem = (i: number) => {\n if (items.length <= 1) return;\n onChange(items.filter((_, idx) => idx !== i));\n };\n const validCount = items.filter((v) => v.trim().length > 0).length;\n\n return (\n <div>\n <ul className=\"space-y-2\">\n {items.map((item, i) => (\n <li key={i} className=\"flex items-center gap-2\">\n <span className=\"w-6 text-right font-mono text-xs text-stone-600\">{i + 1}.</span>\n <input\n type=\"text\"\n value={item}\n onChange={(e) => setItem(i, e.target.value)}\n className=\"flex-grow rounded-lg border-2 border-stone-200 bg-stone-50 px-3 py-2 text-stone-900 focus:border-forest-700 focus:outline-none\"\n placeholder={`Item ${i + 1}`}\n />\n <button\n type=\"button\"\n onClick={() => removeItem(i)}\n disabled={items.length <= 1}\n className=\"btn-ghost text-stone-700 disabled:opacity-30\"\n aria-label={`Remove item ${i + 1}`}\n >\n ×\n </button>\n </li>\n ))}\n </ul>\n <div className=\"mt-3 flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={addItem}\n disabled={items.length >= max}\n className=\"text-sm font-medium text-forest-700 hover:text-forest-800 disabled:opacity-40\"\n >\n + Add item\n </button>\n {listRange && (\n <span className=\"font-mono text-xs text-stone-700\">\n {validCount} / {min}–{max === Infinity ? '∞' : max}\n </span>\n )}\n </div>\n </div>\n );\n}\n\nfunction CompositeInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: AnswerComposite;\n onChange: (v: AnswerComposite) => void;\n}) {\n const subQuestions = question.subQuestions ?? [];\n return (\n <div className=\"space-y-6 rounded-lg border-2 border-stone-200 bg-stone-50 p-4\">\n {subQuestions.map((sub) => (\n <div key={sub.id}>\n <div className=\"text-sm font-medium text-stone-900\">{sub.prompt}</div>\n {sub.subprompt && <div className=\"mt-1 text-xs text-stone-700\">{sub.subprompt}</div>}\n <div className=\"mt-2\">\n <InputForType\n question={sub}\n value={value[sub.id]}\n onChange={(next) => onChange({ ...value, [sub.id]: next })}\n />\n </div>\n </div>\n ))}\n </div>\n );\n}\n\nfunction RepeaterInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: AnswerRepeater;\n onChange: (v: AnswerRepeater) => void;\n}) {\n const rows = value.length > 0 ? value : [{} as Record<string, AnswerValue>];\n const itemSchema = question.itemSchema ?? [];\n const min = question.listRange?.min ?? 1;\n const max = question.listRange?.max ?? Infinity;\n\n const updateRow = (i: number, patch: Record<string, AnswerValue>) => {\n const next = [...rows];\n next[i] = { ...next[i], ...patch };\n onChange(next);\n };\n const addRow = () => {\n if (rows.length < max) onChange([...rows, {} as Record<string, AnswerValue>]);\n };\n const removeRow = (i: number) => {\n if (rows.length <= 1) return;\n onChange(rows.filter((_, idx) => idx !== i));\n };\n\n return (\n <div className=\"space-y-4\">\n {rows.map((row, i) => (\n <div key={i} className=\"rounded-lg border-2 border-stone-200 bg-stone-50 p-4\">\n <div className=\"mb-3 flex items-center justify-between\">\n <span className=\"font-mono text-xs uppercase tracking-wider text-stone-700\">\n Item {i + 1}\n </span>\n <button\n type=\"button\"\n onClick={() => removeRow(i)}\n disabled={rows.length <= min}\n className=\"btn-ghost text-xs text-stone-700 disabled:opacity-30\"\n aria-label={`Remove item ${i + 1}`}\n >\n Remove\n </button>\n </div>\n <div className=\"space-y-4\">\n {itemSchema.map((sub) => (\n <div key={sub.id}>\n <div className=\"text-sm font-medium text-stone-900\">{sub.prompt}</div>\n {sub.subprompt && (\n <div className=\"mt-1 text-xs text-stone-700\">{sub.subprompt}</div>\n )}\n <div className=\"mt-2\">\n <InputForType\n question={sub}\n value={row[sub.id]}\n onChange={(next) => updateRow(i, { [sub.id]: next })}\n />\n </div>\n </div>\n ))}\n </div>\n </div>\n ))}\n <button\n type=\"button\"\n onClick={addRow}\n disabled={rows.length >= max}\n className=\"text-sm font-medium text-forest-700 hover:text-forest-800 disabled:opacity-40\"\n >\n + Add another\n </button>\n </div>\n );\n}\n\nfunction FileUploadInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: AnswerFileUpload;\n onChange: (v: AnswerFileUpload) => void;\n}) {\n const itemSchema = question.itemSchema ?? [];\n\n const onFiles = (files: FileList | null) => {\n if (!files || files.length === 0) return;\n const entries: FileEntry[] = Array.from(files).map((f) => ({\n file: f,\n metadata: {},\n }));\n onChange([...value, ...entries]);\n };\n\n const updateMetadata = (i: number, patch: Record<string, AnswerValue>) => {\n const next = [...value];\n next[i] = { ...next[i], metadata: { ...next[i].metadata, ...patch } };\n onChange(next);\n };\n const removeEntry = (i: number) => onChange(value.filter((_, idx) => idx !== i));\n\n const onDrop = (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n onFiles(e.dataTransfer.files);\n };\n const onDragOver = (e: React.DragEvent<HTMLDivElement>) => e.preventDefault();\n\n return (\n <div className=\"space-y-4\">\n <div\n onDrop={onDrop}\n onDragOver={onDragOver}\n className=\"rounded-lg border-2 border-dashed border-stone-300 bg-stone-50 p-6 text-center\"\n >\n <p className=\"text-sm text-stone-700\">\n Drag PDFs or other files here, or{' '}\n <label className=\"cursor-pointer font-medium text-forest-700 hover:text-forest-800\">\n browse\n <input\n type=\"file\"\n multiple\n className=\"sr-only\"\n onChange={(e) => onFiles(e.target.files)}\n />\n </label>\n </p>\n <p className=\"mt-1 text-xs text-stone-700\">\n You'll add a title, author, and description for each file below.\n </p>\n </div>\n\n {value.length > 0 && (\n <ul className=\"space-y-4\">\n {value.map((entry, i) => {\n const name = entry.file.name;\n const size = 'size' in entry.file ? entry.file.size : undefined;\n return (\n <li key={i} className=\"rounded-lg border-2 border-stone-200 bg-stone-50 p-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"font-medium text-stone-900\">{name}</div>\n {typeof size === 'number' && (\n <div className=\"font-mono text-xs text-stone-700\">\n {(size / 1024).toFixed(1)} KB\n </div>\n )}\n </div>\n <button\n type=\"button\"\n onClick={() => removeEntry(i)}\n className=\"btn-ghost text-xs text-stone-700\"\n aria-label={`Remove ${name}`}\n >\n Remove\n </button>\n </div>\n {itemSchema.length > 0 && (\n <div className=\"mt-4 space-y-3\">\n {itemSchema.map((sub) => (\n <div key={sub.id}>\n <div className=\"text-xs font-medium text-stone-900\">{sub.prompt}</div>\n <div className=\"mt-1\">\n <InputForType\n question={sub}\n value={entry.metadata[sub.id]}\n onChange={(next) => updateMetadata(i, { [sub.id]: next })}\n />\n </div>\n </div>\n ))}\n </div>\n )}\n </li>\n );\n })}\n </ul>\n )}\n </div>\n );\n}\n\nfunction UnknownTypeFallback({ inputType }: { inputType: never }) {\n // Render-time defensive guard for runtime values that bypass TS (e.g.,\n // YAML-loaded interview schemas with typos). Visible to dev; user sees a\n // muted \"unsupported\" notice.\n return (\n <div className=\"rounded-lg border-2 border-stone-300 bg-stone-50 p-4 text-sm text-stone-700\">\n Unsupported question input type:{' '}\n <code className=\"font-mono\">{String(inputType)}</code>\n </div>\n );\n}\n","/**\n * Helpers for rendering one-line / summary previews of answer values in\n * `AnswerSidebar` and `ReviewSummary`. Centralized so the two components\n * stay consistent when new answer shapes are added.\n */\nimport type { AnswerValue, FileEntry, InterviewQuestion } from './types';\n\nexport function isAnswered(value: AnswerValue): boolean {\n if (value === undefined || value === null) return false;\n if (typeof value === 'string') return value.trim().length > 0;\n if (Array.isArray(value)) return value.length > 0;\n if (typeof value === 'object') return Object.keys(value).length > 0;\n return true;\n}\n\n/**\n * A short, single-line preview suitable for sidebar items. Truncates\n * long content. Returns the empty string for unanswered values.\n */\nexport function summarizeShort(question: InterviewQuestion, value: AnswerValue, maxLen = 80): string {\n if (!isAnswered(value)) return '';\n switch (question.inputType) {\n case 'short-text':\n case 'long-text':\n case 'date':\n case 'scale':\n return truncate(String(value), maxLen);\n case 'single-select': {\n const v = String(value);\n const label = question.options?.find((o) => o.value === v)?.label;\n return truncate(label ?? v, maxLen);\n }\n case 'multi-select':\n case 'list': {\n const arr = value as string[];\n const labels = arr.map((v) => {\n const found = question.options?.find((o) => o.value === v)?.label;\n return found ?? v;\n });\n return truncate(labels.join(', '), maxLen);\n }\n case 'composite': {\n // Show the first sub-answer's preview if any.\n const obj = value as { [k: string]: AnswerValue };\n const subs = question.subQuestions ?? [];\n for (const sub of subs) {\n const subVal = obj[sub.id];\n if (isAnswered(subVal)) {\n return truncate(summarizeShort(sub, subVal, maxLen), maxLen);\n }\n }\n return '';\n }\n case 'repeater': {\n const rows = value as Array<{ [k: string]: AnswerValue }>;\n return `${rows.length} item${rows.length === 1 ? '' : 's'}`;\n }\n case 'file-upload': {\n const files = value as FileEntry[];\n return `${files.length} file${files.length === 1 ? '' : 's'}`;\n }\n default:\n return '';\n }\n}\n\n/**\n * A richer multi-line summary suitable for the ReviewSummary list. May\n * contain newlines; consumers should render in a `whitespace-pre-wrap`\n * container.\n */\nexport function summarizeLong(question: InterviewQuestion, value: AnswerValue): string {\n if (!isAnswered(value)) return '';\n switch (question.inputType) {\n case 'short-text':\n case 'long-text':\n case 'date':\n case 'scale':\n return String(value);\n case 'single-select': {\n const v = String(value);\n const label = question.options?.find((o) => o.value === v)?.label;\n return label ?? v;\n }\n case 'multi-select':\n case 'list': {\n const arr = value as string[];\n const labels = arr.map((v) => question.options?.find((o) => o.value === v)?.label ?? v);\n return labels.join('\\n• ').replace(/^/, '• ');\n }\n case 'composite': {\n const obj = value as { [k: string]: AnswerValue };\n const subs = question.subQuestions ?? [];\n const lines: string[] = [];\n for (const sub of subs) {\n const subVal = obj[sub.id];\n if (isAnswered(subVal)) {\n lines.push(`${sub.prompt}: ${summarizeShort(sub, subVal, 200)}`);\n }\n }\n return lines.join('\\n');\n }\n case 'repeater': {\n const rows = value as Array<{ [k: string]: AnswerValue }>;\n const itemSchema = question.itemSchema ?? [];\n const summary = rows.map((row, i) => {\n const parts: string[] = [`Item ${i + 1}:`];\n for (const sub of itemSchema) {\n const subVal = row[sub.id];\n if (isAnswered(subVal)) {\n parts.push(` ${sub.prompt}: ${summarizeShort(sub, subVal, 100)}`);\n }\n }\n return parts.join('\\n');\n });\n return summary.join('\\n');\n }\n case 'file-upload': {\n const files = value as FileEntry[];\n return files\n .map((f, i) => `${i + 1}. ${f.file.name}`)\n .join('\\n');\n }\n default:\n return '';\n }\n}\n\nfunction truncate(s: string, maxLen: number): string {\n return s.length > maxLen ? s.slice(0, maxLen - 1) + '…' : s;\n}\n","'use client';\n\nimport type { InterviewAnswers, InterviewQuestion } from './types';\nimport { isAnswered, summarizeShort } from './summarize';\n\ninterface Props {\n questions: InterviewQuestion[];\n currentIndex: number;\n /** Consumer's current answer record (read-only — engine doesn't write). */\n answers: InterviewAnswers;\n /** Called when the user clicks a sidebar item to jump to that question. */\n onSelectQuestion: (index: number) => void;\n}\n\n/**\n * Sidebar showing all answered questions. Clicking any returns to edit that\n * question without losing later answers. Implements the wiki's pattern:\n * \"Edit any prior answer — a sidebar shows all answered questions.\"\n *\n * **Decoupled from any state-management library.** Consumers receive the\n * answers + jump handler as props.\n *\n * Iteration-1 visual identity (Phase B.2, 2026-05-06):\n * Three item states with distinct token tiers:\n * - current → forest-700 border + forest-50 bg (interactive primary)\n * - answered → stone-200 border + stone-50 bg (default, hover stone-400)\n * - unanswered → stone-200/50 + stone-50/50 (muted via opacity preservation)\n *\n * D.2.1.b extension: previews for composite/repeater/file-upload answers\n * delegated to `summarize.ts` so all eight scalar + three compound types\n * render consistently.\n */\nexport function AnswerSidebar({ questions, currentIndex, answers, onSelectQuestion }: Props) {\n return (\n <aside\n className=\"sticky top-24 hidden max-h-[calc(100vh-6rem)] overflow-y-auto lg:block\"\n aria-label=\"Completed answers\"\n >\n <h3 className=\"mb-3 font-mono text-xs uppercase tracking-wider text-stone-700\">\n Your answers\n </h3>\n <ol className=\"space-y-3\">\n {questions.map((q, i) => {\n const answer = answers[q.id];\n const answered = isAnswered(answer);\n const isCurrent = i === currentIndex;\n const preview = answered ? summarizeShort(q, answer) : '';\n\n return (\n <li key={q.id}>\n <button\n type=\"button\"\n onClick={() => onSelectQuestion(i)}\n className={`w-full rounded-lg border p-3 text-left transition-colors ${\n isCurrent\n ? 'border-forest-700 bg-forest-50'\n : answered\n ? 'border-stone-200 bg-stone-50 hover:border-stone-400'\n : 'border-stone-200/50 bg-stone-50/50 hover:border-stone-300'\n }`}\n >\n <div className=\"flex items-start gap-2\">\n <span\n className={`mt-0.5 font-mono text-xs ${\n isCurrent\n ? 'text-forest-700'\n : answered\n ? 'text-stone-700'\n : 'text-stone-600'\n }`}\n >\n {String(i + 1).padStart(2, '0')}.\n </span>\n <div className=\"flex-grow\">\n <div\n className={`text-xs font-medium ${\n answered ? 'text-stone-900' : 'text-stone-700'\n }`}\n >\n {q.prompt.length > 50 ? q.prompt.slice(0, 50) + '…' : q.prompt}\n </div>\n {answered && (\n <div className=\"mt-1 text-xs italic text-stone-700 line-clamp-1\">\n {preview}\n </div>\n )}\n </div>\n </div>\n </button>\n </li>\n );\n })}\n </ol>\n </aside>\n );\n}\n","'use client';\n\nimport type { InterviewAnswers, InterviewQuestion } from './types';\nimport { isAnswered, summarizeLong } from './summarize';\n\ninterface Props {\n questions: InterviewQuestion[];\n /** Consumer's current answer record (read-only — engine doesn't write). */\n answers: InterviewAnswers;\n onGenerate: () => void;\n onEdit: (questionIndex: number) => void;\n generating: boolean;\n}\n\n/**\n * Final review screen — the penultimate step before generation.\n * Shows all answers so the user can confirm ownership of the output before\n * committing.\n *\n * **Decoupled from any state-management library.** Consumers receive the\n * answer record as a prop.\n *\n * Iteration-1 visual identity (Phase B.2, 2026-05-06):\n * Editorial Josefin display family on the heading and the \"What happens next\"\n * callout title. Stone-tier surfaces and content text throughout. The\n * \"What happens next\" callout box preserves border-copper-300 + bg-copper-50 —\n * preserved-decorative-copper role per iteration-2-blue-accent.md.\n *\n * D.2.1.b extension: rendering of composite/repeater/file-upload answers\n * delegated to `summarize.ts` so all answer types display consistently.\n */\nexport function ReviewSummary({ questions, answers, onGenerate, onEdit, generating }: Props) {\n return (\n <div className=\"animate-slide-up\">\n <h2 className=\"font-display text-3xl font-medium text-stone-900 sm:text-4xl\">\n Review your answers\n </h2>\n <p className=\"mt-4 text-lg text-stone-700\">\n These become the seed content of your project. You can edit anything now, or continue and\n edit later through the platform.\n </p>\n\n <dl className=\"mt-10 space-y-6 border-t border-stone-200 pt-6\">\n {questions.map((q, i) => {\n const answer = answers[q.id];\n const answered = isAnswered(answer);\n const display = answered ? summarizeLong(q, answer) : '';\n\n return (\n // A <div> child of <dl> may contain ONLY dt/dd groups (HTML spec;\n // axe definition-list), so the index + Edit button live INSIDE\n // <dt>. Subgrid keeps all three columns aligned across dt and dd\n // without extra wrappers.\n <div\n key={q.id}\n className=\"grid grid-cols-[auto_1fr_auto] gap-x-4 border-b border-stone-200 pb-6\"\n >\n <dt className=\"col-span-3 grid grid-cols-subgrid\">\n <span aria-hidden=\"true\" className=\"pt-1 font-mono text-sm text-stone-600\">\n {String(i + 1).padStart(2, '0')}\n </span>\n <span className=\"text-sm font-medium text-stone-900\">{q.prompt}</span>\n <button\n type=\"button\"\n onClick={() => onEdit(i)}\n aria-label={`Edit: ${q.prompt}`}\n className=\"btn-ghost self-start text-sm\"\n >\n Edit\n </button>\n </dt>\n <dd className=\"col-span-3 mt-2 grid grid-cols-subgrid\">\n <span className=\"col-start-2 whitespace-pre-wrap text-stone-900\">\n {answered ? (\n display\n ) : (\n <span className=\"italic text-stone-600\">Not answered</span>\n )}\n </span>\n </dd>\n </div>\n );\n })}\n </dl>\n\n {/* \"What happens next\" callout — copper PRESERVED as decorative\n informational frame, same role as HeroSection's etymology box.\n Per iteration-1 §5.2's preserved-decorative-copper governance. */}\n <div className=\"mt-10 rounded-lg border border-copper-300 bg-copper-50 p-6\">\n <h3 className=\"font-display text-xl text-stone-900\">What happens next</h3>\n <p className=\"mt-2 text-stone-900\">\n When you click Generate, the platform will create a GitHub repository in your account,\n populate it with your personalized CLAUDE.md, KNOWLEDGE.md, and wiki, and give you the\n URL. This takes about 30–90 seconds. You can edit everything afterward through the\n platform or through your repo.\n </p>\n <p className=\"mt-3 text-sm text-stone-700\">\n <span className=\"font-medium\">MVP note:</span> In this phase, GitHub repo creation is\n mocked for demonstration. Once OAuth credentials are configured, real repos will be\n created on your behalf.\n </p>\n </div>\n\n <div className=\"mt-8 flex justify-end\">\n <button\n type=\"button\"\n onClick={onGenerate}\n disabled={generating}\n className=\"btn-primary text-lg\"\n >\n {generating ? 'Generating your project…' : 'Generate my platform'}\n </button>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC2BU;AAPH,SAAS,YAAY,EAAE,SAAS,OAAO,0BAA0B,GAAU;AAChF,QAAM,UAAU,KAAK,MAAO,UAAU,QAAS,GAAG;AAElD,SACE,4CAAC,SAAI,WAAU,oDACb,uDAAC,SAAI,WAAU,qBACb;AAAA,iDAAC,SAAI,WAAU,6CACb;AAAA,mDAAC,UAAK,WAAU,6DAA4D;AAAA;AAAA,QAChE;AAAA,QAAQ;AAAA,QAAK;AAAA,SACzB;AAAA,MACA,6CAAC,UAAK,WAAU,oCAAmC;AAAA;AAAA,QAC/C;AAAA,QAA0B;AAAA,SAC9B;AAAA,OACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,MAAK;AAAA,QACL,iBAAe;AAAA,QACf,iBAAe;AAAA,QACf,iBAAe;AAAA,QACf,cAAY,uBAAuB,OAAO;AAAA,QAE1C;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO,EAAE,OAAO,GAAG,OAAO,IAAI;AAAA;AAAA,QAChC;AAAA;AAAA,IACF;AAAA,KACF,GACF;AAEJ;;;AChDA,mBAAoC;AA4G9B,IAAAA,sBAAA;AAxEN,SAAS,gBAAgB,UAA0C;AACjE,UAAQ,SAAS,WAAW;AAAA,IAC1B,KAAK;AAAA,IACL,KAAK;AACH,aAAO,CAAC;AAAA,IACV,KAAK;AACH,aAAO,CAAC;AAAA,IACV,KAAK;AAAA,IACL,KAAK;AACH,aAAO,CAAC;AAAA,IACV;AACE,aAAO;AAAA,EACX;AACF;AAMA,SAAS,eAAe,UAA6B,OAA6B;AAChF,MAAI,CAAC,SAAS,SAAU,QAAO;AAC/B,MAAI,UAAU,UAAa,UAAU,KAAM,QAAO;AAClD,MAAI,OAAO,UAAU,SAAU,QAAO,MAAM,KAAK,EAAE,SAAS;AAC5D,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,SAAS;AAChD,MAAI,OAAO,UAAU,SAAU,QAAO,OAAO,KAAK,KAAK,EAAE,SAAS;AAClE,SAAO;AACT;AAgBO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAU;AACR,QAAM,CAAC,YAAY,aAAa,QAAI;AAAA,IAClC,kBAAkB,gBAAgB,QAAQ;AAAA,EAC5C;AAIA,8BAAU,MAAM;AACd,kBAAc,kBAAkB,gBAAgB,QAAQ,CAAC;AAAA,EAC3D,GAAG,CAAC,SAAS,IAAI,gBAAgB,SAAS,SAAS,CAAC;AAEpD,QAAM,eAAe,CAAC,MAAuB;AAC3C,MAAE,eAAe;AACjB,mBAAe,SAAS,IAAI,UAAU;AACtC,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,eAAe,UAAU,UAAU;AAEtD,SACE,8CAAC,UAAK,UAAU,cAAc,WAAU,oBAEtC;AAAA,iDAAC,QAAG,WAAU,gEACX,mBAAS,QACZ;AAAA,IACC,SAAS,aACR,6CAAC,OAAE,WAAU,+BAA+B,mBAAS,WAAU;AAAA,IAIjE,6CAAC,SAAI,WAAU,QACb;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,OAAO;AAAA,QACP,UAAU;AAAA;AAAA,IACZ,GACF;AAAA,IAGC,SAAS,YAAY,SAAS,SAAS,SAAS,KAC/C,8CAAC,aAAQ,WAAU,QACjB;AAAA,mDAAC,aAAQ,WAAU,4EAA2E,iDAE9F;AAAA,MAGA,6CAAC,QAAG,WAAU,oDACX,mBAAS,SAAS,IAAI,CAAC,IAAI,MAC1B,8CAAC,QAAW,WAAU,iCAAgC;AAAA;AAAA,QAClD;AAAA,QAAG;AAAA,WADE,CAET,CACD,GACH;AAAA,OACF;AAAA,IAID,CAAC,SAAS,YAAY,SAAS,mBAC9B,8CAAC,OAAE,WAAU,+BACX;AAAA,mDAAC,UAAK,WAAU,eAAc,+BAAiB;AAAA,MAAO;AAAA,MAAE,SAAS;AAAA,OACnE;AAAA,IAIF,8CAAC,SAAI,WAAU,2CACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS;AAAA,UACT,UAAU;AAAA,UACV,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,MACA,8CAAC,SAAI,WAAU,cACZ;AAAA,SAAC,SAAS,YACT,6CAAC,YAAO,MAAK,UAAS,SAAS,QAAQ,WAAU,aAAY,kBAE7D;AAAA,QAEF,6CAAC,YAAO,MAAK,UAAS,UAAU,CAAC,YAAY,WAAU,eACpD,mBAAS,mBAAmB,mBAC/B;AAAA,SACF;AAAA,OACF;AAAA,KACF;AAEJ;AAYA,SAAS,aAAa,EAAE,UAAU,OAAO,SAAS,GAAe;AAC/D,UAAQ,SAAS,WAAW;AAAA,IAC1B,KAAK;AACH,aAAO,6CAAC,kBAAe,OAAwB,UAAoB;AAAA,IACrE,KAAK;AACH,aAAO,6CAAC,iBAAc,OAAwB,UAAoB;AAAA,IACpE,KAAK;AACH,aAAO,6CAAC,qBAAkB,UAAoB,OAAwB,UAAoB;AAAA,IAC5F,KAAK;AACH,aAAO,6CAAC,oBAAiB,UAAoB,OAAQ,SAAsB,CAAC,GAAG,UAAoB;AAAA,IACrG,KAAK;AACH,aAAO,6CAAC,aAAU,OAAQ,SAAsB,CAAC,GAAG,UAAoB,WAAW,SAAS,WAAW;AAAA,IACzG,KAAK;AACH,aAAO,6CAAC,cAAW,UAAoB,OAAwB,UAAoB;AAAA,IACrF,KAAK;AACH,aAAO,6CAAC,aAAU,OAAwB,UAAoB,WAAW,SAAS,QAAQ;AAAA,IAC5F,KAAK;AACH,aAAO,6CAAC,kBAAe,UAAoB,OAAQ,SAA6B,CAAC,GAAG,UAAoB;AAAA,IAC1G,KAAK;AACH,aAAO,6CAAC,iBAAc,UAAoB,OAAQ,SAA4B,CAAC,GAAG,UAAoB;AAAA,IACxG,KAAK;AACH,aAAO,6CAAC,mBAAgB,UAAoB,OAAQ,SAA8B,CAAC,GAAG,UAAoB;AAAA,IAC5G,SAAS;AACP,YAAM,cAAqB,SAAS;AACpC,aAAO,6CAAC,uBAAoB,WAAW,aAAa;AAAA,IACtD;AAAA,EACF;AACF;AAEA,SAAS,eAAe,EAAE,OAAO,SAAS,GAAqD;AAC7F,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,OAAO,SAAS;AAAA,MAChB,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,MACxC,WAAS;AAAA,MACT,WAAU;AAAA,MACV,aAAY;AAAA;AAAA,EACd;AAEJ;AAEA,SAAS,cAAc,EAAE,OAAO,SAAS,GAAqD;AAC5F,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,SAAS;AAAA,MAChB,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,MACxC,WAAS;AAAA,MACT,MAAM;AAAA,MACN,WAAU;AAAA,MACV,aAAY;AAAA;AAAA,EACd;AAEJ;AAEA,SAAS,kBAAkB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,SACE,6CAAC,SAAI,WAAU,aAAY,MAAK,cAAa,mBAAiB,KAAK,SAAS,EAAE,IAC1E,oBAAS,WAAW,CAAC,GAAG,IAAI,CAAC,QAC7B;AAAA,IAAC;AAAA;AAAA,MAEC,WAAW,mFACT,UAAU,IAAI,QACV,mCACA,qDACN;AAAA,MAEA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,MAAM,SAAS;AAAA,YACf,OAAO,IAAI;AAAA,YACX,SAAS,UAAU,IAAI;AAAA,YACvB,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,YACxC,WAAU;AAAA;AAAA,QACZ;AAAA,QACA,8CAAC,SACC;AAAA,uDAAC,SAAI,WAAU,8BAA8B,cAAI,OAAM;AAAA,UACtD,IAAI,eACH,6CAAC,SAAI,WAAU,+BAA+B,cAAI,aAAY;AAAA,WAElE;AAAA;AAAA;AAAA,IApBK,IAAI;AAAA,EAqBX,CACD,GACH;AAEJ;AAEA,SAAS,iBAAiB;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,SACE,6CAAC,SAAI,WAAU,aAAY,MAAK,SAAQ,mBAAiB,KAAK,SAAS,EAAE,IACrE,oBAAS,WAAW,CAAC,GAAG,IAAI,CAAC,QAAQ;AACrC,UAAM,UAAU,MAAM,SAAS,IAAI,KAAK;AACxC,WACE;AAAA,MAAC;AAAA;AAAA,QAEC,WAAW,mFACT,UACI,mCACA,qDACN;AAAA,QAEA;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,OAAO,IAAI;AAAA,cACX;AAAA,cACA,UAAU,CAAC,MAAM;AACf,oBAAI,EAAE,OAAO,QAAS,UAAS,CAAC,GAAG,OAAO,IAAI,KAAK,CAAC;AAAA,oBAC/C,UAAS,MAAM,OAAO,CAAC,MAAM,MAAM,IAAI,KAAK,CAAC;AAAA,cACpD;AAAA,cACA,WAAU;AAAA;AAAA,UACZ;AAAA,UACA,8CAAC,SACC;AAAA,yDAAC,SAAI,WAAU,8BAA8B,cAAI,OAAM;AAAA,YACtD,IAAI,eACH,6CAAC,SAAI,WAAU,+BAA+B,cAAI,aAAY;AAAA,aAElE;AAAA;AAAA;AAAA,MAtBK,IAAI;AAAA,IAuBX;AAAA,EAEJ,CAAC,GACH;AAEJ;AAEA,SAAS,WAAW;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,UAAU,SAAS,WAAW,CAAC;AACrC,SACE,6CAAC,SAAI,WAAU,aAAY,MAAK,cAAa,mBAAiB,KAAK,SAAS,EAAE,IAC3E,kBAAQ,IAAI,CAAC,QACZ;AAAA,IAAC;AAAA;AAAA,MAEC,WAAW,oFACT,UAAU,IAAI,QACV,mCACA,qDACN;AAAA,MAEA;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,MAAM,SAAS;AAAA,YACf,OAAO,IAAI;AAAA,YACX,SAAS,UAAU,IAAI;AAAA,YACvB,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,YACxC,WAAU;AAAA;AAAA,QACZ;AAAA,QACA,6CAAC,UAAK,WAAU,oCAAoC,cAAI,OAAM;AAAA,QAC9D,6CAAC,UAAK,WAAU,kBAAkB,cAAI,OAAM;AAAA;AAAA;AAAA,IAhBvC,IAAI;AAAA,EAiBX,CACD,GACH;AAEJ;AAEA,SAAS,UAAU;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAY;AAAA,MACZ,OAAO,SAAS;AAAA,MAChB,UAAU,CAAC,MAAM,SAAS,EAAE,OAAO,KAAK;AAAA,MACxC,WAAS;AAAA,MACT,WAAU;AAAA;AAAA,EACZ;AAEJ;AAEA,SAAS,UAAU;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,QAAQ,MAAM,SAAS,IAAI,QAAQ,CAAC,EAAE;AAC5C,QAAM,MAAM,WAAW,OAAO;AAC9B,QAAM,MAAM,WAAW,OAAO;AAE9B,QAAM,UAAU,CAAC,GAAW,MAAc;AACxC,UAAM,OAAO,CAAC,GAAG,KAAK;AACtB,SAAK,CAAC,IAAI;AACV,aAAS,IAAI;AAAA,EACf;AACA,QAAM,UAAU,MAAM;AACpB,QAAI,MAAM,SAAS,IAAK,UAAS,CAAC,GAAG,OAAO,EAAE,CAAC;AAAA,EACjD;AACA,QAAM,aAAa,CAAC,MAAc;AAChC,QAAI,MAAM,UAAU,EAAG;AACvB,aAAS,MAAM,OAAO,CAAC,GAAG,QAAQ,QAAQ,CAAC,CAAC;AAAA,EAC9C;AACA,QAAM,aAAa,MAAM,OAAO,CAAC,MAAM,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE;AAE5D,SACE,8CAAC,SACC;AAAA,iDAAC,QAAG,WAAU,aACX,gBAAM,IAAI,CAAC,MAAM,MAChB,8CAAC,QAAW,WAAU,2BACpB;AAAA,oDAAC,UAAK,WAAU,mDAAmD;AAAA,YAAI;AAAA,QAAE;AAAA,SAAC;AAAA,MAC1E;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,QAAQ,GAAG,EAAE,OAAO,KAAK;AAAA,UAC1C,WAAU;AAAA,UACV,aAAa,QAAQ,IAAI,CAAC;AAAA;AAAA,MAC5B;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS,MAAM,WAAW,CAAC;AAAA,UAC3B,UAAU,MAAM,UAAU;AAAA,UAC1B,WAAU;AAAA,UACV,cAAY,eAAe,IAAI,CAAC;AAAA,UACjC;AAAA;AAAA,MAED;AAAA,SAjBO,CAkBT,CACD,GACH;AAAA,IACA,8CAAC,SAAI,WAAU,0CACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAS;AAAA,UACT,UAAU,MAAM,UAAU;AAAA,UAC1B,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,MACC,aACC,8CAAC,UAAK,WAAU,oCACb;AAAA;AAAA,QAAW;AAAA,QAAI;AAAA,QAAI;AAAA,QAAE,QAAQ,WAAW,WAAM;AAAA,SACjD;AAAA,OAEJ;AAAA,KACF;AAEJ;AAEA,SAAS,eAAe;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,eAAe,SAAS,gBAAgB,CAAC;AAC/C,SACE,6CAAC,SAAI,WAAU,kEACZ,uBAAa,IAAI,CAAC,QACjB,8CAAC,SACC;AAAA,iDAAC,SAAI,WAAU,sCAAsC,cAAI,QAAO;AAAA,IAC/D,IAAI,aAAa,6CAAC,SAAI,WAAU,+BAA+B,cAAI,WAAU;AAAA,IAC9E,6CAAC,SAAI,WAAU,QACb;AAAA,MAAC;AAAA;AAAA,QACC,UAAU;AAAA,QACV,OAAO,MAAM,IAAI,EAAE;AAAA,QACnB,UAAU,CAAC,SAAS,SAAS,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC;AAAA;AAAA,IAC3D,GACF;AAAA,OATQ,IAAI,EAUd,CACD,GACH;AAEJ;AAEA,SAAS,cAAc;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,OAAO,MAAM,SAAS,IAAI,QAAQ,CAAC,CAAC,CAAgC;AAC1E,QAAM,aAAa,SAAS,cAAc,CAAC;AAC3C,QAAM,MAAM,SAAS,WAAW,OAAO;AACvC,QAAM,MAAM,SAAS,WAAW,OAAO;AAEvC,QAAM,YAAY,CAAC,GAAW,UAAuC;AACnE,UAAM,OAAO,CAAC,GAAG,IAAI;AACrB,SAAK,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,GAAG,GAAG,MAAM;AACjC,aAAS,IAAI;AAAA,EACf;AACA,QAAM,SAAS,MAAM;AACnB,QAAI,KAAK,SAAS,IAAK,UAAS,CAAC,GAAG,MAAM,CAAC,CAAgC,CAAC;AAAA,EAC9E;AACA,QAAM,YAAY,CAAC,MAAc;AAC/B,QAAI,KAAK,UAAU,EAAG;AACtB,aAAS,KAAK,OAAO,CAAC,GAAG,QAAQ,QAAQ,CAAC,CAAC;AAAA,EAC7C;AAEA,SACE,8CAAC,SAAI,WAAU,aACZ;AAAA,SAAK,IAAI,CAAC,KAAK,MACd,8CAAC,SAAY,WAAU,wDACrB;AAAA,oDAAC,SAAI,WAAU,0CACb;AAAA,sDAAC,UAAK,WAAU,6DAA4D;AAAA;AAAA,UACpE,IAAI;AAAA,WACZ;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,MAAK;AAAA,YACL,SAAS,MAAM,UAAU,CAAC;AAAA,YAC1B,UAAU,KAAK,UAAU;AAAA,YACzB,WAAU;AAAA,YACV,cAAY,eAAe,IAAI,CAAC;AAAA,YACjC;AAAA;AAAA,QAED;AAAA,SACF;AAAA,MACA,6CAAC,SAAI,WAAU,aACZ,qBAAW,IAAI,CAAC,QACf,8CAAC,SACC;AAAA,qDAAC,SAAI,WAAU,sCAAsC,cAAI,QAAO;AAAA,QAC/D,IAAI,aACH,6CAAC,SAAI,WAAU,+BAA+B,cAAI,WAAU;AAAA,QAE9D,6CAAC,SAAI,WAAU,QACb;AAAA,UAAC;AAAA;AAAA,YACC,UAAU;AAAA,YACV,OAAO,IAAI,IAAI,EAAE;AAAA,YACjB,UAAU,CAAC,SAAS,UAAU,GAAG,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC;AAAA;AAAA,QACrD,GACF;AAAA,WAXQ,IAAI,EAYd,CACD,GACH;AAAA,SA/BQ,CAgCV,CACD;AAAA,IACD;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS;AAAA,QACT,UAAU,KAAK,UAAU;AAAA,QACzB,WAAU;AAAA,QACX;AAAA;AAAA,IAED;AAAA,KACF;AAEJ;AAEA,SAAS,gBAAgB;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,aAAa,SAAS,cAAc,CAAC;AAE3C,QAAM,UAAU,CAAC,UAA2B;AAC1C,QAAI,CAAC,SAAS,MAAM,WAAW,EAAG;AAClC,UAAM,UAAuB,MAAM,KAAK,KAAK,EAAE,IAAI,CAAC,OAAO;AAAA,MACzD,MAAM;AAAA,MACN,UAAU,CAAC;AAAA,IACb,EAAE;AACF,aAAS,CAAC,GAAG,OAAO,GAAG,OAAO,CAAC;AAAA,EACjC;AAEA,QAAM,iBAAiB,CAAC,GAAW,UAAuC;AACxE,UAAM,OAAO,CAAC,GAAG,KAAK;AACtB,SAAK,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,GAAG,UAAU,EAAE,GAAG,KAAK,CAAC,EAAE,UAAU,GAAG,MAAM,EAAE;AACpE,aAAS,IAAI;AAAA,EACf;AACA,QAAM,cAAc,CAAC,MAAc,SAAS,MAAM,OAAO,CAAC,GAAG,QAAQ,QAAQ,CAAC,CAAC;AAE/E,QAAM,SAAS,CAAC,MAAuC;AACrD,MAAE,eAAe;AACjB,YAAQ,EAAE,aAAa,KAAK;AAAA,EAC9B;AACA,QAAM,aAAa,CAAC,MAAuC,EAAE,eAAe;AAE5E,SACE,8CAAC,SAAI,WAAU,aACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA,WAAU;AAAA,QAEV;AAAA,wDAAC,OAAE,WAAU,0BAAyB;AAAA;AAAA,YACF;AAAA,YAClC,8CAAC,WAAM,WAAU,oEAAmE;AAAA;AAAA,cAElF;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,UAAQ;AAAA,kBACR,WAAU;AAAA,kBACV,UAAU,CAAC,MAAM,QAAQ,EAAE,OAAO,KAAK;AAAA;AAAA,cACzC;AAAA,eACF;AAAA,aACF;AAAA,UACA,6CAAC,OAAE,WAAU,+BAA8B,8EAE3C;AAAA;AAAA;AAAA,IACF;AAAA,IAEC,MAAM,SAAS,KACd,6CAAC,QAAG,WAAU,aACX,gBAAM,IAAI,CAAC,OAAO,MAAM;AACvB,YAAM,OAAO,MAAM,KAAK;AACxB,YAAM,OAAO,UAAU,MAAM,OAAO,MAAM,KAAK,OAAO;AACtD,aACE,8CAAC,QAAW,WAAU,wDACpB;AAAA,sDAAC,SAAI,WAAU,qCACb;AAAA,wDAAC,SACC;AAAA,yDAAC,SAAI,WAAU,8BAA8B,gBAAK;AAAA,YACjD,OAAO,SAAS,YACf,8CAAC,SAAI,WAAU,oCACX;AAAA,sBAAO,MAAM,QAAQ,CAAC;AAAA,cAAE;AAAA,eAC5B;AAAA,aAEJ;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAM,YAAY,CAAC;AAAA,cAC5B,WAAU;AAAA,cACV,cAAY,UAAU,IAAI;AAAA,cAC3B;AAAA;AAAA,UAED;AAAA,WACF;AAAA,QACC,WAAW,SAAS,KACnB,6CAAC,SAAI,WAAU,kBACZ,qBAAW,IAAI,CAAC,QACf,8CAAC,SACC;AAAA,uDAAC,SAAI,WAAU,sCAAsC,cAAI,QAAO;AAAA,UAChE,6CAAC,SAAI,WAAU,QACb;AAAA,YAAC;AAAA;AAAA,cACC,UAAU;AAAA,cACV,OAAO,MAAM,SAAS,IAAI,EAAE;AAAA,cAC5B,UAAU,CAAC,SAAS,eAAe,GAAG,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC;AAAA;AAAA,UAC1D,GACF;AAAA,aARQ,IAAI,EASd,CACD,GACH;AAAA,WAjCK,CAmCT;AAAA,IAEJ,CAAC,GACH;AAAA,KAEJ;AAEJ;AAEA,SAAS,oBAAoB,EAAE,UAAU,GAAyB;AAIhE,SACE,8CAAC,SAAI,WAAU,+EAA8E;AAAA;AAAA,IAC1D;AAAA,IACjC,6CAAC,UAAK,WAAU,aAAa,iBAAO,SAAS,GAAE;AAAA,KACjD;AAEJ;;;AC9pBO,SAAS,WAAW,OAA6B;AACtD,MAAI,UAAU,UAAa,UAAU,KAAM,QAAO;AAClD,MAAI,OAAO,UAAU,SAAU,QAAO,MAAM,KAAK,EAAE,SAAS;AAC5D,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,SAAS;AAChD,MAAI,OAAO,UAAU,SAAU,QAAO,OAAO,KAAK,KAAK,EAAE,SAAS;AAClE,SAAO;AACT;AAMO,SAAS,eAAe,UAA6B,OAAoB,SAAS,IAAY;AACnG,MAAI,CAAC,WAAW,KAAK,EAAG,QAAO;AAC/B,UAAQ,SAAS,WAAW;AAAA,IAC1B,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,SAAS,OAAO,KAAK,GAAG,MAAM;AAAA,IACvC,KAAK,iBAAiB;AACpB,YAAM,IAAI,OAAO,KAAK;AACtB,YAAM,QAAQ,SAAS,SAAS,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG;AAC5D,aAAO,SAAS,SAAS,GAAG,MAAM;AAAA,IACpC;AAAA,IACA,KAAK;AAAA,IACL,KAAK,QAAQ;AACX,YAAM,MAAM;AACZ,YAAM,SAAS,IAAI,IAAI,CAAC,MAAM;AAC5B,cAAM,QAAQ,SAAS,SAAS,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG;AAC5D,eAAO,SAAS;AAAA,MAClB,CAAC;AACD,aAAO,SAAS,OAAO,KAAK,IAAI,GAAG,MAAM;AAAA,IAC3C;AAAA,IACA,KAAK,aAAa;AAEhB,YAAM,MAAM;AACZ,YAAM,OAAO,SAAS,gBAAgB,CAAC;AACvC,iBAAW,OAAO,MAAM;AACtB,cAAM,SAAS,IAAI,IAAI,EAAE;AACzB,YAAI,WAAW,MAAM,GAAG;AACtB,iBAAO,SAAS,eAAe,KAAK,QAAQ,MAAM,GAAG,MAAM;AAAA,QAC7D;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,IACA,KAAK,YAAY;AACf,YAAM,OAAO;AACb,aAAO,GAAG,KAAK,MAAM,QAAQ,KAAK,WAAW,IAAI,KAAK,GAAG;AAAA,IAC3D;AAAA,IACA,KAAK,eAAe;AAClB,YAAM,QAAQ;AACd,aAAO,GAAG,MAAM,MAAM,QAAQ,MAAM,WAAW,IAAI,KAAK,GAAG;AAAA,IAC7D;AAAA,IACA;AACE,aAAO;AAAA,EACX;AACF;AAOO,SAAS,cAAc,UAA6B,OAA4B;AACrF,MAAI,CAAC,WAAW,KAAK,EAAG,QAAO;AAC/B,UAAQ,SAAS,WAAW;AAAA,IAC1B,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO,OAAO,KAAK;AAAA,IACrB,KAAK,iBAAiB;AACpB,YAAM,IAAI,OAAO,KAAK;AACtB,YAAM,QAAQ,SAAS,SAAS,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG;AAC5D,aAAO,SAAS;AAAA,IAClB;AAAA,IACA,KAAK;AAAA,IACL,KAAK,QAAQ;AACX,YAAM,MAAM;AACZ,YAAM,SAAS,IAAI,IAAI,CAAC,MAAM,SAAS,SAAS,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,SAAS,CAAC;AACtF,aAAO,OAAO,KAAK,WAAM,EAAE,QAAQ,KAAK,SAAI;AAAA,IAC9C;AAAA,IACA,KAAK,aAAa;AAChB,YAAM,MAAM;AACZ,YAAM,OAAO,SAAS,gBAAgB,CAAC;AACvC,YAAM,QAAkB,CAAC;AACzB,iBAAW,OAAO,MAAM;AACtB,cAAM,SAAS,IAAI,IAAI,EAAE;AACzB,YAAI,WAAW,MAAM,GAAG;AACtB,gBAAM,KAAK,GAAG,IAAI,MAAM,KAAK,eAAe,KAAK,QAAQ,GAAG,CAAC,EAAE;AAAA,QACjE;AAAA,MACF;AACA,aAAO,MAAM,KAAK,IAAI;AAAA,IACxB;AAAA,IACA,KAAK,YAAY;AACf,YAAM,OAAO;AACb,YAAM,aAAa,SAAS,cAAc,CAAC;AAC3C,YAAM,UAAU,KAAK,IAAI,CAAC,KAAK,MAAM;AACnC,cAAM,QAAkB,CAAC,QAAQ,IAAI,CAAC,GAAG;AACzC,mBAAW,OAAO,YAAY;AAC5B,gBAAM,SAAS,IAAI,IAAI,EAAE;AACzB,cAAI,WAAW,MAAM,GAAG;AACtB,kBAAM,KAAK,KAAK,IAAI,MAAM,KAAK,eAAe,KAAK,QAAQ,GAAG,CAAC,EAAE;AAAA,UACnE;AAAA,QACF;AACA,eAAO,MAAM,KAAK,IAAI;AAAA,MACxB,CAAC;AACD,aAAO,QAAQ,KAAK,IAAI;AAAA,IAC1B;AAAA,IACA,KAAK,eAAe;AAClB,YAAM,QAAQ;AACd,aAAO,MACJ,IAAI,CAAC,GAAG,MAAM,GAAG,IAAI,CAAC,KAAK,EAAE,KAAK,IAAI,EAAE,EACxC,KAAK,IAAI;AAAA,IACd;AAAA,IACA;AACE,aAAO;AAAA,EACX;AACF;AAEA,SAAS,SAAS,GAAW,QAAwB;AACnD,SAAO,EAAE,SAAS,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC,IAAI,WAAM;AAC5D;;;AC5FM,IAAAC,sBAAA;AANC,SAAS,cAAc,EAAE,WAAW,cAAc,SAAS,iBAAiB,GAAU;AAC3F,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,cAAW;AAAA,MAEX;AAAA,qDAAC,QAAG,WAAU,kEAAiE,0BAE/E;AAAA,QACA,6CAAC,QAAG,WAAU,aACX,oBAAU,IAAI,CAAC,GAAG,MAAM;AACvB,gBAAM,SAAS,QAAQ,EAAE,EAAE;AAC3B,gBAAM,WAAW,WAAW,MAAM;AAClC,gBAAM,YAAY,MAAM;AACxB,gBAAM,UAAU,WAAW,eAAe,GAAG,MAAM,IAAI;AAEvD,iBACE,6CAAC,QACC;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAM,iBAAiB,CAAC;AAAA,cACjC,WAAW,4DACT,YACI,mCACA,WACA,wDACA,2DACN;AAAA,cAEA,wDAAC,SAAI,WAAU,0BACb;AAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAW,4BACT,YACI,oBACA,WACA,mBACA,gBACN;AAAA,oBAEC;AAAA,6BAAO,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG;AAAA,sBAAE;AAAA;AAAA;AAAA,gBAClC;AAAA,gBACA,8CAAC,SAAI,WAAU,aACb;AAAA;AAAA,oBAAC;AAAA;AAAA,sBACC,WAAW,uBACT,WAAW,mBAAmB,gBAChC;AAAA,sBAEC,YAAE,OAAO,SAAS,KAAK,EAAE,OAAO,MAAM,GAAG,EAAE,IAAI,WAAM,EAAE;AAAA;AAAA,kBAC1D;AAAA,kBACC,YACC,6CAAC,SAAI,WAAU,mDACZ,mBACH;AAAA,mBAEJ;AAAA,iBACF;AAAA;AAAA,UACF,KAvCO,EAAE,EAwCX;AAAA,QAEJ,CAAC,GACH;AAAA;AAAA;AAAA,EACF;AAEJ;;;AC7DM,IAAAC,sBAAA;AAHC,SAAS,cAAc,EAAE,WAAW,SAAS,YAAY,QAAQ,WAAW,GAAU;AAC3F,SACE,8CAAC,SAAI,WAAU,oBACb;AAAA,iDAAC,QAAG,WAAU,gEAA+D,iCAE7E;AAAA,IACA,6CAAC,OAAE,WAAU,+BAA8B,wIAG3C;AAAA,IAEA,6CAAC,QAAG,WAAU,kDACX,oBAAU,IAAI,CAAC,GAAG,MAAM;AACvB,YAAM,SAAS,QAAQ,EAAE,EAAE;AAC3B,YAAM,WAAW,WAAW,MAAM;AAClC,YAAM,UAAU,WAAW,cAAc,GAAG,MAAM,IAAI;AAEtD;AAAA;AAAA;AAAA;AAAA;AAAA,QAKE;AAAA,UAAC;AAAA;AAAA,YAEC,WAAU;AAAA,YAEV;AAAA,4DAAC,QAAG,WAAU,qCACZ;AAAA,6DAAC,UAAK,eAAY,QAAO,WAAU,yCAChC,iBAAO,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG,GAChC;AAAA,gBACA,6CAAC,UAAK,WAAU,sCAAsC,YAAE,QAAO;AAAA,gBAC/D;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,SAAS,MAAM,OAAO,CAAC;AAAA,oBACvB,cAAY,SAAS,EAAE,MAAM;AAAA,oBAC7B,WAAU;AAAA,oBACX;AAAA;AAAA,gBAED;AAAA,iBACF;AAAA,cACA,6CAAC,QAAG,WAAU,0CACZ,uDAAC,UAAK,WAAU,kDACb,qBACC,UAEA,6CAAC,UAAK,WAAU,yBAAwB,0BAAY,GAExD,GACF;AAAA;AAAA;AAAA,UAzBK,EAAE;AAAA,QA0BT;AAAA;AAAA,IAEJ,CAAC,GACH;AAAA,IAKA,8CAAC,SAAI,WAAU,8DACb;AAAA,mDAAC,QAAG,WAAU,uCAAsC,+BAAiB;AAAA,MACrE,6CAAC,OAAE,WAAU,uBAAsB,kTAKnC;AAAA,MACA,8CAAC,OAAE,WAAU,+BACX;AAAA,qDAAC,UAAK,WAAU,eAAc,uBAAS;AAAA,QAAO;AAAA,SAGhD;AAAA,OACF;AAAA,IAEA,6CAAC,SAAI,WAAU,yBACb;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS;AAAA,QACT,UAAU;AAAA,QACV,WAAU;AAAA,QAET,uBAAa,kCAA6B;AAAA;AAAA,IAC7C,GACF;AAAA,KACF;AAEJ;","names":["import_jsx_runtime","import_jsx_runtime","import_jsx_runtime"]}
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ function ProgressBar({ current, total, estimatedMinutesRemaining }) {
10
10
  " of ",
11
11
  total
12
12
  ] }),
13
- /* @__PURE__ */ jsxs("span", { className: "font-mono text-xs text-stone-500", children: [
13
+ /* @__PURE__ */ jsxs("span", { className: "font-mono text-xs text-stone-700", children: [
14
14
  "~",
15
15
  estimatedMinutesRemaining,
16
16
  " min remaining"
@@ -102,7 +102,7 @@ function QuestionCard({
102
102
  "\u201D"
103
103
  ] }, i)) })
104
104
  ] }),
105
- !question.required && question.skipConsequence && /* @__PURE__ */ jsxs2("p", { className: "mt-6 text-sm text-stone-500", children: [
105
+ !question.required && question.skipConsequence && /* @__PURE__ */ jsxs2("p", { className: "mt-6 text-sm text-stone-700", children: [
106
106
  /* @__PURE__ */ jsx2("span", { className: "font-medium", children: "If you skip this:" }),
107
107
  " ",
108
108
  question.skipConsequence
@@ -140,7 +140,7 @@ function InputForType({ question, value, onChange }) {
140
140
  case "scale":
141
141
  return /* @__PURE__ */ jsx2(ScaleInput, { question, value, onChange });
142
142
  case "date":
143
- return /* @__PURE__ */ jsx2(DateInput, { value, onChange });
143
+ return /* @__PURE__ */ jsx2(DateInput, { value, onChange, ariaLabel: question.prompt });
144
144
  case "composite":
145
145
  return /* @__PURE__ */ jsx2(CompositeInput, { question, value: value ?? {}, onChange });
146
146
  case "repeater":
@@ -266,18 +266,23 @@ function ScaleInput({
266
266
  className: "h-4 w-4 text-forest-700"
267
267
  }
268
268
  ),
269
- /* @__PURE__ */ jsx2("span", { className: "font-mono text-sm text-stone-500", children: opt.value }),
269
+ /* @__PURE__ */ jsx2("span", { className: "font-mono text-sm text-stone-700", children: opt.value }),
270
270
  /* @__PURE__ */ jsx2("span", { className: "text-stone-900", children: opt.label })
271
271
  ]
272
272
  },
273
273
  opt.value
274
274
  )) });
275
275
  }
276
- function DateInput({ value, onChange }) {
276
+ function DateInput({
277
+ value,
278
+ onChange,
279
+ ariaLabel
280
+ }) {
277
281
  return /* @__PURE__ */ jsx2(
278
282
  "input",
279
283
  {
280
284
  type: "date",
285
+ "aria-label": ariaLabel,
281
286
  value: value ?? "",
282
287
  onChange: (e) => onChange(e.target.value),
283
288
  autoFocus: true,
@@ -308,7 +313,7 @@ function ListInput({
308
313
  const validCount = items.filter((v) => v.trim().length > 0).length;
309
314
  return /* @__PURE__ */ jsxs2("div", { children: [
310
315
  /* @__PURE__ */ jsx2("ul", { className: "space-y-2", children: items.map((item, i) => /* @__PURE__ */ jsxs2("li", { className: "flex items-center gap-2", children: [
311
- /* @__PURE__ */ jsxs2("span", { className: "w-6 text-right font-mono text-xs text-stone-400", children: [
316
+ /* @__PURE__ */ jsxs2("span", { className: "w-6 text-right font-mono text-xs text-stone-600", children: [
312
317
  i + 1,
313
318
  "."
314
319
  ] }),
@@ -328,7 +333,7 @@ function ListInput({
328
333
  type: "button",
329
334
  onClick: () => removeItem(i),
330
335
  disabled: items.length <= 1,
331
- className: "btn-ghost text-stone-500 disabled:opacity-30",
336
+ className: "btn-ghost text-stone-700 disabled:opacity-30",
332
337
  "aria-label": `Remove item ${i + 1}`,
333
338
  children: "\xD7"
334
339
  }
@@ -345,7 +350,7 @@ function ListInput({
345
350
  children: "+ Add item"
346
351
  }
347
352
  ),
348
- listRange && /* @__PURE__ */ jsxs2("span", { className: "font-mono text-xs text-stone-500", children: [
353
+ listRange && /* @__PURE__ */ jsxs2("span", { className: "font-mono text-xs text-stone-700", children: [
349
354
  validCount,
350
355
  " / ",
351
356
  min,
@@ -398,7 +403,7 @@ function RepeaterInput({
398
403
  return /* @__PURE__ */ jsxs2("div", { className: "space-y-4", children: [
399
404
  rows.map((row, i) => /* @__PURE__ */ jsxs2("div", { className: "rounded-lg border-2 border-stone-200 bg-stone-50 p-4", children: [
400
405
  /* @__PURE__ */ jsxs2("div", { className: "mb-3 flex items-center justify-between", children: [
401
- /* @__PURE__ */ jsxs2("span", { className: "font-mono text-xs uppercase tracking-wider text-stone-500", children: [
406
+ /* @__PURE__ */ jsxs2("span", { className: "font-mono text-xs uppercase tracking-wider text-stone-700", children: [
402
407
  "Item ",
403
408
  i + 1
404
409
  ] }),
@@ -408,7 +413,7 @@ function RepeaterInput({
408
413
  type: "button",
409
414
  onClick: () => removeRow(i),
410
415
  disabled: rows.length <= min,
411
- className: "btn-ghost text-xs text-stone-500 disabled:opacity-30",
416
+ className: "btn-ghost text-xs text-stone-700 disabled:opacity-30",
412
417
  "aria-label": `Remove item ${i + 1}`,
413
418
  children: "Remove"
414
419
  }
@@ -488,7 +493,7 @@ function FileUploadInput({
488
493
  )
489
494
  ] })
490
495
  ] }),
491
- /* @__PURE__ */ jsx2("p", { className: "mt-1 text-xs text-stone-500", children: "You'll add a title, author, and description for each file below." })
496
+ /* @__PURE__ */ jsx2("p", { className: "mt-1 text-xs text-stone-700", children: "You'll add a title, author, and description for each file below." })
492
497
  ]
493
498
  }
494
499
  ),
@@ -499,7 +504,7 @@ function FileUploadInput({
499
504
  /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-between", children: [
500
505
  /* @__PURE__ */ jsxs2("div", { children: [
501
506
  /* @__PURE__ */ jsx2("div", { className: "font-medium text-stone-900", children: name }),
502
- typeof size === "number" && /* @__PURE__ */ jsxs2("div", { className: "font-mono text-xs text-stone-500", children: [
507
+ typeof size === "number" && /* @__PURE__ */ jsxs2("div", { className: "font-mono text-xs text-stone-700", children: [
503
508
  (size / 1024).toFixed(1),
504
509
  " KB"
505
510
  ] })
@@ -509,7 +514,7 @@ function FileUploadInput({
509
514
  {
510
515
  type: "button",
511
516
  onClick: () => removeEntry(i),
512
- className: "btn-ghost text-xs text-stone-500",
517
+ className: "btn-ghost text-xs text-stone-700",
513
518
  "aria-label": `Remove ${name}`,
514
519
  children: "Remove"
515
520
  }
@@ -531,7 +536,7 @@ function FileUploadInput({
531
536
  ] });
532
537
  }
533
538
  function UnknownTypeFallback({ inputType }) {
534
- return /* @__PURE__ */ jsxs2("div", { className: "rounded-lg border-2 border-stone-300 bg-stone-50 p-4 text-sm text-stone-500", children: [
539
+ return /* @__PURE__ */ jsxs2("div", { className: "rounded-lg border-2 border-stone-300 bg-stone-50 p-4 text-sm text-stone-700", children: [
535
540
  "Unsupported question input type:",
536
541
  " ",
537
542
  /* @__PURE__ */ jsx2("code", { className: "font-mono", children: String(inputType) })
@@ -658,7 +663,7 @@ function AnswerSidebar({ questions, currentIndex, answers, onSelectQuestion }) {
658
663
  className: "sticky top-24 hidden max-h-[calc(100vh-6rem)] overflow-y-auto lg:block",
659
664
  "aria-label": "Completed answers",
660
665
  children: [
661
- /* @__PURE__ */ jsx3("h3", { className: "mb-3 font-mono text-xs uppercase tracking-wider text-stone-500", children: "Your answers" }),
666
+ /* @__PURE__ */ jsx3("h3", { className: "mb-3 font-mono text-xs uppercase tracking-wider text-stone-700", children: "Your answers" }),
662
667
  /* @__PURE__ */ jsx3("ol", { className: "space-y-3", children: questions.map((q, i) => {
663
668
  const answer = answers[q.id];
664
669
  const answered = isAnswered(answer);
@@ -674,7 +679,7 @@ function AnswerSidebar({ questions, currentIndex, answers, onSelectQuestion }) {
674
679
  /* @__PURE__ */ jsxs3(
675
680
  "span",
676
681
  {
677
- className: `mt-0.5 font-mono text-xs ${isCurrent ? "text-forest-700" : answered ? "text-stone-500" : "text-stone-400"}`,
682
+ className: `mt-0.5 font-mono text-xs ${isCurrent ? "text-forest-700" : answered ? "text-stone-700" : "text-stone-600"}`,
678
683
  children: [
679
684
  String(i + 1).padStart(2, "0"),
680
685
  "."
@@ -685,11 +690,11 @@ function AnswerSidebar({ questions, currentIndex, answers, onSelectQuestion }) {
685
690
  /* @__PURE__ */ jsx3(
686
691
  "div",
687
692
  {
688
- className: `text-xs font-medium ${answered ? "text-stone-900" : "text-stone-500"}`,
693
+ className: `text-xs font-medium ${answered ? "text-stone-900" : "text-stone-700"}`,
689
694
  children: q.prompt.length > 50 ? q.prompt.slice(0, 50) + "\u2026" : q.prompt
690
695
  }
691
696
  ),
692
- answered && /* @__PURE__ */ jsx3("div", { className: "mt-1 text-xs italic text-stone-500 line-clamp-1", children: preview })
697
+ answered && /* @__PURE__ */ jsx3("div", { className: "mt-1 text-xs italic text-stone-700 line-clamp-1", children: preview })
693
698
  ] })
694
699
  ] })
695
700
  }
@@ -710,22 +715,36 @@ function ReviewSummary({ questions, answers, onGenerate, onEdit, generating }) {
710
715
  const answer = answers[q.id];
711
716
  const answered = isAnswered(answer);
712
717
  const display = answered ? summarizeLong(q, answer) : "";
713
- return /* @__PURE__ */ jsxs4("div", { className: "flex gap-4 border-b border-stone-200 pb-6", children: [
714
- /* @__PURE__ */ jsx4("span", { className: "font-mono text-sm text-stone-400 pt-1", children: String(i + 1).padStart(2, "0") }),
715
- /* @__PURE__ */ jsxs4("div", { className: "flex-grow", children: [
716
- /* @__PURE__ */ jsx4("dt", { className: "text-sm font-medium text-stone-900", children: q.prompt }),
717
- /* @__PURE__ */ jsx4("dd", { className: "mt-2 text-stone-900 whitespace-pre-wrap", children: answered ? display : /* @__PURE__ */ jsx4("span", { className: "italic text-stone-400", children: "Not answered" }) })
718
- ] }),
719
- /* @__PURE__ */ jsx4(
720
- "button",
718
+ return (
719
+ // A <div> child of <dl> may contain ONLY dt/dd groups (HTML spec;
720
+ // axe definition-list), so the index + Edit button live INSIDE
721
+ // <dt>. Subgrid keeps all three columns aligned across dt and dd
722
+ // without extra wrappers.
723
+ /* @__PURE__ */ jsxs4(
724
+ "div",
721
725
  {
722
- type: "button",
723
- onClick: () => onEdit(i),
724
- className: "btn-ghost text-sm self-start",
725
- children: "Edit"
726
- }
726
+ className: "grid grid-cols-[auto_1fr_auto] gap-x-4 border-b border-stone-200 pb-6",
727
+ children: [
728
+ /* @__PURE__ */ jsxs4("dt", { className: "col-span-3 grid grid-cols-subgrid", children: [
729
+ /* @__PURE__ */ jsx4("span", { "aria-hidden": "true", className: "pt-1 font-mono text-sm text-stone-600", children: String(i + 1).padStart(2, "0") }),
730
+ /* @__PURE__ */ jsx4("span", { className: "text-sm font-medium text-stone-900", children: q.prompt }),
731
+ /* @__PURE__ */ jsx4(
732
+ "button",
733
+ {
734
+ type: "button",
735
+ onClick: () => onEdit(i),
736
+ "aria-label": `Edit: ${q.prompt}`,
737
+ className: "btn-ghost self-start text-sm",
738
+ children: "Edit"
739
+ }
740
+ )
741
+ ] }),
742
+ /* @__PURE__ */ jsx4("dd", { className: "col-span-3 mt-2 grid grid-cols-subgrid", children: /* @__PURE__ */ jsx4("span", { className: "col-start-2 whitespace-pre-wrap text-stone-900", children: answered ? display : /* @__PURE__ */ jsx4("span", { className: "italic text-stone-600", children: "Not answered" }) }) })
743
+ ]
744
+ },
745
+ q.id
727
746
  )
728
- ] }, q.id);
747
+ );
729
748
  }) }),
730
749
  /* @__PURE__ */ jsxs4("div", { className: "mt-10 rounded-lg border border-copper-300 bg-copper-50 p-6", children: [
731
750
  /* @__PURE__ */ jsx4("h3", { className: "font-display text-xl text-stone-900", children: "What happens next" }),
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ProgressBar.tsx","../src/QuestionCard.tsx","../src/summarize.ts","../src/AnswerSidebar.tsx","../src/ReviewSummary.tsx"],"sourcesContent":["'use client';\n\ninterface Props {\n current: number;\n total: number;\n estimatedMinutesRemaining: number;\n}\n\n/**\n * Linear progress indicator for the interview flow. Renders the\n * \"Question N of M\" caption, the estimated minutes remaining, and a\n * forest-700 fill bar at `(current / total) * 100%`.\n *\n * Iteration-1 visual identity (Phase B.2, 2026-05-06):\n * stone-100 surface with stone-200 border; forest-700 fill bar; stone-700\n * caption text. Pure-render component — no state-management dependency.\n *\n * Extracted from `apps/hub/src/components/interview/ProgressBar.tsx`\n * during iteration-3-B.1 (2026-05-07). No prop API change.\n */\nexport function ProgressBar({ current, total, estimatedMinutesRemaining }: Props) {\n const percent = Math.round((current / total) * 100);\n\n return (\n <div className=\"border-b border-stone-200 bg-stone-100 py-3 px-6\">\n <div className=\"mx-auto max-w-3xl\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"font-mono text-xs uppercase tracking-wider text-stone-700\">\n Question {current} of {total}\n </span>\n <span className=\"font-mono text-xs text-stone-500\">\n ~{estimatedMinutesRemaining} min remaining\n </span>\n </div>\n <div\n className=\"mt-2 h-1 w-full overflow-hidden rounded-full bg-stone-200\"\n role=\"progressbar\"\n aria-valuenow={percent}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={`Interview progress: ${percent}% complete`}\n >\n <div\n className=\"h-full bg-forest-700 transition-all duration-300 ease-out\"\n style={{ width: `${percent}%` }}\n />\n </div>\n </div>\n </div>\n );\n}\n","'use client';\n\nimport { useState, useEffect } from 'react';\nimport type {\n InterviewQuestion,\n AnswerValue,\n AnswerComposite,\n AnswerRepeater,\n AnswerFileUpload,\n FileEntry,\n} from './types';\n\ninterface Props {\n question: InterviewQuestion;\n /**\n * The currently-saved answer for this question (from the consumer's\n * state container). The component initializes its local form state\n * from this value and re-syncs when the question id changes.\n */\n existingAnswer?: AnswerValue;\n /**\n * Called when the user submits an answer. The consumer is expected to\n * persist the answer into its state container and then advance via\n * `onNext`.\n */\n onAnswerSubmit: (questionId: string, value: AnswerValue) => void;\n /** Called after `onAnswerSubmit` to advance to the next question. */\n onNext: () => void;\n /** Called when the user clicks the Back button. */\n onBack: () => void;\n isFirst: boolean;\n isLast: boolean;\n}\n\n/**\n * Default value to use when no `existingAnswer` is supplied. Depends on\n * the question's `inputType`.\n */\nfunction defaultValueFor(question: InterviewQuestion): AnswerValue {\n switch (question.inputType) {\n case 'multi-select':\n case 'list':\n return [];\n case 'composite':\n return {} as AnswerComposite;\n case 'repeater':\n case 'file-upload':\n return [];\n default:\n return '';\n }\n}\n\n/**\n * Whether the user's current local value satisfies the required check\n * for the question.\n */\nfunction canAdvanceWith(question: InterviewQuestion, value: AnswerValue): boolean {\n if (!question.required) return true;\n if (value === undefined || value === null) return false;\n if (typeof value === 'string') return value.trim().length > 0;\n if (Array.isArray(value)) return value.length > 0;\n if (typeof value === 'object') return Object.keys(value).length > 0;\n return true;\n}\n\n/**\n * Single question renderer. Handles all input types: short-text, long-text,\n * single-select, multi-select, scale, list, date, composite, repeater,\n * file-upload. Keyboard-navigable and screen-reader safe.\n *\n * **Decoupled from any state-management library.** Consumers receive the\n * existing answer + change handler as props.\n *\n * Iteration-1 visual identity: form input fields use stone-50 elevated\n * surface + stone-200 default border + forest-700 focus border. Selected\n * radio/checkbox option states use forest-700 border + forest-50 background.\n * The examples disclosure has border-l-2 frame in border-copper-200 —\n * preserved-decorative-copper role per iteration-2-blue-accent.md.\n */\nexport function QuestionCard({\n question,\n existingAnswer,\n onAnswerSubmit,\n onNext,\n onBack,\n isFirst,\n isLast,\n}: Props) {\n const [localValue, setLocalValue] = useState<AnswerValue>(\n existingAnswer ?? defaultValueFor(question),\n );\n\n // Sync when question changes (consumer flipped to a different question;\n // local form state should reflect that question's existing answer).\n useEffect(() => {\n setLocalValue(existingAnswer ?? defaultValueFor(question));\n }, [question.id, existingAnswer, question.inputType]);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n onAnswerSubmit(question.id, localValue);\n onNext();\n };\n\n const canAdvance = canAdvanceWith(question, localValue);\n\n return (\n <form onSubmit={handleSubmit} className=\"animate-slide-up\">\n {/* Prompt */}\n <h2 className=\"font-display text-3xl font-medium text-stone-900 sm:text-4xl\">\n {question.prompt}\n </h2>\n {question.subprompt && (\n <p className=\"mt-4 text-lg text-stone-700\">{question.subprompt}</p>\n )}\n\n {/* Input — dispatched per type */}\n <div className=\"mt-8\">\n <InputForType\n question={question}\n value={localValue}\n onChange={setLocalValue}\n />\n </div>\n\n {/* Examples */}\n {question.examples && question.examples.length > 0 && (\n <details className=\"mt-8\">\n <summary className=\"cursor-pointer text-sm font-medium text-forest-700 hover:text-forest-800\">\n Show examples from different fields\n </summary>\n {/* border-copper-200 PRESERVED: decorative-emphasis frame around\n illustrative content, same role as HeroSection's etymology box. */}\n <ul className=\"mt-4 space-y-3 border-l-2 border-copper-200 pl-5\">\n {question.examples.map((ex, i) => (\n <li key={i} className=\"text-sm italic text-stone-700\">\n “{ex}”\n </li>\n ))}\n </ul>\n </details>\n )}\n\n {/* Skip consequence (if applicable) */}\n {!question.required && question.skipConsequence && (\n <p className=\"mt-6 text-sm text-stone-500\">\n <span className=\"font-medium\">If you skip this:</span> {question.skipConsequence}\n </p>\n )}\n\n {/* Nav */}\n <div className=\"mt-10 flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={onBack}\n disabled={isFirst}\n className=\"btn-ghost disabled:opacity-40\"\n >\n ← Back\n </button>\n <div className=\"flex gap-3\">\n {!question.required && (\n <button type=\"button\" onClick={onNext} className=\"btn-ghost\">\n Skip\n </button>\n )}\n <button type=\"submit\" disabled={!canAdvance} className=\"btn-primary\">\n {isLast ? 'Review answers' : 'Continue →'}\n </button>\n </div>\n </div>\n </form>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Per-input-type renderers\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface InputProps {\n question: InterviewQuestion;\n value: AnswerValue;\n onChange: (next: AnswerValue) => void;\n}\n\nfunction InputForType({ question, value, onChange }: InputProps) {\n switch (question.inputType) {\n case 'short-text':\n return <ShortTextInput value={value as string} onChange={onChange} />;\n case 'long-text':\n return <LongTextInput value={value as string} onChange={onChange} />;\n case 'single-select':\n return <SingleSelectInput question={question} value={value as string} onChange={onChange} />;\n case 'multi-select':\n return <MultiSelectInput question={question} value={(value as string[]) ?? []} onChange={onChange} />;\n case 'list':\n return <ListInput value={(value as string[]) ?? []} onChange={onChange} listRange={question.listRange} />;\n case 'scale':\n return <ScaleInput question={question} value={value as string} onChange={onChange} />;\n case 'date':\n return <DateInput value={value as string} onChange={onChange} />;\n case 'composite':\n return <CompositeInput question={question} value={(value as AnswerComposite) ?? {}} onChange={onChange} />;\n case 'repeater':\n return <RepeaterInput question={question} value={(value as AnswerRepeater) ?? []} onChange={onChange} />;\n case 'file-upload':\n return <FileUploadInput question={question} value={(value as AnswerFileUpload) ?? []} onChange={onChange} />;\n default: {\n const _exhaustive: never = question.inputType;\n return <UnknownTypeFallback inputType={_exhaustive} />;\n }\n }\n}\n\nfunction ShortTextInput({ value, onChange }: { value: string; onChange: (v: string) => void }) {\n return (\n <input\n type=\"text\"\n value={value ?? ''}\n onChange={(e) => onChange(e.target.value)}\n autoFocus\n className=\"w-full rounded-lg border-2 border-stone-200 bg-stone-50 px-4 py-3 text-lg text-stone-900 focus:border-forest-700 focus:outline-none\"\n placeholder=\"Type your answer…\"\n />\n );\n}\n\nfunction LongTextInput({ value, onChange }: { value: string; onChange: (v: string) => void }) {\n return (\n <textarea\n value={value ?? ''}\n onChange={(e) => onChange(e.target.value)}\n autoFocus\n rows={5}\n className=\"w-full rounded-lg border-2 border-stone-200 bg-stone-50 px-4 py-3 text-lg text-stone-900 focus:border-forest-700 focus:outline-none\"\n placeholder=\"Type your answer…\"\n />\n );\n}\n\nfunction SingleSelectInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: string;\n onChange: (v: string) => void;\n}) {\n return (\n <div className=\"space-y-3\" role=\"radiogroup\" aria-labelledby={`q-${question.id}`}>\n {(question.options ?? []).map((opt) => (\n <label\n key={opt.value}\n className={`flex cursor-pointer items-start gap-3 rounded-lg border-2 p-4 transition-colors ${\n value === opt.value\n ? 'border-forest-700 bg-forest-50'\n : 'border-stone-200 bg-stone-50 hover:border-stone-400'\n }`}\n >\n <input\n type=\"radio\"\n name={question.id}\n value={opt.value}\n checked={value === opt.value}\n onChange={(e) => onChange(e.target.value)}\n className=\"mt-1 h-4 w-4 text-forest-700\"\n />\n <div>\n <div className=\"font-medium text-stone-900\">{opt.label}</div>\n {opt.description && (\n <div className=\"mt-1 text-sm text-stone-700\">{opt.description}</div>\n )}\n </div>\n </label>\n ))}\n </div>\n );\n}\n\nfunction MultiSelectInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: string[];\n onChange: (v: string[]) => void;\n}) {\n return (\n <div className=\"space-y-2\" role=\"group\" aria-labelledby={`q-${question.id}`}>\n {(question.options ?? []).map((opt) => {\n const checked = value.includes(opt.value);\n return (\n <label\n key={opt.value}\n className={`flex cursor-pointer items-start gap-3 rounded-lg border-2 p-4 transition-colors ${\n checked\n ? 'border-forest-700 bg-forest-50'\n : 'border-stone-200 bg-stone-50 hover:border-stone-400'\n }`}\n >\n <input\n type=\"checkbox\"\n value={opt.value}\n checked={checked}\n onChange={(e) => {\n if (e.target.checked) onChange([...value, opt.value]);\n else onChange(value.filter((v) => v !== opt.value));\n }}\n className=\"mt-1 h-4 w-4 text-forest-700\"\n />\n <div>\n <div className=\"font-medium text-stone-900\">{opt.label}</div>\n {opt.description && (\n <div className=\"mt-1 text-sm text-stone-700\">{opt.description}</div>\n )}\n </div>\n </label>\n );\n })}\n </div>\n );\n}\n\nfunction ScaleInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: string;\n onChange: (v: string) => void;\n}) {\n const options = question.options ?? [];\n return (\n <div className=\"space-y-3\" role=\"radiogroup\" aria-labelledby={`q-${question.id}`}>\n {options.map((opt) => (\n <label\n key={opt.value}\n className={`flex cursor-pointer items-center gap-3 rounded-lg border-2 p-3 transition-colors ${\n value === opt.value\n ? 'border-forest-700 bg-forest-50'\n : 'border-stone-200 bg-stone-50 hover:border-stone-400'\n }`}\n >\n <input\n type=\"radio\"\n name={question.id}\n value={opt.value}\n checked={value === opt.value}\n onChange={(e) => onChange(e.target.value)}\n className=\"h-4 w-4 text-forest-700\"\n />\n <span className=\"font-mono text-sm text-stone-500\">{opt.value}</span>\n <span className=\"text-stone-900\">{opt.label}</span>\n </label>\n ))}\n </div>\n );\n}\n\nfunction DateInput({ value, onChange }: { value: string; onChange: (v: string) => void }) {\n return (\n <input\n type=\"date\"\n value={value ?? ''}\n onChange={(e) => onChange(e.target.value)}\n autoFocus\n className=\"rounded-lg border-2 border-stone-200 bg-stone-50 px-4 py-3 text-lg text-stone-900 focus:border-forest-700 focus:outline-none\"\n />\n );\n}\n\nfunction ListInput({\n value,\n onChange,\n listRange,\n}: {\n value: string[];\n onChange: (v: string[]) => void;\n listRange?: { min: number; max: number };\n}) {\n const items = value.length > 0 ? value : [''];\n const min = listRange?.min ?? 0;\n const max = listRange?.max ?? Infinity;\n\n const setItem = (i: number, v: string) => {\n const next = [...items];\n next[i] = v;\n onChange(next);\n };\n const addItem = () => {\n if (items.length < max) onChange([...items, '']);\n };\n const removeItem = (i: number) => {\n if (items.length <= 1) return;\n onChange(items.filter((_, idx) => idx !== i));\n };\n const validCount = items.filter((v) => v.trim().length > 0).length;\n\n return (\n <div>\n <ul className=\"space-y-2\">\n {items.map((item, i) => (\n <li key={i} className=\"flex items-center gap-2\">\n <span className=\"w-6 text-right font-mono text-xs text-stone-400\">{i + 1}.</span>\n <input\n type=\"text\"\n value={item}\n onChange={(e) => setItem(i, e.target.value)}\n className=\"flex-grow rounded-lg border-2 border-stone-200 bg-stone-50 px-3 py-2 text-stone-900 focus:border-forest-700 focus:outline-none\"\n placeholder={`Item ${i + 1}`}\n />\n <button\n type=\"button\"\n onClick={() => removeItem(i)}\n disabled={items.length <= 1}\n className=\"btn-ghost text-stone-500 disabled:opacity-30\"\n aria-label={`Remove item ${i + 1}`}\n >\n ×\n </button>\n </li>\n ))}\n </ul>\n <div className=\"mt-3 flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={addItem}\n disabled={items.length >= max}\n className=\"text-sm font-medium text-forest-700 hover:text-forest-800 disabled:opacity-40\"\n >\n + Add item\n </button>\n {listRange && (\n <span className=\"font-mono text-xs text-stone-500\">\n {validCount} / {min}–{max === Infinity ? '∞' : max}\n </span>\n )}\n </div>\n </div>\n );\n}\n\nfunction CompositeInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: AnswerComposite;\n onChange: (v: AnswerComposite) => void;\n}) {\n const subQuestions = question.subQuestions ?? [];\n return (\n <div className=\"space-y-6 rounded-lg border-2 border-stone-200 bg-stone-50 p-4\">\n {subQuestions.map((sub) => (\n <div key={sub.id}>\n <div className=\"text-sm font-medium text-stone-900\">{sub.prompt}</div>\n {sub.subprompt && <div className=\"mt-1 text-xs text-stone-700\">{sub.subprompt}</div>}\n <div className=\"mt-2\">\n <InputForType\n question={sub}\n value={value[sub.id]}\n onChange={(next) => onChange({ ...value, [sub.id]: next })}\n />\n </div>\n </div>\n ))}\n </div>\n );\n}\n\nfunction RepeaterInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: AnswerRepeater;\n onChange: (v: AnswerRepeater) => void;\n}) {\n const rows = value.length > 0 ? value : [{} as Record<string, AnswerValue>];\n const itemSchema = question.itemSchema ?? [];\n const min = question.listRange?.min ?? 1;\n const max = question.listRange?.max ?? Infinity;\n\n const updateRow = (i: number, patch: Record<string, AnswerValue>) => {\n const next = [...rows];\n next[i] = { ...next[i], ...patch };\n onChange(next);\n };\n const addRow = () => {\n if (rows.length < max) onChange([...rows, {} as Record<string, AnswerValue>]);\n };\n const removeRow = (i: number) => {\n if (rows.length <= 1) return;\n onChange(rows.filter((_, idx) => idx !== i));\n };\n\n return (\n <div className=\"space-y-4\">\n {rows.map((row, i) => (\n <div key={i} className=\"rounded-lg border-2 border-stone-200 bg-stone-50 p-4\">\n <div className=\"mb-3 flex items-center justify-between\">\n <span className=\"font-mono text-xs uppercase tracking-wider text-stone-500\">\n Item {i + 1}\n </span>\n <button\n type=\"button\"\n onClick={() => removeRow(i)}\n disabled={rows.length <= min}\n className=\"btn-ghost text-xs text-stone-500 disabled:opacity-30\"\n aria-label={`Remove item ${i + 1}`}\n >\n Remove\n </button>\n </div>\n <div className=\"space-y-4\">\n {itemSchema.map((sub) => (\n <div key={sub.id}>\n <div className=\"text-sm font-medium text-stone-900\">{sub.prompt}</div>\n {sub.subprompt && (\n <div className=\"mt-1 text-xs text-stone-700\">{sub.subprompt}</div>\n )}\n <div className=\"mt-2\">\n <InputForType\n question={sub}\n value={row[sub.id]}\n onChange={(next) => updateRow(i, { [sub.id]: next })}\n />\n </div>\n </div>\n ))}\n </div>\n </div>\n ))}\n <button\n type=\"button\"\n onClick={addRow}\n disabled={rows.length >= max}\n className=\"text-sm font-medium text-forest-700 hover:text-forest-800 disabled:opacity-40\"\n >\n + Add another\n </button>\n </div>\n );\n}\n\nfunction FileUploadInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: AnswerFileUpload;\n onChange: (v: AnswerFileUpload) => void;\n}) {\n const itemSchema = question.itemSchema ?? [];\n\n const onFiles = (files: FileList | null) => {\n if (!files || files.length === 0) return;\n const entries: FileEntry[] = Array.from(files).map((f) => ({\n file: f,\n metadata: {},\n }));\n onChange([...value, ...entries]);\n };\n\n const updateMetadata = (i: number, patch: Record<string, AnswerValue>) => {\n const next = [...value];\n next[i] = { ...next[i], metadata: { ...next[i].metadata, ...patch } };\n onChange(next);\n };\n const removeEntry = (i: number) => onChange(value.filter((_, idx) => idx !== i));\n\n const onDrop = (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n onFiles(e.dataTransfer.files);\n };\n const onDragOver = (e: React.DragEvent<HTMLDivElement>) => e.preventDefault();\n\n return (\n <div className=\"space-y-4\">\n <div\n onDrop={onDrop}\n onDragOver={onDragOver}\n className=\"rounded-lg border-2 border-dashed border-stone-300 bg-stone-50 p-6 text-center\"\n >\n <p className=\"text-sm text-stone-700\">\n Drag PDFs or other files here, or{' '}\n <label className=\"cursor-pointer font-medium text-forest-700 hover:text-forest-800\">\n browse\n <input\n type=\"file\"\n multiple\n className=\"sr-only\"\n onChange={(e) => onFiles(e.target.files)}\n />\n </label>\n </p>\n <p className=\"mt-1 text-xs text-stone-500\">\n You'll add a title, author, and description for each file below.\n </p>\n </div>\n\n {value.length > 0 && (\n <ul className=\"space-y-4\">\n {value.map((entry, i) => {\n const name = entry.file.name;\n const size = 'size' in entry.file ? entry.file.size : undefined;\n return (\n <li key={i} className=\"rounded-lg border-2 border-stone-200 bg-stone-50 p-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"font-medium text-stone-900\">{name}</div>\n {typeof size === 'number' && (\n <div className=\"font-mono text-xs text-stone-500\">\n {(size / 1024).toFixed(1)} KB\n </div>\n )}\n </div>\n <button\n type=\"button\"\n onClick={() => removeEntry(i)}\n className=\"btn-ghost text-xs text-stone-500\"\n aria-label={`Remove ${name}`}\n >\n Remove\n </button>\n </div>\n {itemSchema.length > 0 && (\n <div className=\"mt-4 space-y-3\">\n {itemSchema.map((sub) => (\n <div key={sub.id}>\n <div className=\"text-xs font-medium text-stone-900\">{sub.prompt}</div>\n <div className=\"mt-1\">\n <InputForType\n question={sub}\n value={entry.metadata[sub.id]}\n onChange={(next) => updateMetadata(i, { [sub.id]: next })}\n />\n </div>\n </div>\n ))}\n </div>\n )}\n </li>\n );\n })}\n </ul>\n )}\n </div>\n );\n}\n\nfunction UnknownTypeFallback({ inputType }: { inputType: never }) {\n // Render-time defensive guard for runtime values that bypass TS (e.g.,\n // YAML-loaded interview schemas with typos). Visible to dev; user sees a\n // muted \"unsupported\" notice.\n return (\n <div className=\"rounded-lg border-2 border-stone-300 bg-stone-50 p-4 text-sm text-stone-500\">\n Unsupported question input type:{' '}\n <code className=\"font-mono\">{String(inputType)}</code>\n </div>\n );\n}\n","/**\n * Helpers for rendering one-line / summary previews of answer values in\n * `AnswerSidebar` and `ReviewSummary`. Centralized so the two components\n * stay consistent when new answer shapes are added.\n */\nimport type { AnswerValue, FileEntry, InterviewQuestion } from './types';\n\nexport function isAnswered(value: AnswerValue): boolean {\n if (value === undefined || value === null) return false;\n if (typeof value === 'string') return value.trim().length > 0;\n if (Array.isArray(value)) return value.length > 0;\n if (typeof value === 'object') return Object.keys(value).length > 0;\n return true;\n}\n\n/**\n * A short, single-line preview suitable for sidebar items. Truncates\n * long content. Returns the empty string for unanswered values.\n */\nexport function summarizeShort(question: InterviewQuestion, value: AnswerValue, maxLen = 80): string {\n if (!isAnswered(value)) return '';\n switch (question.inputType) {\n case 'short-text':\n case 'long-text':\n case 'date':\n case 'scale':\n return truncate(String(value), maxLen);\n case 'single-select': {\n const v = String(value);\n const label = question.options?.find((o) => o.value === v)?.label;\n return truncate(label ?? v, maxLen);\n }\n case 'multi-select':\n case 'list': {\n const arr = value as string[];\n const labels = arr.map((v) => {\n const found = question.options?.find((o) => o.value === v)?.label;\n return found ?? v;\n });\n return truncate(labels.join(', '), maxLen);\n }\n case 'composite': {\n // Show the first sub-answer's preview if any.\n const obj = value as { [k: string]: AnswerValue };\n const subs = question.subQuestions ?? [];\n for (const sub of subs) {\n const subVal = obj[sub.id];\n if (isAnswered(subVal)) {\n return truncate(summarizeShort(sub, subVal, maxLen), maxLen);\n }\n }\n return '';\n }\n case 'repeater': {\n const rows = value as Array<{ [k: string]: AnswerValue }>;\n return `${rows.length} item${rows.length === 1 ? '' : 's'}`;\n }\n case 'file-upload': {\n const files = value as FileEntry[];\n return `${files.length} file${files.length === 1 ? '' : 's'}`;\n }\n default:\n return '';\n }\n}\n\n/**\n * A richer multi-line summary suitable for the ReviewSummary list. May\n * contain newlines; consumers should render in a `whitespace-pre-wrap`\n * container.\n */\nexport function summarizeLong(question: InterviewQuestion, value: AnswerValue): string {\n if (!isAnswered(value)) return '';\n switch (question.inputType) {\n case 'short-text':\n case 'long-text':\n case 'date':\n case 'scale':\n return String(value);\n case 'single-select': {\n const v = String(value);\n const label = question.options?.find((o) => o.value === v)?.label;\n return label ?? v;\n }\n case 'multi-select':\n case 'list': {\n const arr = value as string[];\n const labels = arr.map((v) => question.options?.find((o) => o.value === v)?.label ?? v);\n return labels.join('\\n• ').replace(/^/, '• ');\n }\n case 'composite': {\n const obj = value as { [k: string]: AnswerValue };\n const subs = question.subQuestions ?? [];\n const lines: string[] = [];\n for (const sub of subs) {\n const subVal = obj[sub.id];\n if (isAnswered(subVal)) {\n lines.push(`${sub.prompt}: ${summarizeShort(sub, subVal, 200)}`);\n }\n }\n return lines.join('\\n');\n }\n case 'repeater': {\n const rows = value as Array<{ [k: string]: AnswerValue }>;\n const itemSchema = question.itemSchema ?? [];\n const summary = rows.map((row, i) => {\n const parts: string[] = [`Item ${i + 1}:`];\n for (const sub of itemSchema) {\n const subVal = row[sub.id];\n if (isAnswered(subVal)) {\n parts.push(` ${sub.prompt}: ${summarizeShort(sub, subVal, 100)}`);\n }\n }\n return parts.join('\\n');\n });\n return summary.join('\\n');\n }\n case 'file-upload': {\n const files = value as FileEntry[];\n return files\n .map((f, i) => `${i + 1}. ${f.file.name}`)\n .join('\\n');\n }\n default:\n return '';\n }\n}\n\nfunction truncate(s: string, maxLen: number): string {\n return s.length > maxLen ? s.slice(0, maxLen - 1) + '…' : s;\n}\n","'use client';\n\nimport type { InterviewAnswers, InterviewQuestion } from './types';\nimport { isAnswered, summarizeShort } from './summarize';\n\ninterface Props {\n questions: InterviewQuestion[];\n currentIndex: number;\n /** Consumer's current answer record (read-only — engine doesn't write). */\n answers: InterviewAnswers;\n /** Called when the user clicks a sidebar item to jump to that question. */\n onSelectQuestion: (index: number) => void;\n}\n\n/**\n * Sidebar showing all answered questions. Clicking any returns to edit that\n * question without losing later answers. Implements the wiki's pattern:\n * \"Edit any prior answer — a sidebar shows all answered questions.\"\n *\n * **Decoupled from any state-management library.** Consumers receive the\n * answers + jump handler as props.\n *\n * Iteration-1 visual identity (Phase B.2, 2026-05-06):\n * Three item states with distinct token tiers:\n * - current → forest-700 border + forest-50 bg (interactive primary)\n * - answered → stone-200 border + stone-50 bg (default, hover stone-400)\n * - unanswered → stone-200/50 + stone-50/50 (muted via opacity preservation)\n *\n * D.2.1.b extension: previews for composite/repeater/file-upload answers\n * delegated to `summarize.ts` so all eight scalar + three compound types\n * render consistently.\n */\nexport function AnswerSidebar({ questions, currentIndex, answers, onSelectQuestion }: Props) {\n return (\n <aside\n className=\"sticky top-24 hidden max-h-[calc(100vh-6rem)] overflow-y-auto lg:block\"\n aria-label=\"Completed answers\"\n >\n <h3 className=\"mb-3 font-mono text-xs uppercase tracking-wider text-stone-500\">\n Your answers\n </h3>\n <ol className=\"space-y-3\">\n {questions.map((q, i) => {\n const answer = answers[q.id];\n const answered = isAnswered(answer);\n const isCurrent = i === currentIndex;\n const preview = answered ? summarizeShort(q, answer) : '';\n\n return (\n <li key={q.id}>\n <button\n type=\"button\"\n onClick={() => onSelectQuestion(i)}\n className={`w-full rounded-lg border p-3 text-left transition-colors ${\n isCurrent\n ? 'border-forest-700 bg-forest-50'\n : answered\n ? 'border-stone-200 bg-stone-50 hover:border-stone-400'\n : 'border-stone-200/50 bg-stone-50/50 hover:border-stone-300'\n }`}\n >\n <div className=\"flex items-start gap-2\">\n <span\n className={`mt-0.5 font-mono text-xs ${\n isCurrent\n ? 'text-forest-700'\n : answered\n ? 'text-stone-500'\n : 'text-stone-400'\n }`}\n >\n {String(i + 1).padStart(2, '0')}.\n </span>\n <div className=\"flex-grow\">\n <div\n className={`text-xs font-medium ${\n answered ? 'text-stone-900' : 'text-stone-500'\n }`}\n >\n {q.prompt.length > 50 ? q.prompt.slice(0, 50) + '…' : q.prompt}\n </div>\n {answered && (\n <div className=\"mt-1 text-xs italic text-stone-500 line-clamp-1\">\n {preview}\n </div>\n )}\n </div>\n </div>\n </button>\n </li>\n );\n })}\n </ol>\n </aside>\n );\n}\n","'use client';\n\nimport type { InterviewAnswers, InterviewQuestion } from './types';\nimport { isAnswered, summarizeLong } from './summarize';\n\ninterface Props {\n questions: InterviewQuestion[];\n /** Consumer's current answer record (read-only — engine doesn't write). */\n answers: InterviewAnswers;\n onGenerate: () => void;\n onEdit: (questionIndex: number) => void;\n generating: boolean;\n}\n\n/**\n * Final review screen — the penultimate step before generation.\n * Shows all answers so the user can confirm ownership of the output before\n * committing.\n *\n * **Decoupled from any state-management library.** Consumers receive the\n * answer record as a prop.\n *\n * Iteration-1 visual identity (Phase B.2, 2026-05-06):\n * Editorial Josefin display family on the heading and the \"What happens next\"\n * callout title. Stone-tier surfaces and content text throughout. The\n * \"What happens next\" callout box preserves border-copper-300 + bg-copper-50 —\n * preserved-decorative-copper role per iteration-2-blue-accent.md.\n *\n * D.2.1.b extension: rendering of composite/repeater/file-upload answers\n * delegated to `summarize.ts` so all answer types display consistently.\n */\nexport function ReviewSummary({ questions, answers, onGenerate, onEdit, generating }: Props) {\n return (\n <div className=\"animate-slide-up\">\n <h2 className=\"font-display text-3xl font-medium text-stone-900 sm:text-4xl\">\n Review your answers\n </h2>\n <p className=\"mt-4 text-lg text-stone-700\">\n These become the seed content of your project. You can edit anything now, or continue and\n edit later through the platform.\n </p>\n\n <dl className=\"mt-10 space-y-6 border-t border-stone-200 pt-6\">\n {questions.map((q, i) => {\n const answer = answers[q.id];\n const answered = isAnswered(answer);\n const display = answered ? summarizeLong(q, answer) : '';\n\n return (\n <div key={q.id} className=\"flex gap-4 border-b border-stone-200 pb-6\">\n <span className=\"font-mono text-sm text-stone-400 pt-1\">\n {String(i + 1).padStart(2, '0')}\n </span>\n <div className=\"flex-grow\">\n <dt className=\"text-sm font-medium text-stone-900\">{q.prompt}</dt>\n <dd className=\"mt-2 text-stone-900 whitespace-pre-wrap\">\n {answered ? (\n display\n ) : (\n <span className=\"italic text-stone-400\">Not answered</span>\n )}\n </dd>\n </div>\n <button\n type=\"button\"\n onClick={() => onEdit(i)}\n className=\"btn-ghost text-sm self-start\"\n >\n Edit\n </button>\n </div>\n );\n })}\n </dl>\n\n {/* \"What happens next\" callout — copper PRESERVED as decorative\n informational frame, same role as HeroSection's etymology box.\n Per iteration-1 §5.2's preserved-decorative-copper governance. */}\n <div className=\"mt-10 rounded-lg border border-copper-300 bg-copper-50 p-6\">\n <h3 className=\"font-display text-xl text-stone-900\">What happens next</h3>\n <p className=\"mt-2 text-stone-900\">\n When you click Generate, the platform will create a GitHub repository in your account,\n populate it with your personalized CLAUDE.md, KNOWLEDGE.md, and wiki, and give you the\n URL. This takes about 30–90 seconds. You can edit everything afterward through the\n platform or through your repo.\n </p>\n <p className=\"mt-3 text-sm text-stone-700\">\n <span className=\"font-medium\">MVP note:</span> In this phase, GitHub repo creation is\n mocked for demonstration. Once OAuth credentials are configured, real repos will be\n created on your behalf.\n </p>\n </div>\n\n <div className=\"mt-8 flex justify-end\">\n <button\n type=\"button\"\n onClick={onGenerate}\n disabled={generating}\n className=\"btn-primary text-lg\"\n >\n {generating ? 'Generating your project…' : 'Generate my platform'}\n </button>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["jsx","jsxs","jsx","jsxs","jsx","jsxs"]}
1
+ {"version":3,"sources":["../src/ProgressBar.tsx","../src/QuestionCard.tsx","../src/summarize.ts","../src/AnswerSidebar.tsx","../src/ReviewSummary.tsx"],"sourcesContent":["'use client';\n\ninterface Props {\n current: number;\n total: number;\n estimatedMinutesRemaining: number;\n}\n\n/**\n * Linear progress indicator for the interview flow. Renders the\n * \"Question N of M\" caption, the estimated minutes remaining, and a\n * forest-700 fill bar at `(current / total) * 100%`.\n *\n * Iteration-1 visual identity (Phase B.2, 2026-05-06):\n * stone-100 surface with stone-200 border; forest-700 fill bar; stone-700\n * caption text. Pure-render component — no state-management dependency.\n *\n * Extracted from `apps/hub/src/components/interview/ProgressBar.tsx`\n * during iteration-3-B.1 (2026-05-07). No prop API change.\n */\nexport function ProgressBar({ current, total, estimatedMinutesRemaining }: Props) {\n const percent = Math.round((current / total) * 100);\n\n return (\n <div className=\"border-b border-stone-200 bg-stone-100 py-3 px-6\">\n <div className=\"mx-auto max-w-3xl\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"font-mono text-xs uppercase tracking-wider text-stone-700\">\n Question {current} of {total}\n </span>\n <span className=\"font-mono text-xs text-stone-700\">\n ~{estimatedMinutesRemaining} min remaining\n </span>\n </div>\n <div\n className=\"mt-2 h-1 w-full overflow-hidden rounded-full bg-stone-200\"\n role=\"progressbar\"\n aria-valuenow={percent}\n aria-valuemin={0}\n aria-valuemax={100}\n aria-label={`Interview progress: ${percent}% complete`}\n >\n <div\n className=\"h-full bg-forest-700 transition-all duration-300 ease-out\"\n style={{ width: `${percent}%` }}\n />\n </div>\n </div>\n </div>\n );\n}\n","'use client';\n\nimport { useState, useEffect } from 'react';\nimport type {\n InterviewQuestion,\n AnswerValue,\n AnswerComposite,\n AnswerRepeater,\n AnswerFileUpload,\n FileEntry,\n} from './types';\n\ninterface Props {\n question: InterviewQuestion;\n /**\n * The currently-saved answer for this question (from the consumer's\n * state container). The component initializes its local form state\n * from this value and re-syncs when the question id changes.\n */\n existingAnswer?: AnswerValue;\n /**\n * Called when the user submits an answer. The consumer is expected to\n * persist the answer into its state container and then advance via\n * `onNext`.\n */\n onAnswerSubmit: (questionId: string, value: AnswerValue) => void;\n /** Called after `onAnswerSubmit` to advance to the next question. */\n onNext: () => void;\n /** Called when the user clicks the Back button. */\n onBack: () => void;\n isFirst: boolean;\n isLast: boolean;\n}\n\n/**\n * Default value to use when no `existingAnswer` is supplied. Depends on\n * the question's `inputType`.\n */\nfunction defaultValueFor(question: InterviewQuestion): AnswerValue {\n switch (question.inputType) {\n case 'multi-select':\n case 'list':\n return [];\n case 'composite':\n return {} as AnswerComposite;\n case 'repeater':\n case 'file-upload':\n return [];\n default:\n return '';\n }\n}\n\n/**\n * Whether the user's current local value satisfies the required check\n * for the question.\n */\nfunction canAdvanceWith(question: InterviewQuestion, value: AnswerValue): boolean {\n if (!question.required) return true;\n if (value === undefined || value === null) return false;\n if (typeof value === 'string') return value.trim().length > 0;\n if (Array.isArray(value)) return value.length > 0;\n if (typeof value === 'object') return Object.keys(value).length > 0;\n return true;\n}\n\n/**\n * Single question renderer. Handles all input types: short-text, long-text,\n * single-select, multi-select, scale, list, date, composite, repeater,\n * file-upload. Keyboard-navigable and screen-reader safe.\n *\n * **Decoupled from any state-management library.** Consumers receive the\n * existing answer + change handler as props.\n *\n * Iteration-1 visual identity: form input fields use stone-50 elevated\n * surface + stone-200 default border + forest-700 focus border. Selected\n * radio/checkbox option states use forest-700 border + forest-50 background.\n * The examples disclosure has border-l-2 frame in border-copper-200 —\n * preserved-decorative-copper role per iteration-2-blue-accent.md.\n */\nexport function QuestionCard({\n question,\n existingAnswer,\n onAnswerSubmit,\n onNext,\n onBack,\n isFirst,\n isLast,\n}: Props) {\n const [localValue, setLocalValue] = useState<AnswerValue>(\n existingAnswer ?? defaultValueFor(question),\n );\n\n // Sync when question changes (consumer flipped to a different question;\n // local form state should reflect that question's existing answer).\n useEffect(() => {\n setLocalValue(existingAnswer ?? defaultValueFor(question));\n }, [question.id, existingAnswer, question.inputType]);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n onAnswerSubmit(question.id, localValue);\n onNext();\n };\n\n const canAdvance = canAdvanceWith(question, localValue);\n\n return (\n <form onSubmit={handleSubmit} className=\"animate-slide-up\">\n {/* Prompt */}\n <h2 className=\"font-display text-3xl font-medium text-stone-900 sm:text-4xl\">\n {question.prompt}\n </h2>\n {question.subprompt && (\n <p className=\"mt-4 text-lg text-stone-700\">{question.subprompt}</p>\n )}\n\n {/* Input — dispatched per type */}\n <div className=\"mt-8\">\n <InputForType\n question={question}\n value={localValue}\n onChange={setLocalValue}\n />\n </div>\n\n {/* Examples */}\n {question.examples && question.examples.length > 0 && (\n <details className=\"mt-8\">\n <summary className=\"cursor-pointer text-sm font-medium text-forest-700 hover:text-forest-800\">\n Show examples from different fields\n </summary>\n {/* border-copper-200 PRESERVED: decorative-emphasis frame around\n illustrative content, same role as HeroSection's etymology box. */}\n <ul className=\"mt-4 space-y-3 border-l-2 border-copper-200 pl-5\">\n {question.examples.map((ex, i) => (\n <li key={i} className=\"text-sm italic text-stone-700\">\n “{ex}”\n </li>\n ))}\n </ul>\n </details>\n )}\n\n {/* Skip consequence (if applicable) */}\n {!question.required && question.skipConsequence && (\n <p className=\"mt-6 text-sm text-stone-700\">\n <span className=\"font-medium\">If you skip this:</span> {question.skipConsequence}\n </p>\n )}\n\n {/* Nav */}\n <div className=\"mt-10 flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={onBack}\n disabled={isFirst}\n className=\"btn-ghost disabled:opacity-40\"\n >\n ← Back\n </button>\n <div className=\"flex gap-3\">\n {!question.required && (\n <button type=\"button\" onClick={onNext} className=\"btn-ghost\">\n Skip\n </button>\n )}\n <button type=\"submit\" disabled={!canAdvance} className=\"btn-primary\">\n {isLast ? 'Review answers' : 'Continue →'}\n </button>\n </div>\n </div>\n </form>\n );\n}\n\n// ─────────────────────────────────────────────────────────────────────────────\n// Per-input-type renderers\n// ─────────────────────────────────────────────────────────────────────────────\n\ninterface InputProps {\n question: InterviewQuestion;\n value: AnswerValue;\n onChange: (next: AnswerValue) => void;\n}\n\nfunction InputForType({ question, value, onChange }: InputProps) {\n switch (question.inputType) {\n case 'short-text':\n return <ShortTextInput value={value as string} onChange={onChange} />;\n case 'long-text':\n return <LongTextInput value={value as string} onChange={onChange} />;\n case 'single-select':\n return <SingleSelectInput question={question} value={value as string} onChange={onChange} />;\n case 'multi-select':\n return <MultiSelectInput question={question} value={(value as string[]) ?? []} onChange={onChange} />;\n case 'list':\n return <ListInput value={(value as string[]) ?? []} onChange={onChange} listRange={question.listRange} />;\n case 'scale':\n return <ScaleInput question={question} value={value as string} onChange={onChange} />;\n case 'date':\n return <DateInput value={value as string} onChange={onChange} ariaLabel={question.prompt} />;\n case 'composite':\n return <CompositeInput question={question} value={(value as AnswerComposite) ?? {}} onChange={onChange} />;\n case 'repeater':\n return <RepeaterInput question={question} value={(value as AnswerRepeater) ?? []} onChange={onChange} />;\n case 'file-upload':\n return <FileUploadInput question={question} value={(value as AnswerFileUpload) ?? []} onChange={onChange} />;\n default: {\n const _exhaustive: never = question.inputType;\n return <UnknownTypeFallback inputType={_exhaustive} />;\n }\n }\n}\n\nfunction ShortTextInput({ value, onChange }: { value: string; onChange: (v: string) => void }) {\n return (\n <input\n type=\"text\"\n value={value ?? ''}\n onChange={(e) => onChange(e.target.value)}\n autoFocus\n className=\"w-full rounded-lg border-2 border-stone-200 bg-stone-50 px-4 py-3 text-lg text-stone-900 focus:border-forest-700 focus:outline-none\"\n placeholder=\"Type your answer…\"\n />\n );\n}\n\nfunction LongTextInput({ value, onChange }: { value: string; onChange: (v: string) => void }) {\n return (\n <textarea\n value={value ?? ''}\n onChange={(e) => onChange(e.target.value)}\n autoFocus\n rows={5}\n className=\"w-full rounded-lg border-2 border-stone-200 bg-stone-50 px-4 py-3 text-lg text-stone-900 focus:border-forest-700 focus:outline-none\"\n placeholder=\"Type your answer…\"\n />\n );\n}\n\nfunction SingleSelectInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: string;\n onChange: (v: string) => void;\n}) {\n return (\n <div className=\"space-y-3\" role=\"radiogroup\" aria-labelledby={`q-${question.id}`}>\n {(question.options ?? []).map((opt) => (\n <label\n key={opt.value}\n className={`flex cursor-pointer items-start gap-3 rounded-lg border-2 p-4 transition-colors ${\n value === opt.value\n ? 'border-forest-700 bg-forest-50'\n : 'border-stone-200 bg-stone-50 hover:border-stone-400'\n }`}\n >\n <input\n type=\"radio\"\n name={question.id}\n value={opt.value}\n checked={value === opt.value}\n onChange={(e) => onChange(e.target.value)}\n className=\"mt-1 h-4 w-4 text-forest-700\"\n />\n <div>\n <div className=\"font-medium text-stone-900\">{opt.label}</div>\n {opt.description && (\n <div className=\"mt-1 text-sm text-stone-700\">{opt.description}</div>\n )}\n </div>\n </label>\n ))}\n </div>\n );\n}\n\nfunction MultiSelectInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: string[];\n onChange: (v: string[]) => void;\n}) {\n return (\n <div className=\"space-y-2\" role=\"group\" aria-labelledby={`q-${question.id}`}>\n {(question.options ?? []).map((opt) => {\n const checked = value.includes(opt.value);\n return (\n <label\n key={opt.value}\n className={`flex cursor-pointer items-start gap-3 rounded-lg border-2 p-4 transition-colors ${\n checked\n ? 'border-forest-700 bg-forest-50'\n : 'border-stone-200 bg-stone-50 hover:border-stone-400'\n }`}\n >\n <input\n type=\"checkbox\"\n value={opt.value}\n checked={checked}\n onChange={(e) => {\n if (e.target.checked) onChange([...value, opt.value]);\n else onChange(value.filter((v) => v !== opt.value));\n }}\n className=\"mt-1 h-4 w-4 text-forest-700\"\n />\n <div>\n <div className=\"font-medium text-stone-900\">{opt.label}</div>\n {opt.description && (\n <div className=\"mt-1 text-sm text-stone-700\">{opt.description}</div>\n )}\n </div>\n </label>\n );\n })}\n </div>\n );\n}\n\nfunction ScaleInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: string;\n onChange: (v: string) => void;\n}) {\n const options = question.options ?? [];\n return (\n <div className=\"space-y-3\" role=\"radiogroup\" aria-labelledby={`q-${question.id}`}>\n {options.map((opt) => (\n <label\n key={opt.value}\n className={`flex cursor-pointer items-center gap-3 rounded-lg border-2 p-3 transition-colors ${\n value === opt.value\n ? 'border-forest-700 bg-forest-50'\n : 'border-stone-200 bg-stone-50 hover:border-stone-400'\n }`}\n >\n <input\n type=\"radio\"\n name={question.id}\n value={opt.value}\n checked={value === opt.value}\n onChange={(e) => onChange(e.target.value)}\n className=\"h-4 w-4 text-forest-700\"\n />\n <span className=\"font-mono text-sm text-stone-700\">{opt.value}</span>\n <span className=\"text-stone-900\">{opt.label}</span>\n </label>\n ))}\n </div>\n );\n}\n\nfunction DateInput({\n value,\n onChange,\n ariaLabel,\n}: {\n value: string;\n onChange: (v: string) => void;\n ariaLabel: string;\n}) {\n return (\n <input\n type=\"date\"\n aria-label={ariaLabel}\n value={value ?? ''}\n onChange={(e) => onChange(e.target.value)}\n autoFocus\n className=\"rounded-lg border-2 border-stone-200 bg-stone-50 px-4 py-3 text-lg text-stone-900 focus:border-forest-700 focus:outline-none\"\n />\n );\n}\n\nfunction ListInput({\n value,\n onChange,\n listRange,\n}: {\n value: string[];\n onChange: (v: string[]) => void;\n listRange?: { min: number; max: number };\n}) {\n const items = value.length > 0 ? value : [''];\n const min = listRange?.min ?? 0;\n const max = listRange?.max ?? Infinity;\n\n const setItem = (i: number, v: string) => {\n const next = [...items];\n next[i] = v;\n onChange(next);\n };\n const addItem = () => {\n if (items.length < max) onChange([...items, '']);\n };\n const removeItem = (i: number) => {\n if (items.length <= 1) return;\n onChange(items.filter((_, idx) => idx !== i));\n };\n const validCount = items.filter((v) => v.trim().length > 0).length;\n\n return (\n <div>\n <ul className=\"space-y-2\">\n {items.map((item, i) => (\n <li key={i} className=\"flex items-center gap-2\">\n <span className=\"w-6 text-right font-mono text-xs text-stone-600\">{i + 1}.</span>\n <input\n type=\"text\"\n value={item}\n onChange={(e) => setItem(i, e.target.value)}\n className=\"flex-grow rounded-lg border-2 border-stone-200 bg-stone-50 px-3 py-2 text-stone-900 focus:border-forest-700 focus:outline-none\"\n placeholder={`Item ${i + 1}`}\n />\n <button\n type=\"button\"\n onClick={() => removeItem(i)}\n disabled={items.length <= 1}\n className=\"btn-ghost text-stone-700 disabled:opacity-30\"\n aria-label={`Remove item ${i + 1}`}\n >\n ×\n </button>\n </li>\n ))}\n </ul>\n <div className=\"mt-3 flex items-center justify-between\">\n <button\n type=\"button\"\n onClick={addItem}\n disabled={items.length >= max}\n className=\"text-sm font-medium text-forest-700 hover:text-forest-800 disabled:opacity-40\"\n >\n + Add item\n </button>\n {listRange && (\n <span className=\"font-mono text-xs text-stone-700\">\n {validCount} / {min}–{max === Infinity ? '∞' : max}\n </span>\n )}\n </div>\n </div>\n );\n}\n\nfunction CompositeInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: AnswerComposite;\n onChange: (v: AnswerComposite) => void;\n}) {\n const subQuestions = question.subQuestions ?? [];\n return (\n <div className=\"space-y-6 rounded-lg border-2 border-stone-200 bg-stone-50 p-4\">\n {subQuestions.map((sub) => (\n <div key={sub.id}>\n <div className=\"text-sm font-medium text-stone-900\">{sub.prompt}</div>\n {sub.subprompt && <div className=\"mt-1 text-xs text-stone-700\">{sub.subprompt}</div>}\n <div className=\"mt-2\">\n <InputForType\n question={sub}\n value={value[sub.id]}\n onChange={(next) => onChange({ ...value, [sub.id]: next })}\n />\n </div>\n </div>\n ))}\n </div>\n );\n}\n\nfunction RepeaterInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: AnswerRepeater;\n onChange: (v: AnswerRepeater) => void;\n}) {\n const rows = value.length > 0 ? value : [{} as Record<string, AnswerValue>];\n const itemSchema = question.itemSchema ?? [];\n const min = question.listRange?.min ?? 1;\n const max = question.listRange?.max ?? Infinity;\n\n const updateRow = (i: number, patch: Record<string, AnswerValue>) => {\n const next = [...rows];\n next[i] = { ...next[i], ...patch };\n onChange(next);\n };\n const addRow = () => {\n if (rows.length < max) onChange([...rows, {} as Record<string, AnswerValue>]);\n };\n const removeRow = (i: number) => {\n if (rows.length <= 1) return;\n onChange(rows.filter((_, idx) => idx !== i));\n };\n\n return (\n <div className=\"space-y-4\">\n {rows.map((row, i) => (\n <div key={i} className=\"rounded-lg border-2 border-stone-200 bg-stone-50 p-4\">\n <div className=\"mb-3 flex items-center justify-between\">\n <span className=\"font-mono text-xs uppercase tracking-wider text-stone-700\">\n Item {i + 1}\n </span>\n <button\n type=\"button\"\n onClick={() => removeRow(i)}\n disabled={rows.length <= min}\n className=\"btn-ghost text-xs text-stone-700 disabled:opacity-30\"\n aria-label={`Remove item ${i + 1}`}\n >\n Remove\n </button>\n </div>\n <div className=\"space-y-4\">\n {itemSchema.map((sub) => (\n <div key={sub.id}>\n <div className=\"text-sm font-medium text-stone-900\">{sub.prompt}</div>\n {sub.subprompt && (\n <div className=\"mt-1 text-xs text-stone-700\">{sub.subprompt}</div>\n )}\n <div className=\"mt-2\">\n <InputForType\n question={sub}\n value={row[sub.id]}\n onChange={(next) => updateRow(i, { [sub.id]: next })}\n />\n </div>\n </div>\n ))}\n </div>\n </div>\n ))}\n <button\n type=\"button\"\n onClick={addRow}\n disabled={rows.length >= max}\n className=\"text-sm font-medium text-forest-700 hover:text-forest-800 disabled:opacity-40\"\n >\n + Add another\n </button>\n </div>\n );\n}\n\nfunction FileUploadInput({\n question,\n value,\n onChange,\n}: {\n question: InterviewQuestion;\n value: AnswerFileUpload;\n onChange: (v: AnswerFileUpload) => void;\n}) {\n const itemSchema = question.itemSchema ?? [];\n\n const onFiles = (files: FileList | null) => {\n if (!files || files.length === 0) return;\n const entries: FileEntry[] = Array.from(files).map((f) => ({\n file: f,\n metadata: {},\n }));\n onChange([...value, ...entries]);\n };\n\n const updateMetadata = (i: number, patch: Record<string, AnswerValue>) => {\n const next = [...value];\n next[i] = { ...next[i], metadata: { ...next[i].metadata, ...patch } };\n onChange(next);\n };\n const removeEntry = (i: number) => onChange(value.filter((_, idx) => idx !== i));\n\n const onDrop = (e: React.DragEvent<HTMLDivElement>) => {\n e.preventDefault();\n onFiles(e.dataTransfer.files);\n };\n const onDragOver = (e: React.DragEvent<HTMLDivElement>) => e.preventDefault();\n\n return (\n <div className=\"space-y-4\">\n <div\n onDrop={onDrop}\n onDragOver={onDragOver}\n className=\"rounded-lg border-2 border-dashed border-stone-300 bg-stone-50 p-6 text-center\"\n >\n <p className=\"text-sm text-stone-700\">\n Drag PDFs or other files here, or{' '}\n <label className=\"cursor-pointer font-medium text-forest-700 hover:text-forest-800\">\n browse\n <input\n type=\"file\"\n multiple\n className=\"sr-only\"\n onChange={(e) => onFiles(e.target.files)}\n />\n </label>\n </p>\n <p className=\"mt-1 text-xs text-stone-700\">\n You'll add a title, author, and description for each file below.\n </p>\n </div>\n\n {value.length > 0 && (\n <ul className=\"space-y-4\">\n {value.map((entry, i) => {\n const name = entry.file.name;\n const size = 'size' in entry.file ? entry.file.size : undefined;\n return (\n <li key={i} className=\"rounded-lg border-2 border-stone-200 bg-stone-50 p-4\">\n <div className=\"flex items-center justify-between\">\n <div>\n <div className=\"font-medium text-stone-900\">{name}</div>\n {typeof size === 'number' && (\n <div className=\"font-mono text-xs text-stone-700\">\n {(size / 1024).toFixed(1)} KB\n </div>\n )}\n </div>\n <button\n type=\"button\"\n onClick={() => removeEntry(i)}\n className=\"btn-ghost text-xs text-stone-700\"\n aria-label={`Remove ${name}`}\n >\n Remove\n </button>\n </div>\n {itemSchema.length > 0 && (\n <div className=\"mt-4 space-y-3\">\n {itemSchema.map((sub) => (\n <div key={sub.id}>\n <div className=\"text-xs font-medium text-stone-900\">{sub.prompt}</div>\n <div className=\"mt-1\">\n <InputForType\n question={sub}\n value={entry.metadata[sub.id]}\n onChange={(next) => updateMetadata(i, { [sub.id]: next })}\n />\n </div>\n </div>\n ))}\n </div>\n )}\n </li>\n );\n })}\n </ul>\n )}\n </div>\n );\n}\n\nfunction UnknownTypeFallback({ inputType }: { inputType: never }) {\n // Render-time defensive guard for runtime values that bypass TS (e.g.,\n // YAML-loaded interview schemas with typos). Visible to dev; user sees a\n // muted \"unsupported\" notice.\n return (\n <div className=\"rounded-lg border-2 border-stone-300 bg-stone-50 p-4 text-sm text-stone-700\">\n Unsupported question input type:{' '}\n <code className=\"font-mono\">{String(inputType)}</code>\n </div>\n );\n}\n","/**\n * Helpers for rendering one-line / summary previews of answer values in\n * `AnswerSidebar` and `ReviewSummary`. Centralized so the two components\n * stay consistent when new answer shapes are added.\n */\nimport type { AnswerValue, FileEntry, InterviewQuestion } from './types';\n\nexport function isAnswered(value: AnswerValue): boolean {\n if (value === undefined || value === null) return false;\n if (typeof value === 'string') return value.trim().length > 0;\n if (Array.isArray(value)) return value.length > 0;\n if (typeof value === 'object') return Object.keys(value).length > 0;\n return true;\n}\n\n/**\n * A short, single-line preview suitable for sidebar items. Truncates\n * long content. Returns the empty string for unanswered values.\n */\nexport function summarizeShort(question: InterviewQuestion, value: AnswerValue, maxLen = 80): string {\n if (!isAnswered(value)) return '';\n switch (question.inputType) {\n case 'short-text':\n case 'long-text':\n case 'date':\n case 'scale':\n return truncate(String(value), maxLen);\n case 'single-select': {\n const v = String(value);\n const label = question.options?.find((o) => o.value === v)?.label;\n return truncate(label ?? v, maxLen);\n }\n case 'multi-select':\n case 'list': {\n const arr = value as string[];\n const labels = arr.map((v) => {\n const found = question.options?.find((o) => o.value === v)?.label;\n return found ?? v;\n });\n return truncate(labels.join(', '), maxLen);\n }\n case 'composite': {\n // Show the first sub-answer's preview if any.\n const obj = value as { [k: string]: AnswerValue };\n const subs = question.subQuestions ?? [];\n for (const sub of subs) {\n const subVal = obj[sub.id];\n if (isAnswered(subVal)) {\n return truncate(summarizeShort(sub, subVal, maxLen), maxLen);\n }\n }\n return '';\n }\n case 'repeater': {\n const rows = value as Array<{ [k: string]: AnswerValue }>;\n return `${rows.length} item${rows.length === 1 ? '' : 's'}`;\n }\n case 'file-upload': {\n const files = value as FileEntry[];\n return `${files.length} file${files.length === 1 ? '' : 's'}`;\n }\n default:\n return '';\n }\n}\n\n/**\n * A richer multi-line summary suitable for the ReviewSummary list. May\n * contain newlines; consumers should render in a `whitespace-pre-wrap`\n * container.\n */\nexport function summarizeLong(question: InterviewQuestion, value: AnswerValue): string {\n if (!isAnswered(value)) return '';\n switch (question.inputType) {\n case 'short-text':\n case 'long-text':\n case 'date':\n case 'scale':\n return String(value);\n case 'single-select': {\n const v = String(value);\n const label = question.options?.find((o) => o.value === v)?.label;\n return label ?? v;\n }\n case 'multi-select':\n case 'list': {\n const arr = value as string[];\n const labels = arr.map((v) => question.options?.find((o) => o.value === v)?.label ?? v);\n return labels.join('\\n• ').replace(/^/, '• ');\n }\n case 'composite': {\n const obj = value as { [k: string]: AnswerValue };\n const subs = question.subQuestions ?? [];\n const lines: string[] = [];\n for (const sub of subs) {\n const subVal = obj[sub.id];\n if (isAnswered(subVal)) {\n lines.push(`${sub.prompt}: ${summarizeShort(sub, subVal, 200)}`);\n }\n }\n return lines.join('\\n');\n }\n case 'repeater': {\n const rows = value as Array<{ [k: string]: AnswerValue }>;\n const itemSchema = question.itemSchema ?? [];\n const summary = rows.map((row, i) => {\n const parts: string[] = [`Item ${i + 1}:`];\n for (const sub of itemSchema) {\n const subVal = row[sub.id];\n if (isAnswered(subVal)) {\n parts.push(` ${sub.prompt}: ${summarizeShort(sub, subVal, 100)}`);\n }\n }\n return parts.join('\\n');\n });\n return summary.join('\\n');\n }\n case 'file-upload': {\n const files = value as FileEntry[];\n return files\n .map((f, i) => `${i + 1}. ${f.file.name}`)\n .join('\\n');\n }\n default:\n return '';\n }\n}\n\nfunction truncate(s: string, maxLen: number): string {\n return s.length > maxLen ? s.slice(0, maxLen - 1) + '…' : s;\n}\n","'use client';\n\nimport type { InterviewAnswers, InterviewQuestion } from './types';\nimport { isAnswered, summarizeShort } from './summarize';\n\ninterface Props {\n questions: InterviewQuestion[];\n currentIndex: number;\n /** Consumer's current answer record (read-only — engine doesn't write). */\n answers: InterviewAnswers;\n /** Called when the user clicks a sidebar item to jump to that question. */\n onSelectQuestion: (index: number) => void;\n}\n\n/**\n * Sidebar showing all answered questions. Clicking any returns to edit that\n * question without losing later answers. Implements the wiki's pattern:\n * \"Edit any prior answer — a sidebar shows all answered questions.\"\n *\n * **Decoupled from any state-management library.** Consumers receive the\n * answers + jump handler as props.\n *\n * Iteration-1 visual identity (Phase B.2, 2026-05-06):\n * Three item states with distinct token tiers:\n * - current → forest-700 border + forest-50 bg (interactive primary)\n * - answered → stone-200 border + stone-50 bg (default, hover stone-400)\n * - unanswered → stone-200/50 + stone-50/50 (muted via opacity preservation)\n *\n * D.2.1.b extension: previews for composite/repeater/file-upload answers\n * delegated to `summarize.ts` so all eight scalar + three compound types\n * render consistently.\n */\nexport function AnswerSidebar({ questions, currentIndex, answers, onSelectQuestion }: Props) {\n return (\n <aside\n className=\"sticky top-24 hidden max-h-[calc(100vh-6rem)] overflow-y-auto lg:block\"\n aria-label=\"Completed answers\"\n >\n <h3 className=\"mb-3 font-mono text-xs uppercase tracking-wider text-stone-700\">\n Your answers\n </h3>\n <ol className=\"space-y-3\">\n {questions.map((q, i) => {\n const answer = answers[q.id];\n const answered = isAnswered(answer);\n const isCurrent = i === currentIndex;\n const preview = answered ? summarizeShort(q, answer) : '';\n\n return (\n <li key={q.id}>\n <button\n type=\"button\"\n onClick={() => onSelectQuestion(i)}\n className={`w-full rounded-lg border p-3 text-left transition-colors ${\n isCurrent\n ? 'border-forest-700 bg-forest-50'\n : answered\n ? 'border-stone-200 bg-stone-50 hover:border-stone-400'\n : 'border-stone-200/50 bg-stone-50/50 hover:border-stone-300'\n }`}\n >\n <div className=\"flex items-start gap-2\">\n <span\n className={`mt-0.5 font-mono text-xs ${\n isCurrent\n ? 'text-forest-700'\n : answered\n ? 'text-stone-700'\n : 'text-stone-600'\n }`}\n >\n {String(i + 1).padStart(2, '0')}.\n </span>\n <div className=\"flex-grow\">\n <div\n className={`text-xs font-medium ${\n answered ? 'text-stone-900' : 'text-stone-700'\n }`}\n >\n {q.prompt.length > 50 ? q.prompt.slice(0, 50) + '…' : q.prompt}\n </div>\n {answered && (\n <div className=\"mt-1 text-xs italic text-stone-700 line-clamp-1\">\n {preview}\n </div>\n )}\n </div>\n </div>\n </button>\n </li>\n );\n })}\n </ol>\n </aside>\n );\n}\n","'use client';\n\nimport type { InterviewAnswers, InterviewQuestion } from './types';\nimport { isAnswered, summarizeLong } from './summarize';\n\ninterface Props {\n questions: InterviewQuestion[];\n /** Consumer's current answer record (read-only — engine doesn't write). */\n answers: InterviewAnswers;\n onGenerate: () => void;\n onEdit: (questionIndex: number) => void;\n generating: boolean;\n}\n\n/**\n * Final review screen — the penultimate step before generation.\n * Shows all answers so the user can confirm ownership of the output before\n * committing.\n *\n * **Decoupled from any state-management library.** Consumers receive the\n * answer record as a prop.\n *\n * Iteration-1 visual identity (Phase B.2, 2026-05-06):\n * Editorial Josefin display family on the heading and the \"What happens next\"\n * callout title. Stone-tier surfaces and content text throughout. The\n * \"What happens next\" callout box preserves border-copper-300 + bg-copper-50 —\n * preserved-decorative-copper role per iteration-2-blue-accent.md.\n *\n * D.2.1.b extension: rendering of composite/repeater/file-upload answers\n * delegated to `summarize.ts` so all answer types display consistently.\n */\nexport function ReviewSummary({ questions, answers, onGenerate, onEdit, generating }: Props) {\n return (\n <div className=\"animate-slide-up\">\n <h2 className=\"font-display text-3xl font-medium text-stone-900 sm:text-4xl\">\n Review your answers\n </h2>\n <p className=\"mt-4 text-lg text-stone-700\">\n These become the seed content of your project. You can edit anything now, or continue and\n edit later through the platform.\n </p>\n\n <dl className=\"mt-10 space-y-6 border-t border-stone-200 pt-6\">\n {questions.map((q, i) => {\n const answer = answers[q.id];\n const answered = isAnswered(answer);\n const display = answered ? summarizeLong(q, answer) : '';\n\n return (\n // A <div> child of <dl> may contain ONLY dt/dd groups (HTML spec;\n // axe definition-list), so the index + Edit button live INSIDE\n // <dt>. Subgrid keeps all three columns aligned across dt and dd\n // without extra wrappers.\n <div\n key={q.id}\n className=\"grid grid-cols-[auto_1fr_auto] gap-x-4 border-b border-stone-200 pb-6\"\n >\n <dt className=\"col-span-3 grid grid-cols-subgrid\">\n <span aria-hidden=\"true\" className=\"pt-1 font-mono text-sm text-stone-600\">\n {String(i + 1).padStart(2, '0')}\n </span>\n <span className=\"text-sm font-medium text-stone-900\">{q.prompt}</span>\n <button\n type=\"button\"\n onClick={() => onEdit(i)}\n aria-label={`Edit: ${q.prompt}`}\n className=\"btn-ghost self-start text-sm\"\n >\n Edit\n </button>\n </dt>\n <dd className=\"col-span-3 mt-2 grid grid-cols-subgrid\">\n <span className=\"col-start-2 whitespace-pre-wrap text-stone-900\">\n {answered ? (\n display\n ) : (\n <span className=\"italic text-stone-600\">Not answered</span>\n )}\n </span>\n </dd>\n </div>\n );\n })}\n </dl>\n\n {/* \"What happens next\" callout — copper PRESERVED as decorative\n informational frame, same role as HeroSection's etymology box.\n Per iteration-1 §5.2's preserved-decorative-copper governance. */}\n <div className=\"mt-10 rounded-lg border border-copper-300 bg-copper-50 p-6\">\n <h3 className=\"font-display text-xl text-stone-900\">What happens next</h3>\n <p className=\"mt-2 text-stone-900\">\n When you click Generate, the platform will create a GitHub repository in your account,\n populate it with your personalized CLAUDE.md, KNOWLEDGE.md, and wiki, and give you the\n URL. This takes about 30–90 seconds. You can edit everything afterward through the\n platform or through your repo.\n </p>\n <p className=\"mt-3 text-sm text-stone-700\">\n <span className=\"font-medium\">MVP note:</span> In this phase, GitHub repo creation is\n mocked for demonstration. Once OAuth credentials are configured, real repos will be\n created on your behalf.\n </p>\n </div>\n\n <div className=\"mt-8 flex justify-end\">\n <button\n type=\"button\"\n onClick={onGenerate}\n disabled={generating}\n className=\"btn-primary text-lg\"\n >\n {generating ? 'Generating your project…' : 'Generate my platform'}\n </button>\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["jsx","jsxs","jsx","jsxs","jsx","jsxs"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dataimago/interview",
3
- "version": "0.2.0-alpha.2",
3
+ "version": "0.2.0-alpha.4",
4
4
  "description": "Domain-agnostic interview engine — React components + schema contract for AI-native onboarding flows. Extracted from dataimago-ai/apps/hub during iteration-3-B.1 (2026-05-07).",
5
5
  "license": "MIT",
6
6
  "repository": {