@airmark/quiver 0.35.6 → 0.35.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/package.json +4 -4
  2. package/quills/af4141/0.1.0/Quill.yaml +39 -49
  3. package/quills/af4141/0.1.0/plate.typ +7 -7
  4. package/quills/afmc_moa/0.0.1/Quill.yaml +126 -153
  5. package/quills/afmc_moa/0.0.1/plate.typ +11 -11
  6. package/quills/classic_resume/0.1.0/Quill.yaml +34 -40
  7. package/quills/classic_resume/0.1.0/example.md +53 -59
  8. package/quills/classic_resume/0.1.0/plate.typ +11 -11
  9. package/quills/cyber_career_plan/0.1.0/Quill.yaml +258 -287
  10. package/quills/cyber_career_plan/0.1.0/plate.typ +92 -70
  11. package/quills/daf1206/0.1.0/plate.typ +18 -18
  12. package/quills/daf4392/0.1.0/Quill.yaml +33 -38
  13. package/quills/daf4392/0.1.0/plate.typ +16 -16
  14. package/quills/usaf_letter/0.1.0/Quill.yaml +143 -158
  15. package/quills/usaf_letter/0.1.0/packages/tonguetoquill-usaf-letter/src/frontmatter.typ +34 -19
  16. package/quills/usaf_letter/0.1.0/packages/tonguetoquill-usaf-letter/src/mainmatter.typ +1 -1
  17. package/quills/usaf_letter/0.1.0/packages/tonguetoquill-usaf-letter/src/primitives.typ +27 -9
  18. package/quills/usaf_letter/0.1.0/plate.typ +26 -28
  19. package/quills/usaf_memo/0.2.0/Quill.yaml +217 -247
  20. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/src/body.typ +15 -1
  21. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/src/frontmatter.typ +34 -19
  22. package/quills/usaf_memo/0.2.0/packages/tonguetoquill-usaf-memo/src/primitives.typ +5 -1
  23. package/quills/usaf_memo/0.2.0/plate.typ +28 -28
  24. package/quills/usaf_memo/0.3.0/Quill.yaml +219 -245
  25. package/quills/usaf_memo/0.3.0/packages/tonguetoquill-usaf-memo/src/body.typ +47 -15
  26. package/quills/usaf_memo/0.3.0/packages/tonguetoquill-usaf-memo/src/frontmatter.typ +34 -19
  27. package/quills/usaf_memo/0.3.0/packages/tonguetoquill-usaf-memo/src/primitives.typ +27 -9
  28. package/quills/usaf_memo/0.3.0/plate.typ +35 -36
  29. package/templates/classic_resume.md +53 -59
  30. package/templates/cyber_career_plan.md +56 -0
  31. package/templates/templates.json +7 -0
@@ -9,260 +9,230 @@ typst:
9
9
 
10
10
  main:
11
11
  description: Top-level body paragraphs are numbered and nested bullets lettered automatically; do not number them by hand.
