feat: add 2 new templates modeled on the referenced menu.furset.ru design

User pointed at https://menu.furset.ru/view/23855347 as a design they
like and asked for a couple more templates in that direction. Added:

- premium-dark: near-black background, warm gold accents, real
  line-drawn icon badges (calendar/people/box -- not emoji) for the
  date/guests/boxes stats, bullet-point value props under the title,
  minimal flat menu list -- closely matching that reference's visual
  language instead of the card-heavy style of the existing templates.
- premium-emerald: the same layout in an emerald-green palette, as
  the second "couple" of designs requested, sharing the cover code
  with premium-dark and only differing by PALETTES entry.

Both plug into the existing shared renderContentPages engine, so they
get proper multi-page menu + pricing pages for free, consistent with
all 6 existing signature templates. New icon-drawing helpers
(iconBadge/iconCalendar/iconPeople/iconGauge/iconBox, statBadgeRow,
bulletList) live in the shared helper section for reuse.

Verified locally: both render in <70ms combined, produce 3 pages each
for a normal order, and hold up under the same adversarial-data pass
used for the other 6 (long names, 350 guests, seven-figure price,
item with no photo/price/category) -- no overlap, no crashes, generous
ellipsis truncation throughout. Fixed one real bug found while
testing: the date value in the stat badge ("8 августа 2026 г.") was
getting ellipsis-truncated at font-size 20px; reduced to 16px so it
fits cleanly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
pavlov346346-source 2026-09-16 11:11:43 +03:00
parent 28fd97bcf3
commit 44bf5e9af1
2 changed files with 38 additions and 6 deletions

View File

@ -4227,7 +4227,9 @@ window.SUN_LEGACY_CATALOG_V175=[{"id":"1","name":"Фуршетный бокс
{id:'emerald-circles',name:'Изумрудные круги',desc:'Тёмно-изумрудная презентация с круглыми фото блюд и списком категорий.',thumb:''}, {id:'emerald-circles',name:'Изумрудные круги',desc:'Тёмно-изумрудная презентация с круглыми фото блюд и списком категорий.',thumb:''},
{id:'midnight-checklist',name:'Тёмный чек-лист',desc:'Компактный тёмно-зелёный макет: нумерованное меню по категориям и фотополоса блюд.',thumb:''}, {id:'midnight-checklist',name:'Тёмный чек-лист',desc:'Компактный тёмно-зелёный макет: нумерованное меню по категориям и фотополоса блюд.',thumb:''},
{id:'gourmet-hero',name:'Гастро-витрина',desc:'Крупный фото-хиро в духе лендинга, вкладки категорий и карточки блюд.',thumb:''}, {id:'gourmet-hero',name:'Гастро-витрина',desc:'Крупный фото-хиро в духе лендинга, вкладки категорий и карточки блюд.',thumb:''},
{id:'diamond-gold',name:'Изумруд и золото',desc:'Тёмно-зелёный дизайн с золотыми акцентами, нумерованной фотосеткой и блоком скидки.',thumb:''} {id:'diamond-gold',name:'Изумруд и золото',desc:'Тёмно-зелёный дизайн с золотыми акцентами, нумерованной фотосеткой и блоком скидки.',thumb:''},
{id:'premium-dark',name:'Премиум тёмный',desc:'Строгий тёмный дизайн с золотыми иконками-бейджами дат и гостей, минималистичным списком меню.',thumb:''},
{id:'premium-emerald',name:'Премиум изумрудный',desc:'Тот же строгий тёмный дизайн с иконками-бейджами, но в изумрудно-зелёной палитре.',thumb:''}
]; ];
const esc=window.SunSafe.escapeHTML; const esc=window.SunSafe.escapeHTML;

View File

