`;
if(id==='editorial-grid')return '';
if(id==='midnight-glass')return '';
if(id==='emerald-gold')return '';
diff --git a/public/core/classic-offer-pdf-v1767.js b/public/core/classic-offer-pdf-v1767.js
index 5b07c7e..b93add4 100644
--- a/public/core/classic-offer-pdf-v1767.js
+++ b/public/core/classic-offer-pdf-v1767.js
@@ -112,7 +112,7 @@
.sun-v1767-group-label{grid-column:1/-1;font-size:10px;font-weight:900;letter-spacing:.07em;text-transform:uppercase;color:#7d858c;padding:6px 2px 1px}
#sunClientOfferPreview .sun-offer-page-canvas[data-sun-classic-cover="1"]{box-shadow:0 18px 50px rgba(31,35,36,.16)}
`;document.head.appendChild(style)}
- function groupPicker(){const grid=document.querySelector('.sun-v1764-offer-template-grid');if(!grid||grid.dataset.sunV1767Grouped==='1')return;const classic=[...grid.querySelectorAll('button')].filter(b=>CLASSIC_SET.has(b.dataset.v1764OfferTemplate)),archive=[...grid.querySelectorAll('button')].filter(b=>ARCHIVE_SET.has(b.dataset.v1764OfferTemplate));if(!classic.length&&!archive.length)return;grid.dataset.sunV1767Grouped='1';const label=t=>{const d=document.createElement('div');d.className='sun-v1767-group-label';d.textContent=t;return d};grid.innerHTML='';if(classic.length){grid.appendChild(label('Классические — как раньше'));classic.forEach(b=>grid.appendChild(b))}if(archive.length){grid.appendChild(label('Архивные шаблоны'));archive.forEach(b=>grid.appendChild(b))}}
+ function groupPicker(){const grid=document.querySelector('.sun-v1764-offer-template-grid');if(!grid||grid.dataset.sunV1767Grouped==='1')return;const classic=[...grid.querySelectorAll('button')].filter(b=>CLASSIC_SET.has(b.dataset.v1764OfferTemplate)),archive=[...grid.querySelectorAll('button')].filter(b=>ARCHIVE_SET.has(b.dataset.v1764OfferTemplate));if(!classic.length&&!archive.length)return;grid.dataset.sunV1767Grouped='1';const label=t=>{const d=document.createElement('div');d.className='sun-v1767-group-label';d.textContent=t;return d};const modern=[...grid.querySelectorAll('button')].filter(b=>!CLASSIC_SET.has(b.dataset.v1764OfferTemplate)&&!ARCHIVE_SET.has(b.dataset.v1764OfferTemplate));grid.innerHTML='';if(classic.length){grid.appendChild(label('Классические — как раньше'));classic.forEach(b=>grid.appendChild(b))}if(modern.length){grid.appendChild(label('Современная коллекция'));modern.forEach(b=>grid.appendChild(b))}if(archive.length){grid.appendChild(label('Дополнительные стили'));archive.forEach(b=>grid.appendChild(b))}}
function maintain(){installPreviewStyles();groupPicker()}
const observer=new MutationObserver(()=>setTimeout(maintain,0));if(document.documentElement)observer.observe(document.documentElement,{childList:true,subtree:true});if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',maintain,{once:true});else maintain();
diff --git a/public/core/performance.js b/public/core/performance.js
index 741e0c9..b3f6444 100644
--- a/public/core/performance.js
+++ b/public/core/performance.js
@@ -1,7 +1,7 @@
(()=>{
'use strict';
const VERSION='17.7.3';
- const RELEASE='20260918-trial-demo';
+ const RELEASE='20260918-proposal-quality';
const hasStoredSession=()=>{try{return Object.keys(localStorage).some(k=>/^sb-.*-auth-token$/i.test(k)&&String(localStorage.getItem(k)||'').length>20)}catch(_){return false}};
function installAuthBoot(){
diff --git a/public/core/proposal-layout.js b/public/core/proposal-layout.js
new file mode 100644
index 0000000..a118edb
--- /dev/null
+++ b/public/core/proposal-layout.js
@@ -0,0 +1,247 @@
+/* Client proposals. A4 layouts inspired by the original v17.6.7 covers.
+ * Coordinates are shared by preview and download; text is measured after local fonts load.
+ */
+(()=>{
+ 'use strict';
+ const W=1000,H=1414,M=70,BOTTOM=1310,SCALE=2.4;
+ const SANS='"Caterium Manrope",Arial,sans-serif';
+ const SERIF='"Caterium Playfair",Georgia,serif';
+ const ITALIC='"Caterium Playfair Italic",Georgia,serif';
+ const definitions=[
+ ['light','Минимализм','split','#fffdf8','#20362d','#98713b','serif','rows'],
+ ['midnight-glass','Luxury Dark','night','#111916','#f6f1e5','#d4b272','serif','rows'],
+ ['editorial-grid','Editorial Magazine','editorial','#f6f3ec','#183d30','#94743c','serif','cards'],
+ ['warm-sun','Warm Sun','sun','#fff4d8','#51361e','#9a5b1b','serif','rows'],
+ ['bento-cards','Bento Cards','bento','#f3f2eb','#27382b','#8b6022','sans','cards'],
+ ['event-story','Event Story','story','#f4ece0','#523a2b','#92643c','serif','rows'],
+ ['black-gold','Food First','photo','#10100e','#fff7e9','#d8b671','serif','cards'],
+ ['personal-letter','Personal Letter','letter','#f7f1e6','#473b2d','#8b673b','italic','rows'],
+ ['event-ticket','Event Ticket','ticket','#eef2f3','#203f53','#38677a','sans','rows'],
+ ['solar-experience','Solar Experience','solar','#ffd54f','#28392c','#77521f','sans','cards'],
+ ['midnight-compact','Ночной минимализм','compact','#122630','#edf4f4','#9cbec4','sans','compact'],
+ ['emerald-gold','Изумрудная классика','frame','#123b31','#f8f2df','#d1b578','serif','rows'],
+ ['neon-emerald','Изумрудный акцент','neon-vertical','#071f1d','#edfff6','#7debaf','sans','compact'],
+ ['cream-elegance','Кремовая классика','arch','#faf3e6','#35432e','#917445','serif','cards'],
+ ['neon-menu','Неоновое меню','neon','#111a15','#f1ffef','#a1ed92','sans','compact'],
+ ['emerald-circles','Изумрудные круги','circles','#102e2c','#f0f6ee','#d3b779','serif','cards'],
+ ['midnight-checklist','Тёмный чек-лист','checklist','#12241d','#f1f5ea','#d7c593','sans','rows'],
+ ['gourmet-hero','Гастро-витрина','gallery','#181611','#fff6e6','#dbb775','serif','cards'],
+ ['diamond-gold','Изумруд и золото','diamond','#133329','#fff6de','#dabe7b','serif','rows'],
+ ['premium-dark','Премиум тёмный','panorama','#141820','#f7f2e9','#cfb18a','sans','rows'],
+ ['premium-emerald','Премиум изумрудный','botanical','#0e382e','#f5f2df','#b8d19c','italic','cards']
+ ];
+ const THEMES=Object.fromEntries(definitions.map(([id,name,cover,bg,ink,accent,type,menu])=>[id,{id,name,cover,bg,ink,accent,type,menu,dark:!['light','editorial-grid','warm-sun','bento-cards','event-story','personal-letter','event-ticket','solar-experience','cream-elegance'].includes(id)}]));
+ const IDs=Object.keys(THEMES);
+ const number=v=>Number.isFinite(Number(v))?Number(v):0;
+ const money=v=>Math.round(number(v)).toLocaleString('ru-RU')+' ₽';
+ const qty=v=>number(v).toLocaleString('ru-RU',{maximumFractionDigits:3});
+ const date=v=>{if(!v)return '';const d=new Date(String(v)+'T12:00:00');return Number.isNaN(d.getTime())?String(v):d.toLocaleDateString('ru-RU',{day:'numeric',month:'long',year:'numeric'})};
+ let fontsPromise;
+ async function ready(){
+ if(!fontsPromise)fontsPromise=(async()=>{
+ if(!window.FontFace||!document.fonts)return;
+ const defs=[['Caterium Manrope','Manrope.ttf','200 800'],['Caterium Playfair','PlayfairDisplay.ttf','400 900'],['Caterium Playfair Italic','PlayfairDisplay-Italic.ttf','400 900']];
+ await Promise.all(defs.map(async([family,file,weight])=>{
+ const face=new FontFace(family,`url("${new URL('fonts/'+file,document.baseURI)}")`,{weight});
+ try{await Promise.race([face.load(),new Promise((_,reject)=>setTimeout(()=>reject(new Error('Font timeout')),8000))]);document.fonts.add(face)}catch(e){console.warn('Proposal font fallback:',family,e.message)}
+ }));
+ await document.fonts.ready;
+ })();
+ return fontsPromise;
+ }
+ function loadImage(src){return new Promise(resolve=>{
+ if(!/^data:image\/(?:png|jpe?g|webp);base64,/i.test(String(src||'')))return resolve(null);
+ const image=new Image();let done=false;
+ const finish=v=>{if(done)return;done=true;clearTimeout(timer);resolve(v)};
+ const timer=setTimeout(()=>finish(null),4000);image.onload=()=>finish(image);image.onerror=()=>finish(null);image.src=src;
+ })}
+ function split(ctx,value,width){
+ const out=[];
+ for(const para of String(value??'').split(/\r?\n/)){
+ if(!para.trim()){out.push('');continue}
+ let line='';
+ for(const word of para.trim().split(/\s+/)){
+ if(ctx.measureText((line?line+' ':'')+word).width<=width){line+=(line?' ':'')+word;continue}
+ if(line){out.push(line);line=''}
+ for(const char of word){if(line&&ctx.measureText(line+char).width>width){out.push(line);line=''}line+=char}
+ }
+ if(line)out.push(line);
+ }
+ return out;
+ }
+ const defaults={showClientName:true,showDate:true,showGuests:true,showGallery:true,showPriceBreakdown:true,showAmountPerGuest:true,showBoxCount:true,showControl:true,showExtras:true,showFooterNote:true,showFinalPhoto:true,metricMode:'weight',texts:{}};
+ function settings(s){return {...defaults,...s.pdfSettings,texts:{...defaults.texts,...s.pdfSettings?.texts,...s.offerOverrides?.texts}}}
+ function painter(canvas,theme){
+ const ctx=canvas.getContext('2d',{alpha:false});const scale=canvas.width/W;ctx.setTransform(scale,0,0,scale,0,0);
+ const boxes=canvas.__proposalLayout||[];canvas.__proposalLayout=boxes;
+ const body=(size=19,weight=400)=>`${weight} ${size}px ${SANS}`;
+ const display=(size=54)=>`${theme.type==='sans'?700:500} ${size}px ${theme.type==='sans'?SANS:theme.type==='italic'?ITALIC:SERIF}`;
+ function rect(x,y,w,h,color,r=0){ctx.fillStyle=color;ctx.beginPath();ctx.roundRect(x,y,w,h,r);ctx.fill()}
+ function line(x,y,w,color=theme.accent){rect(x,y,w,1,color)}
+ function lines(value,w,font){ctx.font=font;return split(ctx,value,w)}
+ function write(value,x,y,w,{size=19,weight=400,color=theme.ink,font=body(size,weight),lh=size*1.42,align='left',role='text'}={}){
+ const values=Array.isArray(value)?value:lines(value,w,font);ctx.save();ctx.font=font;ctx.textBaseline='top';ctx.textAlign=align;ctx.fillStyle=color;
+ const xx=align==='right'?x+w:align==='center'?x+w/2:x;
+ values.forEach((v,i)=>ctx.fillText(v,xx,y+i*lh));ctx.restore();
+ boxes.push({x,y,w,h:values.length*lh,role,text:values.join('\n'),font});return values.length*lh;
+ }
+ function fit(value,x,y,w,h,{size=54,min=18,font,displayFont=true,...opts}={}){
+ let f,ls,lh;
+ do{f=font|| (displayFont?display(size):body(size,opts.weight||500));lh=size*1.27;ls=lines(value,w,f);if(ls.length*lh<=h)break;size-=1}while(size>=min);
+ // Cover copy is repeated in the flowing details when unusually long.
+ if(ls.length*lh>h){canvas.__proposalOverflow=canvas.__proposalOverflow||[];canvas.__proposalOverflow.push(String(value));return write('Подробности на следующих страницах',x,y,w,{size:18,lh:25,...opts})}
+ return write(ls,x,y,w,{...opts,font:f,size,lh});
+ }
+ function photo(img,x,y,w,h,{radius=0,shape='rect',contain=false}={}){
+ ctx.save();ctx.beginPath();if(shape==='circle')ctx.ellipse(x+w/2,y+h/2,w/2,h/2,0,0,Math.PI*2);else if(shape==='diamond'){ctx.moveTo(x+w/2,y);ctx.lineTo(x+w,y+h/2);ctx.lineTo(x+w/2,y+h);ctx.lineTo(x,y+h/2);ctx.closePath()}else ctx.roundRect(x,y,w,h,radius);ctx.clip();
+ rect(x,y,w,h,theme.dark?'#263e34':'#e9e3d7');
+ if(img){const scale=(contain?Math.min:Math.max)(w/img.width,h/img.height);ctx.drawImage(img,x+(w-img.width*scale)/2,y+(h-img.height*scale)/2,img.width*scale,img.height*scale)}
+ ctx.restore();
+ }
+ return {ctx,body,display,rect,line,lines,write,fit,photo};
+ }
+ function page(t,kind){const c=document.createElement('canvas');c.width=W*(t.scale||SCALE);c.height=Math.round(H*(t.scale||SCALE));c.dataset.sunProposalTemplate=t.id;c.dataset.sunProposalPage=kind;const d=painter(c,t);d.rect(0,0,W,H,t.bg);return {c,...d}}
+ function brand(d,s,t,logo,{x=M,y=60,w=860}={}){
+ if(logo){d.rect(x,y-4,78,58,'#fffdf6',8);d.photo(logo,x+6,y,66,50,{contain:true});x+=94;w-=94}
+ d.fit(s.brandName||'Моя компания',x,y+6,w,56,{size:24,min:15,displayFont:false,weight:700});
+ }
+ function facts(s,cfg){return [cfg.showDate?[date(s.date),s.time].filter(Boolean).join(' · '):'',cfg.showGuests&&number(s.guests)?`${qty(s.guests)} гостей`:''].filter(Boolean)}
+ function cover(s,t,images,logo,cfg){
+ const d=page(t,'cover'),hero=images.find(Boolean),hero2=images.filter(Boolean)[1]||hero,hero3=images.filter(Boolean)[2]||hero;
+ const title=s.event||'Ваше мероприятие',client=cfg.showClientName?s.client||'':'',eyebrow=cfg.texts.proposalLabel||'Индивидуальное предложение';
+ const ink=t.ink,accent=t.accent;
+ const heading=(x,y,w,h=250,size=64)=>d.fit(title,x,y,w,h,{size});
+ const sub=(x,y,w,h=94)=>d.fit(client,x,y,w,h,{size:25,displayFont:false});
+ const label=(x,y,w=860)=>d.fit(eyebrow,x,y,w,54,{size:18,displayFont:false,color:accent});
+ const fact=(x,y,w=860)=>d.fit(facts(s,cfg).join(' / '),x,y,w,65,{size:21,displayFont:false});
+ const note=(x,y,w,h=140)=>d.fit(cfg.texts.heroNote||'Меню, подобранное для вашего события.',x,y,w,h,{size:22,displayFont:false,color:ink});
+ const total=(x,y,w=400)=>{d.fit(cfg.texts.totalPriceTitle||'Итоговая стоимость',x,y,w,50,{size:17,displayFont:false,color:accent});d.fit(money(s.pricing?.total),x,y+50,w,100,{size:52})};
+ if(!['night','photo'].includes(t.cover))brand(d,s,t,logo);
+ switch(t.cover){
+ case 'split':
+ label(M,198,400);heading(M,265,414,290,62);sub(M,582,395);d.line(M,718,370);note(M,758,380);d.photo(hero,520,195,410,760,{radius:180});fact(M,1010);total(M,1120);break;
+ case 'night':
+ d.photo(hero,482,0,518,H);d.rect(0,0,482,H,t.bg);brand(d,s,t,logo,{w:340});label(M,235,350);heading(M,310,350,310,58);sub(M,650,345);fact(M,835,345);d.line(M,1000,340);total(M,1050,350);break;
+ case 'editorial':
+ label(M,180);heading(M,244,840,200,72);d.line(M,478,860);d.photo(hero,414,526,516,610);d.write('01',M,530,230,{size:54,font:d.display(54),color:accent});sub(M,638,280,145);fact(M,825,290);total(M,999,310);break;
+ case 'sun':
+ d.rect(758,180,172,172,'#f2c55b',86);label(M,200,550);heading(M,280,630,250,64);sub(M,562,780);d.photo(hero,320,698,610,390,{radius:180});fact(M,649,850);total(M,1140,530);break;
+ case 'bento':
+ label(M,180);heading(M,255,850,200,67);sub(M,480,800);d.photo(hero,M,610,556,430,{radius:26});d.photo(hero2,650,610,280,202,{radius:24});d.photo(hero3,650,838,280,202,{radius:24});fact(M,1080);total(M,1160,740);break;
+ case 'story':
+ label(M,182);heading(M,260,835,200,68);sub(M,485,820);d.line(M,635,860);['Меню','Подготовка','Ваше событие'].forEach((v,i)=>{const x=M+i*310;d.rect(x,627,16,16,accent,8);d.write(v,x,664,240,{size:18})});d.photo(hero,M,735,860,360);fact(M,1140,410);total(553,1130,377);break;
+ case 'photo':{
+ d.photo(hero,0,0,W,H);const g=d.ctx.createLinearGradient(0,0,0,H);g.addColorStop(0,'rgba(0,0,0,.82)');g.addColorStop(.48,'rgba(0,0,0,.24)');g.addColorStop(1,'rgba(0,0,0,.95)');d.ctx.fillStyle=g;d.ctx.fillRect(0,0,W,H);brand(d,s,t,logo);label(M,215);heading(M,290,800,270,74);sub(M,620,800);fact(M,1010);total(M,1120,820);break;}
+ case 'letter':
+ d.rect(44,162,912,1125,'#fffcf5',4);label(94,218,700);d.fit(client?`${client},`:'Дорогие гости,',94,308,760,165,{size:56});d.write('Предложение для вашего мероприятия',94,496,730,{size:22});heading(94,549,730,170,44);note(94,761,470,155);d.photo(hero,690,769,210,210,{shape:'circle'});fact(94,1010,790);total(94,1100,570);break;
+ case 'ticket':
+ d.rect(M,190,860,1080,'#fbfcfa',18);d.rect(740,190,190,1080,'#dbe8ea',18);d.ctx.save();d.ctx.setLineDash([7,9]);d.ctx.strokeStyle=accent;d.ctx.beginPath();d.ctx.moveTo(716,215);d.ctx.lineTo(716,1240);d.ctx.stroke();d.ctx.restore();label(106,246,570);heading(106,329,560,270,59);sub(106,632,550,115);fact(106,790,550);d.photo(hero,106,899,255,200,{radius:10});total(390,946,280);d.write('МЕНЮ',762,268,150,{size:17,weight:700});if(cfg.showDate){d.fit(date(s.date),765,341,140,180,{size:26,displayFont:false});d.fit(s.time||'',765,570,140,80,{size:34,displayFont:false})}break;
+ case 'solar':
+ label(M,205);heading(M,276,460,300,64);d.photo(hero,571,390,359,359,{shape:'circle'});sub(M,649,435,150);d.line(M,860,860);fact(M,913);d.rect(M,1040,860,238,'#fff1b5',30);total(106,1080,780);break;
+ case 'compact':
+ label(M,212);heading(M,300,850,250,70);sub(M,590,820);fact(M,760);d.line(M,867,860);d.photo(hero,550,935,380,330);total(M,980,420);break;
+ case 'frame':
+ d.ctx.strokeStyle=accent;d.ctx.lineWidth=1;d.ctx.strokeRect(38,158,924,1140);label(96,227,808);d.fit(title,96,313,808,255,{size:67,align:'center'});d.fit(client,96,604,808,90,{size:24,displayFont:false,align:'center'});d.photo(hero,240,750,520,300,{radius:160});fact(96,1103,810);total(96,1175,810);break;
+ case 'neon-vertical':
+ d.rect(M,218,12,910,accent);label(114,218,815);heading(114,300,800,240,72);sub(114,571,780);d.photo(hero,114,750,390,390,{radius:195});d.photo(hero2,536,750,390,390,{radius:195});fact(114,668,800);total(114,1170,790);break;
+ case 'arch':
+ label(M,189);d.fit(title,M,265,860,205,{size:65,align:'center'});d.fit(client,M,490,860,94,{size:24,displayFont:false,align:'center'});d.photo(hero,244,648,512,445,{radius:[250,250,10,10]});fact(M,1140,420);total(555,1136,375);break;
+ case 'neon':
+ d.rect(M,190,860,328,accent,24);d.fit(eyebrow,105,222,790,54,{size:18,displayFont:false,color:'#142019'});d.fit(title,105,290,790,200,{size:62,color:'#142019'});sub(M,558,800);fact(M,660);d.photo(hero,M,785,520,425,{radius:24});d.photo(hero2,616,785,314,205,{radius:24});total(616,1040,314);break;
+ case 'circles':
+ label(M,213);heading(M,291,820,225,68);sub(M,550,820);d.photo(hero,M,731,400,400,{shape:'circle'});d.photo(hero2,513,711,256,256,{shape:'circle'});d.photo(hero3,701,919,229,229,{shape:'circle'});fact(M,646);total(M,1165,800);break;
+ case 'checklist':
+ label(M,212);heading(M,294,850,240,67);sub(M,568,810);fact(M,680);d.line(M,786,860);(s.items||[]).slice(0,3).forEach((it,i)=>{const y=843+i*99;d.write(String(i+1).padStart(2,'0'),M,y,70,{size:24,color:accent});d.fit(it.name,170,y,750,77,{size:24,displayFont:false})});total(M,1170,810);break;
+ case 'gallery':
+ label(M,203);heading(M,280,840,210,68);sub(M,528,810);[hero,hero2,hero3].forEach((im,i)=>d.photo(im,M+i*294,707+i*37,272,355,{radius:136}));fact(M,626);total(M,1160,830);break;
+ case 'diamond':
+ label(M,200);heading(M,284,840,220,66);sub(M,537,810);fact(M,648);d.photo(hero,430,735,500,455,{shape:'diamond'});d.write('МЕНЮ',M,879,225,{size:18,color:accent});total(M,969,330);break;
+ case 'panorama':
+ d.photo(hero,0,176,W,467);label(M,701);heading(M,778,840,220,65);sub(M,1040,430,140);fact(M,1209,410);total(550,1135,380);break;
+ case 'botanical':
+ label(M,199,460);heading(M,284,470,350,64);d.photo(hero,590,205,340,590,{radius:170});sub(M,686,460,155);d.line(M,901,860);note(M,958,475,140);fact(M,1150,445);total(568,1119,362);break;
+ }
+ return d.c;
+ }
+ function composition(item){const values=item.compositionTotal?.length?item.compositionTotal:item.composition||[];return (Array.isArray(values)?values:[values]).map(v=>typeof v==='string'?v:v?.name||'').filter(Boolean).join(' · ')}
+ async function renderPages(s){
+ const cfg=settings(s),items=s.items||[],t={...(THEMES[s.offerTemplateId]||THEMES.light),scale:items.length>24?2:SCALE},cache=new Map();
+ const img=src=>{if(!src)return Promise.resolve(null);if(!cache.has(src))cache.set(src,loadImage(src));return cache.get(src)};
+ await ready();
+ const [logo,images,gallery]=await Promise.all([img(s.logo),Promise.all(items.map(i=>img((i.photoData||i.photo)===s.logo?'':i.photoData||i.photo))),Promise.all((s.finalGallery||[]).map(img))]);
+ const covers=[cover(s,t,images,logo,cfg)],pages=[...covers];let d,y;
+ const muted=t.dark?'#c0cabf':'#686a5f',lineColor=t.dark?'#426055':'#d9d2c4',panel=t.dark?'#203b30':'#ffffff';
+ // A sunny cover is paired with warm paper inside, making long menus easier to read.
+ const inner={...t,bg:t.id==='solar-experience'?'#fff9e8':t.bg};
+ function newPage(title){d=page(inner,'content');pages.push(d.c);brand(d,s,t,logo,{y:48});d.line(M,135,860,lineColor);y=172;if(title){y+=d.write(title,M,y,860,{size:36,font:d.display(36),lh:46});y+=28}}
+ function ensure(h,title){if(!d||y+h>BOTTOM)newPage(title)}
+ function flow(value,{size=19,color=t.ink,font,role='text',gap=20}={}){
+ if(!String(value||'').trim())return;
+ ensure(size*1.45+gap);const lines=d.lines(value,860,font||d.body(size));let pos=0;const lh=size*1.45;
+ while(pos
`;
if(id==='editorial-grid')return '';
if(id==='midnight-glass')return '';
if(id==='emerald-gold')return '';
return '';
}
function pickerHtml(){
- const current=activeTemplateId();return `