blacksinisterx commited on
Commit
d817a0e
Β·
verified Β·
1 Parent(s): 439b1dc

deploy: batch update 2 file(s)

Browse files
report_generation/templates/report_base.html CHANGED
@@ -1,79 +1,65 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>{{ report.title }}</title>
7
- <style>
8
- {% include 'report_styles.css' %}
9
- </style>
10
- </head>
11
- <body>
12
- <div class="report-container">
13
- <!-- Report Header -->
14
- <header class="report-header">
15
- <div class="logo">
16
- <h1>πŸ›‘οΈ DetectifAI</h1>
17
- <p class="subtitle">AI-Powered Surveillance System</p>
18
- </div>
19
- <div class="report-meta">
20
- <span class="classification {{ report.metadata.classification|default('CONFIDENTIAL')|lower }}">
21
- {{ report.metadata.classification|default('CONFIDENTIAL') }}
22
- </span>
23
- </div>
24
- </header>
25
-
26
- <!-- Report Content -->
27
- <main class="report-content">
28
- {% for section in report.sections|sort(attribute='order') %}
29
- <section class="report-section" id="section-{{ section.name }}">
30
- {{ section.content|markdown|safe }}
31
-
32
- {% if section.images %}
33
- <div class="evidence-gallery">
34
- <h3 class="gallery-title">Evidence Images</h3>
35
- <div class="gallery-grid">
36
- {% for img in section.images[:max_images] %}
37
- <figure class="evidence-item">
38
- {% if img.url %}
39
- <img src="{{ img.url }}"
40
- alt="{{ img.caption|default('Evidence image') }}"
41
- class="evidence-image"
42
- loading="lazy"
43
- onerror="this.onerror=null; this.src='data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%22200%22 height=%22150%22%3E%3Crect fill=%22%23edf2f7%22 width=%22200%22 height=%22150%22/%3E%3Ctext x=%2250%25%22 y=%2250%25%22 text-anchor=%22middle%22 fill=%22%23718096%22%3EImage unavailable%3C/text%3E%3C/svg%3E';">
44
- {% elif img.embedded_data %}
45
- <img src="data:image/jpeg;base64,{{ img.embedded_data }}"
46
- alt="{{ img.caption|default('Evidence image') }}"
47
- class="evidence-image">
48
- {% elif img.path %}
49
- <img src="{{ img.path }}"
50
- alt="{{ img.caption|default('Evidence image') }}"
51
- class="evidence-image"
52
- onerror="this.onerror=null; this.src='data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 width=%22200%22 height=%22150%22%3E%3Crect fill=%22%23edf2f7%22 width=%22200%22 height=%22150%22/%3E%3Ctext x=%2250%25%22 y=%2250%25%22 text-anchor=%22middle%22 fill=%22%23718096%22%3EImage unavailable%3C/text%3E%3C/svg%3E';">
53
- {% else %}
54
- <div class="image-placeholder">
55
- <span>πŸ“· {{ img.caption|default('Image: ' + (img.id|default('N/A')|string)) }}</span>
56
- </div>
57
- {% endif %}
58
- <figcaption>{{ img.caption|default('Evidence ' + loop.index|string) }}</figcaption>
59
- </figure>
60
- {% endfor %}
61
- </div>
62
- </div>
63
- {% endif %}
64
- </section>
65
- {% endfor %}
66
- </main>
67
-
68
- <!-- Report Footer -->
69
- <footer class="report-footer">
70
- <p>Report ID: {{ report.report_id }}</p>
71
- <p>Generated: {{ report.generated_at|format_datetime }}</p>
72
- <p class="disclaimer">
73
- This report was automatically generated by DetectifAI.
74
- All findings are based on AI analysis and should be verified by qualified personnel.
75
- </p>
76
- </footer>
77
- </div>
78
- </body>
79
- </html>
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>{{ report.title }}</title>
7
+ <style>
8
+ {% include 'report_styles.css' %}
9
+ </style>
10
+ </head>
11
+ <body>
12
+ <div class="report-container">
13
+
14
+ <!-- ── Report Header ───────────────────────────────────────────── -->
15
+ <header class="report-header">
16
+ <div class="logo">
17
+ <div class="logo-row">
18
+ <svg class="logo-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
19
+ <path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>
20
+ </svg>
21
+ <h1>DetectifAI</h1>
22
+ </div>
23
+ <p class="subtitle">AI-Powered Surveillance System</p>
24
+ </div>
25
+ <div class="report-meta">
26
+ <span class="classification {{ report.metadata.classification|default('CONFIDENTIAL')|lower }}">
27
+ {{ report.metadata.classification|default('CONFIDENTIAL') }}
28
+ </span>
29
+ </div>
30
+ </header>
31
+
32
+ <!-- ── Report Content ──────────────────────────────────────────── -->
33
+ <main class="report-content">
34
+ {% for section in report.sections|sort(attribute='order') %}
35
+ <section class="report-section section-{{ section.name }}" id="section-{{ section.name }}">
36
+ <div class="section-content">
37
+ {{ section.content|markdown|safe }}
38
+ </div>
39
+ {# Evidence gallery intentionally omitted β€” images are already
40
+ embedded inline within the markdown content above.
41
+ Rendering section.images here would duplicate every keyframe. #}
42
+ </section>
43
+ {% if not loop.last %}
44
+ <div class="section-divider"></div>
45
+ {% endif %}
46
+ {% endfor %}
47
+ </main>
48
+
49
+ <!-- ── Report Footer ───────────────────────────────────────────── -->
50
+ <footer class="report-footer">
51
+ <div class="footer-info">
52
+ <p><strong>Report ID:</strong> {{ report.report_id }}</p>
53
+ <p><strong>Generated:</strong> {{ report.generated_at|format_datetime }}</p>
54
+ </div>
55
+ <p class="disclaimer">
56
+ This report was automatically generated by DetectifAI using AI analysis.
57
+ All findings should be verified by qualified security personnel.
58
+ Auto-generated captions may contain errors and should be treated as
59
+ assistive context, not definitive evidence.
60
+ </p>
61
+ </footer>
62
+
63
+ </div>
64
+ </body>
65
+ </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
report_generation/templates/report_styles.css CHANGED
@@ -1,25 +1,31 @@
1
  /* ============================================================
2
  DetectifAI Incident Report β€” Stylesheet
3
- Design: Professional forensic document.
4
- Colour palette: navy primary, slate text, white surface.
5
- Print-ready: A4-compatible, page-break aware.
 
 
6
  ============================================================ */
7
 
8
  :root {
9
- --navy: #1a365d;
10
- --navy-mid: #2c5282;
11
- --slate: #2d3748;
12
- --slate-light: #4a5568;
13
- --steel: #718096;
14
- --border: #e2e8f0;
15
- --surface: #f8fafc;
16
- --white: #ffffff;
17
- --accent: #3182ce;
18
- --danger: #c53030;
19
- --warn: #c05621;
20
- --ok: #276749;
21
- --warn-bg: #fffff0;
22
- --danger-bg: #fff5f5;
 
 
 
 
23
  }
24
 
25
  /* ── Reset ─────────────────────────────────────────────────── */
@@ -28,10 +34,10 @@
28
  /* ── Base ──────────────────────────────────────────────────── */
29
  body {
30
  font-family: 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
31
- font-size: 11pt;
32
- line-height: 1.75;
33
  color: var(--slate);
34
- background: #edf2f7;
35
  }
36
 
37
  /* ── Page wrapper ──────────────────────────────────────────── */
@@ -39,300 +45,338 @@ body {
39
  max-width: 210mm;
40
  margin: 24px auto;
41
  background: var(--white);
42
- box-shadow: 0 2px 24px rgba(0,0,0,0.12);
 
 
43
  }
44
 
45
  /* ── Header ────────────────────────────────────────────────── */
46
  .report-header {
47
- background: linear-gradient(135deg, var(--navy) 0%, var(--navy-mid) 100%);
48
  color: var(--white);
49
- padding: 36px 48px;
50
  display: flex;
51
  justify-content: space-between;
52
  align-items: flex-start;
53
- border-bottom: 4px solid var(--accent);
54
  }
55
 
56
  .logo-row {
57
  display: flex;
58
  align-items: center;
59
- gap: 12px;
60
- margin-bottom: 6px;
61
  }
62
 
63
  .logo-icon {
64
- width: 32px;
65
- height: 32px;
66
- color: var(--white);
67
- opacity: 0.9;
68
  flex-shrink: 0;
69
  }
70
 
71
- .logo h1 {
72
- font-size: 26pt;
73
- font-weight: 700;
74
  letter-spacing: -0.5px;
75
  line-height: 1;
 
76
  }
77
 
78
  .subtitle {
79
  font-size: 10pt;
80
  opacity: 0.80;
81
  font-weight: 300;
82
- margin-top: 2px;
83
  }
84
 
85
  /* Classification badge */
86
  .classification {
87
- padding: 8px 18px;
88
  border-radius: 4px;
89
  font-weight: 700;
90
  text-transform: uppercase;
91
  font-size: 9pt;
92
- letter-spacing: 1.5px;
93
  color: var(--white);
94
  white-space: nowrap;
 
95
  }
96
- .classification.confidential { background: var(--danger); }
97
- .classification.internal { background: var(--warn); }
98
- .classification.public { background: var(--ok); }
99
  .classification.restricted { background: #553c9a; }
100
 
101
  /* ── Main content ─────────────────────────���────────────────── */
102
  .report-content {
103
- padding: 48px 48px 32px;
 
104
  }
105
 
106
  .report-section {
107
- margin-bottom: 40px;
108
  }
109
 
 
110
  .section-content {
111
  background: var(--surface);
112
  padding: 28px 32px;
113
  border-radius: 6px;
114
- border-left: 4px solid var(--accent);
 
 
115
  }
116
 
117
  .section-divider {
118
  height: 1px;
119
  background: var(--border);
120
- margin: 40px 0;
121
  }
122
 
123
  /* ── Typography ────────────────────────────────────────────── */
124
  h1 {
125
- font-size: 22pt;
126
  color: var(--navy);
127
- border-bottom: 3px solid var(--accent);
128
- padding-bottom: 12px;
129
- margin-bottom: 20px;
130
- font-weight: 700;
 
131
  }
132
 
133
  h2 {
134
- font-size: 16pt;
135
- color: var(--navy);
136
- border-bottom: 1px solid var(--border);
137
- padding-bottom: 8px;
138
- margin-top: 28px;
139
- margin-bottom: 16px;
140
- font-weight: 600;
141
  }
142
 
143
  h3 {
144
- font-size: 13pt;
145
- color: var(--slate);
146
- margin-top: 22px;
147
  margin-bottom: 12px;
148
  font-weight: 600;
149
  }
150
 
151
  h4 {
152
- font-size: 11pt;
153
- color: var(--slate-light);
154
- margin-top: 16px;
155
- margin-bottom: 8px;
156
  font-weight: 600;
 
 
 
157
  }
158
 
159
  p {
160
  margin-bottom: 14px;
161
- text-align: justify;
162
- hyphens: auto;
163
  }
164
 
165
- strong { color: var(--navy); font-weight: 600; }
166
 
167
  em { color: var(--slate-light); }
168
 
169
  hr {
170
  border: none;
171
- border-top: 1px solid var(--border);
172
- margin: 24px 0;
173
  }
174
 
175
  /* ── Tables ────────────────────────────────────────────────── */
176
  table {
177
  width: 100%;
178
  border-collapse: collapse;
179
- margin: 20px 0;
180
- font-size: 10pt;
181
  border-radius: 6px;
182
  overflow: hidden;
183
- box-shadow: 0 1px 6px rgba(0,0,0,0.08);
 
184
  }
185
 
186
- thead { background: var(--navy); color: var(--white); }
 
 
 
187
 
188
  th {
189
- padding: 12px 14px;
190
- font-weight: 600;
191
  font-size: 9pt;
192
  text-transform: uppercase;
193
- letter-spacing: 0.6px;
194
  text-align: left;
 
 
195
  }
196
 
197
  td {
198
- padding: 11px 14px;
199
- border-bottom: 1px solid var(--border);
200
  vertical-align: top;
 
201
  }
202
 
203
- tbody tr:nth-child(even) { background: var(--surface); }
204
- tbody tr:hover { background: #edf2f7; }
 
 
205
 
206
- td:first-child { font-weight: 600; color: var(--slate); width: 22%; }
 
 
 
 
 
 
 
 
 
 
 
207
 
208
  /* ── Inline images from markdown ── */
209
- /* The markdown renderer produces <p><img …></p> or bare <img …>.
210
- We style these as a clean evidence grid so keyframes are correctly
211
- aligned without duplicating them in a separate gallery block. */
212
  .section-content p > img,
213
  .section-content img {
214
  display: block;
215
  width: 100%;
216
- max-width: 280px;
217
- height: 180px;
218
  object-fit: cover;
219
  border-radius: 6px;
220
- border: 1px solid var(--border);
221
  margin: 8px auto 4px;
222
- box-shadow: 0 2px 8px rgba(0,0,0,0.08);
223
- }
224
-
225
- /* Keyframe grid β€” wraps consecutive images in the evidence section */
226
- .section-content .keyframe-grid {
227
- display: grid;
228
- grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
229
- gap: 20px;
230
- margin: 20px 0;
231
  }
232
 
233
  /* ── Lists ─────────────────────────────────────────────────── */
234
  ul, ol {
235
- margin: 12px 0 12px 24px;
236
  }
237
-
238
  li {
239
- margin-bottom: 6px;
240
  line-height: 1.6;
 
241
  }
242
-
243
- li::marker { color: var(--accent); font-weight: 600; }
244
 
245
  /* ── Blockquotes ───────────────────────────────────────────── */
246
  blockquote {
247
- margin: 16px 0;
248
- padding: 16px 20px;
249
- border-left: 4px solid var(--accent);
250
  background: var(--surface);
251
  border-radius: 0 6px 6px 0;
252
- color: var(--slate-light);
253
  font-style: italic;
 
 
254
  }
255
-
256
  blockquote p { margin-bottom: 0; }
257
 
258
  /* ── Code ──────────────────────────────────────────────────── */
259
  code {
260
- background: #edf2f7;
261
- padding: 2px 6px;
262
  border-radius: 3px;
263
  font-family: 'Courier New', monospace;
264
  font-size: 9.5pt;
265
  color: #c53030;
 
266
  }
267
-
268
  pre {
269
  background: var(--slate);
270
  color: #e2e8f0;
271
- padding: 16px 20px;
272
  border-radius: 6px;
273
  overflow-x: auto;
274
- font-size: 9pt;
275
- margin: 16px 0;
 
276
  }
 
277
 
278
- pre code { background: transparent; color: inherit; padding: 0; }
279
-
280
- /* ── Threat level tags ─────────────────────────────────────── */
281
- .threat-critical { color: var(--danger); font-weight: 600; background: var(--danger-bg); padding: 1px 5px; border-radius: 3px; }
282
- .threat-high { color: var(--warn); font-weight: 600; background: #fffaf0; padding: 1px 5px; border-radius: 3px; }
283
- .threat-medium { color: #b7791f; background: var(--warn-bg); padding: 1px 5px; border-radius: 3px; }
284
- .threat-low { color: var(--ok); background: #f0fff4; padding: 1px 5px; border-radius: 3px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285
 
286
  /* ── Footer ────────────────────────────────────────────────── */
287
  .report-footer {
288
  background: var(--surface);
289
- padding: 24px 48px;
290
- border-top: 2px solid var(--accent);
291
  font-size: 9.5pt;
292
- color: var(--steel);
 
293
  }
294
 
295
  .footer-info {
296
- margin-bottom: 16px;
297
- padding-bottom: 12px;
298
- border-bottom: 1px solid var(--border);
299
  display: flex;
300
- gap: 32px;
301
  flex-wrap: wrap;
 
 
 
302
  }
303
-
304
  .footer-info p { margin: 0; text-align: left; }
 
305
 
306
  .disclaimer {
307
  font-style: italic;
308
- padding: 12px 16px;
309
- background: #fffbeb;
310
- border-left: 3px solid #d69e2e;
311
- border-radius: 3px;
312
  color: #744210;
313
- line-height: 1.5;
 
 
314
  }
315
 
316
  /* ── Print / PDF ──────────────────────���────────────────────── */
317
  @media print {
318
  body { background: white; }
319
-
320
- .report-container {
321
- box-shadow: none;
322
- max-width: 100%;
323
- margin: 0;
324
- }
325
-
326
  .report-header { page-break-after: avoid; }
327
-
328
  .report-section { page-break-inside: avoid; orphans: 3; widows: 3; }
329
-
330
  h1, h2, h3, h4 { page-break-after: avoid; }
331
-
332
  table { page-break-inside: avoid; }
333
  thead { display: table-header-group; }
334
-
335
  img { max-width: 100%; page-break-inside: avoid; }
336
-
337
- a { text-decoration: none; color: var(--navy); }
338
  }
 
1
  /* ============================================================
2
  DetectifAI Incident Report β€” Stylesheet
3
+ Design goals:
4
+ - High contrast on every surface (WCAG AA minimum)
5
+ - Clear visual hierarchy: header > section title > body
6
+ - Professional forensic document aesthetic
7
+ - Print-ready (A4, page-break aware)
8
  ============================================================ */
9
 
10
  :root {
11
+ --navy: #0f2442; /* Deep navy β€” header, h1 */
12
+ --navy-mid: #1a365d; /* Mid navy β€” h2, table header */
13
+ --navy-light: #2c5282; /* Light navy β€” accents */
14
+ --slate: #1a202c; /* Near-black β€” body text */
15
+ --slate-mid: #2d3748; /* Dark slate β€” secondary text */
16
+ --slate-light: #4a5568; /* Medium slate β€” captions */
17
+ --border: #cbd5e0; /* Visible border */
18
+ --border-light: #e2e8f0; /* Subtle separator */
19
+ --surface: #edf2f7; /* Section backgrounds */
20
+ --surface-alt: #e2e8f0; /* Table even rows */
21
+ --white: #ffffff;
22
+ --accent: #2b6cb0; /* Strong blue β€” accent bar, links */
23
+ --danger: #c53030;
24
+ --warn: #c05621;
25
+ --ok: #276749;
26
+ --danger-bg: #fff5f5;
27
+ --warn-bg: #fffaf0;
28
+ --ok-bg: #f0fff4;
29
  }
30
 
31
  /* ── Reset ─────────────────────────────────────────────────── */
 
34
  /* ── Base ──────────────────────────────────────────────────── */
35
  body {
36
  font-family: 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
37
+ font-size: 11.5pt;
38
+ line-height: 1.8;
39
  color: var(--slate);
40
+ background: #dde3ea; /* Mid-grey page backdrop */
41
  }
42
 
43
  /* ── Page wrapper ──────────────────────────────────────────── */
 
45
  max-width: 210mm;
46
  margin: 24px auto;
47
  background: var(--white);
48
+ box-shadow: 0 4px 32px rgba(0,0,0,0.20);
49
+ border-radius: 2px;
50
+ overflow: hidden;
51
  }
52
 
53
  /* ── Header ────────────────────────────────────────────────── */
54
  .report-header {
55
+ background: linear-gradient(135deg, var(--navy) 0%, var(--navy-light) 100%);
56
  color: var(--white);
57
+ padding: 40px 52px;
58
  display: flex;
59
  justify-content: space-between;
60
  align-items: flex-start;
61
+ border-bottom: 5px solid var(--accent);
62
  }
63
 
64
  .logo-row {
65
  display: flex;
66
  align-items: center;
67
+ gap: 14px;
68
+ margin-bottom: 8px;
69
  }
70
 
71
  .logo-icon {
72
+ width: 36px;
73
+ height: 36px;
74
+ color: rgba(255,255,255,0.95);
 
75
  flex-shrink: 0;
76
  }
77
 
78
+ .logo-row h1 {
79
+ font-size: 28pt;
80
+ font-weight: 800;
81
  letter-spacing: -0.5px;
82
  line-height: 1;
83
+ color: var(--white);
84
  }
85
 
86
  .subtitle {
87
  font-size: 10pt;
88
  opacity: 0.80;
89
  font-weight: 300;
90
+ color: rgba(255,255,255,0.85);
91
  }
92
 
93
  /* Classification badge */
94
  .classification {
95
+ padding: 8px 20px;
96
  border-radius: 4px;
97
  font-weight: 700;
98
  text-transform: uppercase;
99
  font-size: 9pt;
100
+ letter-spacing: 2px;
101
  color: var(--white);
102
  white-space: nowrap;
103
+ border: 2px solid rgba(255,255,255,0.30);
104
  }
105
+ .classification.confidential { background: #c53030; }
106
+ .classification.internal { background: #c05621; }
107
+ .classification.public { background: #276749; }
108
  .classification.restricted { background: #553c9a; }
109
 
110
  /* ── Main content ─────────────────────────���────────────────── */
111
  .report-content {
112
+ padding: 48px 52px 36px;
113
+ background: var(--white);
114
  }
115
 
116
  .report-section {
117
+ margin-bottom: 44px;
118
  }
119
 
120
+ /* Section card β€” clearly distinct from the page white */
121
  .section-content {
122
  background: var(--surface);
123
  padding: 28px 32px;
124
  border-radius: 6px;
125
+ border-left: 5px solid var(--accent);
126
+ border: 1px solid var(--border);
127
+ border-left: 5px solid var(--accent);
128
  }
129
 
130
  .section-divider {
131
  height: 1px;
132
  background: var(--border);
133
+ margin: 44px 0;
134
  }
135
 
136
  /* ── Typography ────────────────────────────────────────────── */
137
  h1 {
138
+ font-size: 24pt;
139
  color: var(--navy);
140
+ border-bottom: 4px solid var(--accent);
141
+ padding-bottom: 14px;
142
+ margin-bottom: 24px;
143
+ font-weight: 800;
144
+ letter-spacing: -0.5px;
145
  }
146
 
147
  h2 {
148
+ font-size: 17pt;
149
+ color: var(--navy-mid);
150
+ border-bottom: 2px solid var(--border);
151
+ padding-bottom: 10px;
152
+ margin-top: 32px;
153
+ margin-bottom: 18px;
154
+ font-weight: 700;
155
  }
156
 
157
  h3 {
158
+ font-size: 13.5pt;
159
+ color: var(--navy-light);
160
+ margin-top: 24px;
161
  margin-bottom: 12px;
162
  font-weight: 600;
163
  }
164
 
165
  h4 {
166
+ font-size: 11.5pt;
167
+ color: var(--slate-mid);
168
+ margin-top: 18px;
169
+ margin-bottom: 10px;
170
  font-weight: 600;
171
+ text-transform: uppercase;
172
+ letter-spacing: 0.6px;
173
+ font-size: 9pt;
174
  }
175
 
176
  p {
177
  margin-bottom: 14px;
178
+ color: var(--slate);
 
179
  }
180
 
181
+ strong { color: var(--navy-mid); font-weight: 700; }
182
 
183
  em { color: var(--slate-light); }
184
 
185
  hr {
186
  border: none;
187
+ border-top: 2px solid var(--border);
188
+ margin: 28px 0;
189
  }
190
 
191
  /* ── Tables ────────────────────────────────────────────────── */
192
  table {
193
  width: 100%;
194
  border-collapse: collapse;
195
+ margin: 22px 0;
196
+ font-size: 10.5pt;
197
  border-radius: 6px;
198
  overflow: hidden;
199
+ box-shadow: 0 2px 8px rgba(0,0,0,0.10);
200
+ border: 1px solid var(--border);
201
  }
202
 
203
+ thead {
204
+ background: var(--navy-mid);
205
+ color: var(--white);
206
+ }
207
 
208
  th {
209
+ padding: 13px 16px;
210
+ font-weight: 700;
211
  font-size: 9pt;
212
  text-transform: uppercase;
213
+ letter-spacing: 0.8px;
214
  text-align: left;
215
+ color: var(--white);
216
+ border-bottom: 2px solid rgba(255,255,255,0.2);
217
  }
218
 
219
  td {
220
+ padding: 12px 16px;
221
+ border-bottom: 1px solid var(--border-light);
222
  vertical-align: top;
223
+ color: var(--slate);
224
  }
225
 
226
+ /* Strong zebra striping β€” clearly distinguishable rows */
227
+ tbody tr:nth-child(odd) { background: var(--white); }
228
+ tbody tr:nth-child(even) { background: var(--surface-alt); }
229
+ tbody tr:hover { background: #bee3f8; transition: background 0.15s; }
230
 
231
+ /* First column label style */
232
+ td:first-child {
233
+ font-weight: 600;
234
+ color: var(--navy-mid);
235
+ width: 26%;
236
+ background: var(--surface) !important;
237
+ }
238
+
239
+ /* Override the hover background for first column */
240
+ tbody tr:hover td:first-child {
241
+ background: #bee3f8 !important;
242
+ }
243
 
244
  /* ── Inline images from markdown ── */
 
 
 
245
  .section-content p > img,
246
  .section-content img {
247
  display: block;
248
  width: 100%;
249
+ max-width: 260px;
250
+ height: 170px;
251
  object-fit: cover;
252
  border-radius: 6px;
253
+ border: 2px solid var(--border);
254
  margin: 8px auto 4px;
255
+ box-shadow: 0 2px 12px rgba(0,0,0,0.12);
 
 
 
 
 
 
 
 
256
  }
257
 
258
  /* ── Lists ─────────────────────────────────────────────────── */
259
  ul, ol {
260
+ margin: 14px 0 14px 28px;
261
  }
 
262
  li {
263
+ margin-bottom: 7px;
264
  line-height: 1.6;
265
+ color: var(--slate);
266
  }
267
+ li::marker { color: var(--accent); font-weight: 700; }
 
268
 
269
  /* ── Blockquotes ───────────────────────────────────────────── */
270
  blockquote {
271
+ margin: 18px 0;
272
+ padding: 18px 22px;
273
+ border-left: 5px solid var(--accent);
274
  background: var(--surface);
275
  border-radius: 0 6px 6px 0;
276
+ color: var(--slate-mid);
277
  font-style: italic;
278
+ border: 1px solid var(--border);
279
+ border-left: 5px solid var(--accent);
280
  }
 
281
  blockquote p { margin-bottom: 0; }
282
 
283
  /* ── Code ──────────────────────────────────────────────────── */
284
  code {
285
+ background: var(--surface-alt);
286
+ padding: 2px 7px;
287
  border-radius: 3px;
288
  font-family: 'Courier New', monospace;
289
  font-size: 9.5pt;
290
  color: #c53030;
291
+ border: 1px solid var(--border-light);
292
  }
 
293
  pre {
294
  background: var(--slate);
295
  color: #e2e8f0;
296
+ padding: 18px 22px;
297
  border-radius: 6px;
298
  overflow-x: auto;
299
+ font-size: 9.5pt;
300
+ margin: 18px 0;
301
+ border: 1px solid rgba(255,255,255,0.1);
302
  }
303
+ pre code { background: transparent; border: none; color: inherit; padding: 0; }
304
 
305
+ /* ── Threat level badges ───────────────────────────────────── */
306
+ .threat-critical {
307
+ color: var(--danger);
308
+ font-weight: 700;
309
+ background: var(--danger-bg);
310
+ padding: 2px 7px;
311
+ border-radius: 3px;
312
+ border: 1px solid rgba(197,48,48,0.25);
313
+ }
314
+ .threat-high {
315
+ color: var(--warn);
316
+ font-weight: 700;
317
+ background: var(--warn-bg);
318
+ padding: 2px 7px;
319
+ border-radius: 3px;
320
+ border: 1px solid rgba(192,86,33,0.25);
321
+ }
322
+ .threat-medium {
323
+ color: #b7791f;
324
+ background: var(--warn-bg);
325
+ padding: 2px 7px;
326
+ border-radius: 3px;
327
+ border: 1px solid rgba(183,121,31,0.25);
328
+ }
329
+ .threat-low {
330
+ color: var(--ok);
331
+ background: var(--ok-bg);
332
+ padding: 2px 7px;
333
+ border-radius: 3px;
334
+ border: 1px solid rgba(39,103,73,0.25);
335
+ }
336
 
337
  /* ── Footer ────────────────────────────────────────────────── */
338
  .report-footer {
339
  background: var(--surface);
340
+ padding: 28px 52px;
341
+ border-top: 3px solid var(--navy-mid);
342
  font-size: 9.5pt;
343
+ color: var(--slate-light);
344
+ border-top: 4px solid var(--accent);
345
  }
346
 
347
  .footer-info {
 
 
 
348
  display: flex;
349
+ gap: 36px;
350
  flex-wrap: wrap;
351
+ margin-bottom: 16px;
352
+ padding-bottom: 14px;
353
+ border-bottom: 1px solid var(--border);
354
  }
 
355
  .footer-info p { margin: 0; text-align: left; }
356
+ .footer-info strong { color: var(--navy-mid); }
357
 
358
  .disclaimer {
359
  font-style: italic;
360
+ padding: 12px 18px;
361
+ background: #fffff0;
362
+ border-left: 4px solid #d69e2e;
363
+ border-radius: 0 4px 4px 0;
364
  color: #744210;
365
+ line-height: 1.6;
366
+ border: 1px solid #f6e05e;
367
+ border-left: 4px solid #d69e2e;
368
  }
369
 
370
  /* ── Print / PDF ──────────────────────���────────────────────── */
371
  @media print {
372
  body { background: white; }
373
+ .report-container { box-shadow: none; max-width: 100%; margin: 0; border-radius: 0; }
 
 
 
 
 
 
374
  .report-header { page-break-after: avoid; }
 
375
  .report-section { page-break-inside: avoid; orphans: 3; widows: 3; }
 
376
  h1, h2, h3, h4 { page-break-after: avoid; }
 
377
  table { page-break-inside: avoid; }
378
  thead { display: table-header-group; }
 
379
  img { max-width: 100%; page-break-inside: avoid; }
380
+ a { text-decoration: none; color: var(--navy-mid); }
381
+ .section-content { border: 1px solid var(--border); border-left: 5px solid var(--accent); }
382
  }