@olares/lares-mobile 0.15.5 → 0.15.7

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 (44) hide show
  1. package/README.md +6 -2
  2. package/package.json +2 -2
  3. package/src/App.vue +918 -178
  4. package/src/chat/ChatBar.vue +2 -2
  5. package/src/chat/Composer.vue +467 -16
  6. package/src/chat/Deliverables.vue +22 -10
  7. package/src/chat/HistoryPanel.vue +747 -55
  8. package/src/chat/MessageActions.vue +88 -34
  9. package/src/chat/QuestionCard.vue +5 -5
  10. package/src/chat/StageRow.vue +8 -5
  11. package/src/chat/Transcript.vue +20 -6
  12. package/src/chat/composer-tokens.js +32 -0
  13. package/src/chat/format.js +37 -0
  14. package/src/desktop/DesktopComposer.vue +942 -0
  15. package/src/desktop/DesktopContextMeter.vue +81 -0
  16. package/src/desktop/DesktopGoal.vue +88 -0
  17. package/src/desktop/DesktopPreview.vue +58 -0
  18. package/src/desktop/DesktopPreviewTabs.vue +82 -0
  19. package/src/desktop/DesktopQuestions.vue +118 -0
  20. package/src/desktop/DesktopQueue.vue +203 -0
  21. package/src/desktop/DesktopShell.vue +229 -0
  22. package/src/desktop/DesktopSidebar.vue +645 -0
  23. package/src/desktop/DesktopTodos.vue +52 -0
  24. package/src/desktop/DirectoryBrowser.vue +231 -0
  25. package/src/desktop/DirectoryNewFolder.vue +124 -0
  26. package/src/desktop/ui/PcDialog.vue +100 -0
  27. package/src/desktop/ui/PcPopover.vue +110 -0
  28. package/src/desktop/ui/PcTooltip.vue +95 -0
  29. package/src/desktop/ui/place.js +24 -0
  30. package/src/desktop/workspace-view.js +121 -0
  31. package/src/host.js +20 -2
  32. package/src/index.d.ts +2 -0
  33. package/src/mobile/MobileDirectoryNewFolder.vue +121 -0
  34. package/src/mobile/MobileDirectorySheet.vue +162 -0
  35. package/src/mobile/MobileNewSession.vue +217 -0
  36. package/src/mobile/MobileShell.vue +367 -0
  37. package/src/motion.css +166 -0
  38. package/src/preview/Preview.vue +91 -150
  39. package/src/preview/PreviewBody.vue +185 -0
  40. package/src/settings/AgentSettings.vue +126 -36
  41. package/src/settings/Select.vue +183 -0
  42. package/src/settings/SettingRow.vue +5 -4
  43. package/src/settings/Sheet.vue +4 -4
  44. package/src/styles.css +9 -0
