@baravak/risloo-profile-cli 4.82.0 → 4.83.0

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.
@@ -0,0 +1,490 @@
1
+ const { Profile } = require("../Profile");
2
+
3
+ const BAR_WIDTH_COEFFICIENT = 125;
4
+
5
+ const FACTOR_SPECS = [
6
+ {
7
+ key: "realistic",
8
+ title: "واقع‌گرا",
9
+ maxAbs: 114,
10
+ section: "realistic",
11
+ level: "general",
12
+ },
13
+ {
14
+ key: "mechanics_construction",
15
+ title: "مکانیک و ساخت‌وساز",
16
+ maxAbs: 18,
17
+ section: "realistic",
18
+ },
19
+ {
20
+ key: "computer_hardware_electronics",
21
+ title: "سخت‌افزار کامپیوتر و الکترونیک",
22
+ maxAbs: 12,
23
+ section: "realistic",
24
+ },
25
+ { key: "military", title: "امور نظامی", maxAbs: 12, section: "realistic" },
26
+ {
27
+ key: "protective_services",
28
+ title: "خدمات حفاظتی و ایمنی",
29
+ maxAbs: 10,
30
+ section: "realistic",
31
+ },
32
+ {
33
+ key: "nature_agriculture",
34
+ title: "طبیعت و کشاورزی",
35
+ maxAbs: 20,
36
+ section: "realistic",
37
+ },
38
+ {
39
+ key: "athletics",
40
+ title: "فعالیت‌های ورزشی",
41
+ maxAbs: 18,
42
+ section: "realistic",
43
+ },
44
+
45
+ {
46
+ key: "investigative",
47
+ title: "جستجوگر",
48
+ maxAbs: 82,
49
+ section: "investigative",
50
+ level: "general",
51
+ },
52
+ { key: "science", title: "علوم", maxAbs: 20, section: "investigative" },
53
+ { key: "research", title: "پژوهش", maxAbs: 20, section: "investigative" },
54
+ {
55
+ key: "medical_science",
56
+ title: "علوم پزشکی",
57
+ maxAbs: 14,
58
+ section: "investigative",
59
+ },
60
+ { key: "mathematics", title: "ریاضیات", maxAbs: 12, section: "investigative" },
61
+
62
+ {
63
+ key: "artistic",
64
+ title: "هنری",
65
+ maxAbs: 86,
66
+ section: "artistic",
67
+ level: "general",
68
+ },
69
+ {
70
+ key: "visual_arts_design",
71
+ title: "هنرهای تجسمی و طراحی",
72
+ maxAbs: 16,
73
+ section: "artistic",
74
+ },
75
+ {
76
+ key: "performing_arts",
77
+ title: "هنرهای نمایشی",
78
+ maxAbs: 20,
79
+ section: "artistic",
80
+ },
81
+ {
82
+ key: "writing_mass_communication",
83
+ title: "نویسندگی و ارتباطات جمعی",
84
+ maxAbs: 20,
85
+ section: "artistic",
86
+ },
87
+ {
88
+ key: "culinary_arts",
89
+ title: "هنرهای آشپزی",
90
+ maxAbs: 10,
91
+ section: "artistic",
92
+ },
93
+
94
+ {
95
+ key: "social",
96
+ title: "اجتماعی",
97
+ maxAbs: 100,
98
+ section: "social",
99
+ level: "general",
100
+ },
101
+ {
102
+ key: "counseling_helping",
103
+ title: "مشاوره و کمک‌رسانی",
104
+ maxAbs: 22,
105
+ section: "social",
106
+ },
107
+ {
108
+ key: "teaching_education",
109
+ title: "آموزش و تعلیم",
110
+ maxAbs: 18,
111
+ section: "social",
112
+ },
113
+ {
114
+ key: "human_resources_training",
115
+ title: "منابع انسانی و آموزش",
116
+ maxAbs: 8,
117
+ section: "social",
118
+ },
119
+ {
120
+ key: "social_sciences",
121
+ title: "علوم اجتماعی",
122
+ maxAbs: 8,
123
+ section: "social",
124
+ },
125
+ {
126
+ key: "religion_spirituality",
127
+ title: "دین و معنویت",
128
+ maxAbs: 14,
129
+ section: "social",
130
+ },
131
+ {
132
+ key: "healthcare_services",
133
+ title: "خدمات مراقبت سلامت",
134
+ maxAbs: 8,
135
+ section: "social",
136
+ },
137
+
138
+ {
139
+ key: "enterprising",
140
+ title: "پیشرو",
141
+ maxAbs: 138,
142
+ section: "enterprising",
143
+ level: "general",
144
+ },
145
+ {
146
+ key: "marketing_advertising",
147
+ title: "بازاریابی و تبلیغات",
148
+ maxAbs: 10,
149
+ section: "enterprising",
150
+ },
151
+ { key: "sales", title: "فروش", maxAbs: 16, section: "enterprising" },
152
+ { key: "management", title: "مدیریت", maxAbs: 12, section: "enterprising" },
153
+ {
154
+ key: "entrepreneurship",
155
+ title: "کارآفرینی",
156
+ maxAbs: 10,
157
+ section: "enterprising",
158
+ },
159
+ {
160
+ key: "politics_public_speaking",
161
+ title: "سیاست و سخنرانی عمومی",
162
+ maxAbs: 18,
163
+ section: "enterprising",
164
+ },
165
+ { key: "law", title: "حقوق", maxAbs: 14, section: "enterprising" },
166
+
167
+ {
168
+ key: "conventional",
169
+ title: "قراردادی",
170
+ maxAbs: 60,
171
+ section: "conventional",
172
+ level: "general",
173
+ },
174
+ {
175
+ key: "office_management",
176
+ title: "مدیریت امور اداری",
177
+ maxAbs: 8,
178
+ section: "conventional",
179
+ },
180
+ {
181
+ key: "taxes_accounting",
182
+ title: "مالیات و حسابداری",
183
+ maxAbs: 10,
184
+ section: "conventional",
185
+ },
186
+ {
187
+ key: "programming_information_systems",
188
+ title: "برنامه‌نویسی و سیستم‌های اطلاعاتی",
189
+ maxAbs: 8,
190
+ section: "conventional",
191
+ },
192
+ {
193
+ key: "finance_investing",
194
+ title: "امور مالی و سرمایه‌گذاری",
195
+ maxAbs: 8,
196
+ section: "conventional",
197
+ },
198
+
199
+ {
200
+ key: "work_style",
201
+ title: "سبک کاری",
202
+ maxAbs: 56,
203
+ section: "personal_style",
204
+ descriptionLeft:
205
+ "ترجیح کار مستقل؛ علاقه بیشتر به کار با داده‌ها، ایده‌ها یا اشیا؛ معمولاً محتاط‌تر و کم‌تعامل‌تر در محیط کار.",
206
+ descriptionRight:
207
+ "ترجیح کار با افراد؛ علاقه به کمک‌کردن، تعامل و ارتباط؛ معمولاً اجتماعی‌تر و برون‌گراتر در محیط کار.",
208
+ },
209
+ {
210
+ key: "learning_environment",
211
+ title: "محیط یادگیری",
212
+ maxAbs: 90,
213
+ section: "personal_style",
214
+ descriptionLeft:
215
+ "ترجیح یادگیری عملی و تجربی؛ یادگیری از راه انجام‌دادن؛ علاقه بیشتر به آموزش‌های کوتاه‌مدت و مهارت‌محور.",
216
+ descriptionRight:
217
+ "ترجیح محیط دانشگاهی و نظری؛ یادگیری از طریق کتاب، سخنرانی و مطالعه؛ آمادگی برای تحصیل طولانی‌تر و کسب دانش به‌خاطر خود دانش.",
218
+ },
219
+ {
220
+ key: "leadership_style",
221
+ title: "سبک رهبری",
222
+ maxAbs: 32,
223
+ section: "personal_style",
224
+ descriptionLeft:
225
+ "ترجیح انجام شخصی کار؛ عدم تمایل به فرماندهی و هدایت مستقیم؛ ممکن است بیشتر از راه الگو بودن رهبری کند.",
226
+ descriptionRight:
227
+ "راحت در پذیرفتن مسئولیت و هدایت دیگران؛ علاقه به ایجاد انگیزه، آغاز اقدام، بیان نظر و هماهنگ‌کردن فعالیت‌ها.",
228
+ },
229
+ // Figma swaps the next two description cards; keep them with their scoring keys.
230
+ {
231
+ key: "team_orientation",
232
+ title: "گرایش به کار تیمی",
233
+ maxAbs: 20,
234
+ section: "personal_style",
235
+ descriptionLeft: "ترجیح انجام مستقل وظایف؛ علاقه به نقش مشارکت‌کنندهٔ مستقل و حل مسئله به‌تنهایی.",
236
+ descriptionRight: "ترجیح کار تیمی؛ علاقه به همکاری، اهداف مشترک، تبادل نظر و حل مسئله همراه دیگران.",
237
+ },
238
+ {
239
+ key: "risk_taking",
240
+ title: "ریسک‌پذیری",
241
+ maxAbs: 22,
242
+ section: "personal_style",
243
+ descriptionLeft:
244
+ "ترجیح اطمینان، ثبات و تصمیم‌گیری محتاطانه؛ علاقه کمتر به موقعیت‌های نامطمئن و فعالیت‌های هیجان‌انگیز.",
245
+ descriptionRight:
246
+ "علاقه بیشتر به تجربه‌های تازه، ایده‌های بدیع، هیجان و پذیرش فرصت‌های نامطمئن؛ گرایش به تصمیم‌گیری سریع‌تر.",
247
+ },
248
+ ];
249
+
250
+ const GENERAL_FACTOR_KEYS = ["realistic", "investigative", "artistic", "social", "enterprising", "conventional"];
251
+
252
+ const BASIC_INTEREST_PAGE_2 = ["realistic", "investigative", "artistic"];
253
+ const BASIC_INTEREST_PAGE_3 = ["social", "enterprising", "conventional"];
254
+
255
+ const DESCRIPTION_LINES = {
256
+ work_style: {
257
+ left: [
258
+ "ترجیح کار مستقل؛ علاقه بیشتر به کار با داده‌ها،",
259
+ "ایده‌ها یا اشیا؛ معمولاً محتاط‌تر و کم‌تعامل‌تر در",
260
+ "محیط کار.",
261
+ ],
262
+ right: ["ترجیح کار با افراد؛ علاقه به کمک‌کردن، تعامل و", "ارتباط؛ معمولاً اجتماعی‌تر و برون‌گراتر در محیط کار."],
263
+ },
264
+ learning_environment: {
265
+ left: [
266
+ "ترجیح یادگیری عملی و تجربی؛ یادگیری از راه",
267
+ "انجام‌دادن؛ علاقه بیشتر به آموزش‌های کوتاه‌مدت",
268
+ "و مهارت‌محور.",
269
+ ],
270
+ right: [
271
+ "ترجیح محیط دانشگاهی و نظری؛ یادگیری از طریق",
272
+ "کتاب، سخنرانی و مطالعه؛ آمادگی برای تحصیل",
273
+ "طولانی‌تر و کسب دانش به‌خاطر خود دانش.",
274
+ ],
275
+ },
276
+ leadership_style: {
277
+ left: [
278
+ "ترجیح انجام شخصی کار؛ عدم تمایل به فرماندهی",
279
+ "و هدایت مستقیم؛ ممکن است بیشتر از راه الگو",
280
+ "بودن رهبری کند.",
281
+ ],
282
+ right: [
283
+ "راحت در پذیرفتن مسئولیت و هدایت دیگران؛",
284
+ "علاقه به ایجاد انگیزه، آغاز اقدام، بیان نظر و",
285
+ "هماهنگ‌کردن فعالیت‌ها.",
286
+ ],
287
+ },
288
+ team_orientation: {
289
+ left: ["ترجیح انجام مستقل وظایف؛ علاقه به نقش", "مشارکت‌کنندهٔ مستقل و حل مسئله به‌تنهایی."],
290
+ right: ["ترجیح کار تیمی؛ علاقه به همکاری، اهداف مشترک،", "تبادل نظر و حل مسئله همراه دیگران."],
291
+ },
292
+ risk_taking: {
293
+ left: [
294
+ "ترجیح اطمینان، ثبات و تصمیم‌گیری محتاطانه؛",
295
+ "علاقه کمتر به موقعیت‌های نامطمئن و",
296
+ "فعالیت‌های هیجان‌انگیز.",
297
+ ],
298
+ right: [
299
+ "علاقه بیشتر به تجربه‌های تازه، ایده‌های بدیع،",
300
+ "هیجان و پذیرش فرصت‌های نامطمئن؛ گرایش به",
301
+ "تصمیم‌گیری سریع‌تر.",
302
+ ],
303
+ },
304
+ };
305
+
306
+ class SII93 extends Profile {
307
+ static pages = 4;
308
+
309
+ static partials = {
310
+ SII93_bipolar_rows: "SII93_bipolar_rows.hbs",
311
+ SII93_summary_card: "SII93_summary_card.hbs",
312
+ };
313
+
314
+ labels = Object.fromEntries(
315
+ FACTOR_SPECS.flatMap(({ key }) => [
316
+ [`${key}_raw`, { eng: `${key}_raw` }],
317
+ [`${key}_percentage`, { eng: `${key}_percentage` }],
318
+ ])
319
+ );
320
+
321
+ profileSpec = {
322
+ sample: {
323
+ name: "پرسشنامه رغبت‌سنج استرانگ",
324
+ multiProfile: false,
325
+ questions: false,
326
+ defaultFields: true,
327
+ fields: [],
328
+ },
329
+ profile: {
330
+ get dimensions() {
331
+ const [page1, page2, page3, page4] = this.padding;
332
+ return [
333
+ { width: 812 + 2 * page1.x, height: 364 + 2 * page1.y },
334
+ { width: 895 + 2 * page2.x, height: 664 + 2 * page2.y },
335
+ { width: 895 + 2 * page3.x, height: 664 + 2 * page3.y },
336
+ { width: 799 + 2 * page4.x, height: 668 + 2 * page4.y },
337
+ ];
338
+ },
339
+ padding: [
340
+ { x: 45.5, y: 175 },
341
+ { x: 4, y: 25 },
342
+ { x: 4, y: 25 },
343
+ { x: 52, y: 23 },
344
+ ],
345
+ },
346
+ labels: Object.values(this.labels),
347
+ };
348
+
349
+ constructor(dataset, options, config = {}) {
350
+ super();
351
+ this._init(dataset, options, config);
352
+ }
353
+
354
+ _calcContext() {
355
+ const { dataset } = this;
356
+ const scoresByKey = new Map(dataset.score.map((item) => [item.label.eng, item]));
357
+ const rowsByKey = Object.fromEntries(FACTOR_SPECS.map((factor) => [factor.key, buildRow(factor, scoresByKey)]));
358
+
359
+ return [
360
+ {
361
+ pageKey: "general-occupational-themes",
362
+ titleAppend: " - ۱",
363
+ items: GENERAL_FACTOR_KEYS.map((key) => rowsByKey[key]),
364
+ },
365
+ {
366
+ pageKey: "basic-interest-scales-ria",
367
+ titleAppend: " - ۲",
368
+ groups: buildGroups(BASIC_INTEREST_PAGE_2, rowsByKey),
369
+ },
370
+ {
371
+ pageKey: "basic-interest-scales-sec",
372
+ titleAppend: " - ۳",
373
+ groups: buildGroups(BASIC_INTEREST_PAGE_3, rowsByKey),
374
+ },
375
+ {
376
+ pageKey: "personal-style-scales",
377
+ titleAppend: " - ۴ - مقیاس‌های سبک شخصی",
378
+ items: FACTOR_SPECS.filter(({ section }) => section === "personal_style").map(({ key }) => rowsByKey[key]),
379
+ },
380
+ ];
381
+ }
382
+ }
383
+
384
+ function buildGroups(groupKeys, rowsByKey) {
385
+ return groupKeys.map((key) => ({
386
+ key,
387
+ title: rowsByKey[key].title,
388
+ summary: rowsByKey[key],
389
+ items: FACTOR_SPECS.filter(({ section, level }) => section === key && level !== "general").map(
390
+ (factor) => rowsByKey[factor.key]
391
+ ),
392
+ }));
393
+ }
394
+
395
+ function buildRow(factor, scoresByKey) {
396
+ const raw = getMark(scoresByKey, `${factor.key}_raw`);
397
+ const percentage = getMark(scoresByKey, `${factor.key}_percentage`);
398
+ const scoreNorm = clamp((2 * raw) / factor.maxAbs, -2, 2);
399
+ const score = roundToOne(scoreNorm);
400
+ const zero = raw === 0;
401
+ const isPositive = raw > 0;
402
+ const isNegative = raw < 0;
403
+ const state = zero ? "zero" : isPositive ? "positive" : "negative";
404
+ const rawDisplay = buildRawDisplay(raw, factor.maxAbs, state);
405
+ const descriptionLines = DESCRIPTION_LINES[factor.key] || { left: [], right: [] };
406
+
407
+ return {
408
+ key: factor.key,
409
+ title: factor.title,
410
+ raw,
411
+ percentage,
412
+ maxAbs: factor.maxAbs,
413
+ scoreNorm,
414
+ score,
415
+ scoreText: formatScore(score),
416
+ barW: zero ? 0 : Math.abs(scoreNorm) * BAR_WIDTH_COEFFICIENT,
417
+ barRadius: Math.min(4, (Math.abs(scoreNorm) * BAR_WIDTH_COEFFICIENT) / 2),
418
+ inside: !zero && Math.abs(score) >= 1,
419
+ zero,
420
+ isPositive,
421
+ isNegative,
422
+ state,
423
+ negativeRawText: rawDisplay.negative.text,
424
+ positiveRawText: rawDisplay.positive.text,
425
+ summaryRawText:
426
+ state === "positive"
427
+ ? `${raw} / ${factor.maxAbs}`
428
+ : state === "negative"
429
+ ? `- ${Math.abs(raw)} / - ${factor.maxAbs}`
430
+ : "0",
431
+ rawDisplay,
432
+ descriptionLeft: factor.descriptionLeft || "",
433
+ descriptionRight: factor.descriptionRight || "",
434
+ descriptionLeftLines: descriptionLines.left,
435
+ descriptionRightLines: descriptionLines.right,
436
+ };
437
+ }
438
+
439
+ function getMark(scoresByKey, key) {
440
+ const mark = scoresByKey.get(key)?.mark ?? 0;
441
+ const number = Number(mark);
442
+ return Number.isFinite(number) ? number : 0;
443
+ }
444
+
445
+ function buildRawDisplay(raw, maxAbs, state) {
446
+ const negativeBoundText = `- ${maxAbs}`;
447
+ const positiveBoundText = `${maxAbs}`;
448
+ const resultText = raw < 0 ? `- ${Math.abs(raw)}` : `${raw}`;
449
+ const negativeShowsResult = state !== "positive";
450
+ const positiveShowsResult = state !== "negative";
451
+
452
+ return {
453
+ negative: {
454
+ bound: -maxAbs,
455
+ boundText: negativeBoundText,
456
+ result: negativeShowsResult ? raw : null,
457
+ resultText: negativeShowsResult ? resultText : "",
458
+ showResult: negativeShowsResult,
459
+ showSlash: negativeShowsResult,
460
+ active: state === "negative",
461
+ text: negativeShowsResult ? `${negativeBoundText} / ${resultText}` : negativeBoundText,
462
+ },
463
+ positive: {
464
+ bound: maxAbs,
465
+ boundText: positiveBoundText,
466
+ result: positiveShowsResult ? raw : null,
467
+ resultText: positiveShowsResult ? resultText : "",
468
+ showResult: positiveShowsResult,
469
+ showSlash: positiveShowsResult,
470
+ active: state === "positive",
471
+ text: positiveShowsResult ? `${resultText} / ${positiveBoundText}` : positiveBoundText,
472
+ },
473
+ };
474
+ }
475
+
476
+ function clamp(value, min, max) {
477
+ return Math.min(Math.max(value, min), max);
478
+ }
479
+
480
+ function roundToOne(value) {
481
+ const rounded = (Math.sign(value) * Math.round((Math.abs(value) + Number.EPSILON) * 10)) / 10;
482
+ return Object.is(rounded, -0) ? 0 : rounded;
483
+ }
484
+
485
+ function formatScore(value) {
486
+ const absolute = `${Math.abs(value)}`.replace(".", "٬");
487
+ return value < 0 ? `- ${absolute}` : absolute;
488
+ }
489
+
490
+ module.exports = SII93;
@@ -0,0 +1,100 @@
1
+ {{#each items as |item index|}}
2
+ <g transform="translate(0, {{math ../rowsY '+' (math index '*' ../rowPitch)}})">
3
+ <g transform="translate({{../leftTrackX}}, 0)">
4
+ {{bar 250 24 (object tl=4 bl=4 tr=0 br=0) (toRad 0) fill=../leftTrackFill}}
5
+ </g>
6
+ <g transform="translate({{../rightTrackX}}, 0)">
7
+ {{bar 250 24 (object tl=0 bl=0 tr=4 br=4) (toRad 0) fill=../rightTrackFill}}
8
+ </g>
9
+
10
+ {{#if ../showDescriptions}}
11
+ <g transform="translate({{../leftTrackX}}, 28)">
12
+ {{bar 250 68 (object tl=4 bl=4 tr=0 br=0) (toRad 0) fill=../leftTrackFill}}
13
+ </g>
14
+ <g transform="translate({{../rightTrackX}}, 28)">
15
+ {{bar 250 68 (object tl=0 bl=0 tr=4 br=4) (toRad 0) fill=../rightTrackFill}}
16
+ </g>
17
+
18
+ <text x="{{../leftDescriptionX}}" y="48" font-size="12" font-weight="400" fill="#475569" text-anchor="middle">
19
+ {{#each item.descriptionLeftLines as |line lineIndex|}}
20
+ <tspan x="{{../../leftDescriptionX}}" y="{{math 48 '+' (math lineIndex '*' 17)}}">{{line}}</tspan>
21
+ {{/each}}
22
+ </text>
23
+ <text x="{{../rightDescriptionX}}" y="48" font-size="12" font-weight="400" fill="#475569" text-anchor="middle">
24
+ {{#each item.descriptionRightLines as |line lineIndex|}}
25
+ <tspan x="{{../../rightDescriptionX}}" y="{{math 48 '+' (math lineIndex '*' 17)}}">{{line}}</tspan>
26
+ {{/each}}
27
+ </text>
28
+ {{/if}}
29
+
30
+ {{#if item.isNegative}}
31
+ <g transform="translate({{math ../leftZeroX '-' item.barW}}, 0)">
32
+ {{bar item.barW 24 (object tl=item.barRadius bl=item.barRadius tr=0 br=0) (toRad 0) fill=../leftActiveFill}}
33
+ <text
34
+ x="{{ternary item.inside 7 -7}}"
35
+ y="12"
36
+ dy=".34em"
37
+ font-size="{{ternary item.inside 16 14}}"
38
+ font-weight="{{ternary item.inside 600 500}}"
39
+ fill="{{ternary item.inside 'white' ../leftActiveColor}}"
40
+ text-anchor="{{ternary item.inside 'start' 'end'}}"
41
+ direction="ltr"
42
+ unicode-bidi="bidi-override"
43
+ >{{item.scoreText}}</text>
44
+ </g>
45
+ {{/if}}
46
+
47
+ {{#if item.isPositive}}
48
+ <g transform="translate({{../rightZeroX}}, 0)">
49
+ {{bar item.barW 24 (object tl=0 bl=0 tr=item.barRadius br=item.barRadius) (toRad 0) fill=../rightActiveFill}}
50
+ <text
51
+ x="{{math item.barW '+' (ternary item.inside -7 7)}}"
52
+ y="12"
53
+ dy=".34em"
54
+ font-size="{{ternary item.inside 16 14}}"
55
+ font-weight="{{ternary item.inside 600 500}}"
56
+ fill="{{ternary item.inside 'white' ../rightActiveColor}}"
57
+ text-anchor="{{ternary item.inside 'end' 'start'}}"
58
+ direction="ltr"
59
+ unicode-bidi="bidi-override"
60
+ >{{item.scoreText}}</text>
61
+ </g>
62
+ {{/if}}
63
+
64
+ <rect x="{{../titleX}}" y="0" width="{{../titleWidth}}" height="24" fill="#E2E8F0" fill-opacity="0.25"/>
65
+ <text
66
+ x="{{math ../titleX '+' (math ../titleWidth '/' 2)}}"
67
+ y="12"
68
+ dy=".32em"
69
+ font-size="{{../titleFontSize}}"
70
+ font-weight="{{../titleFontWeight}}"
71
+ fill="#475569"
72
+ text-anchor="middle"
73
+ >{{item.title}}</text>
74
+
75
+ <text
76
+ x="{{../leftRawX}}"
77
+ y="12"
78
+ dy=".3em"
79
+ font-size="12"
80
+ font-weight="400"
81
+ fill="#64748B"
82
+ text-anchor="end"
83
+ direction="ltr"
84
+ unicode-bidi="bidi-override"
85
+ xml:space="preserve"
86
+ ><tspan>{{item.rawDisplay.negative.boundText}}</tspan>{{#if item.rawDisplay.negative.showSlash}}<tspan> / </tspan><tspan font-size="14" font-weight="500">{{item.rawDisplay.negative.resultText}}</tspan>{{/if}}</text>
87
+ <text
88
+ x="{{../rightRawX}}"
89
+ y="12"
90
+ dy=".3em"
91
+ font-size="12"
92
+ font-weight="400"
93
+ fill="#64748B"
94
+ text-anchor="start"
95
+ direction="ltr"
96
+ unicode-bidi="bidi-override"
97
+ xml:space="preserve"
98
+ >{{#if item.rawDisplay.positive.showSlash}}<tspan font-size="14" font-weight="500">{{item.rawDisplay.positive.resultText}}</tspan><tspan> / </tspan>{{/if}}<tspan>{{item.rawDisplay.positive.boundText}}</tspan></text>
99
+ </g>
100
+ {{/each}}
@@ -0,0 +1,46 @@
1
+ <g>
2
+ <rect
3
+ x="0.5"
4
+ y="{{cardY}}"
5
+ width="54"
6
+ height="{{cardHeight}}"
7
+ rx="3.5"
8
+ fill="#F8FAFC"
9
+ stroke="#E2E8F0"
10
+ />
11
+
12
+ <text
13
+ x="21.5"
14
+ y="{{axisY}}"
15
+ transform="rotate(-90 21.5 {{axisY}})"
16
+ font-size="15"
17
+ font-weight="600"
18
+ fill="#475569"
19
+ text-anchor="middle"
20
+ >{{summary.title}}</text>
21
+ <text
22
+ x="42.5"
23
+ y="{{axisY}}"
24
+ transform="rotate(-90 42.5 {{axisY}})"
25
+ font-size="12"
26
+ font-weight="400"
27
+ fill="#64748B"
28
+ text-anchor="middle"
29
+ direction="ltr"
30
+ unicode-bidi="bidi-override"
31
+ xml:space="preserve"
32
+ >{{#if summary.zero}}<tspan font-size="14" font-weight="500">0</tspan>{{else}}{{#if summary.isPositive}}<tspan font-size="14" font-weight="500">{{summary.rawDisplay.positive.resultText}}</tspan><tspan> / </tspan><tspan>{{summary.rawDisplay.positive.boundText}}</tspan>{{else}}<tspan font-size="14" font-weight="500">{{summary.rawDisplay.negative.resultText}}</tspan><tspan> / </tspan><tspan>{{summary.rawDisplay.negative.boundText}}</tspan>{{/if}}{{/if}}</text>
33
+
34
+ <rect x="7.5" y="{{pillY}}" width="40" height="24" rx="6" fill="#F1F5F9"/>
35
+ <text
36
+ x="27.5"
37
+ y="{{math pillY '+' 12}}"
38
+ dy=".34em"
39
+ font-size="14"
40
+ font-weight="600"
41
+ fill="#64748B"
42
+ text-anchor="middle"
43
+ direction="ltr"
44
+ unicode-bidi="bidi-override"
45
+ >{{summary.scoreText}}</text>
46
+ </g>