@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,171 +9,156 @@ typst:
9
9
 
10
10
  main:
11
11
  description: "Write the letter as plain paragraphs; they aren't numbered. Use a block quote for lines that should stay as written, like an address. You can close with your phone number and email."
12
- ui:
13
- groups: [addressing, letterhead, classification, additional]
14
- fields:
15
- letter_from:
16
- type: array
17
- items:
18
- type: plaintext
19
- inline: true
20
- ui:
21
- group: addressing
22
- compact: true
23
- description: "Your rank and full name, then your duty title and mailing address, one per line. Don't put a comma between city and state."
24
-
25
- letter_for:
26
- type: array
27
- items:
28
- type: plaintext
29
- inline: true
30
- ui:
31
- group: addressing
32
- compact: true
33
- description: "The recipient's rank and full name, then their duty title and mailing address, one per line. Don't put a comma between city and state."
34
-
35
- salutation:
36
- type: plaintext
37
- inline: true
38
- ui:
39
- group: addressing
40
- compact: true
41
- description: "The greeting, for example 'Dear Major Smith', with no punctuation after the name."
42
-
43
- date:
44
- type: date
45
- default: ""
46
- ui:
47
- group: addressing
48
- compact: true
49
- description: "The date you sign. Leave blank to add a fillable date field to the PDF instead."
50
-
51
- complimentary_close:
52
- type: plaintext
53
- inline: true
54
- default: Sincerely
55
- ui:
56
- group: addressing
57
- compact: true
58
- description: "The closing above your signature. 'Sincerely' suits most letters."
59
-
60
- signature_block:
61
- type: array
62
- items:
63
- type: plaintext
64
- inline: true
65
- ui:
66
- group: addressing
67
- compact: true
68
- description: "Your name in uppercase, grade, and service, for example 'FIRST M. LAST, Col, USAF'. A personal letter leaves out the duty title."
69
-
70
- letterhead_title:
71
- type: array
72
- items:
73
- type: plaintext
74
- inline: true
75
- default:
76
- - DEPARTMENT OF THE AIR FORCE
77
- ui:
78
- group: letterhead
79
- description: "The letterhead, in uppercase. Keep the first line unless you work for a joint command or a DoW agency, and add your unit's full name on the lines below it."
80
-
81
- letterhead_seal:
82
- type: enum
83
- values:
84
- - dow
85
- - dod
86
- default: dow
87
- ui:
88
- group: letterhead
89
- compact: true
90
- description: "The seal at the top left of the letterhead: Department of War or Department of Defense."
91
-
92
- letterhead_seal_subtitle:
93
- type: plaintext
94
- inline: true
95
- default: ""
96
- ui:
97
- group: letterhead
98
- compact: true
99
- description: "An optional line in bold capitals under the seal."
100
-
101
- tag_line:
102
- type: richtext
103
- inline: true
104
- default: ""
105
- ui:
106
- group: letterhead
107
- compact: true
108
- description: "Your unit's motto, centered at the bottom of every page."
12
+ sections:
13
+ addressing:
14
+ fields:
15
+ letter_from:
16
+ type: array
17
+ items:
18
+ type: plaintext
19
+ inline: true
20
+ ui:
21
+ compact: true
22
+ description: "Your rank and full name, then your duty title and mailing address, one per line. Don't put a comma between city and state."
109
23
 
110
- classification:
111
- type: enum
112
- values:
113
- - UNCLASSIFIED
114
- - CUI
115
- - CONFIDENTIAL
116
- - SECRET
117
- - TOP SECRET
118
- default: ""
119
- ui:
120
- group: classification
121
- compact: true
122
- description: "The classification banner at the top and bottom of every page. Leave blank for an unclassified document."
123
- variants:
124
- CUI:
125
- controlled_by:
24
+ letter_for:
25
+ type: array
26
+ items:
126
27
  type: plaintext
127
28
  inline: true
