@jjlmoya/utils-forensic-science 1.13.0 → 1.14.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.
- package/package.json +2 -1
- package/src/category/index.ts +61 -59
- package/src/category/seo.astro +1 -1
- package/src/components/PreviewNavSidebar.astro +1 -1
- package/src/components/PreviewToolbar.astro +1 -1
- package/src/data.ts +1 -1
- package/src/entries.ts +70 -68
- package/src/env.d.ts +1 -1
- package/src/index.ts +32 -31
- package/src/pages/[locale]/[slug].astro +161 -159
- package/src/pages/[locale].astro +8 -5
- package/src/pages/index.astro +1 -1
- package/src/tests/bibliography_wellformed_export.test.ts +46 -0
- package/src/tests/diacritics_density.test.ts +1 -1
- package/src/tests/faq_count.test.ts +19 -19
- package/src/tests/i18n_coverage.test.ts +36 -36
- package/src/tests/inverted_punctuation.test.ts +1 -1
- package/src/tests/locale_completeness.test.ts +2 -2
- package/src/tests/mocks/astro_mock.js +1 -1
- package/src/tests/no_h1_in_components.test.ts +1 -1
- package/src/tests/script_density.test.ts +94 -94
- package/src/tests/seo_length.test.ts +46 -46
- package/src/tests/seo_parity.test.ts +2 -7
- package/src/tests/seo_translation_completeness.test.ts +68 -0
- package/src/tests/seo_wellformed_export.test.ts +65 -0
- package/src/tests/tool_validation.test.ts +2 -2
- package/src/tests/translation_copy.test.ts +23 -24
- package/src/tool/bloodstain-pattern-origin-analyzer/component.astro +9 -9
- package/src/tool/bloodstain-pattern-origin-analyzer/i18n/zh.ts +1 -1
- package/src/tool/dna-profile-match-probability-lab/bibliography.astro +14 -0
- package/src/tool/dna-profile-match-probability-lab/bibliography.ts +16 -0
- package/src/tool/dna-profile-match-probability-lab/component.astro +121 -0
- package/src/tool/dna-profile-match-probability-lab/controller.ts +159 -0
- package/src/tool/dna-profile-match-probability-lab/dna-profile-match-probability-lab.css +485 -0
- package/src/tool/dna-profile-match-probability-lab/dom-views.ts +93 -0
- package/src/tool/dna-profile-match-probability-lab/entry.ts +29 -0
- package/src/tool/dna-profile-match-probability-lab/evaluator.ts +19 -0
- package/src/tool/dna-profile-match-probability-lab/i18n/de.ts +43 -0
- package/src/tool/dna-profile-match-probability-lab/i18n/en.ts +196 -0
- package/src/tool/dna-profile-match-probability-lab/i18n/es.ts +40 -0
- package/src/tool/dna-profile-match-probability-lab/i18n/fr.ts +10 -0
- package/src/tool/dna-profile-match-probability-lab/i18n/id.ts +41 -0
- package/src/tool/dna-profile-match-probability-lab/i18n/it.ts +10 -0
- package/src/tool/dna-profile-match-probability-lab/i18n/ja.ts +40 -0
- package/src/tool/dna-profile-match-probability-lab/i18n/ko.ts +40 -0
- package/src/tool/dna-profile-match-probability-lab/i18n/nl.ts +29 -0
- package/src/tool/dna-profile-match-probability-lab/i18n/pl.ts +10 -0
- package/src/tool/dna-profile-match-probability-lab/i18n/pt.ts +41 -0
- package/src/tool/dna-profile-match-probability-lab/i18n/ru.ts +29 -0
- package/src/tool/dna-profile-match-probability-lab/i18n/sv.ts +41 -0
- package/src/tool/dna-profile-match-probability-lab/i18n/tr.ts +10 -0
- package/src/tool/dna-profile-match-probability-lab/i18n/zh.ts +29 -0
- package/src/tool/dna-profile-match-probability-lab/index.ts +11 -0
- package/src/tool/dna-profile-match-probability-lab/localize.ts +107 -0
- package/src/tool/dna-profile-match-probability-lab/logic.test.ts +56 -0
- package/src/tool/dna-profile-match-probability-lab/logic.ts +139 -0
- package/src/tool/dna-profile-match-probability-lab/seo.astro +15 -0
- package/src/tool/dna-profile-match-probability-lab/storage.ts +26 -0
- package/src/tool/dna-profile-match-probability-lab/ui.ts +3 -0
- package/src/tool/fire-pattern-origin-analyzer/component.astro +1 -1
- package/src/tool/fire-pattern-origin-analyzer/i18n/zh.ts +5 -1
- package/src/tool/fire-pattern-origin-analyzer/logic.ts +9 -2
- package/src/tool/fire-pattern-origin-analyzer/view-bindings.ts +8 -4
- package/src/tool/fire-pattern-origin-analyzer/view-model.ts +6 -2
- package/src/tool/forensic-age-estimator/bibliography.astro +1 -1
- package/src/tool/forensic-age-estimator/component.astro +1 -1
- package/src/tool/forensic-age-estimator/entry.ts +17 -17
- package/src/tool/forensic-age-estimator/i18n/de.ts +244 -244
- package/src/tool/forensic-age-estimator/i18n/en.ts +244 -244
- package/src/tool/forensic-age-estimator/i18n/es.ts +244 -244
- package/src/tool/forensic-age-estimator/i18n/fr.ts +244 -244
- package/src/tool/forensic-age-estimator/i18n/id.ts +244 -244
- package/src/tool/forensic-age-estimator/i18n/it.ts +244 -244
- package/src/tool/forensic-age-estimator/i18n/nl.ts +244 -244
- package/src/tool/forensic-age-estimator/i18n/pl.ts +244 -244
- package/src/tool/forensic-age-estimator/i18n/pt.ts +244 -244
- package/src/tool/forensic-age-estimator/i18n/ru.ts +244 -244
- package/src/tool/forensic-age-estimator/i18n/sv.ts +244 -244
- package/src/tool/forensic-age-estimator/i18n/tr.ts +244 -244
- package/src/tool/forensic-age-estimator/i18n/zh.ts +245 -245
- package/src/tool/forensic-age-estimator/index.ts +1 -1
- package/src/tool/forensic-age-estimator/seo.astro +1 -1
- package/src/tool/forensic-blood-test-simulator/component.astro +1 -1
- package/src/tool/forensic-fiber-comparison-microscope/component.astro +1 -1
- package/src/tool/forensic-fiber-comparison-microscope/render.ts +1 -1
- package/src/tool/forensic-fiber-comparison-microscope/view.ts +1 -1
- package/src/tool/forensic-fingerprint-minutiae-identifier/component.astro +2 -2
- package/src/tool/forensic-fingerprint-minutiae-identifier/i18n/ja.ts +2 -1
- package/src/tool/forensic-fingerprint-minutiae-identifier/i18n/zh.ts +2 -0
- package/src/tool/forensic-fingerprint-minutiae-identifier/renderer.ts +9 -8
- package/src/tool/forensic-glass-becke-line-simulator/component.astro +1 -1
- package/src/tool/forensic-glass-becke-line-simulator/view.ts +8 -6
- package/src/tool/forensic-image-authenticity-analyzer/component.astro +1 -1
- package/src/tool/forensic-image-authenticity-analyzer/i18n/de.ts +105 -105
- package/src/tool/forensic-image-authenticity-analyzer/i18n/en.ts +105 -105
- package/src/tool/forensic-image-authenticity-analyzer/i18n/es.ts +105 -105
- package/src/tool/forensic-image-authenticity-analyzer/i18n/fr.ts +105 -105
- package/src/tool/forensic-image-authenticity-analyzer/i18n/id.ts +95 -90
- package/src/tool/forensic-image-authenticity-analyzer/i18n/it.ts +105 -105
- package/src/tool/forensic-image-authenticity-analyzer/i18n/ja.ts +7 -2
- package/src/tool/forensic-image-authenticity-analyzer/i18n/ko.ts +4 -1
- package/src/tool/forensic-image-authenticity-analyzer/i18n/nl.ts +95 -92
- package/src/tool/forensic-image-authenticity-analyzer/i18n/pl.ts +95 -92
- package/src/tool/forensic-image-authenticity-analyzer/i18n/pt.ts +105 -105
- package/src/tool/forensic-image-authenticity-analyzer/i18n/ru.ts +97 -92
- package/src/tool/forensic-image-authenticity-analyzer/i18n/sv.ts +97 -93
- package/src/tool/forensic-image-authenticity-analyzer/i18n/tr.ts +98 -93
- package/src/tool/forensic-image-authenticity-analyzer/i18n/zh.ts +11 -0
- package/src/tool/forensic-microcrystal-drug-simulator/component.astro +1 -1
- package/src/tool/forensic-sex-determinator/component.astro +3 -2
- package/src/tool/forensic-stature-estimator/component.astro +1 -1
- package/src/tool/forensic-stature-estimator/i18n/id.ts +4 -0
- package/src/tool/forensic-stature-estimator/i18n/nl.ts +4 -0
- package/src/tool/forensic-stature-estimator/i18n/ru.ts +4 -0
- package/src/tool/forensic-tlc-ink-simulator/component.astro +1 -1
- package/src/tool/forensic-tlc-ink-simulator/i18n/zh.ts +1 -0
- package/src/tool/forensic-toolmark-striation-matcher/component.astro +1 -1
- package/src/tool/forensic-toolmark-striation-matcher/logic.ts +1 -1
- package/src/tool/forensic-toolmark-striation-matcher/renderer.ts +7 -6
- package/src/tool/forensic-toolmark-striation-matcher/view.ts +19 -20
- package/src/tool/gsr-dispersion-calculator/component.astro +1 -1
- package/src/tool/gsr-dispersion-calculator/logic.ts +1 -1
- package/src/tool/time-of-death-algor-mortis-calculator/entry.ts +2 -0
- package/src/tool/widmark-alcohol-simulator/component.astro +1 -1
- package/src/tool/widmark-alcohol-simulator/i18n/de.ts +5 -0
- package/src/tool/widmark-alcohol-simulator/i18n/fr.ts +2 -1
- package/src/tool/widmark-alcohol-simulator/i18n/id.ts +1 -0
- package/src/tool/widmark-alcohol-simulator/i18n/it.ts +4 -1
- package/src/tool/widmark-alcohol-simulator/i18n/ja.ts +4 -1
- package/src/tool/widmark-alcohol-simulator/i18n/nl.ts +5 -1
- package/src/tool/widmark-alcohol-simulator/i18n/pl.ts +5 -1
- package/src/tool/widmark-alcohol-simulator/i18n/pt.ts +5 -1
- package/src/tool/widmark-alcohol-simulator/i18n/ru.ts +4 -1
- package/src/tool/widmark-alcohol-simulator/i18n/sv.ts +5 -1
- package/src/tool/widmark-alcohol-simulator/i18n/tr.ts +4 -1
- package/src/tool/widmark-alcohol-simulator/i18n/zh.ts +4 -1
- package/src/tools.ts +37 -35
- package/src/types.ts +4 -4
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
.dna-match-tool {
|
|
2
|
+
--n-ink: #16242a;
|
|
3
|
+
--n-muted: #5d6b70;
|
|
4
|
+
--n-paper: #f4f0e8;
|
|
5
|
+
--n-card: #fffdf7;
|
|
6
|
+
--n-line: #cbd4d1;
|
|
7
|
+
--n-coral: #c64b43;
|
|
8
|
+
--n-cyan: #188b96;
|
|
9
|
+
--n-moss: #52705f;
|
|
10
|
+
--n-yellow: #e8bf4a;
|
|
11
|
+
--n-shadow: rgba(22, 36, 42, 0.12);
|
|
12
|
+
|
|
13
|
+
display: grid;
|
|
14
|
+
grid-template-columns: minmax(280px, 0.82fr) minmax(360px, 1.18fr);
|
|
15
|
+
gap: 1rem;
|
|
16
|
+
width: 100%;
|
|
17
|
+
max-width: 1180px;
|
|
18
|
+
margin: 0 auto;
|
|
19
|
+
padding: clamp(0.75rem, 2vw, 1.4rem);
|
|
20
|
+
color: var(--n-ink);
|
|
21
|
+
background: var(--n-paper);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.theme-dark .dna-match-tool {
|
|
25
|
+
--n-ink: #f1f3eb;
|
|
26
|
+
--n-muted: #aab8b8;
|
|
27
|
+
--n-paper: #171e20;
|
|
28
|
+
--n-card: #202a2c;
|
|
29
|
+
--n-line: #405054;
|
|
30
|
+
--n-coral: #ed8378;
|
|
31
|
+
--n-cyan: #65c8c5;
|
|
32
|
+
--n-moss: #93bd9b;
|
|
33
|
+
--n-yellow: #f1ce63;
|
|
34
|
+
--n-shadow: rgba(0, 0, 0, 0.28);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.dna-match-controls,
|
|
38
|
+
.dna-match-scene,
|
|
39
|
+
.dna-match-results {
|
|
40
|
+
min-width: 0;
|
|
41
|
+
border: 1px solid var(--n-line);
|
|
42
|
+
background: var(--n-card);
|
|
43
|
+
box-shadow: 0 0.8rem 2rem var(--n-shadow);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.dna-match-controls {
|
|
47
|
+
display: grid;
|
|
48
|
+
align-content: start;
|
|
49
|
+
gap: 0.9rem;
|
|
50
|
+
padding: clamp(1rem, 2.2vw, 1.45rem);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.dna-match-control-head,
|
|
54
|
+
.dna-match-scene-header,
|
|
55
|
+
.dna-match-locus summary,
|
|
56
|
+
.dna-match-legend,
|
|
57
|
+
.dna-match-field,
|
|
58
|
+
.dna-match-result-lead {
|
|
59
|
+
display: flex;
|
|
60
|
+
align-items: center;
|
|
61
|
+
justify-content: space-between;
|
|
62
|
+
gap: 0.75rem;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.dna-match-control-head {
|
|
66
|
+
align-items: flex-start;
|
|
67
|
+
padding-bottom: 0.8rem;
|
|
68
|
+
border-bottom: 1px solid var(--n-line);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.dna-match-kicker {
|
|
72
|
+
display: block;
|
|
73
|
+
color: var(--n-coral);
|
|
74
|
+
font-size: 0.68rem;
|
|
75
|
+
font-weight: 800;
|
|
76
|
+
letter-spacing: 0.11em;
|
|
77
|
+
text-transform: uppercase;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.dna-match-helper,
|
|
81
|
+
.dna-match-scene-note,
|
|
82
|
+
.dna-match-result-detail,
|
|
83
|
+
.dna-match-disclaimer,
|
|
84
|
+
.dna-match-result-lead p {
|
|
85
|
+
margin: 0;
|
|
86
|
+
color: var(--n-muted);
|
|
87
|
+
font-size: 0.78rem;
|
|
88
|
+
line-height: 1.5;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.dna-match-helper {
|
|
92
|
+
max-width: 29rem;
|
|
93
|
+
margin-top: 0.35rem;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.dna-match-locus-count,
|
|
97
|
+
.dna-match-scene-note,
|
|
98
|
+
.dna-match-badge {
|
|
99
|
+
flex: 0 0 auto;
|
|
100
|
+
padding: 0.35rem 0.5rem;
|
|
101
|
+
border: 1px solid var(--n-line);
|
|
102
|
+
color: var(--n-moss);
|
|
103
|
+
font-size: 0.68rem;
|
|
104
|
+
font-weight: 800;
|
|
105
|
+
letter-spacing: 0.04em;
|
|
106
|
+
text-transform: uppercase;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.dna-match-presets {
|
|
110
|
+
display: grid;
|
|
111
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
112
|
+
gap: 0.45rem;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.dna-match-presets button,
|
|
116
|
+
.dna-match-add,
|
|
117
|
+
.dna-match-remove {
|
|
118
|
+
border: 1px solid var(--n-line);
|
|
119
|
+
color: var(--n-ink);
|
|
120
|
+
background: transparent;
|
|
121
|
+
cursor: pointer;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.dna-match-presets button {
|
|
125
|
+
display: grid;
|
|
126
|
+
gap: 0.28rem;
|
|
127
|
+
min-height: 3.25rem;
|
|
128
|
+
padding: 0.55rem;
|
|
129
|
+
text-align: left;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.dna-match-presets button span {
|
|
133
|
+
font-size: 0.69rem;
|
|
134
|
+
font-weight: 800;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.dna-match-presets button small {
|
|
138
|
+
color: var(--n-muted);
|
|
139
|
+
font-size: 0.67rem;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.dna-match-presets button:hover,
|
|
143
|
+
.dna-match-presets button:focus-visible,
|
|
144
|
+
.dna-match-presets button.is-active {
|
|
145
|
+
border-color: var(--n-coral);
|
|
146
|
+
background: color-mix(in srgb, var(--n-coral) 12%, var(--n-card));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.dna-match-locus-list {
|
|
150
|
+
display: grid;
|
|
151
|
+
gap: 0.35rem;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.dna-match-locus {
|
|
155
|
+
border-bottom: 1px solid var(--n-line);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.dna-match-locus summary {
|
|
159
|
+
min-height: 2.6rem;
|
|
160
|
+
color: var(--n-ink);
|
|
161
|
+
cursor: pointer;
|
|
162
|
+
list-style: none;
|
|
163
|
+
font-size: 0.78rem;
|
|
164
|
+
font-weight: 800;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.dna-match-locus summary::-webkit-details-marker {
|
|
168
|
+
display: none;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.dna-match-locus summary::after {
|
|
172
|
+
width: 0.4rem;
|
|
173
|
+
height: 0.4rem;
|
|
174
|
+
border-right: 1px solid var(--n-muted);
|
|
175
|
+
border-bottom: 1px solid var(--n-muted);
|
|
176
|
+
content: '';
|
|
177
|
+
transform: rotate(45deg) translateY(-0.15rem);
|
|
178
|
+
transition: transform 0.2s ease;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.dna-match-locus[open] summary::after {
|
|
182
|
+
transform: rotate(225deg) translateY(-0.15rem);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.dna-match-locus summary span:first-child {
|
|
186
|
+
overflow: hidden;
|
|
187
|
+
text-overflow: ellipsis;
|
|
188
|
+
white-space: nowrap;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.dna-match-locus summary span:nth-child(2) {
|
|
192
|
+
margin-left: auto;
|
|
193
|
+
color: var(--n-cyan);
|
|
194
|
+
font-size: 0.7rem;
|
|
195
|
+
font-weight: 700;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.dna-match-locus-fields {
|
|
199
|
+
display: grid;
|
|
200
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
201
|
+
gap: 0.55rem;
|
|
202
|
+
padding: 0.25rem 0 0.8rem;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.dna-match-field {
|
|
206
|
+
align-items: flex-start;
|
|
207
|
+
flex-direction: column;
|
|
208
|
+
gap: 0.25rem;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.dna-match-field span,
|
|
212
|
+
.dna-match-table-wrap th,
|
|
213
|
+
.dna-match-table-wrap caption {
|
|
214
|
+
color: var(--n-muted);
|
|
215
|
+
font-size: 0.64rem;
|
|
216
|
+
font-weight: 800;
|
|
217
|
+
letter-spacing: 0.05em;
|
|
218
|
+
text-transform: uppercase;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.dna-match-field input {
|
|
222
|
+
box-sizing: border-box;
|
|
223
|
+
width: 100%;
|
|
224
|
+
min-height: 2.1rem;
|
|
225
|
+
border: 1px solid var(--n-line);
|
|
226
|
+
border-radius: 0;
|
|
227
|
+
padding: 0.45rem 0.5rem;
|
|
228
|
+
color: var(--n-ink);
|
|
229
|
+
background: var(--n-paper);
|
|
230
|
+
font-size: 0.78rem;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.dna-match-field input:focus-visible {
|
|
234
|
+
outline: 2px solid var(--n-coral);
|
|
235
|
+
outline-offset: 2px;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.dna-match-remove {
|
|
239
|
+
justify-self: start;
|
|
240
|
+
padding: 0.4rem 0.5rem;
|
|
241
|
+
color: var(--n-coral);
|
|
242
|
+
font-size: 0.66rem;
|
|
243
|
+
font-weight: 800;
|
|
244
|
+
text-transform: uppercase;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.dna-match-remove:disabled {
|
|
248
|
+
cursor: not-allowed;
|
|
249
|
+
opacity: 0.35;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
.dna-match-add {
|
|
253
|
+
width: 100%;
|
|
254
|
+
padding: 0.7rem;
|
|
255
|
+
border-color: var(--n-cyan);
|
|
256
|
+
color: var(--n-cyan);
|
|
257
|
+
font-size: 0.72rem;
|
|
258
|
+
font-weight: 800;
|
|
259
|
+
text-transform: uppercase;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.dna-match-add:hover,
|
|
263
|
+
.dna-match-add:focus-visible,
|
|
264
|
+
.dna-match-remove:hover,
|
|
265
|
+
.dna-match-remove:focus-visible {
|
|
266
|
+
background: color-mix(in srgb, var(--n-cyan) 10%, var(--n-card));
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.dna-match-disclaimer {
|
|
270
|
+
padding-top: 0.8rem;
|
|
271
|
+
border-top: 1px solid var(--n-line);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.dna-match-scene {
|
|
275
|
+
display: grid;
|
|
276
|
+
align-content: start;
|
|
277
|
+
gap: 1rem;
|
|
278
|
+
padding: clamp(1rem, 2.2vw, 1.45rem);
|
|
279
|
+
background: var(--n-paper);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.dna-match-scene-header {
|
|
283
|
+
align-items: flex-start;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.dna-match-scene h2 {
|
|
287
|
+
margin: 0.3rem 0 0;
|
|
288
|
+
font-size: clamp(1.25rem, 3vw, 2rem);
|
|
289
|
+
font-weight: 500;
|
|
290
|
+
letter-spacing: -0.03em;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.dna-match-scene-note {
|
|
294
|
+
max-width: 12rem;
|
|
295
|
+
color: var(--n-muted);
|
|
296
|
+
font-size: 0.68rem;
|
|
297
|
+
font-weight: 600;
|
|
298
|
+
line-height: 1.35;
|
|
299
|
+
text-transform: none;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.dna-match-electropherogram {
|
|
303
|
+
display: grid;
|
|
304
|
+
grid-template-columns: repeat(auto-fit, minmax(6.5rem, 1fr));
|
|
305
|
+
gap: 0.5rem;
|
|
306
|
+
min-height: 18rem;
|
|
307
|
+
padding: 1rem 0.75rem 0.75rem;
|
|
308
|
+
border: 1px solid var(--n-line);
|
|
309
|
+
background: var(--n-card);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.dna-match-lane {
|
|
313
|
+
display: grid;
|
|
314
|
+
grid-template-rows: auto 1fr auto;
|
|
315
|
+
gap: 0.55rem;
|
|
316
|
+
min-width: 0;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.dna-match-lane strong,
|
|
320
|
+
.dna-match-alleles {
|
|
321
|
+
overflow: hidden;
|
|
322
|
+
color: var(--n-muted);
|
|
323
|
+
font-size: 0.62rem;
|
|
324
|
+
text-overflow: ellipsis;
|
|
325
|
+
white-space: nowrap;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
.dna-match-track {
|
|
329
|
+
position: relative;
|
|
330
|
+
display: flex;
|
|
331
|
+
align-items: flex-end;
|
|
332
|
+
justify-content: space-around;
|
|
333
|
+
min-height: 12.8rem;
|
|
334
|
+
border-bottom: 1px solid var(--n-ink);
|
|
335
|
+
background-image: linear-gradient(var(--n-line) 1px, transparent 1px);
|
|
336
|
+
background-size: 100% 25%;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
.dna-match-peak {
|
|
340
|
+
position: relative;
|
|
341
|
+
display: block;
|
|
342
|
+
width: clamp(0.45rem, 1.7vw, 0.8rem);
|
|
343
|
+
min-height: 1.5rem;
|
|
344
|
+
border-radius: 0.3rem 0.3rem 0 0;
|
|
345
|
+
box-shadow: 0 0 1.2rem color-mix(in srgb, currentcolor 35%, transparent);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
.dna-match-peak::after {
|
|
349
|
+
position: absolute;
|
|
350
|
+
right: 50%;
|
|
351
|
+
bottom: -1.25rem;
|
|
352
|
+
color: var(--n-muted);
|
|
353
|
+
content: attr(data-allele);
|
|
354
|
+
font-size: 0.58rem;
|
|
355
|
+
transform: translateX(50%);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
.dna-match-alleles {
|
|
359
|
+
color: var(--n-ink);
|
|
360
|
+
font-weight: 800;
|
|
361
|
+
text-align: center;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.dna-match-legend {
|
|
365
|
+
justify-content: flex-start;
|
|
366
|
+
flex-wrap: wrap;
|
|
367
|
+
color: var(--n-muted);
|
|
368
|
+
font-size: 0.68rem;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.dna-match-legend span {
|
|
372
|
+
display: inline-flex;
|
|
373
|
+
align-items: center;
|
|
374
|
+
gap: 0.3rem;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.dna-match-legend-dot {
|
|
378
|
+
display: inline-block;
|
|
379
|
+
width: 0.55rem;
|
|
380
|
+
height: 0.55rem;
|
|
381
|
+
border-radius: 50%;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.dna-match-legend-dot-coral {
|
|
385
|
+
background: var(--n-coral);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
.dna-match-legend-dot-cyan {
|
|
389
|
+
background: var(--n-cyan);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.dna-match-results {
|
|
393
|
+
grid-column: 1 / -1;
|
|
394
|
+
display: grid;
|
|
395
|
+
grid-template-columns: minmax(260px, 0.7fr) minmax(0, 1.3fr);
|
|
396
|
+
gap: 1.2rem;
|
|
397
|
+
padding: clamp(1rem, 2.2vw, 1.45rem);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
.dna-match-result-lead {
|
|
401
|
+
align-items: flex-start;
|
|
402
|
+
flex-direction: column;
|
|
403
|
+
justify-content: center;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
.dna-match-combined {
|
|
407
|
+
color: var(--n-ink);
|
|
408
|
+
font-size: clamp(1.7rem, 4vw, 3.1rem);
|
|
409
|
+
line-height: 1;
|
|
410
|
+
overflow-wrap: anywhere;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
.dna-match-result-lead p {
|
|
414
|
+
max-width: 25rem;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
.dna-match-badge {
|
|
418
|
+
color: var(--n-moss);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
.dna-match-badge[data-level='invalid'] {
|
|
422
|
+
color: var(--n-coral);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.dna-match-badge[data-level='review'] {
|
|
426
|
+
color: var(--n-yellow);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.dna-match-table-wrap {
|
|
430
|
+
overflow-x: auto;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
.dna-match-table-wrap table {
|
|
434
|
+
width: 100%;
|
|
435
|
+
border-collapse: collapse;
|
|
436
|
+
font-size: 0.75rem;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
.dna-match-table-wrap caption {
|
|
440
|
+
margin-bottom: 0.65rem;
|
|
441
|
+
text-align: left;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
.dna-match-table-wrap th,
|
|
445
|
+
.dna-match-table-wrap td {
|
|
446
|
+
padding: 0.6rem 0.45rem;
|
|
447
|
+
border-bottom: 1px solid var(--n-line);
|
|
448
|
+
text-align: left;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
.dna-match-table-wrap td {
|
|
452
|
+
color: var(--n-ink);
|
|
453
|
+
white-space: nowrap;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
@media (max-width: 780px) {
|
|
457
|
+
.dna-match-tool,
|
|
458
|
+
.dna-match-results {
|
|
459
|
+
grid-template-columns: 1fr;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
.dna-match-results {
|
|
463
|
+
grid-column: auto;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
@media (max-width: 520px) {
|
|
468
|
+
.dna-match-presets {
|
|
469
|
+
grid-template-columns: 1fr;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
.dna-match-electropherogram {
|
|
473
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
.dna-match-locus-fields {
|
|
477
|
+
grid-template-columns: 1fr;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
@media (prefers-reduced-motion: reduce) {
|
|
482
|
+
.dna-match-locus summary::after {
|
|
483
|
+
transition: none;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { DnaProfileMatchProbabilityUI } from './ui';
|
|
2
|
+
import type { LocusInput, ProfileMatchResult } from './logic';
|
|
3
|
+
import { evaluateProfile } from './evaluator';
|
|
4
|
+
|
|
5
|
+
export interface ResultTargets {
|
|
6
|
+
badge: HTMLElement;
|
|
7
|
+
detail: HTMLElement;
|
|
8
|
+
combined: HTMLElement;
|
|
9
|
+
probability: HTMLElement;
|
|
10
|
+
table: HTMLTableSectionElement;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function uiText(ui: DnaProfileMatchProbabilityUI, key: string): string {
|
|
14
|
+
return ui[key] ?? '';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function formatPercent(value: number): string {
|
|
18
|
+
const percent = value * 100;
|
|
19
|
+
return percent > 0 && percent < 0.01 ? `${percent.toExponential(2)}%` : `${percent.toFixed(2)}%`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function formatOneIn(log10Probability: number): string {
|
|
23
|
+
if (log10Probability >= -3) return `1 in ${Math.round(10 ** -log10Probability)}`;
|
|
24
|
+
const exponent = Math.floor(-log10Probability);
|
|
25
|
+
const mantissa = 10 ** (-log10Probability - exponent);
|
|
26
|
+
return `1 in ${mantissa.toFixed(1)} × 10^${exponent}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function addCell(row: HTMLTableRowElement, value: string): void {
|
|
30
|
+
const cell = document.createElement('td');
|
|
31
|
+
cell.textContent = value;
|
|
32
|
+
row.append(cell);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function renderTable(target: HTMLTableSectionElement, result: ProfileMatchResult, ui: DnaProfileMatchProbabilityUI): void {
|
|
36
|
+
target.replaceChildren();
|
|
37
|
+
result.loci.forEach((locus) => {
|
|
38
|
+
const row = document.createElement('tr');
|
|
39
|
+
addCell(row, locus.name || uiText(ui, 'missingValue'));
|
|
40
|
+
addCell(row, `${locus.allele1 || '?'} / ${locus.allele2 || '?'}`);
|
|
41
|
+
addCell(row, locus.errors.length > 0 ? uiText(ui, 'badgeNeedsData') : locus.formula);
|
|
42
|
+
addCell(row, locus.errors.length > 0 ? uiText(ui, 'badgeNeedsData') : formatPercent(locus.genotypeFrequency));
|
|
43
|
+
target.append(row);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function peakHeight(frequency: number): string {
|
|
48
|
+
return `${Math.max(12, Math.min(92, frequency * 220))}%`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function renderPeak(track: HTMLElement, allele: string, frequency: number, color: string): void {
|
|
52
|
+
const peak = document.createElement('span');
|
|
53
|
+
peak.className = 'dna-match-peak';
|
|
54
|
+
peak.style.height = peakHeight(frequency);
|
|
55
|
+
peak.style.backgroundColor = color;
|
|
56
|
+
peak.setAttribute('data-allele', allele || '?');
|
|
57
|
+
track.append(peak);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function renderElectropherogram(target: HTMLElement, loci: LocusInput[], ui: DnaProfileMatchProbabilityUI): void {
|
|
61
|
+
target.replaceChildren();
|
|
62
|
+
loci.forEach((locus, index) => {
|
|
63
|
+
const lane = document.createElement('div');
|
|
64
|
+
lane.className = 'dna-match-lane';
|
|
65
|
+
lane.setAttribute('aria-label', `${locus.name || `${uiText(ui, 'locus')} ${index + 1}`}: ${locus.allele1} / ${locus.allele2}`);
|
|
66
|
+
const name = document.createElement('strong');
|
|
67
|
+
name.textContent = locus.name || `${uiText(ui, 'locus')} ${index + 1}`;
|
|
68
|
+
const track = document.createElement('div');
|
|
69
|
+
track.className = 'dna-match-track';
|
|
70
|
+
renderPeak(track, locus.allele1, locus.frequency1, 'var(--n-coral)');
|
|
71
|
+
renderPeak(track, locus.allele2, locus.frequency2, 'var(--n-cyan)');
|
|
72
|
+
const alleles = document.createElement('span');
|
|
73
|
+
alleles.className = 'dna-match-alleles';
|
|
74
|
+
alleles.textContent = `${locus.allele1 || '?'} · ${locus.allele2 || '?'}`;
|
|
75
|
+
lane.append(name, track, alleles);
|
|
76
|
+
target.append(lane);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function renderResults(targets: ResultTargets, result: ProfileMatchResult, ui: DnaProfileMatchProbabilityUI): void {
|
|
81
|
+
const evaluation = evaluateProfile(result);
|
|
82
|
+
targets.badge.textContent = ui[evaluation.badgeKey] ?? uiText(ui, 'badgeNeedsData');
|
|
83
|
+
targets.badge.dataset.level = evaluation.level;
|
|
84
|
+
targets.detail.textContent = ui[evaluation.detailKey] ?? uiText(ui, 'needsData');
|
|
85
|
+
if (evaluation.level === 'invalid') {
|
|
86
|
+
targets.combined.textContent = uiText(ui, 'notCalculated');
|
|
87
|
+
targets.probability.textContent = uiText(ui, 'completeFields');
|
|
88
|
+
} else {
|
|
89
|
+
targets.combined.textContent = formatOneIn(result.log10CombinedProbability);
|
|
90
|
+
targets.probability.textContent = `${formatPercent(result.combinedProbability)} ${uiText(ui, 'ofRandomProfiles')}`;
|
|
91
|
+
}
|
|
92
|
+
renderTable(targets.table, result, ui);
|
|
93
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ScienceToolEntry, ToolLocaleContent } from '../../types';
|
|
2
|
+
import type { DnaProfileMatchProbabilityUI } from './ui';
|
|
3
|
+
|
|
4
|
+
export type DnaProfileMatchProbabilityLocaleContent = ToolLocaleContent<DnaProfileMatchProbabilityUI>;
|
|
5
|
+
|
|
6
|
+
export const dnaProfileMatchProbabilityLab: ScienceToolEntry<DnaProfileMatchProbabilityUI> = {
|
|
7
|
+
id: 'dna-profile-match-probability-lab',
|
|
8
|
+
icons: {
|
|
9
|
+
bg: 'mdi:dna',
|
|
10
|
+
fg: 'mdi:chart-bell-curve-cumulative',
|
|
11
|
+
},
|
|
12
|
+
i18n: {
|
|
13
|
+
de: () => import('./i18n/de').then((m) => m.content),
|
|
14
|
+
en: () => import('./i18n/en').then((m) => m.content),
|
|
15
|
+
es: () => import('./i18n/es').then((m) => m.content),
|
|
16
|
+
fr: () => import('./i18n/fr').then((m) => m.content),
|
|
17
|
+
id: () => import('./i18n/id').then((m) => m.content),
|
|
18
|
+
it: () => import('./i18n/it').then((m) => m.content),
|
|
19
|
+
ja: () => import('./i18n/ja').then((m) => m.content),
|
|
20
|
+
ko: () => import('./i18n/ko').then((m) => m.content),
|
|
21
|
+
nl: () => import('./i18n/nl').then((m) => m.content),
|
|
22
|
+
pl: () => import('./i18n/pl').then((m) => m.content),
|
|
23
|
+
pt: () => import('./i18n/pt').then((m) => m.content),
|
|
24
|
+
ru: () => import('./i18n/ru').then((m) => m.content),
|
|
25
|
+
sv: () => import('./i18n/sv').then((m) => m.content),
|
|
26
|
+
tr: () => import('./i18n/tr').then((m) => m.content),
|
|
27
|
+
zh: () => import('./i18n/zh').then((m) => m.content),
|
|
28
|
+
},
|
|
29
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ProfileMatchResult } from './logic';
|
|
2
|
+
|
|
3
|
+
export type EvaluationLevel = 'invalid' | 'review' | 'calculated';
|
|
4
|
+
|
|
5
|
+
export interface ProfileEvaluation {
|
|
6
|
+
level: EvaluationLevel;
|
|
7
|
+
badgeKey: string;
|
|
8
|
+
detailKey: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function evaluateProfile(result: ProfileMatchResult): ProfileEvaluation {
|
|
12
|
+
if (result.totalLoci < 2 || result.validLoci < result.totalLoci) {
|
|
13
|
+
return { level: 'invalid', badgeKey: 'badgeNeedsData', detailKey: 'needsData' };
|
|
14
|
+
}
|
|
15
|
+
if (result.validLoci < 4) {
|
|
16
|
+
return { level: 'review', badgeKey: 'badgeExploratory', detailKey: 'exploratoryResult' };
|
|
17
|
+
}
|
|
18
|
+
return { level: 'calculated', badgeKey: 'badgeCalculated', detailKey: 'calculatedResult' };
|
|
19
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { content as enContent } from './en';
|
|
2
|
+
import { createDnaLocale } from '../localize';
|
|
3
|
+
|
|
4
|
+
export const content = createDnaLocale({
|
|
5
|
+
locale: 'de',
|
|
6
|
+
slug: 'dna-profil-uebereinstimmungswahrscheinlichkeit-labor',
|
|
7
|
+
title: 'Labor für die Übereinstimmungswahrscheinlichkeit von DNA Profilen',
|
|
8
|
+
description: 'Erkunden Sie, wie Allelfrequenzen und Hardy-Weinberg-Regeln eine lehrreiche Wahrscheinlichkeit für zufällige DNA-Profilübereinstimmungen ergeben.',
|
|
9
|
+
ui: {
|
|
10
|
+
...enContent.ui,
|
|
11
|
+
controls: 'Profilsteuerung', controlKicker: 'Profil aufbauen', controlHelper: 'Starten Sie mit einem Unterrichts-Preset oder öffnen Sie einen Locus, um Allele und Populationsfrequenzen zu bearbeiten.',
|
|
12
|
+
presets: 'Unterrichts-Presets', presetbalanced: 'Ausgewogen', presethomozygote: 'Homozygoten', presetclassroom: 'Einfacher Kurs', loci: 'Loci', locus: 'Locus', locusName: 'Name des Locus', alleleA: 'Allel A', alleleB: 'Allel B', frequencyA: 'Frequenz A (%)', frequencyB: 'Frequenz B (%)', removeLocus: 'Locus entfernen', addLocus: 'Locus hinzufügen',
|
|
13
|
+
disclaimer: 'Lehrsimulation. Sie identifiziert keine Person, bewertet keinen Fall und ersetzt keine Laborberechnung.', sceneKicker: 'Signalspur', electropherogram: 'Profilspur', sceneNote: 'Zwei Spitzen zeigen die eingegebenen Allele jedes Locus. Die Höhe ist nur ein visueller Hinweis auf die Frequenz.', peakHeight: 'Spitzenhöhe folgt der eingegebenen Frequenz', results: 'Wahrscheinlichkeitsergebnisse', resultKicker: 'Wahrscheinlichkeit einer Zufallsübereinstimmung', locusBreakdown: 'Berechnung Locus für Locus', genotype: 'Genotyp', rule: 'Regel', frequency: 'Genotypfrequenz', badgeNeedsData: 'Daten fehlen', badgeExploratory: 'Explorativ', badgeCalculated: 'Berechnetes Modell', needsData: 'Füllen Sie jeden Locus mit zwei Allelen und Frequenzen zwischen 0 und 100 Prozent aus; die Summe eines Frequenzpaars darf höchstens 100 Prozent betragen.', exploratoryResult: 'Dieses kleine Profil eignet sich zum Lernen. Mehr Loci können ein Profil seltener machen, machen das Modell aber nicht zu einer Fallbewertung.', calculatedResult: 'Das Produkt wird aus den eingegebenen Frequenzen unter vereinfachten Annahmen zur Unabhängigkeit berechnet.', notCalculated: 'Nicht berechnet', completeFields: 'Füllen Sie die Profilfelder aus, um ein Ergebnis zu sehen.', ofRandomProfiles: 'zufälliger Profile unter diesem Unterrichtsmodell', missingValue: 'Unbenannter Locus', pattern: 'Profiltyp', calculation: 'Berechnung', meaning: 'Bedeutung', homozygote: 'Zwei gleiche Allele', heterozygote: 'Zwei verschiedene Allele', independentLoci: 'Mehrere unabhängige Loci', homozygoteMeaning: 'Die Allelfrequenz wird mit sich selbst multipliziert.', heterozygoteMeaning: 'Die beiden Allelfrequenzen werden multipliziert und verdoppelt.', independentLociMeaning: 'Jeder Locus trägt zur kombinierten Profilfrequenz bei.',
|
|
14
|
+
},
|
|
15
|
+
seo: {
|
|
16
|
+
calculatorTitle: 'DNA-Profil-Rechner für zufällige Übereinstimmungswahrscheinlichkeit',
|
|
17
|
+
intro: 'Dieses Labor zur DNA-Profil-Wahrscheinlichkeit zeigt Studierenden und interessierten Lesern, wie aus einem kleinen autosomalen STR-Profil eine Wahrscheinlichkeit unter einem vereinfachten populationsgenetischen Modell entsteht. Geben Sie zwei Allele und ihre Frequenzen für jeden Locus ein. Der Rechner wendet die Hardy-Weinberg-Regel an und multipliziert die Locus-Frequenzen zu einer lehrreichen Zufallsübereinstimmung.',
|
|
18
|
+
methodTitle: 'So funktioniert die Genotypregel',
|
|
19
|
+
method: 'Die Benutzeroberfläche hält den Rechenweg sichtbar: Die Spur zeigt die eingegebenen Allele, die Tabelle zeigt jeden Genotyp und das Endergebnis wird als eins unter einer Zehnerpotenz ausgegeben. Ein homozygoter Locus verwendet p², ein heterozygoter Locus 2pq. Die Presets enthalten bewusst synthetische Unterrichtswerte und keine offizielle Populationsdatenbank.',
|
|
20
|
+
populationTitle: 'Warum Populationsfrequenzen wichtig sind',
|
|
21
|
+
population: 'Allelfrequenzen sind Schätzungen aus Populationsdatenbanken. Referenzpopulation, Stichprobe, Datenbankgröße, Verwandtschaft, Populationsstruktur und Validierung beeinflussen die Interpretation. Wenn die eingegebenen Frequenzen die relevante Population beschreiben, das Profil eine saubere Einzelquelle ist und die Loci als unabhängig gelten, schätzt das Produkt die Häufigkeit bei zufälligen unverwandten Personen. Ändert sich eine Annahme, ändert sich auch die Bedeutung des Ergebnisses.',
|
|
22
|
+
interpretation: 'Das Ergebnis ist eine bedingte Aussage über die eingegebenen Werte. Es berücksichtigt weder die Auswahl einer verdächtigen Person noch die Möglichkeit verwandter Personen, Mischspuren oder einen Datenbanksuch-Effekt. Deshalb sollte ein Unterrichtsbeispiel immer zusammen mit seiner Population, Methode und Unsicherheit gelesen werden.',
|
|
23
|
+
application: 'Für eine sinnvolle Übung kann man zuerst ein Preset wählen, danach nur einen Locus verändern und beobachten, wie sich die Tabelle und die Endwahrscheinlichkeit ändern. So wird sichtbar, dass seltene Allele den Beitrag eines Locus stark verändern können. Anschließend sollte man die Eingabewerte, die Herkunft der Frequenzen und die vereinfachte Unabhängigkeitsannahme notieren. Die Darstellung ist für Unterricht, Selbststudium und eine transparente Erklärung der Rechenschritte gedacht, nicht für eine forensische Stellungnahme.',
|
|
24
|
+
limitsTitle: 'Lehrgrenzen',
|
|
25
|
+
limits: 'In einem echten Fall müssen Auswahl der Person, Datenbank, Mischprofile, Populationsstruktur und fachkundige Interpretation dokumentiert werden. Diese kleine Anwendung analysiert keine Elektropherogramme, korrigiert keine Populationsstruktur, berechnet keine Likelihood-Ratios und durchsucht keine DNA-Datenbank.',
|
|
26
|
+
tipTitle: 'Als Modell verwenden, nicht als Urteil',
|
|
27
|
+
tip: 'Eine kleine Zufallsübereinstimmungswahrscheinlichkeit ist weder eine Aussage über Schuld noch über Identität. Verwenden Sie die Tool als Rechenhilfe und halten Sie Datenquelle, Population, Annahmen und Unsicherheit sichtbar.',
|
|
28
|
+
list: ['<strong>Eine Population:</strong> Mischen Sie keine Frequenzen aus nicht vergleichbaren Datenbanken.', '<strong>Annahmen sichtbar halten:</strong> Das Labor nimmt unverwandte Personen und vereinfachte Locus-Unabhängigkeit an.', '<strong>Wahrscheinlichkeit trennen:</strong> Ein seltenes Profil ist kein Beweis für Quelle oder Schuld.', '<strong>Daten dokumentieren:</strong> Ein formaler Bericht braucht Quelle, Methode, Unsicherheit und Interpretation.'],
|
|
29
|
+
},
|
|
30
|
+
faq: [
|
|
31
|
+
{ question: 'Was bedeutet die Wahrscheinlichkeit einer Zufallsübereinstimmung?', answer: 'Sie schätzt, wie wahrscheinlich es ist, dass eine zufällig ausgewählte unverwandte Person dieses Profil unter den gewählten Frequenzen und Annahmen besitzt. Sie ist nicht die Wahrscheinlichkeit von Schuld oder Herkunft einer Probe.' },
|
|
32
|
+
{ question: 'Wie wird eine Genotypfrequenz berechnet?', answer: 'Für einen Homozygoten verwendet das Labor p². Für einen Heterozygoten verwendet es 2pq; danach werden die Locusfrequenzen multipliziert.' },
|
|
33
|
+
{ question: 'Warum sind die Preset-Frequenzen synthetisch?', answer: 'Sie sind kleine Unterrichtsbeispiele. Forensische Arbeit benötigt eine validierte, repräsentative und dokumentierte Populationsdatenbank.' },
|
|
34
|
+
{ question: 'Kann die Anwendung zwei Personen vergleichen?', answer: 'Nein. Sie nimmt keine biologischen Proben an, vergleicht keine Profile und identifiziert niemanden. Sie zeigt nur ein mathematisches Modell.' },
|
|
35
|
+
{ question: 'Warum ist eine sehr kleine Wahrscheinlichkeit kein Urteil?', answer: 'Die Bedeutung hängt von Datenbank, Auswahl, Profilqualität, Unabhängigkeitsannahmen und fachlicher Interpretation ab.' },
|
|
36
|
+
],
|
|
37
|
+
howTo: [
|
|
38
|
+
{ name: 'Ein Unterrichts-Preset wählen', text: 'Starten Sie mit dem ausgewogenen, homozygoten oder einfachen Kurs-Preset.' },
|
|
39
|
+
{ name: 'Einen Locus bearbeiten', text: 'Geben Sie Namen, zwei Allele und die Frequenz jedes Allels als Prozentwert ein.' },
|
|
40
|
+
{ name: 'Die Locusregel lesen', text: 'Die Tabelle zeigt p² für Homozygoten und 2pq für Heterozygoten.' },
|
|
41
|
+
{ name: 'Das Gesamtergebnis vorsichtig deuten', text: 'Lesen Sie das Ergebnis als Unterrichtsmodell und halten Sie seine Annahmen sichtbar.' },
|
|
42
|
+
],
|
|
43
|
+
});
|