// embroidery.jsx — generates a rich botanical embroidery SVG and rasterises it
// for the reveal canvas. The art is laid out across a 900×1125 (4:5) field, but
// the function takes W/H and scales internally so the wrap is responsive.
//
// Palette is intentionally narrow: warm rose-gold + cream + muted sage + wine
// accent + antique gold for technical lines. NO neon, NO purple/blue.

(function () {
  // ── Seeded RNG so the pattern is stable across renders ───────────────────
  function rng(seed) {
    let s = seed >>> 0;
    return () => {
      s = (s * 1664525 + 1013904223) >>> 0;
      return s / 4294967296;
    };
  }

  // Tint helper: lighten/darken a hex by a factor (1 = same)
  function shade(hex, f) {
    const n = parseInt(hex.slice(1), 16);
    let r = (n >> 16) & 255, g = (n >> 8) & 255, b = n & 255;
    r = Math.max(0, Math.min(255, Math.round(r * f)));
    g = Math.max(0, Math.min(255, Math.round(g * f)));
    b = Math.max(0, Math.min(255, Math.round(b * f)));
    return '#' + ((r << 16) | (g << 8) | b).toString(16).padStart(6, '0');
  }

  // ── Building blocks ──────────────────────────────────────────────────────

  // A single peony petal, drawn pointing UP from origin (0,0).
  // Returns a <path> element with the petal silhouette + a subtle inner vein.
  function petal(cx, cy, len, width, rot, fill, stroke, opacity = 1) {
    const w = width / 2;
    const d = `M 0 0
               C ${-w * 0.6} ${-len * 0.25} ${-w} ${-len * 0.55} ${-w * 0.7} ${-len * 0.85}
               C ${-w * 0.45} ${-len * 1.02} ${w * 0.45} ${-len * 1.02} ${w * 0.7} ${-len * 0.85}
               C ${w} ${-len * 0.55} ${w * 0.6} ${-len * 0.25} 0 0 Z`;
    const vein = `M 0 ${-len * 0.05} Q ${w * 0.05} ${-len * 0.4} 0 ${-len * 0.85}`;
    return `<g transform="translate(${cx} ${cy}) rotate(${rot})" opacity="${opacity}">
      <path d="${d}" fill="${fill}" stroke="${stroke}" stroke-width=".6" stroke-opacity=".7"/>
      <path d="${vein}" stroke="${stroke}" stroke-width=".5" stroke-opacity=".55"
            fill="none" stroke-dasharray="1.6 1.4"/>
    </g>`;
  }

  // Big peony cluster: ring of large outer petals + ring of inner petals + center stitching
  function peony(cx, cy, scale, rotation, palette) {
    const { rose, cream, wine } = palette;
    let out = `<g transform="translate(${cx} ${cy}) rotate(${rotation})">`;

    // outer petals
    const outerN = 9;
    for (let i = 0; i < outerN; i++) {
      const a = (360 / outerN) * i;
      out += petal(0, 0, 110 * scale, 76 * scale, a, shade(rose, 1.05), shade(rose, 0.7), .94);
    }
    // mid petals offset by half
    const midN = 7;
    for (let i = 0; i < midN; i++) {
      const a = (360 / midN) * i + (360 / midN / 2);
      out += petal(0, 0, 82 * scale, 58 * scale, a, shade(rose, 0.92), shade(wine, 0.95), .92);
    }
    // inner petals
    const innN = 6;
    for (let i = 0; i < innN; i++) {
      const a = (360 / innN) * i;
      out += petal(0, 0, 50 * scale, 38 * scale, a, shade(cream, 1.0), shade(rose, 0.7), .95);
    }
    // tiny center curl
    const curlN = 5;
    for (let i = 0; i < curlN; i++) {
      const a = (360 / curlN) * i;
      out += petal(0, 0, 22 * scale, 18 * scale, a, shade(cream, 1.04), shade(wine, 0.9), 1);
    }
    // french-knot stamen dots in middle
    const knN = 8;
    for (let i = 0; i < knN; i++) {
      const a = (Math.PI * 2 / knN) * i;
      const r = 6 * scale;
      const x = Math.cos(a) * r, y = Math.sin(a) * r;
      out += `<circle cx="${x}" cy="${y}" r="${2 * scale}" fill="${shade(wine, .85)}"/>`;
    }
    out += `<circle cx="0" cy="0" r="${3 * scale}" fill="${shade(cream, 1.05)}"/>`;
    out += '</g>';
    return out;
  }

  // Five-petal rose blossom (smaller, simpler than peony)
  function blossom(cx, cy, scale, rotation, palette) {
    const { rose, cream, wine } = palette;
    let out = `<g transform="translate(${cx} ${cy}) rotate(${rotation})">`;
    const n = 5;
    for (let i = 0; i < n; i++) {
      const a = (360 / n) * i;
      out += petal(0, 0, 36 * scale, 30 * scale, a, shade(rose, 1.0), shade(wine, 0.95));
    }
    for (let i = 0; i < n; i++) {
      const a = (360 / n) * i + 36;
      out += petal(0, 0, 18 * scale, 16 * scale, a, shade(cream, 1.02), shade(rose, 0.7));
    }
    out += `<circle cx="0" cy="0" r="${2.5 * scale}" fill="${shade(wine, 0.85)}"/>`;
    // 4 stamen dots
    for (let i = 0; i < 4; i++) {
      const a = (Math.PI * 2 / 4) * i;
      out += `<circle cx="${Math.cos(a) * 5 * scale}" cy="${Math.sin(a) * 5 * scale}"
              r="${1.2 * scale}" fill="${shade(wine, 0.7)}"/>`;
    }
    out += '</g>';
    return out;
  }

  // Tiny forget-me-not bud
  function bud(cx, cy, scale, palette) {
    const { rose, cream, wine } = palette;
    let out = `<g transform="translate(${cx} ${cy})">`;
    for (let i = 0; i < 5; i++) {
      const a = (360 / 5) * i;
      const r = 5 * scale;
      const x = Math.cos((a * Math.PI) / 180) * r;
      const y = Math.sin((a * Math.PI) / 180) * r;
      out += `<circle cx="${x}" cy="${y}" r="${4 * scale}" fill="${shade(rose, 1.05)}"
              stroke="${shade(wine, .85)}" stroke-width=".5"/>`;
    }
    out += `<circle cx="0" cy="0" r="${2 * scale}" fill="${shade(cream, 1.05)}"/>`;
    out += '</g>';
    return out;
  }

  // Leaf with central vein + side veins
  function leaf(cx, cy, length, rot, palette, mirrored = false) {
    const { sage, gold } = palette;
    const w = length * 0.32;
    const m = mirrored ? -1 : 1;
    const d = `M 0 0
               Q ${m * w} ${-length * 0.35} 0 ${-length}
               Q ${-m * w * 0.85} ${-length * 0.35} 0 0 Z`;
    let out = `<g transform="translate(${cx} ${cy}) rotate(${rot})">
      <path d="${d}" fill="${shade(sage, 1.0)}" stroke="${shade(sage, 0.65)}" stroke-width=".7"/>
      <path d="M 0 0 Q 0 ${-length * 0.5} 0 ${-length}" stroke="${shade(gold, .95)}"
            stroke-width=".7" fill="none"/>`;
    // side veins
    const nv = 4;
    for (let i = 1; i <= nv; i++) {
      const t = i / (nv + 1);
      const sx = 0, sy = -length * t;
      const ex = m * w * (1 - t) * 0.7;
      const ey = -length * (t + 0.08);
      out += `<path d="M ${sx} ${sy} Q ${ex * 0.6} ${sy - 4} ${ex} ${ey}"
              stroke="${shade(gold, 0.9)}" stroke-width=".5" fill="none"
              stroke-dasharray="1.4 1"/>`;
    }
    out += '</g>';
    return out;
  }

  // Stem: cubic bezier with running-stitch dashing (two layers: thread + outline)
  function stem(x1, y1, cx1, cy1, cx2, cy2, x2, y2, palette) {
    const { sage, gold } = palette;
    const d = `M ${x1} ${y1} C ${cx1} ${cy1}, ${cx2} ${cy2}, ${x2} ${y2}`;
    return `<g>
      <path d="${d}" stroke="${shade(sage, 0.85)}" stroke-width="3" fill="none"
            stroke-linecap="round" opacity=".88"/>
      <path d="${d}" stroke="${shade(gold, 1.05)}" stroke-width="1" fill="none"
            stroke-dasharray="4 3" stroke-linecap="round" opacity=".85"/>
    </g>`;
  }

  // Technical stitch lines: dashed paths that read like CAD overlays
  function techPath(d, color, width = 0.7, dash = "3 2") {
    return `<path d="${d}" stroke="${color}" stroke-width="${width}" fill="none"
            stroke-dasharray="${dash}" opacity=".7"/>`;
  }

  // A grid of cross-stitches (×) at a regular pitch in a clipped area
  function crossGrid(x, y, w, h, pitch, color, opacity = 0.4) {
    let out = `<g opacity="${opacity}">`;
    for (let gy = y + pitch / 2; gy < y + h; gy += pitch) {
      for (let gx = x + pitch / 2; gx < x + w; gx += pitch) {
        out += `<path d="M ${gx - 2} ${gy - 2} L ${gx + 2} ${gy + 2}
                M ${gx - 2} ${gy + 2} L ${gx + 2} ${gy - 2}"
                stroke="${color}" stroke-width=".7" stroke-linecap="round"/>`;
      }
    }
    out += '</g>';
    return out;
  }

  // Scatter of French knots in a region
  function scatter(x, y, w, h, count, color, seed) {
    const r = rng(seed);
    let out = '';
    for (let i = 0; i < count; i++) {
      const px = x + r() * w, py = y + r() * h;
      const rr = 0.8 + r() * 1.4;
      out += `<circle cx="${px}" cy="${py}" r="${rr}" fill="${color}" opacity="${.5 + r() * .4}"/>`;
    }
    return out;
  }

  // Tiny stitch tick marks along a curve, simulating directional stitches
  function stitchTicks(d, count, color, length = 5) {
    // We can't easily compute points along an arbitrary path in static SVG,
    // so the caller passes a parametric helper. Skipped — we'll use
    // dasharray on duplicate paths instead.
    return '';
  }

  // Technical compass / circular diagram (CAD-flavoured)
  function compass(cx, cy, r, color) {
    let out = `<g transform="translate(${cx} ${cy})" opacity=".55">
      <circle cx="0" cy="0" r="${r}" stroke="${color}" stroke-width=".6"
              fill="none" stroke-dasharray="2 2"/>
      <circle cx="0" cy="0" r="${r * 0.6}" stroke="${color}" stroke-width=".5"
              fill="none" stroke-dasharray="1.2 1.5"/>
      <circle cx="0" cy="0" r="1.2" fill="${color}"/>`;
    for (let i = 0; i < 12; i++) {
      const a = (Math.PI * 2 / 12) * i;
      const x1 = Math.cos(a) * r * 0.85, y1 = Math.sin(a) * r * 0.85;
      const x2 = Math.cos(a) * r, y2 = Math.sin(a) * r;
      out += `<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}"
              stroke="${color}" stroke-width=".5"/>`;
    }
    out += '</g>';
    return out;
  }

  // ── Motif: a tight radial chrysanthemum/mum (Asian-leaning) ────────────
  // Many narrow petals in concentric rings — feels denser and more graphic
  // than a peony. Drawn around (cx, cy).
  function chrysanthemum(cx, cy, scale, rotation, palette) {
    const { rose, cream, wine, gold } = palette;
    let out = `<g transform="translate(${cx} ${cy}) rotate(${rotation})">`;
    const rings = [
      { n: 22, len: 130, w: 22, tint: 0.9,  edge: wine,    op: 0.92 },
      { n: 18, len: 100, w: 20, tint: 1.05, edge: wine,    op: 0.94 },
      { n: 14, len: 72,  w: 18, tint: 0.95, edge: wine,    op: 0.94 },
      { n: 10, len: 44,  w: 16, tint: 1.02, edge: gold,    op: 0.98 },
    ];
    rings.forEach((R, ri) => {
      for (let i = 0; i < R.n; i++) {
        const a = (360 / R.n) * i + (ri * (360 / (R.n * 2)));
        out += petal(0, 0, R.len * scale, R.w * scale, a,
                     shade(rose, R.tint), shade(R.edge, 0.7), R.op);
      }
    });
    // Tight stamen knots
    const knots = 16;
    for (let i = 0; i < knots; i++) {
      const a = (Math.PI * 2 / knots) * i;
      const r = 9 * scale;
      out += `<circle cx="${Math.cos(a) * r}" cy="${Math.sin(a) * r}"
              r="${2 * scale}" fill="${shade(wine, 0.85)}"/>`;
    }
    out += `<circle cx="0" cy="0" r="${4 * scale}" fill="${shade(gold, 1.0)}"
            stroke="${shade(wine, 0.8)}" stroke-width=".6"/>`;
    out += '</g>';
    return out;
  }

  // Single elongated teardrop-style lotus petal
  function lotusPetal(cx, cy, len, w, rot, fill, edge) {
    const d = `M 0 0
               Q ${-w} ${-len * 0.3} ${-w * 0.5} ${-len * 0.7}
               Q ${-w * 0.15} ${-len * 0.92} 0 ${-len}
               Q ${w * 0.15} ${-len * 0.92} ${w * 0.5} ${-len * 0.7}
               Q ${w} ${-len * 0.3} 0 0 Z`;
    return `<g transform="translate(${cx} ${cy}) rotate(${rot})">
      <path d="${d}" fill="${fill}" stroke="${edge}" stroke-width=".7" stroke-opacity=".75"/>
      <path d="M 0 ${-len * 0.1} Q 0 ${-len * 0.5} 0 ${-len * 0.9}"
            stroke="${edge}" stroke-width=".5" stroke-dasharray="1.5 1.3"
            fill="none" stroke-opacity=".65"/>
    </g>`;
  }

  // Lotus blossom with 8 petals + inner ring of 5
  function lotus(cx, cy, scale, rotation, palette) {
    const { rose, cream, wine, gold } = palette;
    let out = `<g transform="translate(${cx} ${cy}) rotate(${rotation})">`;
    // outer petals — 8
    for (let i = 0; i < 8; i++) {
      const a = (360 / 8) * i;
      out += lotusPetal(0, 0, 110 * scale, 38 * scale, a,
                        shade(rose, 1.05), shade(wine, 0.7));
    }
    // inner petals — 5, offset
    for (let i = 0; i < 5; i++) {
      const a = (360 / 5) * i + 36;
      out += lotusPetal(0, 0, 58 * scale, 28 * scale, a,
                        shade(cream, 1.0), shade(rose, 0.7));
    }
    // tiny tight center petals
    for (let i = 0; i < 3; i++) {
      const a = (360 / 3) * i;
      out += lotusPetal(0, 0, 22 * scale, 14 * scale, a,
                        shade(gold, 1.05), shade(wine, 0.8));
    }
    // stamen ring
    for (let i = 0; i < 10; i++) {
      const a = (Math.PI * 2 / 10) * i;
      const r = 8 * scale;
      out += `<circle cx="${Math.cos(a) * r}" cy="${Math.sin(a) * r}"
              r="${1.4 * scale}" fill="${shade(wine, 0.85)}"/>`;
    }
    out += `<circle cx="0" cy="0" r="${3 * scale}" fill="${shade(gold, 1.0)}"/>`;
    out += '</g>';
    return out;
  }

  // Stylised wave (seigaiha-ish, but free-drawn) — for lotus context
  function waveRow(y, W, ampX, ampY, color, opacity = 0.6) {
    let d = `M 0 ${y}`;
    const step = 40;
    for (let x = step; x <= W + step; x += step) {
      d += ` Q ${x - step / 2} ${y - ampY} ${x} ${y}`;
    }
    return `<path d="${d}" stroke="${color}" stroke-width=".8" fill="none"
            opacity="${opacity}" stroke-dasharray="3 2"/>`;
  }

  // Botanical line-art: a single sweeping branch with delicate flowers.
  // Returns SVG fragment (no <svg>).
  function botanicalBranch(W, H, palette, density, seedBase) {
    const { rose, cream, sage, wine, gold } = palette;
    const r = rng(seedBase);
    let svg = '';

    // Master S-curve from bottom-left to upper-right
    const x1 = W * 0.1, y1 = H * 0.88;
    const cx1 = W * 0.2, cy1 = H * 0.45;
    const cx2 = W * 0.7, cy2 = H * 0.55;
    const x2 = W * 0.88, y2 = H * 0.18;
    svg += stem(x1, y1, cx1, cy1, cx2, cy2, x2, y2, palette);

    // Sample points along the curve for placing leaves + small blooms
    const n = density === 'sparse' ? 12 : density === 'medium' ? 18 : 26;
    const cubicPt = (t) => {
      const mt = 1 - t;
      return [
        mt * mt * mt * x1 + 3 * mt * mt * t * cx1 + 3 * mt * t * t * cx2 + t * t * t * x2,
        mt * mt * mt * y1 + 3 * mt * mt * t * cy1 + 3 * mt * t * t * cy2 + t * t * t * y2,
      ];
    };
    for (let i = 1; i < n; i++) {
      const t = i / n + (r() - 0.5) * 0.02;
      const [x, y] = cubicPt(t);
      const m = i % 2 === 0;
      // alternate: leaf, then small blossom every few
      if (i % 4 === 0) {
        const s = 0.55 + r() * 0.3;
        svg += blossom(x + (m ? -18 : 18), y + (r() - 0.5) * 12, s,
                       r() * 360, palette);
      } else if (i % 3 === 0) {
        svg += bud(x + (m ? -14 : 14), y + (r() - 0.5) * 10, 0.55, palette);
      } else {
        const ang = (t * 180 - 60) + (m ? -50 : 50);
        svg += leaf(x, y, 38 + r() * 22, ang, palette, m);
      }
    }

    // Secondary smaller branch
    const bx1 = W * 0.6, by1 = H * 0.55;
    const bcx1 = W * 0.55, bcy1 = H * 0.7;
    const bcx2 = W * 0.3, bcy2 = H * 0.82;
    const bx2 = W * 0.18, by2 = H * 0.85;
    svg += stem(bx1, by1, bcx1, bcy1, bcx2, bcy2, bx2, by2, palette);
    for (let i = 1; i < (density === 'sparse' ? 8 : 14); i++) {
      const t = i / 14;
      const mt = 1 - t;
      const x = mt * mt * mt * bx1 + 3 * mt * mt * t * bcx1 + 3 * mt * t * t * bcx2 + t * t * t * bx2;
      const y = mt * mt * mt * by1 + 3 * mt * mt * t * bcy1 + 3 * mt * t * t * bcy2 + t * t * t * by2;
      const m = i % 2 === 0;
      if (i % 5 === 0) {
        svg += bud(x, y, 0.6, palette);
      } else {
        svg += leaf(x + (m ? -6 : 6), y, 30 + r() * 16, 200 + (m ? -40 : 40) + r() * 30, palette, m);
      }
    }

    return svg;
  }

  // Damask repeat: a 2x2 grid of mirrored ornamental medallions
  function damask(W, H, palette, density) {
    const { rose, cream, wine, gold, sage } = palette;
    let svg = '';
    // Define ONE quadrant ornament, mirror it 4 ways
    const cx = W / 2, cy = H / 2;
    // Mirror via transform scales — but we generate as paths so easier:
    const positions = [
      { x: W * 0.28, y: H * 0.3,  flip: '' },
      { x: W * 0.72, y: H * 0.3,  flip: 'scale(-1,1)' },
      { x: W * 0.28, y: H * 0.72, flip: 'scale(1,-1)' },
      { x: W * 0.72, y: H * 0.72, flip: 'scale(-1,-1)' },
    ];
    positions.forEach((p) => {
      svg += `<g transform="translate(${p.x} ${p.y}) ${p.flip}">`;
      // Ornamental swirls
      svg += `<path d="M -60 0 C -50 -40, -10 -55, 0 -30 C 10 -8, 40 -8, 50 -30
                      C 56 -55, 80 -45, 70 -10 C 65 8, 50 18, 30 14
                      C 12 10, 0 24, -10 38 C -28 50, -55 30, -60 0 Z"
              fill="${shade(rose, 1.02)}" stroke="${shade(wine, 0.7)}" stroke-width=".7" opacity=".9"/>`;
      // Inner curls
      svg += `<path d="M -30 -6 C -22 -22, -2 -22, 6 -10"
              stroke="${shade(gold, 1.05)}" stroke-width=".7" fill="none"
              stroke-dasharray="2.5 1.5"/>`;
      svg += `<path d="M 14 6 C 32 4, 42 -8, 50 -22"
              stroke="${shade(gold, 1.05)}" stroke-width=".7" fill="none"
              stroke-dasharray="2.5 1.5"/>`;
      // Center rosette
      svg += `<circle cx="0" cy="0" r="6" fill="${shade(gold, 1.0)}" stroke="${shade(wine, 0.8)}" stroke-width=".7"/>`;
      for (let i = 0; i < 6; i++) {
        const a = (Math.PI * 2 / 6) * i;
        svg += `<circle cx="${Math.cos(a) * 11}" cy="${Math.sin(a) * 11}"
                r="${1.6}" fill="${shade(wine, 0.85)}"/>`;
      }
      // Small petal frills
      for (let i = 0; i < 4; i++) {
        const a = (Math.PI / 2) * i / 4 - Math.PI / 4;
        const rr = 28;
        svg += `<circle cx="${Math.cos(a) * rr - 18}" cy="${Math.sin(a) * rr - 8}"
                r="${2.5}" fill="${shade(cream, 1.05)}" opacity=".9"/>`;
      }
      svg += `</g>`;
    });

    // Center medallion linking the four
    svg += `<g transform="translate(${cx} ${cy})">
      <circle cx="0" cy="0" r="34" stroke="${shade(gold, 1.0)}" stroke-width=".7"
              fill="none" stroke-dasharray="2 2.5" opacity=".75"/>
      <circle cx="0" cy="0" r="22" stroke="${shade(wine, 0.85)}" stroke-width=".6" fill="none"/>
      <circle cx="0" cy="0" r="8" fill="${shade(rose, 1.05)}" stroke="${shade(wine, 0.7)}" stroke-width=".7"/>
      <circle cx="0" cy="0" r="3" fill="${shade(gold, 1.0)}"/>
    </g>`;

    // Connecting curls between medallions (8 of them — 4 horizontal, 4 vertical)
    const linkPairs = [
      [positions[0], positions[1]],
      [positions[2], positions[3]],
      [positions[0], positions[2]],
      [positions[1], positions[3]],
    ];
    linkPairs.forEach(([a, b]) => {
      const mx = (a.x + b.x) / 2, my = (a.y + b.y) / 2;
      svg += `<path d="M ${a.x} ${a.y} Q ${mx} ${my} ${b.x} ${b.y}"
              stroke="${shade(gold, 1.05)}" stroke-width=".6"
              stroke-dasharray="3 2" fill="none" opacity=".55"/>`;
    });

    return svg;
  }

  // ── Main composition ────────────────────────────────────────────────────
  window.generateEmbroiderySVG = function (W, H, palette, opts = {}) {
    const density = opts.density || 'rich';
    const motif = opts.motif || 'peony';
    const seed = opts.seed || 42;
    const r = rng(seed);

    // Counts by density
    const counts = {
      sparse:  { knots: 60,  leaves: 6,  buds: 3, blooms: 2, gridPitch: 24, crossOp: 0.22 },
      medium:  { knots: 140, leaves: 10, buds: 5, blooms: 3, gridPitch: 18, crossOp: 0.3 },
      rich:    { knots: 240, leaves: 14, buds: 8, blooms: 5, gridPitch: 14, crossOp: 0.38 },
    };
    const c = counts[density] || counts.rich;

    let svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${W}" height="${H}"
                viewBox="0 0 ${W} ${H}" shape-rendering="geometricPrecision">`;

    // Background technical / cross-stitch lattice (very subtle, fills the field)
    svg += crossGrid(0, 0, W, H, c.gridPitch * 2, shade(palette.gold, 0.95), 0.18);

    // A subtle CAD framing rectangle
    svg += `<rect x="${W*0.06}" y="${H*0.06}" width="${W*0.88}" height="${H*0.88}"
             stroke="${shade(palette.gold, 0.95)}" stroke-width=".4" fill="none"
             stroke-dasharray="1.5 3" opacity=".55"/>`;

    // Technical compass diagrams in corners
    svg += compass(W * 0.86, H * 0.13, 38, shade(palette.gold, 1.0));
    svg += compass(W * 0.13, H * 0.86, 30, shade(palette.gold, 1.0));

    // Cross-stitch field in upper-right, denser
    svg += crossGrid(W * 0.55, H * 0.08, W * 0.38, H * 0.28, c.gridPitch,
                     shade(palette.gold, 1.0), c.crossOp);

    // ── Motif-specific composition ────────────────────────────────────────
    if (motif === 'chrysanthemum') {
      svg += renderChrysanthemumScene(W, H, palette, c, r);
    } else if (motif === 'botanical') {
      svg += botanicalBranch(W, H, palette, density, seed + 5);
    } else if (motif === 'lotus') {
      svg += renderLotusScene(W, H, palette, c, r);
    } else if (motif === 'damask') {
      svg += damask(W, H, palette, density);
    } else {
      svg += renderPeonyScene(W, H, palette, c, r);
    }

    // ── Common foreground: French-knot texture + technical footer ────────
    svg += scatter(0, 0, W, H, c.knots, shade(palette.wine, 0.9), seed + 13);
    svg += scatter(0, 0, W, H, Math.floor(c.knots * 0.5), shade(palette.gold, 1.05), seed + 91);
    svg += scatter(0, 0, W, H, Math.floor(c.knots * 0.4), shade(palette.cream, 1.05), seed + 7);

    svg += techPath(`M ${W * 0.1} ${H * 0.95} L ${W * 0.9} ${H * 0.95}`,
                    shade(palette.gold, 1.0), 0.6, "3 3");
    const motifLabel = ({
      peony: 'MOTIF 001 · PEONY · SATIN A4',
      chrysanthemum: 'MOTIF 002 · CHRYSANTHEMUM · SATIN A4',
      botanical: 'MOTIF 003 · BOTANICAL · SATIN A4',
      lotus: 'MOTIF 004 · LOTUS · SATIN A4',
      damask: 'MOTIF 005 · DAMASK · SATIN A4',
    })[motif] || 'CUSTEX · SATIN A4';
    svg += `<text x="${W * 0.5}" y="${H * 0.935}" text-anchor="middle"
             font-family="ui-monospace, monospace" font-size="9"
             fill="${shade(palette.gold, 1.0)}" opacity=".55"
             letter-spacing="3">CUSTEX · ${motifLabel}</text>`;

    svg += '</svg>';
    return svg;
  };

  // ── Peony scene (original) ─────────────────────────────────────────────
  function renderPeonyScene(W, H, palette, c, r) {
    let svg = '';
    const peonyX = W * 0.36, peonyY = H * 0.38;
    const rose2X = W * 0.7,  rose2Y = H * 0.7;
    const budX   = W * 0.2,  budY   = H * 0.78;

    svg += stem(peonyX + 30, peonyY + 60, peonyX + 130, peonyY + 200,
                rose2X - 90, rose2Y - 80, rose2X - 10, rose2Y - 10, palette);
    svg += stem(peonyX - 30, peonyY + 60, peonyX - 90, peonyY + 180,
                budX + 40, budY - 140, budX + 10, budY - 20, palette);
    svg += stem(budX, budY + 20, budX - 60, budY + 80,
                budX + 80, H * 0.95, budX + 140, H * 0.97, palette);

    const leafSpots = [
      { x: peonyX + 70,  y: peonyY + 140, len: 60, rot: 60, m: false },
      { x: peonyX + 130, y: peonyY + 220, len: 70, rot: 95, m: true },
      { x: peonyX + 170, y: peonyY + 300, len: 55, rot: 70, m: false },
      { x: rose2X - 70,  y: rose2Y - 50,  len: 50, rot: 130, m: true },
      { x: rose2X + 50,  y: rose2Y + 60,  len: 60, rot: 200, m: false },
      { x: peonyX - 60,  y: peonyY + 130, len: 65, rot: -50, m: true },
      { x: peonyX - 120, y: peonyY + 220, len: 70, rot: -80, m: false },
      { x: budX + 30,    y: budY - 100,   len: 55, rot: -30, m: true },
      { x: budX - 30,    y: budY - 40,    len: 50, rot: -110, m: false },
      { x: budX + 70,    y: H * 0.92,     len: 45, rot: 40, m: true },
      { x: W * 0.78,     y: H * 0.18,     len: 50, rot: 25, m: false },
      { x: W * 0.82,     y: H * 0.32,     len: 42, rot: 60, m: true },
      { x: W * 0.18,     y: H * 0.22,     len: 48, rot: -40, m: true },
      { x: W * 0.5,      y: H * 0.92,     len: 52, rot: 10, m: false },
    ];
    for (let i = 0; i < Math.min(c.leaves, leafSpots.length); i++) {
      const s = leafSpots[i];
      svg += leaf(s.x, s.y, s.len, s.rot, palette, s.m);
    }
    for (let i = 0; i < c.buds; i++) {
      svg += bud(budX + (r() - 0.5) * 70, budY + (r() - 0.5) * 70, 0.7 + r() * 0.5, palette);
    }
    svg += blossom(rose2X, rose2Y, 1.0, 15, palette);
    if (c.blooms >= 3) svg += blossom(W * 0.62, H * 0.5, 0.7, -10, palette);
    if (c.blooms >= 4) svg += blossom(W * 0.18, H * 0.6, 0.65, 25, palette);
    if (c.blooms >= 5) svg += blossom(W * 0.85, H * 0.55, 0.6, -25, palette);
    svg += peony(peonyX, peonyY, 1.0, r() * 30 - 15, palette);

    // Stitch-direction arrows around the peony
    for (let i = 0; i < 8; i++) {
      const a = (360 / 8) * i;
      const rad = 130;
      const rx = peonyX + Math.cos((a * Math.PI) / 180) * rad;
      const ry = peonyY + Math.sin((a * Math.PI) / 180) * rad;
      svg += `<g transform="translate(${rx} ${ry}) rotate(${a + 90})" opacity=".62">
        <path d="M 0 0 L 14 0" stroke="${shade(palette.gold, 1.0)}" stroke-width=".7" stroke-dasharray="2 1.5"/>
        <path d="M 10 -3 L 14 0 L 10 3" stroke="${shade(palette.gold, 1.0)}"
              stroke-width=".7" fill="none" stroke-linecap="round" stroke-linejoin="round"/>
      </g>`;
    }
    return svg;
  }

  // ── Chrysanthemum scene ────────────────────────────────────────────────
  function renderChrysanthemumScene(W, H, palette, c, r) {
    let svg = '';
    // Hero mum, slightly above centre
    const mx = W * 0.5, my = H * 0.42;
    // Long sweeping leaves radiating outward — drawn BEFORE the bloom
    const leafCount = Math.min(c.leaves, 12);
    for (let i = 0; i < leafCount; i++) {
      const a = (360 / leafCount) * i + 12;
      const dist = 180 + (i % 2 ? 30 : 0);
      const rad = a * Math.PI / 180;
      const lx = mx + Math.cos(rad) * dist;
      const ly = my + Math.sin(rad) * dist;
      svg += leaf(lx, ly, 80, a + 90, palette, i % 2 === 0);
    }
    svg += chrysanthemum(mx, my, 1.0, r() * 20 - 10, palette);
    // Secondary smaller mums
    svg += chrysanthemum(W * 0.18, H * 0.78, 0.42, 15, palette);
    svg += chrysanthemum(W * 0.82, H * 0.78, 0.5, -20, palette);
    if (c.blooms >= 4) svg += chrysanthemum(W * 0.85, H * 0.18, 0.32, 35, palette);
    // Tiny buds scattered
    for (let i = 0; i < c.buds; i++) {
      const a = r() * Math.PI * 2;
      const d = 220 + r() * 120;
      svg += bud(mx + Math.cos(a) * d, my + Math.sin(a) * d, 0.55 + r() * 0.3, palette);
    }
    return svg;
  }

  // ── Lotus + wave scene ─────────────────────────────────────────────────
  function renderLotusScene(W, H, palette, c, r) {
    let svg = '';
    // Three rows of waves in the lower half
    for (let i = 0; i < 3; i++) {
      const y = H * (0.62 + i * 0.1);
      svg += waveRow(y, W, 40, 8 + i * 2, shade(palette.gold, 1.0 - i * 0.1), 0.55 - i * 0.1);
    }
    // Long lotus stem from bottom rising to the bloom
    const lx = W * 0.5, ly = H * 0.36;
    svg += stem(lx, H * 0.92, lx - 20, H * 0.78, lx + 10, H * 0.55, lx, ly + 70, palette);
    // Leaf pads (lily pad) floating on water
    svg += `<ellipse cx="${W * 0.25}" cy="${H * 0.7}" rx="46" ry="14"
            fill="${shade(palette.sage, 1.0)}" stroke="${shade(palette.sage, 0.65)}"
            stroke-width=".8" opacity=".88"/>`;
    svg += `<ellipse cx="${W * 0.78}" cy="${H * 0.78}" rx="58" ry="16"
            fill="${shade(palette.sage, 0.92)}" stroke="${shade(palette.sage, 0.65)}"
            stroke-width=".8" opacity=".88"/>`;
    // Vein lines on the pads
    for (let i = -3; i <= 3; i++) {
      svg += `<line x1="${W * 0.25}" y1="${H * 0.7}"
              x2="${W * 0.25 + i * 14}" y2="${H * 0.7 + 6}"
              stroke="${shade(palette.gold, 0.95)}" stroke-width=".5" opacity=".7"/>`;
    }
    // The lotus blossom (hero)
    svg += lotus(lx, ly, 1.0, r() * 20 - 10, palette);
    // Smaller lotus buds nearby
    svg += lotus(W * 0.2, H * 0.55, 0.32, 25, palette);
    svg += lotus(W * 0.82, H * 0.6, 0.36, -20, palette);
    // Floating petal scatter
    for (let i = 0; i < c.buds; i++) {
      const px = W * (0.1 + r() * 0.8);
      const py = H * (0.6 + r() * 0.32);
      svg += lotusPetal(px, py, 18 + r() * 8, 8, r() * 360,
                        shade(palette.rose, 1.05), shade(palette.wine, 0.7));
    }
    return svg;
  }

  // Render an SVG string into a canvas of given pixel dimensions.
  // Returns a Promise<HTMLCanvasElement>. The canvas is at full pixel-ratio
  // so the reveal stays crisp on retina.
  window.rasteriseSVG = function (svgString, W, H, dpr = (window.devicePixelRatio || 1)) {
    return new Promise((resolve, reject) => {
      const blob = new Blob([svgString], { type: 'image/svg+xml;charset=utf-8' });
      const url = URL.createObjectURL(blob);
      const img = new Image();
      img.onload = () => {
        const cv = document.createElement('canvas');
        cv.width = Math.round(W * dpr);
        cv.height = Math.round(H * dpr);
        const ctx = cv.getContext('2d');
        ctx.imageSmoothingEnabled = true;
        ctx.imageSmoothingQuality = 'high';
        ctx.drawImage(img, 0, 0, cv.width, cv.height);
        URL.revokeObjectURL(url);
        resolve(cv);
      };
      img.onerror = (e) => { URL.revokeObjectURL(url); reject(e); };
      img.src = url;
    });
  };
})();