128
- description: "The office that designated this information as CUI, for example 'SAF/AA'."
129
- poc:
29
+ ui:
30
+ compact: true
31
+ description: "The recipient's rank and full name, then their duty title and mailing address, one per line. Don't put a comma between city and state."
32
+
33
+ salutation:
34
+ type: plaintext
35
+ inline: true
36
+ ui:
37
+ compact: true
38
+ description: "The greeting, for example 'Dear Major Smith', with no punctuation after the name."
39
+
40
+ date:
41
+ type: date
42
+ default: ""
43
+ ui:
44
+ compact: true
45
+ description: "The date you sign. Leave blank to add a fillable date field to the PDF instead."
46
+
47
+ complimentary_close:
48
+ type: plaintext
49
+ inline: true
50
+ default: Sincerely
51
+ ui:
52
+ compact: true
53
+ description: "The closing above your signature. 'Sincerely' suits most letters."
54
+
55
+ signature_block:
56
+ type: array
57
+ items:
130
58
  type: plaintext
131
59
  inline: true
132
- description: "Who to contact with questions about this CUI, with phone and email, for example 'Capt J. Smith, DSN 555-1234, john.smith@us.af.mil'."
133
- category:
60
+ ui:
61
+ compact: true
62
+ description: "Your name in uppercase, grade, and service, for example 'FIRST M. LAST, Col, USAF'. A personal letter leaves out the duty title."
63
+ letterhead:
64
+ fields:
65
+ letterhead_title:
66
+ type: array
67
+ items:
134
68
  type: plaintext
135
69
  inline: true
136
- default: ""
137
- description: "The category from the DoD CUI Registry, for example 'CTI' or 'PRVCY'."
138
- limited_dissemination:
70
+ default:
71
+ - DEPARTMENT OF THE AIR FORCE
72
+ description: "The letterhead, in uppercase. Keep the first line unless you work for a joint command or a DoW agency, and add your unit's full name on the lines below it."
73
+
74
+ letterhead_seal:
75
+ type: enum
76
+ values:
77
+ - dow
78
+ - dod
79
+ default: dow
80
+ ui:
81
+ compact: true
82
+ description: "The seal at the top left of the letterhead: Department of War or Department of Defense."
83
+
84
+ letterhead_seal_subtitle:
85
+ type: plaintext
86
+ inline: true
87
+ default: ""
88
+ ui:
89
+ compact: true
90
+ description: "An optional line in bold capitals under the seal."
91
+
92
+ tag_line:
93
+ type: richtext
94
+ inline: true
95
+ default: ""
96
+ ui:
97
+ compact: true
98
+ description: "Your unit's motto, centered at the bottom of every page."
99
+ classification:
100
+ fields:
101
+ classification:
102
+ type: enum
103
+ values:
104
+ - UNCLASSIFIED
105
+ - CUI
106
+ - CONFIDENTIAL
107
+ - SECRET
108
+ - TOP SECRET
109
+ default: ""
110
+ ui:
111
+ compact: true
112
+ description: "The classification banner at the top and bottom of every page. Leave blank for an unclassified document."
113
+ variants:
114
+ CUI:
115
+ controlled_by:
116
+ type: plaintext
117
+ inline: true
118
+ description: "The office that designated this information as CUI, for example 'SAF/AA'."
119
+ poc:
120
+ type: plaintext
121
+ inline: true
122
+ description: "Who to contact with questions about this CUI, with phone and email, for example 'Capt J. Smith, DSN 555-1234, john.smith@us.af.mil'."
123
+ category:
124
+ type: plaintext
125
+ inline: true
126
+ default: ""
127
+ description: "The category from the DoD CUI Registry, for example 'CTI' or 'PRVCY'."
128
+ limited_dissemination:
129
+ type: plaintext
130
+ inline: true
131
+ default: ""
132
+ description: "A dissemination control for the CUI block, for example 'FEDONLY' or 'NOFORN'. To add one to the banner, use Dissemination."
133
+
134
+ dissemination:
135
+ type: plaintext
136
+ inline: true
137
+ default: ""
138
+ ui:
139
+ compact: true
140
+ description: "A control added to the end of the banner. For example, 'NF' prints as CUI//NF."
141
+ additional:
142
+ fields:
143
+ cc:
144
+ type: array
145
+ items:
139
146
  type: plaintext
140
147
  inline: true
