@striae-org/striae 4.2.1 → 4.3.1

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 (66) hide show
  1. package/app/components/actions/case-import/confirmation-import.ts +20 -1
  2. package/app/components/actions/case-import/orchestrator.ts +3 -0
  3. package/app/components/actions/case-manage.ts +5 -1
  4. package/app/components/actions/confirm-export.ts +12 -3
  5. package/app/components/audit/viewer/audit-entries-list.tsx +20 -2
  6. package/app/components/audit/viewer/use-audit-viewer-export.ts +2 -2
  7. package/app/components/audit/viewer/use-audit-viewer-filters.ts +11 -1
  8. package/app/components/canvas/canvas.tsx +2 -1
  9. package/app/components/navbar/case-modals/archive-case-modal.module.css +0 -76
  10. package/app/components/navbar/case-modals/archive-case-modal.tsx +9 -8
  11. package/app/components/navbar/case-modals/case-modal-shared.module.css +94 -0
  12. package/app/components/navbar/case-modals/delete-case-modal.module.css +9 -0
  13. package/app/components/navbar/case-modals/delete-case-modal.tsx +79 -0
  14. package/app/components/navbar/case-modals/open-case-modal.module.css +2 -1
  15. package/app/components/navbar/case-modals/rename-case-modal.module.css +0 -72
  16. package/app/components/navbar/case-modals/rename-case-modal.tsx +9 -8
  17. package/app/components/navbar/navbar.module.css +11 -0
  18. package/app/components/navbar/navbar.tsx +38 -19
  19. package/app/components/sidebar/case-import/hooks/useImportExecution.ts +2 -0
  20. package/app/components/sidebar/cases/case-sidebar.tsx +27 -3
  21. package/app/components/sidebar/cases/cases-modal.module.css +312 -10
  22. package/app/components/sidebar/cases/cases-modal.tsx +690 -110
  23. package/app/components/sidebar/cases/cases.module.css +23 -0
  24. package/app/components/sidebar/files/delete-files-modal.module.css +26 -0
  25. package/app/components/sidebar/files/delete-files-modal.tsx +94 -0
  26. package/app/components/sidebar/files/files-modal.module.css +285 -44
  27. package/app/components/sidebar/files/files-modal.tsx +452 -145
  28. package/app/components/sidebar/notes/class-details-fields.tsx +146 -0
  29. package/app/components/sidebar/notes/class-details-modal.tsx +147 -0
  30. package/app/components/sidebar/notes/class-details-sections.tsx +561 -0
  31. package/app/components/sidebar/notes/class-details-shared.ts +239 -0
  32. package/app/components/sidebar/notes/notes-editor-form.tsx +43 -5
  33. package/app/components/sidebar/notes/notes.module.css +236 -4
  34. package/app/components/sidebar/notes/use-class-details-state.ts +371 -0
  35. package/app/components/sidebar/sidebar-container.tsx +2 -0
  36. package/app/components/sidebar/sidebar.tsx +8 -1
  37. package/app/hooks/useCaseListPreferences.ts +99 -0
  38. package/app/hooks/useFileListPreferences.ts +106 -0
  39. package/app/routes/striae/striae.tsx +45 -1
  40. package/app/services/audit/audit-export-csv.ts +4 -2
  41. package/app/services/audit/audit-export-report.ts +36 -4
  42. package/app/services/audit/audit.service.ts +2 -0
  43. package/app/services/audit/builders/audit-entry-builder.ts +1 -0
  44. package/app/services/audit/builders/audit-event-builders-workflow.ts +8 -2
  45. package/app/types/annotations.ts +48 -1
  46. package/app/types/audit.ts +1 -0
  47. package/app/utils/data/case-filters.ts +127 -0
  48. package/app/utils/data/confirmation-summary/summary-core.ts +18 -2
  49. package/app/utils/data/file-filters.ts +201 -0
  50. package/app/utils/forensics/confirmation-signature.ts +20 -5
  51. package/functions/api/image/[[path]].ts +4 -0
  52. package/package.json +3 -4
  53. package/workers/audit-worker/wrangler.jsonc.example +1 -1
  54. package/workers/data-worker/src/signing-payload-utils.ts +5 -0
  55. package/workers/data-worker/wrangler.jsonc.example +1 -1
  56. package/workers/image-worker/wrangler.jsonc.example +1 -1
  57. package/workers/keys-worker/wrangler.jsonc.example +1 -1
  58. package/workers/pdf-worker/src/formats/format-striae.ts +84 -118
  59. package/workers/pdf-worker/src/pdf-worker.example.ts +28 -10
  60. package/workers/pdf-worker/src/report-layout.ts +227 -0
  61. package/workers/pdf-worker/src/report-types.ts +20 -0
  62. package/workers/pdf-worker/wrangler.jsonc.example +1 -1
  63. package/workers/user-worker/wrangler.jsonc.example +1 -1
  64. package/wrangler.toml.example +1 -1
  65. package/workers/pdf-worker/src/assets/icon-256.png +0 -0
  66. /package/workers/pdf-worker/src/assets/{generated-assets.ts → generated-assets.example.ts} +0 -0
