diff --git a/src/components/pages/CoffinsStep/CoffinsStep.stories.tsx b/src/components/pages/CoffinsStep/CoffinsStep.stories.tsx
new file mode 100644
index 0000000..763908a
--- /dev/null
+++ b/src/components/pages/CoffinsStep/CoffinsStep.stories.tsx
@@ -0,0 +1,200 @@
+import { useState } from 'react';
+import type { Meta, StoryObj } from '@storybook/react';
+import { CoffinsStep } from './CoffinsStep';
+import type { CoffinsStepValues, CoffinsStepErrors, Coffin } from './CoffinsStep';
+import { Navigation } from '../../organisms/Navigation';
+import Box from '@mui/material/Box';
+
+// ─── Helpers ─────────────────────────────────────────────────────────────────
+
+const FALogo = () => (
+
+
+
+
+);
+
+const nav = (
+ }
+ items={[
+ { label: 'FAQ', href: '/faq' },
+ { label: 'Contact Us', href: '/contact' },
+ ]}
+ />
+);
+
+const sampleCoffins: Coffin[] = [
+ {
+ id: 'cedar-classic',
+ name: 'Cedar Classic',
+ imageUrl: 'https://images.unsplash.com/photo-1618220179428-22790b461013?w=400&h=300&fit=crop',
+ price: 2800,
+ category: 'Solid Timber',
+ isPopular: true,
+ },
+ {
+ id: 'oak-heritage',
+ name: 'Oak Heritage',
+ imageUrl: 'https://images.unsplash.com/photo-1555041469-a586c1029ad9?w=400&h=300&fit=crop',
+ price: 3500,
+ category: 'Solid Timber',
+ },
+ {
+ id: 'eco-willow',
+ name: 'Eco Willow Basket',
+ imageUrl: 'https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=400&h=300&fit=crop',
+ price: 1200,
+ category: 'Environmental',
+ isPopular: true,
+ },
+ {
+ id: 'maple-serenity',
+ name: 'Maple Serenity',
+ imageUrl: 'https://images.unsplash.com/photo-1449247709967-d4461a6a6103?w=400&h=300&fit=crop',
+ price: 4200,
+ category: 'Solid Timber',
+ },
+ {
+ id: 'custom-rose',
+ name: 'Custom Rose Garden',
+ imageUrl: 'https://images.unsplash.com/photo-1490750967868-88aa4f44baee?w=400&h=300&fit=crop',
+ price: 1800,
+ category: 'Custom Board',
+ },
+ {
+ id: 'bronze-eternal',
+ name: 'Bronze Eternal',
+ imageUrl: 'https://images.unsplash.com/photo-1432462770865-65b70566d673?w=400&h=300&fit=crop',
+ price: 6500,
+ category: 'Protective Metal',
+ },
+];
+
+const defaultValues: CoffinsStepValues = {
+ selectedCoffinId: null,
+ categoryFilter: 'all',
+ priceFilter: 'all',
+ page: 1,
+};
+
+// ─── Meta ────────────────────────────────────────────────────────────────────
+
+const meta: Meta = {
+ title: 'Pages/CoffinsStep',
+ component: CoffinsStep,
+ tags: ['autodocs'],
+ parameters: {
+ layout: 'fullscreen',
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+// ─── Interactive (default) ──────────────────────────────────────────────────
+
+/** Full catalogue with filters */
+export const Default: Story = {
+ render: () => {
+ const [values, setValues] = useState({ ...defaultValues });
+ const [errors, setErrors] = useState({});
+
+ const handleContinue = () => {
+ if (!values.selectedCoffinId) {
+ setErrors({ selectedCoffinId: 'Please choose a coffin to continue.' });
+ return;
+ }
+ alert(`Selected: ${values.selectedCoffinId}`);
+ };
+
+ return (
+ {
+ setValues(v);
+ setErrors({});
+ }}
+ onContinue={handleContinue}
+ onBack={() => alert('Back')}
+ onSaveAndExit={() => alert('Save')}
+ errors={errors}
+ coffins={sampleCoffins}
+ totalCount={19}
+ totalPages={2}
+ navigation={nav}
+ />
+ );
+ },
+};
+
+// ─── Coffin selected ────────────────────────────────────────────────────────
+
+/** A coffin is already selected */
+export const CoffinSelected: Story = {
+ render: () => {
+ const [values, setValues] = useState({
+ ...defaultValues,
+ selectedCoffinId: 'cedar-classic',
+ });
+ return (
+ alert('Continue')}
+ onBack={() => alert('Back')}
+ coffins={sampleCoffins}
+ navigation={nav}
+ />
+ );
+ },
+};
+
+// ─── Pre-planning ───────────────────────────────────────────────────────────
+
+/** Pre-planning variant */
+export const PrePlanning: Story = {
+ render: () => {
+ const [values, setValues] = useState({ ...defaultValues });
+ return (
+ alert('Continue')}
+ onBack={() => alert('Back')}
+ coffins={sampleCoffins}
+ isPrePlanning
+ navigation={nav}
+ />
+ );
+ },
+};
+
+// ─── Validation error ───────────────────────────────────────────────────────
+
+/** No coffin selected with error */
+export const WithError: Story = {
+ render: () => {
+ const [values, setValues] = useState({ ...defaultValues });
+ return (
+ {}}
+ errors={{ selectedCoffinId: 'Please choose a coffin to continue.' }}
+ coffins={sampleCoffins}
+ navigation={nav}
+ />
+ );
+ },
+};
diff --git a/src/components/pages/CoffinsStep/CoffinsStep.tsx b/src/components/pages/CoffinsStep/CoffinsStep.tsx
new file mode 100644
index 0000000..7d8a074
--- /dev/null
+++ b/src/components/pages/CoffinsStep/CoffinsStep.tsx
@@ -0,0 +1,350 @@
+import React from 'react';
+import Box from '@mui/material/Box';
+import TextField from '@mui/material/TextField';
+import MenuItem from '@mui/material/MenuItem';
+import Pagination from '@mui/material/Pagination';
+import type { SxProps, Theme } from '@mui/material/styles';
+import { WizardLayout } from '../../templates/WizardLayout';
+import { Card } from '../../atoms/Card';
+import { Badge } from '../../atoms/Badge';
+import { Typography } from '../../atoms/Typography';
+import { Button } from '../../atoms/Button';
+import { Divider } from '../../atoms/Divider';
+
+// ─── Types ───────────────────────────────────────────────────────────────────
+
+/** A coffin available for selection */
+export interface Coffin {
+ id: string;
+ name: string;
+ imageUrl: string;
+ price: number;
+ category: string;
+ isPopular?: boolean;
+}
+
+/** Filter category option */
+export interface CoffinCategory {
+ value: string;
+ label: string;
+}
+
+/** Price range filter option */
+export interface CoffinPriceRange {
+ value: string;
+ label: string;
+}
+
+/** Form values for the coffins step */
+export interface CoffinsStepValues {
+ /** Selected coffin ID */
+ selectedCoffinId: string | null;
+ /** Active category filter */
+ categoryFilter: string;
+ /** Active price filter */
+ priceFilter: string;
+ /** Current page (1-indexed) */
+ page: number;
+}
+
+/** Field-level error messages */
+export interface CoffinsStepErrors {
+ selectedCoffinId?: string;
+}
+
+/** Props for the CoffinsStep page component */
+export interface CoffinsStepProps {
+ /** Current form values */
+ values: CoffinsStepValues;
+ /** Callback when any field value changes */
+ onChange: (values: CoffinsStepValues) => void;
+ /** Callback when the Continue button is clicked */
+ onContinue: () => void;
+ /** Callback for back navigation */
+ onBack?: () => void;
+ /** Callback for save-and-exit */
+ onSaveAndExit?: () => void;
+ /** Field-level validation errors */
+ errors?: CoffinsStepErrors;
+ /** Whether the Continue button is in a loading state */
+ loading?: boolean;
+ /** Available coffins (already filtered by parent) */
+ coffins: Coffin[];
+ /** Total count before pagination (for display) */
+ totalCount?: number;
+ /** Total pages */
+ totalPages?: number;
+ /** Category filter options */
+ categories?: CoffinCategory[];
+ /** Price range filter options */
+ priceRanges?: CoffinPriceRange[];
+ /** Whether this is a pre-planning flow */
+ isPrePlanning?: boolean;
+ /** Navigation bar */
+ navigation?: React.ReactNode;
+ /** Progress stepper */
+ progressStepper?: React.ReactNode;
+ /** Running total */
+ runningTotal?: React.ReactNode;
+ /** Hide the help bar */
+ hideHelpBar?: boolean;
+ /** MUI sx prop */
+ sx?: SxProps;
+}
+
+// ─── Component ───────────────────────────────────────────────────────────────
+
+/**
+ * Step 10 — Coffin selection for the FA arrangement wizard.
+ *
+ * Grid-sidebar layout: filter sidebar (left/top on mobile) + coffin
+ * card grid (main area). Cards show image, name, price, and optional
+ * "Most Popular" badge (Rec #10). Pagination at the bottom.
+ *
+ * Uses Australian terminology: "coffin" not "casket" (both types may
+ * appear in the catalogue — the product type is shown per card).
+ *
+ * Pure presentation component — props in, callbacks out.
+ * Filtering and pagination logic handled by parent.
+ *
+ * Spec: documentation/steps/steps/10_coffins.yaml
+ */
+export const CoffinsStep: React.FC = ({
+ values,
+ onChange,
+ onContinue,
+ onBack,
+ onSaveAndExit,
+ errors,
+ loading = false,
+ coffins,
+ totalCount,
+ totalPages = 1,
+ categories = [
+ { value: 'all', label: 'All categories' },
+ { value: 'solid_timber', label: 'Solid Timber' },
+ { value: 'custom_board', label: 'Custom Board' },
+ { value: 'environmental', label: 'Environmental' },
+ { value: 'designer', label: 'Designer' },
+ { value: 'protective_metal', label: 'Protective Metal' },
+ ],
+ priceRanges = [
+ { value: 'all', label: 'All prices' },
+ { value: 'under_2000', label: 'Under $2,000' },
+ { value: '2000_4000', label: '$2,000 – $4,000' },
+ { value: 'over_4000', label: 'Over $4,000' },
+ ],
+ isPrePlanning = false,
+ navigation,
+ progressStepper,
+ runningTotal,
+ hideHelpBar,
+ sx,
+}) => {
+ const displayCount = totalCount ?? coffins.length;
+
+ const handleFilterChange = (field: 'categoryFilter' | 'priceFilter', value: string) => {
+ onChange({ ...values, [field]: value, page: 1 });
+ };
+
+ return (
+
+ {/* Page heading */}
+
+ Choose a coffin
+
+
+
+ {isPrePlanning
+ ? 'Browse the range to get an idea of styles and pricing. You can change your selection later.'
+ : 'Browse the range available with your selected provider. Use the filters to narrow your options.'}
+
+
+
+ Selecting a coffin within your package allowance won't change your total. Coffins
+ outside the allowance will adjust the price.
+
+
+ {
+ e.preventDefault();
+ onContinue();
+ }}
+ >
+ {/* ─── Filters ─── */}
+
+ handleFilterChange('categoryFilter', e.target.value)}
+ sx={{ minWidth: 200 }}
+ >
+ {categories.map((cat) => (
+
+ ))}
+
+
+ handleFilterChange('priceFilter', e.target.value)}
+ sx={{ minWidth: 200 }}
+ >
+ {priceRanges.map((range) => (
+
+ ))}
+
+
+
+ {/* ─── Results count ─── */}
+
+ Showing {displayCount} coffin{displayCount !== 1 ? 's' : ''}
+
+
+ {/* ─── Coffin card grid ─── */}
+
+ {coffins.map((coffin, index) => (
+ onChange({ ...values, selectedCoffinId: coffin.id })}
+ role="radio"
+ aria-checked={coffin.id === values.selectedCoffinId}
+ tabIndex={
+ values.selectedCoffinId === null
+ ? index === 0
+ ? 0
+ : -1
+ : coffin.id === values.selectedCoffinId
+ ? 0
+ : -1
+ }
+ sx={{ overflow: 'hidden' }}
+ >
+ {/* Image */}
+
+ {coffin.isPopular && (
+
+
+ Most Popular
+
+
+ )}
+
+
+ {/* Content */}
+
+
+ {coffin.name}
+
+
+ {coffin.category}
+
+
+ ${coffin.price.toLocaleString('en-AU')}
+
+
+
+ ))}
+
+
+ {/* Validation error */}
+ {errors?.selectedCoffinId && (
+
+ {errors.selectedCoffinId}
+
+ )}
+
+ {/* Pagination */}
+ {totalPages > 1 && (
+
+ onChange({ ...values, page })}
+ color="primary"
+ />
+
+ )}
+
+
+
+ {/* CTAs */}
+
+ {onSaveAndExit ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ );
+};
+
+CoffinsStep.displayName = 'CoffinsStep';
+export default CoffinsStep;
diff --git a/src/components/pages/CoffinsStep/index.ts b/src/components/pages/CoffinsStep/index.ts
new file mode 100644
index 0000000..6f16c39
--- /dev/null
+++ b/src/components/pages/CoffinsStep/index.ts
@@ -0,0 +1,9 @@
+export { CoffinsStep, default } from './CoffinsStep';
+export type {
+ CoffinsStepProps,
+ CoffinsStepValues,
+ CoffinsStepErrors,
+ Coffin,
+ CoffinCategory,
+ CoffinPriceRange,
+} from './CoffinsStep';