141
- default: ""
142
- description: "A dissemination control for the CUI block, for example 'FEDONLY' or 'NOFORN'. To add one to the banner, use Dissemination."
148
+ default: []
149
+ description: Offices or people receiving a courtesy copy, one per line.
143
150
 
144
- dissemination:
145
- type: plaintext
146
- inline: true
147
- default: ""
148
- ui:
149
- group: classification
150
- compact: true
151
- description: "A control added to the end of the banner. For example, 'NF' prints as CUI//NF."
152
-
153
- cc:
154
- type: array
155
- items:
156
- type: plaintext
157
- inline: true
158
- default: []
159
- ui:
160
- group: additional
161
- description: Offices or people receiving a courtesy copy, one per line.
162
-
163
- attachments:
164
- type: array
165
- items:
166
- type: richtext
167
- inline: true
168
- default: []
169
- ui:
170
- group: additional
171
- description: "Attachments in the order the letter mentions them. Describe each briefly and include its date. Don't write 'as stated'."
172
-
173
- font_size:
174
- type: number
175
- default: 12
176
- ui:
177
- group: additional
178
- compact: true
179
- description: "Body text size in points. The standard is 12."
151
+ attachments:
152
+ type: array
153
+ items:
154
+ type: richtext
155
+ inline: true
156
+ default: []
157
+ description: "Attachments in the order the letter mentions them. Describe each briefly and include its date. Don't write 'as stated'."
158
+
159
+ font_size:
160
+ type: number
161
+ default: 12
162
+ ui:
163
+ compact: true
164
+ description: "Body text size in points. The standard is 12."
@@ -80,6 +80,12 @@
80
80
  none
81
81
  }
82
82
 
83
+ let tag-line = if falsey(footer-tag-line) {
84
+ none
85
+ } else {
86
+ align(center, text(fill: LETTERHEAD_COLOR, font: "Spectral SC", size: 15pt)[#footer-tag-line])
87
+ }
88
+
83
89
  set par(leading: spacing.line, spacing: spacing.line, justify: false)
84
90
  set block(above: spacing.line, below: 0em, spacing: 0em)
85
91
  set text(font: body-font, size: font-size, fallback: true)
@@ -126,14 +132,11 @@
126
132
  )
127
133
  }
128
134
 
129
- if not falsey(footer-tag-line) {
130
- place(
131
- bottom + center,
132
- dy: -0.625in,
133
- align(center)[
134
- #text(fill: LETTERHEAD_COLOR, font: "Spectral SC", size: 15pt)[#footer-tag-line]
135
- ],
136
- )
135
+ // Page 1's tag line rides the indicator block's float when there is one.
136
+ if tag-line != none {
137
+ context if cui-indicator == none or here().page() > 1 {
138
+ place(bottom + center, dy: -0.625in, tag-line)
139
+ }
137
140
  }
138
141
  },
139
142
  )
@@ -142,7 +145,8 @@
142
145
  // corner, dropped into the 0.5in page-edge band. Emitted as a bottom float so
143
146
  // it (1) reserves flow space, raising page 1's effective bottom margin so body
144
147
  // text never overlaps it, and (2) stays pinned to page 1 — as the first flow
145
- // content it can never be bumped to page 2.
148
+ // content it can never be bumped to page 2. Page 1's tag line stands above the
149
+ // block in the same float, since both claim the band.
146
150
  if cui-indicator != none {
147
151
  context {
148
152
  // The box shrink-wraps to its widest line; `set align(left)` keeps the
@@ -154,24 +158,35 @@
154
158
  set align(left)
155
159
  cui-indicator
156
160
  })
157
- // Reserve only the part of the block inside the text area (`reserved`):
158
- // float a box of that height, then `place` the full block inside it pushed
159
- // down by `overhang` so the surplus overflows into the edge band. (A bare
161
+ let block-height = measure(indicator-box).height
162
+ let tag-gap = 0.125in
163
+ let stack-height = if tag-line == none {
164
+ block-height
165
+ } else {
166
+ block-height + tag-gap + measure(tag-line, width: page.width - 2 * spacing.margin).height
167
+ }
168
+ // Reserve only the part of the stack inside the text area (`reserved`):
169
+ // float a box of that height, then `place` the stack inside it pushed down
170
+ // by `overhang` so the surplus overflows into the edge band. (A bare
160
171
  // `box(height: reserved, indicator-box)` overflows *upward* into the body
