//load defaults cfg dict// The base configuration for the template// Don't delete any keys in this dictionary. The template depends on them.#letcfg=(// Metadatadate:"%today%",// use ISO format like 2022-01-01dateformat:"[year]-[month]-[day]",authors:(),title:"",subtitle:"",keywords:"",lang:"en",region:"US",// Layoutmargin:(x:2.5cm,top:3.5cm,bottom:3.5cm),paper:"a4",columns:1,color-fg:black,color-bg:white,// Numberingpage-numbering:"1",page-numbering-both:false,number-sections:false,section-numbering:"1.1.1.1.1",// Typographyfont:"noto sans",heading-font:"noto sans",code-font:"noto mono",header-footer-font:"noto sans",fontsize:11pt,leading:0.65em,spacing:1.2em,justify:true,smartquote:true,// Titlepagetitlepage-rule:3pt+black,titlepage-bg:white,titlepage-fg:black,titlepage-logo:none,titlepage-logo-width:none,titlepage-supervisor:none,// Table of contentstoc:false,toc-depth:6,toc-title:"Table of contents",toc-own-page:false,lof:false,lof-title:"List of figures",lof-own-page:false,lot:false,lot-title:"List of tables",lot-own-page:false,toc-page-numbering:"I",// Header and footerheader-footer-stroke:1pt+black,disable-header:false,disable-footer:false,header-left:"%title%",header-center:none,header-right:"%date%",footer-left:"%author%",footer-center:none,footer-right:"%page%",// Abstractabstract-title:"Abstract",abstract:none,abstract-own-page:false,thanks-title:"Thanks",thanks:none,// Figuresfigure-prefix:"Fig.",table-prefix:"Table",listing-prefix:"Listing",// Tablestable-header-bg:luma(200),table-striped-bg:luma(230),table-stroke-border-x:1pt+black,table-stroke-border-y:1pt+black,table-stroke-header-b:1pt+black,table-stroke-horizontal:1pt+black,table-stroke-vertical:1pt+black,table-inset:6pt,// Otherlistings:false,equation-numbering:none,glossary:none,)// load and join user cfg#letuser_cfg=none// these values override base values if provided#letuser_cfg=(dateformat:"[day].[month].[year]",authors:(),keywords:"",lang:"de",region:"CH",table-header-bg:orange.lighten(75%),table-striped-bg:orange.lighten(90%),table-stroke-border-x:none,table-stroke-border-y:1.5pt+orange.darken(50%),table-stroke-header-b:1.5pt+orange.darken(50%),table-stroke-vertical:0pt,table-stroke-horizontal:1pt+orange.darken(50%),)#(cfg=cfg+user_cfg)// overwrite base config from pandoc variables#letparsedDate="2026-01-22"#iftype(parsedDate)==str{letdateArray=parsedDate.split("-")parsedDate=datetime(year:int(dateArray.at(0)),month:int(dateArray.at(1)),day:int(dateArray.at(2)),)}#(cfg.date=parsedDate)// replace date placeholder#ifcfg.date=="%today%"{(cfg.date=datetime.today())}#(cfg.toc-depth=3)#(cfg.abstract-title=[Abstract])// for markdown hr#lethorizontalrule=line(start:(25%,0%),end:(75%,0%))// definition list styling#showterms:it=>{it.children.map(child=>[#strong[#child.term]#block(inset:(left:1.5em))[#child.description]]).join()}// author parsing#letauthors_oneline=cfg.authors.map(a=>a.name).join(", ")#ifauthors_oneline==none{authors_oneline=""}#letauthors_name_array=cfg.authors.map(a=>a.name)#letdisable-header=cfg.disable-header#letdisable-footer=cfg.disable-footer#letfont=cfg.font#letheader-footer-font=cfg.header-footer-font#letreplace_header_content(content)={ifcontent!=none{ifcontent=="%page%"{letboth=context{page.numbering.clusters().filter(c=>(cin("1","a","A","i","I","α","Α","*","א","一","壹","あ","い","ア","イ","ㄱ","가","\u{0661}","\u{06F1}","\u{0967}","\u{09E7}","\u{0995}","①","⓵",))).len()ifboth>=2{returncontextcounter(page).display(page.numbering,both:true)}}returncontextcounter(page).display(page.numbering)}returncontent.replace("%title%",cfg.title).replace("%date%",cfg.date.display(cfg.dateformat)).replace("%author%",authors_oneline)}}#(cfg.header-left=replace_header_content(cfg.header-left))#(cfg.header-center=replace_header_content(cfg.header-center))#(cfg.header-right=replace_header_content(cfg.header-right))#(cfg.footer-left=replace_header_content(cfg.footer-left))#(cfg.footer-center=replace_header_content(cfg.footer-center))#(cfg.footer-right=replace_header_content(cfg.footer-right))// Define a helper for the header#letmake-header()=context{ifdisable-header!=true[#settext(font:header-footer-font)#grid(columns:(auto,1fr,auto),align:(left,center,right),cfg.header-left,cfg.header-center,cfg.header-right,)#v(-par.spacing+0.5em)#line(length:100%,stroke:cfg.header-footer-stroke)]else[]}// Define a helper for the footer#letfooter-left()={letfl=cfg.footer-leftiflower(fl)=="none"{returnnone}else{returnfl}}#letfooter-right()={letfr=cfg.footer-rightiflower(fr)=="none"{returnnone}else{returnfr}}#letmake-footer()=context{ifdisable-footer!=true[#settext(font:header-footer-font)#line(length:100%,stroke:cfg.header-footer-stroke)#v(-par.spacing+0.5em)#grid(columns:(auto,1fr,auto),align:(left,center,right),footer-left(),cfg.footer-center,footer-right(),)]else[]}// setting pdf meta data#setdocument(title:cfg.title,keywords:cfg.keywords,date:cfg.date,author:authors_name_array,)#letmargin=cfg.margin#ifdisable-header==true{margin=(x:margin.x,top:margin.top-3em,bottom:margin.bottom)}#ifdisable-footer==true{margin=(x:margin.x,top:margin.top,bottom:margin.bottom-3em)}#setpage(paper:cfg.paper,margin:margin,numbering:cfg.page-numbering,)#letleading=cfg.leading#setpar(justify:cfg.justify,leading:leading,spacing:cfg.spacing,)#letfontsize=cfg.fontsize#settext(lang:cfg.lang,region:cfg.region,font:font,size:fontsize,)// set heading styles#letnumbering=none#ifcfg.number-sections{numbering=cfg.section-numbering}#setheading(numbering:numbering)#showheading:settext(font:cfg.heading-font)#showheading.where(level:1):settext(fontsize*1.3)#showheading.where(level:1):setblock(above:2.65em,below:1.75em)#showheading.where(level:2):settext(fontsize*1.1)#showheading.where(level:2):setblock(above:2em,below:1.375em)#showheading.where(level:3):setblock(above:2em,below:1em)// set figure styles#showfigure:setblock(above:2em,below:2em)#showfigure.where(kind:table):setfigure.caption(position:top)#showfigure.where(kind:table):setfigure(supplement:cfg.table-prefix)#showfigure.where(kind:image):setfigure.caption(position:bottom)#showfigure.where(kind:image):setfigure(supplement:cfg.figure-prefix)// listings#showfigure.where(kind:raw):setfigure.caption(position:bottom)#showfigure.where(kind:raw):setfigure(supplement:cfg.listing-prefix)#showfigure.where(kind:raw):setalign(left)// set captions to left#showfigure.caption:setalign(left)// indent lists#showlist:setlist(indent:6pt)#showenum:setenum(indent:6pt)// table styling#lettable-stroke=(x,y)=>(left:ifx==0{cfg.table-stroke-border-x}else{cfg.table-stroke-vertical},right:cfg.table-stroke-border-x,top:ify==0{cfg.table-stroke-border-y}elseify==1{cfg.table-stroke-header-b}else{cfg.table-stroke-horizontal},bottom:cfg.table-stroke-border-y,x:cfg.table-stroke-vertical,y:cfg.table-stroke-horizontal,)// fill for striped tables#letstriped=(x,y)=>{ify==0{cfg.table-header-bg}elseifcalc.even(y)andy>1{cfg.table-striped-bg}else{none}}#lettable-fill=(x,y)=>{ify==0{cfg.table-header-bg}else{none}}#settable(stroke:table-stroke,inset:cfg.table-inset,fill:table-fill,)#showtable:setpar(justify:false,linebreaks:"optimized")#showtable:settext(hyphenate:true,costs:(hyphenation:100000%))// set smart quotes#setsmartquote(enabled:cfg.smartquote)// reduce code line spacing#showraw.where(block:true):settext(1em/0.9)#showraw:settext(ligatures:true,font:cfg.code-font)// YAML-driven tables: load YAML, normalize to a grid, render Typst tables.// --- cell / column helpers ---#letyaml-cell(value)={iftype(value)==dictionaryandvalue.at("markup",default:false)==true{lettext=value.at("value",default:value.at("text",default:none))eval(str(iftext!=none{text}else{""}),mode:"markup")}elseiftype(value)==strandvalue.ends-with("!markup"){eval(value.slice(0,value.len()-7),mode:"markup")}else{[#value]}}#letparse-align(a)={ifa==auto{auto}elseiftype(a)==str{ifa=="left"{left}elseifa=="center"{center}elseifa=="right"{right}else{panic("unknown column align: "+a)}}else{a}}#letparse-width(w)={ifw==auto{auto}elseiftype(w)==str{eval(w)}else{w}}#letparse-column-spec(col)={iftype(col)==dictionaryand"id"incol{(id:str(col.id),label:col.at("label",default:str(col.id)),align:parse-align(col.at("align",default:auto)),width:parse-width(col.at("width",default:auto)),)}elseiftype(col)==dictionary{letkeys=col.keys()ifkeys.len()!=1{panic("column entry must have id/label or be a single-key dictionary")}letid=keys.at(0)(id:str(id),label:col.at(id),align:auto,width:auto,)}else{panic("invalid column spec: "+repr(col))}}#letrow-cells(row,col-ids)={col-ids.map(id=>{ifidnotinrow{panic("row missing column '"+id+"': "+repr(row))}yaml-cell(row.at(id))})}#letlegacy-single-key-rows(rows,col-ids)={letgrouped=()letbuf=(:)forrowinrows{iftype(row)!=dictionary{panic("expected dictionary row in legacy map format")}letkeys=row.keys()ifkeys.len()!=1{returnnone}letkey=keys.at(0)letval=row.at(key)buf.insert(str(key),val)ifbuf.len()==col-ids.len(){grouped.push(row-cells(buf,col-ids))buf=(:)}}ifbuf.len()!=0{panic("legacy row list does not divide evenly into "+str(col-ids.len())+" columns")}grouped}#letrows-are-legacy-single-key(rows)={ifrows.len()==0{returnfalse}rows.all(row=>type(row)==dictionaryandrow.len()==1)}// --- schema detection ---#letdetect-schema(raw)={iftype(raw)==dictionary{if"headers"inrawand"rows"inrawandtype(raw.headers)==array{ifraw.rows.len()>0andtype(raw.rows.at(0))==array{return"matrix"}}if"columns"inrawand"rows"inraw{return"map"}letreserved=("columns","rows","headers")letkeys=raw.keys()ifkeys.all(k=>knotinreserved){return"kv"}}iftype(raw)==arrayandraw.len()>0andtype(raw.at(0))==dictionary{return"records"}panic("could not detect YAML table schema; set schema: explicitly\n"+"data: "+repr(raw),)}// --- normalizers → grid model ---// grid: (headers, rows, col-keys, col-aligns, col-widths, header-default)#letnormalize-kv(raw)={letpairs=raw.pairs()letrows=pairs.map(p=>(yaml-cell(p.at(0)),yaml-cell(p.at(1))))(headers:none,rows:rows,col-keys:("key","value"),col-aligns:(auto,auto),col-widths:(auto,auto),header-default:false,)}#letnormalize-matrix(raw)={letheaders=raw.headers.map(h=>yaml-cell(h))letn=headers.len()letrows=raw.rows.map(r=>{ifr.len()!=n{panic("matrix row length "+str(r.len())+" != header count "+str(n))}r.map(c=>yaml-cell(c))})(headers:headers,rows:rows,col-keys:headers.map(h=>repr(h)),col-aligns:headers.map(_=>auto),col-widths:headers.map(_=>auto),header-default:true,)}#letnormalize-map(raw)={letcol-specs=raw.columns.map(parse-column-spec)letcol-ids=col-specs.map(c=>c.id)letheaders=col-specs.map(c=>yaml-cell(c.label))letcol-aligns=col-specs.map(c=>c.align)letcol-widths=col-specs.map(c=>c.width)letdata-rows=ifrows-are-legacy-single-key(raw.rows){legacy-single-key-rows(raw.rows,col-ids)}else{raw.rows.map(row=>{iftype(row)!=dictionary{panic("map row must be a dictionary")}row-cells(row,col-ids)})}ifdata-rows==none{panic("failed to normalize map rows")}(headers:headers,rows:data-rows,col-keys:col-ids,col-aligns:col-aligns,col-widths:col-widths,header-default:raw.at("header",default:true),)}#letnormalize-records(raw)={letcol-ids=ifraw.len()>0{raw.at(0).keys().map(k=>str(k))}else{()}letheaders=col-ids.map(id=>yaml-cell(id))letrows=raw.map(row=>row-cells(row,col-ids))(headers:headers,rows:rows,col-keys:col-ids,col-aligns:col-ids.map(_=>auto),col-widths:col-ids.map(_=>auto),header-default:true,)}#letnormalize(raw,schema)={letkind=ifschema==auto{detect-schema(raw)}elseiftype(schema)==str{schema}else{panic("schema must be auto or a string")}ifkind=="kv"{normalize-kv(raw)}elseifkind=="map"orkind=="grid"{normalize-map(raw)}elseifkind=="matrix"{normalize-matrix(raw)}elseifkind=="records"{normalize-records(raw)}else{panic("unknown schema: "+repr(kind))}}// --- rendering ---#letresolve-fill(fill,has-header:true)={ifhas-header{iffill==noneorfill==auto{none}elseiffill=="striped"{(x,y)=>{ify==0{cfg.table-header-bg}elseifcalc.even(y){cfg.table-striped-bg}else{none}}}else{fill}}elseiffill==noneorfill==auto{// Without table.header(), row 0 is data — override global header-row fill.(x,y)=>ify==0{white}else{none}}elseiffill=="striped"{(x,y)=>{ifcalc.even(y){cfg.table-striped-bg}else{none}}}else{letbase=fill(x,y)=>ify==0{white}else{base(x,y)}}}#letresolve-stroke(stroke,has-header:true)={ifhas-header{stroke}elseifstroke==auto{// Without table.header(), row 1 is data — use horizontal stroke, not header-b.table-stroke}elseiftype(stroke)==function{(x,y)=>{lets=table-stroke(x,y)ify==1andtype(s)==dictionary{s+(top:cfg.table-stroke-horizontal)}else{s}}}else{stroke}}#letresolve-header(header,grid)={ifheader==auto{ifgrid.header-default{grid.headers}else{none}}elseifheader==false{none}elseifheader==true{grid.headers}elseiftype(header)==array{header.map(h=>yaml-cell(h))}else{panic("header must be auto, true, false, or an array")}}#letbuild-table-args(grid,header-cells,columns,align,fill,stroke,inset,strong-header,table-args,)={letn=grid.col-keys.len()letcol-spec=ifcolumns!=auto{columns}else{letws=grid.col-widthsifws.all(w=>w==auto){// Typst defaults to a single column unless columns is set explicitly.n}else{ws}}letcol-aligns=ifalign!=auto{align}else{letgrid-aligns=grid.col-alignsifgrid-aligns.all(a=>a==auto){auto}else{grid-aligns}}lethas-header=header-cells!=noneletresolved-fill=resolve-fill(fill,has-header:has-header)letresolved-stroke=resolve-stroke(stroke,has-header:has-header)letargs=(columns:col-spec)ifcol-aligns!=auto{args.insert("align",col-aligns)}ifresolved-fill!=none{args.insert("fill",resolved-fill)}ifresolved-stroke!=auto{args.insert("stroke",resolved-stroke)}ifinset!=auto{args.insert("inset",inset)}for(k,v)intable-args.named(){args.insert(str(k),v)}letheader-row=ifheader-cells!=none{letcells=ifstrong-header{header-cells.map(c=>strong(c))}else{header-cells}(table.header(..cells),table.hline())}else{()}letflat-rows=()forrowingrid.rows{forcellinrow{flat-rows.push(cell)}}(args:args,header-row:header-row,flat-rows:flat-rows)}#letyaml-table(path,schema:auto,header:auto,columns:auto,align:auto,fill:none,stroke:auto,inset:auto,strong-header:true,as-figure:false,caption:none,kind:table,..table-args,)={letraw=yaml(path)letgrid=normalize(raw,schema)letheader-cells=resolve-header(header,grid)letbuilt=build-table-args(grid,header-cells,columns,align,fill,stroke,inset,strong-header,table-args,)lettbl=table(..built.args,..built.header-row,..built.flat-rows)ifas-figure{figure(tbl,caption:caption,kind:kind)}else{tbl}}#letyaml-table-figure(path,caption:none,..args)={yaml-table(path,as-figure:true,caption:caption,..args)}// listings#showraw.where(block:true):code=>{block(above:1.5em,below:1.5em)[#setpar(leading:leading*0.75)#code]}#import"@preview/note-me:0.6.0":*#setpage(numbering:cfg.page-numbering,header:make-header(),footer:make-footer(),columns:cfg.columns,)#counter(page).update(1)= Outline<outline>#outline(target:figure.where(kind:table))#figure(```markdown`#outline(target:figure.where(kind:table))`{=typst}```)= Tables Example<tables-example>#figure(align(center)[#table(columns:(12.39%,14.16%,73.45%),align:(left,center,right,),table.header([ColumnOne],[ColumnTwo],[ColumnThree],),table.hline(),[RowOneLeft],[RowOneCenter],[RowOneRight,whichshouldautomaticallybreakifitreachesthewidthofthepage],[RowTwoLeft],[RowTwoCenter],[RowTwoRight],[RowThreeLeft],[RowThreeCenter],[RowThreeRight],)],caption:[TablesCaption],kind:table)= Striped Table `{typst:fill=striped}`<striped-table-typstfillstriped>#figure(align(center)[#table(columns:3,align:(left,center,right,),fill:striped,table.header([ColumnOne],[ColumnTwo],[ColumnThree],),table.hline(),[RowOneLeft],[RowOneCenter],[RowOneRight],[RowTwoLeft],[RowTwoCenter],[RowTwoRight],[RowThreeLeft],[RowThreeCenter],[RowThreeRight],[RowFourLeft],[RowFourCenter],[RowFourRight],)],caption:[StripedTable],kind:table)= Table aligned left `{align=left}`<table-aligned-left-alignleft>#[#showfigure:setalign(left)#figure(align(center)[#table(columns:3,align:(left,center,right,),table.header([ColumnOne],[ColumnTwo],[ColumnThree],),table.hline(),[RowOneLeft],[RowOneCenter],[RowOneRight],[RowTwoLeft],[RowTwoCenter],[RowTwoRight],)],caption:[LeftTable],kind:table)]= Table right aligned `{align=right .unlisted}`<table-right-aligned-alignright-.unlisted>#[#showfigure:setalign(right)#figure(align(center)[#table(columns:3,align:(left,center,right,),table.header([ColumnOne],[ColumnTwo],[ColumnThree],),table.hline(),[RowOneLeft],[RowOneCenter],[RowOneRight],[RowTwoLeft],[RowTwoCenter],[RowTwoRight],)],caption:[UnlistedTable],numbering:none,outlined:false,kind:table)]= Plain Table `{typst:stroke=none}`<plain-table-typststrokenone>#figure(align(center)[#table(columns:3,align:(left,auto,auto,),stroke:none,[RowOne],[RowOne],[RowOne],[RowTwo],[RowTwo],[RowTwo],[RowThree],[RowThree],[RowThree],)],caption:[PlainTable],kind:table)= Table with custom column widths `{columns="(25%, 30%, 1fr)"}`<table-with-custom-column-widths-columns25-30-1fr>#figure(align(center)[#table(columns:(25%,30%,1fr),align:(left,left,left,),table.header([ColumnOne],[ColumnTwo],[ColumnThree],),table.hline(),[RowOneLeftwithsomeFachverantwortlicher],[RowOneCenter],[RowOneRight],[RowTwoLeft],[RowTwoCenter],[RowTwoRight],[RowThreeLeft],[RowThreeCenter\RowThreeafterbreak],[RowThreeRight],)],caption:[TablesCaption],kind:table)