12
- ui:
13
- groups: [addressing, letterhead, classification, additional]
14
- fields:
15
- memo_for:
16
- type: array
17
- items:
18
- type: string
19
- ui:
20
- group: addressing
21
- compact: true
22
- description: "Organization/office symbol in UPPERCASE. To address a specific person, add their rank and name in parentheses (e.g., 'ORG/SYMBOL (LT COL JANE DOE)'). For many recipients, enter 'SEE DISTRIBUTION' and list them in the Distribution field."
23
-
24
- memo_from:
25
- type: array
26
- items:
27
- type: string
28
- default: []
29
- ui:
30
- group: addressing
31
- compact: true
32
- description: "If recipients are on the same installation, use only the office symbol. For recipients on other installations, include the full mailing address, one line each, ending 'City ST 12345-6789', to enable return correspondence. Omit entirely to produce a Memorandum for Record (no MEMO FROM line)."
33
-
34
- subject:
35
- type: string
36
- ui:
37
- group: addressing
38
- description: Be brief and clear. Capitalize the first letter of each word except articles, prepositions, and conjunctions. Include suspense dates in parentheses if applicable.
39
-
40
- signature_block:
41
- type: array
42
- items:
43
- type: string
44
- ui:
45
- group: addressing
46
- compact: true
47
- description: "Line 1: Name in UPPERCASE as signed, grade, and service, as in 'FIRST M. LAST, Capt, USAF'. Line 2: Duty title."
48
-
49
- letterhead_title:
50
- type: string
51
- default: DEPARTMENT OF THE AIR FORCE
52
- ui:
53
- group: letterhead
54
- description: Change only for Joint Commands or DoW agencies.
55
-
56
- letterhead_caption:
57
- type: array
58
- items:
59
- type: string
60
- ui:
61
- group: letterhead
62
- description: The full organization name of your unit, as in HEADQUARTERS 123D EXAMPLE WING.
63
-
64
- letterhead_seal:
65
- type: enum
66
- values:
67
- - dow
68
- - dod
69
- default: dow
70
- ui:
71
- group: letterhead
72
- compact: true
73
- description: Department of War (DoW) or Department of Defense (DoD) seal shown in the letterhead.
74
-
75
- letterhead_seal_subtitle:
76
- type: string
77
- default: ""
78
- ui:
79
- group: letterhead
80
- compact: true
81
- description: Bold-caps line below the seal; blank to omit.
82
-
83
- tag_line:
84
- type: richtext
85
- inline: true
86
- default: ""
87
- ui:
88
- group: letterhead
89
- compact: true
90
- description: "Organizational motto at the bottom of the page. Supports Markdown emphasis (e.g. *italics*, **bold**)."
91
-
12
+ sections:
13
+ addressing:
14
+ fields:
15
+ memo_for:
16
+ type: array
17
+ items:
18
+ type: string
19
+ ui:
20
+ compact: true
21
+ description: "Organization/office symbol in UPPERCASE. To address a specific person, add their rank and name in parentheses (e.g., 'ORG/SYMBOL (LT COL JANE DOE)'). For many recipients, enter 'SEE DISTRIBUTION' and list them in the Distribution field."
22
+
23
+ memo_from:
24
+ type: array
25
+ items:
26
+ type: string
27
+ default: []
28
+ ui:
29
+ compact: true
30
+ description: "If recipients are on the same installation, use only the office symbol. For recipients on other installations, include the full mailing address, one line each, ending 'City ST 12345-6789', to enable return correspondence. Omit entirely to produce a Memorandum for Record (no MEMO FROM line)."
31
+
32
+ subject:
33
+ type: string
34
+ description: Be brief and clear. Capitalize the first letter of each word except articles, prepositions, and conjunctions. Include suspense dates in parentheses if applicable.
35
+
36
+ signature_block:
37
+ type: array
38
+ items:
39
+ type: string
40
+ ui:
41
+ compact: true
42
+ description: "Line 1: Name in UPPERCASE as signed, grade, and service, as in 'FIRST M. LAST, Capt, USAF'. Line 2: Duty title."
43
+ letterhead:
44
+ fields:
45
+ letterhead_title:
46
+ type: string
47
+ default: DEPARTMENT OF THE AIR FORCE
48
+ description: Change only for Joint Commands or DoW agencies.
49
+
50
+ letterhead_caption:
51
+ type: array
52
+ items:
53
+ type: string
54
+ description: The full organization name of your unit, as in HEADQUARTERS 123D EXAMPLE WING.
55
+
56
+ letterhead_seal:
57
+ type: enum
58
+ values:
59
+ - dow
60
+ - dod
61
+ default: dow
62
+ ui:
63
+ compact: true
64
+ description: Department of War (DoW) or Department of Defense (DoD) seal shown in the letterhead.
65
+
66
+ letterhead_seal_subtitle:
67
+ type: string
68
+ default: ""
69
+ ui:
70
+ compact: true
71
+ description: Bold-caps line below the seal; blank to omit.
72
+
73
+ tag_line:
74
+ type: richtext
75
+ inline: true
76
+ default: ""
77
+ ui:
78
+ compact: true
79
+ description: "Organizational motto at the bottom of the page. Supports Markdown emphasis (e.g. *italics*, **bold**)."
92
80
  classification:
93
- type: enum
94
- values:
95
- - UNCLASSIFIED
96
- - CUI
97
- - CONFIDENTIAL
98
- - SECRET
99
- - TOP SECRET
100
- default: ""
101
- ui:
102
- group: classification
103
- compact: true
104
- description: "Select the classification marking shown in the header and footer banner. Unclassified documents typically omit this banner entirely — leave blank unless the document is CUI or classified. Mark per DAFI 16-1404 (DoDM 5200.48 for CUI) and applicable DoD guidance."
105
-
106
- dissemination:
107
- type: string
108
- default: ""
109
- ui:
110
- group: classification
111
- compact: true
112
- description: "Banner dissemination suffix appended after double slash (e.g. 'NF' renders as CUI//NF in the header/footer). Leave blank for no suffix."
113
-
114
- cui_controlled_by:
115
- type: string
116
- default: ""
117
- ui:
118
- group: classification
119
- compact: true
120
- description: "Office or organization that designated this information as CUI (e.g., 'SAF/AA'). Required by DoDM 5200.48 when classification is CUI."
121
-
122
- cui_category:
123
- type: string
124
- default: ""
125
- ui:
126
- group: classification
127
- compact: true
128
- description: "CUI category from the DoD CUI Registry (e.g., 'Privacy/MED', 'CTI', 'PRVCY'). Leave blank to omit."
129
-
130
- cui_limited_dissemination:
131
- type: string
132
- default: ""
133
- ui:
134
- group: classification
135
- compact: true
136
- description: "Limited dissemination control shown in the indicator block (e.g., 'FEDONLY', 'NOFORN'). Independent from the banner suffix above."
137
-
138
- cui_poc:
139
- type: string
140
- default: ""
141
- ui:
142
- group: classification
143
- compact: true
144
- description: "Point of contact for CUI questions (e.g., 'Capt J. Smith, DSN 555-1234, john.smith@us.af.mil'). Required by DoDM 5200.48 when classification is CUI."
145
-
146
- references:
147
- type: array
148
- items:
149
- type: richtext
150
- inline: true
151
- default: []
152
- ui:
153
- group: additional
154
- description: "References, auto-lettered (a), (b), (c) per AFH 33-337. Cite each by organization, type, date, and title; italicize publication titles with *asterisks* (standard Markdown emphasis)."
155
-
156
- cc:
157
- type: array
158
- items:
159
- type: string
160
- default: []
161
- ui:
162
- group: additional
163
- description: List office symbols of recipients to receive copies; for a person, 'Rank and Name, ORG/SYMBOL'.
164
-
165
- distribution:
166
- type: array
167
- items:
168
- type: string
169
- default: []
170
- ui:
171
- group: additional
172
- description: Complete list of recipients if 'SEE DISTRIBUTION' is used in the 'Memo For' field.
81
+ fields:
82
+ classification:
83
+ type: enum
84
+ values:
85
+ - UNCLASSIFIED
86
+ - CUI
87
+ - CONFIDENTIAL
88
+ - SECRET
89
+ - TOP SECRET
90
+ default: ""
91
+ ui:
92
+ compact: true
93
+ description: "Select the classification marking shown in the header and footer banner. Unclassified documents typically omit this banner entirely — leave blank unless the document is CUI or classified. Mark per DAFI 16-1404 (DoDM 5200.48 for CUI) and applicable DoD guidance."
94
+
95
+ dissemination:
96
+ type: string
97
+ default: ""
98
+ ui:
99
+ compact: true
100
+ description: "Banner dissemination suffix appended after double slash (e.g. 'NF' renders as CUI//NF in the header/footer). Leave blank for no suffix."
173
101
 
174
- attachments:
175
- type: array
176
- items:
177
- type: string
178
- default: []
179
- ui:
180
- group: additional
181
- description: List attachments in the order they are mentioned in the memo. Briefly describe each and give its date; do not use 'as stated' or abbreviations.
102
+ cui_controlled_by:
103
+ type: string
104
+ default: ""
105
+ ui:
106
+ compact: true
107
+ description: "Office or organization that designated this information as CUI (e.g., 'SAF/AA'). Required by DoDM 5200.48 when classification is CUI."
182
108
 
183
- memo_style:
184
- type: enum
185
- values:
186
- - usaf
187
- - daf
188
- default: usaf
189
- ui:
190
- group: additional
191
- compact: true
192
- description: "USAF memorandum or DAF headquarters memorandum; DAF changes date format and body paragraph layout per AFH 33-337."
109
+ cui_category:
110
+ type: string
111
+ default: ""
112
+ ui:
113
+ compact: true
114
+ description: "CUI category from the DoD CUI Registry (e.g., 'Privacy/MED', 'CTI', 'PRVCY'). Leave blank to omit."
193
115
 