161
- // instead.) The inner `place` adds no size, so the box stays `reserved`
172
+ // instead.) The inner `place`s add no size, so the box stays `reserved`
162
173
  // tall and the block's bottom lands 0.5in from the page edge.
163
174
  let overhang = spacing.margin - 0.5in
164
- let reserved = measure(indicator-box).height - overhang
175
+ let reserved = stack-height - overhang
165
176
  place(
166
- bottom + right,
177
+ bottom,
167
178
  float: true,
168
- // Slide the right edge into the page-edge band, 0.5in from the border;
169
- // the inner place right-aligns the block to that edge.
170
- dx: spacing.margin - 0.5in,
171
179
  // Minimum gap to the body's last line; the actual gap is larger when the
172
180
  // next paragraph can't fit above the block and breaks to the next page.
173
181
  clearance: spacing.line,
174
- box(height: reserved, place(bottom + right, dy: overhang, indicator-box)),
182
+ box(width: 100%, height: reserved, {
183
+ // Slide the block's right edge into the page-edge band, 0.5in from
184
+ // the border.
185
+ place(bottom + right, dx: spacing.margin - 0.5in, dy: overhang, indicator-box)
186
+ if tag-line != none {
187
+ place(bottom + center, dy: overhang - block-height - tag-gap, tag-line)
188
+ }
189
+ }),
175
190
  )
176
191
  }
177
192
  }
@@ -76,7 +76,7 @@
76
76
  NESTED.update(n => n + 1)
77
77
  context {
78
78
  let last = BLOCKS.get() == BLOCKS.final()
79
- block(above: par.spacing, sticky: last and keeps-signature(it), it)
79
+ block(above: par.spacing, below: par.spacing, sticky: last and keeps-signature(it), it)
80
80
  }
81
81
  NESTED.update(n => n - 1)
82
82
  }
@@ -197,7 +197,10 @@
197
197
  // spaces to the right of page center"
198
198
  // AFH 33-337 "Do not place the signature element on a continuation page by itself"
199
199
  // AFH 33-337 long-name example: "Signature block adjusted to the left" when a
200
- // long name would otherwise exceed the right margin.
200
+ // long name would otherwise exceed the right margin. Only the name line moves
201
+ // the block; any other line that runs long wraps, its overflow beginning "under
202
+ // the third character of the line above". The handbook gives no measurement,
203
+ // so the indent is the width of the line's own first two characters.
201
204
  //
202
205
  // A closing line may open the section above the block, and AFH 33-337 gives it
203
206
  // one geometry across the two documents that have one: on the second line below
@@ -215,6 +218,17 @@
215
218
  /// -> content | none
216
219
  #let format-authority-line(value) = if falsey(value) { none } else { upper(value) }
217
220
 
221
+ // A signature line arrives as `str` or as content; the indent measures its text.
222
+ #let plain-text(it) = {
223
+ if type(it) == str { return it }
224
+ if type(it) != content { return "" }
225
+ if it.has("text") { return plain-text(it.text) }
226
+ if it.has("children") { return it.children.map(plain-text).join(default: "") }
227
+ if it.has("body") { return plain-text(it.body) }
228
+ if it.has("child") { return plain-text(it.child) }
229
+ ""
230
+ }
231
+
218
232
  #let render-signature-block(
219
233
  signature-lines,
220
234
  closing-line: none,
@@ -234,11 +248,11 @@
234
248
  // anchor. pad() is relative to the text area, hence (4.5in - margin).
235
249
  let default-pad = 4.5in - spacing.margin
