Normalize logo size + keep it inside the Preview
Goals

Every template auto-fits into the preview on load (with a little padding).

The logo group (#logo-root) never renders outside the preview (even for huge originals).

Scale/drag later still work and respect the bounds.

A) Normalize the SVG document

On template load (normalize step):

Strip hard sizing: remove width/height attributes from <svg>.

Ensure viewBox:

If missing, compute from the union of all renderable nodes:

temporarily group all visible content, call getBBox() → {minX, minY, width, height}

set <svg viewBox="minX minY width height">

Keep <defs> at root; move all visible nodes into <g id="logo-root"> (if not present).

CSS sizing: preview code should size the svg by CSS:

svg { display:block; width:100%; height:100%; }

preview container has explicit height (e.g., 520px) and overflow:hidden;.

B) Fit-to-preview on first render

After normalization:

Measure the untransformed bbox of #logo-root with getBBox().

Compute a fit scale for the preview’s inner rect (with ~5% padding):

scaleX = (previewWidth * 0.90) / bbox.width
scaleY = (previewHeight * 0.90) / bbox.height
initialScale = Math.min(scaleX, scaleY)


Center it:

Target center: (previewWidth/2, previewHeight/2)

Element center (in svg coords): (bbox.x + bbox.width/2, bbox.y + bbox.height/2)

Translate so centers align after scaling.

Apply a single transform to #logo-root:

transform="translate(tx, ty) scale(initialScale)"


(Keep rotation = 0 on load.)

C) Enforce bounds for later interactions

Use the same clamping logic we discussed earlier:

When scaling via the Logo Size slider:

compute transformed bbox; clamp scale so it never exceeds preview edges

cap at 200% or earlier if edges would be crossed

When dragging: clamp translate so transformed bbox stays fully inside.

Keep overflow:hidden on the preview so there’s no visual spill while dragging near edges.

D) Acceptance

Open Scales of Justice → it auto-fits inside the preview with ~5–10% padding, centered.

Drag/scale/rotate → never bleeds outside.

Other templates also load fit-to-box consistently.

Exports (SVG/PNG) match what’s on screen.

Notes

Don’t change routes or the overlay/drag system.

All transforms live on #logo-root (and per-element groups for text/shapes), not on <svg>.

If a template has extreme off-canvas content (whitespace), the computed viewBox will correct it.