194
- font_size:
195
- type: number
196
- default: 12
197
- ui:
198
- group: additional
199
- compact: true
200
- description: Body text size in points; decimals allowed (e.g. 11.5).
116
+ cui_limited_dissemination:
117
+ type: string
118
+ default: ""
119
+ ui:
120
+ compact: true
121
+ description: "Limited dissemination control shown in the indicator block (e.g., 'FEDONLY', 'NOFORN'). Independent from the banner suffix above."
201
122
 
202
- date:
203
- type: date
204
- default: ""
205
- ui:
206
- group: additional
207
- compact: true
208
- description: YYYY-MM-DD. Leave blank to use today's date.
123
+ cui_poc:
124
+ type: string
125
+ default: ""
126
+ ui:
127
+ compact: true
128
+ description: "Point of contact for CUI questions (e.g., 'Capt J. Smith, DSN 555-1234, john.smith@us.af.mil'). Required by DoDM 5200.48 when classification is CUI."
129
+ additional:
130
+ fields:
131
+ references:
132
+ type: array
133
+ items:
134
+ type: richtext
135
+ inline: true
136
+ default: []
137
+ description: "References, auto-lettered (a), (b), (c) per AFH 33-337. Cite each by organization, type, date, and title; italicize publication titles with *asterisks* (standard Markdown emphasis)."
138
+
139
+ cc:
140
+ type: array
141
+ items:
142
+ type: string
143
+ default: []
144
+ description: List office symbols of recipients to receive copies; for a person, 'Rank and Name, ORG/SYMBOL'.
145
+
146
+ distribution:
147
+ type: array
148
+ items:
149
+ type: string
150
+ default: []
151
+ description: Complete list of recipients if 'SEE DISTRIBUTION' is used in the 'Memo For' field.
152
+
153
+ attachments:
154
+ type: array
155
+ items:
156
+ type: string
157
+ default: []
158
+ description: List attachments in the order they are mentioned in the memo. Briefly describe each and give its date; do not use 'as stated' or abbreviations.
159
+
160
+ memo_style:
161
+ type: enum
162
+ values:
163
+ - usaf
164
+ - daf
165
+ default: usaf
166
+ ui:
167
+ compact: true
168
+ description: "USAF memorandum or DAF headquarters memorandum; DAF changes date format and body paragraph layout per AFH 33-337."
169
+
170
+ font_size:
171
+ type: number
172
+ default: 12
173
+ ui:
174
+ compact: true
175
+ description: Body text size in points; decimals allowed (e.g. 11.5).
176
+
177
+ date:
178
+ type: date
179
+ default: ""
180
+ ui:
181
+ compact: true
182
+ description: YYYY-MM-DD. Leave blank to use today's date.
209
183
 
210
184
  card_kinds:
211
185
  indorsement:
212
186
  title: Routing indorsement
213
187
  description: Chain of routing endorsements. Each endorsement block adds an official response or forwarding action to the original memo.
