2) Add a single function that builds all variants + sizes and drops them in your ZIP

Call this from your existing downloadBrandKit (or create a sibling “Download Assets” button).

async function addLogoAssetSetToZip(zip: any, {
  name,
  svgUrl,
  layout,
  fontFamily,
  textSize,
  iconSize,
  palette,
}: {
  name: string;
  svgUrl: string | null;
  layout: "side-by-side" | "top-bottom";
  fontFamily: string;
  textSize: number;
  iconSize: number;
  palette: {
    primary: string; secondary: string; accent: string; highlight: string;
    neutral: string; surface: string; textLight: string; textDark: string;
  };
}) {
  // width targets -> nice coverage (about 3.3in, 6.6in, 10in at 300ppi)
  const widths = [1000, 2000, 3000];

  const safe = (s: string) => s.replace(/[^a-zA-Z0-9]/g, "-").toLowerCase();
  const folder = zip.folder(`${safe(name)}/logos`)!;

  // --- PNG Logo (transparent)
  for (const w of widths) {
    const blob = await renderLogoPNG({
      width: w, bg: null, withIcon: true, withText: true,
      layout, iconSize: Math.round(iconSize * (w / 1200)),
      textSize: Math.round(textSize * (w / 1200)),
      textColor: palette.textDark, fontFamily, name, svgUrl, pad: 72,
    });
    folder.file(`png_logo_${w}px.png`, blob);
  }

  // --- PNG Reverse Logo (light text on dark background)
  for (const w of widths) {
    const blob = await renderLogoPNG({
      width: w, bg: palette.textDark, withIcon: true, withText: true,
      layout, iconSize: Math.round(iconSize * (w / 1200)),
      textSize: Math.round(textSize * (w / 1200)),
      textColor: palette.textLight, fontFamily, name, svgUrl, pad: 72,
    });
    folder.file(`png_logo_reverse_${w}px.png`, blob);
  }

  // --- JPG Logo (flattened on brand surface)
  for (const w of widths) {
    const blob = await renderLogoJPG({
      width: w, bg: palette.surface, withIcon: true, withText: true,
      layout, iconSize: Math.round(iconSize * (w / 1200)),
      textSize: Math.round(textSize * (w / 1200)),
      textColor: palette.textDark, fontFamily, name, svgUrl, pad: 72,
    });
    folder.file(`jpg_logo_${w}px.jpg`, blob);
  }

  // --- Text Logo (wordmark only, transparent)
  for (const w of widths) {
    const blob = await renderLogoPNG({
      width: w, bg: null, withIcon: false, withText: true,
      layout, iconSize: 0, textSize: Math.round(textSize * (w / 1200)),
      textColor: palette.textDark, fontFamily, name, svgUrl: null, pad: 72,
    });
    folder.file(`text_logo_${w}px.png`, blob);
  }

  // --- PNG Icon (icon only, transparent)
  for (const w of [512, 1024, 2048]) {
    const blob = await renderLogoPNG({
      width: w, bg: null, withIcon: true, withText: false,
      layout: "top-bottom", iconSize: Math.round(w * 0.66), textSize: 0,
      textColor: palette.textDark, fontFamily, name, svgUrl, pad: 0,
    });
    folder.file(`png_icon_${w}px.png`, blob);
  }

  // --- PNG Reverse Icon (icon on dark)
  for (const w of [512, 1024, 2048]) {
    const blob = await renderLogoPNG({
      width: w, bg: palette.textDark, withIcon: true, withText: false,
      layout: "top-bottom", iconSize: Math.round(w * 0.66), textSize: 0,
      textColor: palette.textLight, fontFamily, name, svgUrl, pad: 0,
    });
    folder.file(`png_icon_reverse_${w}px.png`, blob);
  }

  // Keep your original raw SVG too (best for designers)
  if (svgUrl) {
    try {
      const svg = await (await fetch(svgUrl)).text();
      folder.file(`icon.svg`, svg);
    } catch {}
  }
}
