diff --git a/client/src/pages/SongBookImport.jsx b/client/src/pages/SongBookImport.jsx
index 5ccdb568cb..c66f988d44 100644
--- a/client/src/pages/SongBookImport.jsx
+++ b/client/src/pages/SongBookImport.jsx
@@ -11,7 +11,8 @@
* stored until the user reviews and Saves.
*
* Below either tab: a draft form (title/artist/instrument/stage/tags) → Save →
- * createSong → navigate to the new song's viewer.
+ * createSong → navigate to the new song's viewer. PageHeader carries a second
+ * Save so the primary action stays above the fold on a phone.
*/
import { useEffect, useMemo, useRef, useState, useCallback } from 'react';
@@ -230,10 +231,25 @@ export default function SongBookImport() {
title="Import Song"
subtitle="Paste a tab or fetch one from a URL, review, then save"
actions={(
-
-
- SongBook
-
+ <>
+
+
+ SongBook
+
+ {/* The form's own Save sits below a tall textarea + preview — on a
+ phone that is ~1000px down. This header copy keeps the primary
+ action above the fold from any scroll position (#6001). */}
+
+ >
)}
/>
diff --git a/client/src/pages/SongBookImport.test.jsx b/client/src/pages/SongBookImport.test.jsx
index 5db634fff2..fd8595ef7a 100644
--- a/client/src/pages/SongBookImport.test.jsx
+++ b/client/src/pages/SongBookImport.test.jsx
@@ -49,6 +49,24 @@ describe('SongBookImport', () => {
expect(body.content.text).toBe('< C G Am');
});
+ it('the header Save action saves the draft and is gated on content (#6001)', async () => {
+ // The form's own Save sits below the textarea + preview — off-screen on a
+ // phone — so the header copy is the one that has to work above the fold.
+ clipboard.readClipboard.mockResolvedValue('C G Am');
+ renderPage();
+ const headerSave = screen.getByRole('button', { name: 'Save' });
+ expect(headerSave.disabled).toBe(true);
+
+ fireEvent.click(screen.getByRole('button', { name: 'Paste' }));
+ await screen.findByLabelText('Pasted tab content');
+ await waitFor(() => expect(screen.getByRole('button', { name: 'Save' }).disabled).toBe(false));
+
+ fireEvent.change(screen.getByLabelText('Title'), { target: { value: 'Example Song' } });
+ fireEvent.click(screen.getByRole('button', { name: 'Save' }));
+ await waitFor(() => expect(api.createSong).toHaveBeenCalledTimes(1));
+ expect(api.createSong.mock.calls[0][0].title).toBe('Example Song');
+ });
+
it('clamps ChordPro meta before sending: out-of-range capo dropped, long key sliced to 20', async () => {
const sheet = '{key: ThisKeyNameIsWayTooLongForTheSchema}\n{capo: 13}\nC G Am\nInvented lyric line';
renderPage();