What we’re adding

A full-screen (or large) Dialog per card opened by the palette icon.

Inside:

Large LogoPreview (your name in chosen palette/font)

PalettePicker (swatches)

FontPicker with live preview

Buttons: Apply, Use in Brand Kit, Check Domains

Persist the choice per name (and pass via query to Brand Kit).

1) New FontPicker component

src/components/brand/FontPicker.tsx

import React, { useEffect } from 'react';

// Use the same Google Font loader you used in LogoPreview.
function loadGoogleFonts() {
  const existed = document.getElementById('ibrandbiz-google-fonts');
  if (existed) return;
  const link = document.createElement('link');
  link.id = 'ibrandbiz-google-fonts';
  link.rel = 'stylesheet';
  link.href =
    'https://fonts.googleapis.com/css2?family=Inter:wght@600;700;800&family=Montserrat:wght@700&family=Outfit:wght@700&family=Poppins:wght@600&family=Playfair+Display:wght@600&family=Raleway:wght@700&family=Rubik:wght@700&display=swap';
  document.head.appendChild(link);
}

export const FONT_OPTIONS = [
  { label: 'Outfit', sampleWeight: 700 },
  { label: 'Inter', sampleWeight: 800 },
  { label: 'Poppins', sampleWeight: 600 },
  { label: 'Montserrat', sampleWeight: 700 },
  { label: 'Rubik', sampleWeight: 700 },
  { label: 'Raleway', sampleWeight: 700 },
  { label: 'Playfair Display', sampleWeight: 600 }, // serif
];

export function FontPicker({
  value,
  onChange,
  sampleText = 'Your Brand Name',
}: {
  value?: string;
  onChange: (font: string) => void;
  sampleText?: string;
}) {
  useEffect(() => loadGoogleFonts(), []);

  return (
    <div className="grid grid-cols-1 sm:grid-cols-2 gap-2">
      {FONT_OPTIONS.map((f) => (
        <button
          key={f.label}
          onClick={() => onChange(f.label)}
          className={`border rounded-lg text-left p-3 hover:bg-muted transition ${
            value === f.label ? 'border-primary ring-1 ring-primary' : 'border-border'
          }`}
        >
          <div className="text-xs text-muted-foreground mb-1">{f.label}</div>
          <div
            style={{
              fontFamily: `'${f.label}', system-ui, sans-serif`,
              fontWeight: f.sampleWeight as any,
            }}
            className="text-lg truncate"
          >
            {sampleText}
          </div>
        </button>
      ))}
    </div>
  );
}

2) Use a Dialog (shadcn/ui) for the big editor
a) Imports & small types in BusinessName.tsx

Add to the top:

import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog';
import { PalettePicker } from '@/components/brand/PalettePicker';
import { FontPicker } from '@/components/brand/FontPicker';
import { LogoPreview } from '@/components/brand/LogoPreview';
import { PALETTES } from '@/components/brand/palettes';

type BrandChoice = { paletteIndex?: number; fontFamily?: string };

b) Local state (near your other useStates)
const [cardChoices, setCardChoices] = useState<Record<number, BrandChoice>>({});
const [editorOpen, setEditorOpen] = useState<{ index: number | null }>({ index: null });

const defaultPalette = (i: number) => i % PALETTES.length;

c) Open the dialog from the small palette icon

Where you currently have the tiny palette UI on each card, replace that trigger with:

<button
  className="p-1 rounded hover:bg-muted"
  title="Customize palette & font"
  onClick={() => setEditorOpen({ index })}
>
  🎨
</button>


(Keep your heart/save button as is.)

d) Dialog markup (put once at the bottom of the component JSX)
<Dialog open={editorOpen.index !== null} onOpenChange={() => setEditorOpen({ index: null })}>
  <DialogContent className="max-w-3xl">
    {editorOpen.index !== null && (() => {
      const i = editorOpen.index!;
      const nameData = generatedNames[i];
      const choice = cardChoices[i] || {};
      const paletteIndex = choice.paletteIndex ?? defaultPalette(i);
      const fontFamily = choice.fontFamily;

      return (
        <>
          <DialogHeader>
            <DialogTitle>Customize “{nameData.name}”</DialogTitle>
          </DialogHeader>

          <div className="grid gap-6">
            {/* Big preview */}
            <div className="rounded-xl overflow-hidden border">
              <div className="p-6">
                <LogoPreview
                  name={nameData.name}
                  paletteIndex={paletteIndex}
                  fontFamily={fontFamily}
                />
              </div>
            </div>

            {/* Controls */}
            <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
              <div>
                <div className="mb-2 text-sm font-medium">Palette</div>
                <PalettePicker
                  value={paletteIndex}
                  onChange={(idx) =>
                    setCardChoices((s) => ({ ...s, [i]: { ...(s[i] || {}), paletteIndex: idx } }))
                  }
                />
              </div>
              <div>
                <div className="mb-2 text-sm font-medium">Font</div>
                <FontPicker
                  value={fontFamily}
                  onChange={(font) =>
                    setCardChoices((s) => ({ ...s, [i]: { ...(s[i] || {}), fontFamily: font } }))
                  }
                  sampleText={nameData.name}
                />
              </div>
            </div>
          </div>

          <DialogFooter className="gap-2">
            <Button variant="outline" onClick={() => goToDomains(nameData.name)}>
              Check Domains
            </Button>
            <Button
              onClick={() => {
                // persist & go
                const params = new URLSearchParams({
                  name: nameData.name,
                  palette: String(paletteIndex),
                  font: fontFamily || '',
                });
                setEditorOpen({ index: null });
                setLocation(`/brand-kit?${params.toString()}`);
              }}
            >
              Use in Brand Kit
            </Button>
            <Button variant="secondary" onClick={() => setEditorOpen({ index: null })}>
              Apply & Close
            </Button>
          </DialogFooter>
        </>
      );
    })()}
  </DialogContent>
</Dialog>

3) Keep the small, clean tiles

Your tile/cards stay lean (title, save, domain badges, “Use” & “Check Domains”). The 🎨 button opens the big editor where there’s plenty of space for fonts and palettes.

4) Brand Kit handoff (already wired)

We’re passing ?name=<n>&palette=<index>&font=<family> to Brand Kit. If you want, I’ll patch your Brand Kit page to read and apply those on load.

5) One-liner prompt for Rep

“Replace the cramped inline palette/font picker with a Dialog editor per card. Add FontPicker, reuse PalettePicker, and render a big LogoPreview inside the dialog. Persist selection in cardChoices[index] and pass ?name&palette&font to Brand Kit on ‘Use in Brand Kit’. Keep tiles clean; open dialog from a 🎨 button.”