diff --git a/src/components/ClaimDrawer/RawSegmentsPanel.test.tsx b/src/components/ClaimDrawer/RawSegmentsPanel.test.tsx
new file mode 100644
index 0000000..d64407d
--- /dev/null
+++ b/src/components/ClaimDrawer/RawSegmentsPanel.test.tsx
@@ -0,0 +1,203 @@
+// @vitest-environment happy-dom
+// Pure prop-driven component; match the act() convention used by the
+// other ClaimDrawer test files (ClaimDrawerHeader / ClaimDrawerSkeleton /
+// ClaimDrawerError / ValidationPanel / ServiceLinesTable / DiagnosesList
+// / PartiesGrid).
+(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
+
+import React, { act } from "react";
+import { createRoot, type Root } from "react-dom/client";
+import { describe, expect, it } from "vitest";
+import { RawSegmentsPanel } from "./RawSegmentsPanel";
+
+function renderIntoContainer(element: React.ReactElement): {
+ container: HTMLDivElement;
+ unmount: () => void;
+} {
+ const container = document.createElement("div");
+ document.body.appendChild(container);
+ const root: Root = createRoot(container);
+ act(() => {
+ root.render(element);
+ });
+ return {
+ container,
+ unmount: () => {
+ act(() => root.unmount());
+ container.remove();
+ },
+ };
+}
+
+describe("RawSegmentsPanel", () => {
+ it("test_section_label_includes_count", () => {
+ const segments = [
+ ["ISA", "00", " ", "00", " ", "ZZ", "SUBMITTERID ", "ZZ", "RECEIVERID ", "260615", "1200", "^", "00501", "000000001", "0", "P", ":"],
+ ["GS", "HC", "SUBMITTERID", "RECEIVERID", "20260615", "1200", "1", "X", "005010X222A1"],
+ ["ST", "837", "0001", "005010X222A1"],
+ ];
+
+ const { container, unmount } = renderIntoContainer(
+
with segments is NOT rendered in the empty state.
+ expect(
+ container.querySelector('[data-testid="raw-segments-pre"]')
+ ).toBeNull();
+
+ // The / are still present so the user can see
+ // the section header even when there's nothing inside.
+ const details = container.querySelector("details");
+ expect(details).not.toBeNull();
+ const summary = container.querySelector("summary");
+ expect(summary).not.toBeNull();
+
+ unmount();
+ });
+
+ it("test_uses_monospace_font_for_pre_block", () => {
+ const segments = [["ST", "837", "0001"]];
+
+ const { container, unmount } = renderIntoContainer(
+
+ );
+
+ const summary = container.querySelector("summary");
+ act(() => {
+ summary?.dispatchEvent(
+ new MouseEvent("click", { bubbles: true, cancelable: true })
+ );
+ });
+
+ const pre = container.querySelector('[data-testid="raw-segments-pre"]');
+ expect(pre).not.toBeNull();
+ // The mono styling is either via class or inline style; sniff both.
+ const cls = pre?.className ?? "";
+ const style = pre?.getAttribute("style") ?? "";
+ const isMono =
+ cls.includes("font-mono") ||
+ style.includes("--m-font-mono") ||
+ style.includes("font-mono");
+ expect(isMono).toBe(true);
+
+ unmount();
+ });
+});
diff --git a/src/components/ClaimDrawer/RawSegmentsPanel.tsx b/src/components/ClaimDrawer/RawSegmentsPanel.tsx
new file mode 100644
index 0000000..2ae2d74
--- /dev/null
+++ b/src/components/ClaimDrawer/RawSegmentsPanel.tsx
@@ -0,0 +1,75 @@
+import React from "react";
+import type { ClaimDetail } from "@/types";
+
+type RawSegmentsPanelProps = {
+ rawSegments: ClaimDetail["rawSegments"];
+};
+
+/**
+ * Format a single segment by joining its elements with `*` (the X12
+ * element separator). Trailing/leading whitespace inside individual
+ * elements is preserved — these strings come straight off the parser
+ * and any trimming would change the visible byte-for-byte content.
+ */
+function formatSegment(elements: string[]): string {
+ return elements.join("*");
+}
+
+/**
+ * Raw-segments debug section of the claim detail drawer (SP4).
+ *
+ * Renders the exact X12 segment strings the parser saw, collapsed by
+ * default behind a native / so the user can opt in
+ * to a wall of monospace when they're debugging. Element separator is
+ * `*` and segment terminator is implicit at the end of each line —
+ * matches what the parser produces. This is a read-only diagnostic;
+ * the plan keeps it intentionally simple (no copy button for v1).
+ */
+export function RawSegmentsPanel({ rawSegments }: RawSegmentsPanelProps) {
+ return (
+
+
+ Raw Segments ({rawSegments.length})
+
+
+
+
+ {rawSegments.length === 0
+ ? "Show raw segments"
+ : "Show raw segments"}
+
+
+ {rawSegments.length === 0 ? (
+
+ No segments
+
+ ) : (
+
+ {rawSegments.map((segment, i) => (
+
+ {i > 0 ? "\n" : null}
+ {formatSegment(segment)}
+
+ ))}
+
+ )}
+
+
+ );
+}