{"product_id":"fietssticker-naam-vlag-links","title":"Fiets sticker vlag links","description":"\u003cbody\u003e\n\u003cscript\u003ewindow.WIZARD_STARTDESIGN = 'fietslinks';\u003c\/script\u003e\n\n\n\n\u003cmeta charset=\"UTF-8\"\u003e\n\u003cmeta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"\u003e\n\u003ctitle\u003eSocialSticker — naamsticker wizard\u003c\/title\u003e\n\u003clink rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\"\u003e\n\u003clink rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin\u003e\n\u003clink href=\"https:\/\/fonts.googleapis.com\/css2?family=Anton\u0026amp;family=Bebas+Neue\u0026amp;family=Dancing+Script:wght@700\u0026amp;family=Montserrat:wght@600;700;800\u0026amp;family=Poppins:wght@400;500;600;700\u0026amp;family=Saira+Condensed:wght@600;700\u0026amp;display=swap\" rel=\"stylesheet\"\u003e\n\u003cscript src=\"https:\/\/unpkg.com\/@pdf-lib\/fontkit@1.1.1\/dist\/fontkit.umd.min.js\"\u003e\u003c\/script\u003e\n\u003cstyle\u003e\n  :root{\n    --ink:#1A1A1A;\n    --paper:#FFF9F8;\n    --surface:#F5F6F8;\n    --coral:#FE886D;\n    --coral-soft:#FEB5A5;\n    --blue:#4770DB;\n    --bluegrey:#BEC4D2;\n    --line:#ece8e6;\n    --radius:18px;\n    font-family:'Poppins',-apple-system,sans-serif;\n  }\n  *{box-sizing:border-box;margin:0;padding:0}\n  body{background:var(--surface);color:var(--ink);display:flex;justify-content:center}\n  .app{width:100%;max-width:430px;background:var(--paper);min-height:560px;display:flex;flex-direction:column;position:relative}\n\n  .top{padding:16px 20px 12px;position:relative;background:var(--paper);z-index:5;border-bottom:1px solid var(--line)}\n  .brand{display:flex;align-items:center;gap:8px}\n  .brand svg{height:24px;width:auto}\n  .brand .mark{display:flex;gap:1px}\n  .brand .mark span{width:8px;height:17px;background:var(--coral);border-radius:3px;transform:skewX(-8deg)}\n  .brand .mark span:nth-child(2){background:var(--coral-soft)}\n  .brand b{font-weight:700}.brand .dot{color:var(--coral)}\n  .steps{display:flex;gap:6px;margin-top:14px}\n  .steps .s{flex:1;height:5px;border-radius:3px;background:var(--line);transition:.3s}\n  .steps .s.done{background:var(--coral-soft)}\n  .steps .s.active{background:var(--coral)}\n  .stepinfo{display:flex;justify-content:space-between;align-items:baseline;margin-top:11px}\n  .stepinfo .n{font-size:11px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--coral)}\n  .stepinfo .c{font-size:11px;color:#b3aeac}\n  .stepinfo h2{font-size:20px;font-weight:700;letter-spacing:-.4px;margin-top:2px;width:100%}\n\n  .preview{margin:16px 20px;border-radius:var(--radius);padding:22px 16px;background:var(--paper);\n    border:1px solid var(--line);position:relative;overflow:hidden;min-height:96px}\n  \/* het hele bovenblok (merkbalk + stappen + titel + voorbeeld) blijft als\n     één geheel in beeld tijdens het scrollen; alleen de opties eronder scrollen.\n     top-offset houdt ruimte vrij voor de terugkerende Shopify-header —\n     PAS DIT GETAL AAN zodat het net onder je header valt. *\/\n  .stickytop{position:sticky;top:0;z-index:6;background:var(--paper)}\n  .preview.plak{}\n  .raster{position:absolute;inset:0;opacity:.55;pointer-events:none;overflow:hidden}\n  .raster svg{position:absolute;inset:0;width:100%;height:100%}\n  .ptag{font-size:10px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:#c4bfbd;margin-bottom:12px;display:block;position:relative}\n  .set{display:flex;flex-direction:column;gap:6px;align-items:center;position:relative;transition:.3s;cursor:zoom-in}\n  .dsgn{width:100%;display:flex;justify-content:center}\n  .dsgn svg{width:100%;height:auto;display:block;filter:drop-shadow(0 5px 16px rgba(26,26,26,.12))}\n  .set.klein .dsgn{max-width:74%}\n  .set.normaal .dsgn{max-width:92%}\n  .set.groot .dsgn{max-width:100%}\n  \/* enkelvoudig design (bv. kentekensticker): één sticker, bijna volle breedte\n     zodat de smalle strip goed leesbaar is, met wat lucht aan de zijkanten *\/\n  .set.enkel .dsgn{max-width:100%}\n\n  .stk{width:100%;max-width:290px;height:62px;position:relative;display:block;\n    background:var(--stkbg,#1A1A1A);transition:background .3s;box-shadow:0 5px 16px rgba(26,26,26,.12)}\n  .stk.cauberg{clip-path:polygon(4% 0,100% 0,96% 100%,0 100%)}\n  .stk .silo{position:absolute;inset:0;opacity:.3;pointer-events:none;display:none}\n  .stk .nm{position:absolute;top:50%;left:0;transform:translateY(-50%);text-align:center;\n    font-weight:800;color:var(--stkink,#fff);white-space:nowrap;z-index:2;line-height:1}\n  .stk .flag{position:absolute;right:0;top:0;height:100%;width:30px;display:flex;flex-direction:column;z-index:1}\n  .stk .flag i{flex:1}\n\n  .body{flex:1;padding:0 20px 90px}\n  .hint{font-size:13px;color:#8a8482;margin:0 0 16px;line-height:1.5}\n\n  .wgrid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:11px}\n  .card{border:1.5px solid var(--line);border-radius:14px;padding:11px;cursor:pointer;background:#fff;transition:.15s}\n  .card.breed{grid-column:1\/-1}\n  .card.sel{border-color:var(--coral);box-shadow:0 0 0 3px rgba(254,136,109,.12)}\n  .card .mini{height:54px;border-radius:8px;margin-bottom:8px;display:flex;align-items:center;justify-content:center;overflow:hidden;padding:4px;position:relative}\n  \/* SVG losgekoppeld van de layoutberekening: position:absolute zorgt dat de eigen\n     beeldverhouding van elk design de kolombreedte van de grid niet meer kan beïnvloeden\n     (dat was de oorzaak van de ongelijke vakjes). preserveAspectRatio (in de JS) doet de rest. *\/\n  .card .mini svg{position:absolute;inset:4px;width:calc(100% - 8px);height:calc(100% - 8px);display:block}\n  .card .nm2{font-size:13px;font-weight:600;overflow-wrap:break-word}\n  .card .ds{font-size:11px;color:#a39e9c}\n\n  .blk{font-size:13px;font-weight:600;margin:20px 0 9px}\n  .blk:first-child{margin-top:4px}\n  .sizes{display:flex;gap:9px}\n  .chip{flex:1;border:1.5px solid var(--line);border-radius:12px;padding:11px 6px;text-align:center;cursor:pointer;background:#fff;font-size:13px;font-weight:600;transition:.15s;line-height:1.35}\n  .chip small{display:block;font-size:11px;color:#a39e9c;font-weight:400}\n  .chip.sel{border-color:var(--coral);background:var(--coral);color:#fff}\n  .chip.sel small{color:rgba(255,255,255,.85)}\n\n  input[type=text]{width:100%;border:1.5px solid var(--line);border-radius:13px;padding:13px 15px;font-size:16px;font-weight:600;font-family:inherit;color:var(--ink);background:#fff}\n  input[type=text]:focus{outline:none;border-color:var(--coral)}\n  input[type=range]{width:100%;accent-color:var(--coral)}\n\n  .opts{display:flex;flex-wrap:wrap;gap:8px}\n  .opt{border:1.5px solid var(--line);border-radius:11px;padding:8px 13px;font-size:13px;font-weight:600;cursor:pointer;background:#fff;display:flex;align-items:center;gap:7px;transition:.15s}\n  #flags{display:grid;grid-template-columns:repeat(4,1fr);gap:7px}\n  .vlagopt{border:1.5px solid var(--line);border-radius:10px;padding:6px 4px;cursor:pointer;background:#fff;transition:.15s;text-align:center}\n  .vlagopt.sel{border-color:var(--coral);box-shadow:0 0 0 2px rgba(254,136,109,.15)}\n  .vlagopt .vlagmini{height:26px;width:auto;aspect-ratio:3\/2;border-radius:4px;overflow:hidden;margin:0 auto 4px;background:#fff;display:flex;align-items:center;justify-content:center;box-shadow:0 0 0 1px var(--line) inset}\n  .vlagopt .vlagmini svg{max-width:100%;max-height:100%;width:auto;height:auto;display:block}\n  .vlagopt .vlagmini.geen{color:#b3aeac;font-size:13px;font-weight:700}\n  .vlagopt span{font-size:10px;font-weight:500;color:#a39e9c;display:block;line-height:1.15}\n  .vlagopt.sel span{color:var(--ink);font-weight:600}\n  .opt.sel{border-color:var(--coral);background:#fff;box-shadow:0 0 0 2px rgba(254,136,109,.15)}\n  .opt .fg{width:22px;height:15px;border-radius:3px;overflow:hidden;display:flex;flex-direction:column;box-shadow:0 0 0 1px rgba(0,0,0,.06)}\n  .opt .fg i{flex:1}\n  .sw{width:36px;height:36px;border-radius:10px;cursor:pointer;border:2px solid #fff;box-shadow:0 0 0 1.5px var(--line);transition:.15s}\n  .sw.sel{box-shadow:0 0 0 2.5px var(--coral)}\n  .sw.eigen{position:relative;background:conic-gradient(from 0deg,#ff4d4d,#ffd24d,#4dff88,#4dd2ff,#4d4dff,#ff4dff,#ff4d4d);display:flex;align-items:center;justify-content:center;overflow:hidden}\n  .sw.eigen input[type=color]{position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:pointer;border:none;padding:0}\n  .sw.eigen::after{content:\"+\";color:#fff;font-size:18px;font-weight:700;text-shadow:0 1px 3px rgba(0,0,0,.5);pointer-events:none}\n\n  .sum{background:#fff;border:1.5px solid var(--line);border-radius:14px;padding:6px 15px;margin-bottom:6px}\n  .sum .r{display:flex;justify-content:space-between;padding:10px 0;font-size:14px;border-bottom:1px solid var(--line)}\n  .sum .r:last-child{border:0;font-weight:700}\n  .sum .r .k{color:#8a8482}\n  .ups{border:1.5px solid var(--line);border-radius:14px;padding:13px;background:#fff;display:flex;gap:12px;align-items:center;margin-top:10px}\n  .ups .ic{width:42px;height:42px;border-radius:11px;background:var(--surface);display:flex;align-items:center;justify-content:center;flex-shrink:0;color:var(--coral)}\n  .ups .gr{flex:1}.ups .gr .h{font-size:13px;font-weight:600}.ups .gr .d{font-size:11px;color:#a39e9c}\n  .ups button{border:1.5px solid var(--ink);background:#fff;border-radius:10px;padding:7px 12px;font-size:12px;font-weight:600;cursor:pointer;font-family:inherit}\n\n  .nav{position:sticky;bottom:0;left:0;right:0;padding:14px 20px;background:var(--paper);border-top:1px solid var(--line);display:flex;gap:10px;align-items:center;z-index:5}\n  \/* prijs staat vanaf stap 1 in de navbalk en beweegt mee met formaat, kleur en vlag *\/\n  .navprijs{font-size:17px;font-weight:700;color:var(--ink);margin-right:auto;white-space:nowrap}\n  .navprijs:empty{display:none}\n  .navprijs small{display:block;font-size:11px;font-weight:500;color:#a39e9c;line-height:1.2}\n  .btn{border:none;border-radius:14px;padding:15px;font-size:15px;font-weight:700;cursor:pointer;font-family:inherit;transition:.15s}\n  .btn.back{background:transparent;color:#8a8482;padding:15px 4px;flex-shrink:0}\n  .btn.next{flex:1;background:var(--coral);color:#fff}\n  .btn.next:active{transform:translateY(1px)}\n  .btn.cart{flex:1;background:var(--ink);color:#fff;display:flex;align-items:center;justify-content:center;gap:8px}\n  .hide{display:none}\n\n  \/* ===== DESKTOP (breed scherm) =====\n     De wizard wordt breder, de preview blijft bovenaan op volle breedte\n     (fijn voor de brede kentekensticker), en de keuze-opties eronder\n     verdelen zich over meer kolommen zodat de extra ruimte benut wordt.\n     Onder 768px verandert er niets: de mobiele kolom-layout blijft. *\/\n  @media (min-width:768px){\n    .app{max-width:860px}\n    \/* preview groter en met wat meer lucht *\/\n    .preview{padding:30px 28px}\n    \/* de sticker mag op desktop wat compacter zodat 'ie niet het hele scherm vult *\/\n    .set.klein .dsgn{max-width:52%}\n    .set.normaal .dsgn{max-width:66%}\n    .set.groot .dsgn{max-width:80%}\n    .set.enkel .dsgn{max-width:100%}\n    \/* opties krijgen meer ademruimte en kolommen *\/\n    .body{padding:0 28px 90px}\n    .wgrid{grid-template-columns:repeat(2,minmax(0,1fr))}      \/* design-kaartjes: 2 op een rij, ook op desktop; kenteken spant de volle breedte (zie .card.breed) *\/\n    #flags{grid-template-columns:repeat(6,1fr)}      \/* vlaggen: 6 op een rij *\/\n    \/* kleuren\/tekstkleur-rijen mogen ruimer *\/\n    .opts{gap:10px}\n    \/* de hint-tekst niet eindeloos breed laten uitlopen (leesbaarheid) *\/\n    .hint{max-width:620px}\n  }\n\u003c\/style\u003e\n\n\n\u003cdiv class=\"app\"\u003e\n  \u003cdiv class=\"stickytop\"\u003e\n  \u003cdiv class=\"top\"\u003e\n    \u003cdiv class=\"brand\"\u003e\u003csvg viewbox=\"0 0 1500 299.999988\" height=\"24\" style=\"display:block\"\u003e\u003cdefs\u003e\u003cclippath id=\"107b19aa9b\"\u003e\u003cpath d=\"M 1438 184 L 1477.9375 184 L 1477.9375 224 L 1438 224 Z M 1438 184\"\u003e\u003c\/path\u003e\u003c\/clippath\u003e\u003cclippath id=\"2d37aceb3a\"\u003e\u003cpath d=\"M 22.1875 71 L 111 71 L 111 233 L 22.1875 233 Z M 22.1875 71\"\u003e\u003c\/path\u003e\u003c\/clippath\u003e\u003c\/defs\u003e\u003cg id=\"f73c2c1e9f\"\u003e\u003cpath d=\"M 321.148438 103.753906 C 309.847656 100.484375 297.894531 98.523438 283.117188 98.523438 C 230.523438 98.523438 217.265625 155.421875 264.425781 172.207031 C 287.898438 180.492188 299.851562 180.273438 298.980469 187.46875 C 298.546875 191.390625 292.027344 193.570312 282.683594 193.570312 C 270.292969 193.570312 252.90625 189.648438 237.910156 181.144531 L 237.910156 214.0625 C 249.648438 221.910156 268.992188 225.835938 281.59375 225.835938 C 328.320312 226.054688 338.535156 183.542969 323.539062 162.832031 C 311.152344 146.046875 269.425781 146.917969 269.207031 134.710938 C 269.207031 130.566406 275.511719 129.042969 283.988281 129.042969 C 295.503906 129.042969 310.933594 131.875 321.148438 135.582031 Z M 321.148438 103.753906\" style=\"stroke:none;fill-rule:nonzero;fill:#000000;fill-opacity:1;\"\u003e\u003c\/path\u003e\u003cpath d=\"M 338.320312 162.394531 C 338.320312 198.804688 359.402344 223 395.476562 223 C 431.773438 223 452.636719 198.804688 452.636719 162.394531 C 452.636719 125.988281 431.773438 101.792969 395.476562 101.792969 C 359.183594 101.792969 338.320312 125.988281 338.320312 162.394531 Z M 373.960938 162.394531 C 373.960938 145.609375 383.308594 137.324219 395.476562 137.324219 C 408.082031 137.324219 416.992188 145.609375 416.992188 162.394531 C 416.992188 178.964844 408.082031 187.25 395.476562 187.25 C 383.523438 187.25 373.960938 178.964844 373.960938 162.394531 Z M 373.960938 162.394531\" style=\"stroke:none;fill-rule:nonzero;fill:#000000;fill-opacity:1;\"\u003e\u003c\/path\u003e\u003cpath d=\"M 460.242188 162.832031 C 460.242188 199.238281 479.148438 223.4375 515.226562 223.4375 C 538.480469 223.4375 551.519531 215.371094 551.519531 215.371094 L 551.957031 182.234375 C 551.957031 182.234375 538.480469 192.917969 523.269531 192.917969 C 520.441406 192.917969 517.617188 192.480469 514.792969 191.609375 C 505.445312 190.082031 495.882812 179.402344 495.882812 162.832031 C 495.882812 144.738281 506.097656 132.746094 524.136719 132.746094 C 538.265625 132.746094 551.738281 141.6875 551.738281 141.6875 L 551.519531 108.769531 C 551.519531 108.769531 533.046875 102.226562 515.226562 102.226562 C 478.933594 102.226562 460.242188 126.425781 460.242188 162.832031 Z M 460.242188 162.832031\" style=\"stroke:none;fill-rule:nonzero;fill:#000000;fill-opacity:1;\"\u003e\u003c\/path\u003e\u003cpath d=\"M 566.082031 83.914062 C 566.082031 93.070312 573.90625 98.957031 585.859375 98.957031 C 597.597656 98.957031 605.421875 93.070312 605.421875 83.914062 C 605.421875 75.195312 597.597656 68.875 585.859375 68.875 C 573.90625 68.875 566.082031 75.195312 566.082031 83.914062 Z M 567.820312 220.167969 L 603.679688 220.167969 L 603.679688 103.753906 L 567.820312 103.753906 Z M 567.820312 220.167969\" style=\"stroke:none;fill-rule:nonzero;fill:#000000;fill-opacity:1;\"\u003e\u003c\/path\u003e\u003cpath d=\"M 690.613281 220.167969 L 726.257812 220.167969 L 726.257812 163.488281 C 726.257812 138.417969 725.167969 104.84375 689.308594 102.007812 C 684.09375 101.574219 678.878906 101.355469 673.878906 101.355469 C 648.886719 101.355469 627.804688 106.152344 627.804688 106.152344 L 628.023438 138.199219 C 646.710938 133.839844 659.96875 131.222656 669.097656 131.222656 C 686.050781 131.222656 689.960938 139.507812 690.179688 159.34375 C 684.527344 149.753906 673.660156 144.300781 656.058594 144.300781 C 632.585938 144.300781 616.722656 159.5625 616.722656 183.542969 C 616.722656 207.085938 632.585938 222.566406 656.058594 222.566406 C 672.359375 222.566406 684.09375 215.589844 690.394531 204.472656 L 690.394531 203.382812 C 690.613281 207.742188 690.613281 213.191406 690.613281 220.167969 Z M 652.363281 182.890625 C 652.363281 175.695312 658.882812 171.550781 671.488281 171.550781 C 688.441406 171.550781 690.179688 174.167969 690.179688 183.105469 C 690.179688 190.082031 684.09375 194.226562 671.488281 194.226562 C 658.882812 194.226562 652.363281 190.082031 652.363281 182.890625 Z M 652.363281 182.890625\" style=\"stroke:none;fill-rule:nonzero;fill:#000000;fill-opacity:1;\"\u003e\u003c\/path\u003e\u003cpath d=\"M 741.035156 220.167969 L 776.675781 220.601562 L 776.675781 68 L 741.035156 67.566406 Z M 741.035156 220.167969\" style=\"stroke:none;fill-rule:nonzero;fill:#000000;fill-opacity:1;\"\u003e\u003c\/path\u003e\u003cpath d=\"M 875.128906 103.753906 C 863.828125 100.484375 851.875 98.523438 837.09375 98.523438 C 784.5 98.523438 771.242188 155.421875 818.40625 172.207031 C 841.875 180.492188 853.828125 180.273438 852.960938 187.46875 C 852.527344 191.390625 846.003906 193.570312 836.660156 193.570312 C 824.273438 193.570312 806.886719 189.648438 791.890625 181.144531 L 791.890625 214.0625 C 803.625 221.910156 822.96875 225.835938 835.574219 225.835938 C 882.300781 226.054688 892.515625 183.542969 877.519531 162.832031 C 865.128906 146.046875 823.402344 146.917969 823.1875 134.710938 C 823.1875 130.566406 829.488281 129.042969 837.964844 129.042969 C 849.484375 129.042969 864.914062 131.875 875.128906 135.582031 Z M 875.128906 103.753906\" style=\"stroke:none;fill-rule:nonzero;fill:#000000;fill-opacity:1;\"\u003e\u003c\/path\u003e\u003cpath d=\"M 902.078125 128.824219 L 902.078125 176.785156 C 902.078125 204.6875 911.207031 222.566406 939.457031 222.566406 C 947.28125 222.566406 956.84375 221.257812 967.929688 218.207031 L 967.929688 190.300781 C 962.929688 191.828125 957.0625 193.351562 951.847656 193.351562 C 944.023438 193.351562 937.71875 190.082031 937.71875 178.964844 L 937.71875 128.824219 L 961.191406 128.824219 L 961.191406 103.101562 L 937.71875 103.101562 L 937.71875 76.722656 L 911.855469 76.722656 C 908.816406 93.726562 895.773438 103.101562 889.90625 103.101562 L 889.90625 128.824219 Z M 902.078125 128.824219\" style=\"stroke:none;fill-rule:nonzero;fill:#000000;fill-opacity:1;\"\u003e\u003c\/path\u003e\u003cpath d=\"M 977.273438 83.914062 C 977.273438 93.070312 985.097656 98.957031 997.050781 98.957031 C 1008.789062 98.957031 1016.613281 93.070312 1016.613281 83.914062 C 1016.613281 75.195312 1008.789062 68.875 997.050781 68.875 C 985.097656 68.875 977.273438 75.195312 977.273438 83.914062 Z M 979.011719 220.167969 L 1014.875 220.167969 L 1014.875 103.753906 L 979.011719 103.753906 Z M 979.011719 220.167969\" style=\"stroke:none;fill-rule:nonzero;fill:#000000;fill-opacity:1;\"\u003e\u003c\/path\u003e\u003cpath d=\"M 1027.914062 162.832031 C 1027.914062 199.238281 1046.820312 223.4375 1082.898438 223.4375 C 1106.152344 223.4375 1119.191406 215.371094 1119.191406 215.371094 L 1119.625 182.234375 C 1119.625 182.234375 1106.152344 192.917969 1090.9375 192.917969 C 1088.113281 192.917969 1085.289062 192.480469 1082.460938 191.609375 C 1073.117188 190.082031 1063.554688 179.402344 1063.554688 162.832031 C 1063.554688 144.738281 1073.769531 132.746094 1091.808594 132.746094 C 1105.933594 132.746094 1119.410156 141.6875 1119.410156 141.6875 L 1119.191406 108.769531 C 1119.191406 108.769531 1100.71875 102.226562 1082.898438 102.226562 C 1046.601562 102.226562 1027.914062 126.425781 1027.914062 162.832031 Z M 1027.914062 162.832031\" style=\"stroke:none;fill-rule:nonzero;fill:#000000;fill-opacity:1;\"\u003e\u003c\/path\u003e\u003cpath d=\"M 1133.972656 221.691406 L 1169.613281 221.691406 L 1169.613281 173.296875 L 1172.875 173.296875 L 1203.515625 220.601562 L 1244.808594 220.601562 L 1206.558594 161.742188 L 1237.855469 103.101562 L 1198.519531 103.101562 L 1173.523438 149.96875 L 1169.394531 149.96875 L 1169.394531 67.566406 L 1133.753906 67.566406 Z M 1133.972656 221.691406\" style=\"stroke:none;fill-rule:nonzero;fill:#000000;fill-opacity:1;\"\u003e\u003c\/path\u003e\u003cpath d=\"M 1243.046875 162.394531 C 1243.046875 198.804688 1261.738281 223 1297.597656 223 C 1320.632812 223 1339.324219 217.332031 1339.324219 217.332031 L 1339.105469 187.683594 C 1330.414062 191.390625 1316.722656 194.441406 1306.507812 194.441406 C 1294.335938 194.441406 1284.773438 188.558594 1280.863281 176.347656 L 1348.667969 176.347656 L 1349.320312 166.757812 C 1349.320312 133.402344 1340.195312 101.792969 1297.597656 101.792969 C 1261.519531 101.792969 1243.046875 125.988281 1243.046875 162.394531 Z M 1279.339844 149.753906 C 1281.515625 138.199219 1288.035156 131.875 1297.378906 131.875 C 1308.246094 131.875 1313.460938 138.851562 1315.417969 149.753906 Z M 1279.339844 149.753906\" style=\"stroke:none;fill-rule:nonzero;fill:#000000;fill-opacity:1;\"\u003e\u003c\/path\u003e\u003cpath d=\"M 1361.710938 220.167969 L 1397.351562 220.167969 L 1397.351562 184.195312 C 1397.351562 162.179688 1399.089844 155.421875 1403.003906 148.664062 C 1409.304688 137.109375 1420.171875 134.273438 1429.082031 134.273438 C 1437.777344 134.273438 1444.949219 136.890625 1444.949219 136.890625 L 1444.949219 101.574219 C 1444.949219 101.574219 1425.605469 100.046875 1412.132812 109.640625 C 1405.175781 114.652344 1400.613281 121.410156 1397.351562 127.953125 L 1397.351562 103.753906 L 1361.710938 103.753906 Z M 1361.710938 220.167969\" style=\"stroke:none;fill-rule:nonzero;fill:#000000;fill-opacity:1;\"\u003e\u003c\/path\u003e\u003cg clip-path=\"url(#107b19aa9b)\" clip-rule=\"nonzero\"\u003e\u003cpath d=\"M 1438.863281 203.597656 C 1438.863281 215.152344 1446.90625 223.21875 1458.425781 223.21875 C 1469.726562 223.21875 1477.765625 215.152344 1477.765625 203.597656 C 1477.765625 192.480469 1469.726562 184.632812 1458.425781 184.632812 C 1446.90625 184.632812 1438.863281 192.480469 1438.863281 203.597656 Z M 1438.863281 203.597656\" style=\"stroke:none;fill-rule:nonzero;fill:#fe886d;fill-opacity:1;\"\u003e\u003c\/path\u003e\u003c\/g\u003e\u003cg clip-path=\"url(#2d37aceb3a)\" clip-rule=\"nonzero\"\u003e\u003cpath d=\"M 22.230469 232.378906 C 79.496094 130.101562 -2.925781 164.285156 38.230469 71.769531 L 100.539062 71.769531 C 80.089844 125.296875 102.988281 137.113281 108.667969 158.078125 C 114.59375 179.96875 104.589844 200.46875 88.207031 232.378906 Z M 22.230469 232.378906\" style=\"stroke:none;fill-rule:evenodd;fill:#fe886d;fill-opacity:1;\"\u003e\u003c\/path\u003e\u003c\/g\u003e\u003cpath d=\"M 179.601562 71.769531 C 158.382812 123.902344 185.175781 133.421875 191.394531 153.972656 C 198.304688 176.800781 189.304688 198.132812 173.144531 232.378906 L 105.730469 232.378906 C 162.464844 126.753906 82.539062 160.257812 116.554688 71.769531 Z M 179.601562 71.769531\" style=\"stroke:none;fill-rule:evenodd;fill:#feb5a5;fill-opacity:1;\"\u003e\u003c\/path\u003e\u003c\/g\u003e\u003c\/svg\u003e\u003c\/div\u003e\n    \u003cdiv class=\"steps\"\u003e\n      \u003cdiv class=\"s active\" data-s=\"1\"\u003e\u003c\/div\u003e\n\u003cdiv class=\"s\" data-s=\"2\"\u003e\u003c\/div\u003e\n      \u003cdiv class=\"s\" data-s=\"3\"\u003e\u003c\/div\u003e\n\u003cdiv class=\"s\" data-s=\"4\"\u003e\u003c\/div\u003e\n    \u003c\/div\u003e\n    \u003cdiv class=\"stepinfo\"\u003e\n      \u003cspan class=\"n\" id=\"sn\"\u003eStap 1 van 4\u003c\/span\u003e\n      \u003cspan class=\"c\" id=\"sc\"\u003e\u003c\/span\u003e\n    \u003c\/div\u003e\n    \u003cdiv class=\"stepinfo\"\u003e\u003ch2 id=\"st\"\u003eKies je design\u003c\/h2\u003e\u003c\/div\u003e\n  \u003c\/div\u003e\n\n  \u003cdiv class=\"preview plak\"\u003e\n    \u003cdiv class=\"raster\"\u003e\u003csvg viewbox=\"56 176 689 601\" preserveaspectratio=\"none\" style=\"position:absolute;inset:0;width:100%;height:100%\"\u003e\u003cdefs\u003e\u003cfilter x=\"0%\" y=\"0%\" width=\"100%\" height=\"100%\" id=\"d6518b5df7\"\u003e\u003cfecolormatrix values=\"0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0\" color-interpolation-filters=\"sRGB\"\u003e\u003c\/fecolormatrix\u003e\u003c\/filter\u003e\u003cclippath id=\"4d44c48633\"\u003e\u003cpath d=\"M 56.144531 176 L 745 176 L 745 777.925781 L 56.144531 777.925781 Z M 56.144531 176 \" clip-rule=\"nonzero\"\u003e\u003c\/path\u003e\u003c\/clippath\u003e\u003cclippath id=\"95e285798a\"\u003e\u003cpath d=\"M 68.144531 176 L 732.054688 176 C 735.238281 176 738.289062 177.265625 740.539062 179.515625 C 742.789062 181.765625 744.054688 184.820312 744.054688 188 L 744.054688 765.925781 C 744.054688 769.105469 742.789062 772.160156 740.539062 774.410156 C 738.289062 776.660156 735.238281 777.925781 732.054688 777.925781 L 68.144531 777.925781 C 64.960938 777.925781 61.90625 776.660156 59.65625 774.410156 C 57.40625 772.160156 56.144531 769.105469 56.144531 765.925781 L 56.144531 188 C 56.144531 184.820312 57.40625 181.765625 59.65625 179.515625 C 61.90625 177.265625 64.960938 176 68.144531 176 Z M 68.144531 176 \" clip-rule=\"nonzero\"\u003e\u003c\/path\u003e\u003c\/clippath\u003e\u003cclippath id=\"64b7bc8e3b\"\u003e\u003cpath d=\"M 0.144531 0 L 688.238281 0 L 688.238281 601.925781 L 0.144531 601.925781 Z M 0.144531 0 \" clip-rule=\"nonzero\"\u003e\u003c\/path\u003e\u003c\/clippath\u003e\u003cclippath id=\"65b889c8ba\"\u003e\u003cpath d=\"M 12.144531 0 L 676.054688 0 C 679.238281 0 682.289062 1.265625 684.539062 3.515625 C 686.789062 5.765625 688.054688 8.820312 688.054688 12 L 688.054688 589.925781 C 688.054688 593.105469 686.789062 596.160156 684.539062 598.410156 C 682.289062 600.660156 679.238281 601.925781 676.054688 601.925781 L 12.144531 601.925781 C 8.960938 601.925781 5.90625 600.660156 3.65625 598.410156 C 1.40625 596.160156 0.144531 593.105469 0.144531 589.925781 L 0.144531 12 C 0.144531 8.820312 1.40625 5.765625 3.65625 3.515625 C 5.90625 1.265625 8.960938 0 12.144531 0 Z M 12.144531 0 \" clip-rule=\"nonzero\"\u003e\u003c\/path\u003e\u003c\/clippath\u003e\u003cclippath id=\"7195c635ea\"\u003e\u003crect x=\"0\" width=\"689\" y=\"0\" height=\"602\"\u003e\u003c\/rect\u003e\u003c\/clippath\u003e\u003cclippath id=\"c2cd02c779\"\u003e\u003cpath d=\"M 56.144531 176.003906 L 743.894531 176.003906 L 743.894531 778 L 56.144531 778 Z M 56.144531 176.003906 \" clip-rule=\"nonzero\"\u003e\u003c\/path\u003e\u003c\/clippath\u003e\u003cclippath id=\"c0ce7af124\"\u003e\u003cpath d=\"M 68.144531 176.003906 L 732.046875 176.003906 C 735.226562 176.003906 738.28125 177.269531 740.53125 179.519531 C 742.78125 181.769531 744.046875 184.824219 744.046875 188.003906 L 744.046875 765.921875 C 744.046875 769.101562 742.78125 772.15625 740.53125 774.40625 C 738.28125 776.65625 735.226562 777.917969 732.046875 777.917969 L 68.144531 777.917969 C 64.960938 777.917969 61.90625 776.65625 59.65625 774.40625 C 57.40625 772.15625 56.144531 769.101562 56.144531 765.921875 L 56.144531 188.003906 C 56.144531 184.824219 57.40625 181.769531 59.65625 179.519531 C 61.90625 177.269531 64.960938 176.003906 68.144531 176.003906 Z M 68.144531 176.003906 \" clip-rule=\"nonzero\"\u003e\u003c\/path\u003e\u003c\/clippath\u003e\u003cmask id=\"7f4301724a\"\u003e\u003cg filter=\"url(#d6518b5df7)\"\u003e\u003crect x=\"-81\" width=\"972\" fill=\"#000000\" y=\"-80.999999\" height=\"971.999992\" fill-opacity=\"0.49\"\u003e\u003c\/rect\u003e\u003c\/g\u003e\u003c\/mask\u003e\u003cclippath id=\"e48af23bab\"\u003e\u003cpath d=\"M 1.144531 1 L 688.894531 1 L 688.894531 603 L 1.144531 603 Z M 1.144531 1 \" clip-rule=\"nonzero\"\u003e\u003c\/path\u003e\u003c\/clippath\u003e\u003cclippath id=\"eaf65a493f\"\u003e\u003cpath d=\"M 1.144531 13 L 1.144531 590.925781 C 1.144531 597.550781 6.515625 602.925781 13.144531 602.925781 L 677.054688 602.925781 C 683.683594 602.925781 689.054688 597.550781 689.054688 590.925781 L 689.054688 13 C 689.054688 6.375 683.683594 1 677.054688 1 L 13.144531 1 C 6.515625 1 1.144531 6.375 1.144531 13 Z M 1.144531 13 \" clip-rule=\"nonzero\"\u003e\u003c\/path\u003e\u003c\/clippath\u003e\u003cclippath id=\"920e398760\"\u003e\u003crect x=\"0\" width=\"690\" y=\"0\" height=\"604\"\u003e\u003c\/rect\u003e\u003c\/clippath\u003e\u003c\/defs\u003e\u003cg clip-path=\"url(#4d44c48633)\"\u003e\u003cg clip-path=\"url(#95e285798a)\"\u003e\u003cg transform=\"matrix(1, 0, 0, 1, 56, 176)\"\u003e\u003cg clip-path=\"url(#7195c635ea)\"\u003e\u003cg clip-path=\"url(#64b7bc8e3b)\"\u003e\u003cg clip-path=\"url(#65b889c8ba)\"\u003e\u003cpath fill=\"#f0f0f0\" d=\"M 0.144531 0 L 689.0625 0 L 689.0625 601.925781 L 0.144531 601.925781 Z M 0.144531 0 \" fill-opacity=\"1\" fill-rule=\"nonzero\"\u003e\u003c\/path\u003e\u003c\/g\u003e\u003c\/g\u003e\u003c\/g\u003e\u003c\/g\u003e\u003c\/g\u003e\u003c\/g\u003e\u003cg clip-path=\"url(#c2cd02c779)\"\u003e\u003cg clip-path=\"url(#c0ce7af124)\"\u003e\u003cpath stroke-linecap=\"butt\" transform=\"matrix(0.75, 0, 0, 0.75, 56.142752, 176.00169)\" fill=\"none\" stroke-linejoin=\"miter\" d=\"M 16.002373 0.00295454 L 901.205543 0.00295454 C 905.445126 0.00295454 909.518043 1.690455 912.518043 4.690455 C 915.518044 7.690455 917.205544 11.763372 917.205544 16.002955 L 917.205544 786.560286 C 917.205544 790.799869 915.518044 794.872786 912.518043 797.872786 C 909.518043 800.872786 905.445126 802.555078 901.205543 802.555078 L 16.002373 802.555078 C 11.757581 802.555078 7.684665 800.872786 4.684664 797.872786 C 1.684664 794.872786 0.0023725 790.799869 0.0023725 786.560286 L 0.0023725 16.002955 C 0.0023725 11.763372 1.684664 7.690455 4.684664 4.690455 C 7.684665 1.690455 11.757581 0.00295454 16.002373 0.00295454 Z M 16.002373 0.00295454 \" stroke=\"#ffffff\" stroke-width=\"8\" stroke-opacity=\"1\" stroke-miterlimit=\"4\"\u003e\u003c\/path\u003e\u003c\/g\u003e\u003c\/g\u003e\u003cg mask=\"url(#7f4301724a)\"\u003e\u003cg transform=\"matrix(1, 0, 0, 1, 55, 175)\"\u003e\u003cg clip-path=\"url(#920e398760)\"\u003e\u003cg clip-path=\"url(#e48af23bab)\"\u003e\u003cg clip-path=\"url(#eaf65a493f)\"\u003e\u003cpath fill=\"#ffffff\" d=\"M 1.144531 1.074219 L 689.046875 1.074219 L 689.046875 602.851562 L 1.144531 602.851562 Z M 2.21875 2.148438 L 86.054688 2.148438 L 86.054688 85.964844 L 2.21875 85.964844 Z M 88.207031 2.148438 L 172.042969 2.148438 L 172.042969 85.964844 L 88.207031 85.964844 Z M 258.03125 2.148438 L 174.191406 2.148438 L 174.191406 85.964844 L 258.03125 85.964844 Z M 260.179688 2.148438 L 344.019531 2.148438 L 344.019531 85.964844 L 260.179688 85.964844 Z M 430.007812 2.148438 L 346.167969 2.148438 L 346.167969 85.964844 L 430.007812 85.964844 Z M 432.15625 2.148438 L 515.992188 2.148438 L 515.992188 85.964844 L 432.15625 85.964844 Z M 601.984375 2.148438 L 518.144531 2.148438 L 518.144531 85.964844 L 601.984375 85.964844 Z M 604.132812 2.148438 L 687.96875 2.148438 L 687.96875 85.964844 L 604.132812 85.964844 Z M 86.054688 88.117188 L 2.21875 88.117188 L 2.21875 171.933594 L 86.054688 171.933594 Z M 88.207031 88.117188 L 172.042969 88.117188 L 172.042969 171.933594 L 88.207031 171.933594 Z M 258.03125 88.117188 L 174.191406 88.117188 L 174.191406 171.933594 L 258.03125 171.933594 Z M 260.179688 88.117188 L 344.019531 88.117188 L 344.019531 171.933594 L 260.179688 171.933594 Z M 430.007812 88.117188 L 346.167969 88.117188 L 346.167969 171.933594 L 430.007812 171.933594 Z M 432.15625 88.117188 L 515.992188 88.117188 L 515.992188 171.933594 L 432.15625 171.933594 Z M 601.984375 88.117188 L 518.144531 88.117188 L 518.144531 171.933594 L 601.984375 171.933594 Z M 604.132812 88.117188 L 687.96875 88.117188 L 687.96875 171.933594 L 604.132812 171.933594 Z M 86.054688 174.085938 L 2.21875 174.085938 L 2.21875 257.902344 L 86.054688 257.902344 Z M 88.207031 174.085938 L 172.042969 174.085938 L 172.042969 257.902344 L 88.207031 257.902344 Z M 258.03125 174.085938 L 174.191406 174.085938 L 174.191406 257.902344 L 258.03125 257.902344 Z M 260.179688 174.085938 L 344.019531 174.085938 L 344.019531 257.902344 L 260.179688 257.902344 Z M 430.007812 174.085938 L 346.167969 174.085938 L 346.167969 257.902344 L 430.007812 257.902344 Z M 432.15625 174.085938 L 515.992188 174.085938 L 515.992188 257.902344 L 432.15625 257.902344 Z M 601.984375 174.085938 L 518.144531 174.085938 L 518.144531 257.902344 L 601.984375 257.902344 Z M 604.132812 174.085938 L 687.96875 174.085938 L 687.96875 257.902344 L 604.132812 257.902344 Z M 86.054688 260.054688 L 2.21875 260.054688 L 2.21875 343.871094 L 86.054688 343.871094 Z M 88.207031 260.054688 L 172.042969 260.054688 L 172.042969 343.871094 L 88.207031 343.871094 Z M 258.03125 260.054688 L 174.191406 260.054688 L 174.191406 343.871094 L 258.03125 343.871094 Z M 260.179688 260.054688 L 344.019531 260.054688 L 344.019531 343.871094 L 260.179688 343.871094 Z M 430.007812 260.054688 L 346.167969 260.054688 L 346.167969 343.871094 L 430.007812 343.871094 Z M 432.15625 260.054688 L 515.992188 260.054688 L 515.992188 343.871094 L 432.15625 343.871094 Z M 601.984375 260.054688 L 518.144531 260.054688 L 518.144531 343.871094 L 601.984375 343.871094 Z M 604.132812 260.054688 L 687.96875 260.054688 L 687.96875 343.871094 L 604.132812 343.871094 Z M 86.054688 346.019531 L 2.21875 346.019531 L 2.21875 429.839844 L 86.054688 429.839844 Z M 88.207031 346.019531 L 172.042969 346.019531 L 172.042969 429.839844 L 88.207031 429.839844 Z M 258.03125 346.019531 L 174.191406 346.019531 L 174.191406 429.839844 L 258.03125 429.839844 Z M 260.179688 346.019531 L 344.019531 346.019531 L 344.019531 429.839844 L 260.179688 429.839844 Z M 430.007812 346.019531 L 346.167969 346.019531 L 346.167969 429.839844 L 430.007812 429.839844 Z M 432.15625 346.019531 L 515.992188 346.019531 L 515.992188 429.839844 L 432.15625 429.839844 Z M 601.984375 346.019531 L 518.144531 346.019531 L 518.144531 429.839844 L 601.984375 429.839844 Z M 604.132812 346.019531 L 687.96875 346.019531 L 687.96875 429.839844 L 604.132812 429.839844 Z M 86.054688 431.988281 L 2.21875 431.988281 L 2.21875 515.808594 L 86.054688 515.808594 Z M 88.207031 431.988281 L 172.042969 431.988281 L 172.042969 515.808594 L 88.207031 515.808594 Z M 258.03125 431.988281 L 174.191406 431.988281 L 174.191406 515.808594 L 258.03125 515.808594 Z M 260.179688 431.988281 L 344.019531 431.988281 L 344.019531 515.808594 L 260.179688 515.808594 Z M 430.007812 431.988281 L 346.167969 431.988281 L 346.167969 515.808594 L 430.007812 515.808594 Z M 432.15625 431.988281 L 515.992188 431.988281 L 515.992188 515.808594 L 432.15625 515.808594 Z M 601.984375 431.988281 L 518.144531 431.988281 L 518.144531 515.808594 L 601.984375 515.808594 Z M 604.132812 431.988281 L 687.96875 431.988281 L 687.96875 515.808594 L 604.132812 515.808594 Z M 86.054688 517.957031 L 2.21875 517.957031 L 2.21875 601.78125 L 86.054688 601.78125 Z M 88.207031 517.957031 L 172.042969 517.957031 L 172.042969 601.78125 L 88.207031 601.78125 Z M 258.03125 517.957031 L 174.191406 517.957031 L 174.191406 601.78125 L 258.03125 601.78125 Z M 260.179688 517.957031 L 344.019531 517.957031 L 344.019531 601.78125 L 260.179688 601.78125 Z M 430.007812 517.957031 L 346.167969 517.957031 L 346.167969 601.78125 L 430.007812 601.78125 Z M 432.15625 517.957031 L 515.992188 517.957031 L 515.992188 601.78125 L 432.15625 601.78125 Z M 601.984375 517.957031 L 518.144531 517.957031 L 518.144531 601.78125 L 601.984375 601.78125 Z M 604.132812 517.957031 L 687.96875 517.957031 L 687.96875 601.78125 L 604.132812 601.78125 Z M 604.132812 517.957031 \" fill-opacity=\"1\" fill-rule=\"evenodd\"\u003e\u003c\/path\u003e\u003c\/g\u003e\u003c\/g\u003e\u003c\/g\u003e\u003c\/g\u003e\u003c\/g\u003e\u003c\/svg\u003e\u003c\/div\u003e\n    \u003cspan class=\"ptag\"\u003eVoorbeeld — set van 2\u003c\/span\u003e\n    \u003cbutton id=\"vergrootBtn\" title=\"Vergroot\" aria-label=\"Vergroot voorbeeld\" style=\"position:absolute;top:12px;right:12px;z-index:3;height:34px;padding:0 12px;border:1.5px solid var(--line);background:#fff;border-radius:10px;cursor:pointer;display:flex;align-items:center;gap:6px;color:var(--ink);font-family:inherit;font-size:12px;font-weight:600\"\u003e\n      \u003csvg width=\"15\" height=\"15\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\u003e\u003cpath d=\"M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7\"\u003e\u003c\/path\u003e\u003c\/svg\u003e\n      Vergroot\n    \u003c\/button\u003e\n    \u003cdiv class=\"set normaal\" id=\"set\"\u003e\n      \u003cdiv class=\"dsgn\" id=\"dsgn1\"\u003e\u003c\/div\u003e\n      \u003cdiv class=\"dsgn\" id=\"dsgn2\"\u003e\u003c\/div\u003e\n    \u003c\/div\u003e\n  \u003c\/div\u003e\n  \u003c\/div\u003e\n\u003c!-- \/.stickytop --\u003e\n\n  \u003c!-- Fullscreen voorbeeld-overlay: tik op de preview (of het vergroot-knopje)\n       toont de sticker groot. Handig bij de smalle kentekensticker. --\u003e\n  \u003cdiv id=\"vergrootOverlay\" style=\"display:none;position:fixed;inset:0;z-index:50;background:rgba(26,26,26,.82);backdrop-filter:blur(3px);align-items:center;justify-content:center;padding:20px\"\u003e\n    \u003cbutton id=\"vergrootSluit\" aria-label=\"Sluiten\" style=\"position:absolute;top:16px;right:16px;width:44px;height:44px;border:none;background:rgba(255,255,255,.15);color:#fff;border-radius:12px;cursor:pointer;font-size:22px;display:flex;align-items:center;justify-content:center\"\u003e✕\u003c\/button\u003e\n    \u003cdiv id=\"vergrootInhoud\" style=\"width:100%;max-width:1100px;display:flex;flex-direction:column;gap:10px;align-items:center\"\u003e\u003c\/div\u003e\n  \u003c\/div\u003e\n\n  \u003cdiv class=\"body\"\u003e\n    \u003c!-- STAP 1 --\u003e\n    \u003cdiv class=\"step\" data-step=\"1\"\u003e\n      \u003cp class=\"hint\"\u003eKies een design en formaat. Het design bepaalt de stijl — daarna maak je 'm helemaal van jou.\u003c\/p\u003e\n      \u003cdiv class=\"wgrid\" id=\"designs\"\u003e\u003c\/div\u003e\n      \u003cdiv id=\"formaatBlok\"\u003e\n        \u003cdiv class=\"blk\"\u003eFormaat\u003c\/div\u003e\n        \u003cdiv class=\"sizes\" id=\"sizes\"\u003e\n          \u003cdiv class=\"chip\" data-size=\"klein\"\u003eKlein\u003csmall data-maat=\"klein\"\u003e4×0,7 cm\u003c\/small\u003e\n\u003c\/div\u003e\n          \u003cdiv class=\"chip sel\" data-size=\"normaal\"\u003eNormaal\u003csmall data-maat=\"normaal\"\u003e5×0,9 cm\u003c\/small\u003e\n\u003c\/div\u003e\n          \u003cdiv class=\"chip\" data-size=\"groot\"\u003eGroot\u003csmall data-maat=\"groot\"\u003e7×1,2 cm\u003c\/small\u003e\n\u003c\/div\u003e\n        \u003c\/div\u003e\n      \u003c\/div\u003e\n    \u003c\/div\u003e\n\n    \u003c!-- STAP 2 --\u003e\n    \u003cdiv class=\"step hide\" data-step=\"2\"\u003e\n      \u003cp class=\"hint\"\u003eTyp de naam. De tekst schaalt automatisch zodat 'ie altijd netjes binnen het design past.\u003c\/p\u003e\n      \u003cdiv class=\"blk\"\u003eNaam op de sticker\u003c\/div\u003e\n      \u003cinput type=\"text\" id=\"naam\" value=\"JOUW NAAM\" maxlength=\"22\" autocomplete=\"off\"\u003e\n      \u003cdiv id=\"naamHint\" style=\"display:none;font-size:12px;color:var(--coral);margin-top:5px\"\u003eDit teken kan niet op een sticker.\u003c\/div\u003e\n      \u003cdiv id=\"fontBlok\"\u003e\n        \u003cdiv class=\"blk\"\u003eLettertype\u003c\/div\u003e\n        \u003cdiv class=\"opts\" id=\"fonts\"\u003e\n          \u003cdiv class=\"opt sel\" data-font=\"Saira Condensed\"\u003eSaira\u003c\/div\u003e\n          \u003cdiv class=\"opt\" data-font=\"Bebas Neue\"\u003eBebas\u003c\/div\u003e\n          \u003cdiv class=\"opt\" data-font=\"Anton\"\u003eAnton\u003c\/div\u003e\n          \u003cdiv class=\"opt\" data-font=\"Montserrat\"\u003eMontserrat\u003c\/div\u003e\n          \u003cdiv class=\"opt\" data-font=\"Dancing Script\"\u003eDancing\u003c\/div\u003e\n        \u003c\/div\u003e\n      \u003c\/div\u003e\n      \u003cdiv class=\"blk\"\u003eTekstgrootte\u003c\/div\u003e\n      \u003cinput type=\"range\" id=\"size\" min=\"60\" max=\"100\" value=\"100\" step=\"1\"\u003e\n    \u003c\/div\u003e\n\n    \u003c!-- STAP 3 --\u003e\n    \u003cdiv class=\"step hide\" data-step=\"3\"\u003e\n      \u003cp class=\"hint\"\u003eKies een vlag en de kleuren. Alles verschijnt direct in je voorbeeld.\u003c\/p\u003e\n      \u003cdiv class=\"blk\"\u003eVlag\u003c\/div\u003e\n      \u003cdiv class=\"opts\" id=\"flags\"\u003e\u003c\/div\u003e\n      \u003cdiv class=\"blk\"\u003eAchtergrondkleur\u003c\/div\u003e\n      \u003cdiv class=\"opts\"\u003e\n        \u003cdiv class=\"sw sel\" style=\"background:#1A1A1A\" data-bg=\"#1A1A1A\" title=\"Zwart\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"sw\" style=\"background:#FFFFFF\" data-bg=\"#FFFFFF\" title=\"Wit\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"sw\" style=\"background:#FAEB41\" data-bg=\"#FAEB41\" title=\"Geel\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"sw\" style=\"background:#F07A2B\" data-bg=\"#F07A2B\" title=\"Oranje\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"sw\" style=\"background:#E01D1B\" data-bg=\"#E01D1B\" title=\"Rood\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"sw\" style=\"background:#85E4F2\" data-bg=\"#85E4F2\" title=\"Lichtblauw\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"sw\" style=\"background:#22396E\" data-bg=\"#22396E\" title=\"Donkerblauw\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"sw\" style=\"background:#79BA47\" data-bg=\"#79BA47\" title=\"Lichtgroen\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"sw\" style=\"background:#0E3D12\" data-bg=\"#0E3D12\" title=\"Donkergroen\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"sw\" style=\"background:#5B3069\" data-bg=\"#5B3069\" title=\"Paars\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"sw\" style=\"background:#F2A2D0\" data-bg=\"#F2A2D0\" title=\"Roze\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"sw\" style=\"background:#5A5D5E\" data-bg=\"#5A5D5E\" title=\"Grijs\"\u003e\u003c\/div\u003e\n        \u003clabel class=\"sw eigen\" id=\"bgPickWrap\" title=\"Eigen kleur\"\u003e\n          \u003cinput type=\"color\" id=\"bgPick\" value=\"#1A1A1A\"\u003e\n        \u003c\/label\u003e\n      \u003c\/div\u003e\n      \u003cdiv class=\"blk\"\u003eTekstkleur\u003c\/div\u003e\n      \u003cdiv class=\"opts\"\u003e\n        \u003cdiv class=\"sw sel\" style=\"background:#FFFFFF\" data-ink=\"#FFFFFF\" title=\"Wit\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"sw\" style=\"background:#1A1A1A\" data-ink=\"#1A1A1A\" title=\"Zwart\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"sw\" style=\"background:#FAEB41\" data-ink=\"#FAEB41\" title=\"Geel\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"sw\" style=\"background:#F07A2B\" data-ink=\"#F07A2B\" title=\"Oranje\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"sw\" style=\"background:#E01D1B\" data-ink=\"#E01D1B\" title=\"Rood\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"sw\" style=\"background:#85E4F2\" data-ink=\"#85E4F2\" title=\"Lichtblauw\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"sw\" style=\"background:#22396E\" data-ink=\"#22396E\" title=\"Donkerblauw\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"sw\" style=\"background:#79BA47\" data-ink=\"#79BA47\" title=\"Lichtgroen\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"sw\" style=\"background:#0E3D12\" data-ink=\"#0E3D12\" title=\"Donkergroen\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"sw\" style=\"background:#5B3069\" data-ink=\"#5B3069\" title=\"Paars\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"sw\" style=\"background:#F2A2D0\" data-ink=\"#F2A2D0\" title=\"Roze\"\u003e\u003c\/div\u003e\n        \u003cdiv class=\"sw\" style=\"background:#5A5D5E\" data-ink=\"#5A5D5E\" title=\"Grijs\"\u003e\u003c\/div\u003e\n        \u003clabel class=\"sw eigen\" id=\"inkPickWrap\" title=\"Eigen kleur\"\u003e\n          \u003cinput type=\"color\" id=\"inkPick\" value=\"#ffffff\"\u003e\n        \u003c\/label\u003e\n      \u003c\/div\u003e\n    \u003c\/div\u003e\n\n    \u003c!-- STAP 4 --\u003e\n    \u003cdiv class=\"step hide\" data-step=\"4\"\u003e\n      \u003cp class=\"hint\"\u003eBijna klaar! Controleer je sticker hierboven en voeg 'm toe aan je winkelmand.\u003c\/p\u003e\n      \u003cdiv class=\"ups\" style=\"border-color:var(--coral);background:#fff7f4\"\u003e\n        \u003cdiv class=\"ic\" style=\"background:#fff;color:var(--coral)\"\u003e\u003csvg width=\"22\" height=\"22\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\u003e\u003cpath d=\"M12 2l8 3v6c0 5-3.5 8-8 11-4.5-3-8-6-8-11V5z\"\u003e\u003c\/path\u003e\u003cpath d=\"M9 12l2 2 4-4\"\u003e\u003c\/path\u003e\u003c\/svg\u003e\u003c\/div\u003e\n        \u003cdiv class=\"gr\"\u003e\n\u003cdiv class=\"h\"\u003eBeschermlaag (laminaat) \u003cspan style=\"color:var(--coral);font-weight:700\"\u003e· inbegrepen\u003c\/span\u003e\n\u003c\/div\u003e\n\u003cdiv class=\"d\"\u003eExtra slijtvast \u0026amp; UV-bestendig · t.w.v. €2,50, gratis\u003c\/div\u003e\n\u003c\/div\u003e\n      \u003c\/div\u003e\n      \u003cdiv class=\"ups\" id=\"rakelUps\" style=\"cursor:pointer\"\u003e\n        \u003cdiv class=\"ic\" id=\"rakelIc\" style=\"overflow:hidden;padding:0\"\u003e\u003csvg width=\"22\" height=\"22\" viewbox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"\u003e\u003crect x=\"3\" y=\"4\" width=\"18\" height=\"6\" rx=\"1\"\u003e\u003c\/rect\u003e\u003cpath d=\"M7 10v6a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2v-6\"\u003e\u003c\/path\u003e\u003c\/svg\u003e\u003c\/div\u003e\n        \u003cdiv class=\"gr\"\u003e\n\u003cdiv class=\"h\"\u003eApplicatie-rakel \u003cspan id=\"rakelPrijs\" style=\"color:#a39e9c;font-weight:600\"\u003e\u003c\/span\u003e\n\u003c\/div\u003e\n\u003cdiv class=\"d\"\u003ePlak je sticker krasvrij en zonder luchtbellen aan\u003c\/div\u003e\n\u003c\/div\u003e\n        \u003cdiv id=\"rakelToggle\" style=\"width:24px;height:24px;border-radius:7px;border:2px solid var(--line);flex-shrink:0;display:flex;align-items:center;justify-content:center;transition:.15s\"\u003e\u003c\/div\u003e\n      \u003c\/div\u003e\n      \u003cdiv style=\"display:flex;justify-content:space-between;align-items:baseline;margin-top:14px\"\u003e\n        \u003cspan id=\"totaalLabel\" style=\"font-size:14px;font-weight:600\"\u003eTotaal (set van 2)\u003c\/span\u003e\n        \u003cspan id=\"prijsLabel\" style=\"font-size:20px;font-weight:800;color:var(--ink)\"\u003e\u003c\/span\u003e\n      \u003c\/div\u003e\n    \u003c\/div\u003e\n  \u003c\/div\u003e\n\n  \u003cdiv class=\"nav\"\u003e\n    \u003cdiv id=\"navPrijs\" class=\"navprijs\"\u003e\u003c\/div\u003e\n    \u003cbutton class=\"btn back hide\" id=\"back\"\u003e← Terug\u003c\/button\u003e\n    \u003cbutton class=\"btn next\" id=\"next\"\u003eVerder →\u003c\/button\u003e\n  \u003c\/div\u003e\n\u003c\/div\u003e\n\n\u003cscript\u003e\n  \/\/ === INSTELLING PER PLAATSING ===\n  \/\/ Zet op een design-productpagina bv.: window.WIZARD_STARTDESIGN = 'cauberg';\n  \/\/ Dan start de wizard direct op dat design en slaat stap 1 (design-keuze) over.\n  \/\/ Laat leeg\/undefined op de algemene pagina, dan kiest de klant zelf in stap 1.\n  let STARTDESIGN = null; \/\/ wordt bij init uitgelezen (zie hieronder)\n\n  const titel={1:'Kies je design',2:'Jouw naam',3:'Vlag \u0026 kleuren',4:'Overzicht'};\n  const flagNaam={nl:'Nederland',be:'België',de:'Duitsland',it:'Italië',none:'Geen'};\n  let step=1;\n  let state={design:'mortirolo',size:'normaal',naam:'JOUW NAAM',font:'Saira Condensed',flag:'nederland',bg:'#1A1A1A',bgNaam:'Zwart',ink:'#FFFFFF',inkNaam:'Wit',pct:100,silo:null};\n\n  \/\/ === VLAGGEN-BIBLIOTHEEK (datagedreven) — voeg een vlag toe met één regel ===\n  \/\/ key: code, naam: label, bron: Shopify-URL van de vlag-SVG (rechthoekig).\n  const VLAGGEN={\n    nederland:{naam:'Nederland', bron:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Nederland_338f450f-f068-43a1-88c1-daef0f77c298.svg?v=1782403629'},\n    france:{naam:'Frankrijk', bron:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/France.svg?v=1782403630'},\n    espana:{naam:'Spanje', bron:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Espana.svg?v=1782403630'},\n    belgie:{naam:'België', bron:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Belgie_338700b9-654f-45f8-968d-0cb5ff930cdc.svg?v=1782403629'},\n    duitsland:{naam:'Duitsland', bron:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Deutschland.svg?v=1782403629'},\n    turkije:{naam:'Turkije', bron:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Turkije.svg?v=1782403629'},\n    pakistan:{naam:'Pakistan', bron:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Pakistan.svg?v=1782403629'},\n    amsterdam:{naam:'Amsterdam', bron:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Amsterdam_0f1ca171-62fc-4df1-b430-4ad62fff1126.svg?v=1782403629'},\n    achterhoek:{naam:'Achterhoek', bron:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Achterhoek_6b9dc349-4d76-4359-a780-771b9992a45d.svg?v=1782403629'},\n    liemers:{naam:'Liemers', bron:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Liemers_82c5f056-a276-42c3-9384-b067360e1f96.svg?v=1782403631'},\n    gelderland:{naam:'Gelderland', bron:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Gelderland_e6b71cce-3a0b-45f0-ad43-2836eaa50f99.svg?v=1782403629'},\n    brabant:{naam:'Brabant', bron:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Brabant_7fddc06e-245f-45e9-a9ae-b650670ea36e.svg?v=1782403629'},\n    limburg:{naam:'Limburg', bron:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Limburg.svg?v=1782403630'},\n    zeeland:{naam:'Zeeland', bron:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Zeeland_df4c4a88-a67f-460e-b3e8-0f8c3e3932d1.svg?v=1782403629'},\n    drenthe:{naam:'Drenthe', bron:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Drenthe_cbbe4d25-e98e-49e4-8633-f03e66c9f9a5.svg?v=1782403629'},\n    groningen:{naam:'Groningen', bron:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Groningen_794258c5-566b-4d70-9f69-acc90a356309.svg?v=1782403629'},\n    westland:{naam:'Westland', bron:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Westland.svg?v=1782403629'},\n    moergestel:{naam:'Moergestel', bron:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Moergestel.svg?v=1782403630'}\n  };\n  const VLAG_VOLGORDE=['nederland','france','espana','belgie','duitsland','turkije','pakistan','amsterdam','achterhoek','liemers','gelderland','brabant','limburg','zeeland','drenthe','groningen','westland','moergestel'];\n  let vlagCache={}; \/\/ opgehaalde vlag-SVG-teksten\n\n  function stappen(){\n    document.querySelectorAll('.step').forEach(s=\u003es.classList.add('hide'));\n    document.querySelector('.step[data-step=\"'+step+'\"]').classList.remove('hide');\n    document.querySelectorAll('.steps .s').forEach(el=\u003e{const n=+el.dataset.s;el.classList.remove('active','done');\n      if(n\u003cstep)el.classList.add('done');else if(n===step)el.classList.add('active');});\n    const vast=designLigtVast();\n    const totaal = vast ? 3 : 4;\n    const toon = vast ? step-1 : step;\n    document.getElementById('sn').textContent='Stap '+toon+' van '+totaal;\n    document.getElementById('st').textContent=titel[step];\n    document.getElementById('back').classList.toggle('hide',step===minStap());\n    const nb=document.getElementById('next');\n    if(step===4){nb.textContent='In winkelmand';nb.className='btn cart';}\n    else{nb.textContent='Verder →';nb.className='btn next';}\n    if(step===4)nb.textContent='In winkelmand';\n    if(step===4)vulMaatUpsell();\n    toonPrijs();   \/\/ prijs is vanaf stap 1 zichtbaar in de navbalk\n    scrollNaarBoven();\n  }\n  \/\/ zorg dat de bovenkant van de wizard in beeld komt bij elke stap\n  function scrollNaarBoven(){\n    try{\n      const app=document.querySelector('.app');\n      if(app\u0026\u0026app.scrollIntoView){app.scrollIntoView({behavior:'smooth',block:'start'});}\n    }catch(e){}\n  }\n  \/\/ Het design ligt vast als er een STARTDESIGN is, OF als de gekozen\n  \/\/ categorie maar één design bevat (dan valt er niets te kiezen in stap 1).\n  function designLigtVast(){\n    if(STARTDESIGN\u0026\u0026DESIGNS[STARTDESIGN])return true;\n    return zichtbareDesigns().length===1;\n  }\n  \/\/ laagste stap (2 als het design vastligt, anders 1)\n  function minStap(){return designLigtVast()?2:1;}\n  \/\/ design vastzetten en de design-keuze (stap 1) overslaan\n  function pasStartDesignToe(){\n    if(!designLigtVast())return;\n    \/\/ welk design? expliciet STARTDESIGN, anders het enige zichtbare design\n    const key=(STARTDESIGN\u0026\u0026DESIGNS[STARTDESIGN])?STARTDESIGN:zichtbareDesigns()[0];\n    if(!key||!DESIGNS[key])return;\n    state.design=key;\n    const d=DESIGNS[key];\n    state.bg=d.bg;state.bgNaam=d.bgNaam;state.ink=d.ink;state.inkNaam=d.inkNaam;state.font=d.font;\n    \/\/ verberg de stap-1 indicator in de voortgangsbalk\n    const ind=document.querySelector('.steps .s[data-s=\"1\"]');if(ind)ind.style.display='none';\n    \/\/ verplaats het formaat-blok naar stap 2 (anders is het niet kiesbaar)\n    const formaat=document.getElementById('formaatBlok');\n    const stap2=document.querySelector('.step[data-step=\"2\"]');\n    if(formaat\u0026\u0026stap2){stap2.appendChild(formaat);}\n    step=2;\n  }\n  function vulMaatUpsell(){\n    \/\/ betaalde maat-upsells zijn (voorlopig) verborgen — niets te doen\n    laadRakelPrijs();   \/\/ rakel-prijs ophalen (eenmalig)\n    vulRakelUpsell();   \/\/ rakel-blok bijwerken\n  }\n  \/\/ toon de rakel-prijs en de aan\/uit-status van de toggle\n  function vulRakelUpsell(){\n    const prijsEl=document.getElementById('rakelPrijs');\n    const toggle=document.getElementById('rakelToggle');\n    const ic=document.getElementById('rakelIc');\n    \/\/ productfoto in het vierkante vlakje (afgeronde hoeken via .ic + overflow)\n    if(ic \u0026\u0026 rakelAfbeelding){\n      ic.innerHTML='\u003cimg src=\"'+rakelAfbeelding+'\" alt=\"Applicatie-rakel\" '\n        +'style=\"width:100%;height:100%;object-fit:cover;display:block;border-radius:11px\"\u003e';\n      ic.style.cursor='zoom-in'; \/\/ tik = groot bekijken\n    }\n    if(prijsEl){\n      const centen=prijsCache[RAKEL.variant];\n      prijsEl.textContent=(centen!=null)\n        ? '· €'+(centen\/100).toLocaleString('nl-NL',{minimumFractionDigits:2,maximumFractionDigits:2})\n        : '';\n    }\n    if(toggle){\n      if(rakelAan){\n        toggle.style.background='var(--coral)';\n        toggle.style.borderColor='var(--coral)';\n        toggle.innerHTML='\u003csvg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fff\" stroke-width=\"3\"\u003e\u003cpath d=\"M5 12l5 5L20 7\"\/\u003e\u003c\/svg\u003e';\n      }else{\n        toggle.style.background='#fff';\n        toggle.style.borderColor='var(--line)';\n        toggle.innerHTML='';\n      }\n    }\n  }\n\n  \/\/ === PRIJZEN UIT SHOPIFY ===\n  \/\/ haalt \/products\/{handle}.js op en cachet de prijs per variant-ID\n  let prijsCache={}; \/\/ variantId -\u003e prijs in centen\n  \/\/ bepaal de product-handle voor de PRIJZEN. Let op: het design bepaalt welk\n  \/\/ product er werkelijk besteld wordt (zie huidigeVariant), dus die handle heeft\n  \/\/ voorrang. Een landingspagina kan namelijk een ander product zijn dan het\n  \/\/ product dat de wizard in de winkelmand legt — bv. de kenteken-varianten, die\n  \/\/ allemaal naar hetzelfde onderliggende kentekenproduct wijzen. Zonder deze\n  \/\/ voorrang haalt de wizard de prijzen van de landingspagina op, staan de echte\n  \/\/ variant-ID's niet in de cache en blijft de prijs leeg.\n  function huidigeHandle(){\n    const d=DESIGNS[state.design];\n    if(d\u0026\u0026d.handle)return d.handle;\n    \/\/ geen eigen handle in het design: terugvallen op de handle uit de URL\n    try{\n      const m=(window.location.pathname||'').match(\/\\\/products\\\/([^\\\/?#]+)\/);\n      if(m\u0026\u0026m[1])return decodeURIComponent(m[1]);\n    }catch(e){}\n    return '';\n  }\n  function laadPrijzen(){\n    const handle=huidigeHandle();\n    if(!handle){toonPrijs();return Promise.resolve();}\n    return fetch('\/products\/'+handle+'.js')\n      .then(r=\u003er.ok?r.json():null)\n      .then(p=\u003e{\n        if(p\u0026\u0026p.variants){p.variants.forEach(v=\u003e{prijsCache[v.id]=v.price;});}\n        toonPrijs();\n      }).catch(e=\u003e{console.warn('Prijzen laden:',e);toonPrijs();});\n  }\n  \/\/ haal de rakel-prijs op (eenmalig) zodat we 'm in stap 4 kunnen tonen\n  let rakelPrijsGeladen=false;\n  let rakelAfbeelding=''; \/\/ featured_image van het rakel-product (klein, icoon)\n  let rakelAfbeeldingGroot=''; \/\/ volledige resolutie (voor de zoom-weergave)\n  function laadRakelPrijs(){\n    if(rakelPrijsGeladen||!RAKEL.handle)return Promise.resolve();\n    rakelPrijsGeladen=true;\n    return fetch('\/products\/'+RAKEL.handle+'.js')\n      .then(r=\u003er.ok?r.json():null)\n      .then(p=\u003e{\n        if(p\u0026\u0026p.variants){p.variants.forEach(v=\u003e{prijsCache[v.id]=v.price;});}\n        \/\/ productfoto pakken (featured_image of eerste image); compacte variant\n        \/\/ via Shopify image-resize parameter voor een snelle, scherpe thumbnail.\n        let img=p\u0026\u0026(p.featured_image||(p.images\u0026\u0026p.images[0]))||'';\n        if(img){\n          if(img.indexOf('\/\/')===0)img='https:'+img;          \/\/ protocol-relatieve URL\n          rakelAfbeeldingGroot=img;                            \/\/ volledige resolutie (voor zoom)\n          rakelAfbeelding=img.replace(\/(\\.[a-zA-Z]+)(\\?.*)?$\/,'_120x120$1'); \/\/ kleine thumbnail (icoon)\n        }\n        vulRakelUpsell();\n      }).catch(e=\u003e{console.warn('Rakel-prijs:',e);});\n  }\n  \/\/ toon de prijs van de huidige variant in stap 4 en op de knop\n  function toonPrijs(){\n    \/\/ label aanpassen aan het aantal stickers (set van 2, of enkel)\n    const lbl=document.getElementById('totaalLabel');\n    if(lbl)lbl.textContent=(aantalStickers()===1)?'Totaal':'Totaal (set van 2)';\n    const vid=huidigeVariant();\n    let centen=prijsCache[vid];\n    const el=document.getElementById('prijsLabel');\n    const nav=document.getElementById('navPrijs');\n    if(centen!=null){\n      \/\/ rakel meetellen in het totaal als die is aangevinkt\n      let totaal=centen;\n      if(rakelAan \u0026\u0026 prijsCache[RAKEL.variant]!=null)totaal+=prijsCache[RAKEL.variant];\n      const euro=(totaal\/100).toLocaleString('nl-NL',{minimumFractionDigits:2,maximumFractionDigits:2});\n      if(el)el.textContent='€'+euro;\n      \/\/ prijs vanaf stap 1 in de navbalk (in stap 4 staat 'ie al op de knop zelf)\n      if(nav){\n        if(step===4){nav.textContent='';}\n        else{\n          const sub=(aantalStickers()===1)?'per stuk':'set van 2';\n          nav.innerHTML='€'+euro+'\u003csmall\u003e'+sub+'\u003c\/small\u003e';\n        }\n      }\n      \/\/ prijs ook op de winkelmand-knop in stap 4\n      const nb=document.getElementById('next');\n      if(nb \u0026\u0026 step===4)nb.textContent='In winkelmand · €'+euro;\n    }else{\n      if(el)el.textContent='';\n      if(nav)nav.textContent='';\n    }\n  }\n\n  \/\/ === DESIGNS (datagedreven) — voeg een design toe met één regel ===\n  \/\/ Elk design: naam, omschrijving, Shopify-URL van het CorelDraw-SVG,\n  \/\/ standaard kleuren\/font, en de design-grenzen voor de zoom.\n  \/\/\n  \/\/ CATEGORIE: bepaalt welke designs bij elkaar horen en samen getoond worden.\n  \/\/ Het gaat om het SOORT sticker, niet om waar hij op geplakt wordt — een\n  \/\/ naamsticker past immers op fiets, padelracket, step, hockeystick, enz.\n  \/\/  - 'naam'     : naam + vlag stickers (Cauberg, Mortirolo, ...)\n  \/\/  - 'kenteken' : kentekenplaathouder-stickers (eigen logica en maat)\n  \/\/ Zet per plaatsing window.WIZARD_CATEGORIE='kenteken' om alleen die\n  \/\/ categorie te tonen. Niets instellen = alle designs tonen (zoals voorheen).\n  const DESIGNS={\n    mortirolo:{\n      naam:'Mortirolo', omschrijving:'schuin · condensed', categorie:'naam',\n      bron:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Mortirolo_V7.svg?v=1784749358',\n      handle:'naam-vlag-sticker-mortirolo-fiets-set-van-2', \/\/ alg. pagina; op de productpagina wordt de handle uit de URL gelezen\n      bg:'#1A1A1A', bgNaam:'Zwart', ink:'#FFFFFF', inkNaam:'Wit', font:'Montserrat',\n      fontWeight:'600', fontVast:false,\n      maten:{klein:{w:28,h:7},normaal:{w:36,h:9},groot:{w:48,h:12}},\n      varianten:{klein:54242069610823,normaal:54242070069575,groot:54242070528327}\n    },\n    cauberg:{\n      naam:'Cauberg', omschrijving:'strak · vast lettertype', categorie:'naam',\n      bron:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Cauberg_v17.svg?v=1784750118',\n      handle:'naam-vlag-sticker-cauberg-fiets', \/\/ alg. pagina; op de productpagina wordt de handle uit de URL gelezen\n      bg:'#1A1A1A', bgNaam:'Zwart', ink:'#FFFFFF', inkNaam:'Wit', font:'Saira Condensed',\n      fontWeight:'600', fontVast:true,\n      maten:{klein:{w:40,h:7},normaal:{w:50,h:9},groot:{w:70,h:12}},\n      varianten:{klein:52254376591687,normaal:52254377050439,groot:52254377509191}\n    },\n    fiets:{\n      naam:'Fiets sticker R', omschrijving:'', categorie:'naam',\n      bron:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Fiets_sticker_v3.svg?v=1784794498',\n      handle:'', \/\/ TODO: Shopify product-handle invullen\n      bg:'#1A1A1A', bgNaam:'Zwart', ink:'#FFFFFF', inkNaam:'Wit', font:'Bebas Neue',\n      fontWeight:'normal', fontVast:true,\n      maten:{klein:{w:40,h:6},normaal:{w:60,h:9},groot:{w:80,h:12}},\n      varianten:{klein:null,normaal:null,groot:null} \/\/ TODO: variant-ID's\n    },\n    fietslinks:{\n      naam:'Fiets sticker L', omschrijving:'', categorie:'naam',\n      bron:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Fiets_sticker_vlag_links_v3.svg?v=1784798006',\n      handle:'fietssticker-naam-vlag-links',\n      bg:'#1A1A1A', bgNaam:'Zwart', ink:'#FFFFFF', inkNaam:'Wit', font:'Bebas Neue',\n      fontWeight:'normal', fontVast:true,\n      maten:{klein:{w:40,h:6},normaal:{w:60,h:9},groot:{w:80,h:12}},\n      varianten:{klein:54417957519687,normaal:54417958273351,groot:54417959059783}\n    },\n    kenteken:{\n      naam:'Kentekensticker', omschrijving:'Kies tekst, kleur en lettertype', categorie:'kenteken',\n      bron:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Kentekensticker_V3-07-26.svg?v=1784635754',\n      handle:'kentekensticker-kies-tekst-kleur-en-lettertype', \/\/ alg. pagina; op de productpagina wordt de handle uit de URL gelezen\n      bg:'#1A1A1A', bgNaam:'Zwart', ink:'#FFFFFF', inkNaam:'Wit', font:'Bebas Neue',\n      fontWeight:'normal', fontVast:false,\n      \/\/ expliciet midden: automatische detectie leest de tekst-x en die zit hier\n      \/\/ net op het randje (0.23 vs grens 0.25). Hard zetten = betrouwbaar.\n      uitlijning:'midden',\n      \/\/ kenteken heeft EEN vast formaat (500 x 16 mm, de snijmaat)\n      enkelFormaat:true,\n      \/\/ dit product is EEN sticker (niet de standaard set van 2): telt door in\n      \/\/ de preview, de labels en het productiebestand\n      aantal:1,\n      \/\/ standaard geen vlag (de vlagkeuze blijft wel zichtbaar)\n      standaardVlag:'none',\n      \/\/ geen krappe tekenlimiet: de tekst schaalt zich vanzelf naar het kader\n      maxTekens:60,\n      \/\/ strakkere preview-marge: de smalle strip mag zo breed mogelijk in beeld\n      marge:0.04,\n      maten:{normaal:{w:500,h:16}},\n      \/\/ prijs draait op 3 varianten i.p.v. één per formaat. De wizard kiest op\n      \/\/ basis van kleur- en vlagkeuze (zie huidigeVariant): basis \/ +kleur-of-vlag\n      \/\/ \/ +kleur-en-vlag. De feitelijke keuzes komen in de order-properties.\n      prijsVarianten:{\n        basis:54403666346311,   \/\/ zwart\/wit, geen vlag\n        plus1:54403287974215,   \/\/ afwijkende kleur OF vlaggen\n        plus2:54403288006983    \/\/ afwijkende kleur EN vlaggen\n      },\n      \/\/ wat telt als \"basis-kleur\" (geen toeslag): zwarte achtergrond, witte tekst\n      basisBg:'#1A1A1A', basisInk:'#FFFFFF',\n      varianten:{normaal:null}\n    }\n  };\n  const DESIGN_VOLGORDE=['mortirolo','cauberg','fiets','fietslinks','kenteken'];\n\n  \/\/ actieve categorie (uit window.WIZARD_CATEGORIE); leeg = alles tonen\n  let CATEGORIE=null;\n  \/\/ hoeveel stickers levert dit design? standaard een set van 2, kenteken = 1\n  function aantalStickers(){\n    const d=DESIGNS[state.design];\n    return (d\u0026\u0026d.aantal)?d.aantal:2;\n  }\n  \/\/ de designs die in deze plaatsing gekozen mogen worden\n  function zichtbareDesigns(){\n    return DESIGN_VOLGORDE.filter(key=\u003e{\n      const d=DESIGNS[key];\n      if(!d)return false;\n      if(!CATEGORIE)return true;             \/\/ geen filter: alles tonen\n      return d.categorie===CATEGORIE;\n    });\n  }\n\n  \/\/ Marge rond de snijlijn in de previews, als fractie van de boxgrootte.\n  \/\/ Dit is puur \"lucht\" rondom zodat de hele snijlijn (incl. ronde hoeken en\n  \/\/ de vlag-uitsparing) ruim in beeld staat. De previews clippen NIET\n  \/\/ rechthoekig (geen overflow:hidden op het svg), dus de vorm wordt nooit\n  \/\/ recht afgekapt. De achtergrond-bleed is dezelfde kleur als de sticker en\n  \/\/ valt visueel weg. Verhoog\/verlaag voor meer of minder ruimte.\n  const PREVIEW_MARGE=0.08;\n  \/\/ Verticale plaatsing van de naam: afstand van de baseline tot het midden van\n  \/\/ KADER_NAAM, als factor van de fontgrootte. Wordt per design automatisch uit\n  \/\/ het template afgeleid (zie leesBaselineFactor); deze waarde is de terugval.\n  const BASELINE_FACTOR=0.35;\n\n  \/\/ marge voor het huidige design (designs kunnen een eigen marge zetten;\n  \/\/ bij extreme verhoudingen zoals de kentekenstrip is minder lucht beter)\n  function huidigeMarge(){\n    const d=DESIGNS[state.design];\n    return (d\u0026\u0026typeof d.marge==='number')?d.marge:PREVIEW_MARGE;\n  }\n\n  \/\/ === LETTERTYPES (datagedreven) — TTF-bestanden voor opentype.js ===\n  \/\/ naam moet matchen met design.font. ttf = Shopify-URL van het TTF-bestand.\n  const FONTS={\n    'Saira Condensed':{ttf:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/saira-condensed-latin-600-normal.ttf?v=1782559411'},\n    'Montserrat':{ttf:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Montserrat-SemiBold.ttf?v=1782477434'},\n    'Bebas Neue':{ttf:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/BebasNeue-Regular.ttf?v=1784293544'},\n    'Anton':{ttf:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/anton-latin-400-normal.ttf?v=1784710780'},\n    'Dancing Script':{ttf:'https:\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/dancing-script-latin-700-normal.ttf?v=1784710801'}\n  };\n  let fontCache={}; \/\/ geladen opentype-fonts per naam\n\n  \/\/ de keuzeknoppen (Saira\/Bebas\/Anton\/...) tonen in hun eigen lettertype,\n  \/\/ zodat direct zichtbaar is wat je kiest. Zelfde TTF-bronnen als hierboven,\n  \/\/ nu ook als CSS @font-face zodat de browser de knoptekst ermee rendert.\n  function laadFontKnopPreviews(){\n    let css='';\n    Object.keys(FONTS).forEach(naam=\u003e{\n      css+=\"@font-face{font-family:'knop-\"+naam+\"';src:url('\"+FONTS[naam].ttf+\"') format('truetype');font-display:swap;}\\n\";\n    });\n    const st=document.createElement('style');\n    st.textContent=css;\n    document.head.appendChild(st);\n    document.querySelectorAll('.opt[data-font]').forEach(el=\u003e{\n      el.style.fontFamily=\"'knop-\"+el.dataset.font+\"', sans-serif\";\n    });\n  }\n\n  \/\/ hulp: huidige design-bron en -box\n  function bouwDesignKaartjes(){\n    const grid=document.getElementById('designs');\n    grid.innerHTML='';\n    zichtbareDesigns().forEach(key=\u003e{\n      const d=DESIGNS[key];\n      const card=document.createElement('div');\n      card.className='card'+(key===state.design?' sel':'')+(d.categorie==='kenteken'?' breed':'');\n      card.dataset.design=key;\n      card.innerHTML='\u003cdiv class=\"mini\" id=\"mini_'+key+'\"\u003e\u003c\/div\u003e\u003cdiv class=\"nm2\"\u003e'+d.naam+'\u003c\/div\u003e';\n      grid.appendChild(card);\n      const url=d.bron;\n      fetch(url).then(r=\u003er.text()).then(txt=\u003e{\n        txt=slaTransformPlat(txt);\n        const svg=new DOMParser().parseFromString(txt,'image\/svg+xml').documentElement;\n        const host=document.getElementById('mini_'+key);\n        if(!host)return;\n        host.innerHTML='';host.appendChild(svg);\n        \/\/ snijlijn onzichtbaar in de mini (net als de grote preview); de\n        \/\/ magenta haarlijn hoort alleen in het printbestand.\n        svg.querySelectorAll('#SNIJLIJN_KISS,[id^=\"SNIJLIJN_KISS\"]').forEach(el=\u003e{\n          el.setAttribute('fill','none');el.setAttribute('stroke','none');\n        });\n        let box=(d.boxVast)?d.boxVast:boxUitTekst(txt);\n        if(!box)box=berekenBox(svg);\n        if(box \u0026\u0026 (box.maxX-box.minX)\u003e0){\n          const bw=box.maxX-box.minX, bh=box.maxY-box.minY, mg=(typeof d.marge==='number')?d.marge:PREVIEW_MARGE, mx=bw*mg, my=bh*mg;\n          svg.setAttribute('viewBox',(box.minX-mx)+' '+(box.minY-my)+' '+(bw+2*mx)+' '+(bh+2*my));\n          svg.removeAttribute('width');svg.removeAttribute('height');\n          svg.setAttribute('preserveAspectRatio','xMidYMid meet');\n        }\n        svg.querySelectorAll('[id^=\"KLEUR_ACHTERGROND\"]').forEach(el=\u003e{el.setAttribute('fill',d.bg);el.setAttribute('stroke',d.bg);});\n        \/\/ welke vlag toont de mini? standaardVlag van het design (kenteken='none'),\n        \/\/ anders de eerste uit de volgorde (Nederland). Bepaalt ook het kader.\n        const miniVlag=(typeof d.standaardVlag!=='undefined')?d.standaardVlag:VLAG_VOLGORDE[0];\n        const metVlag=(miniVlag \u0026\u0026 miniVlag!=='none');\n        \/\/ tekst: zelfde kader-keuze en uitlijning als de grote preview\n        const t=svg.querySelector('#TEKST_NAAM');\n        if(t){\n          t.textContent='JOUW NAAM';t.setAttribute('fill',d.ink);t.setAttribute('font-family',d.font);\n          const kader=(metVlag\u0026\u0026svg.querySelector('#KADER_NAAM_VLAG'))?svg.querySelector('#KADER_NAAM_VLAG'):svg.querySelector('#KADER_NAAM');\n          if(kader){\n            const kx=+kader.getAttribute('x'),ky=+kader.getAttribute('y'),kw=+kader.getAttribute('width'),kh=+kader.getAttribute('height');\n            let size=kh*1.1;t.setAttribute('font-size',size);let g=0;\n            try{while(t.getComputedTextLength()\u003ekw\u0026\u0026size\u003ekh*0.15\u0026\u0026g\u003c400){size*=0.98;t.setAttribute('font-size',size);g++;}}catch(e){}\n            const uit=(d.uitlijning)||'midden';\n            if(uit==='links'){t.setAttribute('text-anchor','start');t.setAttribute('x',kx);}\n            else if(uit==='rechts'){t.setAttribute('text-anchor','end');t.setAttribute('x',kx+kw);}\n            else{t.setAttribute('text-anchor','middle');t.setAttribute('x',kx+kw\/2);}\n            t.removeAttribute('dominant-baseline');\n            const km=ky+kh\/2;\n            \/\/ zelfde verhouding als de grote preview: uit het template afgeleid\n            \/\/ zelfde plaatsing als de grote preview: kapitaalhoogte van het font\n            const fm=fontCache[d.font];\n            let by=null;\n            if(fm\u0026\u0026fm.unitsPerEm){\n              const cap=(typeof fm.capHeight==='number'\u0026\u0026fm.capHeight\u003e0)?fm.capHeight:(fm.ascent||0);\n              if(cap\u003e0)by=km+((cap\/fm.unitsPerEm)*size)\/2;\n            }\n            if(by===null){\n              const fMini=(typeof d.baselineFactor==='number')?d.baselineFactor:BASELINE_FACTOR;\n              by=km+size*fMini;\n            }\n            t.setAttribute('y',by);\n          }\n        }\n        \/\/ vlag alleen plaatsen als het design er standaard een heeft\n        const slots=Array.from(svg.querySelectorAll('#VLAG_SLOT,[id^=\"VLAG_SLOT\"]'));\n        if(metVlag\u0026\u0026slots.length){\n          const vlagBron=(VLAGGEN[miniVlag]||VLAGGEN[VLAG_VOLGORDE[0]]).bron;\n          const zetVlag=(vtxt)=\u003e{slots.forEach((s,i)=\u003eplaatsVlag(svg,s,vtxt,i));klipOpSnijlijn(svg);};\n          if(vlagCache[vlagBron])zetVlag(vlagCache[vlagBron]);\n          else fetch(vlagBron).then(r=\u003er.text()).then(vtxt=\u003e{vlagCache[vlagBron]=vtxt;zetVlag(vtxt);}).catch(()=\u003e{klipOpSnijlijn(svg);});\n        }else{\n          \/\/ geen vlag: slots onzichtbaar maken en meteen clippen\n          slots.forEach(s=\u003e{s.setAttribute('fill','none');s.setAttribute('stroke','none');});\n          klipOpSnijlijn(svg);\n        }\n      }).catch(e=\u003econsole.warn('Mini-preview:',e));\n    });\n  }\n\n  function huidigeBron(){return (DESIGNS[state.design]||DESIGNS.mortirolo).bron;}\n  function huidigeBox(){return (DESIGNS[state.design]||DESIGNS.mortirolo).box;}\n  let sjabloonCache={};\n\n  \/\/ CorelDRAW wikkelt tekst-objecten bij SVG-export soms in een\n  \/\/ \u003cg transform=\"matrix(1 0 0 1 e f)\"\u003e (ook na Ungroup). De rauwe x\/y in de\n  \/\/ tekst kloppen dan niet met de visuele plek. Deze helper bakt de translate\n  \/\/ (e,f) in de kind-coordinaten en haalt de groep-wrapper weg, zodat de hele\n  \/\/ wizard daarna een schone SVG ziet (net als designs zonder zo'n wrapper).\n  \/\/ Alleen PURE translate (a=d=1,b=c=0) wordt platgeslagen; andere matrices\n  \/\/ blijven staan (zeldzaam; getBBox in de browser handelt die alsnog af).\n  function slaTransformPlat(txt){\n    const gRe=\/\u003cg\\b[^\u003e]*\\btransform=\"matrix\\(\\s*(-?[\\d.]+)\\s+(-?[\\d.]+)\\s+(-?[\\d.]+)\\s+(-?[\\d.]+)\\s+(-?[\\d.]+)\\s+(-?[\\d.]+)\\s*\\)\"[^\u003e]*\u003e([\\s\\S]*?)\u003c\\\/g\u003e\/g;\n    return txt.replace(gRe,function(heel,a,b,c,d,e,f,inhoud){\n      a=+a;b=+b;c=+c;d=+d;e=+e;f=+f;\n      if(a!==1||b!==0||c!==0||d!==1)return heel; \/\/ geen pure translate: laat staan\n      return inhoud\n        .replace(\/(^|[^-\\w])x=\"(-?[\\d.]+)\"\/g,(m,p,v)=\u003ep+'x=\"'+(parseFloat(v)+e)+'\"')\n        .replace(\/(^|[^-\\w])y=\"(-?[\\d.]+)\"\/g,(m,p,v)=\u003ep+'y=\"'+(parseFloat(v)+f)+'\"');\n    });\n  }\n\n  function laadDesign(){\n    const bron=huidigeBron();\n    if(sjabloonCache[bron]){plaatsDesign(sjabloonCache[bron]);return;}\n    fetch(bron).then(r=\u003er.text()).then(txt=\u003e{txt=slaTransformPlat(txt);sjabloonCache[bron]=txt;plaatsDesign(txt);})\n      .catch(e=\u003econsole.warn('Design laden:',e));\n  }\n  \/\/ lees de design-box DIRECT uit de SVG-tekst (werkt ook als de container\n  \/\/ nog niet zichtbaar is — geen getBBox nodig). Zoekt SNIJLIJN_KISS eerst,\n  \/\/ anders KLEUR_ACHTERGROND\/KADER_NAAM.\n  function boxUitTekst(txt){\n    function elementTekst(id){\n      const re=new RegExp('\u003c([a-zA-Z]+)[^\u003e]*\\\\bid=\"'+id+'\"[^\u003e]*\u003e','i');\n      const m=txt.match(re);return m?{tag:m[1],full:m[0]}:null;\n    }\n    function attr(full,naam){\n      \/\/ (^|niet-koppelteken) ervoor, zodat 'width' niet matcht binnen 'stroke-width'\n      const m=full.match(new RegExp('(?:^|[^-a-zA-Z])'+naam+'=\"([^\"]*)\"'));return m?m[1]:null;\n    }\n    function boxVanElement(id){\n      const el=elementTekst(id);if(!el)return null;\n      const x=parseFloat(attr(el.full,'x')), y=parseFloat(attr(el.full,'y'));\n      const w=parseFloat(attr(el.full,'width')), h=parseFloat(attr(el.full,'height'));\n      if(!isNaN(x)\u0026\u0026!isNaN(y)\u0026\u0026!isNaN(w)\u0026\u0026!isNaN(h)){\n        return {minX:x,minY:y,maxX:x+w,maxY:y+h};\n      }\n      if(el.tag==='path'){\n        const m=txt.match(new RegExp('\u003cpath[^\u003e]*\\\\bid=\"'+id+'\"[^\u003e]*\\\\bd=\"([^\"]*)\"','i'))||txt.match(new RegExp('\u003cpath[^\u003e]*\\\\bd=\"([^\"]*)\"[^\u003e]*\\\\bid=\"'+id+'\"','i'));\n        if(m){\n          \/\/ volg de path-commando's zodat RELATIEVE coordinaten (l,c,h,v,...)\n          \/\/ correct meelopen. Alleen ANKER-\/eindpunten tellen mee, niet de\n          \/\/ bezier-controlepunten — zo ligt de box precies op de snijlijn\n          \/\/ (de ronde hoeken zwiepen anders net buiten de snijmaat = bleed).\n          const toks=m[1].match(\/[a-zA-Z]|-?\\d*\\.?\\d+(?:e-?\\d+)?\/gi);\n          if(toks){\n            let i=0,cx=0,cy=0,sx=0,sy=0,cmd='';\n            let minX=Infinity,minY=Infinity,maxX=-Infinity,maxY=-Infinity,had=false;\n            const punt=(x,y)=\u003e{minX=Math.min(minX,x);minY=Math.min(minY,y);maxX=Math.max(maxX,x);maxY=Math.max(maxY,y);had=true;};\n            const num=()=\u003eparseFloat(toks[i++]);\n            const isL=t=\u003e\/^[a-zA-Z]$\/.test(t);\n            while(i\u003ctoks.length){\n              if(isL(toks[i]))cmd=toks[i++];\n              const rel=(cmd===cmd.toLowerCase()), C=cmd.toUpperCase();\n              if(C==='M'||C==='L'||C==='T'){let x=num(),y=num();if(rel){x+=cx;y+=cy;}cx=x;cy=y;if(C==='M'){sx=cx;sy=cy;cmd=rel?'l':'L';}punt(cx,cy);}\n              else if(C==='H'){let x=num();if(rel)x+=cx;cx=x;punt(cx,cy);}\n              else if(C==='V'){let y=num();if(rel)y+=cy;cy=y;punt(cx,cy);}\n              else if(C==='C'){num();num();num();num();let x=num(),y=num();if(rel){x+=cx;y+=cy;}cx=x;cy=y;punt(cx,cy);}\n              else if(C==='S'||C==='Q'){num();num();let x=num(),y=num();if(rel){x+=cx;y+=cy;}cx=x;cy=y;punt(cx,cy);}\n              else if(C==='A'){num();num();num();num();num();let x=num(),y=num();if(rel){x+=cx;y+=cy;}cx=x;cy=y;punt(cx,cy);}\n              else if(C==='Z'){cx=sx;cy=sy;}\n              else i++;\n            }\n            if(had)return {minX,minY,maxX,maxY};\n          }\n        }\n      }\n      return null;\n    }\n    return boxVanElement('SNIJLIJN_KISS')||boxVanElement('KLEUR_ACHTERGROND')||boxVanElement('KADER_NAAM');\n  }\n\n  \/\/ Leidt uit de SVG-bron af waar CorelDRAW de baseline zet t.o.v. het midden\n  \/\/ van KADER_NAAM, als factor van de fontgrootte. Zo bepaalt het template de\n  \/\/ verticale plaatsing en hoeft niemand handmatig een getal te kiezen.\n  function leesBaselineFactor(txt){\n    try{\n      const tTag=(txt.match(\/\u003ctext[^\u003e]*\\bid=\"TEKST_NAAM\"[^\u003e]*\u003e\/)||[])[0];\n      const kTag=(txt.match(\/\u003crect[^\u003e]*\\bid=\"KADER_NAAM\"[^\u003e]*\u003e\/)||[])[0];\n      if(!tTag||!kTag)return null;\n      const num=(tag,attr)=\u003e{\n        const m=tag.match(new RegExp('(?:^|[^-a-zA-Z])'+attr+'=\"([\\\\d.\\\\-]+)'));\n        return m?parseFloat(m[1]):null;\n      };\n      const ty=num(tTag,'y'), fs=num(tTag,'font-size');\n      const ky=num(kTag,'y'), kh=num(kTag,'height');\n      if(ty===null||!fs||ky===null||!kh)return null;\n      const factor=(ty-(ky+kh\/2))\/fs;\n      \/\/ sanity: buiten dit bereik is er iets raars aan de hand\n      if(factor\u003c-1||factor\u003e1)return null;\n      return factor;\n    }catch(e){return null;}\n  }\n\n  function plaatsDesign(txt){\n    \/\/ baseline-verhouding uit het template halen (eenmalig per design)\n    if(DESIGNS[state.design] \u0026\u0026 typeof DESIGNS[state.design].baselineFactor!=='number'){\n      const f=leesBaselineFactor(txt);\n      if(f!==null)DESIGNS[state.design].baselineFactor=f;\n    }\n    \/\/ detecteer en bewaar de tekst-uitlijning uit de SVG (eenmalig per design)\n    if(DESIGNS[state.design] \u0026\u0026 !DESIGNS[state.design].uitlijning){\n      DESIGNS[state.design].uitlijning=uitlijningUitTekst(txt);\n    }\n    \/\/ box: gebruik een VAST gedefinieerde box als die er is, anders ALTIJD\n    \/\/ opnieuw uit de tekst lezen (niet cachen — voorkomt vastzittende foutwaarden)\n    const vast=(DESIGNS[state.design]\u0026\u0026DESIGNS[state.design].boxVast)?DESIGNS[state.design].boxVast:null;\n    let box=vast||boxUitTekst(txt);\n    \/\/ aantal stickers in de preview: set van 2, of enkel (kenteken)\n    const enkel=(aantalStickers()===1);\n    const tweede=document.getElementById('dsgn2');\n    if(tweede)tweede.style.display=enkel?'none':'';\n    const hosts=enkel?['dsgn1']:['dsgn1','dsgn2'];\n    hosts.forEach(id=\u003e{\n      const host=document.getElementById(id);\n      if(!host)return;\n      const doc=new DOMParser().parseFromString(txt,'image\/svg+xml');\n      const svg=doc.documentElement;\n      const eigenVB=svg.getAttribute('viewBox');\n      host.innerHTML='';host.appendChild(svg);\n      if(box \u0026\u0026 (box.maxX-box.minX)\u003e0 \u0026\u0026 (box.maxY-box.minY)\u003e0){\n        const bw=box.maxX-box.minX, bh=box.maxY-box.minY;\n        const marge=huidigeMarge();\n        const mx=bw*marge, my=bh*marge; \/\/ marge per as = proportioneel\n        svg.setAttribute('viewBox',(box.minX-mx)+' '+(box.minY-my)+' '+(bw+2*mx)+' '+(bh+2*my));\n      }else if(eigenVB){\n        svg.setAttribute('viewBox',eigenVB);\n      }\n      svg.removeAttribute('width');svg.removeAttribute('height');\n      svg.setAttribute('preserveAspectRatio','xMidYMid meet');\n    });\n    \/\/ label boven de preview\n    const ptag=document.querySelector('.ptag');\n    if(ptag)ptag.textContent=enkel?'Voorbeeld':'Voorbeeld — set van 2';\n    render();\n  }\n\n  \/\/ bereken de design-grenzen uit de benoemde elementen\n  function berekenBox(svg){\n    \/\/ de preview zoomt bij voorkeur op de SNIJLIJN (de snijmaat = wat de klant\n    \/\/ krijgt). De bleed-achtergrond valt dan netjes buiten beeld.\n    const snij=svg.querySelector('#SNIJLIJN_KISS')||svg.querySelector('[id^=\"SNIJLIJN_KISS\"]');\n    if(snij){\n      try{const bb=snij.getBBox();\n        if(bb.width\u003e0\u0026\u0026bb.height\u003e0)return {minX:bb.x,minY:bb.y,maxX:bb.x+bb.width,maxY:bb.y+bb.height};\n      }catch(e){}\n    }\n    \/\/ geen snijlijn: val terug op de zichtbare design-elementen\n    const ids=['KLEUR_ACHTERGROND','KLEUR_ACHTERGROND_2','KLEUR_ACHTERGROND_3','VLAG_SLOT','TEKST_NAAM','KADER_NAAM'];\n    let minX=Infinity,minY=Infinity,maxX=-Infinity,maxY=-Infinity,gevonden=false;\n    ids.forEach(id=\u003e{\n      const el=svg.querySelector('#'+id);if(!el)return;\n      try{const bb=el.getBBox();\n        minX=Math.min(minX,bb.x);minY=Math.min(minY,bb.y);\n        maxX=Math.max(maxX,bb.x+bb.width);maxY=Math.max(maxY,bb.y+bb.height);\n        gevonden=true;\n      }catch(e){}\n    });\n    if(!gevonden)return null;\n    return {minX,minY,maxX,maxY};\n  }\n\n  \/\/ Knip de preview bij langs de EXACTE snijlijn-vorm (incl. ronde hoeken).\n  \/\/ Zonder dit toont de preview de bleed-achtergrond: die is groter dan de\n  \/\/ snijlijn en heeft rechte hoeken, terwijl de echte sticker de snijvorm\n  \/\/ heeft. Met deze clip geldt: preview = sticker.\n  \/\/ Alleen de PREVIEW wordt geklipt; het printbestand houdt de volle bleed\n  \/\/ (bouwProductieSVG pakt de wrapper weer uit).\n  \/\/ Aanpak: alle inhoud in EEN wrapper-groep met de clip. Zo behouden kinderen\n  \/\/ (zoals de vlag met zijn eigen slot-clip) hun eigen clip-path.\n  function klipOpSnijlijn(svg){\n    const snij=svg.querySelector('#SNIJLIJN_KISS')||svg.querySelector('[id^=\"SNIJLIJN_KISS\"]');\n    if(!snij)return;\n    const ns='http:\/\/www.w3.org\/2000\/svg';\n    let defs=svg.querySelector('defs');\n    if(!defs){defs=document.createElementNS(ns,'defs');svg.insertBefore(defs,svg.firstChild);}\n    let clipId=svg.getAttribute('data-snijclip');\n    if(!clipId){\n      clipId='snijclip_'+Math.random().toString(36).slice(2,8);\n      const cp=document.createElementNS(ns,'clipPath');\n      cp.setAttribute('id',clipId);\n      cp.setAttribute('clipPathUnits','userSpaceOnUse');\n      const vorm=snij.cloneNode(true);\n      vorm.removeAttribute('id');\n      vorm.setAttribute('fill','#000');\n      vorm.removeAttribute('stroke');vorm.removeAttribute('stroke-width');\n      cp.appendChild(vorm);\n      defs.appendChild(cp);\n      svg.setAttribute('data-snijclip',clipId);\n    }\n    let wrap=svg.querySelector('#SNIJ_CLIP_WRAP');\n    if(!wrap){\n      wrap=document.createElementNS(ns,'g');\n      wrap.setAttribute('id','SNIJ_CLIP_WRAP');\n      wrap.setAttribute('clip-path','url(#'+clipId+')');\n      svg.appendChild(wrap);\n    }\n    \/\/ verplaats alle losse inhoud de wrapper in (idempotent: al verplaatste\n    \/\/ elementen zitten er al in en worden overgeslagen)\n    Array.from(svg.children).forEach(el=\u003e{\n      if(el===wrap||el===defs)return;\n      if(el.tagName==='defs'||el.tagName==='clipPath')return;\n      const id=el.getAttribute('id')||'';\n      if(id.indexOf('SNIJLIJN_KISS')===0)return; \/\/ snijlijn zelf buiten de clip\n      wrap.appendChild(el); \/\/ appendChild verplaatst het element\n    });\n  }\n\n  function vulSlots(svg){\n    \/\/ snijlijn onzichtbaar in de preview (komt alleen in het printbestand)\n    svg.querySelectorAll('#SNIJLIJN_KISS,[id^=\"SNIJLIJN_KISS\"]').forEach(el=\u003e{\n      el.setAttribute('fill','none');el.setAttribute('stroke','none');\n    });\n    \/\/ achtergrondkleur: alle KLEUR_ACHTERGROND* meekleuren\n    svg.querySelectorAll('[id^=\"KLEUR_ACHTERGROND\"]').forEach(el=\u003e{\n      el.setAttribute('fill',state.bg);el.setAttribute('stroke',state.bg);\n    });\n    \/\/ tekst\n    const t=svg.querySelector('#TEKST_NAAM');\n    if(t){\n      \/\/ Meerdere spaties zichtbaar houden. SVG vouwt opeenvolgende gewone\n      \/\/ spaties samen tot één, terwijl fontkit (het printbestand) ze allemaal\n      \/\/ meeneemt — de preview week daardoor af van de print. We tonen daarom\n      \/\/ vaste spaties (zelfde breedte, worden niet samengevouwen). Dit raakt\n      \/\/ alleen de weergave: state.naam en het printbestand houden gewone\n      \/\/ spaties, dus er verandert niets aan wat er besteld wordt.\n      t.textContent=(state.naam||'NAAM').replace(\/ \/g,'\\u00A0');\n      t.setAttribute('font-family',state.font);\n      t.setAttribute('fill',state.ink);\n      \/\/ gewicht per design (standaard 600\/SemiBold, zoals in CorelDraw)\n      const d=DESIGNS[state.design];\n      t.setAttribute('font-weight',(d\u0026\u0026d.fontWeight)?d.fontWeight:'600');\n      autoSchaalSVG(svg,t);\n    }\n    \/\/ vlag\n    vulVlag(svg);\n    \/\/ bleed wegknippen langs de snijlijn (alleen preview; preview = sticker)\n    klipOpSnijlijn(svg);\n  }\n\n  \/\/ leid de horizontale uitlijning af uit de positie van de ORIGINELE tekst\n  \/\/ t.o.v. KADER_NAAM in de ruwe SVG-tekst (links \/ midden \/ rechts)\n  function uitlijningUitTekst(txt){\n    function attrVan(tag,naam){const m=tag.match(new RegExp('(?:^|[^-a-zA-Z])'+naam+'=\"([^\"]*)\"'));return m?m[1]:null;}\n    \/\/ KADER_NAAM grenzen\n    const kaderTag=(txt.match(\/\u003c[a-zA-Z]+[^\u003e]*\\bid=\"KADER_NAAM\"[^\u003e]*\u003e\/)||[])[0];\n    const tekstTag=(txt.match(\/\u003ctext[^\u003e]*\\bid=\"TEKST_NAAM\"[^\u003e]*\u003e\/)||[])[0];\n    if(!kaderTag||!tekstTag)return 'midden';\n    const kx=parseFloat(attrVan(kaderTag,'x')), kw=parseFloat(attrVan(kaderTag,'width'));\n    \/\/ text-anchor expliciet? dan die respecteren\n    const anchor=attrVan(tekstTag,'text-anchor');\n    const tx=parseFloat(attrVan(tekstTag,'x'));\n    if(isNaN(kx)||isNaN(kw))return 'midden';\n    if(anchor==='start')return 'links';\n    if(anchor==='end')return 'rechts';\n    if(anchor==='middle')return 'midden';\n    \/\/ anders: afleiden uit waar de tekst-x staat binnen het kader\n    if(!isNaN(tx)){\n      const rel=(tx-kx)\/kw; \/\/ 0 = linkerrand, 0.5 = midden, 1 = rechterrand\n      if(rel\u003c0.25)return 'links';\n      if(rel\u003e0.75)return 'rechts';\n      return 'midden';\n    }\n    return 'midden';\n  }\n\n  \/\/ Kies het juiste tekstkader. Designs kunnen twee kaders hebben:\n  \/\/  - KADER_NAAM       : volle breedte (geen vlaggen)\n  \/\/  - KADER_NAAM_VLAG  : smaller kader (er staan vlaggen naast de tekst)\n  \/\/ Zo hoeft de wizard niets te rekenen: de layout ligt vast in het template.\n  \/\/ Designs met maar één kader (Cauberg, Mortirolo) werken ongewijzigd.\n  function kiesKader(svg){\n    const metVlag=(state.flag!=='none');\n    if(metVlag){\n      const kv=svg.querySelector('#KADER_NAAM_VLAG');\n      if(kv)return kv;\n    }\n    return svg.querySelector('#KADER_NAAM');\n  }\n\n  function autoSchaalSVG(svg,t){\n    const kader=kiesKader(svg);\n    if(!kader)return;\n    const kx=+kader.getAttribute('x'),ky=+kader.getAttribute('y'),kw=+kader.getAttribute('width'),kh=+kader.getAttribute('height');\n    \/\/ begin ruim, krimp tot binnen kader-breedte; pas dan pct toe.\n    \/\/ Krimp in stappen van 2% i.p.v. vaste eenheden: het resultaat hangt dan\n    \/\/ niet af van de schaal van het template en de tekst wordt niet verder\n    \/\/ verkleind dan nodig (met vaste stappen schoot hij makkelijk door).\n    let size=kh*1.1;t.setAttribute('font-size',size);\n    let guard=0;\n    try{\n      while(t.getComputedTextLength()\u003ekw \u0026\u0026 size\u003ekh*0.15 \u0026\u0026 guard\u003c400){\n        size*=0.98;t.setAttribute('font-size',size);guard++;\n      }\n    }catch(e){}\n    const finale=size*(state.pct\/100);\n    t.setAttribute('font-size',finale);\n    \/\/ horizontaal: uitlijning volgens het design (links\/midden\/rechts)\n    const uit=(DESIGNS[state.design]\u0026\u0026DESIGNS[state.design].uitlijning)||'midden';\n    if(uit==='links'){t.setAttribute('text-anchor','start');t.setAttribute('x',kx);}\n    else if(uit==='rechts'){t.setAttribute('text-anchor','end');t.setAttribute('x',kx+kw);}\n    else{t.setAttribute('text-anchor','middle');t.setAttribute('x',kx+kw\/2);}\n    t.removeAttribute('dominant-baseline');\n    \/\/ verticaal: centreer de HOOFDLETTERS exact op het midden van KADER_NAAM.\n    \/\/ Elk font heeft een eigen kapitaalhoogte: bij dezelfde baseline steekt het\n    \/\/ ene font verder omhoog dan het andere (Anton bv. hoger dan Montserrat).\n    \/\/ Daarom rekenen we per font met de echte kapitaalhoogte uit het TTF-bestand\n    \/\/ (via fontkit, dat toch al geladen is). Lukt dat niet, dan valt hij terug op\n    \/\/ de verhouding die het CorelDRAW-template zelf aangeeft.\n    const kaderMidden=ky+kh\/2;\n    const f=fontCache[state.font];\n    let baseline=null;\n    if(f\u0026\u0026f.unitsPerEm){\n      \/\/ capHeight kan ontbreken in sommige fonts; ascent is dan de beste benadering\n      const cap=(typeof f.capHeight==='number'\u0026\u0026f.capHeight\u003e0)?f.capHeight:(f.ascent||0);\n      if(cap\u003e0){\n        \/\/ hoogte van de hoofdletters in de huidige fontgrootte\n        const capPx=(cap\/f.unitsPerEm)*finale;\n        \/\/ baseline zo zetten dat de hoofdletters gecentreerd staan\n        baseline=kaderMidden+capPx\/2;\n      }\n    }\n    if(baseline===null){\n      const factor=(DESIGNS[state.design]\u0026\u0026typeof DESIGNS[state.design].baselineFactor==='number')\n        ? DESIGNS[state.design].baselineFactor\n        : BASELINE_FACTOR;\n      baseline=kaderMidden+finale*factor;\n    }\n    t.setAttribute('y',baseline);\n  }\n\n  \/\/ Vul ALLE vlag-slots van het design met dezelfde vlag. Designs kunnen\n  \/\/ meerdere slots hebben (kenteken: VLAG_SLOT links + VLAG_SLOT_2 rechts);\n  \/\/ designs met één slot (Cauberg, Mortirolo) werken ongewijzigd.\n  function vulVlag(svg){\n    const slots=Array.from(svg.querySelectorAll('#VLAG_SLOT,[id^=\"VLAG_SLOT\"]'));\n    if(!slots.length)return;\n    \/\/ eerdere invullingen opruimen (elk slot heeft een eigen invulling-id)\n    svg.querySelectorAll('[id^=\"VLAG_INVULLING\"]').forEach(el=\u003eel.remove());\n    if(state.flag==='none'){\n      slots.forEach(s=\u003e{s.setAttribute('fill','none');s.setAttribute('stroke','none');});\n      return;\n    }\n    const vlag=VLAGGEN[state.flag];if(!vlag)return;\n    if(vlagCache[vlag.bron]){\n      slots.forEach((s,i)=\u003eplaatsVlag(svg,s,vlagCache[vlag.bron],i));\n    }\n    else{fetch(vlag.bron).then(r=\u003er.text()).then(txt=\u003e{vlagCache[vlag.bron]=txt;render();})\n      .catch(e=\u003econsole.warn('Vlag laden:',e));}\n  }\n\n  function plaatsVlag(svg,slot,vlagTekst,index){\n    let bb;try{bb=slot.getBBox();}catch(e){return;}\n    const ns='http:\/\/www.w3.org\/2000\/svg';\n    let defs=svg.querySelector('defs');if(!defs){defs=document.createElementNS(ns,'defs');svg.insertBefore(defs,svg.firstChild);}\n    \/\/ clipPath op de slot-vorm\n    const clipId='clip_vlag_'+Math.random().toString(36).slice(2,7);\n    const cp=document.createElementNS(ns,'clipPath');cp.setAttribute('id',clipId);\n    const kloon=slot.cloneNode(true);kloon.removeAttribute('id');cp.appendChild(kloon);defs.appendChild(cp);\n    \/\/ groep met clip; uniek id per slot (meerdere slots = meerdere invullingen)\n    const g=document.createElementNS(ns,'g');\n    g.setAttribute('id','VLAG_INVULLING'+(index?'_'+index:''));\n    g.setAttribute('clip-path','url(#'+clipId+')');\n    \/\/ de vlag-SVG inladen als los element\n    const vlagDoc=new DOMParser().parseFromString(vlagTekst,'image\/svg+xml').documentElement;\n    \/\/ bepaal de eigen viewBox\/afmeting van de vlag\n    let vw=parseFloat(vlagDoc.getAttribute('width'))||100, vh=parseFloat(vlagDoc.getAttribute('height'))||100;\n    const vbAttr=vlagDoc.getAttribute('viewBox');\n    let vbX=0, vbY=0;\n    if(vbAttr){const p=vbAttr.split(\/[ ,]+\/).map(Number);if(p.length===4){vbX=p[0];vbY=p[1];vw=p[2];vh=p[3];}}\n    \/\/ de inhoud in een groep zetten\n    const inner=document.createElementNS(ns,'g');\n    Array.from(vlagDoc.childNodes).forEach(n=\u003e{inner.appendChild(n.cloneNode(true));});\n    \/\/ meet de ECHTE inhoud-bbox (niet de viewBox, die kan groter\/anders zijn)\n    g.appendChild(inner);\n    slot.setAttribute('fill','none');slot.setAttribute('stroke','none');\n    slot.parentNode.insertBefore(g, slot.nextSibling);\n    let cb;try{cb=inner.getBBox();}catch(e){cb=null;}\n    \/\/ gebruik de echte inhoud-afmeting als die geldig is, anders de viewBox\n    let bronX=vbX, bronY=vbY, bronW=vw, bronH=vh;\n    if(cb \u0026\u0026 cb.width\u003e0 \u0026\u0026 cb.height\u003e0){bronX=cb.x;bronY=cb.y;bronW=cb.width;bronH=cb.height;}\n    \/\/ STRETCH: rek de vlag uit zodat hij het slot exact vult (x en y apart)\n    const schaalX=bb.width\/bronW, schaalY=bb.height\/bronH;\n    const offX=bb.x-bronX*schaalX;\n    const offY=bb.y-bronY*schaalY;\n    inner.setAttribute('transform','translate('+offX+' '+offY+') scale('+schaalX+' '+schaalY+')');\n  }\n\n  \/\/ bouw de vlag-keuzeknoppen met mini-vlag + naam\n  function bouwVlagKnoppen(){\n    const cont=document.getElementById('flags');\n    cont.innerHTML='';\n    \/\/ 'Geen' als EERSTE optie (is bij sommige designs de standaardkeuze)\n    const geen=document.createElement('div');\n    geen.className='vlagopt'+(state.flag==='none'?' sel':'');\n    geen.dataset.flag='none';\n    geen.innerHTML='\u003cdiv class=\"vlagmini geen\"\u003e✕\u003c\/div\u003e\u003cspan\u003eGeen\u003c\/span\u003e';\n    cont.appendChild(geen);\n    VLAG_VOLGORDE.forEach(key=\u003e{\n      const v=VLAGGEN[key];\n      const o=document.createElement('div');\n      o.className='vlagopt'+(key===state.flag?' sel':'');\n      o.dataset.flag=key;\n      o.innerHTML='\u003cdiv class=\"vlagmini\" id=\"vlagmini_'+key+'\"\u003e\u003c\/div\u003e\u003cspan\u003e'+v.naam+'\u003c\/span\u003e';\n      cont.appendChild(o);\n      \/\/ laad de echte vlag als mini-preview\n      fetch(v.bron).then(r=\u003er.text()).then(txt=\u003e{\n        vlagCache[v.bron]=txt;\n        const host=document.getElementById('vlagmini_'+key);\n        if(host){const s=new DOMParser().parseFromString(txt,'image\/svg+xml').documentElement;\n          \/\/ bepaal de echte viewBox van de vlag (incl. eventuele x\/y offset)\n          let vx=0,vy=0,vw=parseFloat(s.getAttribute('width'))||3, vh=parseFloat(s.getAttribute('height'))||2;\n          const vb=s.getAttribute('viewBox');\n          if(vb){const p=vb.split(\/[ ,]+\/).map(Number);if(p.length===4){vx=p[0];vy=p[1];vw=p[2];vh=p[3];}}\n          \/\/ hele vlag passend tonen, eigen verhouding behouden\n          s.setAttribute('preserveAspectRatio','xMidYMid meet');\n          s.setAttribute('viewBox',vx+' '+vy+' '+vw+' '+vh);\n          s.removeAttribute('width');s.removeAttribute('height');\n          s.style.width='100%';s.style.height='100%';\n          s.style.objectFit='contain';\n          host.innerHTML='';host.appendChild(s);}\n      }).catch(e=\u003econsole.warn('Mini-vlag:',e));\n    });\n  }\n  \/\/ markeer de actieve vlag in de keuzelijst (na een design-wissel)\n  function markeerVlagKeuze(){\n    document.querySelectorAll('#flags .vlagopt').forEach(o=\u003e{\n      o.classList.toggle('sel',o.dataset.flag===state.flag);\n    });\n  }\n\n  function render(){\n    document.querySelectorAll('#set .dsgn svg').forEach(svg=\u003evulSlots(svg));\n  }\n\n  document.getElementById('designs').addEventListener('click',e=\u003e{\n    const c=e.target.closest('.card');if(!c)return;\n    document.querySelectorAll('#designs .card').forEach(x=\u003ex.classList.remove('sel'));c.classList.add('sel');\n    state.design=c.dataset.design;\n    const d=DESIGNS[state.design];\n    if(d){\n      state.bg=d.bg;state.bgNaam=d.bgNaam;state.ink=d.ink;state.inkNaam=d.inkNaam;state.font=d.font;\n      \/\/ standaardvlag toepassen: designs met standaardVlag (kenteken='none')\n      \/\/ volgen dat; andere designs vallen terug op de eerste vlag (Nederland),\n      \/\/ zodat de vlag terugkomt na een bezoek aan een design zonder vlag.\n      state.flag=(typeof d.standaardVlag!=='undefined')?d.standaardVlag:VLAG_VOLGORDE[0];\n      markeerVlagKeuze();\n    }\n    pasFontKeuzeAan();pasFormaatKeuzeAan();werkMaatLabelsBij();\n    laadPrijzen();\n    laadDesign();\n  });\n\n  \/\/ verberg de lettertype-keuze als het design een vast font heeft\n  function pasFontKeuzeAan(){\n    const d=DESIGNS[state.design];\n    const blok=document.getElementById('fontBlok');\n    if(!blok)return;\n    if(d\u0026\u0026d.fontVast){blok.style.display='none';}\n    else{blok.style.display='';\n      const uit=(d\u0026\u0026Array.isArray(d.fontUit))?d.fontUit:[];\n      \/\/ lettertypes die bij dit design niet goed staan, verbergen\n      document.querySelectorAll('#fonts .opt').forEach(o=\u003e{\n        o.style.display=(uit.indexOf(o.dataset.font)!==-1)?'none':'';\n      });\n      \/\/ staat er een verborgen lettertype actief? val terug op het design-standaard\n      if(uit.indexOf(state.font)!==-1)state.font=d.font;\n      \/\/ markeer het juiste font als geselecteerd\n      document.querySelectorAll('#fonts .opt').forEach(o=\u003e{\n        o.classList.toggle('sel',o.dataset.font===state.font);\n      });\n    }\n  }\n  \/\/ verberg de formaat-keuze als het design maar EEN formaat heeft (kenteken)\n  function pasFormaatKeuzeAan(){\n    const d=DESIGNS[state.design];\n    const blok=document.getElementById('formaatBlok');\n    const set=document.getElementById('set');\n    if(d\u0026\u0026d.enkelFormaat){\n      if(blok)blok.style.display='none';\n      \/\/ vaste maat aanhouden; 'normaal' is de enige sleutel in maten{}\n      state.size='normaal';\n    }else{\n      if(blok)blok.style.display='';\n    }\n    \/\/ preview-breedte: enkelvoudig design krijgt de brede weergave\n    if(set){\n      set.className='set '+state.size+(aantalStickers()===1?' enkel':'');\n    }\n    \/\/ tekenlimiet per design (kenteken heeft ruimte, tekst schaalt mee)\n    const inp=document.getElementById('naam');\n    if(inp){\n      const max=(d\u0026\u0026d.maxTekens)?d.maxTekens:22;\n      inp.setAttribute('maxlength',max);\n      if(inp.value.length\u003emax)inp.value=inp.value.slice(0,max);\n    }\n  }\n  document.getElementById('sizes').addEventListener('click',e=\u003e{\n    const c=e.target.closest('.chip');if(!c)return;\n    document.querySelectorAll('#sizes .chip').forEach(x=\u003ex.classList.remove('sel'));c.classList.add('sel');\n    state.size=c.dataset.size;\n    document.getElementById('set').className='set '+state.size+(aantalStickers()===1?' enkel':'');\n    toonPrijs();\n    requestAnimationFrame(render);\n  });\n  \/\/ toegestane tekens: letters (incl. accenten), cijfers, spatie, gangbare\n  \/\/ leestekens EN emoji's. Emoji's worden in het printbestand als afbeelding\n  \/\/ meegenomen (zie emojiNaarAfbeelding), gewone tekens als vectorpad.\n  \/\/ Alleen echte stuurtekens en onzichtbare rommel weren we.\n  const VERBODEN=\/[\\u0000-\\u001F\\u007F-\\u009F]\/g;\n  function schoonNaam(tekst){return (tekst||'').replace(VERBODEN,'');}\n\n  \/\/ Splits een tekst in stukken: gewone tekst en losse emoji's.\n  \/\/ Gebruikt Intl.Segmenter als de browser dat kan (houdt samengestelde\n  \/\/ emoji's als vlaggen en huidskleur-varianten netjes bij elkaar),\n  \/\/ anders een terugval op losse code-punten.\n  function splitsTekst(tekst){\n    const delen=[];\n    let bufferTekst='';\n    const voegToe=(type,waarde)=\u003e{\n      if(type==='tekst'){bufferTekst+=waarde;return;}\n      if(bufferTekst){delen.push({type:'tekst',waarde:bufferTekst});bufferTekst='';}\n      delen.push({type:'emoji',waarde:waarde});\n    };\n    const isEmoji=(s)=\u003e{\n      \/\/ een teken is een emoji als het buiten het gewone latijnse bereik valt\n      \/\/ en als emoji-presentatie bedoeld is\n      try{return \/\\p{Extended_Pictographic}|\\p{Emoji_Presentation}\/u.test(s);}\n      catch(e){return \/[\\u203C-\\u3299\\u{1F000}-\\u{1FAFF}]\/u.test(s);}\n    };\n    try{\n      const seg=new Intl.Segmenter('nl',{granularity:'grapheme'});\n      for(const s of seg.segment(tekst)){\n        voegToe(isEmoji(s.segment)?'emoji':'tekst', s.segment);\n      }\n    }catch(e){\n      \/\/ terugval: per code-punt lopen (Array.from splitst surrogaat-paren correct)\n      Array.from(tekst).forEach(ch=\u003evoegToe(isEmoji(ch)?'emoji':'tekst',ch));\n    }\n    if(bufferTekst)delen.push({type:'tekst',waarde:bufferTekst});\n    return delen;\n  }\n  document.getElementById('naam').addEventListener('input',e=\u003e{\n    const ruw=e.target.value;\n    const schoon=schoonNaam(ruw);\n    if(schoon!==ruw){\n      \/\/ verwijder de geweerde tekens en houd de cursor netjes\n      const pos=e.target.selectionStart-(ruw.length-schoon.length);\n      e.target.value=schoon;\n      try{e.target.setSelectionRange(pos,pos);}catch(_){}\n      \/\/ korte hint tonen\n      const hint=document.getElementById('naamHint');\n      if(hint){hint.style.display='block';clearTimeout(window._nh);window._nh=setTimeout(()=\u003e{hint.style.display='none';},2500);}\n    }\n    state.naam=schoon.toUpperCase();render();\n  });\n  document.getElementById('fonts').addEventListener('click',e=\u003e{\n    const o=e.target.closest('.opt');if(!o)return;\n    document.querySelectorAll('#fonts .opt').forEach(x=\u003ex.classList.remove('sel'));o.classList.add('sel');\n    state.font=o.dataset.font;render();\n  });\n  document.getElementById('flags').addEventListener('click',e=\u003e{\n    const o=e.target.closest('.vlagopt');if(!o)return;\n    document.querySelectorAll('#flags .vlagopt').forEach(x=\u003ex.classList.remove('sel'));o.classList.add('sel');\n    state.flag=o.dataset.flag;render();toonPrijs();\n  });\n  document.querySelectorAll('[data-bg]').forEach(s=\u003e{if(s.classList.contains('sw'))s.addEventListener('click',()=\u003e{\n    document.querySelectorAll('.sw[data-bg]').forEach(x=\u003ex.classList.remove('sel'));\n    document.getElementById('bgPickWrap').classList.remove('sel');s.classList.add('sel');\n    state.bg=s.dataset.bg;state.bgNaam=s.getAttribute('title')||s.dataset.bg;render();toonPrijs();});});\n  document.querySelectorAll('[data-ink]').forEach(s=\u003e{if(s.classList.contains('sw'))s.addEventListener('click',()=\u003e{\n    document.querySelectorAll('.sw[data-ink]').forEach(x=\u003ex.classList.remove('sel'));\n    document.getElementById('inkPickWrap').classList.remove('sel');s.classList.add('sel');\n    state.ink=s.dataset.ink;state.inkNaam=s.getAttribute('title')||s.dataset.ink;render();toonPrijs();});});\n  document.getElementById('size').addEventListener('input',e=\u003e{state.pct=+e.target.value;render();});\n\n  \/\/ eigen kleur kiezers\n  document.getElementById('bgPick').addEventListener('input',e=\u003e{\n    document.querySelectorAll('.sw[data-bg]').forEach(x=\u003ex.classList.remove('sel'));\n    document.getElementById('bgPickWrap').classList.add('sel');\n    state.bg=e.target.value;state.bgNaam='Eigen kleur';render();toonPrijs();\n  });\n  document.getElementById('inkPick').addEventListener('input',e=\u003e{\n    document.querySelectorAll('.sw[data-ink]').forEach(x=\u003ex.classList.remove('sel'));\n    document.getElementById('inkPickWrap').classList.add('sel');\n    state.ink=e.target.value;state.inkNaam='Eigen kleur';render();toonPrijs();\n  });\n\n  \/\/ Variant-ID van je sticker-product (vervang door het echte ID per design)\n  const VARIANT_ID = 53379870916935; \/\/ fallback\/test-variant zolang designs nog geen eigen ID's hebben\n  \/\/ kies de juiste variant-ID op basis van design + gekozen formaat\n  function huidigeVariant(){\n    const d=DESIGNS[state.design];\n    \/\/ designs met prijs-tiers (kenteken): kies op basis van kleur + vlag\n    if(d\u0026\u0026d.prijsVarianten){\n      \/\/ hex normaliseren: #fff en #FFFFFF zijn dezelfde kleur maar niet dezelfde\n      \/\/ tekst. Zonder deze stap blijft de prijs op de duurdere tier hangen zodra\n      \/\/ je terugklikt naar de basiskleur.\n      const norm=(h)=\u003e{\n        let s=String(h||'').trim().toLowerCase().replace(\/^#\/,'');\n        if(s.length===3)s=s[0]+s[0]+s[1]+s[1]+s[2]+s[2];\n        return '#'+s;\n      };\n      const kleurAfwijkend=(norm(state.bg)!==norm(d.basisBg))||(norm(state.ink)!==norm(d.basisInk));\n      const vlagAan=(state.flag \u0026\u0026 state.flag!=='none');\n      let tier='basis';\n      if(kleurAfwijkend \u0026\u0026 vlagAan)tier='plus2';\n      else if(kleurAfwijkend || vlagAan)tier='plus1';\n      return d.prijsVarianten[tier]||d.prijsVarianten.basis;\n    }\n    \/\/ standaard: variant per formaat\n    if(d\u0026\u0026d.varianten\u0026\u0026d.varianten[state.size])return d.varianten[state.size];\n    return VARIANT_ID;\n  }\n  \/\/ Web App URL van je Apps Script opslag-endpoint (vul in na deployen).\n  \/\/ Leeg laten = alleen lokale download, geen Drive-opslag.\n  const OPSLAG_URL = 'https:\/\/script.google.com\/macros\/s\/AKfycbx_RxNkexogvuY7ozURv9Ei9nlPPO9MKG1fSFZvLAFVcG7W-98LHT5qfi5kWhok0DHZ\/exec';\n\n  \/\/ === RAKEL-UPSELL (los regelitem in de winkelmand) ===\n  \/\/ Aan\/uit in stap 4. Prijs komt uit Shopify via de handle (zelfde bron als\n  \/\/ de stickers). Standaard UITGEVINKT. Toevoegen = los line item.\n  const RAKEL={\n    variant:54255499084103,\n    handle:'socialsticker-applicatie-hulp-krasvrije-sticker-wrap-rakel',\n    naam:'Applicatie-rakel'\n  };\n  let rakelAan=false; \/\/ klant moet bewust aanvinken\n  const maatNamen={klein:'Klein (4×0,7 cm)',normaal:'Normaal (5×0,9 cm)',groot:'Groot (7×1,2 cm)'};\n  const designNamen={mortirolo:'Mortirolo',cauberg:'Cauberg',fiets:'Fiets sticker',fietslinks:'Fiets sticker links',kenteken:'Kentekensticker',ventoux:'Mont Ventoux',teide:'El Teide',alpe:'Alpe'};\n\n  \/\/ Unieke code als brug tussen order en Drive-bestand (bijv. SS-7K3M9X)\n  function uniekeCode(){\n    const tekens='ABCDEFGHJKLMNPQRSTUVWXYZ23456789'; \/\/ zonder verwarrende 0\/O\/1\/I\n    let c='';for(let i=0;i\u003c6;i++)c+=tekens[Math.floor(Math.random()*tekens.length)];\n    return 'SS-'+c;\n  }\n\n  \/\/ Bouw het productiebestand uit het ECHTE gerenderde design (preview = productie).\n  const MAAT_MM={klein:{w:40,h:7},normaal:{w:50,h:9},groot:{w:70,h:12}};\n  \/\/ werk de cm-labels van de formaatknoppen bij voor het huidige design\n  function werkMaatLabelsBij(){\n    ['klein','normaal','groot'].forEach(size=\u003e{\n      const mm=maatVoorDesign(size);\n      const cmW=(mm.w\/10).toFixed(mm.w%10===0?0:1).replace('.',',');\n      const cmH=(mm.h\/10).toFixed(1).replace('.',',');\n      document.querySelectorAll('#sizes small[data-maat=\"'+size+'\"]').forEach(el=\u003e{\n        el.textContent=cmW+'×'+cmH+' cm';\n      });\n    });\n  }\n\n  \/\/ maat per design (valt terug op de globale MAAT_MM als een design geen eigen maten heeft)\n  function maatVoorDesign(size){\n    const d=DESIGNS[state.design];\n    if(d\u0026\u0026d.maten\u0026\u0026d.maten[size])return d.maten[size];\n    return MAAT_MM[size]||MAAT_MM.normaal;\n  }\n  const CUT={kiss:'#FF00FF',through:'#00FFFF',insetMm:1,gapMm:8};\n\n  \/\/ laad een font via fontkit (leest TTF\/OTF\/WOFF\/WOFF2) uit cache of ophalen\n  function laadFont(naam){\n    return new Promise((resolve)=\u003e{\n      if(fontCache[naam]){resolve(fontCache[naam]);return;}\n      const f=FONTS[naam];\n      const fk=window.fontkit||window['fontkit'];\n      if(!f||!fk){resolve(null);return;}\n      fetch(f.ttf).then(r=\u003er.arrayBuffer()).then(buf=\u003e{\n        try{\n          \/\/ fontkit verwacht een Uint8Array\/Buffer\n          const font=fk.create(new Uint8Array(buf));\n          fontCache[naam]=font;resolve(font);\n        }catch(e){console.warn('Font parse:',naam,e);resolve(null);}\n      }).catch(e=\u003e{console.warn('Font laden:',naam,e);resolve(null);});\n    });\n  }\n\n  \/\/ === EMOJI'S IN HET PRINTBESTAND ===\n  \/\/ De browser tekent emoji's met de systeemfont van het apparaat van de klant.\n  \/\/ Fontkit kent die vormen niet (ze zitten niet in onze TTF's), dus vangen we\n  \/\/ ze af via een canvas: we tekenen de emoji groot, lezen 'm uit als\n  \/\/ afbeelding en bedden die in de SVG in. Zo staat in het printbestand exact\n  \/\/ wat de klant in de preview zag, zonder externe bronnen.\n  \/\/ Resolutie waarop de emoji wordt uitgetekend. De emoji gaat als PNG mee in\n  \/\/ het printbestand, dus dit bepaalt de scherpte: 256 px geeft bij een emoji\n  \/\/ van ~4 mm ruim 1500 dpi. Hoger kan, maar maakt het bestand zwaarder.\n  const EMOJI_RESOLUTIE=256;\n  let emojiCache={};         \/\/ emoji -\u003e maten en beelddata\n\n  \/\/ Tekent één emoji met de systeemfont van het apparaat en levert de\n  \/\/ bijgesneden afbeelding plus de maatverhoudingen.\n  \/\/ doelPx: gewenst aantal pixels breed in het printbestand. CorelDRAW valt\n  \/\/ terug op de pixelmaat van de PNG als het de width\/height niet volgt, dus\n  \/\/ door de PNG op de eindmaat te renderen kloppen beide interpretaties.\n  function emojiNaarAfbeelding(emoji,doelPx){\n    const sleutel=emoji+'@'+(doelPx?Math.round(doelPx):0);\n    if(emojiCache[sleutel])return emojiCache[sleutel];\n    try{\n      \/\/ teken ruim genoeg: minimaal de basisresolutie, of de gevraagde eindmaat\n      const R=Math.max(EMOJI_RESOLUTIE, Math.min(1024, Math.round(doelPx||0)));\n      const canvas=document.createElement('canvas');\n      \/\/ ruim canvas: sommige emoji's steken buiten het vierkant\n      canvas.width=Math.round(R*1.6);\n      canvas.height=Math.round(R*1.6);\n      const ctx=canvas.getContext('2d');\n      if(!ctx)return null;\n      ctx.textAlign='left';\n      ctx.textBaseline='alphabetic';\n      ctx.font=R+'px sans-serif';\n      \/\/ hoeveel ruimte neemt deze emoji in de tekstregel in? (voor positionering)\n      const adv=ctx.measureText(emoji).width;\n      \/\/ ruim binnen het canvas tekenen zodat niets wegvalt\n      const tekenX=R*0.3, tekenY=R*1.15;\n      ctx.fillText(emoji,tekenX,tekenY);\n      \/\/ bijsnijden op wat er werkelijk getekend is\n      const beeld=ctx.getImageData(0,0,canvas.width,canvas.height).data;\n      let minX=canvas.width,minY=canvas.height,maxX=-1,maxY=-1;\n      for(let y=0;y\u003ccanvas.height;y++){\n        for(let x=0;x\u003ccanvas.width;x++){\n          if(beeld[(y*canvas.width+x)*4+3]\u003e8){ \/\/ niet-transparant\n            if(x\u003cminX)minX=x; if(x\u003emaxX)maxX=x;\n            if(y\u003cminY)minY=y; if(y\u003emaxY)maxY=y;\n          }\n        }\n      }\n      if(maxX\u003c0)return null; \/\/ niets getekend\n      const bw=maxX-minX+1, bh=maxY-minY+1;\n      const uit=document.createElement('canvas');\n      uit.width=bw; uit.height=bh;\n      uit.getContext('2d').drawImage(canvas,minX,minY,bw,bh,0,0,bw,bh);\n      const res={\n        data:uit.toDataURL('image\/png'),\n        \/\/ werkelijke pixelmaten van het bijgesneden beeld: nodig om in het\n        \/\/ printbestand een expliciete schaal te kunnen zetten\n        pxBreedte:bw,\n        pxHoogte:bh,\n        \/\/ maten t.o.v. de fontgrootte, zodat we later kunnen schalen\n        advRatio:adv\/R,               \/\/ breedte in de tekstregel\n        beeldRatio:bw\/R,              \/\/ werkelijke beeldbreedte\n        hoogteRatio:bh\/R,             \/\/ werkelijke beeldhoogte\n        \/\/ hoe ver de onderkant onder de baseline zit\n        onderRatio:(minY+bh-R*1.15)\/R,\n        linksRatio:(minX-R*0.3)\/R\n      };\n      emojiCache[sleutel]=res;\n      return res;\n    }catch(e){console.warn('Emoji tekenen:',emoji,e);return null;}\n  }\n  \/\/ zet tekst om naar SVG, exact gecentreerd op (midX,midY).\n  \/\/ Gewone tekens worden vectorpaden via fontkit; emoji's worden ingebedde\n  \/\/ afbeeldingen (die vormen bestaan niet in onze TTF's). Alles wordt op één\n  \/\/ regel naast elkaar geplaatst, zoals de browser het ook doet.\n  function tekstNaarPad(font,tekst,fontSizePx,midX,midY,kleur,mmSchaal){\n    const scale=fontSizePx\/font.unitsPerEm;\n    const delen=splitsTekst(tekst);\n    \/\/ eerst opmeten hoe breed het geheel wordt (in px)\n    const stukken=[];\n    let totaal=0;\n    delen.forEach(deel=\u003e{\n      if(deel.type==='tekst'){\n        const run=font.layout(deel.waarde);\n        let breedte=0;\n        run.positions.forEach(p=\u003e{breedte+=p.xAdvance;});\n        const px=breedte*scale;\n        stukken.push({type:'tekst',run:run,breedte:px});\n        totaal+=px;\n      }else{\n        \/\/ De emoji gaat als vector mee, dus hij is resolutie-onafhankelijk in\n        \/\/ het printbestand. De canvas-resolutie bepaalt alleen hoe fijn de\n        \/\/ vormen zijn; die staat vast op EMOJI_RESOLUTIE.\n        const em=emojiNaarAfbeelding(deel.waarde,0);\n        if(!em)return; \/\/ niet te tekenen: overslaan\n        const px=em.advRatio*fontSizePx;\n        stukken.push({type:'emoji',em:em,breedte:px});\n        totaal+=px;\n      }\n    });\n    \/\/ verticale plaatsing: baseline zo dat de tekst optisch gecentreerd staat\n    const asc=font.ascent, desc=font.descent;\n    const baseline=midY+((asc+desc)\/2)*scale;\n    let penX=midX-totaal\/2;\n    let uit='';\n    stukken.forEach(stuk=\u003e{\n      if(stuk.type==='tekst'){\n        \/\/ glyphs van dit stuk als één pad\n        let d='';\n        let x=0;\n        stuk.run.glyphs.forEach((glyph,i)=\u003e{\n          const pos=stuk.run.positions[i];\n          const gp=glyph.path.translate(x+(pos.xOffset||0),(pos.yOffset||0));\n          d+=gp.toSVG()+' ';\n          x+=pos.xAdvance;\n        });\n        if(d.trim()){\n          uit+='\u003cpath d=\"'+d.trim()+'\" fill=\"'+kleur+'\" '\n            +'transform=\"translate('+penX.toFixed(2)+' '+baseline.toFixed(2)+') '\n            +'scale('+scale.toFixed(5)+' '+(-scale).toFixed(5)+')\"\/\u003e';\n        }\n      }else{\n        const em=stuk.em;\n        const bw=em.beeldRatio*fontSizePx;\n        const bh=em.hoogteRatio*fontSizePx;\n        \/\/ positie: links t.o.v. de pen, onderkant t.o.v. de baseline\n        const x=penX+em.linksRatio*fontSizePx;\n        const y=baseline+em.onderRatio*fontSizePx-bh;\n        \/\/ De emoji wordt hier NIET getekend, maar gemarkeerd. CorelDRAW past de\n        \/\/ schaal van de omhullende sticker-groep niet toe op ingebedde\n        \/\/ afbeeldingen, waardoor de emoji minuscuul werd. Daarom plaatsen we\n        \/\/ hem later buiten die groep, met coördinaten al in millimeters.\n        \/\/ Het merkteken bewaart de positie en maat in template-eenheden.\n        uit+='\u003cg data-emoji=\"1\"'\n          +' data-x=\"'+x.toFixed(3)+'\" data-y=\"'+y.toFixed(3)+'\"'\n          +' data-w=\"'+bw.toFixed(3)+'\" data-h=\"'+bh.toFixed(3)+'\"'\n          +' data-src=\"'+em.data+'\"\u003e\u003c\/g\u003e';\n      }\n      penX+=stuk.breedte;\n    });\n    return uit;\n  }\n\n  async function bouwProductieSVG(code){\n    const bronSvg=document.querySelector('#set .dsgn svg');\n    if(!bronSvg)return '';\n    const kloon=bronSvg.cloneNode(true);\n    \/\/ BELANGRIJK: de preview-clip (klipOpSnijlijn wikkelt de inhoud in\n    \/\/ #SNIJ_CLIP_WRAP) mag NIET in het printbestand — daar hoort de VOLLE\n    \/\/ bleed in. Pak de groep uit en verwijder de clipPath.\n    const snijClipId=kloon.getAttribute('data-snijclip');\n    kloon.removeAttribute('data-snijclip');\n    const wrap=kloon.querySelector('#SNIJ_CLIP_WRAP');\n    if(wrap){\n      while(wrap.firstChild){kloon.insertBefore(wrap.firstChild,wrap);}\n      wrap.remove();\n    }\n    if(snijClipId){const cp=kloon.querySelector('#'+snijClipId);if(cp)cp.remove();}\n    const tBron=bronSvg.querySelector('#TEKST_NAAM');\n    const tKloon=kloon.querySelector('#TEKST_NAAM');\n\n    \/\/ Schaal alvast bepalen (template-eenheden -\u003e mm). Nodig om emoji's op de\n    \/\/ juiste pixelmaat te renderen: CorelDRAW valt terug op de pixelmaat van de\n    \/\/ PNG, dus die moet overeenkomen met de eindmaat op de sticker.\n    let vooruitSchaal=0;\n    try{\n      const dv0=DESIGNS[state.design];\n      let box0=(dv0\u0026\u0026dv0.boxVast)?dv0.boxVast:boxUitTekst(sjabloonCache[huidigeBron()]||'');\n      if(!box0)box0=berekenBox(bronSvg);\n      if(box0){\n        const mm0=maatVoorDesign(state.size);\n        vooruitSchaal=mm0.w\/(box0.maxX-box0.minX); \/\/ eenheden -\u003e mm\n      }\n    }catch(e){}\n\n    \/\/ probeer de tekst om te zetten naar een vector-pad (preview = productie)\n    let tekstVervangen=false;\n    if(tBron\u0026\u0026tKloon){\n      const font=await laadFont(state.font);\n      const kader=kiesKader(bronSvg);\n      if(font\u0026\u0026kader){\n        const naam=state.naam||'NAAM';\n        \/\/ De browser heeft de tekst in de preview al perfect geschaald en\n        \/\/ geplaatst. We nemen die fontgrootte en positie letterlijk over, zodat\n        \/\/ het printbestand exact overeenkomt met wat de klant zag.\n        \/\/ (Niet herberekenen uit de gemeten breedte: bij emoji's klopt dat niet,\n        \/\/ want fontkit kent die tekens niet en meet ze dus niet mee.)\n        const bb=tBron.getBBox();\n        const previewSize=parseFloat(tBron.getAttribute('font-size'));\n        const matchSize=(!isNaN(previewSize)\u0026\u0026previewSize\u003e0)\n          ? previewSize\n          : (+kader.getAttribute('height'));\n        \/\/ horizontaal midden uit het kader (de preview centreert daar ook op),\n        \/\/ verticaal het midden van de gemeten tekst\n        const kx=+kader.getAttribute('x'), kw=+kader.getAttribute('width');\n        const midX=(!isNaN(kx)\u0026\u0026!isNaN(kw))?(kx+kw\/2):(bb.x+bb.width\/2);\n        const midY=bb.y+bb.height\/2;\n        const padSvg=tekstNaarPad(font,naam,matchSize,midX,midY,state.ink,vooruitSchaal);\n        const wrapper=document.createElementNS('http:\/\/www.w3.org\/2000\/svg','g');\n        wrapper.setAttribute('id','TEKST_NAAM_PAD');\n        \/\/ Niet via innerHTML: die parseert als HTML en gooit het\n        \/\/ naamruimte-attribuut xlink:href weg, waardoor emoji-afbeeldingen in\n        \/\/ CorelDRAW verdwijnen. Daarom netjes als losse SVG-knopen opbouwen.\n        const NS='http:\/\/www.w3.org\/2000\/svg';\n        const XLINK='http:\/\/www.w3.org\/1999\/xlink';\n        const tijdelijk=new DOMParser().parseFromString(\n          '\u003csvg xmlns=\"'+NS+'\" xmlns:xlink=\"'+XLINK+'\"\u003e'+padSvg+'\u003c\/svg\u003e','image\/svg+xml');\n        Array.from(tijdelijk.documentElement.childNodes).forEach(node=\u003e{\n          const kopie=document.importNode(node,true);\n          \/\/ href in de juiste naamruimte zetten op ALLE afbeeldingen, ook die\n          \/\/ in een geneste viewport zitten (de emoji's staan in een eigen\n          \/\/ \u003csvg\u003e, dus alleen het bovenste niveau controleren zou ze missen)\n          const beelden=[];\n          if(kopie.tagName==='image')beelden.push(kopie);\n          if(kopie.querySelectorAll)Array.from(kopie.querySelectorAll('image')).forEach(el=\u003ebeelden.push(el));\n          beelden.forEach(img=\u003e{\n            const bron=img.getAttribute('href')||img.getAttributeNS(XLINK,'href');\n            if(bron)img.setAttributeNS(XLINK,'xlink:href',bron);\n          });\n          wrapper.appendChild(kopie);\n        });\n        tKloon.parentNode.replaceChild(wrapper,tKloon);\n        tekstVervangen=true;\n      }\n    }\n    \/\/ fallback: als omzetten niet lukt, hou de tekst-eigenschappen aan\n    if(!tekstVervangen \u0026\u0026 tBron \u0026\u0026 tKloon){\n      ['x','y','font-size','font-family','fill','text-anchor','font-weight'].forEach(attr=\u003e{\n        const v=tBron.getAttribute(attr);if(v!==null)tKloon.setAttribute(attr,v);\n      });\n      tKloon.removeAttribute('dominant-baseline');\n      tKloon.textContent=state.naam||'NAAM';\n    }\n\n    \/\/ snijlijn KISS uit het design: 1-op-1 overnemen, alleen kleur omzetten\n    \/\/ naar magenta (CutContour). Haarlijn 0,001mm zoals de plotter verwacht.\n    kloon.querySelectorAll('#SNIJLIJN_KISS,[id^=\"SNIJLIJN_KISS\"]').forEach(el=\u003e{\n      el.setAttribute('fill','none');\n      el.setAttribute('stroke','#FF00FF');\n      el.setAttribute('stroke-width','0.001');\n      el.removeAttribute('vector-effect');\n      el.setAttribute('data-cut','kiss');\n    });\n\n    \/\/ zelfde box-logica als de preview: vaste box, anders uit de tekst lezen\n    const dv=DESIGNS[state.design];\n    let box=(dv\u0026\u0026dv.boxVast)?dv.boxVast:boxUitTekst(sjabloonCache[huidigeBron()]||'');\n    if(!box){box=berekenBox(bronSvg);}\n    if(!box)return '';\n    const dW=box.maxX-box.minX, dH=box.maxY-box.minY;\n    const mm=maatVoorDesign(state.size);\n    const schaal=mm.w\/dW;\n    const designInner=new XMLSerializer().serializeToString(kloon)\n      .replace(\/^\u003csvg[^\u003e]*\u003e\/,'').replace(\/\u003c\\\/svg\u003e\\s*$\/,'');\n\n    function sticker(oyMm){\n      let g=`\u003cg transform=\"translate(0 ${oyMm}) scale(${schaal}) translate(${-box.minX} ${-box.minY})\"\u003e`;\n      g+=designInner;\n      g+=`\u003c\/g\u003e`;\n      return g;\n    }\n\n    \/\/ Emoji's buiten de geschaalde groep plaatsen. CorelDRAW past de schaal van\n    \/\/ een groep niet toe op ingebedde afbeeldingen (de emoji werd ~20x te\n    \/\/ klein), dus rekenen we hun positie en maat hier vooraf om naar millimeters\n    \/\/ en zetten we ze los in het bestand. Vectorinhoud houdt wél de groep, want\n    \/\/ die schaalt correct — daar hoeft niets aan te veranderen.\n    function emojisVoorSticker(oyMm){\n      let uit='';\n      kloon.querySelectorAll('g[data-emoji=\"1\"]').forEach(m=\u003e{\n        const ex=parseFloat(m.getAttribute('data-x'));\n        const ey=parseFloat(m.getAttribute('data-y'));\n        const ew=parseFloat(m.getAttribute('data-w'));\n        const eh=parseFloat(m.getAttribute('data-h'));\n        const src=m.getAttribute('data-src');\n        if(isNaN(ex)||isNaN(ey)||!src)return;\n        \/\/ dezelfde omrekening als de sticker-groep, maar nu vooraf uitgevoerd\n        const mx=(ex-box.minX)*schaal;\n        const my=(ey-box.minY)*schaal+oyMm;\n        const mw=ew*schaal, mh=eh*schaal;\n        uit+='\u003cimage href=\"'+src+'\" xlink:href=\"'+src+'\" '\n          +'x=\"'+mx.toFixed(4)+'\" y=\"'+my.toFixed(4)+'\" '\n          +'width=\"'+mw.toFixed(4)+'\" height=\"'+mh.toFixed(4)+'\" '\n          +'preserveAspectRatio=\"none\"\/\u003e';\n      });\n      return uit;\n    }\n\n    const gap=CUT.gapMm;\n    \/\/ aantal stickers in het printbestand: set van 2, of enkel (kenteken)\n    const aantal=aantalStickers();\n    const totW=mm.w;\n    const totH=(aantal===1) ? mm.h : (mm.h*2+gap);\n    const body=(aantal===1)\n      ? (sticker(0)+emojisVoorSticker(0))\n      : (sticker(0)+sticker(mm.h+gap)+emojisVoorSticker(0)+emojisVoorSticker(mm.h+gap));\n\n    return `\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003csvg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" xmlns:xlink=\"http:\/\/www.w3.org\/1999\/xlink\" width=\"${totW}mm\" height=\"${totH}mm\" viewBox=\"0 0 ${totW} ${totH}\" data-code=\"${code}\"\u003e\n  \u003cmetadata\u003ecode:${code} | design:${state.design} | naam:${state.naam} | font:${state.font} | vlag:${state.flag} | bg:${state.bg} | ink:${state.ink} | formaat:${state.size} (${mm.w}x${mm.h}mm) | set:${aantal} | pct:${state.pct} | emoji:${splitsTekst(state.naam||'').filter(d=\u003ed.type==='emoji').length}\u003c\/metadata\u003e\n  ${body}\n\u003c\/svg\u003e`;\n  }\n\n  function downloadSVG(svg,naam){\n    const blob=new Blob([svg],{type:'image\/svg+xml'});\n    const url=URL.createObjectURL(blob);\n    const a=document.createElement('a');a.href=url;a.download=naam;a.click();\n    setTimeout(()=\u003eURL.revokeObjectURL(url),1000);\n  }\n\n  async function inWinkelmand(){\n    const nb=document.getElementById('next');\n    nb.disabled=true; const orig=nb.textContent; nb.textContent='Bezig...';\n    const code=uniekeCode();\n    const props={\n      'Design': designNamen[state.design]||state.design,\n      'Naam': state.naam,\n      'Lettertype': state.font,\n      'Vlag': (state.flag==='none'?'Geen':(VLAGGEN[state.flag]?VLAGGEN[state.flag].naam:state.flag)),\n      'Achtergrondkleur': state.bgNaam,\n      'Tekstkleur': state.inkNaam,\n      'Formaat': maatNamen[state.size]||state.size,\n      'Tekstgrootte': state.pct+'%',\n      '_code': code,\n      '_bg_hex': state.bg,\n      '_ink_hex': state.ink,\n      '_tekstgrootte_pct': String(state.pct)\n    };\n    const t0=performance.now();\n    try{\n      \/\/ winkelmand-items: altijd de sticker, plus de rakel als los regelitem\n      \/\/ wanneer de klant die heeft aangevinkt.\n      const items=[{id:huidigeVariant(),quantity:1,properties:props}];\n      if(rakelAan \u0026\u0026 RAKEL.variant){\n        items.push({id:RAKEL.variant,quantity:1});\n      }\n      const res=await fetch('\/cart\/add.js',{method:'POST',headers:{'Content-Type':'application\/json'},\n        body:JSON.stringify({items:items})});\n      const data=await res.json();\n      const dt=Math.round(performance.now()-t0);\n      if(res.ok){\n        \/\/ bestand op de achtergrond genereren (blokkeert de klant niet)\n        \/\/ bestand op de achtergrond genereren + opslaan (blokkeert de klant niet)\n        try{\n          const svg=await bouwProductieSVG(code);\n          \/\/ naar Drive via Apps Script (vuur-en-vergeet, blokkeert niet)\n          \/\/ text\/plain voorkomt CORS-preflight die Apps Script niet beantwoordt\n          if(svg \u0026\u0026 typeof OPSLAG_URL==='string' \u0026\u0026 OPSLAG_URL.indexOf('http')===0){\n            fetch(OPSLAG_URL,{method:'POST',headers:{'Content-Type':'text\/plain;charset=utf-8'},\n              body:JSON.stringify({code:code,svg:svg})}).catch(e=\u003econsole.warn('Drive-opslag:',e));\n          }\n        }catch(e){console.warn('SVG-generatie:',e);}\n        nb.textContent='Toegevoegd!';\n        setTimeout(toonNaToevoegen,500); \/\/ in de wizard blijven, keuze tonen\n      }\n      else{nb.textContent='Fout: '+(data.description||'onbekend');nb.disabled=false;setTimeout(()=\u003enb.textContent=orig,2500);}\n    }catch(err){nb.textContent='Fout: '+err.message;nb.disabled=false;setTimeout(()=\u003enb.textContent=orig,2500);}\n  }\n\n  document.getElementById('next').addEventListener('click',()=\u003e{\n    if(step===4){inWinkelmand();return;}\n    step=Math.min(4,step+1);stappen();veiligRender();\n  });\n  document.getElementById('back').addEventListener('click',()=\u003e{step=Math.max(minStap(),step-1);stappen();veiligRender();});\n\n  \/\/ klik op het rakel-blok = aan\/uit togglen\n  (function(){\n    const blok=document.getElementById('rakelUps');\n    if(blok)blok.addEventListener('click',()=\u003e{rakelAan=!rakelAan;vulRakelUpsell();toonPrijs();});\n  })();\n\n  \/\/ na succesvol toevoegen: in de wizard blijven en de klant laten kiezen\n  \/\/ (naar winkelmand) of nog een design maken. Vervangt de oude auto-redirect.\n  function toonNaToevoegen(){\n    const nav=document.querySelector('.nav');\n    if(!nav)return;\n    nav.innerHTML=''\n      +'\u003cbutton class=\"btn next\" id=\"naarMand\" style=\"background:var(--ink);white-space:nowrap;flex:1;font-size:14px;padding:14px 8px\"\u003eNaar winkelmand →\u003c\/button\u003e'\n      +'\u003cbutton class=\"btn back\" id=\"nogEen\" style=\"white-space:nowrap;flex:1;font-size:14px;padding:14px 8px;color:#8a8482\"\u003e+ Nog een design\u003c\/button\u003e';\n    document.getElementById('naarMand').addEventListener('click',()=\u003e{window.location.href='\/cart';});\n    document.getElementById('nogEen').addEventListener('click',resetWizard);\n  }\n  \/\/ wizard terugzetten naar het begin voor een volgend design (winkelmand blijft gevuld)\n  function resetWizard(){\n    rakelAan=false;\n    state.naam='JOUW NAAM';state.pct=100;state.flag='nederland';\n    const inp=document.getElementById('naam');if(inp)inp.value='JOUW NAAM';\n    const rng=document.getElementById('size');if(rng)rng.value=100;\n    \/\/ nav-balk herstellen\n    const nav=document.querySelector('.nav');\n    if(nav){nav.innerHTML=''\n      +'\u003cbutton class=\"btn back hide\" id=\"back\"\u003e← Terug\u003c\/button\u003e'\n      +'\u003cbutton class=\"btn next\" id=\"next\"\u003eVerder →\u003c\/button\u003e';\n      document.getElementById('next').addEventListener('click',()=\u003e{\n        if(step===4){inWinkelmand();return;}\n        step=Math.min(4,step+1);stappen();veiligRender();\n      });\n      document.getElementById('back').addEventListener('click',()=\u003e{step=Math.max(minStap(),step-1);stappen();veiligRender();});\n    }\n    step=minStap();\n    stappen();\n    laadDesign();\n    veiligRender();\n  }\n\n  function veiligRender(){requestAnimationFrame(()=\u003erequestAnimationFrame(render));}\n  document.fonts.ready.then(veiligRender);\n  \/\/ Safari laadt fonts soms ná de eerste render; her-render per font dat binnenkomt\n  ['Saira Condensed','Bebas Neue','Anton','Montserrat','Dancing Script'].forEach(f=\u003e{\n    try{document.fonts.load('800 40px \"'+f+'\"').then(veiligRender).catch(()=\u003e{});}catch(e){}\n  });\n  if(document.fonts\u0026\u0026document.fonts.addEventListener){\n    document.fonts.addEventListener('loadingdone',veiligRender);\n  }\n  setTimeout(veiligRender,300);\n  setTimeout(veiligRender,900);\n  setTimeout(veiligRender,1800);\n  window.addEventListener('resize',render);\n\n  \/\/ Fullscreen voorbeeld: tik op de preview (of het vergroot-knopje) toont de\n  \/\/ sticker groot in een overlay. Kloont de actueel gerenderde SVG('s), dus je\n  \/\/ ziet exact je eigen samenstelling. Vooral fijn bij de smalle kentekensticker.\n  (function(){\n    const overlay=document.getElementById('vergrootOverlay');\n    const inhoud=document.getElementById('vergrootInhoud');\n    const btn=document.getElementById('vergrootBtn');\n    const sluit=document.getElementById('vergrootSluit');\n    const setEl=document.getElementById('set');\n    if(!overlay||!inhoud||!setEl)return;\n    function toon(node){\n      inhoud.innerHTML='';\n      inhoud.appendChild(node);\n      overlay.style.display='flex';\n      document.body.style.overflow='hidden'; \/\/ achtergrond niet scrollen\n    }\n    function open(){\n      const houder=document.createElement('div');\n      houder.style.cssText='width:100%;display:flex;flex-direction:column;gap:10px;align-items:center';\n      setEl.querySelectorAll('.dsgn').forEach(d=\u003e{\n        if(d.style.display==='none')return; \/\/ verborgen 2e sticker (kenteken)\n        const svg=d.querySelector('svg');\n        if(!svg)return;\n        const wrap=document.createElement('div');\n        wrap.style.cssText='display:flex;align-items:center;justify-content:center;width:100%';\n        const kloon=svg.cloneNode(true);\n        kloon.removeAttribute('style');\n        kloon.style.display='block';\n        kloon.style.width='100%';\n        kloon.style.height='auto';\n        kloon.style.maxHeight='80vh';\n        kloon.style.filter='drop-shadow(0 8px 30px rgba(0,0,0,.35))';\n        wrap.appendChild(kloon);\n        houder.appendChild(wrap);\n      });\n      toon(houder);\n    }\n    \/\/ rakel-productfoto groot tonen\n    function openRakel(){\n      const bron=rakelAfbeeldingGroot||rakelAfbeelding;\n      if(!bron)return;\n      const img=document.createElement('img');\n      img.src=bron;\n      img.alt='Applicatie-rakel';\n      img.style.cssText='max-width:100%;max-height:80vh;object-fit:contain;display:block;border-radius:16px;filter:drop-shadow(0 8px 30px rgba(0,0,0,.35))';\n      toon(img);\n    }\n    function dicht(){\n      overlay.style.display='none';\n      document.body.style.overflow='';\n    }\n    if(btn)btn.addEventListener('click',(e)=\u003e{e.stopPropagation();open();});\n    \/\/ tik ook op de sticker zelf opent fullscreen\n    setEl.addEventListener('click',open);\n    \/\/ tik op de rakel-productfoto opent die groot\n    const rakelIc=document.getElementById('rakelIc');\n    if(rakelIc)rakelIc.addEventListener('click',(e)=\u003e{\n      if(!rakelAfbeelding)return; \/\/ alleen als er een foto is\n      e.stopPropagation(); \/\/ niet de rakel aan\/uit togglen\n      openRakel();\n    });\n    if(sluit)sluit.addEventListener('click',dicht);\n    overlay.addEventListener('click',(e)=\u003e{if(e.target===overlay)dicht();});\n    document.addEventListener('keydown',(e)=\u003e{if(e.key==='Escape'\u0026\u0026overlay.style.display==='flex')dicht();});\n  })();\n  \/\/ lees de categorie- en startdesign-instelling pas nu uit (window is dan zeker geladen)\n  try{\n    if(typeof window!=='undefined' \u0026\u0026 window.WIZARD_CATEGORIE){\n      CATEGORIE=window.WIZARD_CATEGORIE;\n    }\n  }catch(e){CATEGORIE=null;}\n  try{\n    if(typeof window!=='undefined' \u0026\u0026 window.WIZARD_STARTDESIGN \u0026\u0026 DESIGNS[window.WIZARD_STARTDESIGN]){\n      STARTDESIGN=window.WIZARD_STARTDESIGN;\n    }\n  }catch(e){STARTDESIGN=null;}\n  \/\/ zorg dat het actieve design binnen de gekozen categorie valt; anders het\n  \/\/ eerste zichtbare design nemen (voorkomt bv. Cauberg op een kenteken-pagina)\n  try{\n    const zichtbaar=zichtbareDesigns();\n    if(zichtbaar.length \u0026\u0026 zichtbaar.indexOf(state.design)===-1){\n      state.design=zichtbaar[0];\n      const d=DESIGNS[state.design];\n      if(d){state.bg=d.bg;state.bgNaam=d.bgNaam;state.ink=d.ink;state.inkNaam=d.inkNaam;state.font=d.font;}\n    }\n  }catch(e){}\n  \/\/ startdesign kan de keuze al vastzetten; pas daarna de standaardvlag toe\n  try{\n    const dStart=DESIGNS[(STARTDESIGN\u0026\u0026DESIGNS[STARTDESIGN])?STARTDESIGN:state.design];\n    if(dStart\u0026\u0026dStart.standaardVlag)state.flag=dStart.standaardVlag;\n  }catch(e){}\n\n  bouwDesignKaartjes();\n  bouwVlagKnoppen();\n  try{pasStartDesignToe();}catch(e){console.warn('Startdesign:',e);step=1;}\n  pasFontKeuzeAan();pasFormaatKeuzeAan();werkMaatLabelsBij();\n  laadFontKnopPreviews();\n  stappen();\n  laadDesign();\n  \/\/ fonts vast voorladen voor snelle productie-generatie\n  \/\/ fonts vast voorladen; na binnenkomst opnieuw renderen zodat de verticale\n  \/\/ plaatsing de echte kapitaalhoogte van het font gebruikt\n  Object.keys(FONTS).forEach(n=\u003elaadFont(n).then(f=\u003e{if(f)render();}));\n  \/\/ prijzen ophalen uit Shopify\n  laadPrijzen();\n\u003c\/script\u003e\n\n\u003c\/body\u003e","brand":"socialsticker","offers":[{"title":"Klein (6 x 40 mm)","offer_id":54417957519687,"sku":null,"price":5.95,"currency_code":"EUR","in_stock":true},{"title":"Middel (9 x 60 mm)","offer_id":54417958273351,"sku":null,"price":6.95,"currency_code":"EUR","in_stock":true},{"title":"Groot (12 x 80 mm)","offer_id":54417959059783,"sku":null,"price":7.95,"currency_code":"EUR","in_stock":true}],"thumbnail_url":"\/\/cdn.shopify.com\/s\/files\/1\/0549\/7264\/5612\/files\/Naam_vlagstickerscooter.png?v=1758897291","url":"https:\/\/socialsticker.lu\/products\/fietssticker-naam-vlag-links","provider":"socialsticker","version":"1.0","type":"link"}