@@ -0,0 +1,217 @@
1
+ <template>
2
+ <section class="mobile-new-session" :aria-label="t('desktop.newSession')">
3
+ <div class="mobile-new-session__brand">
4
+ <div class="mobile-new-session__logo" :style="logoStyle" aria-hidden="true" />
5
+ <h2 class="mobile-new-session__title">{{ t("shell.title") }}</h2>
6
+ </div>
7
+
8
+ <div class="mobile-new-session__prompt">
9
+ <div class="mobile-new-session__selectors">
10
+ <button
11
+ type="button"
12
+ class="mobile-new-session__chip mobile-new-session__chip--workspace"
13
+ :disabled="workspaceBusy"
14
+ :aria-label="t('desktop.workspaces')"
15
+ @click="$emit('workspace')"
16
+ >
17
+ <svg viewBox="0 0 24 24" aria-hidden="true">
18
+ <path d="M3.5 7.5h6l1.6 2H20.5v9H3.5z" />
19
+ </svg>
20
+ <span>{{ workspaceLabel }}</span>
21
+ <svg class="mobile-new-session__chevron" viewBox="0 0 24 24" aria-hidden="true">
22
+ <path d="M7 10l5 5 5-5" />
23
+ </svg>
24
+ </button>
25
+ <button
26
+ type="button"
27
+ class="mobile-new-session__chip mobile-new-session__chip--model"
28
+ :disabled="modelBusy"
29
+ :aria-label="modelAria"
30
+ @click="$emit('model')"
31
+ >
32
+ <span>{{ modelLabel || t("model.select") }}</span>
33
+ <svg class="mobile-new-session__chevron" viewBox="0 0 24 24" aria-hidden="true">
34
+ <path d="M7 10l5 5 5-5" />
35
+ </svg>
36
+ </button>
37
+ </div>
38
+ <div class="mobile-new-session__composer">
39
+ <slot />
40
+ </div>
41
+ </div>
42
+ </section>
43
+ </template>
44
+
45
+ <script>
46
+ import { MARK_DATA_URI } from "@olares/lares-core/icons/mark";
47
+
48
+ export default {
49
+ name: "LaresMobileNewSession",
50
+ props: {
51
+ t: { type: Function, required: true },
52
+ workspaceLabel: { type: String, default: "" },
53
+ workspaceBusy: { type: Boolean, default: false },
54
+ modelLabel: { type: String, default: "" },
55
+ modelBusy: { type: Boolean, default: false },
56
+ },
57
+ emits: ["workspace", "model"],
58
+ computed: {
59
+ logoStyle() {
60
+ return { backgroundImage: MARK_DATA_URI };
61
+ },
62
+ modelAria() {
63
+ return this.modelLabel
64
+ ? this.t("model.switchAria", { label: this.modelLabel })
65
+ : this.t("model.select");
66
+ },
67
+ },
68
+ };
69
+ </script>
70
+
71
+ <style scoped>
72
+ .mobile-new-session {
73
+ display: flex;
74
+ width: 100%;
75
+ min-height: 0;
76
+ flex: 1;
77
+ flex-direction: column;
78
+ align-items: center;
79
+ justify-content: center;
80
+ padding: 20px 20px calc(12px + env(safe-area-inset-bottom, 0px));
81
+ }
82
+
83
+ .mobile-new-session__brand {
84
+ display: flex;
85
+ flex-direction: column;
86
+ align-items: center;
87
+ gap: 8px;
88
+ margin-bottom: 32px;
89
+ }
90
+
91
+ .mobile-new-session__logo {
92
+ width: 56px;
93
+ height: 56px;
94
+ border-radius: 14px;
95
+ background-position: center;
96
+ background-repeat: no-repeat;
97
+ background-size: cover;
98
+ box-shadow: inset 0 1.8px 0 rgb(255 255 255 / 50%);
99
+ animation: mobile-brand-in var(--lares-duration-normal, 220ms) var(--lares-ease-out, cubic-bezier(0.32, 0.72, 0, 1));
100
+ }
101
+
102
+ @keyframes mobile-brand-in {
103
+ from {
104
+ opacity: 0;
105
+ transform: scale(0.92);
106
+ }
107
+ }
108
+
109
+ @media (prefers-reduced-motion: reduce) {
110
+ .mobile-new-session__logo {
111
+ animation: none;
112
+ }
113
+ }
114
+
115
+ .mobile-new-session__title {
116
+ margin: 0;
117
+ font-size: 28px;
118
+ font-weight: 600;
119
+ line-height: 34px;
120
+ letter-spacing: -0.02em;
121
+ }
122
+
123
+ .mobile-new-session__prompt {
124
+ display: flex;
125
+ width: min(100%, 420px);
126
+ flex-direction: column;
127
+ gap: 6px;
128
+ }
129
+
130
+ .mobile-new-session__selectors {
131
+ display: flex;
132
+ width: 100%;
133
+ align-items: center;
134
+ justify-content: space-between;
135
+ gap: 10px;
136
+ }
137
+
138
+ .mobile-new-session__chip {
139
+ display: inline-flex;
140
+ min-width: 0;
141
+ align-items: center;
142
+ gap: 6px;
143
+ border: 0;
144
+ border-radius: 999px;
145
+ padding: 6px 10px;
146
+ background: transparent;
147
+ color: var(--q-ink-2);
148
+ font-size: 14px;
149
+ font-weight: 500;
150
+ line-height: 18px;
151
+ transition: background var(--lares-duration-fast, 120ms) var(--lares-ease-out, ease),
152
+ color var(--lares-duration-fast, 120ms) var(--lares-ease-out, ease);
153
+ }
154
+
155
+ .mobile-new-session__chip--workspace {
156
+ flex: 0 1 auto;
157
+ max-width: 46%;
158
+ }
159
+
160
+ .mobile-new-session__chip--model {
161
+ flex: 1 1 auto;
162
+ justify-content: flex-end;
163
+ max-width: 54%;
164
+ }
165
+
166
+ .mobile-new-session__chip span {
167
+ min-width: 0;
168
+ overflow: hidden;
169
+ text-overflow: ellipsis;
170
+ white-space: nowrap;
171
+ }
172
+
173
+ .mobile-new-session__chip svg:not(.mobile-new-session__chevron) {
174
+ width: 18px;
175
+ height: 18px;
176
+ flex-shrink: 0;
177
+ fill: none;
178
+ stroke: currentColor;
179
+ stroke-width: 1.75;
180
+ stroke-linejoin: round;
181
+ }
182
+
183
+ .mobile-new-session__chevron {
184
+ width: 16px;
185
+ height: 16px;
186
+ flex-shrink: 0;
187
+ fill: none;
188
+ stroke: currentColor;
189
+ stroke-width: 1.75;
190
+ stroke-linecap: round;
191
+ stroke-linejoin: round;
192
+ }
193
+
194
+ .mobile-new-session__chip:active:not(:disabled) {
195
+ background: var(--q-btn-bg-pressed);
196
+ }
197
+
198
+ .mobile-new-session__composer {
199
+ width: 100%;
200
+ }
201
+
202
+ @media (max-height: 640px) {
203
+ .mobile-new-session__brand {
204
+ margin-bottom: 24px;
205
+ }
206
+
207
+ .mobile-new-session__logo {
208
+ width: 48px;
209
+ height: 48px;
210
+ }
211
+
212
+ .mobile-new-session__title {
213
+ font-size: 24px;
214
+ line-height: 30px;
215
+ }
216
+ }
217
+ </style>
@@ -0,0 +1,367 @@
1
+ <template>
2
+ <div class="lares-mobile-shell">
3
+ <LaresChatBar
4
+ :t="t"
5
+ :title="barTitle"
6
+ :starting="state.starting"
7
+ @history="$emit('history')"
8
+ @create="$emit('create', state.currentWorkspaceId || null)"
9
+ />
10
+ <LaresHistoryPanel
11
+ :open="state.panel === 'history'"
12
+ :sessions="state.sessions"
13
+ :workspaces="state.workspaces"
14
+ :workspaces-ready="state.workspacesReady"
15
+ :workspace-error="state.workspaceError"
16
+ :archived-session-ids="state.archivedSessionIds"
17
+ :session-id="state.sessionId"
18
+ :ready="state.sessionsReady"
19
+ :unseen="state.unseen"
20
+ :t="t"
21
+ @close="$emit('close-history')"
22
+ @pick="$emit('pick-session', $event)"
23
+ @create="$emit('create', $event)"
24
+ @browse-workspaces="$emit('browse-workspaces')"
25
+ @refresh-workspaces="$emit('refresh-workspaces')"
26
+ @rename-session="(id, title) => $emit('rename-session', id, title)"
27
+ @archive-session="$emit('archive-session', $event)"
28
+ @move-session="(workspaceId, sessionId, before) => $emit('move-session', workspaceId, sessionId, before)"
29
+ />
30
+ <LaresMobileDirectorySheet
31
+ :open="state.directory.open"
32
+ :state="state.directory"
33
+ :t="t"
34
+ @close="$emit('close-directory')"
35
+ @browse="$emit('browse-directory', $event)"
36
+ @choose="$emit('choose-directory', $event)"
37
+ @create-folder="$emit('create-folder', $event)"
38
+ @toggle-hidden="$emit('toggle-hidden', $event)"
39
+ />
40
+ <div class="lares-shell__conversation" :data-hero="newSessionHero ? 'true' : 'false'">
41
+ <p v-if="state.failed" class="lares-shell__status">{{ state.failText }}</p>
42
+ <button
43
+ v-if="state.failed"
44
+ type="button"
45
+ class="lares-shell__retry"
46
+ :disabled="state.starting"
47
+ @click="$emit('retry')"
48
+ >
49
+ {{ t("probe.retry") }}
50
+ </button>
51
+
52
+ <Transition name="lares-view" mode="out-in">
53
+ <LaresMobileNewSession
54
+ v-if="newSessionHero"
55
+ key="hero"
56
+ :t="t"
57
+ :workspace-label="workspaceLabel"
58
+ :workspace-busy="!state.workspacesReady && !state.workspaceError"
59
+ :model-label="state.modelLabel"
60
+ :model-busy="state.modelBusy"
61
+ @workspace="workspaceSheet = true"
62
+ @model="$emit('open-model')"
63
+ >
64
+ <LaresComposer
65
+ ref="composer"
66
+ hero
67
+ :draft="state.draft"
68
+ :sending="state.sending"
69
+ :can-send="state.canSend"
70
+ :model-label="state.modelLabel"
71
+ :model-busy="state.modelBusy"
72
+ :effort-label="state.effortLabel"
73
+ :effort-disabled="state.effortDisabled"
74
+ :attach-pending="state.upload.pending > 0"
75
+ :attach-disabled="!state.sessionId || state.historyLoading || state.starting"
76
+ :voice-phase="state.voicePhase"
77
+ :voice-elapsed="state.voiceElapsed"
78
+ :voice-error="state.voiceErrorText"
79
+ :failures="state.upload.failures"
80
+ :draft-images="state.draftImages"
81
+ :references="state.references"
82
+ :references-loading="state.referencesLoading"
83
+ :references-error="state.referencesError"
84
+ :commands="state.commands"
85
+ :commands-error="state.commandsError"
86
+ :t="t"
87
+ @update:draft="$emit('update-draft', $event)"
88
+ @send="$emit('send')"
89
+ @model="$emit('open-model')"
90
+ @effort="$emit('open-effort')"
91
+ @files="$emit('files', $event)"
92
+ @voice="$emit('voice')"
93
+ @hold-start="$emit('hold-start')"
94
+ @hold-end="$emit('hold-end')"
95
+ @open-commands="$emit('open-commands')"
96
+ @open-references="$emit('open-references', $event)"
97
+ @pick-command="$emit('pick-command', $event)"
98
+ @remove-image="$emit('remove-image', $event)"
99
+ />
100
+ </LaresMobileNewSession>
101
+
102
+ <div v-else key="chat" class="lares-shell__chat">
103
+ <LaresTranscript
104
+ ref="transcript"
105
+ :items="state.viewItems"
106
+ :running="state.running"
107
+ :loading="state.historyLoading || state.starting"
108
+ :previews="state.previews"
109
+ :media-url="mediaUrl"
110
+ :scroll-top="scrollTop"
111
+ :remember-scroll="rememberScroll"
112
+ :sticking="sticking"
113
+ :session-id="state.sessionId"
114
+ :question="state.question"
115
+ :question-busy="state.questionBusy"
116
+ :t="t"
117
+ @open="$emit('open-file', $event)"
118
+ @media="pinLog"
119
+ @answer="forwardAnswer"
120
+ />
121
+ <LaresComposer
122
+ ref="composer"
123
+ :draft="state.draft"
124
+ :sending="state.sending"
125
+ :can-send="state.canSend"
126
+ :model-label="state.modelLabel"
127
+ :model-busy="state.modelBusy"
128
+ :effort-label="state.effortLabel"
129
+ :effort-disabled="state.effortDisabled"
130
+ :attach-pending="state.upload.pending > 0"
131
+ :attach-disabled="!state.sessionId || state.historyLoading || state.starting"
132
+ :voice-phase="state.voicePhase"
133
+ :voice-elapsed="state.voiceElapsed"
134
+ :voice-error="state.voiceErrorText"
135
+ :failures="state.upload.failures"
136
+ :draft-images="state.draftImages"
137
+ :references="state.references"
138
+ :references-loading="state.referencesLoading"
139
+ :references-error="state.referencesError"
140
+ :commands="state.commands"
141
+ :commands-error="state.commandsError"
142
+ :t="t"
143
+ @update:draft="$emit('update-draft', $event)"
144
+ @send="$emit('send')"
145
+ @model="$emit('open-model')"
146
+ @effort="$emit('open-effort')"
147
+ @files="$emit('files', $event)"
148
+ @voice="$emit('voice')"
149
+ @hold-start="$emit('hold-start')"
150
+ @hold-end="$emit('hold-end')"
151
+ @open-commands="$emit('open-commands')"
152
+ @open-references="$emit('open-references', $event)"
153
+ @pick-command="$emit('pick-command', $event)"
154
+ @remove-image="$emit('remove-image', $event)"
155
+ />
156
+ </div>
157
+ </Transition>
158
+ </div>
159
+
160
+ <LaresSheet :open="workspaceSheet" :title="t('desktop.workspaces')" @close="workspaceSheet = false">
161
+ <p v-if="state.workspaceError" class="lares-shell__status">{{ state.workspaceError }}</p>
162
+ <p v-else-if="!state.workspacesReady" class="lares-shell__hint">{{ t("agent.loading") }}</p>
163
+ <p v-else-if="!state.workspaces.length" class="lares-shell__hint">{{ t("desktop.noFolders") }}</p>
164
+ <LaresSettingRow
165
+ v-for="workspace in state.workspaces"
166
+ :key="workspace.workspaceId"
167
+ :label="workspace.title"
168
+ :checked="workspace.workspaceId === state.currentWorkspaceId"
169
+ @click="pickWorkspace(workspace.workspaceId)"
170
+ />
171
+ </LaresSheet>
172
+ <LaresSheet :open="state.modelSheet" :title="t('model.menuAria')" @close="$emit('close-model')">
173
+ <p v-if="state.modelError" class="lares-shell__status">{{ state.modelError }}</p>
174
+ <p v-else-if="!state.models" class="lares-shell__hint">{{ t("agent.loading") }}</p>
175
+ <p v-else-if="!state.modelGroups.length" class="lares-shell__hint">{{ t("model.empty") }}</p>
176
+ <template v-for="section in state.modelGroups" :key="section.provider">
177
+ <p class="lares-shell__heading">{{ section.provider }}</p>
178
+ <LaresSettingRow
179
+ v-for="item in section.models"
180
+ :key="modelKey(item)"
181
+ :label="item.name"
182
+ :checked="modelKey(item) === state.modelCurrent"
183
+ :disabled="state.modelBusy"
184
+ @click="$emit('choose-model', item)"
185
+ />
186
+ </template>
187
+ </LaresSheet>
188
+ <LaresSheet :open="state.effortSheet" :title="t('reasoning.title')" @close="$emit('close-effort')">
189
+ <p v-if="!state.effortRows.length" class="lares-shell__hint">{{ t("reasoning.default") }}</p>
190
+ <LaresSettingRow
191
+ v-for="row in state.effortRows"
192
+ :key="row.key"
193
+ :label="effortName(row)"
194
+ :checked="row.id === state.effortId"
195
+ :disabled="state.modelBusy"
196
+ @click="$emit('choose-effort', row.id)"
197
+ />
198
+ </LaresSheet>
199
+ <Transition name="lares-preview">
200
+ <LaresPreview
201
+ v-if="state.previewMode === 'preview' && state.preview.path"
202
+ :path="state.preview.path"
203
+ :session-id="state.sessionId"
204
+ :status="state.preview.status"
205
+ :data="state.preview.data"
206
+ :error="state.preview.error"
207
+ :media-src="state.previewMediaSrc"
208
+ :download-href="state.previewDownloadHref"
209
+ :href-for="previewHref"
210
+ :t="t"
211
+ @close="$emit('close-preview')"
212
+ @retry="$emit('open-file', state.preview.path)"
213
+ @open="$emit('open-file', $event)"
214
+ />
215
+ </Transition>
216
+ </div>
217
+ </template>
218
+
219
+ <script>
220
+ import LaresChatBar from "../chat/ChatBar.vue";
221
+ import LaresHistoryPanel from "../chat/HistoryPanel.vue";
222
+ import LaresTranscript from "../chat/Transcript.vue";
223
+ import LaresComposer from "../chat/Composer.vue";
224
+ import LaresPreview from "../preview/Preview.vue";
225
+ import LaresSheet from "../settings/Sheet.vue";
226
+ import LaresSettingRow from "../settings/SettingRow.vue";
227
+ import LaresMobileDirectorySheet from "./MobileDirectorySheet.vue";
228
+ import LaresMobileNewSession from "./MobileNewSession.vue";
229
+ import { DEFAULT_WORKSPACE_TITLE } from "@olares/lares-core/workspace/constants";
230
+
231
+ export default {
232
+ name: "LaresMobileShell",
233
+ components: {
234
+ LaresChatBar,
235
+ LaresHistoryPanel,
236
+ LaresTranscript,
237
+ LaresComposer,
238
+ LaresPreview,
239
+ LaresSheet,
240
+ LaresSettingRow,
241
+ LaresMobileDirectorySheet,
242
+ LaresMobileNewSession,
243
+ },
244
+ props: {
245
+ state: { type: Object, required: true },
246
+ t: { type: Function, required: true },
247
+ mediaUrl: { type: Function, required: true },
248
+ scrollTop: { type: Function, required: true },
249
+ rememberScroll: { type: Function, required: true },
250
+ sticking: { type: Function, required: true },
251
+ previewHref: { type: Function, required: true },
252
+ modelKey: { type: Function, required: true },
253
+ effortName: { type: Function, required: true },
254
+ },
255
+ emits: [
256
+ "history", "create", "close-history", "pick-session", "retry", "open-file",
257
+ "answer", "update-draft", "send", "open-model", "open-effort", "files",
258
+ "voice", "hold-start", "hold-end", "close-model", "choose-model",
259
+ "close-effort", "choose-effort", "close-preview",
260
+ "open-commands", "open-references", "pick-command", "remove-image",
261
+ "refresh-workspaces", "browse-workspaces", "browse-directory",
262
+ "close-directory", "choose-directory", "create-folder", "toggle-hidden",
263
+ "rename-session", "archive-session",
264
+ "move-session", "pick-workspace",
265
+ ],
266
+ data() {
267
+ return { workspaceSheet: false };
268
+ },
269
+ computed: {
270
+ newSessionHero() {
271
+ if (this.state.previewMode === "preview" && this.state.preview.path) return false;
272
+ return (
273
+ this.state.viewItems.length === 0
274
+ && !this.state.running
275
+ && !this.state.historyLoading
276
+ && !this.state.starting
277
+ );
278
+ },
279
+ barTitle() {
280
+ return this.newSessionHero ? this.t("desktop.newSession") : this.state.sessionTitle;
281
+ },
282
+ workspaceLabel() {
283
+ if (!this.state.workspacesReady) return this.t("agent.loading");
284
+ const current = this.state.workspaces.find(
285
+ (row) => row.workspaceId === this.state.currentWorkspaceId,
286
+ );
287
+ if (current?.title) return current.title;
288
+ if (this.state.workspaces[0]?.title) return this.state.workspaces[0].title;
289
+ return DEFAULT_WORKSPACE_TITLE;
290
+ },
291
+ },
292
+ methods: {
293
+ pickWorkspace(workspaceId) {
294
+ this.workspaceSheet = false;
295
+ if (!workspaceId || workspaceId === this.state.currentWorkspaceId) return;
296
+ this.$emit("pick-workspace", workspaceId);
297
+ },
298
+ forwardAnswer(label, row) {
299
+ this.$emit("answer", label, row);
300
+ },
301
+ restoreLog() {
302
+ this.$refs.transcript?.restoreLog?.();
303
+ },
304
+ captureLog() {
305
+ this.$refs.transcript?.captureLog?.();
306
+ },
307
+ pinLog() {
308
+ this.$refs.transcript?.scheduleLogPin?.();
309
+ },
310
+ focusComposer() {
311
+ this.$refs.composer?.focus?.();
312
+ },
313
+ },
314
+ };
315
+ </script>
316
+
317
+ <style scoped>
318
+ .lares-mobile-shell {
319
+ position: relative;
320
+ display: flex;
321
+ flex: 1;
322
+ min-height: 0;
323
+ flex-direction: column;
324
+ }
325
+
326
+ .lares-shell__conversation[data-hero="true"] {
327
+ justify-content: center;
328
+ }
329
+
330
+ .lares-shell__chat {
331
+ display: flex;
332
+ min-width: 0;
333
+ min-height: 0;
334
+ flex: 1;
335
+ flex-direction: column;
336
+ }
337
+
338
+ .lares-shell__status,
339
+ .lares-shell__hint {
340
+ margin: 0 20px;
341
+ font-size: 15px;
342
+ color: var(--q-ink-3);
343
+ }
344
+
345
+ .lares-shell__status {
346
+ color: var(--q-orange-default);
347
+ }
348
+
349
+ .lares-shell__retry {
350
+ align-self: flex-start;
351
+ margin: 0 20px;
352
+ border: 0;
353
+ border-radius: 8px;
354
+ padding: 8px 12px;
355
+ background: var(--q-blue-alpha);
356
+ color: var(--q-blue-default);
357
+ }
358
+
359
+ .lares-shell__heading {
360
+ margin: 0;
361
+ padding: 12px 16px 4px;
362
+ color: var(--q-ink-3);
363
+ font-size: 14px;
364
+ font-weight: 500;
365
+ line-height: 18px;
366
+ }
367
+ </style>