@testgorilla/tgo-immersive-test 0.0.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 (37) hide show
  1. package/.eslintrc.json +46 -0
  2. package/README.md +89 -0
  3. package/jest.config.ts +28 -0
  4. package/ng-package.json +16 -0
  5. package/package.json +25 -0
  6. package/project.json +37 -0
  7. package/src/assets/i18n/en.json +18 -0
  8. package/src/index.ts +4 -0
  9. package/src/lib/components/immersive-test/immersive-test.component.html +100 -0
  10. package/src/lib/components/immersive-test/immersive-test.component.scss +247 -0
  11. package/src/lib/components/immersive-test/immersive-test.component.spec.ts +581 -0
  12. package/src/lib/components/immersive-test/immersive-test.component.ts +279 -0
  13. package/src/lib/components/index.ts +6 -0
  14. package/src/lib/components/review-instructions-dialog/index.ts +1 -0
  15. package/src/lib/components/review-instructions-dialog/review-instructions-dialog.component.html +39 -0
  16. package/src/lib/components/review-instructions-dialog/review-instructions-dialog.component.scss +160 -0
  17. package/src/lib/components/review-instructions-dialog/review-instructions-dialog.component.spec.ts +81 -0
  18. package/src/lib/components/review-instructions-dialog/review-instructions-dialog.component.ts +80 -0
  19. package/src/lib/components/ringing-phone-animation/index.ts +1 -0
  20. package/src/lib/components/ringing-phone-animation/ringing-phone-animation.component.html +16 -0
  21. package/src/lib/components/ringing-phone-animation/ringing-phone-animation.component.scss +79 -0
  22. package/src/lib/components/ringing-phone-animation/ringing-phone-animation.component.spec.ts +95 -0
  23. package/src/lib/components/ringing-phone-animation/ringing-phone-animation.component.ts +54 -0
  24. package/src/lib/components/ringing-phone-animation/ringing-phone-animation.sound.ts +2 -0
  25. package/src/lib/components/video-countdown/index.ts +1 -0
  26. package/src/lib/components/video-countdown/video-countdown.component.html +10 -0
  27. package/src/lib/components/video-countdown/video-countdown.component.scss +16 -0
  28. package/src/lib/components/video-countdown/video-countdown.component.spec.ts +59 -0
  29. package/src/lib/components/video-countdown/video-countdown.component.ts +102 -0
  30. package/src/lib/models/index.ts +9 -0
  31. package/src/lib/models/translations.ts +3 -0
  32. package/src/lib/services/index.ts +7 -0
  33. package/src/test-setup.ts +22 -0
  34. package/tsconfig.json +17 -0
  35. package/tsconfig.lib.json +15 -0
  36. package/tsconfig.lib.prod.json +10 -0
  37. package/tsconfig.spec.json +13 -0
