[{"data":1,"prerenderedAt":1209},["ShallowReactive",2],{"guide-\u002Fdocs\u002Fguides\u002Fauthoring\u002Fdesign-for-pdf":3,"guides-all":1141},{"id":4,"title":5,"body":6,"category":1132,"description":1133,"extension":1134,"icon":1135,"meta":1136,"navigation":635,"order":92,"path":1137,"seo":1138,"stem":1139,"__hash__":1140},"guides\u002Fdocs\u002Fguides\u002Fauthoring\u002Fdesign-for-pdf.md","Designing templates that survive PDF rendering",{"type":7,"value":8,"toc":1113},"minimark",[9,14,27,32,35,56,63,67,72,162,165,169,180,184,235,241,245,249,252,340,343,347,350,354,365,369,376,447,469,473,484,536,543,547,562,579,583,597,697,701,1083,1087,1109],[10,11,13],"h1",{"id":12},"designing-for-pdf-rendering","Designing for PDF rendering",[15,16,17,18,22,23,26],"p",{},"Your templates are rendered by ",[19,20,21],"strong",{},"Chromium headless"," (via Gotenberg) and the output is a ",[19,24,25],{},"static PDF",". That changes the design constraints in non-obvious ways.",[28,29,31],"h2",{"id":30},"the-mental-model","The mental model",[15,33,34],{},"The renderer:",[36,37,38,42,45,53],"ol",{},[39,40,41],"li",{},"Loads your HTML + the CSS framework you picked (Tailwind by default).",[39,43,44],{},"Loads the Google Fonts you've added.",[39,46,47,48,52],{},"Compiles the Handlebars and injects ",[49,50,51],"code",{},"variables",".",[39,54,55],{},"Snapshots the page to PDF using Chromium's print engine.",[15,57,58,59,62],{},"Everything that happens ",[19,60,61],{},"at print time"," is what ends up in the file. Anything that depends on time, interaction, or animation is either skipped or frozen.",[28,64,66],{"id":65},"things-to-drop","Things to drop",[68,69,71],"h3",{"id":70},"animations-transitions","Animations & transitions",[73,74,79],"pre",{"className":75,"code":76,"language":77,"meta":78,"style":78},"language-css shiki shiki-themes github-light github-dark","\u002F* All of this is invisible in the PDF and just costs render time. *\u002F\n.btn { transition: all 200ms; }\n@keyframes pulse { ... }\n.spin { animation: spin 1s linear infinite; }\n","css","",[49,80,81,90,121,134],{"__ignoreMap":78},[82,83,86],"span",{"class":84,"line":85},"line",1,[82,87,89],{"class":88},"sJ8bj","\u002F* All of this is invisible in the PDF and just costs render time. *\u002F\n",[82,91,93,97,101,105,108,111,114,118],{"class":84,"line":92},2,[82,94,96],{"class":95},"sScJk",".btn",[82,98,100],{"class":99},"sVt8B"," { ",[82,102,104],{"class":103},"sj4cs","transition",[82,106,107],{"class":99},": ",[82,109,110],{"class":103},"all",[82,112,113],{"class":103}," 200",[82,115,117],{"class":116},"szBVR","ms",[82,119,120],{"class":99},"; }\n",[82,122,124,127,131],{"class":84,"line":123},3,[82,125,126],{"class":116},"@keyframes",[82,128,130],{"class":129},"s4XuR"," pulse",[82,132,133],{"class":99}," { ... }\n",[82,135,137,140,142,145,148,151,154,157,160],{"class":84,"line":136},4,[82,138,139],{"class":95},".spin",[82,141,100],{"class":99},[82,143,144],{"class":103},"animation",[82,146,147],{"class":99},": spin ",[82,149,150],{"class":103},"1",[82,152,153],{"class":116},"s",[82,155,156],{"class":103}," linear",[82,158,159],{"class":103}," infinite",[82,161,120],{"class":99},[15,163,164],{},"The hover\u002Ffocus pseudo-classes don't fire either — there's no cursor.",[68,166,168],{"id":167},"interactivity","Interactivity",[15,170,171,172,175,176,179],{},"No ",[49,173,174],{},"\u003Cbutton>"," JavaScript handlers, no ",[49,177,178],{},"\u003Cinput>"," fields, no scroll-driven effects. Just text, layout, images.",[68,181,183],{"id":182},"time-dependent-values","Time-dependent values",[73,185,189],{"className":186,"code":187,"language":188,"meta":78,"style":78},"language-js shiki shiki-themes github-light github-dark","const today = new Date()      \u002F\u002F freezes at render time, that's fine\nconst random = Math.random()  \u002F\u002F same — fine, but be aware\n","js",[49,190,191,214],{"__ignoreMap":78},[82,192,193,196,199,202,205,208,211],{"class":84,"line":85},[82,194,195],{"class":116},"const",[82,197,198],{"class":103}," today",[82,200,201],{"class":116}," =",[82,203,204],{"class":116}," new",[82,206,207],{"class":95}," Date",[82,209,210],{"class":99},"()      ",[82,212,213],{"class":88},"\u002F\u002F freezes at render time, that's fine\n",[82,215,216,218,221,223,226,229,232],{"class":84,"line":92},[82,217,195],{"class":116},[82,219,220],{"class":103}," random",[82,222,201],{"class":116},[82,224,225],{"class":99}," Math.",[82,227,228],{"class":95},"random",[82,230,231],{"class":99},"()  ",[82,233,234],{"class":88},"\u002F\u002F same — fine, but be aware\n",[15,236,237,238,240],{},"If you genuinely want \"today's date\" on the PDF, pre-compute it in ",[49,239,51],{}," so you control what's printed regardless of when the render happens.",[28,242,244],{"id":243},"things-to-prefer","Things to prefer",[68,246,248],{"id":247},"vector-primitives","Vector primitives",[15,250,251],{},"HTML + CSS + inline SVG stay vectorial in the PDF. They look crisp at any zoom level and stay sharp on print.",[73,253,257],{"className":254,"code":255,"language":256,"meta":78,"style":78},"language-html shiki shiki-themes github-light github-dark","\u003Csvg viewBox=\"0 0 100 100\" class=\"h-24 w-24\">\n  \u003Ccircle cx=\"50\" cy=\"50\" r=\"45\" fill=\"#0f172a\" \u002F>\n\u003C\u002Fsvg>\n","html",[49,258,259,289,331],{"__ignoreMap":78},[82,260,261,264,268,271,274,278,281,283,286],{"class":84,"line":85},[82,262,263],{"class":99},"\u003C",[82,265,267],{"class":266},"s9eBZ","svg",[82,269,270],{"class":95}," viewBox",[82,272,273],{"class":99},"=",[82,275,277],{"class":276},"sZZnC","\"0 0 100 100\"",[82,279,280],{"class":95}," class",[82,282,273],{"class":99},[82,284,285],{"class":276},"\"h-24 w-24\"",[82,287,288],{"class":99},">\n",[82,290,291,294,297,300,302,305,308,310,312,315,317,320,323,325,328],{"class":84,"line":92},[82,292,293],{"class":99},"  \u003C",[82,295,296],{"class":266},"circle",[82,298,299],{"class":95}," cx",[82,301,273],{"class":99},[82,303,304],{"class":276},"\"50\"",[82,306,307],{"class":95}," cy",[82,309,273],{"class":99},[82,311,304],{"class":276},[82,313,314],{"class":95}," r",[82,316,273],{"class":99},[82,318,319],{"class":276},"\"45\"",[82,321,322],{"class":95}," fill",[82,324,273],{"class":99},[82,326,327],{"class":276},"\"#0f172a\"",[82,329,330],{"class":99}," \u002F>\n",[82,332,333,336,338],{"class":84,"line":123},[82,334,335],{"class":99},"\u003C\u002F",[82,337,267],{"class":266},[82,339,288],{"class":99},[15,341,342],{},"That circle prints at 600dpi just as well as at 72dpi. No image to chase.",[68,344,346],{"id":345},"tailwind-utility-classes-for-layout","Tailwind + utility classes for layout",[15,348,349],{},"Tailwind shines in print — predictable spacing, clean typography, no JavaScript dependencies. The framework is the default for new templates.",[68,351,353],{"id":352},"google-fonts-via-the-dashboard","Google Fonts via the dashboard",[15,355,356,357,360,361,364],{},"Add fonts from the editor's font picker, then use them with Tailwind's font-family classes (",[49,358,359],{},"font-sans",", custom via ",[49,362,363],{},"font-display"," if you've set a master). The renderer fetches and subsets them per generation.",[28,366,368],{"id":367},"canvas-based-charts-chartjs-echarts","Canvas-based charts (Chart.js, ECharts, …)",[15,370,371,372,375],{},"Canvas content ",[19,373,374],{},"rasterizes"," in the PDF. At default resolution it looks fuzzy. Two options:",[36,377,378,403],{},[39,379,380,383,384,399,402],{},[19,381,382],{},"Render at high pixel density."," For Chart.js, before creating any chart:",[73,385,387],{"className":186,"code":386,"language":188,"meta":78,"style":78},"Chart.defaults.devicePixelRatio = 4\n",[49,388,389],{"__ignoreMap":78},[82,390,391,394,396],{"class":84,"line":85},[82,392,393],{"class":99},"Chart.defaults.devicePixelRatio ",[82,395,273],{"class":116},[82,397,398],{"class":103}," 4\n",[400,401],"br",{},"That oversamples the canvas 4× — the resulting bitmap stays sharp when embedded.",[39,404,405,408,409,444,446],{},[19,406,407],{},"Use SVG output where the library supports it."," For ECharts:",[73,410,412],{"className":186,"code":411,"language":188,"meta":78,"style":78},"const chart = echarts.init(el, null, {renderer: 'svg'})\n",[49,413,414],{"__ignoreMap":78},[82,415,416,418,421,423,426,429,432,435,438,441],{"class":84,"line":85},[82,417,195],{"class":116},[82,419,420],{"class":103}," chart",[82,422,201],{"class":116},[82,424,425],{"class":99}," echarts.",[82,427,428],{"class":95},"init",[82,430,431],{"class":99},"(el, ",[82,433,434],{"class":103},"null",[82,436,437],{"class":99},", {renderer: ",[82,439,440],{"class":276},"'svg'",[82,442,443],{"class":99},"})\n",[400,445],{},"SVG is always crisp. Prefer it whenever the library offers it.",[448,449,462],"aside",{"className":450},[451,452,453,454,455,456,457,458,459,460,461],"not-prose","my-6","rounded-md","border","border-blue-200","bg-blue-50","text-blue-900","px-4","py-3","text-[14px]","leading-relaxed",[15,463,464,465,468],{},"The AI assistant in the editor knows this rule and applies ",[49,466,467],{},"devicePixelRatio = 4"," by default whenever it adds a Chart.js graph. If you're hand-coding, remember to set it yourself.",[28,470,472],{"id":471},"page-format-landscape","Page format & landscape",[15,474,475,476,479,480,483],{},"Each template has a ",[49,477,478],{},"format"," (A1 through A6) and a ",[49,481,482],{},"landscape"," boolean. Pick them based on content:",[485,486,487,500],"table",{},[488,489,490],"thead",{},[491,492,493,497],"tr",{},[494,495,496],"th",{},"Content",[494,498,499],{},"Pick",[501,502,503,512,520,528],"tbody",{},[491,504,505,509],{},[506,507,508],"td",{},"Invoice, receipt, single-page letter",[506,510,511],{},"A4 portrait",[491,513,514,517],{},[506,515,516],{},"Two-page side-by-side comparison",[506,518,519],{},"A4 landscape",[491,521,522,525],{},[506,523,524],{},"Pocket-size receipt",[506,526,527],{},"A6",[491,529,530,533],{},[506,531,532],{},"Poster, large diagram",[506,534,535],{},"A3 portrait\u002Flandscape",[15,537,538,539,542],{},"You can change these from the editor (right-side properties panel) or via ",[49,540,541],{},"PATCH \u002Fv1\u002Fdocuments\u002F{id}"," from code.",[28,544,546],{"id":545},"fonts-and-weight-variants","Fonts and weight variants",[15,548,549,550,553,554,557,558,561],{},"Add only the weights you actually use — every variant slows the render. A typical document needs ",[49,551,552],{},"400"," for body and ",[49,555,556],{},"600"," or ",[49,559,560],{},"700"," for titles, that's it.",[15,563,564,565,571,572,575,576,578],{},"In the editor: ",[19,566,567,568],{},"Fonts → +Add → Inter Tight → variants ",[49,569,570],{},"400, 600",". Set ",[49,573,574],{},"master: true"," on the font you want as the body default; others apply when you explicitly use them in CSS (e.g. via Tailwind ",[49,577,363],{},").",[28,580,582],{"id":581},"page-breaks","Page breaks",[15,584,585,586,589,590,589,593,596],{},"CSS ",[49,587,588],{},"break-before-page"," \u002F ",[49,591,592],{},"break-after-page",[49,594,595],{},"break-inside-avoid"," work and are the canonical way to control pagination:",[73,598,600],{"className":254,"code":599,"language":256,"meta":78,"style":78},"\u003Csection class=\"break-after-page\">\n  Page 1 content\n\u003C\u002Fsection>\n\n\u003Csection>\n  Page 2 content\n\u003C\u002Fsection>\n\n\u003Ctable class=\"break-inside-avoid\">\n  \u003C!-- never split this table across two pages -->\n\u003C\u002Ftable>\n",[49,601,602,618,623,631,637,646,652,661,666,682,688],{"__ignoreMap":78},[82,603,604,606,609,611,613,616],{"class":84,"line":85},[82,605,263],{"class":99},[82,607,608],{"class":266},"section",[82,610,280],{"class":95},[82,612,273],{"class":99},[82,614,615],{"class":276},"\"break-after-page\"",[82,617,288],{"class":99},[82,619,620],{"class":84,"line":92},[82,621,622],{"class":99},"  Page 1 content\n",[82,624,625,627,629],{"class":84,"line":123},[82,626,335],{"class":99},[82,628,608],{"class":266},[82,630,288],{"class":99},[82,632,633],{"class":84,"line":136},[82,634,636],{"emptyLinePlaceholder":635},true,"\n",[82,638,640,642,644],{"class":84,"line":639},5,[82,641,263],{"class":99},[82,643,608],{"class":266},[82,645,288],{"class":99},[82,647,649],{"class":84,"line":648},6,[82,650,651],{"class":99},"  Page 2 content\n",[82,653,655,657,659],{"class":84,"line":654},7,[82,656,335],{"class":99},[82,658,608],{"class":266},[82,660,288],{"class":99},[82,662,664],{"class":84,"line":663},8,[82,665,636],{"emptyLinePlaceholder":635},[82,667,669,671,673,675,677,680],{"class":84,"line":668},9,[82,670,263],{"class":99},[82,672,485],{"class":266},[82,674,280],{"class":95},[82,676,273],{"class":99},[82,678,679],{"class":276},"\"break-inside-avoid\"",[82,681,288],{"class":99},[82,683,685],{"class":84,"line":684},10,[82,686,687],{"class":88},"  \u003C!-- never split this table across two pages -->\n",[82,689,691,693,695],{"class":84,"line":690},11,[82,692,335],{"class":99},[82,694,485],{"class":266},[82,696,288],{"class":99},[28,698,700],{"id":699},"a-typical-invoice-in-60-lines","A typical invoice in 60 lines",[73,702,706],{"className":703,"code":704,"language":705,"meta":78,"style":78},"language-handlebars shiki shiki-themes github-light github-dark","\u003C!doctype html>\n\u003Chtml lang=\"en\">\n\u003Chead>\n  \u003Cmeta charset=\"utf-8\" \u002F>\n  \u003Ctitle>Invoice {{invoice.number}}\u003C\u002Ftitle>\n\u003C\u002Fhead>\n\u003Cbody class=\"font-sans text-slate-900\">\n  \u003Cmain class=\"p-12\">\n    \u003Cheader class=\"flex items-start justify-between border-b border-slate-200 pb-6\">\n      \u003Cdiv>\n        \u003Cp class=\"text-xs uppercase tracking-widest text-slate-500\">Invoice\u003C\u002Fp>\n        \u003Ch1 class=\"font-display text-3xl font-semibold mt-1\">\n          {{invoice.number}}\n        \u003C\u002Fh1>\n      \u003C\u002Fdiv>\n      \u003Cdiv class=\"text-right\">\n        \u003Cp class=\"text-sm\">Issued {{invoice.issuedOn}}\u003C\u002Fp>\n        \u003Cp class=\"text-sm text-slate-500\">Due {{invoice.dueOn}}\u003C\u002Fp>\n      \u003C\u002Fdiv>\n    \u003C\u002Fheader>\n\n    \u003Csection class=\"grid grid-cols-2 gap-8 mt-8\">\n      \u003Cdiv>\n        \u003Cp class=\"text-xs uppercase tracking-wider text-slate-500\">Billed to\u003C\u002Fp>\n        \u003Cp class=\"mt-1 font-semibold\">{{customer.name}}\u003C\u002Fp>\n        \u003Cp class=\"text-sm text-slate-600\">{{customer.address.line1}}\u003C\u002Fp>\n        \u003Cp class=\"text-sm text-slate-600\">{{customer.address.city}}\u003C\u002Fp>\n      \u003C\u002Fdiv>\n      \u003Cdiv>\n        \u003Cp class=\"text-xs uppercase tracking-wider text-slate-500\">From\u003C\u002Fp>\n        \u003Cp class=\"mt-1 font-semibold\">{{seller.name}}\u003C\u002Fp>\n        \u003Cp class=\"text-sm text-slate-600\">{{seller.address}}\u003C\u002Fp>\n      \u003C\u002Fdiv>\n    \u003C\u002Fsection>\n\n    \u003Ctable class=\"mt-10 w-full text-sm\">\n      \u003Cthead class=\"border-b border-slate-200 text-left\">\n        \u003Ctr>\n          \u003Cth class=\"py-2\">Item\u003C\u002Fth>\n          \u003Cth class=\"py-2 text-right\">Qty\u003C\u002Fth>\n          \u003Cth class=\"py-2 text-right\">Amount\u003C\u002Fth>\n        \u003C\u002Ftr>\n      \u003C\u002Fthead>\n      \u003Ctbody>\n        {{#each items}}\n          \u003Ctr class=\"border-b border-slate-100\">\n            \u003Ctd class=\"py-2\">{{label}}\u003C\u002Ftd>\n            \u003Ctd class=\"py-2 text-right\">{{qty}}\u003C\u002Ftd>\n            \u003Ctd class=\"py-2 text-right\">{{amount}} €\u003C\u002Ftd>\n          \u003C\u002Ftr>\n        {{\u002Feach}}\n      \u003C\u002Ftbody>\n      \u003Ctfoot>\n        \u003Ctr>\n          \u003Ctd class=\"pt-4 font-semibold\" colspan=\"2\">Total\u003C\u002Ftd>\n          \u003Ctd class=\"pt-4 font-semibold text-right\">{{invoice.total}} €\u003C\u002Ftd>\n        \u003C\u002Ftr>\n      \u003C\u002Ftfoot>\n    \u003C\u002Ftable>\n\n    {{#if paid}}\n      \u003Cp class=\"mt-10 text-emerald-700 font-semibold\">PAID\u003C\u002Fp>\n    {{\u002Fif}}\n  \u003C\u002Fmain>\n\u003C\u002Fbody>\n\u003C\u002Fhtml>\n","handlebars",[49,707,708,713,718,723,728,733,738,743,748,753,758,763,769,775,781,787,793,799,805,810,816,821,827,832,838,844,850,856,861,866,872,878,884,889,895,900,906,912,918,924,930,936,942,948,954,960,966,972,978,984,990,996,1002,1008,1013,1019,1025,1030,1036,1042,1047,1053,1059,1065,1071,1077],{"__ignoreMap":78},[82,709,710],{"class":84,"line":85},[82,711,712],{},"\u003C!doctype html>\n",[82,714,715],{"class":84,"line":92},[82,716,717],{},"\u003Chtml lang=\"en\">\n",[82,719,720],{"class":84,"line":123},[82,721,722],{},"\u003Chead>\n",[82,724,725],{"class":84,"line":136},[82,726,727],{},"  \u003Cmeta charset=\"utf-8\" \u002F>\n",[82,729,730],{"class":84,"line":639},[82,731,732],{},"  \u003Ctitle>Invoice {{invoice.number}}\u003C\u002Ftitle>\n",[82,734,735],{"class":84,"line":648},[82,736,737],{},"\u003C\u002Fhead>\n",[82,739,740],{"class":84,"line":654},[82,741,742],{},"\u003Cbody class=\"font-sans text-slate-900\">\n",[82,744,745],{"class":84,"line":663},[82,746,747],{},"  \u003Cmain class=\"p-12\">\n",[82,749,750],{"class":84,"line":668},[82,751,752],{},"    \u003Cheader class=\"flex items-start justify-between border-b border-slate-200 pb-6\">\n",[82,754,755],{"class":84,"line":684},[82,756,757],{},"      \u003Cdiv>\n",[82,759,760],{"class":84,"line":690},[82,761,762],{},"        \u003Cp class=\"text-xs uppercase tracking-widest text-slate-500\">Invoice\u003C\u002Fp>\n",[82,764,766],{"class":84,"line":765},12,[82,767,768],{},"        \u003Ch1 class=\"font-display text-3xl font-semibold mt-1\">\n",[82,770,772],{"class":84,"line":771},13,[82,773,774],{},"          {{invoice.number}}\n",[82,776,778],{"class":84,"line":777},14,[82,779,780],{},"        \u003C\u002Fh1>\n",[82,782,784],{"class":84,"line":783},15,[82,785,786],{},"      \u003C\u002Fdiv>\n",[82,788,790],{"class":84,"line":789},16,[82,791,792],{},"      \u003Cdiv class=\"text-right\">\n",[82,794,796],{"class":84,"line":795},17,[82,797,798],{},"        \u003Cp class=\"text-sm\">Issued {{invoice.issuedOn}}\u003C\u002Fp>\n",[82,800,802],{"class":84,"line":801},18,[82,803,804],{},"        \u003Cp class=\"text-sm text-slate-500\">Due {{invoice.dueOn}}\u003C\u002Fp>\n",[82,806,808],{"class":84,"line":807},19,[82,809,786],{},[82,811,813],{"class":84,"line":812},20,[82,814,815],{},"    \u003C\u002Fheader>\n",[82,817,819],{"class":84,"line":818},21,[82,820,636],{"emptyLinePlaceholder":635},[82,822,824],{"class":84,"line":823},22,[82,825,826],{},"    \u003Csection class=\"grid grid-cols-2 gap-8 mt-8\">\n",[82,828,830],{"class":84,"line":829},23,[82,831,757],{},[82,833,835],{"class":84,"line":834},24,[82,836,837],{},"        \u003Cp class=\"text-xs uppercase tracking-wider text-slate-500\">Billed to\u003C\u002Fp>\n",[82,839,841],{"class":84,"line":840},25,[82,842,843],{},"        \u003Cp class=\"mt-1 font-semibold\">{{customer.name}}\u003C\u002Fp>\n",[82,845,847],{"class":84,"line":846},26,[82,848,849],{},"        \u003Cp class=\"text-sm text-slate-600\">{{customer.address.line1}}\u003C\u002Fp>\n",[82,851,853],{"class":84,"line":852},27,[82,854,855],{},"        \u003Cp class=\"text-sm text-slate-600\">{{customer.address.city}}\u003C\u002Fp>\n",[82,857,859],{"class":84,"line":858},28,[82,860,786],{},[82,862,864],{"class":84,"line":863},29,[82,865,757],{},[82,867,869],{"class":84,"line":868},30,[82,870,871],{},"        \u003Cp class=\"text-xs uppercase tracking-wider text-slate-500\">From\u003C\u002Fp>\n",[82,873,875],{"class":84,"line":874},31,[82,876,877],{},"        \u003Cp class=\"mt-1 font-semibold\">{{seller.name}}\u003C\u002Fp>\n",[82,879,881],{"class":84,"line":880},32,[82,882,883],{},"        \u003Cp class=\"text-sm text-slate-600\">{{seller.address}}\u003C\u002Fp>\n",[82,885,887],{"class":84,"line":886},33,[82,888,786],{},[82,890,892],{"class":84,"line":891},34,[82,893,894],{},"    \u003C\u002Fsection>\n",[82,896,898],{"class":84,"line":897},35,[82,899,636],{"emptyLinePlaceholder":635},[82,901,903],{"class":84,"line":902},36,[82,904,905],{},"    \u003Ctable class=\"mt-10 w-full text-sm\">\n",[82,907,909],{"class":84,"line":908},37,[82,910,911],{},"      \u003Cthead class=\"border-b border-slate-200 text-left\">\n",[82,913,915],{"class":84,"line":914},38,[82,916,917],{},"        \u003Ctr>\n",[82,919,921],{"class":84,"line":920},39,[82,922,923],{},"          \u003Cth class=\"py-2\">Item\u003C\u002Fth>\n",[82,925,927],{"class":84,"line":926},40,[82,928,929],{},"          \u003Cth class=\"py-2 text-right\">Qty\u003C\u002Fth>\n",[82,931,933],{"class":84,"line":932},41,[82,934,935],{},"          \u003Cth class=\"py-2 text-right\">Amount\u003C\u002Fth>\n",[82,937,939],{"class":84,"line":938},42,[82,940,941],{},"        \u003C\u002Ftr>\n",[82,943,945],{"class":84,"line":944},43,[82,946,947],{},"      \u003C\u002Fthead>\n",[82,949,951],{"class":84,"line":950},44,[82,952,953],{},"      \u003Ctbody>\n",[82,955,957],{"class":84,"line":956},45,[82,958,959],{},"        {{#each items}}\n",[82,961,963],{"class":84,"line":962},46,[82,964,965],{},"          \u003Ctr class=\"border-b border-slate-100\">\n",[82,967,969],{"class":84,"line":968},47,[82,970,971],{},"            \u003Ctd class=\"py-2\">{{label}}\u003C\u002Ftd>\n",[82,973,975],{"class":84,"line":974},48,[82,976,977],{},"            \u003Ctd class=\"py-2 text-right\">{{qty}}\u003C\u002Ftd>\n",[82,979,981],{"class":84,"line":980},49,[82,982,983],{},"            \u003Ctd class=\"py-2 text-right\">{{amount}} €\u003C\u002Ftd>\n",[82,985,987],{"class":84,"line":986},50,[82,988,989],{},"          \u003C\u002Ftr>\n",[82,991,993],{"class":84,"line":992},51,[82,994,995],{},"        {{\u002Feach}}\n",[82,997,999],{"class":84,"line":998},52,[82,1000,1001],{},"      \u003C\u002Ftbody>\n",[82,1003,1005],{"class":84,"line":1004},53,[82,1006,1007],{},"      \u003Ctfoot>\n",[82,1009,1011],{"class":84,"line":1010},54,[82,1012,917],{},[82,1014,1016],{"class":84,"line":1015},55,[82,1017,1018],{},"          \u003Ctd class=\"pt-4 font-semibold\" colspan=\"2\">Total\u003C\u002Ftd>\n",[82,1020,1022],{"class":84,"line":1021},56,[82,1023,1024],{},"          \u003Ctd class=\"pt-4 font-semibold text-right\">{{invoice.total}} €\u003C\u002Ftd>\n",[82,1026,1028],{"class":84,"line":1027},57,[82,1029,941],{},[82,1031,1033],{"class":84,"line":1032},58,[82,1034,1035],{},"      \u003C\u002Ftfoot>\n",[82,1037,1039],{"class":84,"line":1038},59,[82,1040,1041],{},"    \u003C\u002Ftable>\n",[82,1043,1045],{"class":84,"line":1044},60,[82,1046,636],{"emptyLinePlaceholder":635},[82,1048,1050],{"class":84,"line":1049},61,[82,1051,1052],{},"    {{#if paid}}\n",[82,1054,1056],{"class":84,"line":1055},62,[82,1057,1058],{},"      \u003Cp class=\"mt-10 text-emerald-700 font-semibold\">PAID\u003C\u002Fp>\n",[82,1060,1062],{"class":84,"line":1061},63,[82,1063,1064],{},"    {{\u002Fif}}\n",[82,1066,1068],{"class":84,"line":1067},64,[82,1069,1070],{},"  \u003C\u002Fmain>\n",[82,1072,1074],{"class":84,"line":1073},65,[82,1075,1076],{},"\u003C\u002Fbody>\n",[82,1078,1080],{"class":84,"line":1079},66,[82,1081,1082],{},"\u003C\u002Fhtml>\n",[28,1084,1086],{"id":1085},"next-steps","Next steps",[1088,1089,1090,1100],"ul",{},[39,1091,1092,1099],{},[19,1093,1094],{},[1095,1096,1098],"a",{"href":1097},"\u002Fdocs\u002Fguides\u002Fauthoring\u002Fmodeling-variables","Modeling your variables →"," — what to make a variable vs. inline.",[39,1101,1102,1108],{},[19,1103,1104],{},[1095,1105,1107],{"href":1106},"\u002Fdocs\u002Fguides\u002Fauthoring\u002Fworking-with-ai","Working with the AI assistant →"," — ask Claude to draft your next template.",[1110,1111,1112],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":78,"searchDepth":92,"depth":92,"links":1114},[1115,1116,1121,1126,1127,1128,1129,1130,1131],{"id":30,"depth":92,"text":31},{"id":65,"depth":92,"text":66,"children":1117},[1118,1119,1120],{"id":70,"depth":123,"text":71},{"id":167,"depth":123,"text":168},{"id":182,"depth":123,"text":183},{"id":243,"depth":92,"text":244,"children":1122},[1123,1124,1125],{"id":247,"depth":123,"text":248},{"id":345,"depth":123,"text":346},{"id":352,"depth":123,"text":353},{"id":367,"depth":92,"text":368},{"id":471,"depth":92,"text":472},{"id":545,"depth":92,"text":546},{"id":581,"depth":92,"text":582},{"id":699,"depth":92,"text":700},{"id":1085,"depth":92,"text":1086},"authoring","PDFs are static — drop the animations, oversample your canvas charts, lean on vectors. The rules that make a template look sharp at print resolution.","md","image",{},"\u002Fdocs\u002Fguides\u002Fauthoring\u002Fdesign-for-pdf",{"title":5,"description":1133},"docs\u002Fguides\u002Fauthoring\u002Fdesign-for-pdf","7I5QDFtujtDaZUFmG96mNIDWDObOCFBw--M4qVrn1-k",[1142,1147,1151,1155,1159,1163,1167,1171,1172,1176,1179,1182,1187,1192,1196,1200,1205],{"path":1143,"title":1144,"description":1145,"category":1146,"order":639},"\u002Fdocs\u002Fguides\u002Fai-mcp\u002Fchatgpt","ChatGPT (via Custom GPT Actions)","ChatGPT doesn't speak MCP natively yet — but you can give it the same powers through a Custom GPT pointed at the Transactional REST API.","ai-mcp",{"path":1148,"title":1149,"description":1150,"category":1146,"order":123},"\u002Fdocs\u002Fguides\u002Fai-mcp\u002Fclaude-code","Claude Code (CLI)","Connect Transactional to Claude Code so it can read your templates and generate PDFs from your terminal.",{"path":1152,"title":1153,"description":1154,"category":1146,"order":92},"\u002Fdocs\u002Fguides\u002Fai-mcp\u002Fclaude-desktop","Claude Desktop","Connect Transactional to Claude Desktop on macOS or Windows so Claude can read your templates and generate PDFs.",{"path":1156,"title":1157,"description":1158,"category":1146,"order":136},"\u002Fdocs\u002Fguides\u002Fai-mcp\u002Fcursor","Cursor","Wire Transactional into Cursor's MCP support so you can generate PDFs from inside your editor.",{"path":1160,"title":1161,"description":1162,"category":1146,"order":648},"\u002Fdocs\u002Fguides\u002Fai-mcp\u002Fgemini","Gemini Code Assist \u002F Gemini CLI","Connect Transactional to Google's Gemini agents through their MCP support.",{"path":1164,"title":1165,"description":1166,"category":1146,"order":654},"\u002Fdocs\u002Fguides\u002Fai-mcp\u002Ftools-reference","MCP tools reference","Every tool the Transactional MCP server exposes, with arguments, return shapes, and a prompt that typically triggers each one.",{"path":1168,"title":1169,"description":1170,"category":1146,"order":85},"\u002Fdocs\u002Fguides\u002Fai-mcp\u002Fuse-from-ai","Use Transactional from your AI assistant","Connect Transactional to Claude, Cursor, ChatGPT, or Gemini via MCP so your assistant can read your templates and generate PDFs directly.",{"path":1137,"title":5,"description":1133,"category":1132,"order":92},{"path":1173,"title":1174,"description":1175,"category":1132,"order":85},"\u002Fdocs\u002Fguides\u002Fauthoring\u002Fhandlebars","Handlebars cheat sheet","The exact subset of Handlebars supported in Transactional templates — variables, conditionals, loops, and what NOT to reach for.",{"path":1097,"title":1177,"description":1178,"category":1132,"order":123},"Modeling your variables","When to make something a variable vs. inline. Keep the API contract small, your templates portable, and your integration code boring.",{"path":1106,"title":1180,"description":1181,"category":1132,"order":136},"Working with the AI assistant","Prompts and patterns to get good templates fast — what to ask, when to iterate, when to start over.",{"path":1183,"title":1184,"description":1185,"category":1186,"order":85},"\u002Fdocs\u002Fguides\u002Fgetting-started\u002Fquickstart","Quickstart — your first PDF in 5 minutes","Sign up, design a template, render your first PDF through the API. End-to-end in five minutes.","getting-started",{"path":1188,"title":1189,"description":1190,"category":1191,"order":85},"\u002Fdocs\u002Fguides\u002Fintegrations\u002Fnode-bun","Calling \u002Fv1\u002Fgenerate from Node.js & Bun","Production-grade integration using native fetch — retries, error handling, streaming the PDF to your storage.","integrations",{"path":1193,"title":1194,"description":1195,"category":1191,"order":92},"\u002Fdocs\u002Fguides\u002Fintegrations\u002Fphp-laravel","Calling \u002Fv1\u002Fgenerate from PHP & Laravel","cURL extension, Guzzle, or Laravel's HTTP client — render PDFs with retries and proper error handling.",{"path":1197,"title":1198,"description":1199,"category":1191,"order":123},"\u002Fdocs\u002Fguides\u002Fintegrations\u002Fpython","Calling \u002Fv1\u002Fgenerate from Python","urllib (stdlib), requests, or httpx with retry — render PDFs from Django, FastAPI, or any Python service.",{"path":1201,"title":1202,"description":1203,"category":1204,"order":85},"\u002Fdocs\u002Fguides\u002Foperations\u002Fmonitoring-usage","Monitoring usage & credits","Read the dashboard gauges, set sane alerts, and decide when to top up vs. upgrade.","operations",{"path":1206,"title":1207,"description":1208,"category":1204,"order":92},"\u002Fdocs\u002Fguides\u002Foperations\u002Fstoring-pdfs","Storing & serving the generated PDF","The \u002Fv1\u002Fgenerate URL is signed and short-lived. Patterns for keeping the PDF around — your bucket, your CDN, your DB.",1780347733852]