{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "patient-results-pdf",
  "title": "Patient Results PDF",
  "description": "React PDF document renderer and block companions for the patient results component family.",
  "registryDependencies": [
    "@blocks/patient-results-presets",
    "@blocks/patient-results-types"
  ],
  "files": [
    {
      "path": "registry/berlin/blocks/patient-results/pdf/patient-results-pdf.tsx",
      "content": "// Generated from packages/ui/src/components/patient-results/pdf/patient-results-pdf.tsx\nimport * as React from \"react\";\n\nimport {\n  Circle,\n  Document,\n  Image,\n  Page,\n  Path,\n  Svg,\n  Text,\n  View,\n} from \"@react-pdf/renderer\";\n\n// Registry source of truth for patient-results PDF pulls into circleOS.\nimport { getPatientResultsPreset } from \"@/registry/berlin/blocks/patient-results-presets\";\nimport type {\n  DiagnosticInterpretationColumnsProps,\n  DiagnosticMetricDonutCardProps,\n  DiagnosticMetricRangeCardProps,\n  DiagnosticMetricSplitCardProps,\n  DiagnosticMetricStatCardProps,\n  DiagnosticReportFooterProps,\n  DiagnosticReportIntroProps,\n  PatientResultsBlock,\n  PatientResultsBlockSpan,\n  PatientResultsReportPage,\n  PatientResultsReportPreset,\n  SegmentMuscleAnalysisProps,\n} from \"@/registry/berlin/blocks/patient-results-types\";\n\nconst POINTS_PER_PIXEL = 0.75;\n\nfunction px(value: number) {\n  return value * POINTS_PER_PIXEL;\n}\n\nconst PDF_PAGE_CONTENT_BUDGET = px(930);\nconst PDF_ROW_GAP = px(20);\nconst PDF_SECTION_GAP = px(28);\nconst PDF_INTRO_ESTIMATED_HEIGHT = px(160);\n\nfunction clamp(value: number, min: number, max: number) {\n  return Math.min(Math.max(value, min), max);\n}\n\nfunction formatMetricValue(value: number) {\n  return Number.isInteger(value) ? `${value}` : value.toFixed(1);\n}\n\nfunction percentageForValue(value: number, min: number, max: number) {\n  if (min === max) return 0;\n  return ((clamp(value, min, max) - min) / (max - min)) * 100;\n}\n\nfunction toNumber(value: unknown) {\n  const numeric = Number(value);\n  return Number.isFinite(numeric) ? numeric : 0;\n}\n\nfunction titleCaseFromType(type: string) {\n  return type.replace(/([A-Z])/g, \" $1\").trim();\n}\n\ntype EditorLikeBlock = {\n  type: string;\n  props?: Record<string, unknown>;\n};\n\nfunction normalizeText(value: unknown, fallback = \"\") {\n  return typeof value === \"string\" ? value : fallback;\n}\n\nfunction normalizeSplitProps(props: Record<string, unknown>) {\n  return {\n    title: normalizeText(props.title, \"Metric\"),\n    summary: normalizeText(props.summary),\n    left: {\n      label: normalizeText(props.leftLabel, \"Left\"),\n      value: toNumber(props.leftValue),\n      fill: toNumber(props.leftFill),\n    },\n    right: {\n      label: normalizeText(props.rightLabel, \"Right\"),\n      value: toNumber(props.rightValue),\n      fill: toNumber(props.rightFill),\n    },\n  } satisfies DiagnosticMetricSplitCardProps;\n}\n\nfunction normalizeRangeProps(props: Record<string, unknown>) {\n  const ticks = normalizeText(props.ticksCsv, \"\")\n    .split(\",\")\n    .map((item) => Number(item.trim()))\n    .filter((item) => Number.isFinite(item));\n\n  return {\n    title: normalizeText(props.title, \"Metric\"),\n    value: toNumber(props.value),\n    unit: normalizeText(props.unit) || undefined,\n    status: normalizeText(props.statusLabel)\n      ? {\n          label: normalizeText(props.statusLabel),\n          tone: normalizeText(\n            props.statusTone,\n            \"supporting\",\n          ) as DiagnosticMetricRangeCardProps[\"status\"] extends infer T\n            ? T extends { tone: infer Tone }\n              ? Tone\n              : never\n            : never,\n        }\n      : undefined,\n    ticks,\n    min: toNumber(props.min),\n    max: toNumber(props.max),\n    pointerValue: toNumber(props.pointerValue),\n    highlightStart: toNumber(props.highlightStart),\n    highlightEnd: toNumber(props.highlightEnd),\n    summary: normalizeText(props.summary) || undefined,\n    layout:\n      normalizeText(props.layout) === \"hero\" ? (\"hero\" as const) : \"compact\",\n  } satisfies DiagnosticMetricRangeCardProps;\n}\n\nfunction normalizeDonutProps(props: Record<string, unknown>) {\n  return {\n    title: normalizeText(props.title, \"Metric\"),\n    value: toNumber(props.value),\n    unit: normalizeText(props.unit) || undefined,\n    progress: toNumber(props.progress),\n    summary: normalizeText(props.summary) || undefined,\n    size:\n      normalizeText(props.size) === \"compact\"\n        ? (\"compact\" as const)\n        : \"regular\",\n  } satisfies DiagnosticMetricDonutCardProps;\n}\n\nfunction normalizeStatProps(props: Record<string, unknown>) {\n  return {\n    title: normalizeText(props.title, \"Metric\"),\n    value: toNumber(props.value),\n    unit: normalizeText(props.unit) || undefined,\n    status: normalizeText(props.statusLabel)\n      ? {\n          label: normalizeText(props.statusLabel),\n          tone: normalizeText(\n            props.statusTone,\n            \"supporting\",\n          ) as DiagnosticMetricStatCardProps[\"status\"] extends infer T\n            ? T extends { tone: infer Tone }\n              ? Tone\n              : never\n            : never,\n        }\n      : undefined,\n  } satisfies DiagnosticMetricStatCardProps;\n}\n\nfunction normalizeInterpretationProps(props: Record<string, unknown>) {\n  return {\n    meaning: normalizeText(props.meaning),\n    improvement: normalizeText(props.improvement),\n  } satisfies DiagnosticInterpretationColumnsProps;\n}\n\nfunction normalizeSegmentAnalysisProps(props: Record<string, unknown>) {\n  const parseJson = <T,>(value: unknown, fallback: T) => {\n    if (typeof value !== \"string\" || !value.trim()) return fallback;\n\n    try {\n      return JSON.parse(value) as T;\n    } catch {\n      return fallback;\n    }\n  };\n\n  return {\n    title: normalizeText(props.title, \"Segment Muscular Analysis\"),\n    summary: normalizeText(\n      props.summary,\n      \"Muscle distribution across different body segments\",\n    ),\n    figureUrl: normalizeText(props.figureUrl),\n    figureAlt: normalizeText(props.figureAlt, \"Segment analysis figure\"),\n    hotspots: parseJson(props.hotspotsJson, []),\n    leftMetrics: parseJson(props.leftMetricsJson, []),\n    rightMetrics: parseJson(props.rightMetricsJson, []),\n  } satisfies SegmentMuscleAnalysisProps;\n}\n\nexport function convertEditorBlockToPatientResultsBlock(\n  block: EditorLikeBlock,\n): PatientResultsBlock | null {\n  const props = block.props ?? {};\n\n  if (block.type === \"diagnosticMetricRange\") {\n    return {\n      type: \"diagnosticMetricRange\",\n      span: \"full\",\n      props: normalizeRangeProps(props),\n    };\n  }\n\n  if (block.type === \"diagnosticMetricDonut\") {\n    return {\n      type: \"diagnosticMetricDonut\",\n      span: \"full\",\n      props: normalizeDonutProps(props),\n    };\n  }\n\n  if (block.type === \"diagnosticMetricSplit\") {\n    return {\n      type: \"diagnosticMetricSplit\",\n      span: \"full\",\n      props: normalizeSplitProps(props),\n    };\n  }\n\n  if (block.type === \"diagnosticMetricStat\") {\n    return {\n      type: \"diagnosticMetricStat\",\n      span: \"full\",\n      props: normalizeStatProps(props),\n    };\n  }\n\n  if (block.type === \"diagnosticInterpretation\") {\n    return {\n      type: \"diagnosticInterpretation\",\n      span: \"full\",\n      props: normalizeInterpretationProps(props),\n    };\n  }\n\n  if (block.type === \"segmentMuscleAnalysis\") {\n    return {\n      type: \"segmentMuscleAnalysis\",\n      span: \"full\",\n      props: normalizeSegmentAnalysisProps(props),\n    };\n  }\n\n  return null;\n}\n\nexport function createPatientResultsPresetFromEditorDocument(\n  presetId: PatientResultsReportPreset[\"id\"],\n  document: EditorLikeBlock[],\n) {\n  const basePreset = getPatientResultsPreset(presetId);\n  const normalizedBlocks = document\n    .map((block) => convertEditorBlockToPatientResultsBlock(block))\n    .filter((block): block is PatientResultsBlock => block !== null);\n\n  let cursor = 0;\n  const pages = basePreset.pages.map((page, pageIndex) => {\n    const expectedCount = page.blocks.length;\n    const isLastPage = pageIndex === basePreset.pages.length - 1;\n    const nextCursor = isLastPage\n      ? normalizedBlocks.length\n      : cursor + expectedCount;\n    const pageBlocks = normalizedBlocks.slice(cursor, nextCursor);\n    cursor = nextCursor;\n\n    return {\n      ...page,\n      blocks: pageBlocks.length > 0 ? pageBlocks : page.blocks,\n    };\n  });\n\n  return {\n    ...basePreset,\n    pages,\n  } satisfies PatientResultsReportPreset;\n}\n\nfunction CircleArcMarkPdf() {\n  return (\n    <Svg width={px(28)} height={px(28)} viewBox=\"0 0 20 20\">\n      <Path\n        d=\"M3.84338 17.8801C2.20252 16.5981 1.00278 14.8359 0.411554 12.8393C-0.179671 10.8427 -0.132885 8.71139 0.545383 6.74267C1.22365 4.77395 2.49957 3.06607 4.1951 1.85732C5.89064 0.648581 7.92121 -0.000726849 10.0035 0C12.0858 0.000727193 14.1159 0.651452 15.8106 1.86138C17.5053 3.07131 18.78 4.78008 19.4569 6.74927C20.1338 8.71846 20.1791 10.8498 19.5865 12.846C18.9938 14.8422 17.7929 16.6036 16.1511 17.8844L12.4604 13.1538C13.1171 12.6414 13.5975 11.9369 13.8346 11.1384C14.0716 10.3399 14.0535 9.48739 13.7828 8.69971C13.512 7.91203 13.0021 7.22852 12.3242 6.74455C11.6464 6.26058 10.8343 6.00029 10.0014 6C9.16848 5.99971 8.35625 6.25943 7.67804 6.74293C6.99983 7.22643 6.48946 7.90958 6.21815 8.69707C5.94685 9.48456 5.92813 10.3371 6.16462 11.1357C6.40111 11.9344 6.88101 12.6393 7.53735 13.152L3.84338 17.8801Z\"\n        fill=\"#000000\"\n      />\n    </Svg>\n  );\n}\n\nexport interface DiagnosticReportHeaderPdfProps {\n  dateLabel?: string;\n}\n\nexport function DiagnosticReportHeaderPdf({\n  dateLabel = \"{{DATE}}\",\n}: DiagnosticReportHeaderPdfProps) {\n  return (\n    <View\n      style={{\n        alignItems: \"center\",\n        flexDirection: \"row\",\n        justifyContent: \"space-between\",\n      }}\n    >\n      <CircleArcMarkPdf />\n      <Text\n        style={{\n          color: \"#5e6470\",\n          fontFamily: \"Helvetica\",\n          fontSize: px(12),\n        }}\n      >\n        {dateLabel}\n      </Text>\n    </View>\n  );\n}\n\nfunction DetailColumnPdf({\n  title,\n  rows,\n}: {\n  title: string;\n  rows: DiagnosticReportIntroProps[\"patient\"];\n}) {\n  return (\n    <View style={{ flex: 1, gap: px(8) }}>\n      <Text\n        style={{\n          color: \"#222222\",\n          fontFamily: \"Helvetica\",\n          fontSize: px(11.5),\n        }}\n      >\n        {title}\n      </Text>\n      <View style={{ gap: px(3) }}>\n        {rows.map((row, index) => (\n          <Text\n            key={`${title}-${row.label}-${index}`}\n            style={{\n              color: \"#6f7070\",\n              fontFamily: \"Helvetica\",\n              fontSize: px(11),\n              lineHeight: 1.45,\n            }}\n          >\n            {row.value}\n          </Text>\n        ))}\n      </View>\n    </View>\n  );\n}\n\nexport function DiagnosticReportIntroPdf({\n  title,\n  patient,\n  biometrics,\n  checkInformation,\n  measuredHeading,\n  measuredSummary,\n}: DiagnosticReportIntroProps) {\n  const columns = [\n    { title: \"Patient\", rows: patient },\n    { title: \"Biometrics\", rows: biometrics },\n    { title: \"Check Information\", rows: checkInformation },\n  ].filter((column) => column.rows.length > 0);\n\n  return (\n    <View style={{ gap: px(20) }}>\n      <Text\n        style={{\n          color: \"#000000\",\n          fontFamily: \"Times-Roman\",\n          fontSize: px(31),\n          lineHeight: 1.04,\n        }}\n      >\n        {title}\n      </Text>\n\n      {columns.length > 0 ? (\n        <View style={{ flexDirection: \"row\", gap: px(20) }}>\n          {columns.map((column) => (\n            <DetailColumnPdf\n              key={column.title}\n              title={column.title}\n              rows={column.rows}\n            />\n          ))}\n        </View>\n      ) : null}\n\n      <View style={{ gap: px(6) }}>\n        <Text\n          style={{\n            color: \"#000000\",\n            fontFamily: \"Times-Roman\",\n            fontSize: px(19),\n            lineHeight: 1.1,\n          }}\n        >\n          {measuredHeading}\n        </Text>\n        <Text\n          style={{\n            color: \"#6f7070\",\n            fontFamily: \"Helvetica\",\n            fontSize: px(11.5),\n            lineHeight: 1.55,\n          }}\n        >\n          {measuredSummary}\n        </Text>\n      </View>\n    </View>\n  );\n}\n\nexport function DiagnosticReportFooterPdf({\n  name = \"Circle Health\",\n  promise = \"Build performance through consistent, guided results.\",\n  address = \"Giesebrechtstr. 20, 10629 Berlin\",\n  phone = \"030 99 28 38 22\",\n  website = \"www.circle.health\",\n  compact = false,\n}: DiagnosticReportFooterProps) {\n  return (\n    <View style={{ gap: px(14) }}>\n      {!compact ? (\n        <View\n          style={{\n            alignItems: \"flex-start\",\n            flexDirection: \"row\",\n            justifyContent: \"space-between\",\n          }}\n        >\n          <Text\n            style={{\n              color: \"#1a1c21\",\n              fontFamily: \"Helvetica\",\n              fontSize: px(13),\n            }}\n          >\n            {name}\n          </Text>\n          <Text\n            style={{\n              color: \"#5e6470\",\n              fontFamily: \"Helvetica\",\n              fontSize: px(13),\n              maxWidth: \"55%\",\n              textAlign: \"right\",\n            }}\n          >\n            {promise}\n          </Text>\n        </View>\n      ) : null}\n\n      <View\n        style={{\n          backgroundColor: \"#d7dae0\",\n          height: px(1),\n          width: \"100%\",\n        }}\n      />\n\n      <View style={{ flexDirection: \"row\", gap: px(16), flexWrap: \"wrap\" }}>\n        {[address, phone, website].map((value) => (\n          <Text\n            key={value}\n            style={{\n              color: \"#5e6470\",\n              fontFamily: \"Helvetica\",\n              fontSize: px(11),\n            }}\n          >\n            {value}\n          </Text>\n        ))}\n      </View>\n    </View>\n  );\n}\n\nfunction PdfStatusBadge({\n  label,\n  tone,\n}: NonNullable<DiagnosticMetricRangeCardProps[\"status\"]>) {\n  const tones = {\n    average: { backgroundColor: \"#f3f4e2\", color: \"#bca818\" },\n    \"below-average\": { backgroundColor: \"#fbf1e7\", color: \"#d07900\" },\n    normal: { backgroundColor: \"#eaf4e2\", color: \"#5f9a3b\" },\n    supporting: { backgroundColor: \"#eef4fb\", color: \"#2061b5\" },\n  };\n  const style = tones[tone] ?? tones.supporting;\n\n  return (\n    <View\n      style={{\n        alignSelf: \"flex-start\",\n        alignItems: \"center\",\n        backgroundColor: style.backgroundColor,\n        borderRadius: px(999),\n        justifyContent: \"center\",\n        paddingHorizontal: px(10),\n        paddingVertical: px(2.5),\n      }}\n    >\n      <Text\n        style={{\n          color: style.color,\n          fontFamily: \"Helvetica\",\n          fontSize: px(9.5),\n          lineHeight: 1.1,\n        }}\n      >\n        {label}\n      </Text>\n    </View>\n  );\n}\n\nfunction PdfCardShell({\n  children,\n  compact = false,\n}: {\n  children: React.ReactNode;\n  compact?: boolean;\n}) {\n  return (\n    <View\n      wrap={false}\n      style={{\n        backgroundColor: \"#ffffff\",\n        borderColor: \"#e6ebf1\",\n        borderRadius: px(compact ? 14 : 16),\n        borderStyle: \"solid\",\n        borderWidth: px(1),\n        padding: px(compact ? 14 : 16),\n      }}\n    >\n      {children}\n    </View>\n  );\n}\n\nexport function DiagnosticMetricSplitCardPdf(\n  props: DiagnosticMetricSplitCardProps,\n) {\n  const pane = (segment: DiagnosticMetricSplitCardProps[\"left\"]) => {\n    const fill = clamp(segment.fill, 0, 1);\n\n    return (\n      <View\n        style={{\n          backgroundColor: \"#eef3f8\",\n          borderRadius: px(12),\n          flex: 1,\n          height: px(106),\n          overflow: \"hidden\",\n          position: \"relative\",\n        }}\n      >\n        <View\n          style={{\n            backgroundColor: \"#b6d1eb\",\n            borderBottomLeftRadius: px(12),\n            borderBottomRightRadius: px(12),\n            bottom: 0,\n            height: `${fill * 100}%`,\n            left: 0,\n            position: \"absolute\",\n            right: 0,\n          }}\n        />\n        <View\n          style={{\n            alignItems: \"center\",\n            paddingTop: px(8),\n            position: \"relative\",\n          }}\n        >\n          <Text\n            style={{\n              color: \"#6f7070\",\n              fontFamily: \"Helvetica\",\n              fontSize: px(10.5),\n            }}\n          >\n            {segment.label}\n          </Text>\n        </View>\n        <View\n          style={{\n            alignItems: \"center\",\n            bottom: 0,\n            height: `${fill * 100}%`,\n            justifyContent: \"flex-end\",\n            left: 0,\n            paddingBottom: px(16),\n            position: \"absolute\",\n            right: 0,\n          }}\n        >\n          <Text\n            style={{\n              color: \"#000000\",\n              fontFamily: \"Helvetica\",\n              fontSize: px(24),\n              lineHeight: 1,\n            }}\n          >\n            {formatMetricValue(segment.value)}\n          </Text>\n        </View>\n      </View>\n    );\n  };\n\n  return (\n    <PdfCardShell>\n      <View style={{ gap: px(14) }}>\n        <View\n          style={{\n            alignItems: \"flex-start\",\n            flexDirection: \"row\",\n            gap: px(12),\n            justifyContent: \"space-between\",\n          }}\n        >\n          <Text\n            style={{\n              color: \"#202020\",\n              fontFamily: \"Helvetica\",\n              fontSize: px(12),\n            }}\n          >\n            {props.title}\n          </Text>\n          {props.summary ? (\n            <Text\n              style={{\n                color: \"#6f7070\",\n                fontFamily: \"Helvetica\",\n                fontSize: px(11),\n                lineHeight: 1.35,\n                maxWidth: \"70%\",\n                textAlign: \"right\",\n              }}\n            >\n              {props.summary}\n            </Text>\n          ) : null}\n        </View>\n\n        <View style={{ flexDirection: \"row\", gap: px(14) }}>\n          {pane(props.left)}\n          {pane(props.right)}\n        </View>\n      </View>\n    </PdfCardShell>\n  );\n}\n\nexport function DiagnosticInterpretationColumnsPdf(\n  props: DiagnosticInterpretationColumnsProps,\n) {\n  const renderColumn = (title: string, body: string) => (\n    <View style={{ flex: 1 }}>\n      <Text\n        style={{\n          color: \"#000000\",\n          fontFamily: \"Times-Roman\",\n          fontSize: px(22),\n          lineHeight: 1.08,\n          marginBottom: px(8),\n        }}\n      >\n        {title}\n      </Text>\n      <Text\n        style={{\n          color: \"#6f7070\",\n          fontFamily: \"Helvetica\",\n          fontSize: px(11.5),\n          lineHeight: 1.55,\n        }}\n      >\n        {body}\n      </Text>\n    </View>\n  );\n\n  return (\n    <View wrap={false} style={{ flexDirection: \"row\", gap: px(24) }}>\n      {renderColumn(\"What this means\", props.meaning)}\n      {renderColumn(\"How to improve\", props.improvement)}\n    </View>\n  );\n}\n\nexport function DiagnosticMetricStatCardPdf(\n  props: DiagnosticMetricStatCardProps,\n) {\n  return (\n    <PdfCardShell compact>\n      <View style={{ gap: px(12) }}>\n        <View\n          style={{\n            alignItems: \"center\",\n            flexDirection: \"row\",\n            justifyContent: \"space-between\",\n          }}\n        >\n          <Text\n            style={{\n              color: \"#202020\",\n              fontFamily: \"Helvetica\",\n              fontSize: px(12),\n              flex: 1,\n            }}\n          >\n            {props.title}\n          </Text>\n          {props.status ? <PdfStatusBadge {...props.status} /> : null}\n        </View>\n\n        <View\n          style={{\n            alignItems: \"flex-end\",\n            flexDirection: \"row\",\n            gap: px(4),\n            justifyContent: \"center\",\n          }}\n        >\n          <Text\n            style={{\n              color: \"#000000\",\n              fontFamily: \"Helvetica\",\n              fontSize: px(48),\n              lineHeight: 1,\n            }}\n          >\n            {formatMetricValue(props.value)}\n          </Text>\n          {props.unit ? (\n            <Text\n              style={{\n                color: \"#000000\",\n                fontFamily: \"Helvetica\",\n                fontSize: px(16),\n                lineHeight: 1,\n              }}\n            >\n              {props.unit}\n            </Text>\n          ) : null}\n        </View>\n      </View>\n    </PdfCardShell>\n  );\n}\n\nexport function DiagnosticMetricRangeCardPdf(\n  props: DiagnosticMetricRangeCardProps,\n) {\n  const isHero = props.layout === \"hero\";\n  const pointerOffset = percentageForValue(\n    props.pointerValue,\n    props.min,\n    props.max,\n  );\n  const highlightLeft = percentageForValue(\n    props.highlightStart ?? props.min,\n    props.min,\n    props.max,\n  );\n  const highlightRight = percentageForValue(\n    props.highlightEnd ?? props.max,\n    props.min,\n    props.max,\n  );\n  const ticks = props.ticks.length > 0 ? props.ticks : [props.min, props.max];\n\n  return (\n    <PdfCardShell compact={!isHero}>\n      <View style={{ gap: px(isHero ? 18 : 14) }}>\n        <View\n          style={{\n            alignItems: \"center\",\n            flexDirection: \"row\",\n            gap: px(16),\n            justifyContent: \"space-between\",\n          }}\n        >\n          <View style={{ flex: 1 }}>\n            <Text\n              style={{\n                color: \"#202020\",\n                fontFamily: \"Helvetica\",\n                flex: 1,\n                fontSize: px(12),\n                lineHeight: 1.35,\n              }}\n            >\n              {props.title}\n            </Text>\n            {props.summary ? (\n              <Text\n                style={{\n                  color: \"#6f7070\",\n                  fontFamily: \"Helvetica\",\n                  fontSize: px(11),\n                  lineHeight: 1.45,\n                  marginTop: px(6),\n                }}\n              >\n                {props.summary}\n              </Text>\n            ) : null}\n          </View>\n          {props.status ? <PdfStatusBadge {...props.status} /> : null}\n        </View>\n\n        <View\n          style={{\n            alignItems: \"flex-end\",\n            flexDirection: \"row\",\n            gap: px(4),\n            justifyContent: \"center\",\n          }}\n        >\n          <Text\n            style={{\n              color: \"#222222\",\n              fontFamily: \"Helvetica\",\n              fontSize: px(48),\n              lineHeight: 1,\n            }}\n          >\n            {formatMetricValue(props.value)}\n          </Text>\n          {props.unit ? (\n            <Text\n              style={{\n                color: \"#222222\",\n                fontFamily: \"Helvetica\",\n                fontSize: px(16),\n                lineHeight: 1,\n              }}\n            >\n              {props.unit}\n            </Text>\n          ) : null}\n        </View>\n\n        <View>\n          <View\n            style={{\n              height: px(18),\n              position: \"relative\",\n            }}\n          >\n            <View\n              style={{\n                backgroundColor: \"#f0f3f7\",\n                borderRadius: px(999),\n                height: px(10),\n                left: 0,\n                position: \"absolute\",\n                right: 0,\n                top: px(6),\n              }}\n            />\n            <View\n              style={{\n                backgroundColor: \"#b8d3ee\",\n                borderRadius: px(999),\n                height: px(10),\n                left: `${Math.min(highlightLeft, highlightRight)}%`,\n                position: \"absolute\",\n                top: px(6),\n                width: `${Math.abs(highlightRight - highlightLeft)}%`,\n              }}\n            />\n            <View\n              style={{\n                left: `${pointerOffset}%`,\n                marginLeft: px(-6),\n                position: \"absolute\",\n                top: 0,\n              }}\n            >\n              <Svg width={px(12)} height={px(19)} viewBox=\"0 0 12 19\">\n                <Path\n                  d=\"M1 1.5C1 0.671573 1.67157 0 2.5 0H9.5C10.3284 0 11 0.671573 11 1.5C11 1.79836 10.911 2.08994 10.7444 2.33744L6 11L1.25559 2.33744C1.08905 2.08994 1 1.79836 1 1.5Z\"\n                  fill=\"#000000\"\n                />\n                <Path d=\"M6 10L6 19\" stroke=\"#cdd5df\" strokeWidth=\"1\" />\n              </Svg>\n            </View>\n          </View>\n          <View\n            style={{\n              flexDirection: \"row\",\n              justifyContent: \"space-between\",\n              marginTop: px(6),\n            }}\n          >\n            {ticks.map((tick) => (\n              <Text\n                key={tick}\n                style={{\n                  color: \"#626262\",\n                  fontFamily: \"Helvetica\",\n                  fontSize: px(10),\n                }}\n              >\n                {tick}\n              </Text>\n            ))}\n          </View>\n        </View>\n      </View>\n    </PdfCardShell>\n  );\n}\n\nexport function DiagnosticMetricDonutCardPdf(\n  props: DiagnosticMetricDonutCardProps,\n) {\n  const circumference = 2 * Math.PI * 42;\n  const progress = clamp(props.progress, 0, 1);\n  const size = props.size === \"compact\" ? px(84) : px(112);\n\n  return (\n    <PdfCardShell compact>\n      <View style={{ gap: px(14) }}>\n        <View\n          style={{\n            alignItems: \"flex-start\",\n            flexDirection: \"row\",\n            gap: px(12),\n            justifyContent: \"space-between\",\n          }}\n        >\n          <Text\n            style={{\n              color: \"#202020\",\n              fontFamily: \"Helvetica\",\n              fontSize: px(12),\n            }}\n          >\n            {props.title}\n          </Text>\n          {props.summary ? (\n            <Text\n              style={{\n                color: \"#6f7070\",\n                fontFamily: \"Helvetica\",\n                fontSize: px(11),\n                lineHeight: 1.35,\n                maxWidth: \"56%\",\n                textAlign: \"right\",\n              }}\n            >\n              {props.summary}\n            </Text>\n          ) : null}\n        </View>\n\n        <View style={{ alignItems: \"center\", justifyContent: \"center\" }}>\n          <View\n            style={{\n              alignItems: \"center\",\n              height: size,\n              justifyContent: \"center\",\n              width: size,\n            }}\n          >\n            <Svg width={size} height={size} viewBox=\"0 0 100 100\">\n              <Circle\n                cx=\"50\"\n                cy=\"50\"\n                r=\"42\"\n                fill=\"none\"\n                stroke=\"#eef2f6\"\n                strokeWidth=\"9\"\n              />\n              <Circle\n                cx=\"50\"\n                cy=\"50\"\n                r=\"42\"\n                fill=\"none\"\n                stroke=\"#b7d2ec\"\n                strokeDasharray={`${circumference * progress} ${circumference}`}\n                strokeLinecap=\"round\"\n                strokeWidth=\"9\"\n                transform=\"rotate(-90 50 50)\"\n              />\n            </Svg>\n            <View\n              style={{\n                alignItems: \"center\",\n                bottom: 0,\n                gap: px(4),\n                justifyContent: \"center\",\n                left: 0,\n                position: \"absolute\",\n                right: 0,\n                top: 0,\n              }}\n            >\n              <Text\n                style={{\n                  color: \"#000000\",\n                  fontFamily: \"Helvetica\",\n                  fontSize: px(props.size === \"compact\" ? 18 : 24),\n                  lineHeight: 1,\n                }}\n              >\n                {formatMetricValue(props.value)}\n              </Text>\n              {props.unit ? (\n                <Text\n                  style={{\n                    color: \"#222222\",\n                    fontFamily: \"Helvetica\",\n                    fontSize: px(9),\n                    lineHeight: 1,\n                  }}\n                >\n                  {props.unit}\n                </Text>\n              ) : null}\n            </View>\n          </View>\n        </View>\n      </View>\n    </PdfCardShell>\n  );\n}\n\nexport function SegmentMuscleAnalysisPdf(props: SegmentMuscleAnalysisProps) {\n  const metricColumn = (items: DiagnosticMetricDonutCardProps[]) => (\n    <View style={{ flex: 1, gap: px(12) }}>\n      {items.map((item, index) => (\n        <DiagnosticMetricDonutCardPdf\n          key={`${item.title}-${index}`}\n          {...item}\n          size=\"compact\"\n        />\n      ))}\n    </View>\n  );\n\n  return (\n    <PdfCardShell>\n      <View style={{ gap: px(14) }}>\n        <View\n          style={{\n            alignItems: \"flex-start\",\n            flexDirection: \"row\",\n            gap: px(16),\n            justifyContent: \"space-between\",\n          }}\n        >\n          <Text\n            style={{\n              color: \"#202020\",\n              fontFamily: \"Helvetica\",\n              fontSize: px(12),\n            }}\n          >\n            {props.title ?? \"Segment Muscular Analysis\"}\n          </Text>\n          {props.summary ? (\n            <Text\n              style={{\n                color: \"#6f7070\",\n                fontFamily: \"Helvetica\",\n                fontSize: px(11),\n                lineHeight: 1.35,\n                maxWidth: \"58%\",\n                textAlign: \"right\",\n              }}\n            >\n              {props.summary}\n            </Text>\n          ) : null}\n        </View>\n\n        <View style={{ flexDirection: \"row\", gap: px(18) }}>\n          {metricColumn(props.leftMetrics)}\n\n          <View\n            style={{\n              alignItems: \"center\",\n              backgroundColor: \"#f7f8fb\",\n              borderRadius: px(18),\n              flex: 1.25,\n              justifyContent: \"center\",\n              minHeight: px(250),\n              overflow: \"hidden\",\n              position: \"relative\",\n            }}\n          >\n            {props.figureUrl ? (\n              <Image\n                src={props.figureUrl}\n                style={{\n                  height: px(240),\n                  objectFit: \"contain\",\n                  width: \"100%\",\n                }}\n              />\n            ) : (\n              <Text\n                style={{\n                  color: \"#6f7070\",\n                  fontFamily: \"Helvetica\",\n                  fontSize: px(11),\n                }}\n              >\n                {props.figureAlt}\n              </Text>\n            )}\n\n            {props.hotspots.map((hotspot, index) => (\n              <View\n                key={`${hotspot.x}-${hotspot.y}-${index}`}\n                style={{\n                  backgroundColor: \"#ffc700\",\n                  borderColor: \"#ffffff\",\n                  borderRadius: px(999),\n                  borderStyle: \"solid\",\n                  borderWidth: px(2),\n                  height: px(10),\n                  left: `${hotspot.x * 100}%`,\n                  position: \"absolute\",\n                  top: `${hotspot.y * 100}%`,\n                  width: px(10),\n                }}\n              />\n            ))}\n          </View>\n\n          {metricColumn(props.rightMetrics)}\n        </View>\n      </View>\n    </PdfCardShell>\n  );\n}\n\nexport function renderPatientResultsPdfBlock(block: PatientResultsBlock) {\n  switch (block.type) {\n    case \"diagnosticMetricRange\":\n      return <DiagnosticMetricRangeCardPdf {...block.props} />;\n    case \"diagnosticMetricDonut\":\n      return <DiagnosticMetricDonutCardPdf {...block.props} />;\n    case \"diagnosticMetricSplit\":\n      return <DiagnosticMetricSplitCardPdf {...block.props} />;\n    case \"diagnosticMetricStat\":\n      return <DiagnosticMetricStatCardPdf {...block.props} />;\n    case \"diagnosticInterpretation\":\n      return <DiagnosticInterpretationColumnsPdf {...block.props} />;\n    case \"segmentMuscleAnalysis\":\n      return <SegmentMuscleAnalysisPdf {...block.props} />;\n    default:\n      return null;\n  }\n}\n\nfunction spanStyle(span: PatientResultsBlockSpan | undefined) {\n  if (span === \"half\") return { width: \"48.75%\" };\n  if (span === \"third\") return { width: \"31.5%\" };\n  return { width: \"100%\" };\n}\n\nfunction groupedRows(blocks: PatientResultsBlock[]) {\n  const rows: PatientResultsBlock[][] = [];\n  let currentRow: PatientResultsBlock[] = [];\n  let used = 0;\n\n  for (const block of blocks) {\n    const span = block.span === \"half\" ? 6 : block.span === \"third\" ? 4 : 12;\n    if (used + span > 12 || span === 12) {\n      if (currentRow.length > 0) {\n        rows.push(currentRow);\n        currentRow = [];\n        used = 0;\n      }\n\n      if (span === 12) {\n        rows.push([block]);\n        continue;\n      }\n    }\n\n    currentRow.push(block);\n    used += span;\n  }\n\n  if (currentRow.length > 0) {\n    rows.push(currentRow);\n  }\n\n  return rows;\n}\n\nfunction estimatePdfBlockHeight(block: PatientResultsBlock) {\n  switch (block.type) {\n    case \"diagnosticMetricRange\":\n      return px(block.props.layout === \"hero\" ? 190 : 170);\n    case \"diagnosticMetricDonut\":\n      return px(block.props.size === \"compact\" ? 150 : 180);\n    case \"diagnosticMetricSplit\":\n      return px(195);\n    case \"diagnosticMetricStat\":\n      return px(150);\n    case \"diagnosticInterpretation\":\n      return px(180);\n    case \"segmentMuscleAnalysis\":\n      return px(320);\n    default:\n      return px(180);\n  }\n}\n\nfunction estimatePdfRowHeight(row: PatientResultsBlock[]) {\n  return Math.max(...row.map((block) => estimatePdfBlockHeight(block)));\n}\n\ntype PatientResultsPdfPageChunk = {\n  id: string;\n  intro?: PatientResultsReportPage[\"intro\"];\n  rows: PatientResultsBlock[][];\n};\n\nfunction chunkPatientResultsPdfPage(page: PatientResultsReportPage) {\n  const rows = groupedRows(page.blocks);\n  const chunks: PatientResultsPdfPageChunk[] = [];\n\n  let currentRows: PatientResultsBlock[][] = [];\n  let usedHeight = page.intro\n    ? PDF_INTRO_ESTIMATED_HEIGHT + PDF_SECTION_GAP\n    : 0;\n\n  const pushChunk = () => {\n    if (!currentRows.length && chunks.length > 0) {\n      return;\n    }\n\n    chunks.push({\n      id: `${page.id}-part-${chunks.length + 1}`,\n      intro: chunks.length === 0 ? page.intro : undefined,\n      rows: currentRows,\n    });\n\n    currentRows = [];\n    usedHeight = 0;\n  };\n\n  for (const row of rows) {\n    const rowHeight = estimatePdfRowHeight(row);\n    const nextHeight =\n      usedHeight + rowHeight + (currentRows.length > 0 ? PDF_ROW_GAP : 0);\n\n    if (currentRows.length > 0 && nextHeight > PDF_PAGE_CONTENT_BUDGET) {\n      pushChunk();\n    }\n\n    if (currentRows.length > 0) {\n      usedHeight += PDF_ROW_GAP;\n    }\n\n    currentRows.push(row);\n    usedHeight += rowHeight;\n  }\n\n  if (currentRows.length > 0 || chunks.length === 0) {\n    pushChunk();\n  }\n\n  return chunks;\n}\n\nexport interface PatientResultsPdfPageProps {\n  page: PatientResultsReportPage;\n  chunk: PatientResultsPdfPageChunk;\n  dateLabel?: string;\n}\n\nexport function PatientResultsPdfPage({\n  page,\n  chunk,\n  dateLabel,\n}: PatientResultsPdfPageProps) {\n  return (\n    <Page\n      size=\"A4\"\n      style={{\n        backgroundColor: \"#ffffff\",\n        color: \"#000000\",\n        paddingBottom: px(34),\n        paddingHorizontal: px(36),\n        paddingTop: px(32),\n      }}\n    >\n      <View\n        style={{\n          flex: 1,\n          justifyContent: \"space-between\",\n        }}\n      >\n        <View style={{ gap: PDF_SECTION_GAP }}>\n          <DiagnosticReportHeaderPdf dateLabel={dateLabel} />\n\n          {chunk.intro ? <DiagnosticReportIntroPdf {...chunk.intro} /> : null}\n\n          <View style={{ gap: PDF_ROW_GAP }}>\n            {chunk.rows.map((row, rowIndex) => (\n              <View\n                key={`${chunk.id}-row-${rowIndex}`}\n                wrap={false}\n                style={{\n                  flexDirection: row.length === 1 ? \"column\" : \"row\",\n                  gap: PDF_ROW_GAP,\n                }}\n              >\n                {row.map((block, blockIndex) => (\n                  <View\n                    key={`${chunk.id}-${block.type}-${rowIndex}-${blockIndex}`}\n                    style={spanStyle(block.span)}\n                  >\n                    {renderPatientResultsPdfBlock(block)}\n                  </View>\n                ))}\n              </View>\n            ))}\n          </View>\n        </View>\n\n        <DiagnosticReportFooterPdf {...page.footer} />\n      </View>\n    </Page>\n  );\n}\n\nexport interface PatientResultsPdfDocumentProps {\n  preset: PatientResultsReportPreset;\n  dateLabel?: string;\n}\n\nexport function PatientResultsPdfDocument({\n  preset,\n  dateLabel,\n}: PatientResultsPdfDocumentProps) {\n  return (\n    <Document title={preset.title}>\n      {preset.pages.flatMap((page) =>\n        chunkPatientResultsPdfPage(page).map((chunk) => (\n          <PatientResultsPdfPage\n            key={chunk.id}\n            page={page}\n            chunk={chunk}\n            dateLabel={dateLabel}\n          />\n        )),\n      )}\n    </Document>\n  );\n}\n\nexport interface PatientResultsPdfDocumentFromEditorProps {\n  presetId: PatientResultsReportPreset[\"id\"];\n  document: EditorLikeBlock[];\n  dateLabel?: string;\n}\n\nexport function PatientResultsPdfDocumentFromEditor({\n  presetId,\n  document,\n  dateLabel,\n}: PatientResultsPdfDocumentFromEditorProps) {\n  const preset = createPatientResultsPresetFromEditorDocument(\n    presetId,\n    document,\n  );\n\n  return <PatientResultsPdfDocument preset={preset} dateLabel={dateLabel} />;\n}\n\nexport function Vo2MaxReportPdf({ dateLabel }: { dateLabel?: string }) {\n  return (\n    <PatientResultsPdfDocument\n      preset={getPatientResultsPreset(\"vo2-max-report\")}\n      dateLabel={dateLabel}\n    />\n  );\n}\n\nexport function VnsReportPdf({ dateLabel }: { dateLabel?: string }) {\n  return (\n    <PatientResultsPdfDocument\n      preset={getPatientResultsPreset(\"vns-report\")}\n      dateLabel={dateLabel}\n    />\n  );\n}\n\nexport function BodyCompositionReportPdf({\n  dateLabel,\n}: {\n  dateLabel?: string;\n}) {\n  return (\n    <PatientResultsPdfDocument\n      preset={getPatientResultsPreset(\"body-composition-report\")}\n      dateLabel={dateLabel}\n    />\n  );\n}\n",
      "type": "registry:lib"
    }
  ],
  "type": "registry:lib"
}