@@ -489,6 +489,29 @@
489
489
  cursor: not-allowed;
490
490
  }
491
491
 
492
+ .sidebarToggle .confirmationExportButton {
493
+ width: 100%;
494
+ padding: 0.625rem 0.75rem;
495
+ background-color: #198754;
496
+ color: white;
497
+ border: none;
498
+ border-radius: 6px;
499
+ font-weight: 600;
500
+ font-size: 0.9rem;
501
+ cursor: pointer;
502
+ transition: all 0.2s;
503
+ }
504
+
505
+ .sidebarToggle .confirmationExportButton:hover:not(:disabled) {
506
+ background-color: #146c43;
507
+ }
508
+
509
+ .sidebarToggle .confirmationExportButton:disabled {
510
+ background-color: var(--backgroundLight);
511
+ color: var(--textLight);
512
+ cursor: not-allowed;
513
+ }
514
+
492
515
  /* Case Actions Section */
493
516
  .caseActionsSection {
494
517
  margin-top: 1.5rem;
@@ -0,0 +1,26 @@
1
+ .modal {
2
+ width: min(620px, calc(100vw - 2rem));
3
+ }
4
+
5
+ .filePreviewList {
6
+ margin: 0.6rem 0 0;
7
+ padding-left: 1.1rem;
8
+ color: #3f2a2e;
9
+ font-size: 0.86rem;
10
+ }
11
+
12
+ .filePreviewList li + li {
13
+ margin-top: 0.3rem;
14
+ }
15
+
16
+ .remainingNote {
17
+ margin-top: 0.5rem;
18
+ font-size: 0.84rem;
19
+ color: #6b2f35;
20
+ }
21
+
22
+ .confirmButton {
23
+ background: #dc3545;
24
+ color: #ffffff;
25
+ border-color: #c82333;
26
+ }
@@ -0,0 +1,94 @@
1
+ import { useMemo } from 'react';
2
+ import { useOverlayDismiss } from '~/hooks/useOverlayDismiss';
3
+ import { type FileData } from '~/types';
4
+ import sharedStyles from '~/components/navbar/case-modals/case-modal-shared.module.css';
5
+ import styles from './delete-files-modal.module.css';
6
+
7
+ interface DeleteFilesModalProps {
8
+ isOpen: boolean;
9
+ isSubmitting?: boolean;
10
+ files: FileData[];
11
+ selectedFileIds: Set<string>;
12
+ onClose: () => void;
13
+ onSubmit: () => Promise<void>;
14
+ }
15
+
16
+ export const DeleteFilesModal = ({
17
+ isOpen,
18
+ isSubmitting = false,
19
+ files,
20
+ selectedFileIds,
21
+ onClose,
22
+ onSubmit,
23
+ }: DeleteFilesModalProps) => {
24
+ const selectedFiles = useMemo(
25
+ () => files.filter((file) => selectedFileIds.has(file.id)),
26
+ [files, selectedFileIds]
27
+ );
28
+
29
+ const previewFiles = selectedFiles.slice(0, 5);
30
+ const remainingCount = Math.max(0, selectedFiles.length - previewFiles.length);
31
+
32
+ const {
33
+ requestClose,
34
+ overlayProps,
35
+ getCloseButtonProps,
36
+ } = useOverlayDismiss({
37
+ isOpen,
38
+ onClose,
39
+ canDismiss: !isSubmitting,
40
+ });
41
+
42
+ if (!isOpen) {
43
+ return null;
44
+ }
45
+
46
+ return (
47
+ <div className={sharedStyles.overlay} aria-label="Close delete files dialog" {...overlayProps}>
48
+ <div className={`${sharedStyles.modal} ${styles.modal}`} role="dialog" aria-modal="true" aria-label="Delete Selected Files">
49
+ <button {...getCloseButtonProps({ ariaLabel: 'Close delete files dialog' })}>×</button>
50
+
51
+ <h3 className={sharedStyles.title}>Delete Selected Files</h3>
52
+ <p className={sharedStyles.subtitle}>
53
+ {selectedFiles.length} file{selectedFiles.length === 1 ? '' : 's'} selected
54
+ </p>
55
+
56
+ <div className={sharedStyles.warningPanel}>
57
+ <p>This action permanently deletes the selected files and their annotation data.</p>
58
+ <p>This operation cannot be undone.</p>
59
+ {previewFiles.length > 0 && (
60
+ <ul className={styles.filePreviewList}>
61
+ {previewFiles.map((file) => (
62
+ <li key={file.id}>{file.originalFilename}</li>
63
+ ))}
64
+ </ul>
65
+ )}
66
+ {remainingCount > 0 && (
67
+ <p className={styles.remainingNote}>and {remainingCount} more...</p>
68
+ )}
69
+ </div>
70
+
71
+ <div className={sharedStyles.actions}>
72
+ <button
73
+ type="button"
74
+ className={sharedStyles.cancelButton}
75
+ onClick={requestClose}
76
+ disabled={isSubmitting}
77
+ >
78
+ Cancel
79
+ </button>
80
+ <button
81
+ type="button"
82
+ className={`${sharedStyles.confirmButton} ${styles.confirmButton}`}
83
+ onClick={() => {
84
+ void onSubmit();
85
+ }}
86
+ disabled={isSubmitting || selectedFiles.length === 0}
87
+ >
88
+ {isSubmitting ? 'Deleting...' : `Delete ${selectedFiles.length} File${selectedFiles.length === 1 ? '' : 's'}`}
89
+ </button>
90
+ </div>
91
+ </div>
92
+ </div>
93
+ );
94
+ };
@@ -14,9 +14,10 @@
14
14
  position: relative;
15
15
  background: var(--backgroundLight);
16
16
  border-radius: var(--spaceXS);
17
+ overflow: hidden;
17
18
  width: 90%;
18
19
  max-width: var(--maxWidthL);
19
- max-height: 80vh;
20
+ max-height: 84vh;
20
21
  box-shadow: 0 var(--spaceXS) var(--spaceL)
21
22
  color-mix(in lab, var(--black) 10%, transparent);
22
23
  cursor: default;
@@ -41,6 +42,9 @@
41
42
  overflow-y: auto;
42
43
  flex: 1;
43
44
  min-height: 0;
45
+ display: flex;
46
+ flex-direction: column;
47
+ gap: var(--spaceM);
44
48
  }