236
250
  context {
237
- // Measure each line at its rendered settings to detect long-name overflow.
238
- // The closing line shares the anchor, so it joins the measurement: the
239
- // wider of the two decides the shift and they stay aligned.
251
+ // Measure the name line at its rendered settings to detect long-name
252
+ // overflow. The closing line shares the anchor, so it joins the
253
+ // measurement: the wider of the two decides the shift and they stay aligned.
240
254
  let body-width = page.width - 2 * spacing.margin
241
- let anchored-lines = signature-lines
255
+ let anchored-lines = signature-lines.slice(0, calc.min(1, signature-lines.len()))
242
256
  if closing-line != none { anchored-lines.push(closing-line) }
243
257
  let widest = 0pt
244
258
  for line in anchored-lines {
@@ -305,9 +319,9 @@
305
319
  #pad(left: left-pad)[
306
320
  #text(hyphenate: false)[
307
321
  #for line in signature-lines {
308
- // AFH 33-337: "indent the next line to begin under the third character
309
- // of the line above" — 2-character indent ≈ 1em in Times New Roman 12pt
310
- par(hanging-indent: .5em, line)
322
+ let clusters = plain-text(line).clusters()
323
+ let lead = clusters.slice(0, calc.min(2, clusters.len())).join()
324
+ par(hanging-indent: measure(lead).width, line)
311
325
  }
312
326
  // The page the backmatter compares its own against. Must stay
313
327
  // inside the unbreakable block: a marker outside one travels with
@@ -393,7 +407,11 @@
393
407
  /// - it (content): The table element to style and render
394
408
  /// -> content
395
409
  #let render-memo-table(it) = {
396
- show table.cell.where(y: 0): set text(weight: "bold")
410
+ // A headless table's first row is a body row, which Typst also numbers 0.
411
+ show table: t => if t.children.any(c => c.func() == table.header) {
412
+ show table.cell.where(y: 0): set text(weight: "bold")
413
+ t
414
+ } else { t }
397
415
  set table(
398
416
  stroke: 0.5pt + black,
399
417
  inset: (x: 0.5em, y: 0.4em),
@@ -1,6 +1,4 @@
1
- #import "@local/quillmark-helper:0.1.0": (
2
- data, display, form-field, signature-field,
3
- )
1
+ #import "@local/quillmark-helper:0.2.0" as qm
4
2
  #import "@local/tonguetoquill-usaf-letter:0.1.0": (
5
3
  backmatter, date-pattern, frontmatter, mainmatter,
6
4
  )
@@ -10,10 +8,10 @@
10
8
  // the title alone — the package skips a falsey caption. An empty array renders
11
9
  // no letterhead text at all, silently: the block is `place`d, so an empty title
12
10
  // leaves no glyphs and takes no space from the flow, and the seal stands alone.
13
- #let letterhead_lines = data.letterhead_title
11
+ #let letterhead_lines = qm.data.letterhead_title
14
12
 
15
13
  // Body text size, in points. Also the height of a blank date's fill-in widget.
16
- #let body_font_size = data.font_size * 1pt
14
+ #let body_font_size = qm.data.font_size * 1pt
17
15
 
18
16
  // A blank date's fill-in slot: an empty AcroForm text box the signer types the
19
17
  // date into, set in the body face and flush right, as the printed date would
@@ -27,7 +25,7 @@
27
25
  #let date_slot(name, field) = context box(
28
26
  width: date_slot_width,
29
27
  height: measure[0].height,