@ -5,7 +5,7 @@
const VERSION='18.1.0'; const VERSION='18.1.0';
const RELEASE='20260916-v18-1-0-signature-offer-pdf-polish'; const RELEASE='20260916-v18-1-0-signature-offer-pdf-polish';
const W=1000,H=1414,SCALE=1.6,M=54; const W=1000,H=1414,SCALE=1.6,M=54;
const SIGNATURE_IDS=['cream-elegance','neon-menu','emerald-circles','midnight-checklist','gourmet-hero','diamond-gold']; const SIGNATURE_IDS=['cream-elegance','neon-menu','emerald-circles','midnight-checklist','gourmet-hero','diamond-gold','premium-dark','premium-emerald'];
const SIGNATURE_SET=new Set(SIGNATURE_IDS); const SIGNATURE_SET=new Set(SIGNATURE_IDS);
const INNER_THEME={ const INNER_THEME={
'cream-elegance':'light', 'cream-elegance':'light',
@ -13,7 +13,9 @@
'emerald-circles':'midnight-glass', 'emerald-circles':'midnight-glass',
'midnight-checklist':'midnight-glass', 'midnight-checklist':'midnight-glass',
'gourmet-hero':'black-gold', 'gourmet-hero':'black-gold',
'diamond-gold':'black-gold' 'diamond-gold':'black-gold',
'premium-dark':'black-gold',
'premium-emerald':'midnight-glass'
}; };
const PALETTES={ const PALETTES={
'cream-elegance':{bg:'#faf3e6',paper:'#ffffff',ink:'#22281f',muted:'#726c5f',accent:'#8f8536',accent2:'#4f6a3f',deep:'#274a34',line:'#ecdfc4',foot:'#faf3e6'}, 'cream-elegance':{bg:'#faf3e6',paper:'#ffffff',ink:'#22281f',muted:'#726c5f',accent:'#8f8536',accent2:'#4f6a3f',deep:'#274a34',line:'#ecdfc4',foot:'#faf3e6'},
@ -21,7 +23,9 @@
'emerald-circles':{bg:'#08181c',paper:'#0d2226',ink:'#eef6f2',muted:'#94aca6',accent:'#c9a24a',accent2:'#2f9e78',deep:'#0a2a26',line:'#1f4642',foot:'#08181c'}, 'emerald-circles':{bg:'#08181c',paper:'#0d2226',ink:'#eef6f2',muted:'#94aca6',accent:'#c9a24a',accent2:'#2f9e78',deep:'#0a2a26',line:'#1f4642',foot:'#08181c'},
'midnight-checklist':{bg:'#06170f',paper:'#0b2417',ink:'#eef6ee',muted:'#8fac97',accent:'#dfb957',accent2:'#3f8f5c',deep:'#123822',line:'#1f4a30',foot:'#06170f'}, 'midnight-checklist':{bg:'#06170f',paper:'#0b2417',ink:'#eef6ee',muted:'#8fac97',accent:'#dfb957',accent2:'#3f8f5c',deep:'#123822',line:'#1f4a30',foot:'#06170f'},
'gourmet-hero':{bg:'#0a0a09',paper:'#141311',ink:'#f5f1e8',muted:'#a89f8e',accent:'#d7ac55',accent2:'#8a6a2c',deep:'#1c1a15',line:'#3a352a',foot:'#0a0a09'}, 'gourmet-hero':{bg:'#0a0a09',paper:'#141311',ink:'#f5f1e8',muted:'#a89f8e',accent:'#d7ac55',accent2:'#8a6a2c',deep:'#1c1a15',line:'#3a352a',foot:'#0a0a09'},
'diamond-gold':{bg:'#071510',paper:'#0d251c',ink:'#f0f5ee',muted:'#93ab9c',accent:'#e0b95c',accent2:'#2f9e6f',deep:'#123d29',line:'#204b34',foot:'#071510'} 'diamond-gold':{bg:'#071510',paper:'#0d251c',ink:'#f0f5ee',muted:'#93ab9c',accent:'#e0b95c',accent2:'#2f9e6f',deep:'#123d29',line:'#204b34',foot:'#071510'},
'premium-dark':{bg:'#0a0d12',paper:'#12161d',ink:'#f5f6f8',muted:'#8b93a1',accent:'#e0a545',accent2:'#c9863a',deep:'#171c24',line:'#252b35',foot:'#0a0d12'},
'premium-emerald':{bg:'#0a1210',paper:'#121d19',ink:'#f2f8f5',muted:'#8fa79c',accent:'#3fcf8e',accent2:'#2a9d6c',deep:'#17241f',line:'#233830',foot:'#0a1210'}
}; };
// Distinctive Cyrillic-friendly type pairing per polished template (falls back to Georgia/Arial elsewhere). // Distinctive Cyrillic-friendly type pairing per polished template (falls back to Georgia/Arial elsewhere).
@ -31,7 +35,9 @@
'emerald-circles':{display:'"Playfair Display",Georgia,serif',label:'"Montserrat",Arial,sans-serif'}, 'emerald-circles':{display:'"Playfair Display",Georgia,serif',label:'"Montserrat",Arial,sans-serif'},
'midnight-checklist':{display:'"Unbounded",Arial,sans-serif',label:'"Manrope",Arial,sans-serif'}, 'midnight-checklist':{display:'"Unbounded",Arial,sans-serif',label:'"Manrope",Arial,sans-serif'},
'gourmet-hero':{display:'"Unbounded",Arial,sans-serif',label:'"Manrope",Arial,sans-serif'}, 'gourmet-hero':{display:'"Unbounded",Arial,sans-serif',label:'"Manrope",Arial,sans-serif'},
'diamond-gold':{display:'"Playfair Display",Georgia,serif',label:'"Montserrat",Arial,sans-serif'} 'diamond-gold':{display:'"Playfair Display",Georgia,serif',label:'"Montserrat",Arial,sans-serif'},
'premium-dark':{display:'"Unbounded",Arial,sans-serif',label:'"Manrope",Arial,sans-serif'},
'premium-emerald':{display:'"Unbounded",Arial,sans-serif',label:'"Manrope",Arial,sans-serif'}
}; };
function fontsFor(id){return FONT_STACKS[id]||{display:'Georgia,serif',label:'Arial,sans-serif'}} function fontsFor(id){return FONT_STACKS[id]||{display:'Georgia,serif',label:'Arial,sans-serif'}}
function ensureFontLink(){ function ensureFontLink(){
@ -69,6 +75,14 @@
function eventTitle(s){const event=String(s.event||'Персональное предложение').trim();return String(s.client||'').trim()?'Предложение для '+String(s.client).trim():event} function eventTitle(s){const event=String(s.event||'Персональное предложение').trim();return String(s.client||'').trim()?'Предложение для '+String(s.client).trim():event}
function footer(ctx,p,page,total,brandName='Солнце Кейтеринг',fonts){const lf=fonts?.label||'Arial';line(ctx,M,H-48,W-M,H-48,p.line,1);text(ctx,String(brandName||'Солнце Кейтеринг')+' · предложение клиенту',M,H-34,500,16,{font:`500 10px ${lf}`,color:p.muted,maxLines:1});text(ctx,String(page)+' / '+String(total),W-M,H-34,100,16,{font:`500 10px ${lf}`,color:p.muted,align:'right',maxLines:1})} function footer(ctx,p,page,total,brandName='Солнце Кейтеринг',fonts){const lf=fonts?.label||'Arial';line(ctx,M,H-48,W-M,H-48,p.line,1);text(ctx,String(brandName||'Солнце Кейтеринг')+' · предложение клиенту',M,H-34,500,16,{font:`500 10px ${lf}`,color:p.muted,maxLines:1});text(ctx,String(page)+' / '+String(total),W-M,H-34,100,16,{font:`500 10px ${lf}`,color:p.muted,align:'right',maxLines:1})}
function iconCircle(ctx,cx,cy,r,glyph,{fill,stroke,glyphColor='#fff',size=20}={}){roundRect(ctx,cx-r,cy-r,r*2,r*2,r,fill,stroke,1.4);text(ctx,glyph,cx,cy-size/2-1,r*2,size+4,{font:`${size}px Arial`,color:glyphColor,align:'center',maxLines:1})} function iconCircle(ctx,cx,cy,r,glyph,{fill,stroke,glyphColor='#fff',size=20}={}){roundRect(ctx,cx-r,cy-r,r*2,r*2,r,fill,stroke,1.4);text(ctx,glyph,cx,cy-size/2-1,r*2,size+4,{font:`${size}px Arial`,color:glyphColor,align:'center',maxLines:1})}
// Small line-drawn icon badges (calendar/people/gauge/box) for the "premium" templates, so those stat cards use real iconography instead of emoji.
function iconBadge(ctx,x,y,size,p,draw){roundRect(ctx,x,y,size,size,size*0.28,p.deep,p.accent,1.4);ctx.save();ctx.translate(x+size/2,y+size/2);ctx.strokeStyle=p.accent;ctx.fillStyle=p.accent;ctx.lineWidth=Math.max(1.6,size*0.05);ctx.lineCap='round';ctx.lineJoin='round';draw(ctx,size*0.32);ctx.restore()}
function iconCalendar(ctx,r){roundRect(ctx,-r,-r*0.75,r*2,r*1.65,r*0.22,null,ctx.strokeStyle,ctx.lineWidth);ctx.beginPath();ctx.moveTo(-r,-r*0.3);ctx.lineTo(r,-r*0.3);ctx.stroke();ctx.beginPath();ctx.moveTo(-r*0.5,-r*1.05);ctx.lineTo(-r*0.5,-r*0.55);ctx.stroke();ctx.beginPath();ctx.moveTo(r*0.5,-r*1.05);ctx.lineTo(r*0.5,-r*0.55);ctx.stroke()}
function iconPeople(ctx,r){ctx.beginPath();ctx.arc(0,-r*0.4,r*0.4,0,Math.PI*2);ctx.stroke();ctx.beginPath();ctx.arc(0,r*0.75,r*0.82,Math.PI,0,true);ctx.stroke()}
function iconGauge(ctx,r){ctx.beginPath();ctx.arc(0,r*0.15,r*0.85,Math.PI,0);ctx.stroke();ctx.beginPath();ctx.moveTo(0,r*0.15);ctx.lineTo(r*0.48,-r*0.32);ctx.stroke();ctx.beginPath();ctx.arc(0,r*0.15,r*0.1,0,Math.PI*2);ctx.fill()}
function iconBox(ctx,r){roundRect(ctx,-r,-r*0.75,r*2,r*1.55,r*0.16,null,ctx.strokeStyle,ctx.lineWidth);ctx.beginPath();ctx.moveTo(-r,-r*0.05);ctx.lineTo(r,-r*0.05);ctx.stroke();ctx.beginPath();ctx.moveTo(0,-r*0.75);ctx.lineTo(0,r*0.8);ctx.stroke()}
function statBadgeRow(ctx,p,f,x,y,w,h,cards){const gap=14,cw=(w-gap*(cards.length-1))/cards.length;const bs=Math.min(52,h*0.42);cards.forEach(([draw,value,label],i)=>{const xx=x+i*(cw+gap);roundRect(ctx,xx,y,cw,h,20,p.paper,p.line,1);iconBadge(ctx,xx+18,y+18,bs,p,draw);text(ctx,value,xx+18+bs+10,y+18+bs/2-12,cw-18-bs-10-12,24,{font:`700 16px ${f.display}`,color:'#fff',maxLines:1});text(ctx,label,xx+18,y+h-30,cw-36,16,{font:`500 12px ${f.label}`,color:p.muted,maxLines:1})})}
function bulletList(ctx,p,f,x,y,w,lineH,items,color){let yy=y;items.forEach(t=>{ctx.save();ctx.fillStyle=p.accent;ctx.beginPath();ctx.arc(x+4,yy+9,4,0,Math.PI*2);ctx.fill();ctx.restore();const used=text(ctx,t,x+20,yy,w-20,18,{font:`500 14px ${f.label}`,color:color||p.ink,maxLines:2});yy+=Math.max(lineH,used+6)});return yy-y}
function factChips(ctx,s,p,x,y,w,{dark=true,fonts}={}){const lf=fonts?.label||'Arial';const facts=[];if(s.date)facts.push(dateText(s.date));if(s.guests)facts.push(String(s.guests)+' '+plural(s.guests,'гость','гостя','гостей'));if(s.time)facts.push('Доставка '+String(s.time));const gap=8,cw=(w-gap*Math.max(0,facts.length-1))/Math.max(1,facts.length);facts.forEach((f,i)=>{const xx=x+i*(cw+gap);roundRect(ctx,xx,y,cw,44,13,dark?'rgba(255,255,255,.06)':p.paper,dark?'rgba(255,255,255,.2)':p.line);text(ctx,f,xx+cw/2,y+14,cw-14,17,{font:`600 12px ${lf}`,color:dark?'#f4f1e6':p.ink,align:'center',maxLines:1})})} function factChips(ctx,s,p,x,y,w,{dark=true,fonts}={}){const lf=fonts?.label||'Arial';const facts=[];if(s.date)facts.push(dateText(s.date));if(s.guests)facts.push(String(s.guests)+' '+plural(s.guests,'гость','гостя','гостей'));if(s.time)facts.push('Доставка '+String(s.time));const gap=8,cw=(w-gap*Math.max(0,facts.length-1))/Math.max(1,facts.length);facts.forEach((f,i)=>{const xx=x+i*(cw+gap);roundRect(ctx,xx,y,cw,44,13,dark?'rgba(255,255,255,.06)':p.paper,dark?'rgba(255,255,255,.2)':p.line);text(ctx,f,xx+cw/2,y+14,cw-14,17,{font:`600 12px ${lf}`,color:dark?'#f4f1e6':p.ink,align:'center',maxLines:1})})}
function menuList(ctx,s,p,x,y,w,rowH,count,{dark=true,numbered=true,fonts}={}){const df=fonts?.display||'Georgia',lf=fonts?.label||'Arial';const items=(s.items||[]).slice(0,count),gap=8;items.forEach((item,i)=>{const yy=y+i*(rowH+gap);roundRect(ctx,x,yy,w,rowH,13,dark?'rgba(255,255,255,.05)':p.paper,dark?'rgba(255,255,255,.14)':p.line);const badgeX=x+14;if(numbered){roundRect(ctx,badgeX,yy+rowH/2-13,26,26,13,p.accent,null);text(ctx,String(i+1),badgeX+13,yy+rowH/2-9,26,18,{font:`700 12px ${lf}`,color:p.deep,align:'center',maxLines:1})}const textX=numbered?badgeX+38:x+16;text(ctx,item.name||'Позиция меню',textX,yy+10,w-(textX-x)-70,20,{font:`600 14px ${df}`,color:dark?'#fff':p.ink,maxLines:1});const meta=[item.weight?String(item.weight):'',].filter(Boolean).join(' · ');if(meta)text(ctx,meta,textX,yy+rowH-24,w-(textX-x)-70,16,{font:`500 11px ${lf}`,color:p.muted,maxLines:1});text(ctx,'× '+Math.round(Number(item.qty||1)),x+w-16,yy+rowH/2-9,50,18,{font:`700 12px ${lf}`,color:p.accent,align:'right',maxLines:1})});return items.length*(rowH+gap)} function menuList(ctx,s,p,x,y,w,rowH,count,{dark=true,numbered=true,fonts}={}){const df=fonts?.display||'Georgia',lf=fonts?.label||'Arial';const items=(s.items||[]).slice(0,count),gap=8;items.forEach((item,i)=>{const yy=y+i*(rowH+gap);roundRect(ctx,x,yy,w,rowH,13,dark?'rgba(255,255,255,.05)':p.paper,dark?'rgba(255,255,255,.14)':p.line);const badgeX=x+14;if(numbered){roundRect(ctx,badgeX,yy+rowH/2-13,26,26,13,p.accent,null);text(ctx,String(i+1),badgeX+13,yy+rowH/2-9,26,18,{font:`700 12px ${lf}`,color:p.deep,align:'center',maxLines:1})}const textX=numbered?badgeX+38:x+16;text(ctx,item.name||'Позиция меню',textX,yy+10,w-(textX-x)-70,20,{font:`600 14px ${df}`,color:dark?'#fff':p.ink,maxLines:1});const meta=[item.weight?String(item.weight):'',].filter(Boolean).join(' · ');if(meta)text(ctx,meta,textX,yy+rowH-24,w-(textX-x)-70,16,{font:`500 11px ${lf}`,color:p.muted,maxLines:1});text(ctx,'× '+Math.round(Number(item.qty||1)),x+w-16,yy+rowH/2-9,50,18,{font:`700 12px ${lf}`,color:p.accent,align:'right',maxLines:1})});return items.length*(rowH+gap)}
function photoGridSquare(ctx,s,p,x,y,w,h,cols,rows,{numbered=true,fonts}={}){const lf=fonts?.label||'Arial';const items=(s.items||[]).slice(0,cols*rows);const gap=7,cw=(w-gap*(cols-1))/cols,ch=(h-gap*(rows-1))/rows;return (async()=>{const imgs=await Promise.all(items.map(it=>loadImage(it.photoData||'')));imgs.forEach((img,i)=>{const col=i%cols,row=Math.floor(i/cols),xx=x+col*(cw+gap),yy=y+row*(ch+gap);roundRect(ctx,xx,yy,cw,ch,10,p.deep,null);if(img)coverImage(ctx,img,xx,yy,cw,ch,10);if(numbered){roundRect(ctx,xx+6,yy+6,22,22,11,'rgba(6,10,8,.72)',null);text(ctx,String(i+1),xx+17,yy+10,22,16,{font:`700 10px ${lf}`,color:'#fff',align:'center',maxLines:1})}})})()} function photoGridSquare(ctx,s,p,x,y,w,h,cols,rows,{numbered=true,fonts}={}){const lf=fonts?.label||'Arial';const items=(s.items||[]).slice(0,cols*rows);const gap=7,cw=(w-gap*(cols-1))/cols,ch=(h-gap*(rows-1))/rows;return (async()=>{const imgs=await Promise.all(items.map(it=>loadImage(it.photoData||'')));imgs.forEach((img,i)=>{const col=i%cols,row=Math.floor(i/cols),xx=x+col*(cw+gap),yy=y+row*(ch+gap);roundRect(ctx,xx,yy,cw,ch,10,p.deep,null);if(img)coverImage(ctx,img,xx,yy,cw,ch,10);if(numbered){roundRect(ctx,xx+6,yy+6,22,22,11,'rgba(6,10,8,.72)',null);text(ctx,String(i+1),xx+17,yy+10,22,16,{font:`700 10px ${lf}`,color:'#fff',align:'center',maxLines:1})}})})()}
@ -162,6 +176,20 @@
statCards(ctx,s,p,M,900,306,90,[[Math.round(classicBoxCount(s))||0,'КОРОБОК'],[(s.items||[]).length,'ПОЗИЦИЙ']],{dark:true,fonts:f});priceBand(ctx,s,p,376,900,306,90,{dark:true,fonts:f}); statCards(ctx,s,p,M,900,306,90,[[Math.round(classicBoxCount(s))||0,'КОРОБОК'],[(s.items||[]).length,'ПОЗИЦИЙ']],{dark:true,fonts:f});priceBand(ctx,s,p,376,900,306,90,{dark:true,fonts:f});
const dgx=698,dgy=900;roundRect(ctx,dgx,dgy,248,90,16,'rgba(255,255,255,.04)',p.line);ctx.save();ctx.translate(dgx+124,dgy+45);ctx.rotate(Math.PI/4);ctx.fillStyle=p.accent;ctx.fillRect(-16,-16,32,32);ctx.restore();text(ctx,'СКИДКА ВКЛЮЧЕНА',dgx+124,dgy+70,248,14,{font:`700 9px ${f.label}`,color:p.muted,align:'center',maxLines:1}); const dgx=698,dgy=900;roundRect(ctx,dgx,dgy,248,90,16,'rgba(255,255,255,.04)',p.line);ctx.save();ctx.translate(dgx+124,dgy+45);ctx.rotate(Math.PI/4);ctx.fillStyle=p.accent;ctx.fillRect(-16,-16,32,32);ctx.restore();text(ctx,'СКИДКА ВКЛЮЧЕНА',dgx+124,dgy+70,248,14,{font:`700 9px ${f.label}`,color:p.muted,align:'center',maxLines:1});
checklistCard(ctx,p,M,1010,470,170,'ДОСТАВКА И КОНТРОЛЬ КАЧЕСТВА',CHECK_LINES,{dark:true,fonts:f});addonRow(ctx,p,540,1010,406,170,ADDON_LINES.concat(['Посуда','Мебель']),{dark:true,fonts:f}); checklistCard(ctx,p,M,1010,470,170,'ДОСТАВКА И КОНТРОЛЬ КАЧЕСТВА',CHECK_LINES,{dark:true,fonts:f});addonRow(ctx,p,540,1010,406,170,ADDON_LINES.concat(['Посуда','Мебель']),{dark:true,fonts:f});
}else if(id==='premium-dark'||id==='premium-emerald'){
logoOrBrand(ctx,logo,p,{x:M,y:44,dark:true,fonts:f},s.brandName);
text(ctx,'ПЕРСОНАЛЬНОЕ ПРЕДЛОЖЕНИЕ',M,140,500,16,{font:`700 11px ${f.label}`,color:p.accent,maxLines:1});
text(ctx,title,M,164,W-2*M,40,{font:`700 32px ${f.display}`,color:'#fff',maxLines:2});
bulletList(ctx,p,f,M,256,W-2*M,30,CHECK_LINES,'#dfe3e8');
if(hero)coverImage(ctx,hero,M,396,W-2*M,230,26);
statBadgeRow(ctx,p,f,M,650,W-2*M,104,[[iconCalendar,dateText(s.date)||'Уточняется','Дата мероприятия'],[iconPeople,s.guests?String(s.guests):'—','Количество гостей'],[iconBox,String(Math.round(classicBoxCount(s))||0),'Коробок в заказе']]);
text(ctx,'МЕНЮ',W/2,786,W,26,{font:`700 22px ${f.display}`,color:'#fff',align:'center',maxLines:1});
line(ctx,M,812,410,812,p.line,1);line(ctx,590,812,W-M,812,p.line,1);
await photoGridSquare(ctx,s,p,M,846,W-2*M,272,3,2,{numbered:true,fonts:f});
statCards(ctx,s,p,M,1138,565,95,[[Math.round(classicBoxCount(s))||0,'КОРОБОК'],[(s.items||[]).length,'ПОЗИЦИЙ']],{dark:true,fonts:f});
priceBand(ctx,s,p,640,1138,306,95,{dark:true,fonts:f});
checklistCard(ctx,p,M,1253,470,113,'ВСЁ ПОД КОНТРОЛЕМ',CHECK_LINES.slice(0,2),{dark:true,fonts:f});
addonRow(ctx,p,540,1253,406,113,ADDON_LINES,{dark:true,fonts:f});
} }
canvas.dataset.sunSignatureTemplate=id;canvas.dataset.sunSignatureCover='1';return canvas; canvas.dataset.sunSignatureTemplate=id;canvas.dataset.sunSignatureCover='1';return canvas;
} }
@ -241,13 +269,15 @@
} }
function installPreviewStyles(){if(document.getElementById('sunSignatureOfferPreviewV18'))return;const style=document.createElement('style');style.id='sunSignatureOfferPreviewV18';style.textContent=` function installPreviewStyles(){if(document.getElementById('sunSignatureOfferPreviewV18'))return;const style=document.createElement('style');style.id='sunSignatureOfferPreviewV18';style.textContent=`
.sun-offer-template-mini[data-template-mini="cream-elegance"] i,.sun-offer-template-mini[data-template-mini="neon-menu"] i,.sun-offer-template-mini[data-template-mini="emerald-circles"] i,.sun-offer-template-mini[data-template-mini="midnight-checklist"] i,.sun-offer-template-mini[data-template-mini="gourmet-hero"] i,.sun-offer-template-mini[data-template-mini="diamond-gold"] i{display:none!important} .sun-offer-template-mini[data-template-mini="cream-elegance"] i,.sun-offer-template-mini[data-template-mini="neon-menu"] i,.sun-offer-template-mini[data-template-mini="emerald-circles"] i,.sun-offer-template-mini[data-template-mini="midnight-checklist"] i,.sun-offer-template-mini[data-template-mini="gourmet-hero"] i,.sun-offer-template-mini[data-template-mini="diamond-gold"] i,.sun-offer-template-mini[data-template-mini="premium-dark"] i,.sun-offer-template-mini[data-template-mini="premium-emerald"] i{display:none!important}
.sun-offer-template-mini[data-template-mini="cream-elegance"]{background:radial-gradient(circle at 78% 30%,#fff 0 18%,#8f8536 19% 21%,transparent 22%),linear-gradient(#fdf7ea,#f2e3bf)!important} .sun-offer-template-mini[data-template-mini="cream-elegance"]{background:radial-gradient(circle at 78% 30%,#fff 0 18%,#8f8536 19% 21%,transparent 22%),linear-gradient(#fdf7ea,#f2e3bf)!important}
.sun-offer-template-mini[data-template-mini="neon-menu"]{background:linear-gradient(90deg,rgba(57,226,122,.35),transparent 45%),linear-gradient(135deg,#0d1210,#070908)!important;border-color:#1f4430!important} .sun-offer-template-mini[data-template-mini="neon-menu"]{background:linear-gradient(90deg,rgba(57,226,122,.35),transparent 45%),linear-gradient(135deg,#0d1210,#070908)!important;border-color:#1f4430!important}
.sun-offer-template-mini[data-template-mini="emerald-circles"]{background:radial-gradient(circle at 70% 55%,#c9a24a 0 6%,transparent 7%),radial-gradient(circle at 85% 55%,#c9a24a 0 6%,transparent 7%),linear-gradient(135deg,#0d2226,#08181c)!important;border-color:#1f4642!important} .sun-offer-template-mini[data-template-mini="emerald-circles"]{background:radial-gradient(circle at 70% 55%,#c9a24a 0 6%,transparent 7%),radial-gradient(circle at 85% 55%,#c9a24a 0 6%,transparent 7%),linear-gradient(135deg,#0d2226,#08181c)!important;border-color:#1f4642!important}
.sun-offer-template-mini[data-template-mini="midnight-checklist"]{background:repeating-linear-gradient(0deg,#0b2417 0 11%,#123822 11% 12%),#06170f!important;border-color:#1f4a30!important} .sun-offer-template-mini[data-template-mini="midnight-checklist"]{background:repeating-linear-gradient(0deg,#0b2417 0 11%,#123822 11% 12%),#06170f!important;border-color:#1f4a30!important}
.sun-offer-template-mini[data-template-mini="gourmet-hero"]{background:linear-gradient(90deg,#141311 0 55%,#3a352a 55% 58%,#0a0a09 58%)!important;border-color:#3a352a!important} .sun-offer-template-mini[data-template-mini="gourmet-hero"]{background:linear-gradient(90deg,#141311 0 55%,#3a352a 55% 58%,#0a0a09 58%)!important;border-color:#3a352a!important}
.sun-offer-template-mini[data-template-mini="diamond-gold"]{background:radial-gradient(circle at 75% 35%,#e0b95c 0 5%,transparent 6%),linear-gradient(135deg,#123d29,#071510)!important;border-color:#204b34!important} .sun-offer-template-mini[data-template-mini="diamond-gold"]{background:radial-gradient(circle at 75% 35%,#e0b95c 0 5%,transparent 6%),linear-gradient(135deg,#123d29,#071510)!important;border-color:#204b34!important}
.sun-offer-template-mini[data-template-mini="premium-dark"]{background:radial-gradient(circle at 18% 15%,rgba(224,165,69,.35),transparent 40%),linear-gradient(160deg,#12161d,#0a0d12)!important;border-color:#252b35!important}
.sun-offer-template-mini[data-template-mini="premium-emerald"]{background:radial-gradient(circle at 18% 15%,rgba(63,207,142,.35),transparent 40%),linear-gradient(160deg,#121d19,#0a1210)!important;border-color:#233830!important}
`;document.head.appendChild(style)} `;document.head.appendChild(style)}
if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',installPreviewStyles,{once:true});else installPreviewStyles(); if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',installPreviewStyles,{once:true});else installPreviewStyles();