45
49
 
46
50
  .closeButton {
@@ -57,6 +61,114 @@
57
61
  color: var(--text);
58
62
  }
59
63
 
64
+ .controlsSection {
65
+ display: grid;
66
+ grid-template-columns: repeat(4, minmax(0, 1fr));
67
+ gap: var(--spaceM);
68
+ align-items: end;
69
+ }
70
+
71
+ .controlGroup {
72
+ display: flex;
73
+ flex-direction: column;
74
+ gap: var(--spaceXS);
75
+ }
76
+
77
+ .controlGroup label {
78
+ color: var(--textTitle);
79
+ font-size: var(--fontSizeBodyS);
80
+ font-weight: var(--fontWeightMedium);
81
+ }
82
+
83
+ .controlGroup select {
84
+ width: 100%;
85
+ border: 1px solid color-mix(in lab, var(--text) 15%, transparent);
86
+ border-radius: var(--spaceXS);
87
+ background: var(--backgroundLight);
88
+ color: var(--textBody);
89
+ padding: var(--spaceS) var(--spaceM);
90
+ font-size: var(--fontSizeBodyS);
91
+ }
92
+
93
+ .controlGroup select:focus {
94
+ outline: 2px solid color-mix(in lab, var(--primary) 30%, transparent);
95
+ outline-offset: 1px;
96
+ }
97
+
98
+ .resetButton {
99
+ border: 1px solid color-mix(in lab, var(--text) 15%, transparent);
100
+ border-radius: var(--spaceXS);
101
+ background: var(--backgroundLight);
102
+ color: var(--textBody);
103
+ padding: var(--spaceS) var(--spaceM);
104
+ font-size: var(--fontSizeBodyS);
105
+ cursor: pointer;
106
+ }
107
+
108
+ .resetButton:disabled {
109
+ cursor: not-allowed;
110
+ opacity: 0.5;
111
+ }
112
+
113
+ .searchSection {
114
+ display: flex;
115
+ flex-direction: column;
116
+ gap: var(--spaceXS);
117
+ }
118
+
119
+ .searchSection label {
120
+ color: var(--textTitle);
121
+ font-size: var(--fontSizeBodyS);
122
+ font-weight: var(--fontWeightMedium);
123
+ }
124
+
125
+ .searchInput {
126
+ width: 100%;
127
+ border: 1px solid color-mix(in lab, var(--text) 15%, transparent);
128
+ border-radius: var(--spaceXS);
129
+ background: var(--backgroundLight);
130
+ color: var(--textBody);
131
+ padding: var(--spaceS) var(--spaceM);
132
+ font-size: var(--fontSizeBodyS);
133
+ }
134
+
135
+ .searchInput:focus {
136
+ outline: 2px solid color-mix(in lab, var(--primary) 30%, transparent);
137
+ outline-offset: 1px;
138
+ }
139
+
140
+ .fileCount {
141
+ margin: 0;
142
+ font-size: var(--fontSizeBodyS);
143
+ color: var(--textLight);
144
+ }
145
+
146
+ .actionNotice {
147
+ margin: 0;
148
+ border-radius: var(--spaceXS);
149
+ padding: var(--spaceS) var(--spaceM);
150
+ font-size: var(--fontSizeBodyS);
151
+ border: 1px solid transparent;
152
+ }
153
+
154
+ .actionNoticeSuccess {
155
+ background: color-mix(in lab, var(--success) 15%, var(--backgroundLight));
156
+ color: var(--textBody);
157
+ border-color: color-mix(in lab, var(--success) 35%, transparent);
158
+ }
159
+
160
+ .actionNoticeWarning {
161
+ background: color-mix(in lab, var(--warning) 18%, var(--backgroundLight));
162
+ color: var(--textBody);
163
+ border-color: color-mix(in lab, var(--warning) 40%, transparent);
164
+ }
165
+
166
+ .actionNoticeError {
167
+ background: color-mix(in lab, var(--error) 16%, var(--backgroundLight));
168
+ color: var(--error);
169
+ border-color: color-mix(in lab, var(--error) 30%, transparent);
170
+ }
171
+
60
172
  .filesList {
61
173
  list-style: none;
62
174
  padding: 0;
@@ -67,36 +179,70 @@
67
179
  }