214
- ui:
215
- groups: [addressing, additional]
216
- fields:
217
- from:
218
- type: string
219
- ui:
220
- group: addressing
221
- compact: true
222
- description: Office symbol or Rank Name of the endorsing official.
223
- for:
224
- type: string
225
- ui:
226
- group: addressing
227
- compact: true
228
- description: Office symbol or organization receiving the endorsed memo.
229
- signature_block:
230
- type: array
231
- items:
232
- type: string
233
- ui:
234
- group: addressing
235
- compact: true
236
- description: "Line 1: Name in UPPERCASE as signed, grade, and service, as in 'FIRST M. LAST, Capt, USAF'. Line 2: Duty title."
237
- format:
238
- type: enum
239
- values:
240
- - standard
241
- - informal
242
- - separate_page
243
- default: standard
244
- ui:
245
- group: additional
246
- compact: true
247
- description: "'standard' (formal, same page), 'informal' (less formal routing), or 'separate_page' (begins on a new page)."
248
- action:
249
- type: enum
250
- values:
251
- - undecided
252
- - approve
253
- - disapprove
254
- - undecided_concur
255
- - concur
256
- - nonconcur
257
- default: ""
258
- ui:
259
- group: additional
260
- compact: true
261
- description: "Decision taken by the endorser, shown as an either/or line with the choice circled. Leave blank to hide the line entirely. Approval authority: 'approve' or 'disapprove' (use 'undecided' to print Approve/Disapprove for the endorser to circle by hand). Coordinating official: 'concur' or 'nonconcur' (use 'undecided_concur' to print Concur/Nonconcur unmarked)."
262
- date:
263
- type: date
264
- default: ""
265
- ui:
266
- group: additional
267
- compact: true
268
- description: "YYYY-MM-DD. Date the endorser signs/forwards the memo (per AFH 33-337 Ch. 14, this is distinct from the originating memo's date). Leave blank to render a fill-in line for the endorser to date by hand when signing."
188
+ sections:
189
+ addressing:
190
+ fields:
191
+ from:
192
+ type: string
193
+ ui:
194
+ compact: true
195
+ description: Office symbol or Rank Name of the endorsing official.
196
+ for:
197
+ type: string
198
+ ui:
199
+ compact: true
200
+ description: Office symbol or organization receiving the endorsed memo.
201
+ signature_block:
202
+ type: array
203
+ items:
204
+ type: string
205
+ ui:
206
+ compact: true
207
+ description: "Line 1: Name in UPPERCASE as signed, grade, and service, as in 'FIRST M. LAST, Capt, USAF'. Line 2: Duty title."
208
+ additional:
209
+ fields:
210
+ format:
211
+ type: enum
212
+ values:
213
+ - standard
214
+ - informal
215
+ - separate_page
216
+ default: standard
217
+ ui:
218
+ compact: true
219
+ description: "'standard' (formal, same page), 'informal' (less formal routing), or 'separate_page' (begins on a new page)."
220
+ action:
221
+ type: enum
222
+ values:
223
+ - undecided
224
+ - approve
225
+ - disapprove
226
+ - undecided_concur
227
+ - concur
228
+ - nonconcur
229
+ default: ""
230
+ ui:
231
+ compact: true
232
+ description: "Decision taken by the endorser, shown as an either/or line with the choice circled. Leave blank to hide the line entirely. Approval authority: 'approve' or 'disapprove' (use 'undecided' to print Approve/Disapprove for the endorser to circle by hand). Coordinating official: 'concur' or 'nonconcur' (use 'undecided_concur' to print Concur/Nonconcur unmarked)."
233
+ date:
234
+ type: date
235
+ default: ""
236
+ ui:
237
+ compact: true
238
+ description: "YYYY-MM-DD. Date the endorser signs/forwards the memo (per AFH 33-337 Ch. 14, this is distinct from the originating memo's date). Leave blank to render a fill-in line for the endorser to date by hand when signing."
@@ -145,6 +145,20 @@
145
145
  })
146
146
  t
147
147
  }