package/.eslintrc.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "extends": ["../../.eslintrc.json"],
3
+ "ignorePatterns": ["!**/*"],
4
+ "overrides": [
5
+ {
6
+ "files": ["*.ts"],
7
+ "extends": ["plugin:@nx/angular", "plugin:@angular-eslint/template/process-inline-templates"],
8
+ "rules": {
9
+ "@angular-eslint/directive-selector": [
10
+ "error",
11
+ {
12
+ "type": "attribute",
13
+ "prefix": "tgo",
14
+ "style": "camelCase"
15
+ }
16
+ ],
17
+ "@angular-eslint/component-selector": [
18
+ "error",
19
+ {
20
+ "type": "element",
21
+ "prefix": "tgo",
22
+ "style": "kebab-case"
23
+ }
24
+ ]
25
+ }
26
+ },
27
+ {
28
+ "files": ["*.html"],
29
+ "extends": ["plugin:@nx/angular-template"],
30
+ "rules": {}
31
+ },
32
+ {
33
+ "files": ["*.json"],
34
+ "parser": "jsonc-eslint-parser",
35
+ "rules": {
36
+ "@nx/dependency-checks": [
37
+ "error",
38
+ {
39
+ "ignoredFiles": ["{projectRoot}/eslint.config.{js,cjs,mjs}"],
40
+ "ignoredDependencies": ["@vimeo/player"]
41
+ }
42
+ ]
43
+ }
44
+ }
45
+ ]
46
+ }
package/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # @testgorilla/tgo-immersive-test
2
+
3
+ Immersive Test component for TestGorilla assessments.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @testgorilla/tgo-immersive-test
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```typescript
14
+ import { ImmersiveTestComponent } from '@testgorilla/tgo-immersive-test';
15
+
16
+ @Component({
17
+ imports: [ImmersiveTestComponent],
18
+ template: `
19
+ <tgo-immersive-test
20
+ [question]="question"
21
+ [test]="test"
22
+ [isFirstQuestion]="false"
23
+ [expirationObservable]="expirationObservable"
24
+ [selectedMediaDevices]="selectedMediaDevices"
25
+ [mediaAccessChanged]="mediaAccessChanged"
26
+ (submissionStateChanged)="onSubmissionStateChanged($event)"
27
+ (loadingStateChanged)="onLoadingStateChanged($event)"
28
+ (requestMediaAccess)="onRequestMediaAccess()"
29
+ ></tgo-immersive-test>
30
+ `,
31
+ })
32
+ export class MyComponent {}
33
+ ```
34
+
35
+ ## API
36
+
37
+ ### Inputs
38
+
39
+ | Name | Type | Required | Default | Description |
40
+ | -------------------- | ---------------------------------- | -------- | ------- | ------------------------------------------------ |
41
+ | question | Question | Yes | - | Question data containing text/media content |
42
+ | test | TestResultRead | Yes | - | Test configuration and metadata |
43
+ | isFirstQuestion | boolean | No | false | Whether this is the first question in the test |
44
+ | expirationObservable | Observable\<void\> | No | - | Observable to trigger test expiration externally |
45
+ | selectedMediaDevices | SelectedMediaDevices | No | - | Selected audio/video device IDs |
46
+ | mediaAccessChanged | Observable\<SelectedMediaDevices\> | No | - | Observable for media device changes |
47
+
48
+ ### Outputs
49
+
50
+ | Name | Type | Description |
51
+ | ---------------------- | ---------------------------------------- | ----------------------------------------------- |
52
+ | submissionStateChanged | EventEmitter\<ISubmissionState \| null\> | Emits submission state when answer is submitted |
53
+ | loadingStateChanged | EventEmitter\<boolean\> | Emits loading state changes |
54
+ | requestMediaAccess | EventEmitter\<void\> | Emits when media access permission is needed |
55
+
56
+ ## Peer Dependencies
57
+
58
+ This library requires the following peer dependencies:
59
+
60
+ - `@angular/common` ~18.2.13
61
+ - `@angular/core` ~18.2.13
62
+ - `@angular/animations` ~18.2.13
63
+ - `@angular/material` ~18.2.14 (for dialog support)
64
+ - `@ngneat/transloco` ~4.3.0
65
+ - `@testgorilla/tgo-ui` ~3.14.10
66
+ - `@vimeo/player` ^2.25.1
67
+ - `ngx-quill` ^26.0.10 (for rich text display in review instructions)
68
+ - `rxjs` ~7.8.1
69
+
70
+ ## Internal Dependencies
71
+
72
+ All required services, models, and components are included within this library:
73
+
74
+ - `MediaService` - Handles audio/video recording and playback
75
+ - `ThemeService` - Provides theme/company color configuration
76
+ - `Question`, `TestResultRead`, `SelectedMediaDevices`, `ISubmissionState` - Type definitions
77
+ - `AudioAnimationComponent`, `RingingPhoneAnimationComponent`, `VideoCountdownComponent`, `VimeoVideoComponent` - UI components
78
+ - `ReviewInstructionsDialogComponent` - Dialog component for review instructions
79
+ - `TranslocoLazyModuleUtils`, `getAvailableLangs` - Translation utilities
80
+
81
+ ## Features
82
+
83
+ - Audio and video question playback
84
+ - Candidate video recording
85
+ - Audio answer recording
86
+ - Media device selection
87
+ - Translation support via Transloco
88
+ - Review instructions dialog
89
+ - Preview mode support
package/jest.config.ts ADDED
@@ -0,0 +1,28 @@
1
+ export default {
2
+ displayName: 'tgo-immersive-test',
3
+ preset: '../../jest.preset.js',
4
+ setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
5
+ coverageDirectory: '../../coverage/packages/tgo-immersive-test',
6
+ testMatch: ['**/__tests__/**/*.[jt]s?(x)', '**/*.spec.[jt]s?(x)'],
7
+ testPathIgnorePatterns: ['/node_modules/', '/src/lib/models/'],
8
+ moduleNameMapper: {
9
+ '^@testgorilla/tgo-ui$': '<rootDir>/../tgo-test-shared/src/test-mocks/tgo-ui.mock.ts',
10
+ },
11
+ transform: {
12
+ '^.+\\.(ts|mjs|js|html)$': [
13
+ 'jest-preset-angular',
14
+ {
15
+ tsconfig: '<rootDir>/tsconfig.spec.json',
16
+ stringifyContentPathRegex: '\\.(html|svg)$',
17
+ },
18
+ ],
19
+ },
20
+ transformIgnorePatterns: [
21
+ 'node_modules/(?!.*\\.mjs$|lodash-es|@testgorilla|ng2-charts|chart\\.js|chartjs-plugin-datalabels)',
22
+ ],
23
+ snapshotSerializers: [
24
+ 'jest-preset-angular/build/serializers/no-ng-attributes',
25
+ 'jest-preset-angular/build/serializers/ng-snapshot',
26
+ 'jest-preset-angular/build/serializers/html-comment',
27
+ ],
28
+ };
@@ -0,0 +1,16 @@
1
+ {
2
+ "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
3
+ "dest": "../../dist/packages/tgo-immersive-test",
4
+ "assets": [
5
+ {
6
+ "glob": "**/*",
7
+ "input": "./src/assets",
8
+ "output": "./assets"
9
+ }
10
+ ],
11
+ "lib": {
12
+ "entryFile": "./src/index.ts"
13
+ },
14
+ "allowedNonPeerDependencies": []
15
+ }
16
+
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "@testgorilla/tgo-immersive-test",
3
+ "version": "0.0.1",
4
+ "peerDependencies": {
5
+ "@angular/common": "~18.2.13",
6
+ "@angular/core": "~18.2.13",
7
+ "@angular/animations": "~18.2.13",
8
+ "@angular/material": "~18.2.14",
9
+ "@ngneat/transloco": "~4.3.0",
10
+ "@testgorilla/tgo-ui": "~3.14.10",
11
+ "@testgorilla/tgo-test-shared": "~0.0.1",
12
+ "jest-preset-angular": "~14.2.4",
13
+ "ngx-quill": "^26.0.10",
14
+ "rxjs": "~7.8.1"
15
+ },
16
+ "typings": "src/lib/types",
17
+ "sideEffects": false,
18
+ "license": "PROPRIETARY",
19
+ "publishConfig": {
20
+ "access": "restricted",
21
+ "registry": "https://registry.npmjs.org/"
22
+ },
23
+ "displayName": "Immersive Test",
24
+ "description": "Immersive Test component"
25
+ }
package/project.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "tgo-immersive-test",
3
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
4
+ "sourceRoot": "packages/tgo-immersive-test/src",
5
+ "prefix": "tgo",
6
+ "projectType": "library",
7
+ "tags": [],
8
+ "targets": {
9
+ "build": {
10
+ "executor": "@nx/angular:package",
11
+ "outputs": ["{workspaceRoot}/dist/{projectRoot}"],
12
+ "options": {
13
+ "project": "packages/tgo-immersive-test/ng-package.json"
14
+ },
15
+ "configurations": {
16
+ "production": {
17
+ "tsConfig": "packages/tgo-immersive-test/tsconfig.lib.prod.json"
18
+ },
19
+ "development": {
20
+ "tsConfig": "packages/tgo-immersive-test/tsconfig.lib.json"
21
+ }
22
+ },
23
+ "defaultConfiguration": "production"
24
+ },
25
+ "test": {
26
+ "executor": "@nx/jest:jest",
27
+ "outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
28
+ "options": {
29
+ "jestConfig": "packages/tgo-immersive-test/jest.config.ts"
30
+ }
31
+ },
32
+ "lint": {
33
+ "executor": "@nx/eslint:lint"
34
+ }
35
+ }
36
+ }
37
+
@@ -0,0 +1,18 @@
1
+ {
2
+ "TEST": {
3
+ "YOU": "You",
4
+ "RECORDING_STARTED": "Recording started",
5
+ "ANSWER_THE_QUESTION": "Answer the customer's question, then submit.",
6
+ "ANSWER_COMPLETED": "Submit answer",
7
+ "ANSWER": "Answer",
8
+ "CUSTOMER": "Customer",
9
+ "AUDIO_READY": "Your audio file is ready.",
10
+ "AUDIO_PREVIEW": "Audio is only available during practice questions.",
11
+ "REVIEW_INSTRUCTIONS": "Review Instructions",
12
+ "GET_READY": "Get ready to answer the customer's question."
13
+ },
14
+ "INSTRUCTIONS_MODAL": {
15
+ "TITLE": "Review Instructions",
16
+ "CLOSE": "Close"
17
+ }
18
+ }
package/src/index.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from './lib/components';
2
+ export * from './lib/components/immersive-test/immersive-test.component';
3
+ export * from './lib/models';
4
+ export * from './lib/services';
@@ -0,0 +1,100 @@
1
+ <div class="immersive-test">
2
+ <div class="test-container">
3
+ <div
4
+ class="media-container"
5
+ [class.is-video-visible]="isQuestionPlaying() && !isAnswering()"
6
+ [class.is-playing]="isVideoPlaying()"
7
+ [class.is-answering]="isAnswering()"
8
+ >
9
+ <div class="candidate-no-camera" *ngIf="!candidateVideoStreamReady()">
10
+ <h3>&nbsp;</h3>
11
+ <tgo-audio-animation
12
+ *ngIf="isAnswering()"
13
+ [volume]="volume()"
14
+ [fakeData]="false"
15
+ ></tgo-audio-animation>
16
+ <ui-icon name="User-profile-in-line" color="white" size="24"></ui-icon>
17
+ <h3 class="bold">{{ translations['YOU'] }}</h3>
18
+ </div>
19
+ <div class="candidate-camera" [hidden]="!candidateVideoStreamReady()">
20
+ <tgo-audio-animation
21
+ *ngIf="isAnswering() && candidateVideoStreamReady()"
22
+ [volume]="volume()"
23
+ [fakeData]="false"
24
+ ></tgo-audio-animation>
25
+ <video height #video id="video" playsinline (loadedmetadata)="onVideoLoad()"></video>
26
+ <h3 class="bold" *ngIf="candidateVideoStreamReady()">
27
+ {{ translations['YOU'] }}
28
+ </h3>
29
+ </div>
30
+ <tgo-audio-animation *ngIf="isVideoPlaying()" [fakeData]="true"></tgo-audio-animation>
31
+ <tgo-vimeo-video
32
+ *ngIf="isVideo"
33
+ [isPlaying]="isQuestionPlaying()"
34
+ [videoUrl]="fileUrl"
35
+ (videoEnded)="startCountdown()"
36
+ (videoStarted)="isVideoPlaying.set(true)"
37
+ ></tgo-vimeo-video>
38
+ <div class="audio-info" *ngIf="isQuestionPlaying() && !isVideo">
39
+ <ui-icon name="User-profile-filled" color="white" size="80"></ui-icon>
40
+ </div>
41
+ <div class="start" *ngIf="isFirstQuestion && !isQuestionPlaying()">
42
+ <tgo-ringing-phone-animation [isRinging]="true"></tgo-ringing-phone-animation>
43
+ <ui-button
44
+ [label]="translations['ANSWER']"
45
+ [class.white-btn]="test.is_preview_mode"
46
+ variant="primary"
47
+ [companyColor]="companyColor"
48
+ (click)="startQuestion()"
49
+ data-testid="immersive-test.start-question-btn"
50
+ ></ui-button>
51
+ </div>
52
+ <div class="overlay" *ngIf="isAnswering() || isCountingDown()" [@fadeInFadeOut]>
53
+ <div class="answer" *ngIf="!audioUrl() && isAnswering()">
54
+ <div>
55
+ <h3 class="uppercase recording-started">
56
+ <span class="recording-dot"></span>{{ translations['RECORDING_STARTED'] }}
57
+ </h3>
58
+ <h1 class="bold">
59
+ {{ translations['ANSWER_THE_QUESTION'] }}
60
+ </h1>
61
+ </div>
62
+ <ui-button
63
+ [label]="translations['ANSWER_COMPLETED']"
64
+ [class.white-btn]="test.is_preview_mode"
65
+ variant="primary"
66
+ [companyColor]="companyColor"
67
+ (click)="stopRecording()"
68
+ data-testid="immersive-test.stop-recording-btn"
69
+ ></ui-button>
70
+ </div>
71
+ <div class="answer" *ngIf="isCountingDown()">
72
+ <div>
73
+ <h1 class="bold">
74
+ {{ translations['GET_READY'] }}
75
+ </h1>
76
+ </div>
77
+ <tgo-video-countdown (finish)="startRecordAnswer()"></tgo-video-countdown>
78
+ <div>&nbsp;</div>
79
+ </div>
80
+ <div class="preview" [class.hidden]="!audioUrl()" *ngIf="test.is_preview_mode">
81
+ <h4>{{ translations['AUDIO_READY'] }}</h4>
82
+ <p>{{ translations['AUDIO_PREVIEW'] }}</p>
83
+ <audio #audio controls></audio>
84
+ </div>
85
+ </div>
86
+ </div>
87
+ <div class="media-info">
88
+ <h3 class="bold">{{ translations['CUSTOMER'] }}</h3>
89
+ <ui-button
90
+ [hidden]="!test.test_instruction && !test.intro_text"
91
+ class="review-button"
92
+ [label]="translations['REVIEW_INSTRUCTIONS']"
93
+ variant="secondary"
94
+ size="small"
95
+ (click)="openReviewInstructionsDialog()"
96
+ data-testid="immersive-test.review-instructions-btn"
97
+ ></ui-button>
98
+ </div>
99
+ </div>
100
+ </div>
@@ -0,0 +1,247 @@
1
+ @import '@testgorilla/tgo-ui/projects/tgo-canopy-ui/theme/variables';
2
+
3
+ $border-radius: 10px;
4
+
5
+ .immersive-test {
6
+ padding: 0 64px;
7
+ margin-top: 40px;
8
+
9
+ .media-info {
10
+ width: 100%;
11
+ display: flex;
12
+ justify-content: space-between;
13
+ align-items: center;
14
+ background: rgba(36, 36, 36, 0.66);
15
+ background-color: $black;
16
+ border-bottom-left-radius: $border-radius;
17
+ border-bottom-right-radius: $border-radius;
18
+ padding: 13px 32px;
19
+ color: $tgo-white;
20
+
21
+ ::ng-deep ui-button button {
22
+ border-color: $tgo-white;
23
+ color: $tgo-white;
24
+ }
25
+ }
26
+
27
+ .test-container {
28
+ min-width: 360px;
29
+ max-width: 1312px;
30
+ min-height: 725px;
31
+ height: min(
32
+ 725px,
33
+ 100%,
34
+ max(calc(100vw - 200px), calc(100vh - 200px), 200px)
35
+ );
36
+ border-radius: $border-radius;
37
+ display: flex;
38
+ flex-direction: column;
39
+ justify-content: space-between;
40
+ position: relative;
41
+ background-color: $black;
42
+ }
43
+
44
+ .media-container {
45
+ position: relative;
46
+ color: $tgo-white;
47
+ flex-grow: 1;
48
+ border-top-left-radius: $border-radius;
49
+ border-top-right-radius: $border-radius;
50
+ aspect-ratio: 16 / 9;
51
+
52
+ .candidate-no-camera {
53
+ position: absolute;
54
+ width: 200px;
55
+ aspect-ratio: 16 / 9;
56
+ z-index: 3;
57
+ top: 32px;
58
+ left: 32px;
59
+ border-radius: $border-radius;
60
+ background-color: #1a47aa;
61
+ display: flex;
62
+ justify-content: space-between;
63
+ flex-direction: column;
64
+ padding: 16px;
65
+
66
+ ui-icon {
67
+ margin: auto;
68
+ }
69
+ }
70
+
71
+ .candidate-camera {
72
+ position: absolute;
73
+ width: 200px;
74
+ top: 32px;
75
+ left: 32px;
76
+ z-index: 3;
77
+
78
+ video {
79
+ width: 200px;
80
+ border-radius: $border-radius;
81
+ }
82
+
83
+ h3 {
84
+ position: absolute;
85
+ bottom: 16px;
86
+ left: 16px;
87
+ }
88
+ }
89
+
90
+ tgo-audio-animation {
91
+ position: absolute;
92
+ top: 32px;
93
+ right: 32px;
94
+ z-index: 1;
95
+ }
96
+
97
+ tgo-vimeo-video {
98
+ display: none;
99
+ position: absolute;
100
+ height: 100%;
101
+ width: 100%;
102
+ }
103
+
104
+ &.is-video-visible {
105
+ tgo-vimeo-video {
106
+ display: block;
107
+ }
108
+ }
109
+
110
+ &.is-playing {
111
+ border: 4px solid $informative-40;
112
+ border-bottom-width: 3px;
113
+ }
114
+
115
+ &.is-answering {
116
+ .candidate-camera,
117
+ .candidate-no-camera {
118
+ tgo-audio-animation {
119
+ position: absolute;
120
+ top: 16px;
121
+ right: 16px;
122
+ }
123
+ }
124
+
125
+ .candidate-camera video,
126
+ .candidate-no-camera {
127
+ border: 3px solid $informative-40;
128
+ border-radius: $border-radius;
129
+ }
130
+
131
+ tgo-vimeo-video {
132
+ display: block;
133
+ }
134
+ }
135
+
136
+ .start,
137
+ .audio-info,
138
+ .overlay,
139
+ .answer {
140
+ display: flex;
141
+ justify-content: center;
142
+ align-items: center;
143
+ flex-direction: column;
144
+ gap: 40px;
145
+ height: 100%;
146
+ }
147
+
148
+ .preview {
149
+ height: 100%;
150
+ display: flex;
151
+ align-items: center;
152
+ flex-direction: column;
153
+ justify-content: flex-end;
154
+ padding: 24px;
155
+
156
+ p {
157
+ color: $grayscale-30;
158
+ margin: 8px 0;
159
+ }
160
+
161
+ audio {
162
+ margin: 16px 0;
163
+ }
164
+
165
+ &.hidden {
166
+ display: none;
167
+ }
168
+ }
169
+ }
170
+
171
+ h3,
172
+ h4 {
173
+ color: $tgo-white;
174
+ }
175
+
176
+ .bold {
177
+ font-weight: 700;
178
+ }
179
+
180
+ ui-button.review-button ::ng-deep button {
181
+ border: 1px solid $tgo-white;
182
+ }
183
+
184
+ ui-button.white-btn ::ng-deep button {
185
+ background-color: $tgo-white;
186
+ border-color: $tgo-white;
187
+ color: $tgo-black;
188
+
189
+ &:hover {
190
+ background-color: $grayscale-50 !important;
191
+ }
192
+ }
193
+
194
+ .overlay {
195
+ top: 0;
196
+ position: absolute;
197
+ width: 100%;
198
+ height: 100%;
199
+ background-color: rgb(36 36 36 / 88%);
200
+ z-index: 2;
201
+ border-radius: $border-radius;
202
+
203
+ h1,
204
+ h3 {
205
+ color: $tgo-white;
206
+ text-align: center;
207
+ }
208
+
209
+ h3 {
210
+ margin-bottom: 10px;
211
+ }
212
+ }
213
+
214
+ tgo-radial-progress {
215
+ position: absolute;
216
+ top: 50%;
217
+ left: 50%;
218
+ transform: translate(-50%, -50%);
219
+ }
220
+
221
+ .uppercase {
222
+ text-transform: uppercase;
223
+ }
224
+
225
+ .recording-started {
226
+ display: flex;
227
+ align-items: center;
228
+ justify-content: center;
229
+ gap: 10px;
230
+ }
231
+
232
+ .recording-dot {
233
+ background-color: $error-40;
234
+ display: inline-block;
235
+ width: 20px;
236
+ height: 20px;
237
+ border-radius: 50%;
238
+ }
239
+ }
240
+
241
+ @media screen and (max-width: 600px) {
242
+ .immersive-test {
243
+ padding: 0 24px;
244
+ margin-top: 16px;
245
+ }
246
+ }
247
+