68
180
 
69
181
  .fileItem {
70
- display: flex;
71
- justify-content: space-between;
72
- align-items: center;
73
- padding: var(--spaceM) var(--spaceL);
74
- border: 1px solid #e9ecef;
182
+ width: 100%;
183
+ padding: var(--spaceM);
184
+ border: 1px solid color-mix(in lab, var(--text) 15%, transparent);
75
185
  border-radius: var(--spaceXS);
186
+ display: grid;
187
+ grid-template-columns: auto 1fr auto;
188
+ align-items: center;
189
+ gap: var(--spaceM);
76
190
  background: var(--backgroundLight);
77
191
  cursor: pointer;
78
- transition: all var(--durationS) var(--bezierFastoutSlowin);
192
+ color: var(--textBody);
193
+ transition:
194
+ border-color var(--durationS) var(--bezierFastoutSlowin),
195
+ background-color var(--durationS) var(--bezierFastoutSlowin),
196
+ box-shadow var(--durationS) var(--bezierFastoutSlowin);
79
197
  }
80
198
 
81
199
  .fileItem:hover {
82
200
  background-color: color-mix(in lab, var(--background) 95%, transparent);
83
201
  }
84
202
 
203
+ .fileItem:focus {
204
+ outline: none;
205
+ border-color: color-mix(in lab, var(--primary) 60%, transparent);
206
+ box-shadow: 0 0 0 2px color-mix(in lab, var(--primary) 18%, transparent);
207
+ }
208
+
85
209
  .fileItem.active {
86
- background-color: color-mix(in lab, var(--background) 90%, transparent);
87
- font-weight: var(--fontWeightMedium);
210
+ border-color: color-mix(in lab, var(--primary) 55%, transparent);
211
+ box-shadow:
212
+ inset 4px 0 0 color-mix(in lab, var(--primary) 55%, transparent),
213
+ 0 0 0 1px color-mix(in lab, var(--primary) 16%, transparent);
214
+ }
215
+
216
+ .deleteSelector {
217
+ margin: 0;
218
+ width: var(--spaceL);
219
+ height: var(--spaceL);
220
+ cursor: pointer;
221
+ }
222
+
223
+ .deleteSelector {
224
+ accent-color: var(--error);
88
225
  }