148
+ // A `qm-table` wrapper's `align` places its table from outside it, so the
149
+ // placement is buffered with the table, and the emission spans the text
150
+ // width for it to place the table across.
151
+ show align: a => if a.body.func() == table {
152
+ PAR_BUFFER.update(pars => {
153
+ pars.push((
154
+ content: a,
155
+ nest_level: -1,
156
+ kind: "table",
157
+ ))
158
+ pars
159
+ })
160
+ none
161
+ } else { a }
148
162
  {
149
163
  show heading: h => {
150
164
  IS_HEADING.update(true)
@@ -268,7 +282,7 @@
268
282
  }
269
283
  let final_par = {
270
284
  if kind == "table" {
271
- render-memo-table(item_content)
285
+ block(width: 100%, render-memo-table(item_content))
272
286
  } else if kind == "continuation" {
273
287
  // Continuation block within a multi-block list item:
274
288
  // indent to align with preceding numbered paragraph's text, no new number.
@@ -92,6 +92,12 @@
92
92
  none
93
93
  }
94
94
 
95
+ let tag_line = if falsey(footer_tag_line) {
96
+ none
97
+ } else {
98
+ align(center, text(fill: LETTERHEAD_COLOR, font: "cinzel", size: 15pt)[#footer_tag_line])
99
+ }
100
+
95
101
  // Document-wide typography settings (inlined from configure())
96
102
  set par(leading: spacing.line, spacing: spacing.line, justify: false)
97
103
  set block(above: spacing.line, below: 0em, spacing: 0em)
@@ -138,14 +144,11 @@
138
144
  )
139
145
  }
140
146
 
141
- if not falsey(footer_tag_line) {
142
- place(
143
- bottom + center,
144
- dy: -0.625in,
145
- align(center)[
146
- #text(fill: LETTERHEAD_COLOR, font: "cinzel", size: 15pt)[#footer_tag_line]
147
- ],
148
- )
147
+ // Page 1's tag line rides the indicator block's float when there is one.
148
+ if tag_line != none {
149
+ context if cui_indicator == none or here().page() > 1 {
150
+ place(bottom + center, dy: -0.625in, tag_line)
151
+ }
149
152
  }
150
153
  },
151
154
  )
@@ -154,7 +157,8 @@
154
157
  // corner, dropped into the 0.5in page-edge band. Emitted as a bottom float so
155
158
  // it (1) reserves flow space, raising page 1's effective bottom margin so body
156
159
  // text never overlaps it, and (2) stays pinned to page 1 — as the first flow
157
- // content it can never be bumped to page 2.
160
+ // content it can never be bumped to page 2. Page 1's tag line stands above the
161
+ // block in the same float, since both claim the band.
158
162
  if cui_indicator != none {
159
163
  context {
160
164
  // The box shrink-wraps to its widest line; `set align(left)` keeps the
@@ -166,24 +170,35 @@
166
170
  set align(left)
167
171
  cui_indicator
168
172
  })
169
- // Reserve only the part of the block inside the text area (`reserved`):
170
- // float a box of that height, then `place` the full block inside it pushed
171
- // down by `overhang` so the surplus overflows into the edge band. (A bare
173
+ let block_height = measure(indicator_box).height
174
+ let tag_gap = 0.125in
175
+ let stack_height = if tag_line == none {
176
+ block_height
177
+ } else {
178
+ block_height + tag_gap + measure(tag_line, width: page.width - 2 * spacing.margin).height
179
+ }
180
+ // Reserve only the part of the stack inside the text area (`reserved`):
181
+ // float a box of that height, then `place` the stack inside it pushed down
182
+ // by `overhang` so the surplus overflows into the edge band. (A bare
172
183
  // `box(height: reserved, indicator_box)` overflows *upward* into the body
173
- // instead.) The inner `place` adds no size, so the box stays `reserved`
184
+ // instead.) The inner `place`s add no size, so the box stays `reserved`
174
185
  // tall and the block's bottom lands 0.5in from the page edge.
175
186
  let overhang = spacing.margin - 0.5in
176
- let reserved = measure(indicator_box).height - overhang
187
+ let reserved = stack_height - overhang
177
188
  place(
178
- bottom + right,
189
+ bottom,
179
190
  float: true,
180
- // Slide the right edge into the page-edge band, 0.5in from the border;
181
- // the inner place right-aligns the block to that edge.
182
- dx: spacing.margin - 0.5in,
183
191
  // Minimum gap to the body's last line; the actual gap is larger when the
184
192
  // next paragraph can't fit above the block and breaks to the next page.
185
193
  clearance: spacing.line,
186
- box(height: reserved, place(bottom + right, dy: overhang, indicator_box)),
194
+ box(width: 100%, height: reserved, {
195
+ // Slide the block's right edge into the page-edge band, 0.5in from
196
+ // the border.
197
+ place(bottom + right, dx: spacing.margin - 0.5in, dy: overhang, indicator_box)
198
+ if tag_line != none {
199
+ place(bottom + center, dy: overhang - block_height - tag_gap, tag_line)
200
+ }
201
+ }),
187
202
  )
188
203
  }
189
204
  }
@@ -358,7 +358,11 @@
358
358
  #let render-memo-table(it) = {
359
359
  // AFH 33-337 does not specify table formatting, so we follow the general
360
360
  // aesthetic principles of the standard: bold headers for clarity.
361
- show table.cell.where(y: 0): set text(weight: "bold")
361
+ // A headless table's first row is a body row, which Typst also numbers 0.
362
+ show table: t => if t.children.any(c => c.func() == table.header) {
363
+ show table.cell.where(y: 0): set text(weight: "bold")
364
+ t
365
+ } else { t }
362
366
  set table(
363
367
  stroke: 0.5pt + black,
364
368
  inset: (x: 0.5em, y: 0.4em),