diff --git a/src/components/pages/AdditionalServicesStep/AdditionalServicesStep.stories.tsx b/src/components/pages/AdditionalServicesStep/AdditionalServicesStep.stories.tsx
new file mode 100644
index 0000000..090a26c
--- /dev/null
+++ b/src/components/pages/AdditionalServicesStep/AdditionalServicesStep.stories.tsx
@@ -0,0 +1,157 @@
+import { useState } from 'react';
+import type { Meta, StoryObj } from '@storybook/react';
+import { AdditionalServicesStep } from './AdditionalServicesStep';
+import type { AdditionalServicesStepValues } from './AdditionalServicesStep';
+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 defaultValues: AdditionalServicesStepValues = {
+ dressing: false,
+ viewing: false,
+ viewingSameVenue: null,
+ prayers: false,
+ funeralAnnouncement: true,
+ catering: false,
+ music: false,
+ liveMusician: false,
+ musicianType: null,
+ bearing: null,
+ newspaperNotice: false,
+};
+
+// ─── Meta ────────────────────────────────────────────────────────────────────
+
+const meta: Meta = {
+ title: 'Pages/AdditionalServicesStep',
+ component: AdditionalServicesStep,
+ tags: ['autodocs'],
+ parameters: {
+ layout: 'fullscreen',
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+// ─── Interactive (default) ──────────────────────────────────────────────────
+
+/** Full interactive flow with both sections */
+export const Default: Story = {
+ render: () => {
+ const [values, setValues] = useState({ ...defaultValues });
+ return (
+ alert(JSON.stringify(values, null, 2))}
+ onBack={() => alert('Back')}
+ onSaveAndExit={() => alert('Save')}
+ newspaperPrice={250}
+ musicianPrice={450}
+ navigation={nav}
+ />
+ );
+ },
+};
+
+// ─── Many options enabled ───────────────────────────────────────────────────
+
+/** Multiple services toggled on with sub-options visible */
+export const ManyOptionsEnabled: Story = {
+ render: () => {
+ const [values, setValues] = useState({
+ dressing: true,
+ viewing: true,
+ viewingSameVenue: 'yes',
+ prayers: false,
+ funeralAnnouncement: true,
+ catering: true,
+ music: true,
+ liveMusician: true,
+ musicianType: 'vocalist',
+ bearing: 'both',
+ newspaperNotice: true,
+ });
+ return (
+ alert('Continue')}
+ onBack={() => alert('Back')}
+ cateringPrice={850}
+ newspaperPrice={250}
+ musicianPrice={450}
+ navigation={nav}
+ />
+ );
+ },
+};
+
+// ─── Pre-planning ───────────────────────────────────────────────────────────
+
+/** Pre-planning variant */
+export const PrePlanning: Story = {
+ render: () => {
+ const [values, setValues] = useState({ ...defaultValues });
+ return (
+ alert('Continue')}
+ onBack={() => alert('Back')}
+ isPrePlanning
+ navigation={nav}
+ />
+ );
+ },
+};
+
+// ─── Minimal (provider shows few options) ───────────────────────────────────
+
+/** Announcement only — minimal provider offerings */
+export const Minimal: Story = {
+ render: () => {
+ const [values, setValues] = useState({
+ ...defaultValues,
+ funeralAnnouncement: true,
+ });
+ return (
+ alert('Continue')}
+ onBack={() => alert('Back')}
+ navigation={nav}
+ />
+ );
+ },
+};
diff --git a/src/components/pages/AdditionalServicesStep/AdditionalServicesStep.tsx b/src/components/pages/AdditionalServicesStep/AdditionalServicesStep.tsx
new file mode 100644
index 0000000..2813f41
--- /dev/null
+++ b/src/components/pages/AdditionalServicesStep/AdditionalServicesStep.tsx
@@ -0,0 +1,352 @@
+import React from 'react';
+import Box from '@mui/material/Box';
+import Paper from '@mui/material/Paper';
+import FormControl from '@mui/material/FormControl';
+import FormLabel from '@mui/material/FormLabel';
+import FormControlLabel from '@mui/material/FormControlLabel';
+import RadioGroup from '@mui/material/RadioGroup';
+import Radio from '@mui/material/Radio';
+import type { SxProps, Theme } from '@mui/material/styles';
+import { WizardLayout } from '../../templates/WizardLayout';
+import { AddOnOption } from '../../molecules/AddOnOption';
+import { Collapse } from '../../atoms/Collapse';
+import { Typography } from '../../atoms/Typography';
+import { Button } from '../../atoms/Button';
+import { Divider } from '../../atoms/Divider';
+
+// ─── Types ───────────────────────────────────────────────────────────────────
+
+/** Form values for the additional services step */
+export interface AdditionalServicesStepValues {
+ // Section 1: Complimentary inclusions
+ dressing: boolean;
+ viewing: boolean;
+ viewingSameVenue: 'yes' | 'no' | null;
+ prayers: boolean;
+ funeralAnnouncement: boolean;
+
+ // Section 2: Paid extras
+ catering: boolean;
+ music: boolean;
+ liveMusician: boolean;
+ musicianType: 'vocalist' | 'cellist' | 'other' | null;
+ bearing: 'family' | 'funeralHouse' | 'both' | null;
+ newspaperNotice: boolean;
+}
+
+/** Props for the AdditionalServicesStep page component */
+export interface AdditionalServicesStepProps {
+ /** Current form values */
+ values: AdditionalServicesStepValues;
+ /** Callback when any field value changes */
+ onChange: (values: AdditionalServicesStepValues) => void;
+ /** Callback when the Continue button is clicked */
+ onContinue: () => void;
+ /** Callback for back navigation */
+ onBack?: () => void;
+ /** Callback for save-and-exit */
+ onSaveAndExit?: () => void;
+ /** Whether the Continue button is in a loading state */
+ loading?: boolean;
+ /** Price for catering (undefined = POA) */
+ cateringPrice?: number;
+ /** Price for newspaper notice (undefined = POA) */
+ newspaperPrice?: number;
+ /** Price for live musician (undefined = POA) */
+ musicianPrice?: number;
+ /** 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 12 — Additional Services for the FA arrangement wizard.
+ *
+ * Merged from baseline steps 14 (optionals) and 15 (extras) per Rec #2.
+ * Two sections preserving the semantic distinction:
+ * 1. Complimentary inclusions (toggle on/off at no cost)
+ * 2. Paid extras (toggle with pricing or POA)
+ *
+ * Progressive disclosure: sub-options revealed when parent toggle is on.
+ * Toggle design is inherently low-pressure — no upsell language.
+ *
+ * Pure presentation component — props in, callbacks out.
+ *
+ * Spec: documentation/steps/steps/12_additional_services.yaml
+ */
+export const AdditionalServicesStep: React.FC = ({
+ values,
+ onChange,
+ onContinue,
+ onBack,
+ onSaveAndExit,
+ loading = false,
+ cateringPrice,
+ newspaperPrice,
+ musicianPrice,
+ isPrePlanning = false,
+ navigation,
+ progressStepper,
+ runningTotal,
+ hideHelpBar,
+ sx,
+}) => {
+ const handleToggle = (field: keyof AdditionalServicesStepValues, checked: boolean) => {
+ const next = { ...values, [field]: checked };
+ // Reset dependent fields when parent toggled off
+ if (field === 'viewing' && !checked) {
+ next.viewingSameVenue = null;
+ }
+ if (field === 'music' && !checked) {
+ next.liveMusician = false;
+ next.musicianType = null;
+ }
+ if (field === 'liveMusician' && !checked) {
+ next.musicianType = null;
+ }
+ onChange(next);
+ };
+
+ const handleFieldChange = (
+ field: K,
+ value: AdditionalServicesStepValues[K],
+ ) => {
+ onChange({ ...values, [field]: value });
+ };
+
+ return (
+
+ {/* Page heading */}
+
+ Additional services
+
+
+
+ {isPrePlanning
+ ? "These options can be finalised later. Toggle on the ones you're interested in."
+ : 'Choose which services to include in your plan.'}
+
+
+ {
+ e.preventDefault();
+ onContinue();
+ }}
+ >
+ {/* ─── Section 1: Complimentary inclusions ─── */}
+
+
+ Complimentary inclusions
+
+
+ These items are included at no additional cost. You can choose to include or remove
+ them.
+
+
+
+ handleToggle('dressing', c)}
+ />
+
+ handleToggle('viewing', c)}
+ />
+
+
+
+
+
+ Same venue as the service?
+
+
+ handleFieldChange(
+ 'viewingSameVenue',
+ e.target.value as AdditionalServicesStepValues['viewingSameVenue'],
+ )
+ }
+ >
+ } label="Yes, same venue" />
+ } label="No, different venue" />
+
+
+
+
+
+ handleToggle('prayers', c)}
+ />
+
+ handleToggle('funeralAnnouncement', c)}
+ />
+
+
+
+ {/* ─── Section 2: Paid extras ─── */}
+
+
+ Additional extras
+
+
+ These items are available but may incur additional costs. Prices shown where available.
+
+
+
+ handleToggle('catering', c)}
+ />
+
+ handleToggle('music', c)}
+ />
+
+
+
+ handleToggle('liveMusician', c)}
+ />
+
+
+
+
+
+ Musician type
+
+
+ handleFieldChange(
+ 'musicianType',
+ e.target.value as AdditionalServicesStepValues['musicianType'],
+ )
+ }
+ >
+ } label="Vocalist" />
+ } label="Cellist" />
+ } label="Other" />
+
+
+
+
+
+
+
+ {/* Coffin bearing */}
+
+
+
+ Coffin bearing
+
+
+ handleFieldChange(
+ 'bearing',
+ e.target.value as AdditionalServicesStepValues['bearing'],
+ )
+ }
+ >
+ } label="Family and friends" />
+ }
+ label="Professional bearers"
+ />
+ }
+ label="Both family and professional"
+ />
+
+
+
+
+
+ handleToggle('newspaperNotice', c)}
+ />
+
+
+
+
+
+ {/* CTAs */}
+
+ {onSaveAndExit ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ );
+};
+
+AdditionalServicesStep.displayName = 'AdditionalServicesStep';
+export default AdditionalServicesStep;
diff --git a/src/components/pages/AdditionalServicesStep/index.ts b/src/components/pages/AdditionalServicesStep/index.ts
new file mode 100644
index 0000000..23af28d
--- /dev/null
+++ b/src/components/pages/AdditionalServicesStep/index.ts
@@ -0,0 +1,5 @@
+export { AdditionalServicesStep, default } from './AdditionalServicesStep';
+export type {
+ AdditionalServicesStepProps,
+ AdditionalServicesStepValues,
+} from './AdditionalServicesStep';