89
226
 
90
227
  .fileInfo {
91
- flex: 1;
92
- min-width: 0; /* Allow text truncation */
228
+ min-width: 0;
229
+ display: flex;
230
+ flex-direction: column;
231
+ gap: var(--spaceXS);
93
232
  }
94
233
 
95
234
  .fileName {
96
235
  font-weight: var(--fontWeightMedium);
97
236
  color: var(--textBody);
98
- margin-bottom: var(--spaceXS);
99
- word-break: break-word;
237
+ overflow: hidden;
238
+ text-overflow: ellipsis;
239
+ white-space: nowrap;
240
+ }
241
+
242
+ .fileMetaRow {
243
+ display: flex;
244
+ gap: var(--spaceM);
245
+ flex-wrap: wrap;
100
246
  }
101
247
 
102
248
  .fileDate {
@@ -104,53 +250,98 @@
104
250
  color: var(--textLight);
105
251
  }
106
252
 
107
- .deleteButton {
108
- background: none;
109
- border: none;
110
- color: #dc3545;
111
- font-size: 1.2rem;
112
- cursor: pointer;
113
- padding: 0.5rem;
253
+ .classTypeBadge {
114
254
  border-radius: var(--spaceXS);
115
- margin-left: var(--spaceM);
116
- transition: all var(--durationS) var(--bezierFastoutSlowin);
117
- flex-shrink: 0;
255
+ border: 1px solid color-mix(in lab, var(--text) 14%, transparent);
256
+ padding: 0.1rem 0.45rem;
257
+ font-size: var(--fontSizeBodyS);
258
+ color: var(--textBody);
259
+ background: color-mix(in lab, var(--background) 94%, transparent);
260
+ }
261
+
262
+ .confirmationBadge {
263
+ justify-self: end;
264
+ border-radius: var(--spaceXS);
265
+ padding: var(--spaceXS) var(--spaceS);
266
+ font-size: var(--fontSizeBodyS);
267
+ font-weight: var(--fontWeightMedium);
268
+ color: var(--textBody);
269
+ border: 1px solid color-mix(in lab, var(--text) 15%, transparent);
270
+ white-space: nowrap;
271
+ }
272
+
273
+ .footerActions {
118
274
  display: flex;
275
+ justify-content: space-between;
119
276
  align-items: center;
120
- justify-content: center;
121
- min-width: 32px;
122
- height: 32px;
277
+ gap: var(--spaceM);
278
+ padding: var(--spaceL);
279
+ border-top: 1px solid color-mix(in lab, var(--text) 10%, transparent);
280
+ background: var(--backgroundLight);
281
+ flex-shrink: 0;
123
282
  }
124
283
 
125
- .deleteButton:hover:not(:disabled) {
126
- color: #bd2130;
127
- background-color: rgba(220, 53, 69, 0.1);
284
+ .maintenanceActions {
285
+ display: flex;
286
+ flex-wrap: wrap;
287
+ gap: var(--spaceS);
128
288
  }
129
289
 
130
- .deleteButton:disabled {
131
- opacity: 0.5;
132
- cursor: not-allowed;
290
+ .secondaryActionButton {
291
+ border: 1px solid color-mix(in lab, var(--text) 15%, transparent);
292
+ border-radius: var(--spaceXS);
293
+ background: var(--backgroundLight);
294
+ color: var(--textBody);
295
+ padding: var(--spaceS) var(--spaceM);
296
+ font-size: var(--fontSizeBodyS);
297
+ cursor: pointer;
298
+ transition: background-color var(--durationS) var(--bezierFastoutSlowin);
133
299
  }
134
300
 
135
- .errorState,
136
- .emptyState {
137
- text-align: center;
138
- padding: var(--space2XL);
139
- color: var(--textLight);
301
+ .secondaryActionButton:hover:not(:disabled) {
302
+ background: color-mix(in lab, var(--background) 94%, transparent);
140
303
  }
141
304
 
142
- .errorState {
305
+ .secondaryActionButton:disabled {
306
+ cursor: not-allowed;
307
+ opacity: 0.5;
308
+ }
309
+
310
+ .deleteActionButton {
311
+ border-color: color-mix(in lab, var(--error) 25%, transparent);
143
312
  color: var(--error);
144
313
  }
145
314
 
315
+ .deleteActionButton:hover:not(:disabled) {
316
+ background: color-mix(in lab, var(--error) 12%, var(--backgroundLight));
317
+ }
318
+
319
+ .openSelectedButton {
320
+ background: var(--primary);
321
+ color: var(--white);
322
+ border: none;
323
+ border-radius: var(--spaceXS);
324
+ padding: var(--spaceS) var(--spaceL);
325
+ font-size: var(--fontSizeBodyS);
326
+ cursor: pointer;
327
+ transition: background-color var(--durationS) var(--bezierFastoutSlowin);
328
+ }
329
+
330
+ .openSelectedButton:hover:not(:disabled) {
331
+ background: color-mix(in lab, var(--primary) 85%, var(--black));
332
+ }
333
+
334
+ .openSelectedButton:disabled {
335
+ background: color-mix(in lab, var(--text) 20%, transparent);
336
+ color: var(--textLight);
337
+ cursor: not-allowed;
338
+ }
339
+
146
340
  .pagination {
147
341
  display: flex;
148
- justify-content: space-between;
342
+ justify-content: flex-end;
149
343
  align-items: center;
150
- padding: var(--spaceL);
151
- border-top: 1px solid color-mix(in lab, var(--text) 10%, transparent);
152
- background: var(--backgroundLight);
153
- flex-shrink: 0;
344
+ gap: var(--spaceM);
154
345
  }
155
346
 
156
347
  .pagination button {
@@ -179,7 +370,13 @@
179
370
  color: var(--textBody);
180
371
  font-weight: var(--fontWeightMedium);
181
372
  }
182
- /* Confirmation Status Indicators */
373
+
374
+ .emptyState {
375
+ text-align: center;
376
+ padding: var(--spaceXL);
377
+ color: var(--textLight);
378
+ }
379
+
183
380
  .fileItemNotConfirmed {
184
381
  background-color: color-mix(
185
382
  in lab,
@@ -212,6 +409,14 @@
212
409
  );
213
410
  }
214
411
 
412
+ .confirmationBadge.fileItemNotConfirmed {
413
+ background-color: color-mix(
414
+ in lab,
415
+ var(--warning) 22%,
416
+ var(--backgroundLight)
417
+ );
418
+ }
419
+
215
420
  .fileItemConfirmed {
216
421
  background-color: color-mix(
217
422
  in lab,
@@ -243,3 +448,39 @@
243
448
  var(--backgroundLight)
244
449
  );
245
450
  }
451
+
452
+ .confirmationBadge.fileItemConfirmed {
453
+ background-color: color-mix(
454
+ in lab,
455
+ var(--success) 28%,
456
+ var(--backgroundLight)
457
+ );
458
+ }
459
+
460
+ @media (max-width: 980px) {
461
+ .controlsSection {
462
+ grid-template-columns: repeat(2, minmax(0, 1fr));
463
+ }
464
+
465
+ .fileItem {
466
+ grid-template-columns: auto 1fr;
467
+ }
468
+
469
+ .confirmationBadge {
470
+ grid-column: 1 / -1;
471
+ justify-self: start;
472
+ }
473
+
474
+ .footerActions {
475
+ flex-direction: column;
476
+ align-items: stretch;
477
+ }
478
+
479
+ .maintenanceActions {
480
+ width: 100%;
481
+ }
482
+
483
+ .pagination {
484
+ justify-content: space-between;
485
+ }
486
+ }