30
- place(horizon + left, form-field(
28
+ place(horizon + left, qm.form-field(
31
29
  name,
32
30
  type: "text",
33
31
  width: date_slot_width,
@@ -42,10 +40,10 @@
42
40
  #show: frontmatter.with(
43
41
  letterhead-title: letterhead_lines.at(0, default: ""),
44
42
  letterhead-caption: if letterhead_lines.len() > 1 { letterhead_lines.slice(1) } else { () },
45
- letterhead-seal-subtitle: data.letterhead_seal_subtitle,
43
+ letterhead-seal-subtitle: qm.data.letterhead_seal_subtitle,
46
44
  // A letter has no seal-less state, so the blank takes the default, DoW.
47
45
  letterhead-seal: image(
48
- if data.letterhead_seal == "dod" {
46
+ if qm.data.letterhead_seal == "dod" {
49
47
  "assets/dod_seal.png"
50
48
  } else {
51
49
  "assets/dow_seal.png"
@@ -54,7 +52,7 @@
54
52
 
55
53
  // Date. `data.date` is the native `datetime` and would render identically,
56
54
  // but its ink would be born inside the package and carry no schema address.
57
- // `display` places the field's *content* projection instead: the glyphs are
55
+ // `qm.ink` places the field's *content* projection instead: the glyphs are
58
56
  // born in the generated helper, so the letter's date stays click-to-edit
59
57
  // however deep the package formats it.
60
58
  //
@@ -63,33 +61,33 @@
63
61
  // than stamped with the compile date. Passing it as the date also keeps it
64
62
  // from `frontmatter`'s own `datetime.today()` fallback.
65
63
  date: {
66
- let authored = display("date", date-pattern())
64
+ let authored = qm.ink(qm.data, "date", date-pattern())
67
65
  if authored != none { authored } else { date_slot("Date", "date") }
68
66
  },
69
67
 
70
- letter-from: data.letter_from,
71
- letter-for: data.letter_for,
72
- salutation: data.salutation,
68
+ letter-from: qm.data.letter_from,
69
+ letter-for: qm.data.letter_for,
70
+ salutation: qm.data.salutation,
73
71
 
74
- footer-tag-line: data.tag_line,
72
+ footer-tag-line: qm.data.tag_line,
75
73
 
76
74
  // The blank reads as no banner, which is what the package's own
77
75
  // `classification-level: none` default means.
78
- classification-level: data.classification.value,
76
+ classification-level: qm.data.classification.value,
79
77
 
80
- dissemination: data.dissemination,
78
+ dissemination: qm.data.dissemination,
81
79
 
82
80
  // CUI designation indicator block fields (DoDM 5200.48). `classification`
83
81
  // declares a `CUI` variant, so these four exist only where the discriminant
84
82
  // reads CUI, and the branch is what makes reading them total: inside it every
85
83
  // declared field of that world is present, outside it none is. The package's
86
84
  // own `cui_*: none` defaults cover the worlds that omit them.
87
- ..if data.classification.value == "CUI" {
85
+ ..if qm.data.classification.value == "CUI" {
88
86
  (
89
- cui-controlled-by: data.classification.controlled_by,
90
- cui-category: data.classification.category,
91
- cui-limited-dissemination: data.classification.limited_dissemination,
92
- cui-poc: data.classification.poc,
87
+ cui-controlled-by: qm.data.classification.controlled_by,
88
+ cui-category: qm.data.classification.category,
89
+ cui-limited-dissemination: qm.data.classification.limited_dissemination,
90
+ cui-poc: qm.data.classification.poc,
93
91
  )
94
92
  },
95
93
 
@@ -98,24 +96,24 @@
98
96
 
99
97
  // An empty body reaches the plate as `""`, and `mainmatter` would still set a
100
98
  // blank paragraph for it, dropping the close two lines too far.
101
- #if data.at("$body") != "" {
102
- mainmatter[#data.at("$body")]
99
+ #if qm.data.at("$body") != "" {
100
+ mainmatter[#qm.data.at("$body")]
103
101
  }
104
102
 
105
103
  #backmatter(
106
- complimentary-close: data.complimentary_close,
107
- signature-block: data.signature_block,
104
+ complimentary-close: qm.data.complimentary_close,
105
+ signature-block: qm.data.signature_block,
108
106
  // The widget sits at the bottom of AFH 33-337's four blank lines and is
109
107
  // sized to two and a half of them, so the line and a half above it stays
110
108
  // clear of the complimentary close without moving the block off the fifth
111
109
  // line.
112
- signing-field: signature-field(
110
+ signing-field: qm.signature-field(
113
111
  "Signature",
114
112
  field: "signature_block",
115
113
  height: body_font_size * 2.5,
116
114
  ),
117
115
 
118
- ..if data.attachments.len() > 0 { (attachments: data.attachments) },
116
+ ..if qm.data.attachments.len() > 0 { (attachments: qm.data.attachments) },
119
117
 
120
- ..if data.cc.len() > 0 { (cc: data.cc) },
118
+ ..if qm.data.cc.len() > 0 { (cc: qm.data.cc) },
121
119
  )