@praxisui/ai 8.0.0-beta.30 → 8.0.0-beta.31
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/README.md +13 -2
- package/fesm2022/praxisui-ai.mjs +118 -27
- package/index.d.ts +44 -4
- package/package.json +2 -2
package/fesm2022/praxisui-ai.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Component, Injectable, InjectionToken, Optional, Inject, inject, signal, computed, ChangeDetectorRef, ElementRef, ViewChild, Input, ChangeDetectionStrategy, EventEmitter, Output } from '@angular/core';
|
|
2
|
+
import { Component, Injectable, InjectionToken, Optional, Inject, inject, signal, computed, ChangeDetectorRef, ElementRef, ViewChild, Input, ChangeDetectionStrategy, EventEmitter, Output, booleanAttribute } from '@angular/core';
|
|
3
3
|
import { SchemaType, GoogleGenerativeAI } from '@google/generative-ai';
|
|
4
4
|
import { throwError, from, Observable, of, BehaviorSubject, tap, map as map$1, catchError as catchError$1, isObservable, firstValueFrom } from 'rxjs';
|
|
5
5
|
import { map, catchError, filter, take } from 'rxjs/operators';
|
|
@@ -408,6 +408,51 @@ const AI_STREAM_EVENT_SCHEMA_VERSION = 'v1';
|
|
|
408
408
|
const AI_DOMAIN_CATALOG_CONTEXT_HINT_SCHEMA_VERSION = 'praxis.ai.context-hints.domain-catalog/v0.2';
|
|
409
409
|
const AI_STREAM_EVENT_TYPES = ['status', 'thought.step', 'heartbeat', 'result', 'error', 'cancelled'];
|
|
410
410
|
|
|
411
|
+
function createComponentAuthoringContext(authoringContract) {
|
|
412
|
+
return {
|
|
413
|
+
authoringContract: toAiJsonObject(authoringContract, 'authoringContract'),
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
function toAiJsonObject(value, path = 'value') {
|
|
417
|
+
const normalized = toAiJsonValue(value, path);
|
|
418
|
+
if (!normalized || Array.isArray(normalized) || typeof normalized !== 'object') {
|
|
419
|
+
throw new Error(`${path} must be a JSON object.`);
|
|
420
|
+
}
|
|
421
|
+
return normalized;
|
|
422
|
+
}
|
|
423
|
+
function toAiJsonValue(value, path) {
|
|
424
|
+
if (value === undefined)
|
|
425
|
+
return undefined;
|
|
426
|
+
if (value === null) {
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
if (typeof value === 'string' || typeof value === 'boolean') {
|
|
430
|
+
return value;
|
|
431
|
+
}
|
|
432
|
+
if (typeof value === 'number') {
|
|
433
|
+
if (!Number.isFinite(value)) {
|
|
434
|
+
throw new Error(`${path} must be a finite JSON number.`);
|
|
435
|
+
}
|
|
436
|
+
return value;
|
|
437
|
+
}
|
|
438
|
+
if (Array.isArray(value)) {
|
|
439
|
+
return value
|
|
440
|
+
.map((item, index) => toAiJsonValue(item, `${path}[${index}]`))
|
|
441
|
+
.filter((item) => item !== undefined);
|
|
442
|
+
}
|
|
443
|
+
if (typeof value === 'object') {
|
|
444
|
+
const result = {};
|
|
445
|
+
for (const [key, item] of Object.entries(value)) {
|
|
446
|
+
const normalized = toAiJsonValue(item, `${path}.${key}`);
|
|
447
|
+
if (normalized !== undefined) {
|
|
448
|
+
result[key] = normalized;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
return result;
|
|
452
|
+
}
|
|
453
|
+
throw new Error(`${path} contains a non-JSON value.`);
|
|
454
|
+
}
|
|
455
|
+
|
|
411
456
|
/**
|
|
412
457
|
* Base implementation for AI Adapters.
|
|
413
458
|
* Provides common validation logic against the Capabilities Catalog.
|
|
@@ -1081,6 +1126,12 @@ class AiBackendApiService {
|
|
|
1081
1126
|
let source = null;
|
|
1082
1127
|
const events$ = new Observable((subscriber) => {
|
|
1083
1128
|
let disposed = false;
|
|
1129
|
+
const closeSource = () => {
|
|
1130
|
+
if (source) {
|
|
1131
|
+
source.close();
|
|
1132
|
+
source = null;
|
|
1133
|
+
}
|
|
1134
|
+
};
|
|
1084
1135
|
const openStream = async () => {
|
|
1085
1136
|
if (typeof EventSource === 'undefined') {
|
|
1086
1137
|
subscriber.error(new AiPatchStreamConnectionError('unsupported', 'EventSource is not supported in this environment.'));
|
|
@@ -1095,10 +1146,14 @@ class AiBackendApiService {
|
|
|
1095
1146
|
return;
|
|
1096
1147
|
}
|
|
1097
1148
|
source = new EventSource(endpoint, { withCredentials: true });
|
|
1098
|
-
|
|
1149
|
+
const handleMessage = (messageEvent) => {
|
|
1099
1150
|
try {
|
|
1100
1151
|
const parsed = this.parsePatchStreamEnvelope(messageEvent.data);
|
|
1101
1152
|
subscriber.next(parsed);
|
|
1153
|
+
if (this.isTerminalStreamEventType(parsed.type)) {
|
|
1154
|
+
subscriber.complete();
|
|
1155
|
+
closeSource();
|
|
1156
|
+
}
|
|
1102
1157
|
}
|
|
1103
1158
|
catch (error) {
|
|
1104
1159
|
if (error instanceof AiPatchStreamConnectionError) {
|
|
@@ -1108,6 +1163,8 @@ class AiBackendApiService {
|
|
|
1108
1163
|
subscriber.error(new AiPatchStreamConnectionError('parse', 'Failed to parse stream event payload.'));
|
|
1109
1164
|
}
|
|
1110
1165
|
};
|
|
1166
|
+
source.onmessage = handleMessage;
|
|
1167
|
+
this.registerNamedStreamEventListeners(source, handleMessage);
|
|
1111
1168
|
source.onerror = () => {
|
|
1112
1169
|
if (!source) {
|
|
1113
1170
|
subscriber.error(new AiPatchStreamConnectionError('transport', 'Patch stream connection error.'));
|
|
@@ -1123,10 +1180,7 @@ class AiBackendApiService {
|
|
|
1123
1180
|
void openStream();
|
|
1124
1181
|
return () => {
|
|
1125
1182
|
disposed = true;
|
|
1126
|
-
|
|
1127
|
-
source.close();
|
|
1128
|
-
source = null;
|
|
1129
|
-
}
|
|
1183
|
+
closeSource();
|
|
1130
1184
|
};
|
|
1131
1185
|
});
|
|
1132
1186
|
return {
|
|
@@ -1171,6 +1225,12 @@ class AiBackendApiService {
|
|
|
1171
1225
|
let source = null;
|
|
1172
1226
|
const events$ = new Observable((subscriber) => {
|
|
1173
1227
|
let disposed = false;
|
|
1228
|
+
const closeSource = () => {
|
|
1229
|
+
if (source) {
|
|
1230
|
+
source.close();
|
|
1231
|
+
source = null;
|
|
1232
|
+
}
|
|
1233
|
+
};
|
|
1174
1234
|
const openStream = async () => {
|
|
1175
1235
|
if (typeof EventSource === 'undefined') {
|
|
1176
1236
|
subscriber.error(new AiPatchStreamConnectionError('unsupported', 'EventSource is not supported in this environment.'));
|
|
@@ -1185,10 +1245,14 @@ class AiBackendApiService {
|
|
|
1185
1245
|
return;
|
|
1186
1246
|
}
|
|
1187
1247
|
source = new EventSource(endpoint, { withCredentials: true });
|
|
1188
|
-
|
|
1248
|
+
const handleMessage = (messageEvent) => {
|
|
1189
1249
|
try {
|
|
1190
1250
|
const parsed = this.parsePatchStreamEnvelope(messageEvent.data);
|
|
1191
1251
|
subscriber.next(parsed);
|
|
1252
|
+
if (this.isTerminalStreamEventType(parsed.type)) {
|
|
1253
|
+
subscriber.complete();
|
|
1254
|
+
closeSource();
|
|
1255
|
+
}
|
|
1192
1256
|
}
|
|
1193
1257
|
catch (error) {
|
|
1194
1258
|
if (error instanceof AiPatchStreamConnectionError) {
|
|
@@ -1198,6 +1262,8 @@ class AiBackendApiService {
|
|
|
1198
1262
|
subscriber.error(new AiPatchStreamConnectionError('parse', 'Failed to parse agentic authoring stream event payload.'));
|
|
1199
1263
|
}
|
|
1200
1264
|
};
|
|
1265
|
+
source.onmessage = handleMessage;
|
|
1266
|
+
this.registerNamedStreamEventListeners(source, handleMessage);
|
|
1201
1267
|
source.onerror = () => {
|
|
1202
1268
|
if (!source) {
|
|
1203
1269
|
subscriber.error(new AiPatchStreamConnectionError('transport', 'Agentic authoring stream connection error.'));
|
|
@@ -1211,10 +1277,7 @@ class AiBackendApiService {
|
|
|
1211
1277
|
void openStream();
|
|
1212
1278
|
return () => {
|
|
1213
1279
|
disposed = true;
|
|
1214
|
-
|
|
1215
|
-
source.close();
|
|
1216
|
-
source = null;
|
|
1217
|
-
}
|
|
1280
|
+
closeSource();
|
|
1218
1281
|
};
|
|
1219
1282
|
});
|
|
1220
1283
|
return {
|
|
@@ -1447,6 +1510,17 @@ class AiBackendApiService {
|
|
|
1447
1510
|
isJsonObject(value) {
|
|
1448
1511
|
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
1449
1512
|
}
|
|
1513
|
+
registerNamedStreamEventListeners(source, handler) {
|
|
1514
|
+
if (typeof source.addEventListener !== 'function') {
|
|
1515
|
+
return;
|
|
1516
|
+
}
|
|
1517
|
+
for (const eventType of AI_STREAM_EVENT_TYPES) {
|
|
1518
|
+
source.addEventListener(eventType, handler);
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
isTerminalStreamEventType(type) {
|
|
1522
|
+
return type === 'result' || type === 'error' || type === 'cancelled';
|
|
1523
|
+
}
|
|
1450
1524
|
async probePatchStreamEndpoint(endpoint) {
|
|
1451
1525
|
if (typeof fetch === 'undefined') {
|
|
1452
1526
|
return null;
|
|
@@ -2353,6 +2427,7 @@ class PraxisAssistantSessionRegistryService {
|
|
|
2353
2427
|
contextSnapshot: normalized.contextSnapshot,
|
|
2354
2428
|
badge: normalized.badge,
|
|
2355
2429
|
icon: normalized.icon,
|
|
2430
|
+
presence: normalized.presence,
|
|
2356
2431
|
createdAt: existing?.createdAt ?? now,
|
|
2357
2432
|
updatedAt: now,
|
|
2358
2433
|
};
|
|
@@ -2448,6 +2523,7 @@ class PraxisAssistantSessionRegistryService {
|
|
|
2448
2523
|
contextSnapshot,
|
|
2449
2524
|
badge: descriptor.badge?.trim() || '',
|
|
2450
2525
|
icon: descriptor.icon?.trim() || '',
|
|
2526
|
+
presence: descriptor.presence || 'global-dock',
|
|
2451
2527
|
updatedAt: descriptor.updatedAt?.trim() || null,
|
|
2452
2528
|
};
|
|
2453
2529
|
}
|
|
@@ -2863,6 +2939,7 @@ class PraxisAiAssistantComponent {
|
|
|
2863
2939
|
adapter;
|
|
2864
2940
|
riskPolicy = null;
|
|
2865
2941
|
allowManualPatchEdit = false;
|
|
2942
|
+
hasBackdrop = false;
|
|
2866
2943
|
overlayPositions = [
|
|
2867
2944
|
{
|
|
2868
2945
|
originX: 'end',
|
|
@@ -3149,6 +3226,7 @@ class PraxisAiAssistantComponent {
|
|
|
3149
3226
|
const componentType = this.resolveComponentType();
|
|
3150
3227
|
this.currentComponentId = componentId || null;
|
|
3151
3228
|
this.currentComponentType = componentType || null;
|
|
3229
|
+
await this.adapter.prepareAuthoringContext?.();
|
|
3152
3230
|
const configRoot = this.resolveConfigRoot(this.adapter.getCurrentConfig?.());
|
|
3153
3231
|
const dataProfile = this.adapter.getDataProfile ? this.adapter.getDataProfile() : null;
|
|
3154
3232
|
const schemaFields = this.adapter.getSchemaFields ? this.adapter.getSchemaFields() : undefined;
|
|
@@ -3211,7 +3289,7 @@ class PraxisAiAssistantComponent {
|
|
|
3211
3289
|
}
|
|
3212
3290
|
result = this.compileAdapterResponse(result);
|
|
3213
3291
|
keepContextHints = result?.type === 'clarification';
|
|
3214
|
-
const handled = this.handlePatchResponse(result, configRoot, componentId, componentType);
|
|
3292
|
+
const handled = this.handlePatchResponse(result, configRoot, componentId, componentType, prompt);
|
|
3215
3293
|
if (handled) {
|
|
3216
3294
|
this.appendHistoryAssistantResponse(result, componentId, componentType);
|
|
3217
3295
|
return;
|
|
@@ -5091,7 +5169,7 @@ class PraxisAiAssistantComponent {
|
|
|
5091
5169
|
if (event.type === 'result') {
|
|
5092
5170
|
this.streamTerminalState = 'completed';
|
|
5093
5171
|
this.processingInfoVisible = false;
|
|
5094
|
-
const response = this.asRecord(payload?.['response']);
|
|
5172
|
+
const response = this.asRecord(payload?.['response']) ?? payload;
|
|
5095
5173
|
if (!response) {
|
|
5096
5174
|
return {
|
|
5097
5175
|
type: 'error',
|
|
@@ -5275,7 +5353,7 @@ class PraxisAiAssistantComponent {
|
|
|
5275
5353
|
warnings: warnings.length ? warnings : undefined,
|
|
5276
5354
|
};
|
|
5277
5355
|
}
|
|
5278
|
-
handlePatchResponse(result, configRoot, componentId, componentType) {
|
|
5356
|
+
handlePatchResponse(result, configRoot, componentId, componentType, requestPrompt) {
|
|
5279
5357
|
if (!result) {
|
|
5280
5358
|
this.streamTerminalState = 'failed';
|
|
5281
5359
|
this.errorMsg = 'Resposta vazia da IA.';
|
|
@@ -5297,12 +5375,12 @@ class PraxisAiAssistantComponent {
|
|
|
5297
5375
|
const questions = result.questions?.filter((q) => !!q && q.trim().length > 0) || [];
|
|
5298
5376
|
if (questions.length && (!result.options || result.options.length === 0)
|
|
5299
5377
|
&& (!result.optionPayloads || result.optionPayloads.length === 0)) {
|
|
5300
|
-
this.enterClarificationWithQuestions(result.message, questions, configRoot, componentId, componentType);
|
|
5378
|
+
this.enterClarificationWithQuestions(result.message, questions, configRoot, componentId, componentType, requestPrompt);
|
|
5301
5379
|
this.applyClarificationUi(result);
|
|
5302
5380
|
return true;
|
|
5303
5381
|
}
|
|
5304
5382
|
const enriched = this.enrichClarification(result, configRoot, componentId, componentType);
|
|
5305
|
-
this.enterClarification(enriched.message, enriched.options, configRoot, componentId, componentType,
|
|
5383
|
+
this.enterClarification(enriched.message, enriched.options, configRoot, componentId, componentType, requestPrompt, enriched.optionPayloads);
|
|
5306
5384
|
this.applyClarificationUi(enriched);
|
|
5307
5385
|
return true;
|
|
5308
5386
|
}
|
|
@@ -5775,10 +5853,10 @@ class PraxisAiAssistantComponent {
|
|
|
5775
5853
|
}
|
|
5776
5854
|
this.cdr.markForCheck();
|
|
5777
5855
|
}
|
|
5778
|
-
enterClarificationWithQuestions(message, questions, configRoot, componentId, componentType) {
|
|
5856
|
+
enterClarificationWithQuestions(message, questions, configRoot, componentId, componentType, basePrompt) {
|
|
5779
5857
|
this.setState('clarification');
|
|
5780
5858
|
this.clarificationMessage = message || 'Preciso de mais detalhes para continuar.';
|
|
5781
|
-
const base = (this.userPrompt
|
|
5859
|
+
const base = (basePrompt ?? this.userPrompt).trim();
|
|
5782
5860
|
this.clarificationBasePrompt = base || null;
|
|
5783
5861
|
this.userPrompt = '';
|
|
5784
5862
|
this.activeContextHints = null;
|
|
@@ -6591,7 +6669,7 @@ class PraxisAiAssistantComponent {
|
|
|
6591
6669
|
return 'Erro ao comunicar com a IA. Tente novamente.';
|
|
6592
6670
|
}
|
|
6593
6671
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisAiAssistantComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
6594
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: PraxisAiAssistantComponent, isStandalone: true, selector: "praxis-ai-assistant", inputs: { adapter: "adapter", riskPolicy: "riskPolicy", allowManualPatchEdit: "allowManualPatchEdit" }, viewQueries: [{ propertyName: "overlayOrigin", first: true, predicate: CdkOverlayOrigin, descendants: true }, { propertyName: "triggerButton", first: true, predicate: ["triggerBtn"], descendants: true, read: ElementRef }, { propertyName: "inputElement", first: true, predicate: ["inputEl"], descendants: true }], ngImport: i0, template: "<!-- Trigger Button -->\n<button \n mat-icon-button \n cdkOverlayOrigin \n #trigger=\"cdkOverlayOrigin\"\n #triggerBtn\n (click)=\"open()\"\n [disabled]=\"isOpen\"\n class=\"ai-trigger-btn\"\n matTooltip=\"Assistente de Configura\u00E7\u00E3o\"\n aria-label=\"Abrir Assistente IA\">\n <mat-icon>auto_awesome</mat-icon>\n</button>\n\n<!-- Overlay Template -->\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"isOpen\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayPush]=\"true\"\n [cdkConnectedOverlayViewportMargin]=\"12\"\n cdkConnectedOverlayPanelClass=\"ai-assistant-overlay-pane\"\n cdkConnectedOverlayBackdropClass=\"ai-assistant-backdrop\"\n (backdropClick)=\"close()\"\n (detach)=\"close()\">\n\n <div\n class=\"ai-assistant-panel\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Assistente de Configura\u00E7\u00E3o\"\n [attr.aria-busy]=\"isBusyState() ? 'true' : null\"\n cdkTrapFocus\n [cdkTrapFocusAutoCapture]=\"true\"\n (keydown)=\"onKeydown($event)\"\n >\n \n <!-- HEADER -->\n <div class=\"assistant-header\">\n <div class=\"assistant-header__left\">\n <mat-icon class=\"magic-icon\">auto_awesome</mat-icon>\n <div class=\"assistant-title-group\">\n <div class=\"assistant-title\">Assistente de Configura\u00E7\u00E3o</div>\n <div class=\"assistant-subtitle\">Copiloto contextual para ajustes guiados</div>\n <div class=\"assistant-header-chips\">\n <span\n class=\"mode-chip\"\n [class.mock]=\"mockMode\"\n [matTooltip]=\"mockMode ? 'Sem chave de API: respostas de demonstra\u00E7\u00E3o' : 'Conectado ao assistente configurado'\"\n >\n {{ mockMode ? 'Mock' : 'Conectado' }}\n </span>\n <span\n class=\"policy-chip\"\n [class.strict]=\"isStrictRiskPolicy()\"\n [matTooltip]=\"getRiskPolicyTooltip()\"\n >\n {{ getRiskPolicyLabel() }}\n </span>\n </div>\n </div>\n </div>\n <div class=\"assistant-header__right\">\n <button\n mat-icon-button\n type=\"button\"\n class=\"assistant-close-btn\"\n (click)=\"close()\"\n aria-label=\"Fechar assistente\"\n matTooltip=\"Fechar assistente\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n <div\n class=\"assistant-status\"\n [class.processing]=\"isBusyState()\"\n [class.pending]=\"state === 'clarification'\"\n [class.warning]=\"state === 'error'\"\n [class.success]=\"state === 'review' || state === 'success'\"\n [class.compact]=\"!shouldShowSystemStatusDetail()\"\n role=\"status\"\n [attr.aria-live]=\"getSystemStatusAriaLive()\"\n aria-atomic=\"true\"\n >\n <span class=\"assistant-status-dot\" aria-hidden=\"true\"></span>\n <div class=\"assistant-status-content\">\n <div class=\"assistant-status-label\">\n <span class=\"assistant-status-label-prefix\">Status:</span>\n <span>{{ getSystemStatusLabel() }}</span>\n <span *ngIf=\"shouldShowSnapshotFallbackBadge()\" class=\"assistant-status-mode\">Snapshot</span>\n </div>\n <div *ngIf=\"shouldShowSystemStatusDetail()\" class=\"assistant-status-detail\">{{ getSystemStatusDetail() }}</div>\n </div>\n </div>\n <div class=\"assistant-flow\" *ngIf=\"shouldShowTaskFlow()\" role=\"list\" aria-label=\"Fluxo da proposta\">\n <div\n class=\"flow-step\"\n role=\"listitem\"\n *ngFor=\"let step of flowSteps\"\n [class.active]=\"getFlowStepState(step.step) === 'active'\"\n [class.done]=\"getFlowStepState(step.step) === 'done'\"\n >\n <span class=\"flow-step-index\">{{ step.step }}</span>\n <span class=\"flow-step-content\">\n <span class=\"flow-step-label\">{{ step.label }}</span>\n <span class=\"flow-step-detail\">{{ getFlowStepDetail(step.step) }}</span>\n </span>\n </div>\n </div>\n <div class=\"assistant-nav\">\n <div\n class=\"assistant-tabs\"\n role=\"tablist\"\n aria-label=\"Se\u00E7\u00F5es do assistente\"\n (keydown)=\"onTabsKeydown($event)\"\n >\n <button\n class=\"assistant-tab\"\n type=\"button\"\n *ngIf=\"isTaskMode()\"\n id=\"assistant-tab-task\"\n role=\"tab\"\n aria-label=\"Proposta atual\"\n [attr.aria-selected]=\"isActiveTab('task')\"\n aria-controls=\"assistant-panel-task\"\n [attr.tabindex]=\"isActiveTab('task') ? 0 : -1\"\n [class.active]=\"isActiveTab('task')\"\n (click)=\"setActiveTab('task')\"\n >\n Proposta\n <span *ngIf=\"hasPendingClarification() && !isActiveTab('task')\" class=\"assistant-tab-badge\">1</span>\n </button>\n <button\n class=\"assistant-tab\"\n type=\"button\"\n id=\"assistant-tab-chat\"\n role=\"tab\"\n aria-label=\"Hist\u00F3rico\"\n [attr.aria-selected]=\"isActiveTab('chat')\"\n aria-controls=\"assistant-panel-chat\"\n [attr.tabindex]=\"isActiveTab('chat') ? 0 : -1\"\n [class.active]=\"isActiveTab('chat')\"\n (click)=\"setActiveTab('chat')\"\n >\n Hist\u00F3rico\n </button>\n <button\n class=\"assistant-tab\"\n type=\"button\"\n id=\"assistant-tab-suggestions\"\n role=\"tab\"\n aria-label=\"Sugest\u00F5es de melhoria\"\n [attr.aria-selected]=\"isActiveTab('suggestions')\"\n aria-controls=\"assistant-panel-suggestions\"\n [attr.tabindex]=\"isActiveTab('suggestions') ? 0 : -1\"\n [class.active]=\"isActiveTab('suggestions')\"\n (click)=\"setActiveTab('suggestions')\"\n >\n Sugest\u00F5es\n </button>\n </div>\n </div>\n\n <!-- BODY: Dynamic Content based on State -->\n <div class=\"assistant-body\">\n <div class=\"assistant-thought assistant-section\" *ngIf=\"shouldShowThoughtCard()\">\n <div class=\"assistant-thought-meta\">\n <mat-icon>psychology</mat-icon>\n <span>{{ getThoughtTimingLabel() }}</span>\n </div>\n <div class=\"assistant-thought-summary\">{{ getThoughtSummary() }}</div>\n <div class=\"assistant-thought-plan\">\n <div class=\"assistant-thought-plan-title\">{{ getThoughtPlanTitle() }}</div>\n <div class=\"assistant-thought-plan-actions\">\n <button\n mat-stroked-button\n type=\"button\"\n class=\"thought-action-details\"\n (click)=\"openThoughtDetails()\"\n [attr.aria-label]=\"getThoughtDetailsLabel()\"\n [matTooltip]=\"getThoughtDetailsTooltip()\"\n >\n {{ getThoughtDetailsLabel() }}\n </button>\n <button\n *ngIf=\"shouldShowThoughtPreviewAction()\"\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n class=\"thought-action-preview\"\n (click)=\"openThoughtPreview()\"\n [matTooltip]=\"getThoughtPreviewTooltip()\"\n >\n Pr\u00E9via\n </button>\n </div>\n <div class=\"assistant-thought-plan-hint\">{{ getThoughtActionHint() }}</div>\n <ng-container *ngIf=\"getThoughtChecklist() as thoughtChecklist\">\n <div class=\"assistant-thought-checklist\" *ngIf=\"thoughtChecklist.length\">\n <div *ngFor=\"let item of thoughtChecklist\" class=\"assistant-thought-checklist-item\">\n <mat-icon>radio_button_unchecked</mat-icon>\n <span>{{ item }}</span>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n <div *ngIf=\"processingInfoVisible\" class=\"processing-banner\">\n <mat-spinner diameter=\"16\"></mat-spinner>\n <span>{{ aiExplanation || 'Analisando solicita\u00E7\u00E3o e preparando proposta...' }}</span>\n <button mat-button type=\"button\" class=\"processing-retry\" (click)=\"retryProcessing()\">Tentar novamente</button>\n </div>\n <div\n class=\"assistant-history assistant-section\"\n *ngIf=\"historyContext && isActiveTab('chat')\"\n id=\"assistant-panel-chat\"\n role=\"tabpanel\"\n aria-labelledby=\"assistant-tab-chat\"\n >\n <div class=\"section-header\">\n <div class=\"section-heading\">\n <div class=\"section-title\">Hist\u00F3rico</div>\n <div class=\"section-subtitle\">Sess\u00F5es recentes, pedidos reaproveit\u00E1veis e desfazer r\u00E1pido.</div>\n </div>\n <div class=\"history-actions\" role=\"group\" aria-label=\"A\u00E7\u00F5es do hist\u00F3rico\">\n <button\n mat-stroked-button\n type=\"button\"\n class=\"history-action-btn\"\n (click)=\"historyExpanded = !historyExpanded\"\n [matTooltip]=\"historyExpanded ? 'Recolher hist\u00F3rico' : 'Expandir hist\u00F3rico'\"\n [attr.aria-label]=\"historyExpanded ? 'Recolher hist\u00F3rico' : 'Expandir hist\u00F3rico'\"\n [disabled]=\"!historyWarnings.length && !historySessions.length && !activeHistoryMessages.length\"\n >\n <mat-icon>{{ historyExpanded ? 'expand_less' : 'expand_more' }}</mat-icon>\n <span>{{ historyExpanded ? 'Recolher' : 'Expandir' }}</span>\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n class=\"history-action-btn\"\n (click)=\"startNewSession()\"\n matTooltip=\"Nova conversa\"\n aria-label=\"Nova conversa\"\n [disabled]=\"isBusyState()\"\n >\n <mat-icon>add_comment</mat-icon>\n <span>Nova conversa</span>\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n (click)=\"clearHistory()\"\n matTooltip=\"Limpar hist\u00F3rico local\"\n aria-label=\"Limpar hist\u00F3rico local\"\n class=\"history-action-btn history-action-btn--danger\"\n [disabled]=\"!historySessions.length\"\n >\n <mat-icon>delete_outline</mat-icon>\n <span>Limpar</span>\n </button>\n </div>\n </div>\n <div *ngIf=\"historyUndoDeleteSession\" class=\"history-undo\">\n <span>Sess\u00E3o removida.</span>\n <button mat-button type=\"button\" (click)=\"undoRemoveHistorySession()\">\n Desfazer\n </button>\n </div>\n\n <div *ngIf=\"historyExpanded && historyWarnings.length\" class=\"history-warnings\">\n <mat-icon>info</mat-icon>\n <div class=\"history-warnings-list\">\n <div *ngFor=\"let warning of historyWarnings\">{{ warning }}</div>\n <div class=\"history-warnings-hint\">\n Configure headers via API_CONFIG_STORAGE_OPTIONS no host.\n </div>\n </div>\n </div>\n\n <div *ngIf=\"historyExpanded && historySessions.length\" class=\"history-sessions\">\n <div\n class=\"history-session\"\n *ngFor=\"let session of historySessions\"\n role=\"button\"\n tabindex=\"0\"\n (click)=\"selectHistorySession(session.id)\"\n (keydown)=\"onHistorySessionCardKeydown($event, session.id)\"\n [class.active]=\"session.id === activeHistorySession?.id\"\n [matTooltip]=\"getHistorySessionTooltip(session)\"\n [matTooltipDisabled]=\"!session.componentType && !session.componentId\"\n >\n <div class=\"history-session-main\">\n <span class=\"history-session-title\">{{ session.title }}</span>\n <div class=\"history-session-main-right\">\n <span class=\"history-session-time\">{{ session.updatedAt | date:'short' }}</span>\n <div class=\"history-session-tools\">\n <button\n mat-icon-button\n type=\"button\"\n class=\"history-session-tool\"\n (click)=\"reuseHistorySessionPrompt(session.id, $event)\"\n matTooltip=\"Reusar \u00FAltimo pedido\"\n aria-label=\"Reusar \u00FAltimo pedido\"\n >\n <mat-icon>edit_note</mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n class=\"history-session-tool history-session-tool--danger\"\n (click)=\"removeHistorySession(session.id, $event)\"\n matTooltip=\"Excluir sess\u00E3o\"\n aria-label=\"Excluir sess\u00E3o\"\n >\n <mat-icon>delete_outline</mat-icon>\n </button>\n </div>\n </div>\n </div>\n <div class=\"history-session-meta\">\n <span *ngIf=\"session.componentType\" class=\"history-chip\">{{ session.componentType }}</span>\n <span *ngIf=\"session.componentId\" class=\"history-chip\">{{ session.componentId }}</span>\n </div>\n </div>\n </div>\n <div *ngIf=\"historyExpanded && !historySessions.length\" class=\"history-empty\">\n Nenhuma sess\u00E3o salva ainda.\n </div>\n\n <div *ngIf=\"historyExpanded && activeHistoryMessages.length\" class=\"history-messages\">\n <div\n *ngIf=\"activeHistoryTotalMessages > activeHistoryMessages.length\"\n class=\"history-messages-hint\"\n >\n Mostrando \u00FAltimas {{ activeHistoryMessages.length }} de {{ activeHistoryTotalMessages }} mensagens.\n </div>\n <div\n *ngFor=\"let msg of activeHistoryMessages\"\n class=\"history-message\"\n [class.user]=\"msg.role === 'user'\"\n [class.assistant]=\"msg.role === 'assistant'\"\n >\n <div class=\"history-message-header\">\n <span class=\"history-message-role\">{{ msg.role === 'user' ? 'Voc\u00EA' : 'Assistente' }}</span>\n <span class=\"history-message-time\">{{ msg.createdAt | date:'shortTime' }}</span>\n <span\n *ngIf=\"msg.context?.usedRag\"\n class=\"history-rag\"\n matTooltip=\"Resposta baseada em contexto recuperado (RAG)\"\n >RAG</span>\n </div>\n <div class=\"history-message-text\">{{ msg.text }}</div>\n </div>\n </div>\n <div *ngIf=\"historyExpanded && historySessions.length && !activeHistoryMessages.length\" class=\"history-empty history-empty--panel\">\n Selecione uma sess\u00E3o para visualizar as mensagens.\n </div>\n <div class=\"history-helper\" *ngIf=\"historyExpanded\">\n O hist\u00F3rico \u00E9 local ao usu\u00E1rio e ao componente atual.\n </div>\n </div>\n\n <div\n class=\"loading-suggestions assistant-section\"\n *ngIf=\"loadingSuggestions && isActiveTab('suggestions')\"\n id=\"assistant-panel-suggestions\"\n role=\"tabpanel\"\n aria-labelledby=\"assistant-tab-suggestions\"\n >\n <mat-spinner diameter=\"20\"></mat-spinner>\n <span>Carregando sugest\u00F5es de melhoria...</span>\n </div>\n \n <!-- STATE: LISTENING (Suggestions) -->\n <div\n *ngIf=\"state === 'listening' && isActiveTab('suggestions')\"\n class=\"suggestions-area assistant-section\"\n id=\"assistant-panel-suggestions\"\n role=\"tabpanel\"\n aria-labelledby=\"assistant-tab-suggestions\"\n >\n <div class=\"section-header\">\n <div class=\"section-title\">Sugest\u00F5es de melhoria</div>\n <div class=\"suggestions-actions\">\n <button mat-icon-button type=\"button\" (click)=\"refreshSuggestions()\" [disabled]=\"loadingSuggestions\" matTooltip=\"Atualizar sugest\u00F5es\">\n <mat-icon>refresh</mat-icon>\n </button>\n </div>\n </div>\n <div class=\"suggestions-hero\" *ngIf=\"!loadingSuggestions\">\n <div class=\"suggestions-hero__label\">Contexto ativo</div>\n <div class=\"suggestions-hero__title\">{{ adapter.componentName || 'Componente atual' }}</div>\n <div class=\"suggestions-hero__detail\">{{ getSystemStatusDetail() }}</div>\n </div>\n <div *ngIf=\"suggestionsWarnings.length\" class=\"warnings-area\">\n <mat-icon class=\"warnings-icon\">warning_amber</mat-icon>\n <div class=\"warnings-content\">\n <div class=\"warnings-title\">Avisos</div>\n <div class=\"warnings-list\">\n <div *ngFor=\"let warning of suggestionsWarnings\">{{ warning }}</div>\n </div>\n </div>\n </div>\n <div class=\"suggestions-content\" *ngIf=\"!loadingSuggestions && (richSuggestions.length || hasDismissedSuggestions())\">\n <div class=\"suggestions-filter\" *ngIf=\"hasDismissedSuggestions()\">\n <span>{{ getDismissedSuggestionCount() }} oculta(s)</span>\n <button mat-button type=\"button\" (click)=\"restoreDismissedSuggestions()\">\n Restaurar\n </button>\n </div>\n <div class=\"suggestions-list\" *ngIf=\"getVisibleSuggestions().length; else allSuggestionsHidden\">\n <div\n class=\"suggestion-item\"\n *ngFor=\"let sug of getVisibleSuggestions()\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"'Selecionar sugest\u00E3o: ' + sug.label\"\n (click)=\"selectSuggestion(sug)\"\n (keydown)=\"onSuggestionCardKeydown($event, sug)\"\n >\n <div class=\"suggestion-copy\">\n <div class=\"suggestion-main\">\n <mat-icon *ngIf=\"sug.icon\" class=\"suggestion-icon\">{{ sug.icon }}</mat-icon>\n <span class=\"suggestion-label\">{{ sug.label }}</span>\n <span *ngIf=\"sug.group\" class=\"suggestion-group\">{{ sug.group }}</span>\n </div>\n <div *ngIf=\"sug.description\" class=\"suggestion-desc\">{{ sug.description }}</div>\n </div>\n <div class=\"suggestion-actions\">\n <span class=\"suggestion-arrow\" aria-hidden=\"true\">\n <mat-icon>chevron_right</mat-icon>\n </span>\n <button\n mat-icon-button\n type=\"button\"\n class=\"suggestion-action-btn\"\n (click)=\"prepareSuggestionPrompt(sug, $event)\"\n matTooltip=\"Refinar pedido\"\n aria-label=\"Refinar pedido\"\n >\n <mat-icon>edit</mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n class=\"suggestion-action-btn suggestion-action-btn--danger\"\n (click)=\"dismissSuggestion(sug, $event)\"\n matTooltip=\"Ocultar sugest\u00E3o\"\n aria-label=\"Ocultar sugest\u00E3o\"\n >\n <mat-icon>visibility_off</mat-icon>\n </button>\n </div>\n </div>\n </div>\n <ng-template #allSuggestionsHidden>\n <div class=\"suggestions-empty suggestions-empty--inline\">\n Todas as sugest\u00F5es foram ocultadas.\n </div>\n </ng-template>\n </div>\n <div class=\"suggestions-empty\" *ngIf=\"!loadingSuggestions && !richSuggestions.length\">\n Nenhuma sugest\u00E3o dispon\u00EDvel no momento.\n </div>\n <div class=\"suggestions-helper\" *ngIf=\"!loadingSuggestions && !richSuggestions.length\">\n Selecione uma sugest\u00E3o acima ou descreva uma altera\u00E7\u00E3o no campo inferior.\n </div>\n </div>\n\n <!-- STATE: CLARIFICATION (Two-Step Flow) -->\n <div\n *ngIf=\"state === 'clarification' && isActiveTab('task')\"\n class=\"clarification-area assistant-card\"\n id=\"assistant-panel-task\"\n role=\"tabpanel\"\n aria-labelledby=\"assistant-tab-task\"\n >\n <div class=\"task-header\" *ngIf=\"!shouldShowThoughtCard()\">\n <div class=\"task-title\">{{ getTaskTitle() }}</div>\n <div class=\"task-subtitle\">{{ getTaskSubtitle() }}</div>\n <div *ngIf=\"clarificationOptions.length > 1 && getTaskSelectionSummary() as selectionSummary\" class=\"task-meta\">\n <span class=\"task-meta-label\">Selecionado:</span>\n <span class=\"task-meta-value\">{{ selectionSummary }}</span>\n </div>\n <div *ngIf=\"shouldShowTaskSteps()\" class=\"task-steps\">\n <span class=\"task-step active\">1 Dados</span>\n <span class=\"task-step\">2 Layout</span>\n <span class=\"task-step\">3 Revis\u00E3o</span>\n </div>\n </div>\n <div *ngIf=\"clarificationResponseType === 'context'\" class=\"context-only\">\n <mat-spinner diameter=\"24\"></mat-spinner>\n <div class=\"context-only-hint\">Buscando contexto adicional...</div>\n </div>\n <ng-template #clarificationOptionContent let-opt let-index=\"index\" let-compact=\"compact\">\n <div class=\"clarification-decision-head\" *ngIf=\"!compact\">\n <span class=\"clarification-decision-index\">{{ index + 1 }}</span>\n <span class=\"clarification-decision-type\">{{ getClarificationOptionKindLabel(opt) }}</span>\n <span class=\"spacer\"></span>\n <span class=\"clarification-decision-state\" *ngIf=\"isClarificationSelected(opt)\">Selecionado</span>\n </div>\n <ng-container [ngSwitch]=\"getClarificationOptionLayout(opt)\">\n <div *ngSwitchCase=\"'endpoint'\" class=\"clarification-card\">\n <div class=\"clarification-card-header\">\n <mat-icon class=\"endpoint-icon\">{{ getEndpointIcon(opt) }}</mat-icon>\n <ng-container *ngIf=\"getEndpointMethod(opt) as method\">\n <span class=\"endpoint-method\" [attr.data-method]=\"method\">{{ method }}</span>\n </ng-container>\n <span class=\"endpoint-label\">{{ opt.label }}</span>\n <span class=\"spacer\"></span>\n <mat-icon class=\"select-indicator\">\n {{ isClarificationSelected(opt) ? 'check_circle' : 'radio_button_unchecked' }}\n </mat-icon>\n </div>\n <div class=\"clarification-card-body\">\n <ng-container *ngIf=\"getEndpointPath(opt) as path\">\n <div class=\"endpoint-path\">{{ path }}</div>\n </ng-container>\n <div\n *ngIf=\"opt.contextHints?.description\"\n class=\"endpoint-description\"\n [matTooltip]=\"getDescriptionTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowDescriptionTooltip(opt)\"\n >\n {{ opt.contextHints?.description }}\n </div>\n </div>\n </div>\n <div *ngSwitchCase=\"'color'\" class=\"clarification-color\">\n <span\n class=\"color-swatch\"\n [style.background]=\"getSafeHexColor(opt) || 'var(--md-sys-color-surface-container-highest)'\"\n ></span>\n <div class=\"color-meta\">\n <span class=\"color-label\">{{ opt.label }}</span>\n <span *ngIf=\"opt.contextHints?.hexColor\" class=\"color-value\">{{ opt.contextHints?.hexColor }}</span>\n </div>\n </div>\n <div *ngSwitchCase=\"'description'\" class=\"clarification-description\">\n <span class=\"clarification-label\">{{ opt.label }}</span>\n <span\n *ngIf=\"opt.contextHints?.description\"\n class=\"clarification-subtitle\"\n [matTooltip]=\"getDescriptionTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowDescriptionTooltip(opt)\"\n >\n {{ opt.contextHints?.description }}\n </span>\n </div>\n <span *ngSwitchDefault class=\"clarification-plain-label\">{{ opt.label }}</span>\n </ng-container>\n </ng-template>\n <div *ngIf=\"warnings.length\" class=\"warnings-area\">\n <mat-icon class=\"warnings-icon\">warning_amber</mat-icon>\n <div class=\"warnings-content\">\n <div class=\"warnings-title\">Avisos</div>\n <div class=\"warnings-list\">\n <div *ngFor=\"let warning of warnings\">{{ warning }}</div>\n </div>\n </div>\n </div>\n <div\n *ngIf=\"clarificationQuestions.length\"\n class=\"clarification-questions\"\n [class.attention-highlight]=\"highlightClarificationDetails && !clarificationOptions.length\"\n >\n <div *ngFor=\"let question of clarificationQuestions; let i = index\" class=\"clarification-question\">\n <div class=\"clarification-question-label\">{{ question }}</div>\n <input\n type=\"text\"\n [(ngModel)]=\"clarificationAnswers[i]\"\n [placeholder]=\"'Resposta ' + (i + 1)\"\n autocomplete=\"off\">\n </div>\n </div>\n <div\n *ngIf=\"clarificationOptions.length\"\n class=\"clarification-options-block\"\n [class.attention-highlight]=\"highlightClarificationDetails\"\n >\n <div class=\"clarification-options-title\">\n {{ clarificationOptions.length === 1 ? 'Decis\u00E3o sugerida' : 'Decis\u00F5es sugeridas' }}\n </div>\n <div *ngIf=\"clarificationOptions.length === 1\" class=\"clarification-options-hint\">\n Etapa 2 de 4: confirme a melhor op\u00E7\u00E3o para continuar.\n </div>\n <div *ngIf=\"clarificationOptions.length > 1\" class=\"clarification-options-hint\">\n Etapa 2 de 4: selecione a alternativa mais aderente para gerar a proposta.\n </div>\n <div\n *ngIf=\"clarificationResponseType === 'confirm'\"\n class=\"clarification-buttons\"\n [class.list]=\"clarificationPresentation === 'list'\"\n >\n <button\n mat-button\n type=\"button\"\n *ngFor=\"let opt of clarificationOptions; let i = index\"\n (click)=\"onClarificationOptionClick(opt)\"\n class=\"clarification-option\"\n [class.selected]=\"isClarificationSelected(opt)\"\n [matTooltip]=\"getClarificationTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowClarificationTooltip(opt) || isEndpointOption(opt)\"\n >\n <ng-container *ngTemplateOutlet=\"clarificationOptionContent; context: { $implicit: opt, index: i, compact: false }\"></ng-container>\n </button>\n </div>\n <div\n *ngIf=\"clarificationSelectionMode === 'multiple'\"\n class=\"clarification-buttons\"\n [class.list]=\"clarificationPresentation === 'list'\"\n >\n <button\n mat-button\n type=\"button\"\n *ngFor=\"let opt of clarificationOptions; let i = index\"\n (click)=\"onClarificationOptionClick(opt)\"\n [class.selected]=\"isClarificationSelected(opt)\"\n class=\"clarification-option\"\n [matTooltip]=\"getClarificationTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowClarificationTooltip(opt) || isEndpointOption(opt)\"\n >\n <ng-container *ngTemplateOutlet=\"clarificationOptionContent; context: { $implicit: opt, index: i, compact: false }\"></ng-container>\n </button>\n </div>\n <div\n *ngIf=\"clarificationResponseType !== 'confirm' && clarificationSelectionMode === 'single' && clarificationPresentation !== 'chips'\"\n class=\"clarification-buttons\"\n [class.list]=\"clarificationPresentation === 'list'\"\n >\n <button\n mat-button\n type=\"button\"\n *ngFor=\"let opt of clarificationOptions; let i = index\"\n (click)=\"onClarificationOptionClick(opt)\"\n class=\"clarification-option\"\n [class.selected]=\"isClarificationSelected(opt)\"\n [matTooltip]=\"getClarificationTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowClarificationTooltip(opt) || isEndpointOption(opt)\"\n >\n <ng-container *ngTemplateOutlet=\"clarificationOptionContent; context: { $implicit: opt, index: i, compact: false }\"></ng-container>\n </button>\n </div>\n <div\n *ngIf=\"clarificationResponseType !== 'confirm' && clarificationSelectionMode === 'single' && clarificationPresentation === 'chips'\"\n class=\"clarification-chips\"\n >\n <ng-container *ngFor=\"let opt of clarificationOptions; let i = index\">\n <button\n *ngIf=\"isEndpointOption(opt); else chipOption\"\n mat-button\n type=\"button\"\n class=\"clarification-option clarification-card-button\"\n (click)=\"onClarificationOptionClick(opt)\"\n [class.selected]=\"isClarificationSelected(opt)\"\n [matTooltip]=\"getClarificationTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowClarificationTooltip(opt) || isEndpointOption(opt)\"\n >\n <ng-container *ngTemplateOutlet=\"clarificationOptionContent; context: { $implicit: opt, index: i, compact: false }\"></ng-container>\n </button>\n <ng-template #chipOption>\n <mat-chip\n (click)=\"onClarificationOptionClick(opt)\"\n [matTooltip]=\"getClarificationTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowClarificationTooltip(opt)\"\n class=\"clarification-chip\"\n >\n <ng-container *ngTemplateOutlet=\"clarificationOptionContent; context: { $implicit: opt, index: i, compact: true }\"></ng-container>\n </mat-chip>\n </ng-template>\n </ng-container>\n </div>\n </div>\n <div\n *ngIf=\"clarificationAllowCustom && clarificationResponseType !== 'context'\"\n class=\"clarification-manual-toggle\"\n >\n <span class=\"clarification-manual-label\">N\u00E3o encontrou o recurso?</span>\n <button mat-button type=\"button\" (click)=\"toggleManualInput()\">\n {{ showManualInput ? 'Ocultar resposta manual' : 'Responder manualmente' }}\n </button>\n </div>\n <div\n *ngIf=\"clarificationAllowCustom && showManualInput && clarificationResponseType !== 'context'\"\n class=\"clarification-free\"\n >\n <input\n type=\"text\"\n [(ngModel)]=\"clarificationFreeText\"\n placeholder=\"Digite sua resposta\u2026\"\n autocomplete=\"off\"\n (keydown.enter)=\"confirmTaskAction()\"\n />\n </div>\n <div\n *ngIf=\"clarificationAllowCustom && showManualInput && clarificationResponseType !== 'context'\"\n class=\"clarification-free-hint\"\n >\n Pressione Enter para enviar.\n </div>\n </div>\n\n <!-- STATE: REVIEW (Diff/Explanation) -->\n <div\n *ngIf=\"state === 'review' && isActiveTab('task')\"\n class=\"review-area assistant-card\"\n id=\"assistant-panel-task\"\n role=\"tabpanel\"\n aria-labelledby=\"assistant-tab-task\"\n >\n <div class=\"task-header\" *ngIf=\"!shouldShowThoughtCard()\">\n <div class=\"task-title\">{{ getTaskTitle() }}</div>\n <div class=\"task-subtitle\">{{ getTaskSubtitle() }}</div>\n <div *ngIf=\"clarificationOptions.length > 1 && getTaskSelectionSummary() as selectionSummary\" class=\"task-meta\">\n <span class=\"task-meta-label\">Selecionado:</span>\n <span class=\"task-meta-value\">{{ selectionSummary }}</span>\n </div>\n <div *ngIf=\"shouldShowTaskSteps()\" class=\"task-steps\">\n <span class=\"task-step\">1 Dados</span>\n <span class=\"task-step\">2 Layout</span>\n <span class=\"task-step active\">3 Revis\u00E3o</span>\n </div>\n </div>\n <div *ngIf=\"warnings.length\" class=\"warnings-area\">\n <mat-icon class=\"warnings-icon\">warning_amber</mat-icon>\n <div class=\"warnings-content\">\n <div class=\"warnings-title\">Avisos</div>\n <div class=\"warnings-list\">\n <div *ngFor=\"let warning of warnings\">{{ warning }}</div>\n </div>\n </div>\n </div>\n <div class=\"review-trust\">\n <span class=\"trust-chip\" [matTooltip]=\"getScopeTooltip()\">{{ getScopeLabel() }}</span>\n <span class=\"trust-chip\" [matTooltip]=\"getConfidenceTooltip()\">{{ getConfidenceLabel() }}</span>\n <span class=\"trust-chip risk-chip\" [class.medium]=\"getReviewRiskLevel() === 'm\u00E9dio'\" [class.high]=\"getReviewRiskLevel() === 'alto'\">\n Risco {{ getReviewRiskLevel() }}\n </span>\n </div>\n <div class=\"review-summary\" [class.attention-highlight]=\"highlightReviewDetails\">\n <div class=\"review-summary-title\">Resumo da proposta</div>\n <div class=\"review-summary-line\">{{ getReviewSummary() }}</div>\n </div>\n <div class=\"review-diff\">\n <div class=\"review-diff-title\">Pr\u00E9via de mudan\u00E7as</div>\n <ng-container *ngIf=\"pendingDiff.length; else noDiffPreview\">\n <div class=\"review-diff-summary\">\n <div *ngFor=\"let line of getDiffSummaryLines()\" class=\"review-diff-line\">{{ line }}</div>\n <div *ngIf=\"pendingDiff.length > 3\" class=\"review-diff-more\">\u2026 +{{ pendingDiff.length - 3 }} mudan\u00E7as</div>\n </div>\n <button mat-stroked-button type=\"button\" class=\"review-diff-toggle\" (click)=\"toggleFullDiff()\">\n {{ getDiffToggleLabel() }}\n </button>\n </ng-container>\n <ng-template #noDiffPreview>\n <div class=\"review-diff-empty\">\n N\u00E3o foi poss\u00EDvel gerar um diff estruturado. Revise o resumo e aplique com cautela.\n </div>\n </ng-template>\n <div *ngIf=\"showFullDiff && pendingDiff.length\" class=\"review-diff-full\">\n <div *ngFor=\"let diff of pendingDiff\" class=\"review-diff-block\">\n <div class=\"review-diff-path\">{{ diff.path }}</div>\n <div class=\"review-diff-label\">Antes:</div>\n <pre>{{ diff.before | json }}</pre>\n <div class=\"review-diff-label\">Depois:</div>\n <pre>{{ diff.after | json }}</pre>\n </div>\n </div>\n </div>\n <div class=\"ai-explanation\" *ngIf=\"aiExplanation.trim()\">\n {{ aiExplanation }}\n </div>\n </div>\n\n <!-- STATE: ERROR -->\n <div\n *ngIf=\"state === 'error' && (isActiveTab('task') || (!isTaskMode() && isActiveTab('suggestions')))\"\n class=\"error-area assistant-card\"\n [attr.id]=\"isTaskMode() ? 'assistant-panel-task' : 'assistant-panel-suggestions'\"\n role=\"tabpanel\"\n [attr.aria-labelledby]=\"isTaskMode() ? 'assistant-tab-task' : 'assistant-tab-suggestions'\"\n >\n <div class=\"error-msg\">\n <mat-icon color=\"warn\">error_outline</mat-icon>\n <span>{{ errorMsg }}</span>\n </div>\n <div *ngIf=\"warnings.length\" class=\"warnings-area\">\n <mat-icon class=\"warnings-icon\">warning_amber</mat-icon>\n <div class=\"warnings-content\">\n <div class=\"warnings-title\">Avisos</div>\n <div class=\"warnings-list\">\n <div *ngFor=\"let warning of warnings\">{{ warning }}</div>\n </div>\n </div>\n </div>\n <div *ngIf=\"shouldShowApplyDetails()\" class=\"apply-details\">\n <div class=\"apply-details-header\">\n <div class=\"apply-details-title\">Detalhes da aplica\u00E7\u00E3o</div>\n <div class=\"apply-details-actions\" *ngIf=\"allowManualPatchEdit\">\n <button mat-button type=\"button\" (click)=\"togglePatchPathEditor()\" [disabled]=\"!pendingPatch\">\n {{ patchPathEditorExpanded ? 'Ocultar paths' : 'Editar por path' }}\n </button>\n <button mat-button type=\"button\" (click)=\"togglePatchEditor()\" [disabled]=\"!pendingPatch\">\n {{ patchEditorExpanded ? 'Ocultar editor' : 'Editar patch' }}\n </button>\n </div>\n </div>\n <div class=\"apply-details-meta\" *ngIf=\"lastApplyAt\">\n \u00DAltima tentativa: {{ lastApplyAt | date:'short' }}\n </div>\n <div class=\"apply-paths\" *ngIf=\"getApplyPaths().length\">\n <span class=\"apply-path-chip\" *ngFor=\"let path of getApplyPaths()\">{{ path }}</span>\n </div>\n <div class=\"apply-warnings\" *ngIf=\"applyWarnings.length\">\n <div class=\"apply-warnings-title\">Avisos da aplica\u00E7\u00E3o</div>\n <div class=\"apply-warnings-list\">\n <div *ngFor=\"let warning of applyWarnings\">{{ warning }}</div>\n </div>\n </div>\n <div class=\"patch-path-editor\" *ngIf=\"allowManualPatchEdit && patchPathEditorExpanded\">\n <div class=\"patch-editor-label\">Editar por path</div>\n <div class=\"patch-editor-hint\">Texto simples vira string; para for\u00E7ar texto em true/false/n\u00FAmero, use aspas.</div>\n <div class=\"patch-path-editor-empty\" *ngIf=\"!getEditablePatchPathEdits().length\">\n Nenhum path edit\u00E1vel dispon\u00EDvel para este patch.\n </div>\n <div class=\"patch-path-rows\" *ngIf=\"getEditablePatchPathEdits().length\">\n <div class=\"patch-path-row\" *ngFor=\"let edit of getEditablePatchPathEdits(); let i = index\">\n <div class=\"patch-path-label\">{{ edit.path }}</div>\n <input\n type=\"text\"\n [(ngModel)]=\"patchPathEdits[i].valueText\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n />\n <div *ngIf=\"patchPathEdits[i].error\" class=\"patch-editor-error\">{{ patchPathEdits[i].error }}</div>\n </div>\n </div>\n <div *ngIf=\"patchPathEditorError\" class=\"patch-editor-error\">{{ patchPathEditorError }}</div>\n <div class=\"patch-editor-actions\">\n <button mat-button type=\"button\" (click)=\"resetPatchPathEdits()\">\n Restaurar valores\n </button>\n <button mat-button type=\"button\" (click)=\"applyPathEditsToPatch()\">\n Aplicar no patch\n </button>\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"reapplyPathEdits()\">\n Reaplicar por path\n </button>\n </div>\n </div>\n <div class=\"patch-editor\" *ngIf=\"allowManualPatchEdit && patchEditorExpanded\">\n <label class=\"patch-editor-label\">Patch JSON</label>\n <textarea\n [(ngModel)]=\"patchEditorText\"\n spellcheck=\"false\"\n ></textarea>\n <div *ngIf=\"patchEditorError\" class=\"patch-editor-error\">{{ patchEditorError }}</div>\n <div class=\"patch-editor-actions\">\n <button mat-button type=\"button\" (click)=\"resetPatchEditor()\">\n Restaurar original\n </button>\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"reapplyEditedPatch()\">\n Reaplicar patch\n </button>\n </div>\n </div>\n </div>\n <div class=\"review-actions\">\n <button mat-button (click)=\"close()\">Fechar</button>\n <button mat-stroked-button (click)=\"retry()\">Tentar Novamente</button>\n </div>\n </div>\n\n <!-- STATE: SUCCESS -->\n <div\n *ngIf=\"state === 'success' && (isActiveTab('task') || (!isTaskMode() && isActiveTab('suggestions')))\"\n class=\"success-area assistant-card\"\n [attr.id]=\"isTaskMode() ? 'assistant-panel-task' : 'assistant-panel-suggestions'\"\n role=\"tabpanel\"\n [attr.aria-labelledby]=\"isTaskMode() ? 'assistant-tab-task' : 'assistant-tab-suggestions'\"\n >\n <div class=\"success-msg\">\n <mat-icon class=\"success-icon\">check_circle</mat-icon>\n <span>{{ aiExplanation || 'Configura\u00E7\u00E3o atualizada.' }}</span>\n </div>\n <div *ngIf=\"warnings.length\" class=\"warnings-area\">\n <mat-icon class=\"warnings-icon\">warning_amber</mat-icon>\n <div class=\"warnings-content\">\n <div class=\"warnings-title\">Avisos</div>\n <div class=\"warnings-list\">\n <div *ngFor=\"let warning of warnings\">{{ warning }}</div>\n </div>\n </div>\n </div>\n <div *ngIf=\"shouldShowApplyDetails()\" class=\"apply-details\">\n <div class=\"apply-details-header\">\n <div class=\"apply-details-title\">Detalhes da aplica\u00E7\u00E3o</div>\n <div class=\"apply-details-actions\" *ngIf=\"allowManualPatchEdit\">\n <button mat-button type=\"button\" (click)=\"togglePatchPathEditor()\" [disabled]=\"!pendingPatch\">\n {{ patchPathEditorExpanded ? 'Ocultar paths' : 'Editar por path' }}\n </button>\n <button mat-button type=\"button\" (click)=\"togglePatchEditor()\" [disabled]=\"!pendingPatch\">\n {{ patchEditorExpanded ? 'Ocultar editor' : 'Editar e reaplicar' }}\n </button>\n </div>\n </div>\n <div class=\"apply-details-meta\" *ngIf=\"lastApplyAt\">\n Aplicado em {{ lastApplyAt | date:'short' }}\n </div>\n <div class=\"apply-paths\" *ngIf=\"getApplyPaths().length\">\n <span class=\"apply-path-chip\" *ngFor=\"let path of getApplyPaths()\">{{ path }}</span>\n </div>\n <div class=\"apply-warnings\" *ngIf=\"applyWarnings.length\">\n <div class=\"apply-warnings-title\">Avisos da aplica\u00E7\u00E3o</div>\n <div class=\"apply-warnings-list\">\n <div *ngFor=\"let warning of applyWarnings\">{{ warning }}</div>\n </div>\n </div>\n <div class=\"patch-path-editor\" *ngIf=\"allowManualPatchEdit && patchPathEditorExpanded\">\n <div class=\"patch-editor-label\">Editar por path</div>\n <div class=\"patch-editor-hint\">Texto simples vira string; para for\u00E7ar texto em true/false/n\u00FAmero, use aspas.</div>\n <div class=\"patch-path-editor-empty\" *ngIf=\"!getEditablePatchPathEdits().length\">\n Nenhum path edit\u00E1vel dispon\u00EDvel para este patch.\n </div>\n <div class=\"patch-path-rows\" *ngIf=\"getEditablePatchPathEdits().length\">\n <div class=\"patch-path-row\" *ngFor=\"let edit of getEditablePatchPathEdits(); let i = index\">\n <div class=\"patch-path-label\">{{ edit.path }}</div>\n <input\n type=\"text\"\n [(ngModel)]=\"patchPathEdits[i].valueText\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n />\n <div *ngIf=\"patchPathEdits[i].error\" class=\"patch-editor-error\">{{ patchPathEdits[i].error }}</div>\n </div>\n </div>\n <div *ngIf=\"patchPathEditorError\" class=\"patch-editor-error\">{{ patchPathEditorError }}</div>\n <div class=\"patch-editor-actions\">\n <button mat-button type=\"button\" (click)=\"resetPatchPathEdits()\">\n Restaurar valores\n </button>\n <button mat-button type=\"button\" (click)=\"applyPathEditsToPatch()\">\n Aplicar no patch\n </button>\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"reapplyPathEdits()\">\n Reaplicar por path\n </button>\n </div>\n </div>\n <div class=\"patch-editor\" *ngIf=\"allowManualPatchEdit && patchEditorExpanded\">\n <label class=\"patch-editor-label\">Patch JSON</label>\n <textarea\n [(ngModel)]=\"patchEditorText\"\n spellcheck=\"false\"\n ></textarea>\n <div *ngIf=\"patchEditorError\" class=\"patch-editor-error\">{{ patchEditorError }}</div>\n <div class=\"patch-editor-actions\">\n <button mat-button type=\"button\" (click)=\"resetPatchEditor()\">\n Restaurar original\n </button>\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"reapplyEditedPatch()\">\n Reaplicar patch\n </button>\n </div>\n </div>\n </div>\n <button mat-button color=\"warn\" (click)=\"undoLastChange()\">\n <mat-icon>undo</mat-icon> Desfazer\n </button>\n </div>\n\n </div>\n\n <div class=\"assistant-footer\">\n <ng-container *ngIf=\"!isTaskMode(); else taskFooter\">\n <button\n mat-icon-button\n type=\"button\"\n class=\"composer-leading composer-leading-btn\"\n [matMenuTriggerFor]=\"assistantQuickMenu\"\n aria-label=\"Abrir a\u00E7\u00F5es r\u00E1pidas\"\n matTooltip=\"A\u00E7\u00F5es r\u00E1pidas\"\n >\n <mat-icon>add</mat-icon>\n </button>\n <input\n #inputEl\n type=\"text\"\n [(ngModel)]=\"userPrompt\"\n [disabled]=\"state === 'processing' || state === 'applying'\"\n placeholder=\"Descreva a altera\u00E7\u00E3o que deseja aplicar\u2026\"\n autocomplete=\"off\"\n />\n <div class=\"send-actions\">\n <button\n mat-icon-button\n class=\"send-btn\"\n *ngIf=\"state === 'listening'\"\n (click)=\"submitPrompt()\"\n [disabled]=\"!userPrompt.trim()\"\n [class.ready]=\"!!userPrompt.trim()\"\n >\n <mat-icon>arrow_upward</mat-icon>\n </button>\n <mat-spinner diameter=\"20\" *ngIf=\"state === 'processing' || state === 'applying'\"></mat-spinner>\n </div>\n </ng-container>\n <ng-template #taskFooter>\n <div class=\"task-footer\">\n <div class=\"task-footer-left\">\n <button mat-button type=\"button\" (click)=\"handleTaskSecondary()\">{{ getTaskCancelLabel() }}</button>\n <button\n *ngIf=\"state === 'review'\"\n mat-stroked-button\n type=\"button\"\n (click)=\"retry()\"\n >\n {{ getTaskSecondaryLabel() }}\n </button>\n </div>\n <div class=\"task-footer-right\">\n <button\n class=\"task-primary-btn\"\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n (click)=\"confirmTaskAction()\"\n [disabled]=\"isTaskPrimaryDisabled()\"\n >\n {{ getTaskPrimaryLabel() }}\n </button>\n <mat-spinner diameter=\"20\" *ngIf=\"state === 'processing' || state === 'applying'\"></mat-spinner>\n </div>\n </div>\n </ng-template>\n </div>\n\n <mat-menu #assistantQuickMenu=\"matMenu\" panelClass=\"assistant-quick-menu-panel\">\n <button mat-menu-item type=\"button\" (click)=\"setActiveTab('chat')\">\n <mat-icon>history</mat-icon>\n <span>Hist\u00F3rico</span>\n </button>\n <button mat-menu-item type=\"button\" (click)=\"setActiveTab('suggestions')\">\n <mat-icon>lightbulb</mat-icon>\n <span>Sugest\u00F5es</span>\n </button>\n <button mat-menu-item type=\"button\" (click)=\"startNewSession()\">\n <mat-icon>add_comment</mat-icon>\n <span>Nova conversa</span>\n </button>\n <button mat-menu-item type=\"button\" (click)=\"refreshSuggestions()\" [disabled]=\"loadingSuggestions\">\n <mat-icon>refresh</mat-icon>\n <span>Atualizar sugest\u00F5es</span>\n </button>\n <button\n mat-menu-item\n type=\"button\"\n (click)=\"restoreDismissedSuggestions()\"\n [disabled]=\"!hasDismissedSuggestions()\"\n >\n <mat-icon>visibility</mat-icon>\n <span>Restaurar sugest\u00F5es ocultas</span>\n </button>\n <button\n mat-menu-item\n type=\"button\"\n class=\"assistant-quick-menu-danger\"\n (click)=\"clearHistory()\"\n [disabled]=\"!historySessions.length\"\n >\n <mat-icon>delete_outline</mat-icon>\n <span>Limpar hist\u00F3rico local</span>\n </button>\n </mat-menu>\n </div>\n\n</ng-template>\n", styles: ["@keyframes assistantPremiumEnter{0%{opacity:0;transform:translate(14px) scale(.99)}to{opacity:1;transform:translate(0) scale(1)}}:host ::ng-deep .ai-assistant-backdrop{background:color-mix(in srgb,var(--md-sys-color-scrim, var(--md-sys-color-shadow, var(--md-sys-color-on-surface))) 42%,transparent);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}::ng-deep .ai-assistant-overlay-pane{max-width:calc(100vw - 24px);max-height:calc(100vh - 24px)}.ai-assistant-panel{box-sizing:border-box;width:min(604px,100vw - 18px);min-height:min(620px,100vh - 18px);max-height:min(820px,100vh - 18px);display:flex;flex-direction:column;overflow:hidden;color:var(--md-sys-color-on-surface);border-left:1px solid color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));border-top:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));box-shadow:0 18px 48px color-mix(in srgb,var(--md-sys-color-shadow, var(--md-sys-color-on-surface)) 42%,transparent),inset 0 1px color-mix(in srgb,var(--md-sys-color-on-surface) 10%,transparent);background:radial-gradient(circle at 14% 8%,color-mix(in srgb,var(--md-sys-color-primary-container) 38%,transparent) 0%,transparent 44%),linear-gradient(165deg,color-mix(in srgb,var(--md-sys-color-surface-container-highest) 88%,var(--md-sys-color-surface)),var(--md-sys-color-surface));animation:assistantPremiumEnter .24s cubic-bezier(.22,1,.36,1)}.assistant-header{position:relative;display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:12px 16px 10px;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));background:linear-gradient(130deg,color-mix(in srgb,var(--md-sys-color-primary-container) 28%,transparent) 0%,transparent 52%),var(--md-sys-color-surface-container-low)}.assistant-header:after{content:\"\";position:absolute;left:16px;right:16px;bottom:-1px;height:1px;background:linear-gradient(90deg,color-mix(in srgb,var(--md-sys-color-primary) 55%,transparent),transparent);pointer-events:none}.assistant-header .assistant-header__left{min-width:0;display:flex;align-items:flex-start;gap:12px}.assistant-header .magic-icon{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;width:30px;height:30px;font-size:18px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 30%,transparent);box-shadow:0 4px 12px color-mix(in srgb,var(--md-sys-color-primary) 26%,transparent)}.assistant-header .assistant-title-group{min-width:0;display:flex;flex-direction:column;gap:4px}.assistant-header .assistant-title{font-size:15px;font-weight:700;letter-spacing:.01em;overflow-wrap:anywhere}.assistant-header .assistant-subtitle{display:block;font-size:11px;line-height:1.25;color:color-mix(in srgb,var(--md-sys-color-on-surface) 70%,var(--md-sys-color-on-surface-variant));overflow-wrap:anywhere}.assistant-header-chips{display:inline-flex;align-items:center;flex-wrap:wrap;gap:6px}.assistant-header .mode-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 28%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-primary-container) 64%,var(--md-sys-color-surface-container));color:color-mix(in srgb,var(--md-sys-color-on-primary-container) 85%,var(--md-sys-color-on-surface));font-size:10px;font-weight:700;letter-spacing:.04em;text-transform:uppercase}.assistant-header .mode-chip:before{content:\"\";width:6px;height:6px;border-radius:999px;background:currentColor;box-shadow:0 0 0 3px color-mix(in srgb,currentColor 16%,transparent)}.assistant-header .mode-chip.mock{border-color:color-mix(in srgb,var(--md-sys-color-error) 34%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-error-container) 72%,var(--md-sys-color-surface-container));color:color-mix(in srgb,var(--md-sys-color-on-error-container) 85%,var(--md-sys-color-error))}.assistant-header .policy-chip{padding:2px 8px;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 84%,transparent);background:var(--md-sys-color-surface-container-high);font-size:10px;letter-spacing:.02em;font-weight:600}.assistant-header .policy-chip.strict{border-color:color-mix(in srgb,var(--md-sys-color-primary) 42%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-primary-container) 56%,var(--md-sys-color-surface-container-high))}.assistant-status{display:flex;align-items:flex-start;gap:10px;padding:10px 16px;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));border-radius:0;background:linear-gradient(160deg,color-mix(in srgb,var(--md-sys-color-primary-container) 24%,transparent),transparent 48%),var(--md-sys-color-surface-container-low)}.assistant-status-dot{width:8px;height:8px;margin-top:6px;border-radius:999px;flex:0 0 auto;background:var(--md-sys-color-primary);box-shadow:0 0 0 4px color-mix(in srgb,var(--md-sys-color-primary) 16%,transparent)}.assistant-status.warning .assistant-status-dot{background:var(--md-sys-color-error);box-shadow:0 0 0 4px color-mix(in srgb,var(--md-sys-color-error) 16%,transparent)}.assistant-status.success .assistant-status-dot{background:color-mix(in srgb,var(--md-sys-color-primary) 74%,var(--md-sys-color-tertiary, var(--md-sys-color-primary)))}.assistant-status-content{min-width:0;display:flex;flex-direction:column;gap:2px}.assistant-status-label{display:flex;align-items:center;flex-wrap:wrap;gap:4px;font-size:12px;font-weight:700;line-height:1.35}.assistant-status-detail{font-size:11px;line-height:1.4;color:var(--md-sys-color-on-surface-variant);overflow-wrap:anywhere}.assistant-status-mode{padding:1px 6px;border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-primary-container) 72%,transparent);color:var(--md-sys-color-on-primary-container);font-size:10px;font-weight:700}.assistant-nav{padding:8px 16px 0}.assistant-nav .assistant-tabs{display:flex;align-items:center;gap:4px;border-radius:12px;padding:5px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));border-color:color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));background:linear-gradient(155deg,color-mix(in srgb,var(--md-sys-color-primary-container) 14%,transparent),transparent 58%),var(--md-sys-color-surface-container-low)}.assistant-nav .assistant-tab{appearance:none;min-width:0;min-height:30px;border:0;border-radius:8px;padding:0 10px;background:transparent;color:var(--md-sys-color-on-surface-variant);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;flex:1 1 0;font-size:11px;font-weight:700;letter-spacing:.01em}.assistant-nav .assistant-tab.active{background:var(--md-sys-color-surface-container-highest);color:var(--md-sys-color-on-surface);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 34%,transparent),0 6px 12px color-mix(in srgb,var(--md-sys-color-primary) 18%,transparent)}.assistant-section,.assistant-card{border-radius:14px;border-color:color-mix(in srgb,var(--md-sys-color-primary) 20%,var(--md-sys-color-outline-variant));background:linear-gradient(160deg,color-mix(in srgb,var(--md-sys-color-primary-container) 16%,transparent),transparent 50%),var(--md-sys-color-surface-container-lowest);box-shadow:0 6px 18px color-mix(in srgb,var(--md-sys-color-shadow, var(--md-sys-color-on-surface)) 12%,transparent),inset 0 1px color-mix(in srgb,var(--md-sys-color-on-surface) 7%,transparent)}.suggestions-hero{margin:2px 0 4px;padding:10px 12px;border-radius:12px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));background:linear-gradient(120deg,color-mix(in srgb,var(--md-sys-color-primary-container) 34%,transparent) 0%,transparent 52%),var(--md-sys-color-surface-container-low)}.suggestions-hero__label{font-size:10px;letter-spacing:.08em;text-transform:uppercase;font-weight:700;color:var(--md-sys-color-on-surface-variant);opacity:.88}.suggestions-hero__title{margin-top:2px;font-size:13px;font-weight:700;color:var(--md-sys-color-on-surface)}.suggestions-hero__detail{margin-top:4px;font-size:12px;line-height:1.4;color:color-mix(in srgb,var(--md-sys-color-on-surface) 78%,var(--md-sys-color-on-surface-variant))}.suggestions-content .suggestion-item{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:12px;padding:12px;border-radius:12px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));border-color:color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));background:linear-gradient(140deg,color-mix(in srgb,var(--md-sys-color-primary-container) 16%,transparent),transparent 56%),var(--md-sys-color-surface-container-lowest)}.suggestions-list{display:flex;flex-direction:column;gap:10px}.suggestion-copy{min-width:0;display:grid;gap:4px}.suggestion-main{min-width:0;display:flex;align-items:center;flex-wrap:wrap;gap:8px}.suggestion-icon{width:18px;height:18px;font-size:18px;flex:0 0 auto;color:var(--md-sys-color-primary)}.suggestion-label{min-width:0;font-size:13px;font-weight:700;line-height:1.35;overflow-wrap:anywhere}.suggestion-group{padding:2px 6px;border-radius:999px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface-variant);font-size:10px;font-weight:700;line-height:1.2}.suggestion-desc{font-size:12px;line-height:1.35;color:var(--md-sys-color-on-surface-variant);overflow-wrap:anywhere}.suggestion-actions{display:inline-flex;align-items:center;justify-content:flex-end;gap:4px}.suggestion-action-btn,.suggestion-arrow{width:32px;height:32px;display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;color:var(--md-sys-color-on-surface-variant)}.suggestions-content .suggestion-item:hover,.suggestions-content .suggestion-item:focus-visible{border-color:color-mix(in srgb,var(--md-sys-color-primary) 58%,var(--md-sys-color-outline-variant));box-shadow:0 8px 18px color-mix(in srgb,var(--md-sys-color-primary) 18%,transparent),inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 28%,transparent)}.assistant-footer{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:8px;padding:10px 16px;border-top-color:color-mix(in srgb,var(--md-sys-color-primary) 20%,var(--md-sys-color-outline-variant));background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-primary-container) 16%,transparent),transparent 56%),var(--md-sys-color-surface-container-low)}.assistant-footer .task-footer{grid-column:1/-1}.composer-leading{width:30px;height:30px;display:inline-flex;align-items:center;justify-content:center;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 30%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-primary-container) 70%,var(--md-sys-color-surface-container-low));color:var(--md-sys-color-primary);box-shadow:0 4px 10px color-mix(in srgb,var(--md-sys-color-primary) 16%,transparent)}.composer-leading mat-icon{width:16px;height:16px;font-size:16px}.assistant-footer input{box-sizing:border-box;width:100%;min-width:0;height:34px;border:1px solid;border-radius:8px;padding:0 12px;color:var(--md-sys-color-on-surface);border-color:color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));background:var(--md-sys-color-surface);box-shadow:inset 0 1px 2px color-mix(in srgb,var(--md-sys-color-shadow, var(--md-sys-color-on-surface)) 12%,transparent)}.send-actions{min-width:36px;display:inline-flex;align-items:center;justify-content:center}.assistant-footer .send-btn{--mdc-icon-button-icon-size: 20px;--mdc-icon-button-state-layer-size: 36px;--mat-icon-button-state-layer-size: 36px;width:36px;height:36px;padding:8px;line-height:1;display:inline-flex;align-items:center;justify-content:center;border-color:color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));background:var(--md-sys-color-surface)}.assistant-footer .send-btn mat-icon{width:20px;height:20px;margin:0;font-size:20px;line-height:20px;display:inline-flex;align-items:center;justify-content:center}.assistant-footer .send-btn.ready{background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary-container) 84%,var(--md-sys-color-primary)),var(--md-sys-color-primary));color:var(--md-sys-color-on-primary);box-shadow:0 8px 18px color-mix(in srgb,var(--md-sys-color-primary) 30%,transparent)}.task-primary-btn{border-radius:12px;box-shadow:0 8px 18px color-mix(in srgb,var(--md-sys-color-primary) 24%,transparent)}@media(max-width:959px){.assistant-header{padding:12px 12px 10px}.assistant-section,.assistant-card{margin:4px 12px 10px}.assistant-header:after{left:12px;right:12px}.assistant-header .assistant-title{font-size:14px}.assistant-header .assistant-subtitle{font-size:10px}.assistant-footer{grid-template-columns:minmax(0,1fr) auto}.composer-leading{display:none}}.assistant-thought{margin-top:0;gap:10px;border-color:color-mix(in srgb,var(--md-sys-color-primary) 26%,var(--md-sys-color-outline-variant));background:linear-gradient(145deg,color-mix(in srgb,var(--md-sys-color-primary-container) 28%,transparent),transparent 58%),var(--md-sys-color-surface-container-low)}.assistant-thought-meta{display:inline-flex;align-items:center;gap:6px;font-size:11px;color:var(--md-sys-color-on-surface-variant)}.assistant-thought-meta mat-icon{width:15px;height:15px;font-size:15px;color:var(--md-sys-color-primary)}.assistant-thought-summary{font-size:13px;line-height:1.45;color:var(--md-sys-color-on-surface)}.assistant-thought-plan{border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 32%,var(--md-sys-color-outline-variant));border-radius:12px;padding:10px;background:var(--md-sys-color-surface-container-lowest);display:flex;flex-direction:column;gap:8px}.assistant-thought-plan-title{font-size:13px;font-weight:700;color:var(--md-sys-color-on-surface)}.assistant-thought-plan-actions{display:grid;grid-template-columns:repeat(auto-fit,minmax(0,1fr));gap:8px}.assistant-thought-plan-actions .mdc-button{min-width:0}.assistant-thought-plan-hint{font-size:11px;color:var(--md-sys-color-on-surface-variant);line-height:1.35}.assistant-thought-checklist{display:flex;flex-direction:column;gap:5px}.assistant-thought-checklist-item{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--md-sys-color-on-surface-variant)}.assistant-thought-checklist-item mat-icon{width:14px;height:14px;font-size:14px}.assistant-flow{grid-template-columns:1fr;gap:6px}.flow-step{display:flex;align-items:flex-start;gap:8px;text-align:left;padding:7px 8px;border-radius:10px}.flow-step-index{width:18px;height:18px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-highest);color:var(--md-sys-color-on-surface);flex:0 0 auto}.flow-step-content{min-width:0;display:flex;flex-direction:column;gap:1px}.flow-step-label{font-size:11px;font-weight:700;color:var(--md-sys-color-on-surface)}.flow-step-detail{font-size:11px;color:var(--md-sys-color-on-surface-variant);line-height:1.3}.flow-step.active .flow-step-index{border-color:color-mix(in srgb,var(--md-sys-color-primary) 60%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-primary-container) 85%,var(--md-sys-color-surface-container-highest));color:var(--md-sys-color-on-primary-container)}.flow-step.done .flow-step-index{border-color:transparent;background:color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-surface-container-highest))}.task-timeline{margin-top:4px;display:grid;gap:6px}.task-timeline-item{display:flex;align-items:flex-start;gap:8px;border:1px solid var(--md-sys-color-outline-variant);border-radius:10px;padding:6px 8px;background:var(--md-sys-color-surface-container-low);opacity:.76}.task-timeline-item.active{opacity:1;border-color:color-mix(in srgb,var(--md-sys-color-primary) 40%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-primary-container) 34%,var(--md-sys-color-surface-container-low))}.task-timeline-item.done{opacity:.9;border-color:color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant))}.task-timeline-dot{width:18px;height:18px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-highest);color:var(--md-sys-color-on-surface);flex:0 0 auto}.task-timeline-copy{min-width:0;display:flex;flex-direction:column;gap:1px}.task-timeline-title{font-size:11px;font-weight:700;color:var(--md-sys-color-on-surface)}.task-timeline-detail{font-size:11px;line-height:1.3;color:var(--md-sys-color-on-surface-variant)}.clarification-decision-head{display:inline-flex;align-items:center;width:100%;gap:6px;padding:8px 12px 0;box-sizing:border-box}.clarification-decision-index{width:18px;height:18px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 35%,var(--md-sys-color-outline-variant));color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 68%,transparent)}.clarification-decision-type{font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--md-sys-color-on-surface-variant);opacity:.92}.clarification-decision-state{font-size:10px;font-weight:700;color:var(--md-sys-color-primary)}.clarification-option{border-color:color-mix(in srgb,var(--md-sys-color-primary) 20%,var(--md-sys-color-outline-variant));background:linear-gradient(145deg,color-mix(in srgb,var(--md-sys-color-primary-container) 16%,transparent),transparent 55%),var(--md-sys-color-surface-container-low)}.clarification-option.selected{border-color:color-mix(in srgb,var(--md-sys-color-primary) 56%,var(--md-sys-color-outline-variant));background:linear-gradient(145deg,color-mix(in srgb,var(--md-sys-color-primary-container) 44%,transparent),transparent 62%),var(--md-sys-color-surface-container);box-shadow:0 8px 16px color-mix(in srgb,var(--md-sys-color-primary) 18%,transparent)}.clarification-options-block{overflow:visible;padding-right:4px}@media(max-width:959px){.assistant-thought-plan-actions{grid-template-columns:1fr}}.ai-assistant-panel{width:min(604px,100vw - 18px)}.assistant-section,.assistant-card{margin:0;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 20%,var(--md-sys-color-outline-variant))}.assistant-section{min-height:0;padding:14px 16px;overflow:visible}.assistant-card{min-height:0;padding:14px 16px 16px;overflow:visible}.suggestions-area,.assistant-history,.loading-suggestions{overflow-y:auto;overflow-x:hidden}.section-header{min-width:0;display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:10px}.section-title{min-width:0;font-size:14px;font-weight:700;line-height:1.35;overflow-wrap:anywhere}.suggestions-actions{flex:0 0 auto;display:inline-flex;align-items:center}.review-area,.error-area,.success-area,.clarification-area{padding:0;overflow-y:auto;overflow-x:hidden;scrollbar-gutter:auto}.review-trust{margin:2px 0 4px}.trust-chip{max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.warnings-area,.review-summary,.review-diff,.apply-details,.clarification-options-block,.clarification-manual-toggle{width:100%;max-width:100%;min-width:0}.review-diff{padding:12px 14px}.review-diff-full{padding:10px;overflow-x:auto}.review-diff-block{min-width:0}.review-diff-block pre{overflow-wrap:anywhere;word-break:break-word}.clarification-options-block{padding:4px 2px 10px}.clarification-option{line-height:normal}:host ::ng-deep .clarification-option .mdc-button__label{line-height:1.35!important}.clarification-plain-label{padding:6px 12px 12px;font-size:14px;line-height:1.35}.clarification-manual-toggle{margin-top:10px;padding:10px 2px 0;flex-wrap:wrap;row-gap:6px}.suggestions-content .suggestion-actions{gap:6px}.suggestions-content .suggestion-arrow,.suggestions-content .suggestion-action-btn mat-icon,.suggestions-content .suggestion-arrow mat-icon{display:inline-flex;align-items:center;justify-content:center}:host ::ng-deep .assistant-quick-menu-panel{min-width:244px;max-width:min(90vw,320px);border-radius:14px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 26%,var(--md-sys-color-outline-variant));background:var(--md-sys-color-surface-container-high);box-shadow:0 12px 28px color-mix(in srgb,var(--md-sys-color-shadow, var(--md-sys-color-on-surface)) 32%,transparent),inset 0 1px color-mix(in srgb,var(--md-sys-color-on-surface) 6%,transparent);overflow:hidden;padding:6px}:host ::ng-deep .assistant-quick-menu-panel .mat-mdc-menu-item{min-height:36px;border-radius:10px;color:var(--md-sys-color-on-surface);font-size:12px;font-weight:500;margin:1px 0}:host ::ng-deep .assistant-quick-menu-panel .mat-mdc-menu-item .mat-icon{color:color-mix(in srgb,var(--md-sys-color-on-surface) 82%,var(--md-sys-color-on-surface-variant))}:host ::ng-deep .assistant-quick-menu-panel .mat-mdc-menu-item:hover:not([disabled]){background:color-mix(in srgb,var(--md-sys-color-primary-container) 45%,transparent)}:host ::ng-deep .assistant-quick-menu-panel .mat-mdc-menu-item:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:-2px}:host ::ng-deep .assistant-quick-menu-panel .assistant-quick-menu-danger{color:var(--md-sys-color-error)}:host ::ng-deep .assistant-quick-menu-panel .assistant-quick-menu-danger .mat-icon{color:var(--md-sys-color-error)}@media(max-width:959px){::ng-deep .ai-assistant-overlay-pane{top:12px!important;left:12px!important;width:calc(100vw - 24px)!important;height:calc(100vh - 24px)!important;max-width:calc(100vw - 24px);max-height:calc(100vh - 24px);transform:none!important}.ai-assistant-panel{width:calc(100vw - 48px);min-height:min(620px,100vh - 48px);max-height:calc(100vh - 48px)}.assistant-section,.assistant-card{margin:0}.assistant-card,.assistant-section{padding:12px}}.ai-trigger-btn{--mdc-icon-button-state-layer-size: 36px;width:36px;height:36px;border-radius:8px;background:color-mix(in srgb,var(--md-sys-color-primary) 9%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 22%,transparent);color:var(--md-sys-color-primary);opacity:1}.ai-trigger-btn:hover:not(:disabled){background:color-mix(in srgb,var(--md-sys-color-primary) 16%,transparent);border-color:color-mix(in srgb,var(--md-sys-color-primary) 36%,transparent);color:var(--md-sys-color-on-primary-container)}.ai-trigger-btn:focus-visible,.assistant-close-btn:focus-visible,.assistant-tab:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.assistant-close-btn{width:28px;height:28px;color:var(--md-sys-color-on-surface-variant)}.assistant-close-btn:hover:not(:disabled){background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface)}.assistant-body{padding:12px 16px;overflow:hidden;min-height:0;flex:1;display:flex;flex-direction:column;gap:12px}.assistant-body>*{min-height:0}@media(max-width:959px){.assistant-nav{padding:8px 12px 0}.assistant-body,.assistant-footer{padding:10px 12px}.suggestions-content .suggestion-item{grid-template-columns:1fr;align-items:start}.suggestion-actions{justify-content:flex-start}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i3.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i3.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i3.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i5.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i5.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i6.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i8.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i9.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i16.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["role", "id", "aria-label", "aria-description", "value", "color", "removable", "highlighted", "disableRipple", "disabled"], outputs: ["removed", "destroyed"], exportAs: ["matChip"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i11.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i11.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i11.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "pipe", type: i3.JsonPipe, name: "json" }, { kind: "pipe", type: i3.DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
6672
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: PraxisAiAssistantComponent, isStandalone: true, selector: "praxis-ai-assistant", inputs: { adapter: "adapter", riskPolicy: "riskPolicy", allowManualPatchEdit: "allowManualPatchEdit", hasBackdrop: "hasBackdrop" }, viewQueries: [{ propertyName: "overlayOrigin", first: true, predicate: CdkOverlayOrigin, descendants: true }, { propertyName: "triggerButton", first: true, predicate: ["triggerBtn"], descendants: true, read: ElementRef }, { propertyName: "inputElement", first: true, predicate: ["inputEl"], descendants: true }], ngImport: i0, template: "<!-- Trigger Button -->\n<button \n mat-icon-button \n cdkOverlayOrigin \n #trigger=\"cdkOverlayOrigin\"\n #triggerBtn\n (click)=\"open()\"\n [disabled]=\"isOpen\"\n class=\"ai-trigger-btn\"\n matTooltip=\"Assistente de Configura\u00E7\u00E3o\"\n aria-label=\"Abrir Assistente IA\">\n <mat-icon>auto_awesome</mat-icon>\n</button>\n\n<!-- Overlay Template -->\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"isOpen\"\n [cdkConnectedOverlayHasBackdrop]=\"hasBackdrop\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayPush]=\"true\"\n [cdkConnectedOverlayViewportMargin]=\"12\"\n cdkConnectedOverlayPanelClass=\"ai-assistant-overlay-pane\"\n cdkConnectedOverlayBackdropClass=\"ai-assistant-backdrop\"\n (backdropClick)=\"close()\"\n (overlayOutsideClick)=\"close()\"\n (detach)=\"close()\">\n\n <div\n class=\"ai-assistant-panel\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Assistente de Configura\u00E7\u00E3o\"\n [attr.aria-busy]=\"isBusyState() ? 'true' : null\"\n [cdkTrapFocus]=\"hasBackdrop\"\n [cdkTrapFocusAutoCapture]=\"hasBackdrop\"\n (keydown)=\"onKeydown($event)\"\n >\n \n <!-- HEADER -->\n <div class=\"assistant-header\">\n <div class=\"assistant-header__left\">\n <mat-icon class=\"magic-icon\">auto_awesome</mat-icon>\n <div class=\"assistant-title-group\">\n <div class=\"assistant-title\">Assistente de Configura\u00E7\u00E3o</div>\n <div class=\"assistant-subtitle\">Copiloto contextual para ajustes guiados</div>\n <div class=\"assistant-header-chips\">\n <span\n class=\"mode-chip\"\n [class.mock]=\"mockMode\"\n [matTooltip]=\"mockMode ? 'Sem chave de API: respostas de demonstra\u00E7\u00E3o' : 'Conectado ao assistente configurado'\"\n >\n {{ mockMode ? 'Mock' : 'Conectado' }}\n </span>\n <span\n class=\"policy-chip\"\n [class.strict]=\"isStrictRiskPolicy()\"\n [matTooltip]=\"getRiskPolicyTooltip()\"\n >\n {{ getRiskPolicyLabel() }}\n </span>\n </div>\n </div>\n </div>\n <div class=\"assistant-header__right\">\n <button\n mat-icon-button\n type=\"button\"\n class=\"assistant-close-btn\"\n (click)=\"close()\"\n aria-label=\"Fechar assistente\"\n matTooltip=\"Fechar assistente\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n <div\n class=\"assistant-status\"\n [class.processing]=\"isBusyState()\"\n [class.pending]=\"state === 'clarification'\"\n [class.warning]=\"state === 'error'\"\n [class.success]=\"state === 'review' || state === 'success'\"\n [class.compact]=\"!shouldShowSystemStatusDetail()\"\n role=\"status\"\n [attr.aria-live]=\"getSystemStatusAriaLive()\"\n aria-atomic=\"true\"\n >\n <span class=\"assistant-status-dot\" aria-hidden=\"true\"></span>\n <div class=\"assistant-status-content\">\n <div class=\"assistant-status-label\">\n <span class=\"assistant-status-label-prefix\">Status:</span>\n <span>{{ getSystemStatusLabel() }}</span>\n <span *ngIf=\"shouldShowSnapshotFallbackBadge()\" class=\"assistant-status-mode\">Snapshot</span>\n </div>\n <div *ngIf=\"shouldShowSystemStatusDetail()\" class=\"assistant-status-detail\">{{ getSystemStatusDetail() }}</div>\n </div>\n </div>\n <div class=\"assistant-flow\" *ngIf=\"shouldShowTaskFlow()\" role=\"list\" aria-label=\"Fluxo da proposta\">\n <div\n class=\"flow-step\"\n role=\"listitem\"\n *ngFor=\"let step of flowSteps\"\n [class.active]=\"getFlowStepState(step.step) === 'active'\"\n [class.done]=\"getFlowStepState(step.step) === 'done'\"\n >\n <span class=\"flow-step-index\">{{ step.step }}</span>\n <span class=\"flow-step-content\">\n <span class=\"flow-step-label\">{{ step.label }}</span>\n <span class=\"flow-step-detail\">{{ getFlowStepDetail(step.step) }}</span>\n </span>\n </div>\n </div>\n <div class=\"assistant-nav\">\n <div\n class=\"assistant-tabs\"\n role=\"tablist\"\n aria-label=\"Se\u00E7\u00F5es do assistente\"\n (keydown)=\"onTabsKeydown($event)\"\n >\n <button\n class=\"assistant-tab\"\n type=\"button\"\n *ngIf=\"isTaskMode()\"\n id=\"assistant-tab-task\"\n role=\"tab\"\n aria-label=\"Proposta atual\"\n [attr.aria-selected]=\"isActiveTab('task')\"\n aria-controls=\"assistant-panel-task\"\n [attr.tabindex]=\"isActiveTab('task') ? 0 : -1\"\n [class.active]=\"isActiveTab('task')\"\n (click)=\"setActiveTab('task')\"\n >\n Proposta\n <span *ngIf=\"hasPendingClarification() && !isActiveTab('task')\" class=\"assistant-tab-badge\">1</span>\n </button>\n <button\n class=\"assistant-tab\"\n type=\"button\"\n id=\"assistant-tab-chat\"\n role=\"tab\"\n aria-label=\"Hist\u00F3rico\"\n [attr.aria-selected]=\"isActiveTab('chat')\"\n aria-controls=\"assistant-panel-chat\"\n [attr.tabindex]=\"isActiveTab('chat') ? 0 : -1\"\n [class.active]=\"isActiveTab('chat')\"\n (click)=\"setActiveTab('chat')\"\n >\n Hist\u00F3rico\n </button>\n <button\n class=\"assistant-tab\"\n type=\"button\"\n id=\"assistant-tab-suggestions\"\n role=\"tab\"\n aria-label=\"Sugest\u00F5es de melhoria\"\n [attr.aria-selected]=\"isActiveTab('suggestions')\"\n aria-controls=\"assistant-panel-suggestions\"\n [attr.tabindex]=\"isActiveTab('suggestions') ? 0 : -1\"\n [class.active]=\"isActiveTab('suggestions')\"\n (click)=\"setActiveTab('suggestions')\"\n >\n Sugest\u00F5es\n </button>\n </div>\n </div>\n\n <!-- BODY: Dynamic Content based on State -->\n <div class=\"assistant-body\">\n <div class=\"assistant-thought assistant-section\" *ngIf=\"shouldShowThoughtCard()\">\n <div class=\"assistant-thought-meta\">\n <mat-icon>psychology</mat-icon>\n <span>{{ getThoughtTimingLabel() }}</span>\n </div>\n <div class=\"assistant-thought-summary\">{{ getThoughtSummary() }}</div>\n <div class=\"assistant-thought-plan\">\n <div class=\"assistant-thought-plan-title\">{{ getThoughtPlanTitle() }}</div>\n <div class=\"assistant-thought-plan-actions\">\n <button\n mat-stroked-button\n type=\"button\"\n class=\"thought-action-details\"\n (click)=\"openThoughtDetails()\"\n [attr.aria-label]=\"getThoughtDetailsLabel()\"\n [matTooltip]=\"getThoughtDetailsTooltip()\"\n >\n {{ getThoughtDetailsLabel() }}\n </button>\n <button\n *ngIf=\"shouldShowThoughtPreviewAction()\"\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n class=\"thought-action-preview\"\n (click)=\"openThoughtPreview()\"\n [matTooltip]=\"getThoughtPreviewTooltip()\"\n >\n Pr\u00E9via\n </button>\n </div>\n <div class=\"assistant-thought-plan-hint\">{{ getThoughtActionHint() }}</div>\n <ng-container *ngIf=\"getThoughtChecklist() as thoughtChecklist\">\n <div class=\"assistant-thought-checklist\" *ngIf=\"thoughtChecklist.length\">\n <div *ngFor=\"let item of thoughtChecklist\" class=\"assistant-thought-checklist-item\">\n <mat-icon>radio_button_unchecked</mat-icon>\n <span>{{ item }}</span>\n </div>\n </div>\n <div class=\"assistant-thought-shimmer\" *ngIf=\"isBusyState() && !thoughtChecklist.length\">\n <div class=\"shimmer-line shimmer-line-1\"></div>\n <div class=\"shimmer-line shimmer-line-2\"></div>\n <div class=\"shimmer-line shimmer-line-3\"></div>\n </div>\n </ng-container>\n </div>\n </div>\n <div *ngIf=\"processingInfoVisible\" class=\"processing-banner\">\n <mat-spinner diameter=\"16\"></mat-spinner>\n <span>{{ aiExplanation || 'Analisando solicita\u00E7\u00E3o e preparando proposta...' }}</span>\n <button mat-button type=\"button\" class=\"processing-retry\" (click)=\"retryProcessing()\">Tentar novamente</button>\n </div>\n <div\n class=\"assistant-history assistant-section\"\n *ngIf=\"historyContext && isActiveTab('chat')\"\n id=\"assistant-panel-chat\"\n role=\"tabpanel\"\n aria-labelledby=\"assistant-tab-chat\"\n >\n <div class=\"section-header\">\n <div class=\"section-heading\">\n <div class=\"section-title\">Hist\u00F3rico</div>\n <div class=\"section-subtitle\">Sess\u00F5es recentes, pedidos reaproveit\u00E1veis e desfazer r\u00E1pido.</div>\n </div>\n <div class=\"history-actions\" role=\"group\" aria-label=\"A\u00E7\u00F5es do hist\u00F3rico\">\n <button\n mat-stroked-button\n type=\"button\"\n class=\"history-action-btn\"\n (click)=\"historyExpanded = !historyExpanded\"\n [matTooltip]=\"historyExpanded ? 'Recolher hist\u00F3rico' : 'Expandir hist\u00F3rico'\"\n [attr.aria-label]=\"historyExpanded ? 'Recolher hist\u00F3rico' : 'Expandir hist\u00F3rico'\"\n [disabled]=\"!historyWarnings.length && !historySessions.length && !activeHistoryMessages.length\"\n >\n <mat-icon>{{ historyExpanded ? 'expand_less' : 'expand_more' }}</mat-icon>\n <span>{{ historyExpanded ? 'Recolher' : 'Expandir' }}</span>\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n class=\"history-action-btn\"\n (click)=\"startNewSession()\"\n matTooltip=\"Nova conversa\"\n aria-label=\"Nova conversa\"\n [disabled]=\"isBusyState()\"\n >\n <mat-icon>add_comment</mat-icon>\n <span>Nova conversa</span>\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n (click)=\"clearHistory()\"\n matTooltip=\"Limpar hist\u00F3rico local\"\n aria-label=\"Limpar hist\u00F3rico local\"\n class=\"history-action-btn history-action-btn--danger\"\n [disabled]=\"!historySessions.length\"\n >\n <mat-icon>delete_outline</mat-icon>\n <span>Limpar</span>\n </button>\n </div>\n </div>\n <div *ngIf=\"historyUndoDeleteSession\" class=\"history-undo\">\n <span>Sess\u00E3o removida.</span>\n <button mat-button type=\"button\" (click)=\"undoRemoveHistorySession()\">\n Desfazer\n </button>\n </div>\n\n <div *ngIf=\"historyExpanded && historyWarnings.length\" class=\"history-warnings\">\n <mat-icon>info</mat-icon>\n <div class=\"history-warnings-list\">\n <div *ngFor=\"let warning of historyWarnings\">{{ warning }}</div>\n <div class=\"history-warnings-hint\">\n Configure headers via API_CONFIG_STORAGE_OPTIONS no host.\n </div>\n </div>\n </div>\n\n <div *ngIf=\"historyExpanded && historySessions.length\" class=\"history-sessions\">\n <div\n class=\"history-session\"\n *ngFor=\"let session of historySessions\"\n role=\"button\"\n tabindex=\"0\"\n (click)=\"selectHistorySession(session.id)\"\n (keydown)=\"onHistorySessionCardKeydown($event, session.id)\"\n [class.active]=\"session.id === activeHistorySession?.id\"\n [matTooltip]=\"getHistorySessionTooltip(session)\"\n [matTooltipDisabled]=\"!session.componentType && !session.componentId\"\n >\n <div class=\"history-session-main\">\n <span class=\"history-session-title\">{{ session.title }}</span>\n <div class=\"history-session-main-right\">\n <span class=\"history-session-time\">{{ session.updatedAt | date:'short' }}</span>\n <div class=\"history-session-tools\">\n <button\n mat-icon-button\n type=\"button\"\n class=\"history-session-tool\"\n (click)=\"reuseHistorySessionPrompt(session.id, $event)\"\n matTooltip=\"Reusar \u00FAltimo pedido\"\n aria-label=\"Reusar \u00FAltimo pedido\"\n >\n <mat-icon>edit_note</mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n class=\"history-session-tool history-session-tool--danger\"\n (click)=\"removeHistorySession(session.id, $event)\"\n matTooltip=\"Excluir sess\u00E3o\"\n aria-label=\"Excluir sess\u00E3o\"\n >\n <mat-icon>delete_outline</mat-icon>\n </button>\n </div>\n </div>\n </div>\n <div class=\"history-session-meta\">\n <span *ngIf=\"session.componentType\" class=\"history-chip\">{{ session.componentType }}</span>\n <span *ngIf=\"session.componentId\" class=\"history-chip\">{{ session.componentId }}</span>\n </div>\n </div>\n </div>\n <div *ngIf=\"historyExpanded && !historySessions.length\" class=\"history-empty\">\n Nenhuma sess\u00E3o salva ainda.\n </div>\n\n <div *ngIf=\"historyExpanded && activeHistoryMessages.length\" class=\"history-messages\">\n <div\n *ngIf=\"activeHistoryTotalMessages > activeHistoryMessages.length\"\n class=\"history-messages-hint\"\n >\n Mostrando \u00FAltimas {{ activeHistoryMessages.length }} de {{ activeHistoryTotalMessages }} mensagens.\n </div>\n <div\n *ngFor=\"let msg of activeHistoryMessages\"\n class=\"history-message\"\n [class.user]=\"msg.role === 'user'\"\n [class.assistant]=\"msg.role === 'assistant'\"\n >\n <div class=\"history-message-header\">\n <span class=\"history-message-role\">{{ msg.role === 'user' ? 'Voc\u00EA' : 'Assistente' }}</span>\n <span class=\"history-message-time\">{{ msg.createdAt | date:'shortTime' }}</span>\n <span\n *ngIf=\"msg.context?.usedRag\"\n class=\"history-rag\"\n matTooltip=\"Resposta baseada em contexto recuperado (RAG)\"\n >RAG</span>\n </div>\n <div class=\"history-message-text\">{{ msg.text }}</div>\n </div>\n </div>\n <div *ngIf=\"historyExpanded && historySessions.length && !activeHistoryMessages.length\" class=\"history-empty history-empty--panel\">\n Selecione uma sess\u00E3o para visualizar as mensagens.\n </div>\n <div class=\"history-helper\" *ngIf=\"historyExpanded\">\n O hist\u00F3rico \u00E9 local ao usu\u00E1rio e ao componente atual.\n </div>\n </div>\n\n <div\n class=\"loading-suggestions assistant-section\"\n *ngIf=\"loadingSuggestions && isActiveTab('suggestions')\"\n id=\"assistant-panel-suggestions\"\n role=\"tabpanel\"\n aria-labelledby=\"assistant-tab-suggestions\"\n >\n <mat-spinner diameter=\"20\"></mat-spinner>\n <span>Carregando sugest\u00F5es de melhoria...</span>\n </div>\n \n <!-- STATE: LISTENING (Suggestions) -->\n <div\n *ngIf=\"state === 'listening' && isActiveTab('suggestions')\"\n class=\"suggestions-area assistant-section\"\n id=\"assistant-panel-suggestions\"\n role=\"tabpanel\"\n aria-labelledby=\"assistant-tab-suggestions\"\n >\n <div class=\"section-header\">\n <div class=\"section-title\">Sugest\u00F5es de melhoria</div>\n <div class=\"suggestions-actions\">\n <button mat-icon-button type=\"button\" (click)=\"refreshSuggestions()\" [disabled]=\"loadingSuggestions\" matTooltip=\"Atualizar sugest\u00F5es\">\n <mat-icon>refresh</mat-icon>\n </button>\n </div>\n </div>\n <div class=\"suggestions-hero\" *ngIf=\"!loadingSuggestions\">\n <div class=\"suggestions-hero__label\">Contexto ativo</div>\n <div class=\"suggestions-hero__title\">{{ adapter.componentName || 'Componente atual' }}</div>\n <div class=\"suggestions-hero__detail\">{{ getSystemStatusDetail() }}</div>\n </div>\n <div *ngIf=\"suggestionsWarnings.length\" class=\"warnings-area\">\n <mat-icon class=\"warnings-icon\">warning_amber</mat-icon>\n <div class=\"warnings-content\">\n <div class=\"warnings-title\">Avisos</div>\n <div class=\"warnings-list\">\n <div *ngFor=\"let warning of suggestionsWarnings\">{{ warning }}</div>\n </div>\n </div>\n </div>\n <div class=\"suggestions-content\" *ngIf=\"!loadingSuggestions && (richSuggestions.length || hasDismissedSuggestions())\">\n <div class=\"suggestions-filter\" *ngIf=\"hasDismissedSuggestions()\">\n <span>{{ getDismissedSuggestionCount() }} oculta(s)</span>\n <button mat-button type=\"button\" (click)=\"restoreDismissedSuggestions()\">\n Restaurar\n </button>\n </div>\n <div class=\"suggestions-list\" *ngIf=\"getVisibleSuggestions().length; else allSuggestionsHidden\">\n <div\n class=\"suggestion-item\"\n *ngFor=\"let sug of getVisibleSuggestions()\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"'Selecionar sugest\u00E3o: ' + sug.label\"\n (click)=\"selectSuggestion(sug)\"\n (keydown)=\"onSuggestionCardKeydown($event, sug)\"\n >\n <div class=\"suggestion-copy\">\n <div class=\"suggestion-main\">\n <mat-icon *ngIf=\"sug.icon\" class=\"suggestion-icon\">{{ sug.icon }}</mat-icon>\n <span class=\"suggestion-label\">{{ sug.label }}</span>\n <span *ngIf=\"sug.group\" class=\"suggestion-group\">{{ sug.group }}</span>\n </div>\n <div *ngIf=\"sug.description\" class=\"suggestion-desc\">{{ sug.description }}</div>\n </div>\n <div class=\"suggestion-actions\">\n <span class=\"suggestion-arrow\" aria-hidden=\"true\">\n <mat-icon>chevron_right</mat-icon>\n </span>\n <button\n mat-icon-button\n type=\"button\"\n class=\"suggestion-action-btn\"\n (click)=\"prepareSuggestionPrompt(sug, $event)\"\n matTooltip=\"Refinar pedido\"\n aria-label=\"Refinar pedido\"\n >\n <mat-icon>edit</mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n class=\"suggestion-action-btn suggestion-action-btn--danger\"\n (click)=\"dismissSuggestion(sug, $event)\"\n matTooltip=\"Ocultar sugest\u00E3o\"\n aria-label=\"Ocultar sugest\u00E3o\"\n >\n <mat-icon>visibility_off</mat-icon>\n </button>\n </div>\n </div>\n </div>\n <ng-template #allSuggestionsHidden>\n <div class=\"suggestions-empty suggestions-empty--inline\">\n Todas as sugest\u00F5es foram ocultadas.\n </div>\n </ng-template>\n </div>\n <div class=\"suggestions-empty\" *ngIf=\"!loadingSuggestions && !richSuggestions.length\">\n Nenhuma sugest\u00E3o dispon\u00EDvel no momento.\n </div>\n <div class=\"suggestions-helper\" *ngIf=\"!loadingSuggestions && !richSuggestions.length\">\n Selecione uma sugest\u00E3o acima ou descreva uma altera\u00E7\u00E3o no campo inferior.\n </div>\n </div>\n\n <!-- STATE: CLARIFICATION (Two-Step Flow) -->\n <div\n *ngIf=\"state === 'clarification' && isActiveTab('task')\"\n class=\"clarification-area assistant-card\"\n id=\"assistant-panel-task\"\n role=\"tabpanel\"\n aria-labelledby=\"assistant-tab-task\"\n >\n <div class=\"task-header\" *ngIf=\"!shouldShowThoughtCard()\">\n <div class=\"task-title\">{{ getTaskTitle() }}</div>\n <div class=\"task-subtitle\">{{ getTaskSubtitle() }}</div>\n <div *ngIf=\"clarificationOptions.length > 1 && getTaskSelectionSummary() as selectionSummary\" class=\"task-meta\">\n <span class=\"task-meta-label\">Selecionado:</span>\n <span class=\"task-meta-value\">{{ selectionSummary }}</span>\n </div>\n <div *ngIf=\"shouldShowTaskSteps()\" class=\"task-steps\">\n <span class=\"task-step active\">1 Dados</span>\n <span class=\"task-step\">2 Layout</span>\n <span class=\"task-step\">3 Revis\u00E3o</span>\n </div>\n </div>\n <div *ngIf=\"clarificationResponseType === 'context'\" class=\"context-only\">\n <mat-spinner diameter=\"24\"></mat-spinner>\n <div class=\"context-only-hint\">Buscando contexto adicional...</div>\n </div>\n <ng-template #clarificationOptionContent let-opt let-index=\"index\" let-compact=\"compact\">\n <div class=\"clarification-decision-head\" *ngIf=\"!compact\">\n <span class=\"clarification-decision-index\">{{ index + 1 }}</span>\n <span class=\"clarification-decision-type\">{{ getClarificationOptionKindLabel(opt) }}</span>\n <span class=\"spacer\"></span>\n <span class=\"clarification-decision-state\" *ngIf=\"isClarificationSelected(opt)\">Selecionado</span>\n </div>\n <ng-container [ngSwitch]=\"getClarificationOptionLayout(opt)\">\n <div *ngSwitchCase=\"'endpoint'\" class=\"clarification-card\">\n <div class=\"clarification-card-header\">\n <mat-icon class=\"endpoint-icon\">{{ getEndpointIcon(opt) }}</mat-icon>\n <ng-container *ngIf=\"getEndpointMethod(opt) as method\">\n <span class=\"endpoint-method\" [attr.data-method]=\"method\">{{ method }}</span>\n </ng-container>\n <span class=\"endpoint-label\">{{ opt.label }}</span>\n <span class=\"spacer\"></span>\n <mat-icon class=\"select-indicator\">\n {{ isClarificationSelected(opt) ? 'check_circle' : 'radio_button_unchecked' }}\n </mat-icon>\n </div>\n <div class=\"clarification-card-body\">\n <ng-container *ngIf=\"getEndpointPath(opt) as path\">\n <div class=\"endpoint-path\">{{ path }}</div>\n </ng-container>\n <div\n *ngIf=\"opt.contextHints?.description\"\n class=\"endpoint-description\"\n [matTooltip]=\"getDescriptionTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowDescriptionTooltip(opt)\"\n >\n {{ opt.contextHints?.description }}\n </div>\n </div>\n </div>\n <div *ngSwitchCase=\"'color'\" class=\"clarification-color\">\n <span\n class=\"color-swatch\"\n [style.background]=\"getSafeHexColor(opt) || 'var(--md-sys-color-surface-container-highest)'\"\n ></span>\n <div class=\"color-meta\">\n <span class=\"color-label\">{{ opt.label }}</span>\n <span *ngIf=\"opt.contextHints?.hexColor\" class=\"color-value\">{{ opt.contextHints?.hexColor }}</span>\n </div>\n </div>\n <div *ngSwitchCase=\"'description'\" class=\"clarification-description\">\n <span class=\"clarification-label\">{{ opt.label }}</span>\n <span\n *ngIf=\"opt.contextHints?.description\"\n class=\"clarification-subtitle\"\n [matTooltip]=\"getDescriptionTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowDescriptionTooltip(opt)\"\n >\n {{ opt.contextHints?.description }}\n </span>\n </div>\n <span *ngSwitchDefault class=\"clarification-plain-label\">{{ opt.label }}</span>\n </ng-container>\n </ng-template>\n <div *ngIf=\"warnings.length\" class=\"warnings-area\">\n <mat-icon class=\"warnings-icon\">warning_amber</mat-icon>\n <div class=\"warnings-content\">\n <div class=\"warnings-title\">Avisos</div>\n <div class=\"warnings-list\">\n <div *ngFor=\"let warning of warnings\">{{ warning }}</div>\n </div>\n </div>\n </div>\n <div\n *ngIf=\"clarificationQuestions.length\"\n class=\"clarification-questions\"\n [class.attention-highlight]=\"highlightClarificationDetails && !clarificationOptions.length\"\n >\n <div *ngFor=\"let question of clarificationQuestions; let i = index\" class=\"clarification-question\">\n <div class=\"clarification-question-label\">{{ question }}</div>\n <input\n type=\"text\"\n [(ngModel)]=\"clarificationAnswers[i]\"\n [placeholder]=\"'Resposta ' + (i + 1)\"\n autocomplete=\"off\">\n </div>\n </div>\n <div\n *ngIf=\"clarificationOptions.length\"\n class=\"clarification-options-block\"\n [class.attention-highlight]=\"highlightClarificationDetails\"\n >\n <div class=\"clarification-options-title\">\n {{ clarificationOptions.length === 1 ? 'Decis\u00E3o sugerida' : 'Decis\u00F5es sugeridas' }}\n </div>\n <div *ngIf=\"clarificationOptions.length === 1\" class=\"clarification-options-hint\">\n Etapa 2 de 4: confirme a melhor op\u00E7\u00E3o para continuar.\n </div>\n <div *ngIf=\"clarificationOptions.length > 1\" class=\"clarification-options-hint\">\n Etapa 2 de 4: selecione a alternativa mais aderente para gerar a proposta.\n </div>\n <div\n *ngIf=\"clarificationResponseType === 'confirm'\"\n class=\"clarification-buttons\"\n [class.list]=\"clarificationPresentation === 'list'\"\n >\n <button\n mat-button\n type=\"button\"\n *ngFor=\"let opt of clarificationOptions; let i = index\"\n (click)=\"onClarificationOptionClick(opt)\"\n class=\"clarification-option\"\n [class.selected]=\"isClarificationSelected(opt)\"\n [matTooltip]=\"getClarificationTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowClarificationTooltip(opt) || isEndpointOption(opt)\"\n >\n <ng-container *ngTemplateOutlet=\"clarificationOptionContent; context: { $implicit: opt, index: i, compact: false }\"></ng-container>\n </button>\n </div>\n <div\n *ngIf=\"clarificationSelectionMode === 'multiple'\"\n class=\"clarification-buttons\"\n [class.list]=\"clarificationPresentation === 'list'\"\n >\n <button\n mat-button\n type=\"button\"\n *ngFor=\"let opt of clarificationOptions; let i = index\"\n (click)=\"onClarificationOptionClick(opt)\"\n [class.selected]=\"isClarificationSelected(opt)\"\n class=\"clarification-option\"\n [matTooltip]=\"getClarificationTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowClarificationTooltip(opt) || isEndpointOption(opt)\"\n >\n <ng-container *ngTemplateOutlet=\"clarificationOptionContent; context: { $implicit: opt, index: i, compact: false }\"></ng-container>\n </button>\n </div>\n <div\n *ngIf=\"clarificationResponseType !== 'confirm' && clarificationSelectionMode === 'single' && clarificationPresentation !== 'chips'\"\n class=\"clarification-buttons\"\n [class.list]=\"clarificationPresentation === 'list'\"\n >\n <button\n mat-button\n type=\"button\"\n *ngFor=\"let opt of clarificationOptions; let i = index\"\n (click)=\"onClarificationOptionClick(opt)\"\n class=\"clarification-option\"\n [class.selected]=\"isClarificationSelected(opt)\"\n [matTooltip]=\"getClarificationTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowClarificationTooltip(opt) || isEndpointOption(opt)\"\n >\n <ng-container *ngTemplateOutlet=\"clarificationOptionContent; context: { $implicit: opt, index: i, compact: false }\"></ng-container>\n </button>\n </div>\n <div\n *ngIf=\"clarificationResponseType !== 'confirm' && clarificationSelectionMode === 'single' && clarificationPresentation === 'chips'\"\n class=\"clarification-chips\"\n >\n <ng-container *ngFor=\"let opt of clarificationOptions; let i = index\">\n <button\n *ngIf=\"isEndpointOption(opt); else chipOption\"\n mat-button\n type=\"button\"\n class=\"clarification-option clarification-card-button\"\n (click)=\"onClarificationOptionClick(opt)\"\n [class.selected]=\"isClarificationSelected(opt)\"\n [matTooltip]=\"getClarificationTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowClarificationTooltip(opt) || isEndpointOption(opt)\"\n >\n <ng-container *ngTemplateOutlet=\"clarificationOptionContent; context: { $implicit: opt, index: i, compact: false }\"></ng-container>\n </button>\n <ng-template #chipOption>\n <mat-chip\n (click)=\"onClarificationOptionClick(opt)\"\n [matTooltip]=\"getClarificationTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowClarificationTooltip(opt)\"\n class=\"clarification-chip\"\n >\n <ng-container *ngTemplateOutlet=\"clarificationOptionContent; context: { $implicit: opt, index: i, compact: true }\"></ng-container>\n </mat-chip>\n </ng-template>\n </ng-container>\n </div>\n </div>\n <div\n *ngIf=\"clarificationAllowCustom && clarificationResponseType !== 'context'\"\n class=\"clarification-manual-toggle\"\n >\n <span class=\"clarification-manual-label\">N\u00E3o encontrou o recurso?</span>\n <button mat-button type=\"button\" (click)=\"toggleManualInput()\">\n {{ showManualInput ? 'Ocultar resposta manual' : 'Responder manualmente' }}\n </button>\n </div>\n <div\n *ngIf=\"clarificationAllowCustom && showManualInput && clarificationResponseType !== 'context'\"\n class=\"clarification-free\"\n >\n <input\n type=\"text\"\n [(ngModel)]=\"clarificationFreeText\"\n placeholder=\"Digite sua resposta\u2026\"\n autocomplete=\"off\"\n (keydown.enter)=\"confirmTaskAction()\"\n />\n </div>\n <div\n *ngIf=\"clarificationAllowCustom && showManualInput && clarificationResponseType !== 'context'\"\n class=\"clarification-free-hint\"\n >\n Pressione Enter para enviar.\n </div>\n </div>\n\n <!-- STATE: REVIEW (Diff/Explanation) -->\n <div\n *ngIf=\"state === 'review' && isActiveTab('task')\"\n class=\"review-area assistant-card\"\n id=\"assistant-panel-task\"\n role=\"tabpanel\"\n aria-labelledby=\"assistant-tab-task\"\n >\n <div class=\"task-header\" *ngIf=\"!shouldShowThoughtCard()\">\n <div class=\"task-title\">{{ getTaskTitle() }}</div>\n <div class=\"task-subtitle\">{{ getTaskSubtitle() }}</div>\n <div *ngIf=\"clarificationOptions.length > 1 && getTaskSelectionSummary() as selectionSummary\" class=\"task-meta\">\n <span class=\"task-meta-label\">Selecionado:</span>\n <span class=\"task-meta-value\">{{ selectionSummary }}</span>\n </div>\n <div *ngIf=\"shouldShowTaskSteps()\" class=\"task-steps\">\n <span class=\"task-step\">1 Dados</span>\n <span class=\"task-step\">2 Layout</span>\n <span class=\"task-step active\">3 Revis\u00E3o</span>\n </div>\n </div>\n <div *ngIf=\"warnings.length\" class=\"warnings-area\">\n <mat-icon class=\"warnings-icon\">warning_amber</mat-icon>\n <div class=\"warnings-content\">\n <div class=\"warnings-title\">Avisos</div>\n <div class=\"warnings-list\">\n <div *ngFor=\"let warning of warnings\">{{ warning }}</div>\n </div>\n </div>\n </div>\n <div class=\"review-trust\">\n <span class=\"trust-chip\" [matTooltip]=\"getScopeTooltip()\">{{ getScopeLabel() }}</span>\n <span class=\"trust-chip\" [matTooltip]=\"getConfidenceTooltip()\">{{ getConfidenceLabel() }}</span>\n <span class=\"trust-chip risk-chip\" [class.medium]=\"getReviewRiskLevel() === 'm\u00E9dio'\" [class.high]=\"getReviewRiskLevel() === 'alto'\">\n Risco {{ getReviewRiskLevel() }}\n </span>\n </div>\n <div class=\"review-summary\" [class.attention-highlight]=\"highlightReviewDetails\">\n <div class=\"review-summary-title\">Resumo da proposta</div>\n <div class=\"review-summary-line\">{{ getReviewSummary() }}</div>\n </div>\n <div class=\"review-diff\">\n <div class=\"review-diff-title\">Pr\u00E9via de mudan\u00E7as</div>\n <ng-container *ngIf=\"pendingDiff.length; else noDiffPreview\">\n <div class=\"review-diff-summary\">\n <div *ngFor=\"let line of getDiffSummaryLines()\" class=\"review-diff-line\">{{ line }}</div>\n <div *ngIf=\"pendingDiff.length > 3\" class=\"review-diff-more\">\u2026 +{{ pendingDiff.length - 3 }} mudan\u00E7as</div>\n </div>\n <button mat-stroked-button type=\"button\" class=\"review-diff-toggle\" (click)=\"toggleFullDiff()\">\n {{ getDiffToggleLabel() }}\n </button>\n </ng-container>\n <ng-template #noDiffPreview>\n <div class=\"review-diff-empty\">\n N\u00E3o foi poss\u00EDvel gerar um diff estruturado. Revise o resumo e aplique com cautela.\n </div>\n </ng-template>\n <div *ngIf=\"showFullDiff && pendingDiff.length\" class=\"review-diff-full\">\n <div *ngFor=\"let diff of pendingDiff\" class=\"review-diff-block\">\n <div class=\"review-diff-path\">{{ diff.path }}</div>\n <div class=\"review-diff-label\">Antes:</div>\n <pre>{{ diff.before | json }}</pre>\n <div class=\"review-diff-label\">Depois:</div>\n <pre>{{ diff.after | json }}</pre>\n </div>\n </div>\n </div>\n <div class=\"ai-explanation\" *ngIf=\"aiExplanation.trim()\">\n {{ aiExplanation }}\n </div>\n </div>\n\n <!-- STATE: ERROR -->\n <div\n *ngIf=\"state === 'error' && (isActiveTab('task') || (!isTaskMode() && isActiveTab('suggestions')))\"\n class=\"error-area assistant-card\"\n [attr.id]=\"isTaskMode() ? 'assistant-panel-task' : 'assistant-panel-suggestions'\"\n role=\"tabpanel\"\n [attr.aria-labelledby]=\"isTaskMode() ? 'assistant-tab-task' : 'assistant-tab-suggestions'\"\n >\n <div class=\"error-msg\">\n <mat-icon color=\"warn\">error_outline</mat-icon>\n <span>{{ errorMsg }}</span>\n </div>\n <div *ngIf=\"warnings.length\" class=\"warnings-area\">\n <mat-icon class=\"warnings-icon\">warning_amber</mat-icon>\n <div class=\"warnings-content\">\n <div class=\"warnings-title\">Avisos</div>\n <div class=\"warnings-list\">\n <div *ngFor=\"let warning of warnings\">{{ warning }}</div>\n </div>\n </div>\n </div>\n <div *ngIf=\"shouldShowApplyDetails()\" class=\"apply-details\">\n <div class=\"apply-details-header\">\n <div class=\"apply-details-title\">Detalhes da aplica\u00E7\u00E3o</div>\n <div class=\"apply-details-actions\" *ngIf=\"allowManualPatchEdit\">\n <button mat-button type=\"button\" (click)=\"togglePatchPathEditor()\" [disabled]=\"!pendingPatch\">\n {{ patchPathEditorExpanded ? 'Ocultar paths' : 'Editar por path' }}\n </button>\n <button mat-button type=\"button\" (click)=\"togglePatchEditor()\" [disabled]=\"!pendingPatch\">\n {{ patchEditorExpanded ? 'Ocultar editor' : 'Editar patch' }}\n </button>\n </div>\n </div>\n <div class=\"apply-details-meta\" *ngIf=\"lastApplyAt\">\n \u00DAltima tentativa: {{ lastApplyAt | date:'short' }}\n </div>\n <div class=\"apply-paths\" *ngIf=\"getApplyPaths().length\">\n <span class=\"apply-path-chip\" *ngFor=\"let path of getApplyPaths()\">{{ path }}</span>\n </div>\n <div class=\"apply-warnings\" *ngIf=\"applyWarnings.length\">\n <div class=\"apply-warnings-title\">Avisos da aplica\u00E7\u00E3o</div>\n <div class=\"apply-warnings-list\">\n <div *ngFor=\"let warning of applyWarnings\">{{ warning }}</div>\n </div>\n </div>\n <div class=\"patch-path-editor\" *ngIf=\"allowManualPatchEdit && patchPathEditorExpanded\">\n <div class=\"patch-editor-label\">Editar por path</div>\n <div class=\"patch-editor-hint\">Texto simples vira string; para for\u00E7ar texto em true/false/n\u00FAmero, use aspas.</div>\n <div class=\"patch-path-editor-empty\" *ngIf=\"!getEditablePatchPathEdits().length\">\n Nenhum path edit\u00E1vel dispon\u00EDvel para este patch.\n </div>\n <div class=\"patch-path-rows\" *ngIf=\"getEditablePatchPathEdits().length\">\n <div class=\"patch-path-row\" *ngFor=\"let edit of getEditablePatchPathEdits(); let i = index\">\n <div class=\"patch-path-label\">{{ edit.path }}</div>\n <input\n type=\"text\"\n [(ngModel)]=\"patchPathEdits[i].valueText\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n />\n <div *ngIf=\"patchPathEdits[i].error\" class=\"patch-editor-error\">{{ patchPathEdits[i].error }}</div>\n </div>\n </div>\n <div *ngIf=\"patchPathEditorError\" class=\"patch-editor-error\">{{ patchPathEditorError }}</div>\n <div class=\"patch-editor-actions\">\n <button mat-button type=\"button\" (click)=\"resetPatchPathEdits()\">\n Restaurar valores\n </button>\n <button mat-button type=\"button\" (click)=\"applyPathEditsToPatch()\">\n Aplicar no patch\n </button>\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"reapplyPathEdits()\">\n Reaplicar por path\n </button>\n </div>\n </div>\n <div class=\"patch-editor\" *ngIf=\"allowManualPatchEdit && patchEditorExpanded\">\n <label class=\"patch-editor-label\">Patch JSON</label>\n <textarea\n [(ngModel)]=\"patchEditorText\"\n spellcheck=\"false\"\n ></textarea>\n <div *ngIf=\"patchEditorError\" class=\"patch-editor-error\">{{ patchEditorError }}</div>\n <div class=\"patch-editor-actions\">\n <button mat-button type=\"button\" (click)=\"resetPatchEditor()\">\n Restaurar original\n </button>\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"reapplyEditedPatch()\">\n Reaplicar patch\n </button>\n </div>\n </div>\n </div>\n <div class=\"review-actions\">\n <button mat-button (click)=\"close()\">Fechar</button>\n <button mat-stroked-button (click)=\"retry()\">Tentar Novamente</button>\n </div>\n </div>\n\n <!-- STATE: SUCCESS -->\n <div\n *ngIf=\"state === 'success' && (isActiveTab('task') || (!isTaskMode() && isActiveTab('suggestions')))\"\n class=\"success-area assistant-card\"\n [attr.id]=\"isTaskMode() ? 'assistant-panel-task' : 'assistant-panel-suggestions'\"\n role=\"tabpanel\"\n [attr.aria-labelledby]=\"isTaskMode() ? 'assistant-tab-task' : 'assistant-tab-suggestions'\"\n >\n <div class=\"success-msg\">\n <mat-icon class=\"success-icon\">check_circle</mat-icon>\n <span>{{ aiExplanation || 'Configura\u00E7\u00E3o atualizada.' }}</span>\n </div>\n <div *ngIf=\"warnings.length\" class=\"warnings-area\">\n <mat-icon class=\"warnings-icon\">warning_amber</mat-icon>\n <div class=\"warnings-content\">\n <div class=\"warnings-title\">Avisos</div>\n <div class=\"warnings-list\">\n <div *ngFor=\"let warning of warnings\">{{ warning }}</div>\n </div>\n </div>\n </div>\n <div *ngIf=\"shouldShowApplyDetails()\" class=\"apply-details\">\n <div class=\"apply-details-header\">\n <div class=\"apply-details-title\">Detalhes da aplica\u00E7\u00E3o</div>\n <div class=\"apply-details-actions\" *ngIf=\"allowManualPatchEdit\">\n <button mat-button type=\"button\" (click)=\"togglePatchPathEditor()\" [disabled]=\"!pendingPatch\">\n {{ patchPathEditorExpanded ? 'Ocultar paths' : 'Editar por path' }}\n </button>\n <button mat-button type=\"button\" (click)=\"togglePatchEditor()\" [disabled]=\"!pendingPatch\">\n {{ patchEditorExpanded ? 'Ocultar editor' : 'Editar e reaplicar' }}\n </button>\n </div>\n </div>\n <div class=\"apply-details-meta\" *ngIf=\"lastApplyAt\">\n Aplicado em {{ lastApplyAt | date:'short' }}\n </div>\n <div class=\"apply-paths\" *ngIf=\"getApplyPaths().length\">\n <span class=\"apply-path-chip\" *ngFor=\"let path of getApplyPaths()\">{{ path }}</span>\n </div>\n <div class=\"apply-warnings\" *ngIf=\"applyWarnings.length\">\n <div class=\"apply-warnings-title\">Avisos da aplica\u00E7\u00E3o</div>\n <div class=\"apply-warnings-list\">\n <div *ngFor=\"let warning of applyWarnings\">{{ warning }}</div>\n </div>\n </div>\n <div class=\"patch-path-editor\" *ngIf=\"allowManualPatchEdit && patchPathEditorExpanded\">\n <div class=\"patch-editor-label\">Editar por path</div>\n <div class=\"patch-editor-hint\">Texto simples vira string; para for\u00E7ar texto em true/false/n\u00FAmero, use aspas.</div>\n <div class=\"patch-path-editor-empty\" *ngIf=\"!getEditablePatchPathEdits().length\">\n Nenhum path edit\u00E1vel dispon\u00EDvel para este patch.\n </div>\n <div class=\"patch-path-rows\" *ngIf=\"getEditablePatchPathEdits().length\">\n <div class=\"patch-path-row\" *ngFor=\"let edit of getEditablePatchPathEdits(); let i = index\">\n <div class=\"patch-path-label\">{{ edit.path }}</div>\n <input\n type=\"text\"\n [(ngModel)]=\"patchPathEdits[i].valueText\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n />\n <div *ngIf=\"patchPathEdits[i].error\" class=\"patch-editor-error\">{{ patchPathEdits[i].error }}</div>\n </div>\n </div>\n <div *ngIf=\"patchPathEditorError\" class=\"patch-editor-error\">{{ patchPathEditorError }}</div>\n <div class=\"patch-editor-actions\">\n <button mat-button type=\"button\" (click)=\"resetPatchPathEdits()\">\n Restaurar valores\n </button>\n <button mat-button type=\"button\" (click)=\"applyPathEditsToPatch()\">\n Aplicar no patch\n </button>\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"reapplyPathEdits()\">\n Reaplicar por path\n </button>\n </div>\n </div>\n <div class=\"patch-editor\" *ngIf=\"allowManualPatchEdit && patchEditorExpanded\">\n <label class=\"patch-editor-label\">Patch JSON</label>\n <textarea\n [(ngModel)]=\"patchEditorText\"\n spellcheck=\"false\"\n ></textarea>\n <div *ngIf=\"patchEditorError\" class=\"patch-editor-error\">{{ patchEditorError }}</div>\n <div class=\"patch-editor-actions\">\n <button mat-button type=\"button\" (click)=\"resetPatchEditor()\">\n Restaurar original\n </button>\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"reapplyEditedPatch()\">\n Reaplicar patch\n </button>\n </div>\n </div>\n </div>\n <button mat-button color=\"warn\" (click)=\"undoLastChange()\">\n <mat-icon>undo</mat-icon> Desfazer\n </button>\n </div>\n\n </div>\n\n <div class=\"assistant-footer\">\n <ng-container *ngIf=\"!isTaskMode(); else taskFooter\">\n <button\n mat-icon-button\n type=\"button\"\n class=\"composer-leading composer-leading-btn\"\n [matMenuTriggerFor]=\"assistantQuickMenu\"\n aria-label=\"Abrir a\u00E7\u00F5es r\u00E1pidas\"\n matTooltip=\"A\u00E7\u00F5es r\u00E1pidas\"\n >\n <mat-icon>add</mat-icon>\n </button>\n <input\n #inputEl\n type=\"text\"\n [(ngModel)]=\"userPrompt\"\n [disabled]=\"state === 'processing' || state === 'applying'\"\n placeholder=\"Descreva a altera\u00E7\u00E3o que deseja aplicar\u2026\"\n autocomplete=\"off\"\n />\n <div class=\"send-actions\">\n <button\n mat-icon-button\n class=\"send-btn\"\n *ngIf=\"state === 'listening'\"\n (click)=\"submitPrompt()\"\n [disabled]=\"!userPrompt.trim()\"\n [class.ready]=\"!!userPrompt.trim()\"\n >\n <mat-icon>arrow_upward</mat-icon>\n </button>\n <mat-spinner diameter=\"20\" *ngIf=\"state === 'processing' || state === 'applying'\"></mat-spinner>\n </div>\n </ng-container>\n <ng-template #taskFooter>\n <div class=\"task-footer\">\n <div class=\"task-footer-left\">\n <button mat-button type=\"button\" (click)=\"handleTaskSecondary()\">{{ getTaskCancelLabel() }}</button>\n <button\n *ngIf=\"state === 'review'\"\n mat-stroked-button\n type=\"button\"\n (click)=\"retry()\"\n >\n {{ getTaskSecondaryLabel() }}\n </button>\n </div>\n <div class=\"task-footer-right\">\n <button\n class=\"task-primary-btn\"\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n (click)=\"confirmTaskAction()\"\n [disabled]=\"isTaskPrimaryDisabled()\"\n >\n {{ getTaskPrimaryLabel() }}\n </button>\n <mat-spinner diameter=\"20\" *ngIf=\"state === 'processing' || state === 'applying'\"></mat-spinner>\n </div>\n </div>\n </ng-template>\n </div>\n\n <mat-menu #assistantQuickMenu=\"matMenu\" panelClass=\"assistant-quick-menu-panel\">\n <button mat-menu-item type=\"button\" (click)=\"setActiveTab('chat')\">\n <mat-icon>history</mat-icon>\n <span>Hist\u00F3rico</span>\n </button>\n <button mat-menu-item type=\"button\" (click)=\"setActiveTab('suggestions')\">\n <mat-icon>lightbulb</mat-icon>\n <span>Sugest\u00F5es</span>\n </button>\n <button mat-menu-item type=\"button\" (click)=\"startNewSession()\">\n <mat-icon>add_comment</mat-icon>\n <span>Nova conversa</span>\n </button>\n <button mat-menu-item type=\"button\" (click)=\"refreshSuggestions()\" [disabled]=\"loadingSuggestions\">\n <mat-icon>refresh</mat-icon>\n <span>Atualizar sugest\u00F5es</span>\n </button>\n <button\n mat-menu-item\n type=\"button\"\n (click)=\"restoreDismissedSuggestions()\"\n [disabled]=\"!hasDismissedSuggestions()\"\n >\n <mat-icon>visibility</mat-icon>\n <span>Restaurar sugest\u00F5es ocultas</span>\n </button>\n <button\n mat-menu-item\n type=\"button\"\n class=\"assistant-quick-menu-danger\"\n (click)=\"clearHistory()\"\n [disabled]=\"!historySessions.length\"\n >\n <mat-icon>delete_outline</mat-icon>\n <span>Limpar hist\u00F3rico local</span>\n </button>\n </mat-menu>\n </div>\n\n</ng-template>\n", styles: ["@keyframes assistantPremiumEnter{0%{opacity:0;transform:translate(14px) scale(.99)}to{opacity:1;transform:translate(0) scale(1)}}:host ::ng-deep .ai-assistant-backdrop{background:color-mix(in srgb,var(--md-sys-color-scrim, var(--md-sys-color-shadow, var(--md-sys-color-on-surface))) 42%,transparent);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}::ng-deep .ai-assistant-overlay-pane{max-width:calc(100vw - 24px);max-height:calc(100vh - 24px)}.ai-assistant-panel{box-sizing:border-box;width:min(604px,100vw - 18px);min-height:min(620px,100vh - 18px);max-height:min(820px,100vh - 18px);display:flex;flex-direction:column;overflow:hidden;color:var(--md-sys-color-on-surface);border-left:1px solid color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));border-top:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));box-shadow:0 18px 48px color-mix(in srgb,var(--md-sys-color-shadow, var(--md-sys-color-on-surface)) 42%,transparent),inset 0 1px color-mix(in srgb,var(--md-sys-color-on-surface) 10%,transparent);background:radial-gradient(circle at 14% 8%,color-mix(in srgb,var(--md-sys-color-primary-container) 38%,transparent) 0%,transparent 44%),linear-gradient(165deg,color-mix(in srgb,var(--md-sys-color-surface-container-highest) 88%,var(--md-sys-color-surface)),var(--md-sys-color-surface));animation:assistantPremiumEnter .24s cubic-bezier(.22,1,.36,1)}.assistant-header{position:relative;display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:12px 16px 10px;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));background:linear-gradient(130deg,color-mix(in srgb,var(--md-sys-color-primary-container) 28%,transparent) 0%,transparent 52%),var(--md-sys-color-surface-container-low)}.assistant-header:after{content:\"\";position:absolute;left:16px;right:16px;bottom:-1px;height:1px;background:linear-gradient(90deg,color-mix(in srgb,var(--md-sys-color-primary) 55%,transparent),transparent);pointer-events:none}.assistant-header .assistant-header__left{min-width:0;display:flex;align-items:flex-start;gap:12px}.assistant-header .magic-icon{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;width:30px;height:30px;font-size:18px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 30%,transparent);box-shadow:0 4px 12px color-mix(in srgb,var(--md-sys-color-primary) 26%,transparent)}.assistant-header .assistant-title-group{min-width:0;display:flex;flex-direction:column;gap:4px}.assistant-header .assistant-title{font-size:15px;font-weight:700;letter-spacing:.01em;overflow-wrap:anywhere}.assistant-header .assistant-subtitle{display:block;font-size:11px;line-height:1.25;color:color-mix(in srgb,var(--md-sys-color-on-surface) 70%,var(--md-sys-color-on-surface-variant));overflow-wrap:anywhere}.assistant-header-chips{display:inline-flex;align-items:center;flex-wrap:wrap;gap:6px}.assistant-header .mode-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 28%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-primary-container) 64%,var(--md-sys-color-surface-container));color:color-mix(in srgb,var(--md-sys-color-on-primary-container) 85%,var(--md-sys-color-on-surface));font-size:10px;font-weight:700;letter-spacing:.04em;text-transform:uppercase}.assistant-header .mode-chip:before{content:\"\";width:6px;height:6px;border-radius:999px;background:currentColor;box-shadow:0 0 0 3px color-mix(in srgb,currentColor 16%,transparent)}.assistant-header .mode-chip.mock{border-color:color-mix(in srgb,var(--md-sys-color-error) 34%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-error-container) 72%,var(--md-sys-color-surface-container));color:color-mix(in srgb,var(--md-sys-color-on-error-container) 85%,var(--md-sys-color-error))}.assistant-header .policy-chip{padding:2px 8px;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 84%,transparent);background:var(--md-sys-color-surface-container-high);font-size:10px;letter-spacing:.02em;font-weight:600}.assistant-header .policy-chip.strict{border-color:color-mix(in srgb,var(--md-sys-color-primary) 42%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-primary-container) 56%,var(--md-sys-color-surface-container-high))}.assistant-status{display:flex;align-items:flex-start;gap:10px;padding:10px 16px;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));border-radius:0;background:linear-gradient(160deg,color-mix(in srgb,var(--md-sys-color-primary-container) 24%,transparent),transparent 48%),var(--md-sys-color-surface-container-low)}.assistant-status-dot{width:8px;height:8px;margin-top:6px;border-radius:999px;flex:0 0 auto;background:var(--md-sys-color-primary);box-shadow:0 0 0 4px color-mix(in srgb,var(--md-sys-color-primary) 16%,transparent)}.assistant-status.warning .assistant-status-dot{background:var(--md-sys-color-error);box-shadow:0 0 0 4px color-mix(in srgb,var(--md-sys-color-error) 16%,transparent)}.assistant-status.success .assistant-status-dot{background:color-mix(in srgb,var(--md-sys-color-primary) 74%,var(--md-sys-color-tertiary, var(--md-sys-color-primary)))}.assistant-status-content{min-width:0;display:flex;flex-direction:column;gap:2px}.assistant-status-label{display:flex;align-items:center;flex-wrap:wrap;gap:4px;font-size:12px;font-weight:700;line-height:1.35}.assistant-status-detail{font-size:11px;line-height:1.4;color:var(--md-sys-color-on-surface-variant);overflow-wrap:anywhere}.assistant-status-mode{padding:1px 6px;border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-primary-container) 72%,transparent);color:var(--md-sys-color-on-primary-container);font-size:10px;font-weight:700}.assistant-nav{padding:8px 16px 0}.assistant-nav .assistant-tabs{display:flex;align-items:center;gap:4px;border-radius:12px;padding:5px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));border-color:color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));background:linear-gradient(155deg,color-mix(in srgb,var(--md-sys-color-primary-container) 14%,transparent),transparent 58%),var(--md-sys-color-surface-container-low)}.assistant-nav .assistant-tab{appearance:none;min-width:0;min-height:30px;border:0;border-radius:8px;padding:0 10px;background:transparent;color:var(--md-sys-color-on-surface-variant);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;flex:1 1 0;font-size:11px;font-weight:700;letter-spacing:.01em}.assistant-nav .assistant-tab.active{background:var(--md-sys-color-surface-container-highest);color:var(--md-sys-color-on-surface);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 34%,transparent),0 6px 12px color-mix(in srgb,var(--md-sys-color-primary) 18%,transparent)}.assistant-section,.assistant-card{border-radius:14px;border-color:color-mix(in srgb,var(--md-sys-color-primary) 20%,var(--md-sys-color-outline-variant));background:linear-gradient(160deg,color-mix(in srgb,var(--md-sys-color-primary-container) 16%,transparent),transparent 50%),var(--md-sys-color-surface-container-lowest);box-shadow:0 6px 18px color-mix(in srgb,var(--md-sys-color-shadow, var(--md-sys-color-on-surface)) 12%,transparent),inset 0 1px color-mix(in srgb,var(--md-sys-color-on-surface) 7%,transparent)}.suggestions-hero{margin:2px 0 4px;padding:10px 12px;border-radius:12px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));background:linear-gradient(120deg,color-mix(in srgb,var(--md-sys-color-primary-container) 34%,transparent) 0%,transparent 52%),var(--md-sys-color-surface-container-low)}.suggestions-hero__label{font-size:10px;letter-spacing:.08em;text-transform:uppercase;font-weight:700;color:var(--md-sys-color-on-surface-variant);opacity:.88}.suggestions-hero__title{margin-top:2px;font-size:13px;font-weight:700;color:var(--md-sys-color-on-surface)}.suggestions-hero__detail{margin-top:4px;font-size:12px;line-height:1.4;color:color-mix(in srgb,var(--md-sys-color-on-surface) 78%,var(--md-sys-color-on-surface-variant))}.suggestions-content .suggestion-item{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:12px;padding:12px;border-radius:12px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));border-color:color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));background:linear-gradient(140deg,color-mix(in srgb,var(--md-sys-color-primary-container) 16%,transparent),transparent 56%),var(--md-sys-color-surface-container-lowest);transition:transform .2s cubic-bezier(.25,.8,.25,1),border-color .2s ease,box-shadow .2s ease}.suggestions-list{display:flex;flex-direction:column;gap:10px}.suggestion-copy{min-width:0;display:grid;gap:4px}.suggestion-main{min-width:0;display:flex;align-items:center;flex-wrap:wrap;gap:8px}.suggestion-icon{width:18px;height:18px;font-size:18px;flex:0 0 auto;color:var(--md-sys-color-primary)}.suggestion-label{min-width:0;font-size:13px;font-weight:700;line-height:1.35;overflow-wrap:anywhere}.suggestion-group{padding:2px 6px;border-radius:999px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface-variant);font-size:10px;font-weight:700;line-height:1.2}.suggestion-desc{font-size:12px;line-height:1.35;color:var(--md-sys-color-on-surface-variant);overflow-wrap:anywhere}.suggestion-actions{display:inline-flex;align-items:center;justify-content:flex-end;gap:4px}.suggestion-action-btn,.suggestion-arrow{width:32px;height:32px;display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;color:var(--md-sys-color-on-surface-variant)}.suggestions-content .suggestion-item:hover,.suggestions-content .suggestion-item:focus-visible{border-color:color-mix(in srgb,var(--md-sys-color-primary) 58%,var(--md-sys-color-outline-variant));box-shadow:0 8px 18px color-mix(in srgb,var(--md-sys-color-primary) 18%,transparent),inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 28%,transparent);transform:translateY(-2px) scale(1.01)}.assistant-footer{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:8px;padding:10px 16px;border-top-color:color-mix(in srgb,var(--md-sys-color-primary) 20%,var(--md-sys-color-outline-variant));background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-primary-container) 16%,transparent),transparent 56%),var(--md-sys-color-surface-container-low)}.assistant-footer .task-footer{grid-column:1/-1}.composer-leading{width:30px;height:30px;display:inline-flex;align-items:center;justify-content:center;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 30%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-primary-container) 70%,var(--md-sys-color-surface-container-low));color:var(--md-sys-color-primary);box-shadow:0 4px 10px color-mix(in srgb,var(--md-sys-color-primary) 16%,transparent)}.composer-leading mat-icon{width:16px;height:16px;font-size:16px}.assistant-footer input{box-sizing:border-box;width:100%;min-width:0;height:34px;border:1px solid;border-radius:8px;padding:0 12px;color:var(--md-sys-color-on-surface);border-color:color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));background:var(--md-sys-color-surface);box-shadow:inset 0 1px 2px color-mix(in srgb,var(--md-sys-color-shadow, var(--md-sys-color-on-surface)) 12%,transparent)}.send-actions{min-width:36px;display:inline-flex;align-items:center;justify-content:center}.assistant-footer .send-btn{--mdc-icon-button-icon-size: 20px;--mdc-icon-button-state-layer-size: 36px;--mat-icon-button-state-layer-size: 36px;width:36px;height:36px;padding:8px;line-height:1;display:inline-flex;align-items:center;justify-content:center;border-color:color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));background:var(--md-sys-color-surface)}.assistant-footer .send-btn mat-icon{width:20px;height:20px;margin:0;font-size:20px;line-height:20px;display:inline-flex;align-items:center;justify-content:center}.assistant-footer .send-btn.ready{background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary-container) 84%,var(--md-sys-color-primary)),var(--md-sys-color-primary));color:var(--md-sys-color-on-primary);box-shadow:0 8px 18px color-mix(in srgb,var(--md-sys-color-primary) 30%,transparent)}.task-primary-btn{border-radius:12px;box-shadow:0 8px 18px color-mix(in srgb,var(--md-sys-color-primary) 24%,transparent)}@media(max-width:959px){.assistant-header{padding:12px 12px 10px}.assistant-section,.assistant-card{margin:4px 12px 10px}.assistant-header:after{left:12px;right:12px}.assistant-header .assistant-title{font-size:14px}.assistant-header .assistant-subtitle{font-size:10px}.assistant-footer{grid-template-columns:minmax(0,1fr) auto}.composer-leading{display:none}}.assistant-thought{margin-top:0;gap:10px;border-color:color-mix(in srgb,var(--md-sys-color-primary) 26%,var(--md-sys-color-outline-variant));background:linear-gradient(145deg,color-mix(in srgb,var(--md-sys-color-primary-container) 28%,transparent),transparent 58%),var(--md-sys-color-surface-container-low)}.assistant-thought-meta{display:inline-flex;align-items:center;gap:6px;font-size:11px;color:var(--md-sys-color-on-surface-variant)}.assistant-thought-meta mat-icon{width:15px;height:15px;font-size:15px;color:var(--md-sys-color-primary)}.assistant-thought-summary{font-size:13px;line-height:1.45;color:var(--md-sys-color-on-surface)}.assistant-thought-plan{border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 32%,var(--md-sys-color-outline-variant));border-radius:12px;padding:10px;background:var(--md-sys-color-surface-container-lowest);display:flex;flex-direction:column;gap:8px}.assistant-thought-plan-title{font-size:13px;font-weight:700;color:var(--md-sys-color-on-surface)}.assistant-thought-plan-actions{display:grid;grid-template-columns:repeat(auto-fit,minmax(0,1fr));gap:8px}.assistant-thought-plan-actions .mdc-button{min-width:0}.assistant-thought-plan-hint{font-size:11px;color:var(--md-sys-color-on-surface-variant);line-height:1.35}.assistant-thought-checklist{display:flex;flex-direction:column;gap:5px}.assistant-thought-checklist-item{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--md-sys-color-on-surface-variant)}.assistant-thought-checklist-item mat-icon{width:14px;height:14px;font-size:14px}.assistant-thought-shimmer{display:flex;flex-direction:column;gap:8px;margin-top:4px}.assistant-thought-shimmer .shimmer-line{height:12px;border-radius:4px;position:relative;overflow:hidden;background:var(--md-sys-color-surface-container-highest)}.assistant-thought-shimmer .shimmer-line:after{content:\"\";position:absolute;inset:0;transform:translate(-100%);background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--md-sys-color-primary) 8%,transparent),transparent);animation:assistantShimmerEffect 1.5s infinite}.assistant-thought-shimmer .shimmer-line-1{width:85%}.assistant-thought-shimmer .shimmer-line-2{width:92%}.assistant-thought-shimmer .shimmer-line-3{width:64%}@keyframes assistantShimmerEffect{to{transform:translate(100%)}}.assistant-flow{grid-template-columns:1fr;gap:6px}.flow-step{display:flex;align-items:flex-start;gap:8px;text-align:left;padding:7px 8px;border-radius:10px}.flow-step-index{width:18px;height:18px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-highest);color:var(--md-sys-color-on-surface);flex:0 0 auto}.flow-step-content{min-width:0;display:flex;flex-direction:column;gap:1px}.flow-step-label{font-size:11px;font-weight:700;color:var(--md-sys-color-on-surface)}.flow-step-detail{font-size:11px;color:var(--md-sys-color-on-surface-variant);line-height:1.3}.flow-step.active .flow-step-index{border-color:color-mix(in srgb,var(--md-sys-color-primary) 60%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-primary-container) 85%,var(--md-sys-color-surface-container-highest));color:var(--md-sys-color-on-primary-container)}.flow-step.done .flow-step-index{border-color:transparent;background:color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-surface-container-highest))}.task-timeline{margin-top:4px;display:grid;gap:6px}.task-timeline-item{display:flex;align-items:flex-start;gap:8px;border:1px solid var(--md-sys-color-outline-variant);border-radius:10px;padding:6px 8px;background:var(--md-sys-color-surface-container-low);opacity:.76}.task-timeline-item.active{opacity:1;border-color:color-mix(in srgb,var(--md-sys-color-primary) 40%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-primary-container) 34%,var(--md-sys-color-surface-container-low))}.task-timeline-item.done{opacity:.9;border-color:color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant))}.task-timeline-dot{width:18px;height:18px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-highest);color:var(--md-sys-color-on-surface);flex:0 0 auto}.task-timeline-copy{min-width:0;display:flex;flex-direction:column;gap:1px}.task-timeline-title{font-size:11px;font-weight:700;color:var(--md-sys-color-on-surface)}.task-timeline-detail{font-size:11px;line-height:1.3;color:var(--md-sys-color-on-surface-variant)}.clarification-decision-head{display:inline-flex;align-items:center;width:100%;gap:6px;padding:8px 12px 0;box-sizing:border-box}.clarification-decision-index{width:18px;height:18px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 35%,var(--md-sys-color-outline-variant));color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 68%,transparent)}.clarification-decision-type{font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--md-sys-color-on-surface-variant);opacity:.92}.clarification-decision-state{font-size:10px;font-weight:700;color:var(--md-sys-color-primary)}.clarification-option{border-color:color-mix(in srgb,var(--md-sys-color-primary) 20%,var(--md-sys-color-outline-variant));background:linear-gradient(145deg,color-mix(in srgb,var(--md-sys-color-primary-container) 16%,transparent),transparent 55%),var(--md-sys-color-surface-container-low)}.clarification-option.selected{border-color:color-mix(in srgb,var(--md-sys-color-primary) 56%,var(--md-sys-color-outline-variant));background:linear-gradient(145deg,color-mix(in srgb,var(--md-sys-color-primary-container) 44%,transparent),transparent 62%),var(--md-sys-color-surface-container);box-shadow:0 8px 16px color-mix(in srgb,var(--md-sys-color-primary) 18%,transparent)}.clarification-options-block{overflow:visible;padding-right:4px}@media(max-width:959px){.assistant-thought-plan-actions{grid-template-columns:1fr}}.ai-assistant-panel{width:min(604px,100vw - 18px)}.assistant-section,.assistant-card{margin:0;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 20%,var(--md-sys-color-outline-variant))}.assistant-section{min-height:0;padding:14px 16px;overflow:visible}.assistant-card{min-height:0;padding:14px 16px 16px;overflow:visible}.suggestions-area,.assistant-history,.loading-suggestions{overflow-y:auto;overflow-x:hidden}.section-header{min-width:0;display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:10px}.section-title{min-width:0;font-size:14px;font-weight:700;line-height:1.35;overflow-wrap:anywhere}.suggestions-actions{flex:0 0 auto;display:inline-flex;align-items:center}.review-area,.error-area,.success-area,.clarification-area{padding:0;overflow-y:auto;overflow-x:hidden;scrollbar-gutter:auto}.review-trust{margin:2px 0 4px}.trust-chip{max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.warnings-area,.review-summary,.review-diff,.apply-details,.clarification-options-block,.clarification-manual-toggle{width:100%;max-width:100%;min-width:0}.review-diff{padding:12px 14px}.review-diff-full{padding:10px;overflow-x:auto}.review-diff-block{min-width:0}.review-diff-block pre{overflow-wrap:anywhere;word-break:break-word}.clarification-options-block{padding:4px 2px 10px}.clarification-option{line-height:normal}:host ::ng-deep .clarification-option .mdc-button__label{line-height:1.35!important}.clarification-plain-label{padding:6px 12px 12px;font-size:14px;line-height:1.35}.clarification-manual-toggle{margin-top:10px;padding:10px 2px 0;flex-wrap:wrap;row-gap:6px}.suggestions-content .suggestion-actions{gap:6px}.suggestions-content .suggestion-arrow,.suggestions-content .suggestion-action-btn mat-icon,.suggestions-content .suggestion-arrow mat-icon{display:inline-flex;align-items:center;justify-content:center}:host ::ng-deep .assistant-quick-menu-panel{min-width:244px;max-width:min(90vw,320px);border-radius:14px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 26%,var(--md-sys-color-outline-variant));background:var(--md-sys-color-surface-container-high);box-shadow:0 12px 28px color-mix(in srgb,var(--md-sys-color-shadow, var(--md-sys-color-on-surface)) 32%,transparent),inset 0 1px color-mix(in srgb,var(--md-sys-color-on-surface) 6%,transparent);overflow:hidden;padding:6px}:host ::ng-deep .assistant-quick-menu-panel .mat-mdc-menu-item{min-height:36px;border-radius:10px;color:var(--md-sys-color-on-surface);font-size:12px;font-weight:500;margin:1px 0}:host ::ng-deep .assistant-quick-menu-panel .mat-mdc-menu-item .mat-icon{color:color-mix(in srgb,var(--md-sys-color-on-surface) 82%,var(--md-sys-color-on-surface-variant))}:host ::ng-deep .assistant-quick-menu-panel .mat-mdc-menu-item:hover:not([disabled]){background:color-mix(in srgb,var(--md-sys-color-primary-container) 45%,transparent)}:host ::ng-deep .assistant-quick-menu-panel .mat-mdc-menu-item:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:-2px}:host ::ng-deep .assistant-quick-menu-panel .assistant-quick-menu-danger{color:var(--md-sys-color-error)}:host ::ng-deep .assistant-quick-menu-panel .assistant-quick-menu-danger .mat-icon{color:var(--md-sys-color-error)}@media(max-width:959px){::ng-deep .ai-assistant-overlay-pane{top:12px!important;left:12px!important;width:calc(100vw - 24px)!important;height:calc(100vh - 24px)!important;max-width:calc(100vw - 24px);max-height:calc(100vh - 24px);transform:none!important}.ai-assistant-panel{width:calc(100vw - 48px);min-height:min(620px,100vh - 48px);max-height:calc(100vh - 48px)}.assistant-section,.assistant-card{margin:0}.assistant-card,.assistant-section{padding:12px}}.ai-trigger-btn{--mdc-icon-button-state-layer-size: 36px;width:36px;height:36px;border-radius:8px;background:color-mix(in srgb,var(--md-sys-color-primary) 9%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 22%,transparent);color:var(--md-sys-color-primary);opacity:1}.ai-trigger-btn:hover:not(:disabled){background:color-mix(in srgb,var(--md-sys-color-primary) 16%,transparent);border-color:color-mix(in srgb,var(--md-sys-color-primary) 36%,transparent);color:var(--md-sys-color-on-primary-container)}.ai-trigger-btn:focus-visible,.assistant-close-btn:focus-visible,.assistant-tab:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.assistant-close-btn{width:28px;height:28px;color:var(--md-sys-color-on-surface-variant)}.assistant-close-btn:hover:not(:disabled){background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface)}.assistant-body{padding:12px 16px;overflow:hidden;min-height:0;flex:1;display:flex;flex-direction:column;gap:12px}.assistant-body>*{min-height:0}@media(max-width:959px){.assistant-nav{padding:8px 12px 0}.assistant-body,.assistant-footer{padding:10px 12px}.suggestions-content .suggestion-item{grid-template-columns:1fr;align-items:start}.suggestion-actions{justify-content:flex-start}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i3.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i3.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i3.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i5.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i5.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "ngmodule", type: A11yModule }, { kind: "directive", type: i6.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "ngmodule", type: MatDialogModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i8.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i9.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatChipsModule }, { kind: "component", type: i16.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["role", "id", "aria-label", "aria-description", "value", "color", "removable", "highlighted", "disableRipple", "disabled"], outputs: ["removed", "destroyed"], exportAs: ["matChip"] }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i11.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i11.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i11.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "pipe", type: i3.JsonPipe, name: "json" }, { kind: "pipe", type: i3.DatePipe, name: "date" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
6595
6673
|
}
|
|
6596
6674
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisAiAssistantComponent, decorators: [{
|
|
6597
6675
|
type: Component,
|
|
@@ -6607,7 +6685,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
6607
6685
|
MatTooltipModule,
|
|
6608
6686
|
MatChipsModule,
|
|
6609
6687
|
MatMenuModule,
|
|
6610
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Trigger Button -->\n<button \n mat-icon-button \n cdkOverlayOrigin \n #trigger=\"cdkOverlayOrigin\"\n #triggerBtn\n (click)=\"open()\"\n [disabled]=\"isOpen\"\n class=\"ai-trigger-btn\"\n matTooltip=\"Assistente de Configura\u00E7\u00E3o\"\n aria-label=\"Abrir Assistente IA\">\n <mat-icon>auto_awesome</mat-icon>\n</button>\n\n<!-- Overlay Template -->\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"isOpen\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayPush]=\"true\"\n [cdkConnectedOverlayViewportMargin]=\"12\"\n cdkConnectedOverlayPanelClass=\"ai-assistant-overlay-pane\"\n cdkConnectedOverlayBackdropClass=\"ai-assistant-backdrop\"\n (backdropClick)=\"close()\"\n (detach)=\"close()\">\n\n <div\n class=\"ai-assistant-panel\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Assistente de Configura\u00E7\u00E3o\"\n [attr.aria-busy]=\"isBusyState() ? 'true' : null\"\n cdkTrapFocus\n [cdkTrapFocusAutoCapture]=\"true\"\n (keydown)=\"onKeydown($event)\"\n >\n \n <!-- HEADER -->\n <div class=\"assistant-header\">\n <div class=\"assistant-header__left\">\n <mat-icon class=\"magic-icon\">auto_awesome</mat-icon>\n <div class=\"assistant-title-group\">\n <div class=\"assistant-title\">Assistente de Configura\u00E7\u00E3o</div>\n <div class=\"assistant-subtitle\">Copiloto contextual para ajustes guiados</div>\n <div class=\"assistant-header-chips\">\n <span\n class=\"mode-chip\"\n [class.mock]=\"mockMode\"\n [matTooltip]=\"mockMode ? 'Sem chave de API: respostas de demonstra\u00E7\u00E3o' : 'Conectado ao assistente configurado'\"\n >\n {{ mockMode ? 'Mock' : 'Conectado' }}\n </span>\n <span\n class=\"policy-chip\"\n [class.strict]=\"isStrictRiskPolicy()\"\n [matTooltip]=\"getRiskPolicyTooltip()\"\n >\n {{ getRiskPolicyLabel() }}\n </span>\n </div>\n </div>\n </div>\n <div class=\"assistant-header__right\">\n <button\n mat-icon-button\n type=\"button\"\n class=\"assistant-close-btn\"\n (click)=\"close()\"\n aria-label=\"Fechar assistente\"\n matTooltip=\"Fechar assistente\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n <div\n class=\"assistant-status\"\n [class.processing]=\"isBusyState()\"\n [class.pending]=\"state === 'clarification'\"\n [class.warning]=\"state === 'error'\"\n [class.success]=\"state === 'review' || state === 'success'\"\n [class.compact]=\"!shouldShowSystemStatusDetail()\"\n role=\"status\"\n [attr.aria-live]=\"getSystemStatusAriaLive()\"\n aria-atomic=\"true\"\n >\n <span class=\"assistant-status-dot\" aria-hidden=\"true\"></span>\n <div class=\"assistant-status-content\">\n <div class=\"assistant-status-label\">\n <span class=\"assistant-status-label-prefix\">Status:</span>\n <span>{{ getSystemStatusLabel() }}</span>\n <span *ngIf=\"shouldShowSnapshotFallbackBadge()\" class=\"assistant-status-mode\">Snapshot</span>\n </div>\n <div *ngIf=\"shouldShowSystemStatusDetail()\" class=\"assistant-status-detail\">{{ getSystemStatusDetail() }}</div>\n </div>\n </div>\n <div class=\"assistant-flow\" *ngIf=\"shouldShowTaskFlow()\" role=\"list\" aria-label=\"Fluxo da proposta\">\n <div\n class=\"flow-step\"\n role=\"listitem\"\n *ngFor=\"let step of flowSteps\"\n [class.active]=\"getFlowStepState(step.step) === 'active'\"\n [class.done]=\"getFlowStepState(step.step) === 'done'\"\n >\n <span class=\"flow-step-index\">{{ step.step }}</span>\n <span class=\"flow-step-content\">\n <span class=\"flow-step-label\">{{ step.label }}</span>\n <span class=\"flow-step-detail\">{{ getFlowStepDetail(step.step) }}</span>\n </span>\n </div>\n </div>\n <div class=\"assistant-nav\">\n <div\n class=\"assistant-tabs\"\n role=\"tablist\"\n aria-label=\"Se\u00E7\u00F5es do assistente\"\n (keydown)=\"onTabsKeydown($event)\"\n >\n <button\n class=\"assistant-tab\"\n type=\"button\"\n *ngIf=\"isTaskMode()\"\n id=\"assistant-tab-task\"\n role=\"tab\"\n aria-label=\"Proposta atual\"\n [attr.aria-selected]=\"isActiveTab('task')\"\n aria-controls=\"assistant-panel-task\"\n [attr.tabindex]=\"isActiveTab('task') ? 0 : -1\"\n [class.active]=\"isActiveTab('task')\"\n (click)=\"setActiveTab('task')\"\n >\n Proposta\n <span *ngIf=\"hasPendingClarification() && !isActiveTab('task')\" class=\"assistant-tab-badge\">1</span>\n </button>\n <button\n class=\"assistant-tab\"\n type=\"button\"\n id=\"assistant-tab-chat\"\n role=\"tab\"\n aria-label=\"Hist\u00F3rico\"\n [attr.aria-selected]=\"isActiveTab('chat')\"\n aria-controls=\"assistant-panel-chat\"\n [attr.tabindex]=\"isActiveTab('chat') ? 0 : -1\"\n [class.active]=\"isActiveTab('chat')\"\n (click)=\"setActiveTab('chat')\"\n >\n Hist\u00F3rico\n </button>\n <button\n class=\"assistant-tab\"\n type=\"button\"\n id=\"assistant-tab-suggestions\"\n role=\"tab\"\n aria-label=\"Sugest\u00F5es de melhoria\"\n [attr.aria-selected]=\"isActiveTab('suggestions')\"\n aria-controls=\"assistant-panel-suggestions\"\n [attr.tabindex]=\"isActiveTab('suggestions') ? 0 : -1\"\n [class.active]=\"isActiveTab('suggestions')\"\n (click)=\"setActiveTab('suggestions')\"\n >\n Sugest\u00F5es\n </button>\n </div>\n </div>\n\n <!-- BODY: Dynamic Content based on State -->\n <div class=\"assistant-body\">\n <div class=\"assistant-thought assistant-section\" *ngIf=\"shouldShowThoughtCard()\">\n <div class=\"assistant-thought-meta\">\n <mat-icon>psychology</mat-icon>\n <span>{{ getThoughtTimingLabel() }}</span>\n </div>\n <div class=\"assistant-thought-summary\">{{ getThoughtSummary() }}</div>\n <div class=\"assistant-thought-plan\">\n <div class=\"assistant-thought-plan-title\">{{ getThoughtPlanTitle() }}</div>\n <div class=\"assistant-thought-plan-actions\">\n <button\n mat-stroked-button\n type=\"button\"\n class=\"thought-action-details\"\n (click)=\"openThoughtDetails()\"\n [attr.aria-label]=\"getThoughtDetailsLabel()\"\n [matTooltip]=\"getThoughtDetailsTooltip()\"\n >\n {{ getThoughtDetailsLabel() }}\n </button>\n <button\n *ngIf=\"shouldShowThoughtPreviewAction()\"\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n class=\"thought-action-preview\"\n (click)=\"openThoughtPreview()\"\n [matTooltip]=\"getThoughtPreviewTooltip()\"\n >\n Pr\u00E9via\n </button>\n </div>\n <div class=\"assistant-thought-plan-hint\">{{ getThoughtActionHint() }}</div>\n <ng-container *ngIf=\"getThoughtChecklist() as thoughtChecklist\">\n <div class=\"assistant-thought-checklist\" *ngIf=\"thoughtChecklist.length\">\n <div *ngFor=\"let item of thoughtChecklist\" class=\"assistant-thought-checklist-item\">\n <mat-icon>radio_button_unchecked</mat-icon>\n <span>{{ item }}</span>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n <div *ngIf=\"processingInfoVisible\" class=\"processing-banner\">\n <mat-spinner diameter=\"16\"></mat-spinner>\n <span>{{ aiExplanation || 'Analisando solicita\u00E7\u00E3o e preparando proposta...' }}</span>\n <button mat-button type=\"button\" class=\"processing-retry\" (click)=\"retryProcessing()\">Tentar novamente</button>\n </div>\n <div\n class=\"assistant-history assistant-section\"\n *ngIf=\"historyContext && isActiveTab('chat')\"\n id=\"assistant-panel-chat\"\n role=\"tabpanel\"\n aria-labelledby=\"assistant-tab-chat\"\n >\n <div class=\"section-header\">\n <div class=\"section-heading\">\n <div class=\"section-title\">Hist\u00F3rico</div>\n <div class=\"section-subtitle\">Sess\u00F5es recentes, pedidos reaproveit\u00E1veis e desfazer r\u00E1pido.</div>\n </div>\n <div class=\"history-actions\" role=\"group\" aria-label=\"A\u00E7\u00F5es do hist\u00F3rico\">\n <button\n mat-stroked-button\n type=\"button\"\n class=\"history-action-btn\"\n (click)=\"historyExpanded = !historyExpanded\"\n [matTooltip]=\"historyExpanded ? 'Recolher hist\u00F3rico' : 'Expandir hist\u00F3rico'\"\n [attr.aria-label]=\"historyExpanded ? 'Recolher hist\u00F3rico' : 'Expandir hist\u00F3rico'\"\n [disabled]=\"!historyWarnings.length && !historySessions.length && !activeHistoryMessages.length\"\n >\n <mat-icon>{{ historyExpanded ? 'expand_less' : 'expand_more' }}</mat-icon>\n <span>{{ historyExpanded ? 'Recolher' : 'Expandir' }}</span>\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n class=\"history-action-btn\"\n (click)=\"startNewSession()\"\n matTooltip=\"Nova conversa\"\n aria-label=\"Nova conversa\"\n [disabled]=\"isBusyState()\"\n >\n <mat-icon>add_comment</mat-icon>\n <span>Nova conversa</span>\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n (click)=\"clearHistory()\"\n matTooltip=\"Limpar hist\u00F3rico local\"\n aria-label=\"Limpar hist\u00F3rico local\"\n class=\"history-action-btn history-action-btn--danger\"\n [disabled]=\"!historySessions.length\"\n >\n <mat-icon>delete_outline</mat-icon>\n <span>Limpar</span>\n </button>\n </div>\n </div>\n <div *ngIf=\"historyUndoDeleteSession\" class=\"history-undo\">\n <span>Sess\u00E3o removida.</span>\n <button mat-button type=\"button\" (click)=\"undoRemoveHistorySession()\">\n Desfazer\n </button>\n </div>\n\n <div *ngIf=\"historyExpanded && historyWarnings.length\" class=\"history-warnings\">\n <mat-icon>info</mat-icon>\n <div class=\"history-warnings-list\">\n <div *ngFor=\"let warning of historyWarnings\">{{ warning }}</div>\n <div class=\"history-warnings-hint\">\n Configure headers via API_CONFIG_STORAGE_OPTIONS no host.\n </div>\n </div>\n </div>\n\n <div *ngIf=\"historyExpanded && historySessions.length\" class=\"history-sessions\">\n <div\n class=\"history-session\"\n *ngFor=\"let session of historySessions\"\n role=\"button\"\n tabindex=\"0\"\n (click)=\"selectHistorySession(session.id)\"\n (keydown)=\"onHistorySessionCardKeydown($event, session.id)\"\n [class.active]=\"session.id === activeHistorySession?.id\"\n [matTooltip]=\"getHistorySessionTooltip(session)\"\n [matTooltipDisabled]=\"!session.componentType && !session.componentId\"\n >\n <div class=\"history-session-main\">\n <span class=\"history-session-title\">{{ session.title }}</span>\n <div class=\"history-session-main-right\">\n <span class=\"history-session-time\">{{ session.updatedAt | date:'short' }}</span>\n <div class=\"history-session-tools\">\n <button\n mat-icon-button\n type=\"button\"\n class=\"history-session-tool\"\n (click)=\"reuseHistorySessionPrompt(session.id, $event)\"\n matTooltip=\"Reusar \u00FAltimo pedido\"\n aria-label=\"Reusar \u00FAltimo pedido\"\n >\n <mat-icon>edit_note</mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n class=\"history-session-tool history-session-tool--danger\"\n (click)=\"removeHistorySession(session.id, $event)\"\n matTooltip=\"Excluir sess\u00E3o\"\n aria-label=\"Excluir sess\u00E3o\"\n >\n <mat-icon>delete_outline</mat-icon>\n </button>\n </div>\n </div>\n </div>\n <div class=\"history-session-meta\">\n <span *ngIf=\"session.componentType\" class=\"history-chip\">{{ session.componentType }}</span>\n <span *ngIf=\"session.componentId\" class=\"history-chip\">{{ session.componentId }}</span>\n </div>\n </div>\n </div>\n <div *ngIf=\"historyExpanded && !historySessions.length\" class=\"history-empty\">\n Nenhuma sess\u00E3o salva ainda.\n </div>\n\n <div *ngIf=\"historyExpanded && activeHistoryMessages.length\" class=\"history-messages\">\n <div\n *ngIf=\"activeHistoryTotalMessages > activeHistoryMessages.length\"\n class=\"history-messages-hint\"\n >\n Mostrando \u00FAltimas {{ activeHistoryMessages.length }} de {{ activeHistoryTotalMessages }} mensagens.\n </div>\n <div\n *ngFor=\"let msg of activeHistoryMessages\"\n class=\"history-message\"\n [class.user]=\"msg.role === 'user'\"\n [class.assistant]=\"msg.role === 'assistant'\"\n >\n <div class=\"history-message-header\">\n <span class=\"history-message-role\">{{ msg.role === 'user' ? 'Voc\u00EA' : 'Assistente' }}</span>\n <span class=\"history-message-time\">{{ msg.createdAt | date:'shortTime' }}</span>\n <span\n *ngIf=\"msg.context?.usedRag\"\n class=\"history-rag\"\n matTooltip=\"Resposta baseada em contexto recuperado (RAG)\"\n >RAG</span>\n </div>\n <div class=\"history-message-text\">{{ msg.text }}</div>\n </div>\n </div>\n <div *ngIf=\"historyExpanded && historySessions.length && !activeHistoryMessages.length\" class=\"history-empty history-empty--panel\">\n Selecione uma sess\u00E3o para visualizar as mensagens.\n </div>\n <div class=\"history-helper\" *ngIf=\"historyExpanded\">\n O hist\u00F3rico \u00E9 local ao usu\u00E1rio e ao componente atual.\n </div>\n </div>\n\n <div\n class=\"loading-suggestions assistant-section\"\n *ngIf=\"loadingSuggestions && isActiveTab('suggestions')\"\n id=\"assistant-panel-suggestions\"\n role=\"tabpanel\"\n aria-labelledby=\"assistant-tab-suggestions\"\n >\n <mat-spinner diameter=\"20\"></mat-spinner>\n <span>Carregando sugest\u00F5es de melhoria...</span>\n </div>\n \n <!-- STATE: LISTENING (Suggestions) -->\n <div\n *ngIf=\"state === 'listening' && isActiveTab('suggestions')\"\n class=\"suggestions-area assistant-section\"\n id=\"assistant-panel-suggestions\"\n role=\"tabpanel\"\n aria-labelledby=\"assistant-tab-suggestions\"\n >\n <div class=\"section-header\">\n <div class=\"section-title\">Sugest\u00F5es de melhoria</div>\n <div class=\"suggestions-actions\">\n <button mat-icon-button type=\"button\" (click)=\"refreshSuggestions()\" [disabled]=\"loadingSuggestions\" matTooltip=\"Atualizar sugest\u00F5es\">\n <mat-icon>refresh</mat-icon>\n </button>\n </div>\n </div>\n <div class=\"suggestions-hero\" *ngIf=\"!loadingSuggestions\">\n <div class=\"suggestions-hero__label\">Contexto ativo</div>\n <div class=\"suggestions-hero__title\">{{ adapter.componentName || 'Componente atual' }}</div>\n <div class=\"suggestions-hero__detail\">{{ getSystemStatusDetail() }}</div>\n </div>\n <div *ngIf=\"suggestionsWarnings.length\" class=\"warnings-area\">\n <mat-icon class=\"warnings-icon\">warning_amber</mat-icon>\n <div class=\"warnings-content\">\n <div class=\"warnings-title\">Avisos</div>\n <div class=\"warnings-list\">\n <div *ngFor=\"let warning of suggestionsWarnings\">{{ warning }}</div>\n </div>\n </div>\n </div>\n <div class=\"suggestions-content\" *ngIf=\"!loadingSuggestions && (richSuggestions.length || hasDismissedSuggestions())\">\n <div class=\"suggestions-filter\" *ngIf=\"hasDismissedSuggestions()\">\n <span>{{ getDismissedSuggestionCount() }} oculta(s)</span>\n <button mat-button type=\"button\" (click)=\"restoreDismissedSuggestions()\">\n Restaurar\n </button>\n </div>\n <div class=\"suggestions-list\" *ngIf=\"getVisibleSuggestions().length; else allSuggestionsHidden\">\n <div\n class=\"suggestion-item\"\n *ngFor=\"let sug of getVisibleSuggestions()\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"'Selecionar sugest\u00E3o: ' + sug.label\"\n (click)=\"selectSuggestion(sug)\"\n (keydown)=\"onSuggestionCardKeydown($event, sug)\"\n >\n <div class=\"suggestion-copy\">\n <div class=\"suggestion-main\">\n <mat-icon *ngIf=\"sug.icon\" class=\"suggestion-icon\">{{ sug.icon }}</mat-icon>\n <span class=\"suggestion-label\">{{ sug.label }}</span>\n <span *ngIf=\"sug.group\" class=\"suggestion-group\">{{ sug.group }}</span>\n </div>\n <div *ngIf=\"sug.description\" class=\"suggestion-desc\">{{ sug.description }}</div>\n </div>\n <div class=\"suggestion-actions\">\n <span class=\"suggestion-arrow\" aria-hidden=\"true\">\n <mat-icon>chevron_right</mat-icon>\n </span>\n <button\n mat-icon-button\n type=\"button\"\n class=\"suggestion-action-btn\"\n (click)=\"prepareSuggestionPrompt(sug, $event)\"\n matTooltip=\"Refinar pedido\"\n aria-label=\"Refinar pedido\"\n >\n <mat-icon>edit</mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n class=\"suggestion-action-btn suggestion-action-btn--danger\"\n (click)=\"dismissSuggestion(sug, $event)\"\n matTooltip=\"Ocultar sugest\u00E3o\"\n aria-label=\"Ocultar sugest\u00E3o\"\n >\n <mat-icon>visibility_off</mat-icon>\n </button>\n </div>\n </div>\n </div>\n <ng-template #allSuggestionsHidden>\n <div class=\"suggestions-empty suggestions-empty--inline\">\n Todas as sugest\u00F5es foram ocultadas.\n </div>\n </ng-template>\n </div>\n <div class=\"suggestions-empty\" *ngIf=\"!loadingSuggestions && !richSuggestions.length\">\n Nenhuma sugest\u00E3o dispon\u00EDvel no momento.\n </div>\n <div class=\"suggestions-helper\" *ngIf=\"!loadingSuggestions && !richSuggestions.length\">\n Selecione uma sugest\u00E3o acima ou descreva uma altera\u00E7\u00E3o no campo inferior.\n </div>\n </div>\n\n <!-- STATE: CLARIFICATION (Two-Step Flow) -->\n <div\n *ngIf=\"state === 'clarification' && isActiveTab('task')\"\n class=\"clarification-area assistant-card\"\n id=\"assistant-panel-task\"\n role=\"tabpanel\"\n aria-labelledby=\"assistant-tab-task\"\n >\n <div class=\"task-header\" *ngIf=\"!shouldShowThoughtCard()\">\n <div class=\"task-title\">{{ getTaskTitle() }}</div>\n <div class=\"task-subtitle\">{{ getTaskSubtitle() }}</div>\n <div *ngIf=\"clarificationOptions.length > 1 && getTaskSelectionSummary() as selectionSummary\" class=\"task-meta\">\n <span class=\"task-meta-label\">Selecionado:</span>\n <span class=\"task-meta-value\">{{ selectionSummary }}</span>\n </div>\n <div *ngIf=\"shouldShowTaskSteps()\" class=\"task-steps\">\n <span class=\"task-step active\">1 Dados</span>\n <span class=\"task-step\">2 Layout</span>\n <span class=\"task-step\">3 Revis\u00E3o</span>\n </div>\n </div>\n <div *ngIf=\"clarificationResponseType === 'context'\" class=\"context-only\">\n <mat-spinner diameter=\"24\"></mat-spinner>\n <div class=\"context-only-hint\">Buscando contexto adicional...</div>\n </div>\n <ng-template #clarificationOptionContent let-opt let-index=\"index\" let-compact=\"compact\">\n <div class=\"clarification-decision-head\" *ngIf=\"!compact\">\n <span class=\"clarification-decision-index\">{{ index + 1 }}</span>\n <span class=\"clarification-decision-type\">{{ getClarificationOptionKindLabel(opt) }}</span>\n <span class=\"spacer\"></span>\n <span class=\"clarification-decision-state\" *ngIf=\"isClarificationSelected(opt)\">Selecionado</span>\n </div>\n <ng-container [ngSwitch]=\"getClarificationOptionLayout(opt)\">\n <div *ngSwitchCase=\"'endpoint'\" class=\"clarification-card\">\n <div class=\"clarification-card-header\">\n <mat-icon class=\"endpoint-icon\">{{ getEndpointIcon(opt) }}</mat-icon>\n <ng-container *ngIf=\"getEndpointMethod(opt) as method\">\n <span class=\"endpoint-method\" [attr.data-method]=\"method\">{{ method }}</span>\n </ng-container>\n <span class=\"endpoint-label\">{{ opt.label }}</span>\n <span class=\"spacer\"></span>\n <mat-icon class=\"select-indicator\">\n {{ isClarificationSelected(opt) ? 'check_circle' : 'radio_button_unchecked' }}\n </mat-icon>\n </div>\n <div class=\"clarification-card-body\">\n <ng-container *ngIf=\"getEndpointPath(opt) as path\">\n <div class=\"endpoint-path\">{{ path }}</div>\n </ng-container>\n <div\n *ngIf=\"opt.contextHints?.description\"\n class=\"endpoint-description\"\n [matTooltip]=\"getDescriptionTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowDescriptionTooltip(opt)\"\n >\n {{ opt.contextHints?.description }}\n </div>\n </div>\n </div>\n <div *ngSwitchCase=\"'color'\" class=\"clarification-color\">\n <span\n class=\"color-swatch\"\n [style.background]=\"getSafeHexColor(opt) || 'var(--md-sys-color-surface-container-highest)'\"\n ></span>\n <div class=\"color-meta\">\n <span class=\"color-label\">{{ opt.label }}</span>\n <span *ngIf=\"opt.contextHints?.hexColor\" class=\"color-value\">{{ opt.contextHints?.hexColor }}</span>\n </div>\n </div>\n <div *ngSwitchCase=\"'description'\" class=\"clarification-description\">\n <span class=\"clarification-label\">{{ opt.label }}</span>\n <span\n *ngIf=\"opt.contextHints?.description\"\n class=\"clarification-subtitle\"\n [matTooltip]=\"getDescriptionTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowDescriptionTooltip(opt)\"\n >\n {{ opt.contextHints?.description }}\n </span>\n </div>\n <span *ngSwitchDefault class=\"clarification-plain-label\">{{ opt.label }}</span>\n </ng-container>\n </ng-template>\n <div *ngIf=\"warnings.length\" class=\"warnings-area\">\n <mat-icon class=\"warnings-icon\">warning_amber</mat-icon>\n <div class=\"warnings-content\">\n <div class=\"warnings-title\">Avisos</div>\n <div class=\"warnings-list\">\n <div *ngFor=\"let warning of warnings\">{{ warning }}</div>\n </div>\n </div>\n </div>\n <div\n *ngIf=\"clarificationQuestions.length\"\n class=\"clarification-questions\"\n [class.attention-highlight]=\"highlightClarificationDetails && !clarificationOptions.length\"\n >\n <div *ngFor=\"let question of clarificationQuestions; let i = index\" class=\"clarification-question\">\n <div class=\"clarification-question-label\">{{ question }}</div>\n <input\n type=\"text\"\n [(ngModel)]=\"clarificationAnswers[i]\"\n [placeholder]=\"'Resposta ' + (i + 1)\"\n autocomplete=\"off\">\n </div>\n </div>\n <div\n *ngIf=\"clarificationOptions.length\"\n class=\"clarification-options-block\"\n [class.attention-highlight]=\"highlightClarificationDetails\"\n >\n <div class=\"clarification-options-title\">\n {{ clarificationOptions.length === 1 ? 'Decis\u00E3o sugerida' : 'Decis\u00F5es sugeridas' }}\n </div>\n <div *ngIf=\"clarificationOptions.length === 1\" class=\"clarification-options-hint\">\n Etapa 2 de 4: confirme a melhor op\u00E7\u00E3o para continuar.\n </div>\n <div *ngIf=\"clarificationOptions.length > 1\" class=\"clarification-options-hint\">\n Etapa 2 de 4: selecione a alternativa mais aderente para gerar a proposta.\n </div>\n <div\n *ngIf=\"clarificationResponseType === 'confirm'\"\n class=\"clarification-buttons\"\n [class.list]=\"clarificationPresentation === 'list'\"\n >\n <button\n mat-button\n type=\"button\"\n *ngFor=\"let opt of clarificationOptions; let i = index\"\n (click)=\"onClarificationOptionClick(opt)\"\n class=\"clarification-option\"\n [class.selected]=\"isClarificationSelected(opt)\"\n [matTooltip]=\"getClarificationTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowClarificationTooltip(opt) || isEndpointOption(opt)\"\n >\n <ng-container *ngTemplateOutlet=\"clarificationOptionContent; context: { $implicit: opt, index: i, compact: false }\"></ng-container>\n </button>\n </div>\n <div\n *ngIf=\"clarificationSelectionMode === 'multiple'\"\n class=\"clarification-buttons\"\n [class.list]=\"clarificationPresentation === 'list'\"\n >\n <button\n mat-button\n type=\"button\"\n *ngFor=\"let opt of clarificationOptions; let i = index\"\n (click)=\"onClarificationOptionClick(opt)\"\n [class.selected]=\"isClarificationSelected(opt)\"\n class=\"clarification-option\"\n [matTooltip]=\"getClarificationTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowClarificationTooltip(opt) || isEndpointOption(opt)\"\n >\n <ng-container *ngTemplateOutlet=\"clarificationOptionContent; context: { $implicit: opt, index: i, compact: false }\"></ng-container>\n </button>\n </div>\n <div\n *ngIf=\"clarificationResponseType !== 'confirm' && clarificationSelectionMode === 'single' && clarificationPresentation !== 'chips'\"\n class=\"clarification-buttons\"\n [class.list]=\"clarificationPresentation === 'list'\"\n >\n <button\n mat-button\n type=\"button\"\n *ngFor=\"let opt of clarificationOptions; let i = index\"\n (click)=\"onClarificationOptionClick(opt)\"\n class=\"clarification-option\"\n [class.selected]=\"isClarificationSelected(opt)\"\n [matTooltip]=\"getClarificationTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowClarificationTooltip(opt) || isEndpointOption(opt)\"\n >\n <ng-container *ngTemplateOutlet=\"clarificationOptionContent; context: { $implicit: opt, index: i, compact: false }\"></ng-container>\n </button>\n </div>\n <div\n *ngIf=\"clarificationResponseType !== 'confirm' && clarificationSelectionMode === 'single' && clarificationPresentation === 'chips'\"\n class=\"clarification-chips\"\n >\n <ng-container *ngFor=\"let opt of clarificationOptions; let i = index\">\n <button\n *ngIf=\"isEndpointOption(opt); else chipOption\"\n mat-button\n type=\"button\"\n class=\"clarification-option clarification-card-button\"\n (click)=\"onClarificationOptionClick(opt)\"\n [class.selected]=\"isClarificationSelected(opt)\"\n [matTooltip]=\"getClarificationTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowClarificationTooltip(opt) || isEndpointOption(opt)\"\n >\n <ng-container *ngTemplateOutlet=\"clarificationOptionContent; context: { $implicit: opt, index: i, compact: false }\"></ng-container>\n </button>\n <ng-template #chipOption>\n <mat-chip\n (click)=\"onClarificationOptionClick(opt)\"\n [matTooltip]=\"getClarificationTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowClarificationTooltip(opt)\"\n class=\"clarification-chip\"\n >\n <ng-container *ngTemplateOutlet=\"clarificationOptionContent; context: { $implicit: opt, index: i, compact: true }\"></ng-container>\n </mat-chip>\n </ng-template>\n </ng-container>\n </div>\n </div>\n <div\n *ngIf=\"clarificationAllowCustom && clarificationResponseType !== 'context'\"\n class=\"clarification-manual-toggle\"\n >\n <span class=\"clarification-manual-label\">N\u00E3o encontrou o recurso?</span>\n <button mat-button type=\"button\" (click)=\"toggleManualInput()\">\n {{ showManualInput ? 'Ocultar resposta manual' : 'Responder manualmente' }}\n </button>\n </div>\n <div\n *ngIf=\"clarificationAllowCustom && showManualInput && clarificationResponseType !== 'context'\"\n class=\"clarification-free\"\n >\n <input\n type=\"text\"\n [(ngModel)]=\"clarificationFreeText\"\n placeholder=\"Digite sua resposta\u2026\"\n autocomplete=\"off\"\n (keydown.enter)=\"confirmTaskAction()\"\n />\n </div>\n <div\n *ngIf=\"clarificationAllowCustom && showManualInput && clarificationResponseType !== 'context'\"\n class=\"clarification-free-hint\"\n >\n Pressione Enter para enviar.\n </div>\n </div>\n\n <!-- STATE: REVIEW (Diff/Explanation) -->\n <div\n *ngIf=\"state === 'review' && isActiveTab('task')\"\n class=\"review-area assistant-card\"\n id=\"assistant-panel-task\"\n role=\"tabpanel\"\n aria-labelledby=\"assistant-tab-task\"\n >\n <div class=\"task-header\" *ngIf=\"!shouldShowThoughtCard()\">\n <div class=\"task-title\">{{ getTaskTitle() }}</div>\n <div class=\"task-subtitle\">{{ getTaskSubtitle() }}</div>\n <div *ngIf=\"clarificationOptions.length > 1 && getTaskSelectionSummary() as selectionSummary\" class=\"task-meta\">\n <span class=\"task-meta-label\">Selecionado:</span>\n <span class=\"task-meta-value\">{{ selectionSummary }}</span>\n </div>\n <div *ngIf=\"shouldShowTaskSteps()\" class=\"task-steps\">\n <span class=\"task-step\">1 Dados</span>\n <span class=\"task-step\">2 Layout</span>\n <span class=\"task-step active\">3 Revis\u00E3o</span>\n </div>\n </div>\n <div *ngIf=\"warnings.length\" class=\"warnings-area\">\n <mat-icon class=\"warnings-icon\">warning_amber</mat-icon>\n <div class=\"warnings-content\">\n <div class=\"warnings-title\">Avisos</div>\n <div class=\"warnings-list\">\n <div *ngFor=\"let warning of warnings\">{{ warning }}</div>\n </div>\n </div>\n </div>\n <div class=\"review-trust\">\n <span class=\"trust-chip\" [matTooltip]=\"getScopeTooltip()\">{{ getScopeLabel() }}</span>\n <span class=\"trust-chip\" [matTooltip]=\"getConfidenceTooltip()\">{{ getConfidenceLabel() }}</span>\n <span class=\"trust-chip risk-chip\" [class.medium]=\"getReviewRiskLevel() === 'm\u00E9dio'\" [class.high]=\"getReviewRiskLevel() === 'alto'\">\n Risco {{ getReviewRiskLevel() }}\n </span>\n </div>\n <div class=\"review-summary\" [class.attention-highlight]=\"highlightReviewDetails\">\n <div class=\"review-summary-title\">Resumo da proposta</div>\n <div class=\"review-summary-line\">{{ getReviewSummary() }}</div>\n </div>\n <div class=\"review-diff\">\n <div class=\"review-diff-title\">Pr\u00E9via de mudan\u00E7as</div>\n <ng-container *ngIf=\"pendingDiff.length; else noDiffPreview\">\n <div class=\"review-diff-summary\">\n <div *ngFor=\"let line of getDiffSummaryLines()\" class=\"review-diff-line\">{{ line }}</div>\n <div *ngIf=\"pendingDiff.length > 3\" class=\"review-diff-more\">\u2026 +{{ pendingDiff.length - 3 }} mudan\u00E7as</div>\n </div>\n <button mat-stroked-button type=\"button\" class=\"review-diff-toggle\" (click)=\"toggleFullDiff()\">\n {{ getDiffToggleLabel() }}\n </button>\n </ng-container>\n <ng-template #noDiffPreview>\n <div class=\"review-diff-empty\">\n N\u00E3o foi poss\u00EDvel gerar um diff estruturado. Revise o resumo e aplique com cautela.\n </div>\n </ng-template>\n <div *ngIf=\"showFullDiff && pendingDiff.length\" class=\"review-diff-full\">\n <div *ngFor=\"let diff of pendingDiff\" class=\"review-diff-block\">\n <div class=\"review-diff-path\">{{ diff.path }}</div>\n <div class=\"review-diff-label\">Antes:</div>\n <pre>{{ diff.before | json }}</pre>\n <div class=\"review-diff-label\">Depois:</div>\n <pre>{{ diff.after | json }}</pre>\n </div>\n </div>\n </div>\n <div class=\"ai-explanation\" *ngIf=\"aiExplanation.trim()\">\n {{ aiExplanation }}\n </div>\n </div>\n\n <!-- STATE: ERROR -->\n <div\n *ngIf=\"state === 'error' && (isActiveTab('task') || (!isTaskMode() && isActiveTab('suggestions')))\"\n class=\"error-area assistant-card\"\n [attr.id]=\"isTaskMode() ? 'assistant-panel-task' : 'assistant-panel-suggestions'\"\n role=\"tabpanel\"\n [attr.aria-labelledby]=\"isTaskMode() ? 'assistant-tab-task' : 'assistant-tab-suggestions'\"\n >\n <div class=\"error-msg\">\n <mat-icon color=\"warn\">error_outline</mat-icon>\n <span>{{ errorMsg }}</span>\n </div>\n <div *ngIf=\"warnings.length\" class=\"warnings-area\">\n <mat-icon class=\"warnings-icon\">warning_amber</mat-icon>\n <div class=\"warnings-content\">\n <div class=\"warnings-title\">Avisos</div>\n <div class=\"warnings-list\">\n <div *ngFor=\"let warning of warnings\">{{ warning }}</div>\n </div>\n </div>\n </div>\n <div *ngIf=\"shouldShowApplyDetails()\" class=\"apply-details\">\n <div class=\"apply-details-header\">\n <div class=\"apply-details-title\">Detalhes da aplica\u00E7\u00E3o</div>\n <div class=\"apply-details-actions\" *ngIf=\"allowManualPatchEdit\">\n <button mat-button type=\"button\" (click)=\"togglePatchPathEditor()\" [disabled]=\"!pendingPatch\">\n {{ patchPathEditorExpanded ? 'Ocultar paths' : 'Editar por path' }}\n </button>\n <button mat-button type=\"button\" (click)=\"togglePatchEditor()\" [disabled]=\"!pendingPatch\">\n {{ patchEditorExpanded ? 'Ocultar editor' : 'Editar patch' }}\n </button>\n </div>\n </div>\n <div class=\"apply-details-meta\" *ngIf=\"lastApplyAt\">\n \u00DAltima tentativa: {{ lastApplyAt | date:'short' }}\n </div>\n <div class=\"apply-paths\" *ngIf=\"getApplyPaths().length\">\n <span class=\"apply-path-chip\" *ngFor=\"let path of getApplyPaths()\">{{ path }}</span>\n </div>\n <div class=\"apply-warnings\" *ngIf=\"applyWarnings.length\">\n <div class=\"apply-warnings-title\">Avisos da aplica\u00E7\u00E3o</div>\n <div class=\"apply-warnings-list\">\n <div *ngFor=\"let warning of applyWarnings\">{{ warning }}</div>\n </div>\n </div>\n <div class=\"patch-path-editor\" *ngIf=\"allowManualPatchEdit && patchPathEditorExpanded\">\n <div class=\"patch-editor-label\">Editar por path</div>\n <div class=\"patch-editor-hint\">Texto simples vira string; para for\u00E7ar texto em true/false/n\u00FAmero, use aspas.</div>\n <div class=\"patch-path-editor-empty\" *ngIf=\"!getEditablePatchPathEdits().length\">\n Nenhum path edit\u00E1vel dispon\u00EDvel para este patch.\n </div>\n <div class=\"patch-path-rows\" *ngIf=\"getEditablePatchPathEdits().length\">\n <div class=\"patch-path-row\" *ngFor=\"let edit of getEditablePatchPathEdits(); let i = index\">\n <div class=\"patch-path-label\">{{ edit.path }}</div>\n <input\n type=\"text\"\n [(ngModel)]=\"patchPathEdits[i].valueText\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n />\n <div *ngIf=\"patchPathEdits[i].error\" class=\"patch-editor-error\">{{ patchPathEdits[i].error }}</div>\n </div>\n </div>\n <div *ngIf=\"patchPathEditorError\" class=\"patch-editor-error\">{{ patchPathEditorError }}</div>\n <div class=\"patch-editor-actions\">\n <button mat-button type=\"button\" (click)=\"resetPatchPathEdits()\">\n Restaurar valores\n </button>\n <button mat-button type=\"button\" (click)=\"applyPathEditsToPatch()\">\n Aplicar no patch\n </button>\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"reapplyPathEdits()\">\n Reaplicar por path\n </button>\n </div>\n </div>\n <div class=\"patch-editor\" *ngIf=\"allowManualPatchEdit && patchEditorExpanded\">\n <label class=\"patch-editor-label\">Patch JSON</label>\n <textarea\n [(ngModel)]=\"patchEditorText\"\n spellcheck=\"false\"\n ></textarea>\n <div *ngIf=\"patchEditorError\" class=\"patch-editor-error\">{{ patchEditorError }}</div>\n <div class=\"patch-editor-actions\">\n <button mat-button type=\"button\" (click)=\"resetPatchEditor()\">\n Restaurar original\n </button>\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"reapplyEditedPatch()\">\n Reaplicar patch\n </button>\n </div>\n </div>\n </div>\n <div class=\"review-actions\">\n <button mat-button (click)=\"close()\">Fechar</button>\n <button mat-stroked-button (click)=\"retry()\">Tentar Novamente</button>\n </div>\n </div>\n\n <!-- STATE: SUCCESS -->\n <div\n *ngIf=\"state === 'success' && (isActiveTab('task') || (!isTaskMode() && isActiveTab('suggestions')))\"\n class=\"success-area assistant-card\"\n [attr.id]=\"isTaskMode() ? 'assistant-panel-task' : 'assistant-panel-suggestions'\"\n role=\"tabpanel\"\n [attr.aria-labelledby]=\"isTaskMode() ? 'assistant-tab-task' : 'assistant-tab-suggestions'\"\n >\n <div class=\"success-msg\">\n <mat-icon class=\"success-icon\">check_circle</mat-icon>\n <span>{{ aiExplanation || 'Configura\u00E7\u00E3o atualizada.' }}</span>\n </div>\n <div *ngIf=\"warnings.length\" class=\"warnings-area\">\n <mat-icon class=\"warnings-icon\">warning_amber</mat-icon>\n <div class=\"warnings-content\">\n <div class=\"warnings-title\">Avisos</div>\n <div class=\"warnings-list\">\n <div *ngFor=\"let warning of warnings\">{{ warning }}</div>\n </div>\n </div>\n </div>\n <div *ngIf=\"shouldShowApplyDetails()\" class=\"apply-details\">\n <div class=\"apply-details-header\">\n <div class=\"apply-details-title\">Detalhes da aplica\u00E7\u00E3o</div>\n <div class=\"apply-details-actions\" *ngIf=\"allowManualPatchEdit\">\n <button mat-button type=\"button\" (click)=\"togglePatchPathEditor()\" [disabled]=\"!pendingPatch\">\n {{ patchPathEditorExpanded ? 'Ocultar paths' : 'Editar por path' }}\n </button>\n <button mat-button type=\"button\" (click)=\"togglePatchEditor()\" [disabled]=\"!pendingPatch\">\n {{ patchEditorExpanded ? 'Ocultar editor' : 'Editar e reaplicar' }}\n </button>\n </div>\n </div>\n <div class=\"apply-details-meta\" *ngIf=\"lastApplyAt\">\n Aplicado em {{ lastApplyAt | date:'short' }}\n </div>\n <div class=\"apply-paths\" *ngIf=\"getApplyPaths().length\">\n <span class=\"apply-path-chip\" *ngFor=\"let path of getApplyPaths()\">{{ path }}</span>\n </div>\n <div class=\"apply-warnings\" *ngIf=\"applyWarnings.length\">\n <div class=\"apply-warnings-title\">Avisos da aplica\u00E7\u00E3o</div>\n <div class=\"apply-warnings-list\">\n <div *ngFor=\"let warning of applyWarnings\">{{ warning }}</div>\n </div>\n </div>\n <div class=\"patch-path-editor\" *ngIf=\"allowManualPatchEdit && patchPathEditorExpanded\">\n <div class=\"patch-editor-label\">Editar por path</div>\n <div class=\"patch-editor-hint\">Texto simples vira string; para for\u00E7ar texto em true/false/n\u00FAmero, use aspas.</div>\n <div class=\"patch-path-editor-empty\" *ngIf=\"!getEditablePatchPathEdits().length\">\n Nenhum path edit\u00E1vel dispon\u00EDvel para este patch.\n </div>\n <div class=\"patch-path-rows\" *ngIf=\"getEditablePatchPathEdits().length\">\n <div class=\"patch-path-row\" *ngFor=\"let edit of getEditablePatchPathEdits(); let i = index\">\n <div class=\"patch-path-label\">{{ edit.path }}</div>\n <input\n type=\"text\"\n [(ngModel)]=\"patchPathEdits[i].valueText\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n />\n <div *ngIf=\"patchPathEdits[i].error\" class=\"patch-editor-error\">{{ patchPathEdits[i].error }}</div>\n </div>\n </div>\n <div *ngIf=\"patchPathEditorError\" class=\"patch-editor-error\">{{ patchPathEditorError }}</div>\n <div class=\"patch-editor-actions\">\n <button mat-button type=\"button\" (click)=\"resetPatchPathEdits()\">\n Restaurar valores\n </button>\n <button mat-button type=\"button\" (click)=\"applyPathEditsToPatch()\">\n Aplicar no patch\n </button>\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"reapplyPathEdits()\">\n Reaplicar por path\n </button>\n </div>\n </div>\n <div class=\"patch-editor\" *ngIf=\"allowManualPatchEdit && patchEditorExpanded\">\n <label class=\"patch-editor-label\">Patch JSON</label>\n <textarea\n [(ngModel)]=\"patchEditorText\"\n spellcheck=\"false\"\n ></textarea>\n <div *ngIf=\"patchEditorError\" class=\"patch-editor-error\">{{ patchEditorError }}</div>\n <div class=\"patch-editor-actions\">\n <button mat-button type=\"button\" (click)=\"resetPatchEditor()\">\n Restaurar original\n </button>\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"reapplyEditedPatch()\">\n Reaplicar patch\n </button>\n </div>\n </div>\n </div>\n <button mat-button color=\"warn\" (click)=\"undoLastChange()\">\n <mat-icon>undo</mat-icon> Desfazer\n </button>\n </div>\n\n </div>\n\n <div class=\"assistant-footer\">\n <ng-container *ngIf=\"!isTaskMode(); else taskFooter\">\n <button\n mat-icon-button\n type=\"button\"\n class=\"composer-leading composer-leading-btn\"\n [matMenuTriggerFor]=\"assistantQuickMenu\"\n aria-label=\"Abrir a\u00E7\u00F5es r\u00E1pidas\"\n matTooltip=\"A\u00E7\u00F5es r\u00E1pidas\"\n >\n <mat-icon>add</mat-icon>\n </button>\n <input\n #inputEl\n type=\"text\"\n [(ngModel)]=\"userPrompt\"\n [disabled]=\"state === 'processing' || state === 'applying'\"\n placeholder=\"Descreva a altera\u00E7\u00E3o que deseja aplicar\u2026\"\n autocomplete=\"off\"\n />\n <div class=\"send-actions\">\n <button\n mat-icon-button\n class=\"send-btn\"\n *ngIf=\"state === 'listening'\"\n (click)=\"submitPrompt()\"\n [disabled]=\"!userPrompt.trim()\"\n [class.ready]=\"!!userPrompt.trim()\"\n >\n <mat-icon>arrow_upward</mat-icon>\n </button>\n <mat-spinner diameter=\"20\" *ngIf=\"state === 'processing' || state === 'applying'\"></mat-spinner>\n </div>\n </ng-container>\n <ng-template #taskFooter>\n <div class=\"task-footer\">\n <div class=\"task-footer-left\">\n <button mat-button type=\"button\" (click)=\"handleTaskSecondary()\">{{ getTaskCancelLabel() }}</button>\n <button\n *ngIf=\"state === 'review'\"\n mat-stroked-button\n type=\"button\"\n (click)=\"retry()\"\n >\n {{ getTaskSecondaryLabel() }}\n </button>\n </div>\n <div class=\"task-footer-right\">\n <button\n class=\"task-primary-btn\"\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n (click)=\"confirmTaskAction()\"\n [disabled]=\"isTaskPrimaryDisabled()\"\n >\n {{ getTaskPrimaryLabel() }}\n </button>\n <mat-spinner diameter=\"20\" *ngIf=\"state === 'processing' || state === 'applying'\"></mat-spinner>\n </div>\n </div>\n </ng-template>\n </div>\n\n <mat-menu #assistantQuickMenu=\"matMenu\" panelClass=\"assistant-quick-menu-panel\">\n <button mat-menu-item type=\"button\" (click)=\"setActiveTab('chat')\">\n <mat-icon>history</mat-icon>\n <span>Hist\u00F3rico</span>\n </button>\n <button mat-menu-item type=\"button\" (click)=\"setActiveTab('suggestions')\">\n <mat-icon>lightbulb</mat-icon>\n <span>Sugest\u00F5es</span>\n </button>\n <button mat-menu-item type=\"button\" (click)=\"startNewSession()\">\n <mat-icon>add_comment</mat-icon>\n <span>Nova conversa</span>\n </button>\n <button mat-menu-item type=\"button\" (click)=\"refreshSuggestions()\" [disabled]=\"loadingSuggestions\">\n <mat-icon>refresh</mat-icon>\n <span>Atualizar sugest\u00F5es</span>\n </button>\n <button\n mat-menu-item\n type=\"button\"\n (click)=\"restoreDismissedSuggestions()\"\n [disabled]=\"!hasDismissedSuggestions()\"\n >\n <mat-icon>visibility</mat-icon>\n <span>Restaurar sugest\u00F5es ocultas</span>\n </button>\n <button\n mat-menu-item\n type=\"button\"\n class=\"assistant-quick-menu-danger\"\n (click)=\"clearHistory()\"\n [disabled]=\"!historySessions.length\"\n >\n <mat-icon>delete_outline</mat-icon>\n <span>Limpar hist\u00F3rico local</span>\n </button>\n </mat-menu>\n </div>\n\n</ng-template>\n", styles: ["@keyframes assistantPremiumEnter{0%{opacity:0;transform:translate(14px) scale(.99)}to{opacity:1;transform:translate(0) scale(1)}}:host ::ng-deep .ai-assistant-backdrop{background:color-mix(in srgb,var(--md-sys-color-scrim, var(--md-sys-color-shadow, var(--md-sys-color-on-surface))) 42%,transparent);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}::ng-deep .ai-assistant-overlay-pane{max-width:calc(100vw - 24px);max-height:calc(100vh - 24px)}.ai-assistant-panel{box-sizing:border-box;width:min(604px,100vw - 18px);min-height:min(620px,100vh - 18px);max-height:min(820px,100vh - 18px);display:flex;flex-direction:column;overflow:hidden;color:var(--md-sys-color-on-surface);border-left:1px solid color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));border-top:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));box-shadow:0 18px 48px color-mix(in srgb,var(--md-sys-color-shadow, var(--md-sys-color-on-surface)) 42%,transparent),inset 0 1px color-mix(in srgb,var(--md-sys-color-on-surface) 10%,transparent);background:radial-gradient(circle at 14% 8%,color-mix(in srgb,var(--md-sys-color-primary-container) 38%,transparent) 0%,transparent 44%),linear-gradient(165deg,color-mix(in srgb,var(--md-sys-color-surface-container-highest) 88%,var(--md-sys-color-surface)),var(--md-sys-color-surface));animation:assistantPremiumEnter .24s cubic-bezier(.22,1,.36,1)}.assistant-header{position:relative;display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:12px 16px 10px;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));background:linear-gradient(130deg,color-mix(in srgb,var(--md-sys-color-primary-container) 28%,transparent) 0%,transparent 52%),var(--md-sys-color-surface-container-low)}.assistant-header:after{content:\"\";position:absolute;left:16px;right:16px;bottom:-1px;height:1px;background:linear-gradient(90deg,color-mix(in srgb,var(--md-sys-color-primary) 55%,transparent),transparent);pointer-events:none}.assistant-header .assistant-header__left{min-width:0;display:flex;align-items:flex-start;gap:12px}.assistant-header .magic-icon{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;width:30px;height:30px;font-size:18px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 30%,transparent);box-shadow:0 4px 12px color-mix(in srgb,var(--md-sys-color-primary) 26%,transparent)}.assistant-header .assistant-title-group{min-width:0;display:flex;flex-direction:column;gap:4px}.assistant-header .assistant-title{font-size:15px;font-weight:700;letter-spacing:.01em;overflow-wrap:anywhere}.assistant-header .assistant-subtitle{display:block;font-size:11px;line-height:1.25;color:color-mix(in srgb,var(--md-sys-color-on-surface) 70%,var(--md-sys-color-on-surface-variant));overflow-wrap:anywhere}.assistant-header-chips{display:inline-flex;align-items:center;flex-wrap:wrap;gap:6px}.assistant-header .mode-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 28%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-primary-container) 64%,var(--md-sys-color-surface-container));color:color-mix(in srgb,var(--md-sys-color-on-primary-container) 85%,var(--md-sys-color-on-surface));font-size:10px;font-weight:700;letter-spacing:.04em;text-transform:uppercase}.assistant-header .mode-chip:before{content:\"\";width:6px;height:6px;border-radius:999px;background:currentColor;box-shadow:0 0 0 3px color-mix(in srgb,currentColor 16%,transparent)}.assistant-header .mode-chip.mock{border-color:color-mix(in srgb,var(--md-sys-color-error) 34%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-error-container) 72%,var(--md-sys-color-surface-container));color:color-mix(in srgb,var(--md-sys-color-on-error-container) 85%,var(--md-sys-color-error))}.assistant-header .policy-chip{padding:2px 8px;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 84%,transparent);background:var(--md-sys-color-surface-container-high);font-size:10px;letter-spacing:.02em;font-weight:600}.assistant-header .policy-chip.strict{border-color:color-mix(in srgb,var(--md-sys-color-primary) 42%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-primary-container) 56%,var(--md-sys-color-surface-container-high))}.assistant-status{display:flex;align-items:flex-start;gap:10px;padding:10px 16px;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));border-radius:0;background:linear-gradient(160deg,color-mix(in srgb,var(--md-sys-color-primary-container) 24%,transparent),transparent 48%),var(--md-sys-color-surface-container-low)}.assistant-status-dot{width:8px;height:8px;margin-top:6px;border-radius:999px;flex:0 0 auto;background:var(--md-sys-color-primary);box-shadow:0 0 0 4px color-mix(in srgb,var(--md-sys-color-primary) 16%,transparent)}.assistant-status.warning .assistant-status-dot{background:var(--md-sys-color-error);box-shadow:0 0 0 4px color-mix(in srgb,var(--md-sys-color-error) 16%,transparent)}.assistant-status.success .assistant-status-dot{background:color-mix(in srgb,var(--md-sys-color-primary) 74%,var(--md-sys-color-tertiary, var(--md-sys-color-primary)))}.assistant-status-content{min-width:0;display:flex;flex-direction:column;gap:2px}.assistant-status-label{display:flex;align-items:center;flex-wrap:wrap;gap:4px;font-size:12px;font-weight:700;line-height:1.35}.assistant-status-detail{font-size:11px;line-height:1.4;color:var(--md-sys-color-on-surface-variant);overflow-wrap:anywhere}.assistant-status-mode{padding:1px 6px;border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-primary-container) 72%,transparent);color:var(--md-sys-color-on-primary-container);font-size:10px;font-weight:700}.assistant-nav{padding:8px 16px 0}.assistant-nav .assistant-tabs{display:flex;align-items:center;gap:4px;border-radius:12px;padding:5px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));border-color:color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));background:linear-gradient(155deg,color-mix(in srgb,var(--md-sys-color-primary-container) 14%,transparent),transparent 58%),var(--md-sys-color-surface-container-low)}.assistant-nav .assistant-tab{appearance:none;min-width:0;min-height:30px;border:0;border-radius:8px;padding:0 10px;background:transparent;color:var(--md-sys-color-on-surface-variant);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;flex:1 1 0;font-size:11px;font-weight:700;letter-spacing:.01em}.assistant-nav .assistant-tab.active{background:var(--md-sys-color-surface-container-highest);color:var(--md-sys-color-on-surface);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 34%,transparent),0 6px 12px color-mix(in srgb,var(--md-sys-color-primary) 18%,transparent)}.assistant-section,.assistant-card{border-radius:14px;border-color:color-mix(in srgb,var(--md-sys-color-primary) 20%,var(--md-sys-color-outline-variant));background:linear-gradient(160deg,color-mix(in srgb,var(--md-sys-color-primary-container) 16%,transparent),transparent 50%),var(--md-sys-color-surface-container-lowest);box-shadow:0 6px 18px color-mix(in srgb,var(--md-sys-color-shadow, var(--md-sys-color-on-surface)) 12%,transparent),inset 0 1px color-mix(in srgb,var(--md-sys-color-on-surface) 7%,transparent)}.suggestions-hero{margin:2px 0 4px;padding:10px 12px;border-radius:12px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));background:linear-gradient(120deg,color-mix(in srgb,var(--md-sys-color-primary-container) 34%,transparent) 0%,transparent 52%),var(--md-sys-color-surface-container-low)}.suggestions-hero__label{font-size:10px;letter-spacing:.08em;text-transform:uppercase;font-weight:700;color:var(--md-sys-color-on-surface-variant);opacity:.88}.suggestions-hero__title{margin-top:2px;font-size:13px;font-weight:700;color:var(--md-sys-color-on-surface)}.suggestions-hero__detail{margin-top:4px;font-size:12px;line-height:1.4;color:color-mix(in srgb,var(--md-sys-color-on-surface) 78%,var(--md-sys-color-on-surface-variant))}.suggestions-content .suggestion-item{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:12px;padding:12px;border-radius:12px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));border-color:color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));background:linear-gradient(140deg,color-mix(in srgb,var(--md-sys-color-primary-container) 16%,transparent),transparent 56%),var(--md-sys-color-surface-container-lowest)}.suggestions-list{display:flex;flex-direction:column;gap:10px}.suggestion-copy{min-width:0;display:grid;gap:4px}.suggestion-main{min-width:0;display:flex;align-items:center;flex-wrap:wrap;gap:8px}.suggestion-icon{width:18px;height:18px;font-size:18px;flex:0 0 auto;color:var(--md-sys-color-primary)}.suggestion-label{min-width:0;font-size:13px;font-weight:700;line-height:1.35;overflow-wrap:anywhere}.suggestion-group{padding:2px 6px;border-radius:999px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface-variant);font-size:10px;font-weight:700;line-height:1.2}.suggestion-desc{font-size:12px;line-height:1.35;color:var(--md-sys-color-on-surface-variant);overflow-wrap:anywhere}.suggestion-actions{display:inline-flex;align-items:center;justify-content:flex-end;gap:4px}.suggestion-action-btn,.suggestion-arrow{width:32px;height:32px;display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;color:var(--md-sys-color-on-surface-variant)}.suggestions-content .suggestion-item:hover,.suggestions-content .suggestion-item:focus-visible{border-color:color-mix(in srgb,var(--md-sys-color-primary) 58%,var(--md-sys-color-outline-variant));box-shadow:0 8px 18px color-mix(in srgb,var(--md-sys-color-primary) 18%,transparent),inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 28%,transparent)}.assistant-footer{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:8px;padding:10px 16px;border-top-color:color-mix(in srgb,var(--md-sys-color-primary) 20%,var(--md-sys-color-outline-variant));background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-primary-container) 16%,transparent),transparent 56%),var(--md-sys-color-surface-container-low)}.assistant-footer .task-footer{grid-column:1/-1}.composer-leading{width:30px;height:30px;display:inline-flex;align-items:center;justify-content:center;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 30%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-primary-container) 70%,var(--md-sys-color-surface-container-low));color:var(--md-sys-color-primary);box-shadow:0 4px 10px color-mix(in srgb,var(--md-sys-color-primary) 16%,transparent)}.composer-leading mat-icon{width:16px;height:16px;font-size:16px}.assistant-footer input{box-sizing:border-box;width:100%;min-width:0;height:34px;border:1px solid;border-radius:8px;padding:0 12px;color:var(--md-sys-color-on-surface);border-color:color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));background:var(--md-sys-color-surface);box-shadow:inset 0 1px 2px color-mix(in srgb,var(--md-sys-color-shadow, var(--md-sys-color-on-surface)) 12%,transparent)}.send-actions{min-width:36px;display:inline-flex;align-items:center;justify-content:center}.assistant-footer .send-btn{--mdc-icon-button-icon-size: 20px;--mdc-icon-button-state-layer-size: 36px;--mat-icon-button-state-layer-size: 36px;width:36px;height:36px;padding:8px;line-height:1;display:inline-flex;align-items:center;justify-content:center;border-color:color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));background:var(--md-sys-color-surface)}.assistant-footer .send-btn mat-icon{width:20px;height:20px;margin:0;font-size:20px;line-height:20px;display:inline-flex;align-items:center;justify-content:center}.assistant-footer .send-btn.ready{background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary-container) 84%,var(--md-sys-color-primary)),var(--md-sys-color-primary));color:var(--md-sys-color-on-primary);box-shadow:0 8px 18px color-mix(in srgb,var(--md-sys-color-primary) 30%,transparent)}.task-primary-btn{border-radius:12px;box-shadow:0 8px 18px color-mix(in srgb,var(--md-sys-color-primary) 24%,transparent)}@media(max-width:959px){.assistant-header{padding:12px 12px 10px}.assistant-section,.assistant-card{margin:4px 12px 10px}.assistant-header:after{left:12px;right:12px}.assistant-header .assistant-title{font-size:14px}.assistant-header .assistant-subtitle{font-size:10px}.assistant-footer{grid-template-columns:minmax(0,1fr) auto}.composer-leading{display:none}}.assistant-thought{margin-top:0;gap:10px;border-color:color-mix(in srgb,var(--md-sys-color-primary) 26%,var(--md-sys-color-outline-variant));background:linear-gradient(145deg,color-mix(in srgb,var(--md-sys-color-primary-container) 28%,transparent),transparent 58%),var(--md-sys-color-surface-container-low)}.assistant-thought-meta{display:inline-flex;align-items:center;gap:6px;font-size:11px;color:var(--md-sys-color-on-surface-variant)}.assistant-thought-meta mat-icon{width:15px;height:15px;font-size:15px;color:var(--md-sys-color-primary)}.assistant-thought-summary{font-size:13px;line-height:1.45;color:var(--md-sys-color-on-surface)}.assistant-thought-plan{border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 32%,var(--md-sys-color-outline-variant));border-radius:12px;padding:10px;background:var(--md-sys-color-surface-container-lowest);display:flex;flex-direction:column;gap:8px}.assistant-thought-plan-title{font-size:13px;font-weight:700;color:var(--md-sys-color-on-surface)}.assistant-thought-plan-actions{display:grid;grid-template-columns:repeat(auto-fit,minmax(0,1fr));gap:8px}.assistant-thought-plan-actions .mdc-button{min-width:0}.assistant-thought-plan-hint{font-size:11px;color:var(--md-sys-color-on-surface-variant);line-height:1.35}.assistant-thought-checklist{display:flex;flex-direction:column;gap:5px}.assistant-thought-checklist-item{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--md-sys-color-on-surface-variant)}.assistant-thought-checklist-item mat-icon{width:14px;height:14px;font-size:14px}.assistant-flow{grid-template-columns:1fr;gap:6px}.flow-step{display:flex;align-items:flex-start;gap:8px;text-align:left;padding:7px 8px;border-radius:10px}.flow-step-index{width:18px;height:18px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-highest);color:var(--md-sys-color-on-surface);flex:0 0 auto}.flow-step-content{min-width:0;display:flex;flex-direction:column;gap:1px}.flow-step-label{font-size:11px;font-weight:700;color:var(--md-sys-color-on-surface)}.flow-step-detail{font-size:11px;color:var(--md-sys-color-on-surface-variant);line-height:1.3}.flow-step.active .flow-step-index{border-color:color-mix(in srgb,var(--md-sys-color-primary) 60%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-primary-container) 85%,var(--md-sys-color-surface-container-highest));color:var(--md-sys-color-on-primary-container)}.flow-step.done .flow-step-index{border-color:transparent;background:color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-surface-container-highest))}.task-timeline{margin-top:4px;display:grid;gap:6px}.task-timeline-item{display:flex;align-items:flex-start;gap:8px;border:1px solid var(--md-sys-color-outline-variant);border-radius:10px;padding:6px 8px;background:var(--md-sys-color-surface-container-low);opacity:.76}.task-timeline-item.active{opacity:1;border-color:color-mix(in srgb,var(--md-sys-color-primary) 40%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-primary-container) 34%,var(--md-sys-color-surface-container-low))}.task-timeline-item.done{opacity:.9;border-color:color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant))}.task-timeline-dot{width:18px;height:18px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-highest);color:var(--md-sys-color-on-surface);flex:0 0 auto}.task-timeline-copy{min-width:0;display:flex;flex-direction:column;gap:1px}.task-timeline-title{font-size:11px;font-weight:700;color:var(--md-sys-color-on-surface)}.task-timeline-detail{font-size:11px;line-height:1.3;color:var(--md-sys-color-on-surface-variant)}.clarification-decision-head{display:inline-flex;align-items:center;width:100%;gap:6px;padding:8px 12px 0;box-sizing:border-box}.clarification-decision-index{width:18px;height:18px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 35%,var(--md-sys-color-outline-variant));color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 68%,transparent)}.clarification-decision-type{font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--md-sys-color-on-surface-variant);opacity:.92}.clarification-decision-state{font-size:10px;font-weight:700;color:var(--md-sys-color-primary)}.clarification-option{border-color:color-mix(in srgb,var(--md-sys-color-primary) 20%,var(--md-sys-color-outline-variant));background:linear-gradient(145deg,color-mix(in srgb,var(--md-sys-color-primary-container) 16%,transparent),transparent 55%),var(--md-sys-color-surface-container-low)}.clarification-option.selected{border-color:color-mix(in srgb,var(--md-sys-color-primary) 56%,var(--md-sys-color-outline-variant));background:linear-gradient(145deg,color-mix(in srgb,var(--md-sys-color-primary-container) 44%,transparent),transparent 62%),var(--md-sys-color-surface-container);box-shadow:0 8px 16px color-mix(in srgb,var(--md-sys-color-primary) 18%,transparent)}.clarification-options-block{overflow:visible;padding-right:4px}@media(max-width:959px){.assistant-thought-plan-actions{grid-template-columns:1fr}}.ai-assistant-panel{width:min(604px,100vw - 18px)}.assistant-section,.assistant-card{margin:0;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 20%,var(--md-sys-color-outline-variant))}.assistant-section{min-height:0;padding:14px 16px;overflow:visible}.assistant-card{min-height:0;padding:14px 16px 16px;overflow:visible}.suggestions-area,.assistant-history,.loading-suggestions{overflow-y:auto;overflow-x:hidden}.section-header{min-width:0;display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:10px}.section-title{min-width:0;font-size:14px;font-weight:700;line-height:1.35;overflow-wrap:anywhere}.suggestions-actions{flex:0 0 auto;display:inline-flex;align-items:center}.review-area,.error-area,.success-area,.clarification-area{padding:0;overflow-y:auto;overflow-x:hidden;scrollbar-gutter:auto}.review-trust{margin:2px 0 4px}.trust-chip{max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.warnings-area,.review-summary,.review-diff,.apply-details,.clarification-options-block,.clarification-manual-toggle{width:100%;max-width:100%;min-width:0}.review-diff{padding:12px 14px}.review-diff-full{padding:10px;overflow-x:auto}.review-diff-block{min-width:0}.review-diff-block pre{overflow-wrap:anywhere;word-break:break-word}.clarification-options-block{padding:4px 2px 10px}.clarification-option{line-height:normal}:host ::ng-deep .clarification-option .mdc-button__label{line-height:1.35!important}.clarification-plain-label{padding:6px 12px 12px;font-size:14px;line-height:1.35}.clarification-manual-toggle{margin-top:10px;padding:10px 2px 0;flex-wrap:wrap;row-gap:6px}.suggestions-content .suggestion-actions{gap:6px}.suggestions-content .suggestion-arrow,.suggestions-content .suggestion-action-btn mat-icon,.suggestions-content .suggestion-arrow mat-icon{display:inline-flex;align-items:center;justify-content:center}:host ::ng-deep .assistant-quick-menu-panel{min-width:244px;max-width:min(90vw,320px);border-radius:14px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 26%,var(--md-sys-color-outline-variant));background:var(--md-sys-color-surface-container-high);box-shadow:0 12px 28px color-mix(in srgb,var(--md-sys-color-shadow, var(--md-sys-color-on-surface)) 32%,transparent),inset 0 1px color-mix(in srgb,var(--md-sys-color-on-surface) 6%,transparent);overflow:hidden;padding:6px}:host ::ng-deep .assistant-quick-menu-panel .mat-mdc-menu-item{min-height:36px;border-radius:10px;color:var(--md-sys-color-on-surface);font-size:12px;font-weight:500;margin:1px 0}:host ::ng-deep .assistant-quick-menu-panel .mat-mdc-menu-item .mat-icon{color:color-mix(in srgb,var(--md-sys-color-on-surface) 82%,var(--md-sys-color-on-surface-variant))}:host ::ng-deep .assistant-quick-menu-panel .mat-mdc-menu-item:hover:not([disabled]){background:color-mix(in srgb,var(--md-sys-color-primary-container) 45%,transparent)}:host ::ng-deep .assistant-quick-menu-panel .mat-mdc-menu-item:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:-2px}:host ::ng-deep .assistant-quick-menu-panel .assistant-quick-menu-danger{color:var(--md-sys-color-error)}:host ::ng-deep .assistant-quick-menu-panel .assistant-quick-menu-danger .mat-icon{color:var(--md-sys-color-error)}@media(max-width:959px){::ng-deep .ai-assistant-overlay-pane{top:12px!important;left:12px!important;width:calc(100vw - 24px)!important;height:calc(100vh - 24px)!important;max-width:calc(100vw - 24px);max-height:calc(100vh - 24px);transform:none!important}.ai-assistant-panel{width:calc(100vw - 48px);min-height:min(620px,100vh - 48px);max-height:calc(100vh - 48px)}.assistant-section,.assistant-card{margin:0}.assistant-card,.assistant-section{padding:12px}}.ai-trigger-btn{--mdc-icon-button-state-layer-size: 36px;width:36px;height:36px;border-radius:8px;background:color-mix(in srgb,var(--md-sys-color-primary) 9%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 22%,transparent);color:var(--md-sys-color-primary);opacity:1}.ai-trigger-btn:hover:not(:disabled){background:color-mix(in srgb,var(--md-sys-color-primary) 16%,transparent);border-color:color-mix(in srgb,var(--md-sys-color-primary) 36%,transparent);color:var(--md-sys-color-on-primary-container)}.ai-trigger-btn:focus-visible,.assistant-close-btn:focus-visible,.assistant-tab:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.assistant-close-btn{width:28px;height:28px;color:var(--md-sys-color-on-surface-variant)}.assistant-close-btn:hover:not(:disabled){background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface)}.assistant-body{padding:12px 16px;overflow:hidden;min-height:0;flex:1;display:flex;flex-direction:column;gap:12px}.assistant-body>*{min-height:0}@media(max-width:959px){.assistant-nav{padding:8px 12px 0}.assistant-body,.assistant-footer{padding:10px 12px}.suggestions-content .suggestion-item{grid-template-columns:1fr;align-items:start}.suggestion-actions{justify-content:flex-start}}\n"] }]
|
|
6688
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Trigger Button -->\n<button \n mat-icon-button \n cdkOverlayOrigin \n #trigger=\"cdkOverlayOrigin\"\n #triggerBtn\n (click)=\"open()\"\n [disabled]=\"isOpen\"\n class=\"ai-trigger-btn\"\n matTooltip=\"Assistente de Configura\u00E7\u00E3o\"\n aria-label=\"Abrir Assistente IA\">\n <mat-icon>auto_awesome</mat-icon>\n</button>\n\n<!-- Overlay Template -->\n<ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"trigger\"\n [cdkConnectedOverlayOpen]=\"isOpen\"\n [cdkConnectedOverlayHasBackdrop]=\"hasBackdrop\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayPush]=\"true\"\n [cdkConnectedOverlayViewportMargin]=\"12\"\n cdkConnectedOverlayPanelClass=\"ai-assistant-overlay-pane\"\n cdkConnectedOverlayBackdropClass=\"ai-assistant-backdrop\"\n (backdropClick)=\"close()\"\n (overlayOutsideClick)=\"close()\"\n (detach)=\"close()\">\n\n <div\n class=\"ai-assistant-panel\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Assistente de Configura\u00E7\u00E3o\"\n [attr.aria-busy]=\"isBusyState() ? 'true' : null\"\n [cdkTrapFocus]=\"hasBackdrop\"\n [cdkTrapFocusAutoCapture]=\"hasBackdrop\"\n (keydown)=\"onKeydown($event)\"\n >\n \n <!-- HEADER -->\n <div class=\"assistant-header\">\n <div class=\"assistant-header__left\">\n <mat-icon class=\"magic-icon\">auto_awesome</mat-icon>\n <div class=\"assistant-title-group\">\n <div class=\"assistant-title\">Assistente de Configura\u00E7\u00E3o</div>\n <div class=\"assistant-subtitle\">Copiloto contextual para ajustes guiados</div>\n <div class=\"assistant-header-chips\">\n <span\n class=\"mode-chip\"\n [class.mock]=\"mockMode\"\n [matTooltip]=\"mockMode ? 'Sem chave de API: respostas de demonstra\u00E7\u00E3o' : 'Conectado ao assistente configurado'\"\n >\n {{ mockMode ? 'Mock' : 'Conectado' }}\n </span>\n <span\n class=\"policy-chip\"\n [class.strict]=\"isStrictRiskPolicy()\"\n [matTooltip]=\"getRiskPolicyTooltip()\"\n >\n {{ getRiskPolicyLabel() }}\n </span>\n </div>\n </div>\n </div>\n <div class=\"assistant-header__right\">\n <button\n mat-icon-button\n type=\"button\"\n class=\"assistant-close-btn\"\n (click)=\"close()\"\n aria-label=\"Fechar assistente\"\n matTooltip=\"Fechar assistente\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n <div\n class=\"assistant-status\"\n [class.processing]=\"isBusyState()\"\n [class.pending]=\"state === 'clarification'\"\n [class.warning]=\"state === 'error'\"\n [class.success]=\"state === 'review' || state === 'success'\"\n [class.compact]=\"!shouldShowSystemStatusDetail()\"\n role=\"status\"\n [attr.aria-live]=\"getSystemStatusAriaLive()\"\n aria-atomic=\"true\"\n >\n <span class=\"assistant-status-dot\" aria-hidden=\"true\"></span>\n <div class=\"assistant-status-content\">\n <div class=\"assistant-status-label\">\n <span class=\"assistant-status-label-prefix\">Status:</span>\n <span>{{ getSystemStatusLabel() }}</span>\n <span *ngIf=\"shouldShowSnapshotFallbackBadge()\" class=\"assistant-status-mode\">Snapshot</span>\n </div>\n <div *ngIf=\"shouldShowSystemStatusDetail()\" class=\"assistant-status-detail\">{{ getSystemStatusDetail() }}</div>\n </div>\n </div>\n <div class=\"assistant-flow\" *ngIf=\"shouldShowTaskFlow()\" role=\"list\" aria-label=\"Fluxo da proposta\">\n <div\n class=\"flow-step\"\n role=\"listitem\"\n *ngFor=\"let step of flowSteps\"\n [class.active]=\"getFlowStepState(step.step) === 'active'\"\n [class.done]=\"getFlowStepState(step.step) === 'done'\"\n >\n <span class=\"flow-step-index\">{{ step.step }}</span>\n <span class=\"flow-step-content\">\n <span class=\"flow-step-label\">{{ step.label }}</span>\n <span class=\"flow-step-detail\">{{ getFlowStepDetail(step.step) }}</span>\n </span>\n </div>\n </div>\n <div class=\"assistant-nav\">\n <div\n class=\"assistant-tabs\"\n role=\"tablist\"\n aria-label=\"Se\u00E7\u00F5es do assistente\"\n (keydown)=\"onTabsKeydown($event)\"\n >\n <button\n class=\"assistant-tab\"\n type=\"button\"\n *ngIf=\"isTaskMode()\"\n id=\"assistant-tab-task\"\n role=\"tab\"\n aria-label=\"Proposta atual\"\n [attr.aria-selected]=\"isActiveTab('task')\"\n aria-controls=\"assistant-panel-task\"\n [attr.tabindex]=\"isActiveTab('task') ? 0 : -1\"\n [class.active]=\"isActiveTab('task')\"\n (click)=\"setActiveTab('task')\"\n >\n Proposta\n <span *ngIf=\"hasPendingClarification() && !isActiveTab('task')\" class=\"assistant-tab-badge\">1</span>\n </button>\n <button\n class=\"assistant-tab\"\n type=\"button\"\n id=\"assistant-tab-chat\"\n role=\"tab\"\n aria-label=\"Hist\u00F3rico\"\n [attr.aria-selected]=\"isActiveTab('chat')\"\n aria-controls=\"assistant-panel-chat\"\n [attr.tabindex]=\"isActiveTab('chat') ? 0 : -1\"\n [class.active]=\"isActiveTab('chat')\"\n (click)=\"setActiveTab('chat')\"\n >\n Hist\u00F3rico\n </button>\n <button\n class=\"assistant-tab\"\n type=\"button\"\n id=\"assistant-tab-suggestions\"\n role=\"tab\"\n aria-label=\"Sugest\u00F5es de melhoria\"\n [attr.aria-selected]=\"isActiveTab('suggestions')\"\n aria-controls=\"assistant-panel-suggestions\"\n [attr.tabindex]=\"isActiveTab('suggestions') ? 0 : -1\"\n [class.active]=\"isActiveTab('suggestions')\"\n (click)=\"setActiveTab('suggestions')\"\n >\n Sugest\u00F5es\n </button>\n </div>\n </div>\n\n <!-- BODY: Dynamic Content based on State -->\n <div class=\"assistant-body\">\n <div class=\"assistant-thought assistant-section\" *ngIf=\"shouldShowThoughtCard()\">\n <div class=\"assistant-thought-meta\">\n <mat-icon>psychology</mat-icon>\n <span>{{ getThoughtTimingLabel() }}</span>\n </div>\n <div class=\"assistant-thought-summary\">{{ getThoughtSummary() }}</div>\n <div class=\"assistant-thought-plan\">\n <div class=\"assistant-thought-plan-title\">{{ getThoughtPlanTitle() }}</div>\n <div class=\"assistant-thought-plan-actions\">\n <button\n mat-stroked-button\n type=\"button\"\n class=\"thought-action-details\"\n (click)=\"openThoughtDetails()\"\n [attr.aria-label]=\"getThoughtDetailsLabel()\"\n [matTooltip]=\"getThoughtDetailsTooltip()\"\n >\n {{ getThoughtDetailsLabel() }}\n </button>\n <button\n *ngIf=\"shouldShowThoughtPreviewAction()\"\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n class=\"thought-action-preview\"\n (click)=\"openThoughtPreview()\"\n [matTooltip]=\"getThoughtPreviewTooltip()\"\n >\n Pr\u00E9via\n </button>\n </div>\n <div class=\"assistant-thought-plan-hint\">{{ getThoughtActionHint() }}</div>\n <ng-container *ngIf=\"getThoughtChecklist() as thoughtChecklist\">\n <div class=\"assistant-thought-checklist\" *ngIf=\"thoughtChecklist.length\">\n <div *ngFor=\"let item of thoughtChecklist\" class=\"assistant-thought-checklist-item\">\n <mat-icon>radio_button_unchecked</mat-icon>\n <span>{{ item }}</span>\n </div>\n </div>\n <div class=\"assistant-thought-shimmer\" *ngIf=\"isBusyState() && !thoughtChecklist.length\">\n <div class=\"shimmer-line shimmer-line-1\"></div>\n <div class=\"shimmer-line shimmer-line-2\"></div>\n <div class=\"shimmer-line shimmer-line-3\"></div>\n </div>\n </ng-container>\n </div>\n </div>\n <div *ngIf=\"processingInfoVisible\" class=\"processing-banner\">\n <mat-spinner diameter=\"16\"></mat-spinner>\n <span>{{ aiExplanation || 'Analisando solicita\u00E7\u00E3o e preparando proposta...' }}</span>\n <button mat-button type=\"button\" class=\"processing-retry\" (click)=\"retryProcessing()\">Tentar novamente</button>\n </div>\n <div\n class=\"assistant-history assistant-section\"\n *ngIf=\"historyContext && isActiveTab('chat')\"\n id=\"assistant-panel-chat\"\n role=\"tabpanel\"\n aria-labelledby=\"assistant-tab-chat\"\n >\n <div class=\"section-header\">\n <div class=\"section-heading\">\n <div class=\"section-title\">Hist\u00F3rico</div>\n <div class=\"section-subtitle\">Sess\u00F5es recentes, pedidos reaproveit\u00E1veis e desfazer r\u00E1pido.</div>\n </div>\n <div class=\"history-actions\" role=\"group\" aria-label=\"A\u00E7\u00F5es do hist\u00F3rico\">\n <button\n mat-stroked-button\n type=\"button\"\n class=\"history-action-btn\"\n (click)=\"historyExpanded = !historyExpanded\"\n [matTooltip]=\"historyExpanded ? 'Recolher hist\u00F3rico' : 'Expandir hist\u00F3rico'\"\n [attr.aria-label]=\"historyExpanded ? 'Recolher hist\u00F3rico' : 'Expandir hist\u00F3rico'\"\n [disabled]=\"!historyWarnings.length && !historySessions.length && !activeHistoryMessages.length\"\n >\n <mat-icon>{{ historyExpanded ? 'expand_less' : 'expand_more' }}</mat-icon>\n <span>{{ historyExpanded ? 'Recolher' : 'Expandir' }}</span>\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n class=\"history-action-btn\"\n (click)=\"startNewSession()\"\n matTooltip=\"Nova conversa\"\n aria-label=\"Nova conversa\"\n [disabled]=\"isBusyState()\"\n >\n <mat-icon>add_comment</mat-icon>\n <span>Nova conversa</span>\n </button>\n <button\n mat-stroked-button\n type=\"button\"\n (click)=\"clearHistory()\"\n matTooltip=\"Limpar hist\u00F3rico local\"\n aria-label=\"Limpar hist\u00F3rico local\"\n class=\"history-action-btn history-action-btn--danger\"\n [disabled]=\"!historySessions.length\"\n >\n <mat-icon>delete_outline</mat-icon>\n <span>Limpar</span>\n </button>\n </div>\n </div>\n <div *ngIf=\"historyUndoDeleteSession\" class=\"history-undo\">\n <span>Sess\u00E3o removida.</span>\n <button mat-button type=\"button\" (click)=\"undoRemoveHistorySession()\">\n Desfazer\n </button>\n </div>\n\n <div *ngIf=\"historyExpanded && historyWarnings.length\" class=\"history-warnings\">\n <mat-icon>info</mat-icon>\n <div class=\"history-warnings-list\">\n <div *ngFor=\"let warning of historyWarnings\">{{ warning }}</div>\n <div class=\"history-warnings-hint\">\n Configure headers via API_CONFIG_STORAGE_OPTIONS no host.\n </div>\n </div>\n </div>\n\n <div *ngIf=\"historyExpanded && historySessions.length\" class=\"history-sessions\">\n <div\n class=\"history-session\"\n *ngFor=\"let session of historySessions\"\n role=\"button\"\n tabindex=\"0\"\n (click)=\"selectHistorySession(session.id)\"\n (keydown)=\"onHistorySessionCardKeydown($event, session.id)\"\n [class.active]=\"session.id === activeHistorySession?.id\"\n [matTooltip]=\"getHistorySessionTooltip(session)\"\n [matTooltipDisabled]=\"!session.componentType && !session.componentId\"\n >\n <div class=\"history-session-main\">\n <span class=\"history-session-title\">{{ session.title }}</span>\n <div class=\"history-session-main-right\">\n <span class=\"history-session-time\">{{ session.updatedAt | date:'short' }}</span>\n <div class=\"history-session-tools\">\n <button\n mat-icon-button\n type=\"button\"\n class=\"history-session-tool\"\n (click)=\"reuseHistorySessionPrompt(session.id, $event)\"\n matTooltip=\"Reusar \u00FAltimo pedido\"\n aria-label=\"Reusar \u00FAltimo pedido\"\n >\n <mat-icon>edit_note</mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n class=\"history-session-tool history-session-tool--danger\"\n (click)=\"removeHistorySession(session.id, $event)\"\n matTooltip=\"Excluir sess\u00E3o\"\n aria-label=\"Excluir sess\u00E3o\"\n >\n <mat-icon>delete_outline</mat-icon>\n </button>\n </div>\n </div>\n </div>\n <div class=\"history-session-meta\">\n <span *ngIf=\"session.componentType\" class=\"history-chip\">{{ session.componentType }}</span>\n <span *ngIf=\"session.componentId\" class=\"history-chip\">{{ session.componentId }}</span>\n </div>\n </div>\n </div>\n <div *ngIf=\"historyExpanded && !historySessions.length\" class=\"history-empty\">\n Nenhuma sess\u00E3o salva ainda.\n </div>\n\n <div *ngIf=\"historyExpanded && activeHistoryMessages.length\" class=\"history-messages\">\n <div\n *ngIf=\"activeHistoryTotalMessages > activeHistoryMessages.length\"\n class=\"history-messages-hint\"\n >\n Mostrando \u00FAltimas {{ activeHistoryMessages.length }} de {{ activeHistoryTotalMessages }} mensagens.\n </div>\n <div\n *ngFor=\"let msg of activeHistoryMessages\"\n class=\"history-message\"\n [class.user]=\"msg.role === 'user'\"\n [class.assistant]=\"msg.role === 'assistant'\"\n >\n <div class=\"history-message-header\">\n <span class=\"history-message-role\">{{ msg.role === 'user' ? 'Voc\u00EA' : 'Assistente' }}</span>\n <span class=\"history-message-time\">{{ msg.createdAt | date:'shortTime' }}</span>\n <span\n *ngIf=\"msg.context?.usedRag\"\n class=\"history-rag\"\n matTooltip=\"Resposta baseada em contexto recuperado (RAG)\"\n >RAG</span>\n </div>\n <div class=\"history-message-text\">{{ msg.text }}</div>\n </div>\n </div>\n <div *ngIf=\"historyExpanded && historySessions.length && !activeHistoryMessages.length\" class=\"history-empty history-empty--panel\">\n Selecione uma sess\u00E3o para visualizar as mensagens.\n </div>\n <div class=\"history-helper\" *ngIf=\"historyExpanded\">\n O hist\u00F3rico \u00E9 local ao usu\u00E1rio e ao componente atual.\n </div>\n </div>\n\n <div\n class=\"loading-suggestions assistant-section\"\n *ngIf=\"loadingSuggestions && isActiveTab('suggestions')\"\n id=\"assistant-panel-suggestions\"\n role=\"tabpanel\"\n aria-labelledby=\"assistant-tab-suggestions\"\n >\n <mat-spinner diameter=\"20\"></mat-spinner>\n <span>Carregando sugest\u00F5es de melhoria...</span>\n </div>\n \n <!-- STATE: LISTENING (Suggestions) -->\n <div\n *ngIf=\"state === 'listening' && isActiveTab('suggestions')\"\n class=\"suggestions-area assistant-section\"\n id=\"assistant-panel-suggestions\"\n role=\"tabpanel\"\n aria-labelledby=\"assistant-tab-suggestions\"\n >\n <div class=\"section-header\">\n <div class=\"section-title\">Sugest\u00F5es de melhoria</div>\n <div class=\"suggestions-actions\">\n <button mat-icon-button type=\"button\" (click)=\"refreshSuggestions()\" [disabled]=\"loadingSuggestions\" matTooltip=\"Atualizar sugest\u00F5es\">\n <mat-icon>refresh</mat-icon>\n </button>\n </div>\n </div>\n <div class=\"suggestions-hero\" *ngIf=\"!loadingSuggestions\">\n <div class=\"suggestions-hero__label\">Contexto ativo</div>\n <div class=\"suggestions-hero__title\">{{ adapter.componentName || 'Componente atual' }}</div>\n <div class=\"suggestions-hero__detail\">{{ getSystemStatusDetail() }}</div>\n </div>\n <div *ngIf=\"suggestionsWarnings.length\" class=\"warnings-area\">\n <mat-icon class=\"warnings-icon\">warning_amber</mat-icon>\n <div class=\"warnings-content\">\n <div class=\"warnings-title\">Avisos</div>\n <div class=\"warnings-list\">\n <div *ngFor=\"let warning of suggestionsWarnings\">{{ warning }}</div>\n </div>\n </div>\n </div>\n <div class=\"suggestions-content\" *ngIf=\"!loadingSuggestions && (richSuggestions.length || hasDismissedSuggestions())\">\n <div class=\"suggestions-filter\" *ngIf=\"hasDismissedSuggestions()\">\n <span>{{ getDismissedSuggestionCount() }} oculta(s)</span>\n <button mat-button type=\"button\" (click)=\"restoreDismissedSuggestions()\">\n Restaurar\n </button>\n </div>\n <div class=\"suggestions-list\" *ngIf=\"getVisibleSuggestions().length; else allSuggestionsHidden\">\n <div\n class=\"suggestion-item\"\n *ngFor=\"let sug of getVisibleSuggestions()\"\n role=\"button\"\n tabindex=\"0\"\n [attr.aria-label]=\"'Selecionar sugest\u00E3o: ' + sug.label\"\n (click)=\"selectSuggestion(sug)\"\n (keydown)=\"onSuggestionCardKeydown($event, sug)\"\n >\n <div class=\"suggestion-copy\">\n <div class=\"suggestion-main\">\n <mat-icon *ngIf=\"sug.icon\" class=\"suggestion-icon\">{{ sug.icon }}</mat-icon>\n <span class=\"suggestion-label\">{{ sug.label }}</span>\n <span *ngIf=\"sug.group\" class=\"suggestion-group\">{{ sug.group }}</span>\n </div>\n <div *ngIf=\"sug.description\" class=\"suggestion-desc\">{{ sug.description }}</div>\n </div>\n <div class=\"suggestion-actions\">\n <span class=\"suggestion-arrow\" aria-hidden=\"true\">\n <mat-icon>chevron_right</mat-icon>\n </span>\n <button\n mat-icon-button\n type=\"button\"\n class=\"suggestion-action-btn\"\n (click)=\"prepareSuggestionPrompt(sug, $event)\"\n matTooltip=\"Refinar pedido\"\n aria-label=\"Refinar pedido\"\n >\n <mat-icon>edit</mat-icon>\n </button>\n <button\n mat-icon-button\n type=\"button\"\n class=\"suggestion-action-btn suggestion-action-btn--danger\"\n (click)=\"dismissSuggestion(sug, $event)\"\n matTooltip=\"Ocultar sugest\u00E3o\"\n aria-label=\"Ocultar sugest\u00E3o\"\n >\n <mat-icon>visibility_off</mat-icon>\n </button>\n </div>\n </div>\n </div>\n <ng-template #allSuggestionsHidden>\n <div class=\"suggestions-empty suggestions-empty--inline\">\n Todas as sugest\u00F5es foram ocultadas.\n </div>\n </ng-template>\n </div>\n <div class=\"suggestions-empty\" *ngIf=\"!loadingSuggestions && !richSuggestions.length\">\n Nenhuma sugest\u00E3o dispon\u00EDvel no momento.\n </div>\n <div class=\"suggestions-helper\" *ngIf=\"!loadingSuggestions && !richSuggestions.length\">\n Selecione uma sugest\u00E3o acima ou descreva uma altera\u00E7\u00E3o no campo inferior.\n </div>\n </div>\n\n <!-- STATE: CLARIFICATION (Two-Step Flow) -->\n <div\n *ngIf=\"state === 'clarification' && isActiveTab('task')\"\n class=\"clarification-area assistant-card\"\n id=\"assistant-panel-task\"\n role=\"tabpanel\"\n aria-labelledby=\"assistant-tab-task\"\n >\n <div class=\"task-header\" *ngIf=\"!shouldShowThoughtCard()\">\n <div class=\"task-title\">{{ getTaskTitle() }}</div>\n <div class=\"task-subtitle\">{{ getTaskSubtitle() }}</div>\n <div *ngIf=\"clarificationOptions.length > 1 && getTaskSelectionSummary() as selectionSummary\" class=\"task-meta\">\n <span class=\"task-meta-label\">Selecionado:</span>\n <span class=\"task-meta-value\">{{ selectionSummary }}</span>\n </div>\n <div *ngIf=\"shouldShowTaskSteps()\" class=\"task-steps\">\n <span class=\"task-step active\">1 Dados</span>\n <span class=\"task-step\">2 Layout</span>\n <span class=\"task-step\">3 Revis\u00E3o</span>\n </div>\n </div>\n <div *ngIf=\"clarificationResponseType === 'context'\" class=\"context-only\">\n <mat-spinner diameter=\"24\"></mat-spinner>\n <div class=\"context-only-hint\">Buscando contexto adicional...</div>\n </div>\n <ng-template #clarificationOptionContent let-opt let-index=\"index\" let-compact=\"compact\">\n <div class=\"clarification-decision-head\" *ngIf=\"!compact\">\n <span class=\"clarification-decision-index\">{{ index + 1 }}</span>\n <span class=\"clarification-decision-type\">{{ getClarificationOptionKindLabel(opt) }}</span>\n <span class=\"spacer\"></span>\n <span class=\"clarification-decision-state\" *ngIf=\"isClarificationSelected(opt)\">Selecionado</span>\n </div>\n <ng-container [ngSwitch]=\"getClarificationOptionLayout(opt)\">\n <div *ngSwitchCase=\"'endpoint'\" class=\"clarification-card\">\n <div class=\"clarification-card-header\">\n <mat-icon class=\"endpoint-icon\">{{ getEndpointIcon(opt) }}</mat-icon>\n <ng-container *ngIf=\"getEndpointMethod(opt) as method\">\n <span class=\"endpoint-method\" [attr.data-method]=\"method\">{{ method }}</span>\n </ng-container>\n <span class=\"endpoint-label\">{{ opt.label }}</span>\n <span class=\"spacer\"></span>\n <mat-icon class=\"select-indicator\">\n {{ isClarificationSelected(opt) ? 'check_circle' : 'radio_button_unchecked' }}\n </mat-icon>\n </div>\n <div class=\"clarification-card-body\">\n <ng-container *ngIf=\"getEndpointPath(opt) as path\">\n <div class=\"endpoint-path\">{{ path }}</div>\n </ng-container>\n <div\n *ngIf=\"opt.contextHints?.description\"\n class=\"endpoint-description\"\n [matTooltip]=\"getDescriptionTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowDescriptionTooltip(opt)\"\n >\n {{ opt.contextHints?.description }}\n </div>\n </div>\n </div>\n <div *ngSwitchCase=\"'color'\" class=\"clarification-color\">\n <span\n class=\"color-swatch\"\n [style.background]=\"getSafeHexColor(opt) || 'var(--md-sys-color-surface-container-highest)'\"\n ></span>\n <div class=\"color-meta\">\n <span class=\"color-label\">{{ opt.label }}</span>\n <span *ngIf=\"opt.contextHints?.hexColor\" class=\"color-value\">{{ opt.contextHints?.hexColor }}</span>\n </div>\n </div>\n <div *ngSwitchCase=\"'description'\" class=\"clarification-description\">\n <span class=\"clarification-label\">{{ opt.label }}</span>\n <span\n *ngIf=\"opt.contextHints?.description\"\n class=\"clarification-subtitle\"\n [matTooltip]=\"getDescriptionTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowDescriptionTooltip(opt)\"\n >\n {{ opt.contextHints?.description }}\n </span>\n </div>\n <span *ngSwitchDefault class=\"clarification-plain-label\">{{ opt.label }}</span>\n </ng-container>\n </ng-template>\n <div *ngIf=\"warnings.length\" class=\"warnings-area\">\n <mat-icon class=\"warnings-icon\">warning_amber</mat-icon>\n <div class=\"warnings-content\">\n <div class=\"warnings-title\">Avisos</div>\n <div class=\"warnings-list\">\n <div *ngFor=\"let warning of warnings\">{{ warning }}</div>\n </div>\n </div>\n </div>\n <div\n *ngIf=\"clarificationQuestions.length\"\n class=\"clarification-questions\"\n [class.attention-highlight]=\"highlightClarificationDetails && !clarificationOptions.length\"\n >\n <div *ngFor=\"let question of clarificationQuestions; let i = index\" class=\"clarification-question\">\n <div class=\"clarification-question-label\">{{ question }}</div>\n <input\n type=\"text\"\n [(ngModel)]=\"clarificationAnswers[i]\"\n [placeholder]=\"'Resposta ' + (i + 1)\"\n autocomplete=\"off\">\n </div>\n </div>\n <div\n *ngIf=\"clarificationOptions.length\"\n class=\"clarification-options-block\"\n [class.attention-highlight]=\"highlightClarificationDetails\"\n >\n <div class=\"clarification-options-title\">\n {{ clarificationOptions.length === 1 ? 'Decis\u00E3o sugerida' : 'Decis\u00F5es sugeridas' }}\n </div>\n <div *ngIf=\"clarificationOptions.length === 1\" class=\"clarification-options-hint\">\n Etapa 2 de 4: confirme a melhor op\u00E7\u00E3o para continuar.\n </div>\n <div *ngIf=\"clarificationOptions.length > 1\" class=\"clarification-options-hint\">\n Etapa 2 de 4: selecione a alternativa mais aderente para gerar a proposta.\n </div>\n <div\n *ngIf=\"clarificationResponseType === 'confirm'\"\n class=\"clarification-buttons\"\n [class.list]=\"clarificationPresentation === 'list'\"\n >\n <button\n mat-button\n type=\"button\"\n *ngFor=\"let opt of clarificationOptions; let i = index\"\n (click)=\"onClarificationOptionClick(opt)\"\n class=\"clarification-option\"\n [class.selected]=\"isClarificationSelected(opt)\"\n [matTooltip]=\"getClarificationTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowClarificationTooltip(opt) || isEndpointOption(opt)\"\n >\n <ng-container *ngTemplateOutlet=\"clarificationOptionContent; context: { $implicit: opt, index: i, compact: false }\"></ng-container>\n </button>\n </div>\n <div\n *ngIf=\"clarificationSelectionMode === 'multiple'\"\n class=\"clarification-buttons\"\n [class.list]=\"clarificationPresentation === 'list'\"\n >\n <button\n mat-button\n type=\"button\"\n *ngFor=\"let opt of clarificationOptions; let i = index\"\n (click)=\"onClarificationOptionClick(opt)\"\n [class.selected]=\"isClarificationSelected(opt)\"\n class=\"clarification-option\"\n [matTooltip]=\"getClarificationTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowClarificationTooltip(opt) || isEndpointOption(opt)\"\n >\n <ng-container *ngTemplateOutlet=\"clarificationOptionContent; context: { $implicit: opt, index: i, compact: false }\"></ng-container>\n </button>\n </div>\n <div\n *ngIf=\"clarificationResponseType !== 'confirm' && clarificationSelectionMode === 'single' && clarificationPresentation !== 'chips'\"\n class=\"clarification-buttons\"\n [class.list]=\"clarificationPresentation === 'list'\"\n >\n <button\n mat-button\n type=\"button\"\n *ngFor=\"let opt of clarificationOptions; let i = index\"\n (click)=\"onClarificationOptionClick(opt)\"\n class=\"clarification-option\"\n [class.selected]=\"isClarificationSelected(opt)\"\n [matTooltip]=\"getClarificationTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowClarificationTooltip(opt) || isEndpointOption(opt)\"\n >\n <ng-container *ngTemplateOutlet=\"clarificationOptionContent; context: { $implicit: opt, index: i, compact: false }\"></ng-container>\n </button>\n </div>\n <div\n *ngIf=\"clarificationResponseType !== 'confirm' && clarificationSelectionMode === 'single' && clarificationPresentation === 'chips'\"\n class=\"clarification-chips\"\n >\n <ng-container *ngFor=\"let opt of clarificationOptions; let i = index\">\n <button\n *ngIf=\"isEndpointOption(opt); else chipOption\"\n mat-button\n type=\"button\"\n class=\"clarification-option clarification-card-button\"\n (click)=\"onClarificationOptionClick(opt)\"\n [class.selected]=\"isClarificationSelected(opt)\"\n [matTooltip]=\"getClarificationTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowClarificationTooltip(opt) || isEndpointOption(opt)\"\n >\n <ng-container *ngTemplateOutlet=\"clarificationOptionContent; context: { $implicit: opt, index: i, compact: false }\"></ng-container>\n </button>\n <ng-template #chipOption>\n <mat-chip\n (click)=\"onClarificationOptionClick(opt)\"\n [matTooltip]=\"getClarificationTooltip(opt)\"\n [matTooltipDisabled]=\"!shouldShowClarificationTooltip(opt)\"\n class=\"clarification-chip\"\n >\n <ng-container *ngTemplateOutlet=\"clarificationOptionContent; context: { $implicit: opt, index: i, compact: true }\"></ng-container>\n </mat-chip>\n </ng-template>\n </ng-container>\n </div>\n </div>\n <div\n *ngIf=\"clarificationAllowCustom && clarificationResponseType !== 'context'\"\n class=\"clarification-manual-toggle\"\n >\n <span class=\"clarification-manual-label\">N\u00E3o encontrou o recurso?</span>\n <button mat-button type=\"button\" (click)=\"toggleManualInput()\">\n {{ showManualInput ? 'Ocultar resposta manual' : 'Responder manualmente' }}\n </button>\n </div>\n <div\n *ngIf=\"clarificationAllowCustom && showManualInput && clarificationResponseType !== 'context'\"\n class=\"clarification-free\"\n >\n <input\n type=\"text\"\n [(ngModel)]=\"clarificationFreeText\"\n placeholder=\"Digite sua resposta\u2026\"\n autocomplete=\"off\"\n (keydown.enter)=\"confirmTaskAction()\"\n />\n </div>\n <div\n *ngIf=\"clarificationAllowCustom && showManualInput && clarificationResponseType !== 'context'\"\n class=\"clarification-free-hint\"\n >\n Pressione Enter para enviar.\n </div>\n </div>\n\n <!-- STATE: REVIEW (Diff/Explanation) -->\n <div\n *ngIf=\"state === 'review' && isActiveTab('task')\"\n class=\"review-area assistant-card\"\n id=\"assistant-panel-task\"\n role=\"tabpanel\"\n aria-labelledby=\"assistant-tab-task\"\n >\n <div class=\"task-header\" *ngIf=\"!shouldShowThoughtCard()\">\n <div class=\"task-title\">{{ getTaskTitle() }}</div>\n <div class=\"task-subtitle\">{{ getTaskSubtitle() }}</div>\n <div *ngIf=\"clarificationOptions.length > 1 && getTaskSelectionSummary() as selectionSummary\" class=\"task-meta\">\n <span class=\"task-meta-label\">Selecionado:</span>\n <span class=\"task-meta-value\">{{ selectionSummary }}</span>\n </div>\n <div *ngIf=\"shouldShowTaskSteps()\" class=\"task-steps\">\n <span class=\"task-step\">1 Dados</span>\n <span class=\"task-step\">2 Layout</span>\n <span class=\"task-step active\">3 Revis\u00E3o</span>\n </div>\n </div>\n <div *ngIf=\"warnings.length\" class=\"warnings-area\">\n <mat-icon class=\"warnings-icon\">warning_amber</mat-icon>\n <div class=\"warnings-content\">\n <div class=\"warnings-title\">Avisos</div>\n <div class=\"warnings-list\">\n <div *ngFor=\"let warning of warnings\">{{ warning }}</div>\n </div>\n </div>\n </div>\n <div class=\"review-trust\">\n <span class=\"trust-chip\" [matTooltip]=\"getScopeTooltip()\">{{ getScopeLabel() }}</span>\n <span class=\"trust-chip\" [matTooltip]=\"getConfidenceTooltip()\">{{ getConfidenceLabel() }}</span>\n <span class=\"trust-chip risk-chip\" [class.medium]=\"getReviewRiskLevel() === 'm\u00E9dio'\" [class.high]=\"getReviewRiskLevel() === 'alto'\">\n Risco {{ getReviewRiskLevel() }}\n </span>\n </div>\n <div class=\"review-summary\" [class.attention-highlight]=\"highlightReviewDetails\">\n <div class=\"review-summary-title\">Resumo da proposta</div>\n <div class=\"review-summary-line\">{{ getReviewSummary() }}</div>\n </div>\n <div class=\"review-diff\">\n <div class=\"review-diff-title\">Pr\u00E9via de mudan\u00E7as</div>\n <ng-container *ngIf=\"pendingDiff.length; else noDiffPreview\">\n <div class=\"review-diff-summary\">\n <div *ngFor=\"let line of getDiffSummaryLines()\" class=\"review-diff-line\">{{ line }}</div>\n <div *ngIf=\"pendingDiff.length > 3\" class=\"review-diff-more\">\u2026 +{{ pendingDiff.length - 3 }} mudan\u00E7as</div>\n </div>\n <button mat-stroked-button type=\"button\" class=\"review-diff-toggle\" (click)=\"toggleFullDiff()\">\n {{ getDiffToggleLabel() }}\n </button>\n </ng-container>\n <ng-template #noDiffPreview>\n <div class=\"review-diff-empty\">\n N\u00E3o foi poss\u00EDvel gerar um diff estruturado. Revise o resumo e aplique com cautela.\n </div>\n </ng-template>\n <div *ngIf=\"showFullDiff && pendingDiff.length\" class=\"review-diff-full\">\n <div *ngFor=\"let diff of pendingDiff\" class=\"review-diff-block\">\n <div class=\"review-diff-path\">{{ diff.path }}</div>\n <div class=\"review-diff-label\">Antes:</div>\n <pre>{{ diff.before | json }}</pre>\n <div class=\"review-diff-label\">Depois:</div>\n <pre>{{ diff.after | json }}</pre>\n </div>\n </div>\n </div>\n <div class=\"ai-explanation\" *ngIf=\"aiExplanation.trim()\">\n {{ aiExplanation }}\n </div>\n </div>\n\n <!-- STATE: ERROR -->\n <div\n *ngIf=\"state === 'error' && (isActiveTab('task') || (!isTaskMode() && isActiveTab('suggestions')))\"\n class=\"error-area assistant-card\"\n [attr.id]=\"isTaskMode() ? 'assistant-panel-task' : 'assistant-panel-suggestions'\"\n role=\"tabpanel\"\n [attr.aria-labelledby]=\"isTaskMode() ? 'assistant-tab-task' : 'assistant-tab-suggestions'\"\n >\n <div class=\"error-msg\">\n <mat-icon color=\"warn\">error_outline</mat-icon>\n <span>{{ errorMsg }}</span>\n </div>\n <div *ngIf=\"warnings.length\" class=\"warnings-area\">\n <mat-icon class=\"warnings-icon\">warning_amber</mat-icon>\n <div class=\"warnings-content\">\n <div class=\"warnings-title\">Avisos</div>\n <div class=\"warnings-list\">\n <div *ngFor=\"let warning of warnings\">{{ warning }}</div>\n </div>\n </div>\n </div>\n <div *ngIf=\"shouldShowApplyDetails()\" class=\"apply-details\">\n <div class=\"apply-details-header\">\n <div class=\"apply-details-title\">Detalhes da aplica\u00E7\u00E3o</div>\n <div class=\"apply-details-actions\" *ngIf=\"allowManualPatchEdit\">\n <button mat-button type=\"button\" (click)=\"togglePatchPathEditor()\" [disabled]=\"!pendingPatch\">\n {{ patchPathEditorExpanded ? 'Ocultar paths' : 'Editar por path' }}\n </button>\n <button mat-button type=\"button\" (click)=\"togglePatchEditor()\" [disabled]=\"!pendingPatch\">\n {{ patchEditorExpanded ? 'Ocultar editor' : 'Editar patch' }}\n </button>\n </div>\n </div>\n <div class=\"apply-details-meta\" *ngIf=\"lastApplyAt\">\n \u00DAltima tentativa: {{ lastApplyAt | date:'short' }}\n </div>\n <div class=\"apply-paths\" *ngIf=\"getApplyPaths().length\">\n <span class=\"apply-path-chip\" *ngFor=\"let path of getApplyPaths()\">{{ path }}</span>\n </div>\n <div class=\"apply-warnings\" *ngIf=\"applyWarnings.length\">\n <div class=\"apply-warnings-title\">Avisos da aplica\u00E7\u00E3o</div>\n <div class=\"apply-warnings-list\">\n <div *ngFor=\"let warning of applyWarnings\">{{ warning }}</div>\n </div>\n </div>\n <div class=\"patch-path-editor\" *ngIf=\"allowManualPatchEdit && patchPathEditorExpanded\">\n <div class=\"patch-editor-label\">Editar por path</div>\n <div class=\"patch-editor-hint\">Texto simples vira string; para for\u00E7ar texto em true/false/n\u00FAmero, use aspas.</div>\n <div class=\"patch-path-editor-empty\" *ngIf=\"!getEditablePatchPathEdits().length\">\n Nenhum path edit\u00E1vel dispon\u00EDvel para este patch.\n </div>\n <div class=\"patch-path-rows\" *ngIf=\"getEditablePatchPathEdits().length\">\n <div class=\"patch-path-row\" *ngFor=\"let edit of getEditablePatchPathEdits(); let i = index\">\n <div class=\"patch-path-label\">{{ edit.path }}</div>\n <input\n type=\"text\"\n [(ngModel)]=\"patchPathEdits[i].valueText\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n />\n <div *ngIf=\"patchPathEdits[i].error\" class=\"patch-editor-error\">{{ patchPathEdits[i].error }}</div>\n </div>\n </div>\n <div *ngIf=\"patchPathEditorError\" class=\"patch-editor-error\">{{ patchPathEditorError }}</div>\n <div class=\"patch-editor-actions\">\n <button mat-button type=\"button\" (click)=\"resetPatchPathEdits()\">\n Restaurar valores\n </button>\n <button mat-button type=\"button\" (click)=\"applyPathEditsToPatch()\">\n Aplicar no patch\n </button>\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"reapplyPathEdits()\">\n Reaplicar por path\n </button>\n </div>\n </div>\n <div class=\"patch-editor\" *ngIf=\"allowManualPatchEdit && patchEditorExpanded\">\n <label class=\"patch-editor-label\">Patch JSON</label>\n <textarea\n [(ngModel)]=\"patchEditorText\"\n spellcheck=\"false\"\n ></textarea>\n <div *ngIf=\"patchEditorError\" class=\"patch-editor-error\">{{ patchEditorError }}</div>\n <div class=\"patch-editor-actions\">\n <button mat-button type=\"button\" (click)=\"resetPatchEditor()\">\n Restaurar original\n </button>\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"reapplyEditedPatch()\">\n Reaplicar patch\n </button>\n </div>\n </div>\n </div>\n <div class=\"review-actions\">\n <button mat-button (click)=\"close()\">Fechar</button>\n <button mat-stroked-button (click)=\"retry()\">Tentar Novamente</button>\n </div>\n </div>\n\n <!-- STATE: SUCCESS -->\n <div\n *ngIf=\"state === 'success' && (isActiveTab('task') || (!isTaskMode() && isActiveTab('suggestions')))\"\n class=\"success-area assistant-card\"\n [attr.id]=\"isTaskMode() ? 'assistant-panel-task' : 'assistant-panel-suggestions'\"\n role=\"tabpanel\"\n [attr.aria-labelledby]=\"isTaskMode() ? 'assistant-tab-task' : 'assistant-tab-suggestions'\"\n >\n <div class=\"success-msg\">\n <mat-icon class=\"success-icon\">check_circle</mat-icon>\n <span>{{ aiExplanation || 'Configura\u00E7\u00E3o atualizada.' }}</span>\n </div>\n <div *ngIf=\"warnings.length\" class=\"warnings-area\">\n <mat-icon class=\"warnings-icon\">warning_amber</mat-icon>\n <div class=\"warnings-content\">\n <div class=\"warnings-title\">Avisos</div>\n <div class=\"warnings-list\">\n <div *ngFor=\"let warning of warnings\">{{ warning }}</div>\n </div>\n </div>\n </div>\n <div *ngIf=\"shouldShowApplyDetails()\" class=\"apply-details\">\n <div class=\"apply-details-header\">\n <div class=\"apply-details-title\">Detalhes da aplica\u00E7\u00E3o</div>\n <div class=\"apply-details-actions\" *ngIf=\"allowManualPatchEdit\">\n <button mat-button type=\"button\" (click)=\"togglePatchPathEditor()\" [disabled]=\"!pendingPatch\">\n {{ patchPathEditorExpanded ? 'Ocultar paths' : 'Editar por path' }}\n </button>\n <button mat-button type=\"button\" (click)=\"togglePatchEditor()\" [disabled]=\"!pendingPatch\">\n {{ patchEditorExpanded ? 'Ocultar editor' : 'Editar e reaplicar' }}\n </button>\n </div>\n </div>\n <div class=\"apply-details-meta\" *ngIf=\"lastApplyAt\">\n Aplicado em {{ lastApplyAt | date:'short' }}\n </div>\n <div class=\"apply-paths\" *ngIf=\"getApplyPaths().length\">\n <span class=\"apply-path-chip\" *ngFor=\"let path of getApplyPaths()\">{{ path }}</span>\n </div>\n <div class=\"apply-warnings\" *ngIf=\"applyWarnings.length\">\n <div class=\"apply-warnings-title\">Avisos da aplica\u00E7\u00E3o</div>\n <div class=\"apply-warnings-list\">\n <div *ngFor=\"let warning of applyWarnings\">{{ warning }}</div>\n </div>\n </div>\n <div class=\"patch-path-editor\" *ngIf=\"allowManualPatchEdit && patchPathEditorExpanded\">\n <div class=\"patch-editor-label\">Editar por path</div>\n <div class=\"patch-editor-hint\">Texto simples vira string; para for\u00E7ar texto em true/false/n\u00FAmero, use aspas.</div>\n <div class=\"patch-path-editor-empty\" *ngIf=\"!getEditablePatchPathEdits().length\">\n Nenhum path edit\u00E1vel dispon\u00EDvel para este patch.\n </div>\n <div class=\"patch-path-rows\" *ngIf=\"getEditablePatchPathEdits().length\">\n <div class=\"patch-path-row\" *ngFor=\"let edit of getEditablePatchPathEdits(); let i = index\">\n <div class=\"patch-path-label\">{{ edit.path }}</div>\n <input\n type=\"text\"\n [(ngModel)]=\"patchPathEdits[i].valueText\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n />\n <div *ngIf=\"patchPathEdits[i].error\" class=\"patch-editor-error\">{{ patchPathEdits[i].error }}</div>\n </div>\n </div>\n <div *ngIf=\"patchPathEditorError\" class=\"patch-editor-error\">{{ patchPathEditorError }}</div>\n <div class=\"patch-editor-actions\">\n <button mat-button type=\"button\" (click)=\"resetPatchPathEdits()\">\n Restaurar valores\n </button>\n <button mat-button type=\"button\" (click)=\"applyPathEditsToPatch()\">\n Aplicar no patch\n </button>\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"reapplyPathEdits()\">\n Reaplicar por path\n </button>\n </div>\n </div>\n <div class=\"patch-editor\" *ngIf=\"allowManualPatchEdit && patchEditorExpanded\">\n <label class=\"patch-editor-label\">Patch JSON</label>\n <textarea\n [(ngModel)]=\"patchEditorText\"\n spellcheck=\"false\"\n ></textarea>\n <div *ngIf=\"patchEditorError\" class=\"patch-editor-error\">{{ patchEditorError }}</div>\n <div class=\"patch-editor-actions\">\n <button mat-button type=\"button\" (click)=\"resetPatchEditor()\">\n Restaurar original\n </button>\n <button mat-flat-button color=\"primary\" type=\"button\" (click)=\"reapplyEditedPatch()\">\n Reaplicar patch\n </button>\n </div>\n </div>\n </div>\n <button mat-button color=\"warn\" (click)=\"undoLastChange()\">\n <mat-icon>undo</mat-icon> Desfazer\n </button>\n </div>\n\n </div>\n\n <div class=\"assistant-footer\">\n <ng-container *ngIf=\"!isTaskMode(); else taskFooter\">\n <button\n mat-icon-button\n type=\"button\"\n class=\"composer-leading composer-leading-btn\"\n [matMenuTriggerFor]=\"assistantQuickMenu\"\n aria-label=\"Abrir a\u00E7\u00F5es r\u00E1pidas\"\n matTooltip=\"A\u00E7\u00F5es r\u00E1pidas\"\n >\n <mat-icon>add</mat-icon>\n </button>\n <input\n #inputEl\n type=\"text\"\n [(ngModel)]=\"userPrompt\"\n [disabled]=\"state === 'processing' || state === 'applying'\"\n placeholder=\"Descreva a altera\u00E7\u00E3o que deseja aplicar\u2026\"\n autocomplete=\"off\"\n />\n <div class=\"send-actions\">\n <button\n mat-icon-button\n class=\"send-btn\"\n *ngIf=\"state === 'listening'\"\n (click)=\"submitPrompt()\"\n [disabled]=\"!userPrompt.trim()\"\n [class.ready]=\"!!userPrompt.trim()\"\n >\n <mat-icon>arrow_upward</mat-icon>\n </button>\n <mat-spinner diameter=\"20\" *ngIf=\"state === 'processing' || state === 'applying'\"></mat-spinner>\n </div>\n </ng-container>\n <ng-template #taskFooter>\n <div class=\"task-footer\">\n <div class=\"task-footer-left\">\n <button mat-button type=\"button\" (click)=\"handleTaskSecondary()\">{{ getTaskCancelLabel() }}</button>\n <button\n *ngIf=\"state === 'review'\"\n mat-stroked-button\n type=\"button\"\n (click)=\"retry()\"\n >\n {{ getTaskSecondaryLabel() }}\n </button>\n </div>\n <div class=\"task-footer-right\">\n <button\n class=\"task-primary-btn\"\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n (click)=\"confirmTaskAction()\"\n [disabled]=\"isTaskPrimaryDisabled()\"\n >\n {{ getTaskPrimaryLabel() }}\n </button>\n <mat-spinner diameter=\"20\" *ngIf=\"state === 'processing' || state === 'applying'\"></mat-spinner>\n </div>\n </div>\n </ng-template>\n </div>\n\n <mat-menu #assistantQuickMenu=\"matMenu\" panelClass=\"assistant-quick-menu-panel\">\n <button mat-menu-item type=\"button\" (click)=\"setActiveTab('chat')\">\n <mat-icon>history</mat-icon>\n <span>Hist\u00F3rico</span>\n </button>\n <button mat-menu-item type=\"button\" (click)=\"setActiveTab('suggestions')\">\n <mat-icon>lightbulb</mat-icon>\n <span>Sugest\u00F5es</span>\n </button>\n <button mat-menu-item type=\"button\" (click)=\"startNewSession()\">\n <mat-icon>add_comment</mat-icon>\n <span>Nova conversa</span>\n </button>\n <button mat-menu-item type=\"button\" (click)=\"refreshSuggestions()\" [disabled]=\"loadingSuggestions\">\n <mat-icon>refresh</mat-icon>\n <span>Atualizar sugest\u00F5es</span>\n </button>\n <button\n mat-menu-item\n type=\"button\"\n (click)=\"restoreDismissedSuggestions()\"\n [disabled]=\"!hasDismissedSuggestions()\"\n >\n <mat-icon>visibility</mat-icon>\n <span>Restaurar sugest\u00F5es ocultas</span>\n </button>\n <button\n mat-menu-item\n type=\"button\"\n class=\"assistant-quick-menu-danger\"\n (click)=\"clearHistory()\"\n [disabled]=\"!historySessions.length\"\n >\n <mat-icon>delete_outline</mat-icon>\n <span>Limpar hist\u00F3rico local</span>\n </button>\n </mat-menu>\n </div>\n\n</ng-template>\n", styles: ["@keyframes assistantPremiumEnter{0%{opacity:0;transform:translate(14px) scale(.99)}to{opacity:1;transform:translate(0) scale(1)}}:host ::ng-deep .ai-assistant-backdrop{background:color-mix(in srgb,var(--md-sys-color-scrim, var(--md-sys-color-shadow, var(--md-sys-color-on-surface))) 42%,transparent);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}::ng-deep .ai-assistant-overlay-pane{max-width:calc(100vw - 24px);max-height:calc(100vh - 24px)}.ai-assistant-panel{box-sizing:border-box;width:min(604px,100vw - 18px);min-height:min(620px,100vh - 18px);max-height:min(820px,100vh - 18px);display:flex;flex-direction:column;overflow:hidden;color:var(--md-sys-color-on-surface);border-left:1px solid color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));border-top:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));box-shadow:0 18px 48px color-mix(in srgb,var(--md-sys-color-shadow, var(--md-sys-color-on-surface)) 42%,transparent),inset 0 1px color-mix(in srgb,var(--md-sys-color-on-surface) 10%,transparent);background:radial-gradient(circle at 14% 8%,color-mix(in srgb,var(--md-sys-color-primary-container) 38%,transparent) 0%,transparent 44%),linear-gradient(165deg,color-mix(in srgb,var(--md-sys-color-surface-container-highest) 88%,var(--md-sys-color-surface)),var(--md-sys-color-surface));animation:assistantPremiumEnter .24s cubic-bezier(.22,1,.36,1)}.assistant-header{position:relative;display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:12px 16px 10px;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));background:linear-gradient(130deg,color-mix(in srgb,var(--md-sys-color-primary-container) 28%,transparent) 0%,transparent 52%),var(--md-sys-color-surface-container-low)}.assistant-header:after{content:\"\";position:absolute;left:16px;right:16px;bottom:-1px;height:1px;background:linear-gradient(90deg,color-mix(in srgb,var(--md-sys-color-primary) 55%,transparent),transparent);pointer-events:none}.assistant-header .assistant-header__left{min-width:0;display:flex;align-items:flex-start;gap:12px}.assistant-header .magic-icon{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;width:30px;height:30px;font-size:18px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 30%,transparent);box-shadow:0 4px 12px color-mix(in srgb,var(--md-sys-color-primary) 26%,transparent)}.assistant-header .assistant-title-group{min-width:0;display:flex;flex-direction:column;gap:4px}.assistant-header .assistant-title{font-size:15px;font-weight:700;letter-spacing:.01em;overflow-wrap:anywhere}.assistant-header .assistant-subtitle{display:block;font-size:11px;line-height:1.25;color:color-mix(in srgb,var(--md-sys-color-on-surface) 70%,var(--md-sys-color-on-surface-variant));overflow-wrap:anywhere}.assistant-header-chips{display:inline-flex;align-items:center;flex-wrap:wrap;gap:6px}.assistant-header .mode-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 28%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-primary-container) 64%,var(--md-sys-color-surface-container));color:color-mix(in srgb,var(--md-sys-color-on-primary-container) 85%,var(--md-sys-color-on-surface));font-size:10px;font-weight:700;letter-spacing:.04em;text-transform:uppercase}.assistant-header .mode-chip:before{content:\"\";width:6px;height:6px;border-radius:999px;background:currentColor;box-shadow:0 0 0 3px color-mix(in srgb,currentColor 16%,transparent)}.assistant-header .mode-chip.mock{border-color:color-mix(in srgb,var(--md-sys-color-error) 34%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-error-container) 72%,var(--md-sys-color-surface-container));color:color-mix(in srgb,var(--md-sys-color-on-error-container) 85%,var(--md-sys-color-error))}.assistant-header .policy-chip{padding:2px 8px;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 84%,transparent);background:var(--md-sys-color-surface-container-high);font-size:10px;letter-spacing:.02em;font-weight:600}.assistant-header .policy-chip.strict{border-color:color-mix(in srgb,var(--md-sys-color-primary) 42%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-primary-container) 56%,var(--md-sys-color-surface-container-high))}.assistant-status{display:flex;align-items:flex-start;gap:10px;padding:10px 16px;border-bottom:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));border-radius:0;background:linear-gradient(160deg,color-mix(in srgb,var(--md-sys-color-primary-container) 24%,transparent),transparent 48%),var(--md-sys-color-surface-container-low)}.assistant-status-dot{width:8px;height:8px;margin-top:6px;border-radius:999px;flex:0 0 auto;background:var(--md-sys-color-primary);box-shadow:0 0 0 4px color-mix(in srgb,var(--md-sys-color-primary) 16%,transparent)}.assistant-status.warning .assistant-status-dot{background:var(--md-sys-color-error);box-shadow:0 0 0 4px color-mix(in srgb,var(--md-sys-color-error) 16%,transparent)}.assistant-status.success .assistant-status-dot{background:color-mix(in srgb,var(--md-sys-color-primary) 74%,var(--md-sys-color-tertiary, var(--md-sys-color-primary)))}.assistant-status-content{min-width:0;display:flex;flex-direction:column;gap:2px}.assistant-status-label{display:flex;align-items:center;flex-wrap:wrap;gap:4px;font-size:12px;font-weight:700;line-height:1.35}.assistant-status-detail{font-size:11px;line-height:1.4;color:var(--md-sys-color-on-surface-variant);overflow-wrap:anywhere}.assistant-status-mode{padding:1px 6px;border-radius:999px;background:color-mix(in srgb,var(--md-sys-color-primary-container) 72%,transparent);color:var(--md-sys-color-on-primary-container);font-size:10px;font-weight:700}.assistant-nav{padding:8px 16px 0}.assistant-nav .assistant-tabs{display:flex;align-items:center;gap:4px;border-radius:12px;padding:5px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));border-color:color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));background:linear-gradient(155deg,color-mix(in srgb,var(--md-sys-color-primary-container) 14%,transparent),transparent 58%),var(--md-sys-color-surface-container-low)}.assistant-nav .assistant-tab{appearance:none;min-width:0;min-height:30px;border:0;border-radius:8px;padding:0 10px;background:transparent;color:var(--md-sys-color-on-surface-variant);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;flex:1 1 0;font-size:11px;font-weight:700;letter-spacing:.01em}.assistant-nav .assistant-tab.active{background:var(--md-sys-color-surface-container-highest);color:var(--md-sys-color-on-surface);box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 34%,transparent),0 6px 12px color-mix(in srgb,var(--md-sys-color-primary) 18%,transparent)}.assistant-section,.assistant-card{border-radius:14px;border-color:color-mix(in srgb,var(--md-sys-color-primary) 20%,var(--md-sys-color-outline-variant));background:linear-gradient(160deg,color-mix(in srgb,var(--md-sys-color-primary-container) 16%,transparent),transparent 50%),var(--md-sys-color-surface-container-lowest);box-shadow:0 6px 18px color-mix(in srgb,var(--md-sys-color-shadow, var(--md-sys-color-on-surface)) 12%,transparent),inset 0 1px color-mix(in srgb,var(--md-sys-color-on-surface) 7%,transparent)}.suggestions-hero{margin:2px 0 4px;padding:10px 12px;border-radius:12px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));background:linear-gradient(120deg,color-mix(in srgb,var(--md-sys-color-primary-container) 34%,transparent) 0%,transparent 52%),var(--md-sys-color-surface-container-low)}.suggestions-hero__label{font-size:10px;letter-spacing:.08em;text-transform:uppercase;font-weight:700;color:var(--md-sys-color-on-surface-variant);opacity:.88}.suggestions-hero__title{margin-top:2px;font-size:13px;font-weight:700;color:var(--md-sys-color-on-surface)}.suggestions-hero__detail{margin-top:4px;font-size:12px;line-height:1.4;color:color-mix(in srgb,var(--md-sys-color-on-surface) 78%,var(--md-sys-color-on-surface-variant))}.suggestions-content .suggestion-item{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:12px;padding:12px;border-radius:12px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));border-color:color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-outline-variant));background:linear-gradient(140deg,color-mix(in srgb,var(--md-sys-color-primary-container) 16%,transparent),transparent 56%),var(--md-sys-color-surface-container-lowest);transition:transform .2s cubic-bezier(.25,.8,.25,1),border-color .2s ease,box-shadow .2s ease}.suggestions-list{display:flex;flex-direction:column;gap:10px}.suggestion-copy{min-width:0;display:grid;gap:4px}.suggestion-main{min-width:0;display:flex;align-items:center;flex-wrap:wrap;gap:8px}.suggestion-icon{width:18px;height:18px;font-size:18px;flex:0 0 auto;color:var(--md-sys-color-primary)}.suggestion-label{min-width:0;font-size:13px;font-weight:700;line-height:1.35;overflow-wrap:anywhere}.suggestion-group{padding:2px 6px;border-radius:999px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface-variant);font-size:10px;font-weight:700;line-height:1.2}.suggestion-desc{font-size:12px;line-height:1.35;color:var(--md-sys-color-on-surface-variant);overflow-wrap:anywhere}.suggestion-actions{display:inline-flex;align-items:center;justify-content:flex-end;gap:4px}.suggestion-action-btn,.suggestion-arrow{width:32px;height:32px;display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;color:var(--md-sys-color-on-surface-variant)}.suggestions-content .suggestion-item:hover,.suggestions-content .suggestion-item:focus-visible{border-color:color-mix(in srgb,var(--md-sys-color-primary) 58%,var(--md-sys-color-outline-variant));box-shadow:0 8px 18px color-mix(in srgb,var(--md-sys-color-primary) 18%,transparent),inset 0 0 0 1px color-mix(in srgb,var(--md-sys-color-primary) 28%,transparent);transform:translateY(-2px) scale(1.01)}.assistant-footer{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:8px;padding:10px 16px;border-top-color:color-mix(in srgb,var(--md-sys-color-primary) 20%,var(--md-sys-color-outline-variant));background:linear-gradient(180deg,color-mix(in srgb,var(--md-sys-color-primary-container) 16%,transparent),transparent 56%),var(--md-sys-color-surface-container-low)}.assistant-footer .task-footer{grid-column:1/-1}.composer-leading{width:30px;height:30px;display:inline-flex;align-items:center;justify-content:center;border-radius:999px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 30%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-primary-container) 70%,var(--md-sys-color-surface-container-low));color:var(--md-sys-color-primary);box-shadow:0 4px 10px color-mix(in srgb,var(--md-sys-color-primary) 16%,transparent)}.composer-leading mat-icon{width:16px;height:16px;font-size:16px}.assistant-footer input{box-sizing:border-box;width:100%;min-width:0;height:34px;border:1px solid;border-radius:8px;padding:0 12px;color:var(--md-sys-color-on-surface);border-color:color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));background:var(--md-sys-color-surface);box-shadow:inset 0 1px 2px color-mix(in srgb,var(--md-sys-color-shadow, var(--md-sys-color-on-surface)) 12%,transparent)}.send-actions{min-width:36px;display:inline-flex;align-items:center;justify-content:center}.assistant-footer .send-btn{--mdc-icon-button-icon-size: 20px;--mdc-icon-button-state-layer-size: 36px;--mat-icon-button-state-layer-size: 36px;width:36px;height:36px;padding:8px;line-height:1;display:inline-flex;align-items:center;justify-content:center;border-color:color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant));background:var(--md-sys-color-surface)}.assistant-footer .send-btn mat-icon{width:20px;height:20px;margin:0;font-size:20px;line-height:20px;display:inline-flex;align-items:center;justify-content:center}.assistant-footer .send-btn.ready{background:linear-gradient(135deg,color-mix(in srgb,var(--md-sys-color-primary-container) 84%,var(--md-sys-color-primary)),var(--md-sys-color-primary));color:var(--md-sys-color-on-primary);box-shadow:0 8px 18px color-mix(in srgb,var(--md-sys-color-primary) 30%,transparent)}.task-primary-btn{border-radius:12px;box-shadow:0 8px 18px color-mix(in srgb,var(--md-sys-color-primary) 24%,transparent)}@media(max-width:959px){.assistant-header{padding:12px 12px 10px}.assistant-section,.assistant-card{margin:4px 12px 10px}.assistant-header:after{left:12px;right:12px}.assistant-header .assistant-title{font-size:14px}.assistant-header .assistant-subtitle{font-size:10px}.assistant-footer{grid-template-columns:minmax(0,1fr) auto}.composer-leading{display:none}}.assistant-thought{margin-top:0;gap:10px;border-color:color-mix(in srgb,var(--md-sys-color-primary) 26%,var(--md-sys-color-outline-variant));background:linear-gradient(145deg,color-mix(in srgb,var(--md-sys-color-primary-container) 28%,transparent),transparent 58%),var(--md-sys-color-surface-container-low)}.assistant-thought-meta{display:inline-flex;align-items:center;gap:6px;font-size:11px;color:var(--md-sys-color-on-surface-variant)}.assistant-thought-meta mat-icon{width:15px;height:15px;font-size:15px;color:var(--md-sys-color-primary)}.assistant-thought-summary{font-size:13px;line-height:1.45;color:var(--md-sys-color-on-surface)}.assistant-thought-plan{border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 32%,var(--md-sys-color-outline-variant));border-radius:12px;padding:10px;background:var(--md-sys-color-surface-container-lowest);display:flex;flex-direction:column;gap:8px}.assistant-thought-plan-title{font-size:13px;font-weight:700;color:var(--md-sys-color-on-surface)}.assistant-thought-plan-actions{display:grid;grid-template-columns:repeat(auto-fit,minmax(0,1fr));gap:8px}.assistant-thought-plan-actions .mdc-button{min-width:0}.assistant-thought-plan-hint{font-size:11px;color:var(--md-sys-color-on-surface-variant);line-height:1.35}.assistant-thought-checklist{display:flex;flex-direction:column;gap:5px}.assistant-thought-checklist-item{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--md-sys-color-on-surface-variant)}.assistant-thought-checklist-item mat-icon{width:14px;height:14px;font-size:14px}.assistant-thought-shimmer{display:flex;flex-direction:column;gap:8px;margin-top:4px}.assistant-thought-shimmer .shimmer-line{height:12px;border-radius:4px;position:relative;overflow:hidden;background:var(--md-sys-color-surface-container-highest)}.assistant-thought-shimmer .shimmer-line:after{content:\"\";position:absolute;inset:0;transform:translate(-100%);background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--md-sys-color-primary) 8%,transparent),transparent);animation:assistantShimmerEffect 1.5s infinite}.assistant-thought-shimmer .shimmer-line-1{width:85%}.assistant-thought-shimmer .shimmer-line-2{width:92%}.assistant-thought-shimmer .shimmer-line-3{width:64%}@keyframes assistantShimmerEffect{to{transform:translate(100%)}}.assistant-flow{grid-template-columns:1fr;gap:6px}.flow-step{display:flex;align-items:flex-start;gap:8px;text-align:left;padding:7px 8px;border-radius:10px}.flow-step-index{width:18px;height:18px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-highest);color:var(--md-sys-color-on-surface);flex:0 0 auto}.flow-step-content{min-width:0;display:flex;flex-direction:column;gap:1px}.flow-step-label{font-size:11px;font-weight:700;color:var(--md-sys-color-on-surface)}.flow-step-detail{font-size:11px;color:var(--md-sys-color-on-surface-variant);line-height:1.3}.flow-step.active .flow-step-index{border-color:color-mix(in srgb,var(--md-sys-color-primary) 60%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-primary-container) 85%,var(--md-sys-color-surface-container-highest));color:var(--md-sys-color-on-primary-container)}.flow-step.done .flow-step-index{border-color:transparent;background:color-mix(in srgb,var(--md-sys-color-primary) 18%,var(--md-sys-color-surface-container-highest))}.task-timeline{margin-top:4px;display:grid;gap:6px}.task-timeline-item{display:flex;align-items:flex-start;gap:8px;border:1px solid var(--md-sys-color-outline-variant);border-radius:10px;padding:6px 8px;background:var(--md-sys-color-surface-container-low);opacity:.76}.task-timeline-item.active{opacity:1;border-color:color-mix(in srgb,var(--md-sys-color-primary) 40%,var(--md-sys-color-outline-variant));background:color-mix(in srgb,var(--md-sys-color-primary-container) 34%,var(--md-sys-color-surface-container-low))}.task-timeline-item.done{opacity:.9;border-color:color-mix(in srgb,var(--md-sys-color-primary) 24%,var(--md-sys-color-outline-variant))}.task-timeline-dot{width:18px;height:18px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;border:1px solid var(--md-sys-color-outline-variant);background:var(--md-sys-color-surface-container-highest);color:var(--md-sys-color-on-surface);flex:0 0 auto}.task-timeline-copy{min-width:0;display:flex;flex-direction:column;gap:1px}.task-timeline-title{font-size:11px;font-weight:700;color:var(--md-sys-color-on-surface)}.task-timeline-detail{font-size:11px;line-height:1.3;color:var(--md-sys-color-on-surface-variant)}.clarification-decision-head{display:inline-flex;align-items:center;width:100%;gap:6px;padding:8px 12px 0;box-sizing:border-box}.clarification-decision-index{width:18px;height:18px;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 35%,var(--md-sys-color-outline-variant));color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary-container) 68%,transparent)}.clarification-decision-type{font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--md-sys-color-on-surface-variant);opacity:.92}.clarification-decision-state{font-size:10px;font-weight:700;color:var(--md-sys-color-primary)}.clarification-option{border-color:color-mix(in srgb,var(--md-sys-color-primary) 20%,var(--md-sys-color-outline-variant));background:linear-gradient(145deg,color-mix(in srgb,var(--md-sys-color-primary-container) 16%,transparent),transparent 55%),var(--md-sys-color-surface-container-low)}.clarification-option.selected{border-color:color-mix(in srgb,var(--md-sys-color-primary) 56%,var(--md-sys-color-outline-variant));background:linear-gradient(145deg,color-mix(in srgb,var(--md-sys-color-primary-container) 44%,transparent),transparent 62%),var(--md-sys-color-surface-container);box-shadow:0 8px 16px color-mix(in srgb,var(--md-sys-color-primary) 18%,transparent)}.clarification-options-block{overflow:visible;padding-right:4px}@media(max-width:959px){.assistant-thought-plan-actions{grid-template-columns:1fr}}.ai-assistant-panel{width:min(604px,100vw - 18px)}.assistant-section,.assistant-card{margin:0;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 20%,var(--md-sys-color-outline-variant))}.assistant-section{min-height:0;padding:14px 16px;overflow:visible}.assistant-card{min-height:0;padding:14px 16px 16px;overflow:visible}.suggestions-area,.assistant-history,.loading-suggestions{overflow-y:auto;overflow-x:hidden}.section-header{min-width:0;display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:10px}.section-title{min-width:0;font-size:14px;font-weight:700;line-height:1.35;overflow-wrap:anywhere}.suggestions-actions{flex:0 0 auto;display:inline-flex;align-items:center}.review-area,.error-area,.success-area,.clarification-area{padding:0;overflow-y:auto;overflow-x:hidden;scrollbar-gutter:auto}.review-trust{margin:2px 0 4px}.trust-chip{max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.warnings-area,.review-summary,.review-diff,.apply-details,.clarification-options-block,.clarification-manual-toggle{width:100%;max-width:100%;min-width:0}.review-diff{padding:12px 14px}.review-diff-full{padding:10px;overflow-x:auto}.review-diff-block{min-width:0}.review-diff-block pre{overflow-wrap:anywhere;word-break:break-word}.clarification-options-block{padding:4px 2px 10px}.clarification-option{line-height:normal}:host ::ng-deep .clarification-option .mdc-button__label{line-height:1.35!important}.clarification-plain-label{padding:6px 12px 12px;font-size:14px;line-height:1.35}.clarification-manual-toggle{margin-top:10px;padding:10px 2px 0;flex-wrap:wrap;row-gap:6px}.suggestions-content .suggestion-actions{gap:6px}.suggestions-content .suggestion-arrow,.suggestions-content .suggestion-action-btn mat-icon,.suggestions-content .suggestion-arrow mat-icon{display:inline-flex;align-items:center;justify-content:center}:host ::ng-deep .assistant-quick-menu-panel{min-width:244px;max-width:min(90vw,320px);border-radius:14px;border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 26%,var(--md-sys-color-outline-variant));background:var(--md-sys-color-surface-container-high);box-shadow:0 12px 28px color-mix(in srgb,var(--md-sys-color-shadow, var(--md-sys-color-on-surface)) 32%,transparent),inset 0 1px color-mix(in srgb,var(--md-sys-color-on-surface) 6%,transparent);overflow:hidden;padding:6px}:host ::ng-deep .assistant-quick-menu-panel .mat-mdc-menu-item{min-height:36px;border-radius:10px;color:var(--md-sys-color-on-surface);font-size:12px;font-weight:500;margin:1px 0}:host ::ng-deep .assistant-quick-menu-panel .mat-mdc-menu-item .mat-icon{color:color-mix(in srgb,var(--md-sys-color-on-surface) 82%,var(--md-sys-color-on-surface-variant))}:host ::ng-deep .assistant-quick-menu-panel .mat-mdc-menu-item:hover:not([disabled]){background:color-mix(in srgb,var(--md-sys-color-primary-container) 45%,transparent)}:host ::ng-deep .assistant-quick-menu-panel .mat-mdc-menu-item:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:-2px}:host ::ng-deep .assistant-quick-menu-panel .assistant-quick-menu-danger{color:var(--md-sys-color-error)}:host ::ng-deep .assistant-quick-menu-panel .assistant-quick-menu-danger .mat-icon{color:var(--md-sys-color-error)}@media(max-width:959px){::ng-deep .ai-assistant-overlay-pane{top:12px!important;left:12px!important;width:calc(100vw - 24px)!important;height:calc(100vh - 24px)!important;max-width:calc(100vw - 24px);max-height:calc(100vh - 24px);transform:none!important}.ai-assistant-panel{width:calc(100vw - 48px);min-height:min(620px,100vh - 48px);max-height:calc(100vh - 48px)}.assistant-section,.assistant-card{margin:0}.assistant-card,.assistant-section{padding:12px}}.ai-trigger-btn{--mdc-icon-button-state-layer-size: 36px;width:36px;height:36px;border-radius:8px;background:color-mix(in srgb,var(--md-sys-color-primary) 9%,transparent);border:1px solid color-mix(in srgb,var(--md-sys-color-primary) 22%,transparent);color:var(--md-sys-color-primary);opacity:1}.ai-trigger-btn:hover:not(:disabled){background:color-mix(in srgb,var(--md-sys-color-primary) 16%,transparent);border-color:color-mix(in srgb,var(--md-sys-color-primary) 36%,transparent);color:var(--md-sys-color-on-primary-container)}.ai-trigger-btn:focus-visible,.assistant-close-btn:focus-visible,.assistant-tab:focus-visible{outline:2px solid var(--md-sys-color-primary);outline-offset:2px}.assistant-close-btn{width:28px;height:28px;color:var(--md-sys-color-on-surface-variant)}.assistant-close-btn:hover:not(:disabled){background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface)}.assistant-body{padding:12px 16px;overflow:hidden;min-height:0;flex:1;display:flex;flex-direction:column;gap:12px}.assistant-body>*{min-height:0}@media(max-width:959px){.assistant-nav{padding:8px 12px 0}.assistant-body,.assistant-footer{padding:10px 12px}.suggestions-content .suggestion-item{grid-template-columns:1fr;align-items:start}.suggestion-actions{justify-content:flex-start}}\n"] }]
|
|
6611
6689
|
}], propDecorators: { adapter: [{
|
|
6612
6690
|
type: Input,
|
|
6613
6691
|
args: [{ required: true }]
|
|
@@ -6615,6 +6693,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
6615
6693
|
type: Input
|
|
6616
6694
|
}], allowManualPatchEdit: [{
|
|
6617
6695
|
type: Input
|
|
6696
|
+
}], hasBackdrop: [{
|
|
6697
|
+
type: Input
|
|
6618
6698
|
}], overlayOrigin: [{
|
|
6619
6699
|
type: ViewChild,
|
|
6620
6700
|
args: [CdkOverlayOrigin]
|
|
@@ -6689,8 +6769,8 @@ class PraxisAiAssistantShellComponent {
|
|
|
6689
6769
|
canSubmit = true;
|
|
6690
6770
|
canApply = false;
|
|
6691
6771
|
submitOnEnter = true;
|
|
6692
|
-
showAttachAction =
|
|
6693
|
-
enablePastedAttachments =
|
|
6772
|
+
showAttachAction = false;
|
|
6773
|
+
enablePastedAttachments = false;
|
|
6694
6774
|
enableFileAttachments = false;
|
|
6695
6775
|
attachmentAccept = '';
|
|
6696
6776
|
attachmentMultiple = true;
|
|
@@ -7082,6 +7162,11 @@ class PraxisAiAssistantShellComponent {
|
|
|
7082
7162
|
|| this.getQuickReplyPresentationItems(reply).length
|
|
7083
7163
|
|| this.getQuickReplyContextChips(reply).length);
|
|
7084
7164
|
}
|
|
7165
|
+
shouldUseInlineQuickReplies() {
|
|
7166
|
+
if (!this.quickReplies.length)
|
|
7167
|
+
return false;
|
|
7168
|
+
return this.quickReplies.every((reply) => this.isGuidedActionQuickReply(reply) && !this.isRichQuickReply(reply));
|
|
7169
|
+
}
|
|
7085
7170
|
getQuickReplyDescription(reply) {
|
|
7086
7171
|
const authored = this.quickReplyPresentation(reply)?.description?.trim();
|
|
7087
7172
|
if (authored)
|
|
@@ -7515,7 +7600,7 @@ class PraxisAiAssistantShellComponent {
|
|
|
7515
7600
|
}
|
|
7516
7601
|
getCloseIcon() {
|
|
7517
7602
|
const label = this.resolvedLabels.close.toLocaleLowerCase('pt-BR');
|
|
7518
|
-
return label.includes('minimiz') ? '
|
|
7603
|
+
return label.includes('minimiz') ? 'horizontal_rule' : 'close';
|
|
7519
7604
|
}
|
|
7520
7605
|
normalizeShellAction(action, fallback) {
|
|
7521
7606
|
const source = action ?? fallback;
|
|
@@ -7820,7 +7905,7 @@ class PraxisAiAssistantShellComponent {
|
|
|
7820
7905
|
this.ownedPreviewUrls.delete(previewUrl);
|
|
7821
7906
|
}
|
|
7822
7907
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisAiAssistantShellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
7823
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: PraxisAiAssistantShellComponent, isStandalone: true, selector: "praxis-ai-assistant-shell", inputs: { labels: "labels", mode: "mode", state: "state", contextItems: "contextItems", attachments: "attachments", messages: "messages", quickReplies: "quickReplies", prompt: "prompt", statusText: "statusText", errorText: "errorText", testIdPrefix: "testIdPrefix", panelTestId: "panelTestId", submitTestId: "submitTestId", applyTestId: "applyTestId", primaryAction: "primaryAction", secondaryActions: "secondaryActions", governanceActions: "governanceActions", busy: "busy", canSubmit: "canSubmit", canApply: "canApply", submitOnEnter: "submitOnEnter", showAttachAction: "showAttachAction", enablePastedAttachments: "enablePastedAttachments", enableFileAttachments: "enableFileAttachments", attachmentAccept: "attachmentAccept", attachmentMultiple: "attachmentMultiple", draggable: "draggable", resizable: "resizable", minWidth: "minWidth", minHeight: "minHeight", margin: "margin", layout: "layout" }, outputs: { promptChange: "promptChange", submitPrompt: "submitPrompt", apply: "apply", retryTurn: "retryTurn", cancelTurn: "cancelTurn", shellAction: "shellAction", close: "close", attach: "attach", attachmentsPasted: "attachmentsPasted", attachmentsSelected: "attachmentsSelected", removeAttachment: "removeAttachment", messageAction: "messageAction", editMessage: "editMessage", resendMessage: "resendMessage", quickReply: "quickReply", layoutChange: "layoutChange" }, viewQueries: [{ propertyName: "panel", first: true, predicate: ["panel"], descendants: true, static: true }, { propertyName: "conversation", first: true, predicate: ["conversation"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<section\n #panel\n class=\"praxis-ai-assistant-shell\"\n role=\"dialog\"\n [attr.aria-label]=\"resolvedLabels.title\"\n [attr.aria-busy]=\"busy ? 'true' : null\"\n [style.left.px]=\"currentLayout.left\"\n [style.top.px]=\"currentLayout.top\"\n [style.width.px]=\"currentLayout.width\"\n [style.height.px]=\"currentLayout.height\"\n [attr.data-testid]=\"panelTestId || testIdPrefix\"\n>\n <header\n class=\"praxis-ai-assistant-shell__header\"\n [attr.data-testid]=\"testIdPrefix + '-drag-handle'\"\n [attr.aria-label]=\"resolvedLabels.dragHandleAria\"\n (pointerdown)=\"startDrag($event)\"\n >\n <div class=\"praxis-ai-assistant-shell__identity\" aria-hidden=\"true\">\n <mat-icon>auto_awesome</mat-icon>\n </div>\n <div class=\"praxis-ai-assistant-shell__title-group\">\n <div class=\"praxis-ai-assistant-shell__title-row\">\n <strong>{{ resolvedLabels.title }}</strong>\n <div class=\"praxis-ai-assistant-shell__badges\" aria-hidden=\"true\">\n <span class=\"praxis-ai-assistant-shell__badge praxis-ai-assistant-shell__badge--context\">\n {{ getModeLabel() }}\n </span>\n <span\n class=\"praxis-ai-assistant-shell__badge praxis-ai-assistant-shell__badge--state\"\n [class.praxis-ai-assistant-shell__badge--error]=\"state === 'error'\"\n >\n <span class=\"praxis-ai-assistant-shell__state-dot\" aria-hidden=\"true\"></span>\n {{ getStateLabel() }}\n </span>\n </div>\n </div>\n <p *ngIf=\"resolvedLabels.subtitle\">{{ resolvedLabels.subtitle }}</p>\n </div>\n <div class=\"praxis-ai-assistant-shell__header-actions\">\n <button\n mat-icon-button\n type=\"button\"\n [matTooltip]=\"resolvedLabels.close\"\n [attr.aria-label]=\"resolvedLabels.close\"\n (pointerdown)=\"$event.stopPropagation()\"\n (click)=\"close.emit()\"\n [attr.data-testid]=\"testIdPrefix + '-close'\"\n >\n <mat-icon>{{ getCloseIcon() }}</mat-icon>\n </button>\n </div>\n </header>\n\n <div class=\"praxis-ai-assistant-shell__body\">\n <div\n *ngIf=\"contextItems.length\"\n class=\"praxis-ai-assistant-shell__context\"\n [attr.aria-label]=\"resolvedLabels.contextAria\"\n [attr.data-testid]=\"testIdPrefix + '-context'\"\n >\n <span\n *ngFor=\"let item of contextItems; trackBy: trackContextItem\"\n class=\"praxis-ai-assistant-shell__context-item\"\n [attr.data-testid]=\"testIdPrefix + '-context-' + item.id\"\n >\n <mat-icon *ngIf=\"item.icon\" aria-hidden=\"true\">{{ item.icon }}</mat-icon>\n <span class=\"praxis-ai-assistant-shell__context-label\">{{ item.label }}</span>\n <span *ngIf=\"item.value\" class=\"praxis-ai-assistant-shell__context-value\">{{ item.value }}</span>\n </span>\n </div>\n\n <div\n #conversation\n class=\"praxis-ai-assistant-shell__conversation\"\n [attr.data-testid]=\"testIdPrefix + '-conversation'\"\n [attr.aria-label]=\"resolvedLabels.conversationAria\"\n >\n <article\n *ngIf=\"!messages.length\"\n class=\"praxis-ai-assistant-shell__message praxis-ai-assistant-shell__message--assistant\"\n [attr.data-testid]=\"testIdPrefix + '-message-assistant-empty'\"\n >\n {{ resolvedLabels.emptyConversation }}\n </article>\n <article\n *ngFor=\"let message of messages; trackBy: trackMessage\"\n class=\"praxis-ai-assistant-shell__message\"\n [class.praxis-ai-assistant-shell__message--user]=\"message.role === 'user'\"\n [class.praxis-ai-assistant-shell__message--assistant]=\"message.role === 'assistant'\"\n [class.praxis-ai-assistant-shell__message--status]=\"message.role === 'status'\"\n [class.praxis-ai-assistant-shell__message--error]=\"message.role === 'error'\"\n [attr.data-testid]=\"testIdPrefix + '-message-' + message.role\"\n >\n <div\n class=\"praxis-ai-assistant-shell__message-content\"\n [innerHTML]=\"renderMessageText(message.text)\"\n ></div>\n <div\n *ngIf=\"message.actions?.length || message.editable || message.resendable\"\n class=\"praxis-ai-assistant-shell__message-actions\"\n >\n <button\n *ngIf=\"message.editable\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.editMessage\"\n [attr.aria-label]=\"resolvedLabels.editMessage\"\n [attr.data-testid]=\"testIdPrefix + '-message-edit-' + message.id\"\n (click)=\"onMessageAction(message, { id: 'edit', label: resolvedLabels.editMessage, kind: 'edit' })\"\n >\n <mat-icon aria-hidden=\"true\">edit</mat-icon>\n </button>\n <button\n *ngIf=\"message.resendable\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.resendMessage\"\n [attr.aria-label]=\"resolvedLabels.resendMessage\"\n [attr.data-testid]=\"testIdPrefix + '-message-resend-' + message.id\"\n (click)=\"onMessageAction(message, { id: 'resend', label: resolvedLabels.resendMessage, kind: 'resend' })\"\n >\n <mat-icon aria-hidden=\"true\">replay</mat-icon>\n </button>\n <ng-container *ngFor=\"let action of message.actions || []; trackBy: trackMessageAction\">\n <button\n *ngIf=\"isMessageActionIconOnly(action); else textualMessageAction\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy || action.disabled\"\n [matTooltip]=\"getMessageActionLabel(action)\"\n [attr.aria-label]=\"getMessageActionLabel(action)\"\n [attr.data-testid]=\"testIdPrefix + '-message-action-' + message.id + '-' + action.id\"\n (click)=\"onMessageAction(message, action)\"\n >\n <mat-icon aria-hidden=\"true\">{{ getMessageActionIcon(action) }}</mat-icon>\n </button>\n <ng-template #textualMessageAction>\n <button\n mat-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action\"\n [disabled]=\"busy || action.disabled\"\n [attr.aria-label]=\"getMessageActionLabel(action)\"\n [attr.data-testid]=\"testIdPrefix + '-message-action-' + message.id + '-' + action.id\"\n (click)=\"onMessageAction(message, action)\"\n >\n {{ action.label }}\n </button>\n </ng-template>\n </ng-container>\n </div>\n </article>\n </div>\n\n <div\n *ngIf=\"attachments.length\"\n class=\"praxis-ai-assistant-shell__attachments\"\n [attr.aria-label]=\"resolvedLabels.attachmentsAria\"\n [attr.data-testid]=\"testIdPrefix + '-attachments'\"\n >\n <div\n *ngFor=\"let attachment of attachments; trackBy: trackAttachment\"\n class=\"praxis-ai-assistant-shell__attachment\"\n [class.praxis-ai-assistant-shell__attachment--error]=\"attachment.status === 'error'\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-' + attachment.id\"\n >\n <img\n *ngIf=\"attachment.previewUrl && attachment.kind === 'image'\"\n class=\"praxis-ai-assistant-shell__attachment-preview\"\n [src]=\"attachment.previewUrl\"\n [alt]=\"attachment.name\"\n >\n <span class=\"praxis-ai-assistant-shell__attachment-name\">{{ attachment.name }}</span>\n <span class=\"praxis-ai-assistant-shell__attachment-kind\">{{ attachment.kind }}</span>\n <button\n mat-icon-button\n type=\"button\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.removeAttachment\"\n [attr.aria-label]=\"resolvedLabels.removeAttachment + ': ' + attachment.name\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-remove-' + attachment.id\"\n (click)=\"onRemoveAttachment(attachment)\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n\n <div\n *ngIf=\"quickReplies.length\"\n class=\"praxis-ai-assistant-shell__quick-replies\"\n [attr.data-testid]=\"testIdPrefix + '-quick-replies'\"\n [attr.aria-label]=\"resolvedLabels.quickRepliesAria\"\n >\n <button\n *ngFor=\"let reply of quickReplies; trackBy: trackQuickReply\"\n mat-stroked-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__quick-reply\"\n [class.praxis-ai-assistant-shell__quick-reply--compact]=\"!isRichQuickReply(reply)\"\n [class.praxis-ai-assistant-shell__quick-reply--guided-action]=\"isGuidedActionQuickReply(reply)\"\n [class.praxis-ai-assistant-shell__quick-reply--contextual-action]=\"isContextualPreviewActionQuickReply(reply)\"\n [ngClass]=\"'praxis-ai-assistant-shell__quick-reply--tone-' + getQuickReplyTone(reply)\"\n [attr.data-testid]=\"testIdPrefix + '-quick-reply-' + (reply.id || reply.kind)\"\n [attr.aria-label]=\"getQuickReplyAriaLabel(reply)\"\n [disabled]=\"busy\"\n (click)=\"onQuickReply(reply)\"\n >\n <span class=\"praxis-ai-assistant-shell__quick-reply-ambient\" aria-hidden=\"true\"></span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-icon-frame\" aria-hidden=\"true\">\n <mat-icon\n class=\"praxis-ai-assistant-shell__quick-reply-icon\"\n >\n {{ getQuickReplyIcon(reply) }}\n </mat-icon>\n </span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-copy\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-header\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-heading\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-label\">{{ reply.label }}</span>\n <span\n *ngIf=\"getQuickReplyDescription(reply)\"\n class=\"praxis-ai-assistant-shell__quick-reply-description\"\n >\n {{ getQuickReplyDescription(reply) }}\n </span>\n </span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-actions\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-badge\">\n {{ getQuickReplyCategoryLabel(reply) }}\n </span>\n <mat-icon\n *ngIf=\"getQuickReplyTechnicalDetails(reply)\"\n class=\"praxis-ai-assistant-shell__quick-reply-details\"\n [matTooltip]=\"getQuickReplyTechnicalDetails(reply)\"\n [attr.aria-label]=\"resolvedLabels.quickReplyDetails\"\n >\n info\n </mat-icon>\n </span>\n </span>\n <span\n *ngIf=\"getQuickReplyContextChips(reply).length\"\n class=\"praxis-ai-assistant-shell__quick-reply-context\"\n >\n <span\n *ngFor=\"let chip of getQuickReplyContextChips(reply)\"\n class=\"praxis-ai-assistant-shell__quick-reply-context-chip\"\n [attr.aria-label]=\"chip.ariaLabel\"\n >\n <mat-icon aria-hidden=\"true\">{{ chip.icon }}</mat-icon>\n <span>{{ chip.value }}</span>\n </span>\n </span>\n <span\n *ngIf=\"getQuickReplyPresentationItems(reply).length\"\n class=\"praxis-ai-assistant-shell__quick-reply-insights\"\n >\n <span\n *ngFor=\"let item of getQuickReplyPresentationItems(reply)\"\n class=\"praxis-ai-assistant-shell__quick-reply-insight\"\n >\n <mat-icon aria-hidden=\"true\">{{ item.icon }}</mat-icon>\n <span class=\"praxis-ai-assistant-shell__quick-reply-insight-copy\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-insight-label\">\n {{ item.label }}\n </span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-insight-value\">\n {{ item.value }}\n </span>\n </span>\n </span>\n </span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-cta\">\n {{ getQuickReplyCtaLabel(reply) }}\n <mat-icon aria-hidden=\"true\">arrow_forward</mat-icon>\n </span>\n </span>\n </button>\n </div>\n <p\n *ngIf=\"shouldShowStatusText()\"\n class=\"praxis-ai-assistant-shell__status\"\n [attr.data-testid]=\"testIdPrefix + '-status'\"\n >\n {{ statusText }}\n </p>\n <p\n *ngIf=\"shouldShowErrorText()\"\n class=\"praxis-ai-assistant-shell__error\"\n [attr.data-testid]=\"testIdPrefix + '-error'\"\n >\n {{ errorText }}\n </p>\n </div>\n\n <footer class=\"praxis-ai-assistant-shell__footer\">\n <label class=\"praxis-ai-assistant-shell__label\" for=\"praxis-ai-assistant-shell-prompt\">\n {{ resolvedLabels.prompt }}\n </label>\n <div class=\"praxis-ai-assistant-shell__composer\">\n <textarea\n id=\"praxis-ai-assistant-shell-prompt\"\n class=\"praxis-ai-assistant-shell__prompt\"\n [attr.data-testid]=\"testIdPrefix + '-prompt'\"\n [placeholder]=\"resolvedLabels.promptPlaceholder\"\n [ngModel]=\"currentPrompt\"\n [disabled]=\"busy\"\n (ngModelChange)=\"onPromptInput($event)\"\n (keydown)=\"onPromptKeydown($event)\"\n (paste)=\"onPromptPaste($event)\"\n ></textarea>\n <div class=\"praxis-ai-assistant-shell__composer-actions\">\n <ng-container *ngIf=\"showAttachAction\">\n <input\n #attachmentInput\n type=\"file\"\n hidden\n [attr.accept]=\"attachmentAccept || null\"\n [attr.multiple]=\"attachmentMultiple ? '' : null\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-input'\"\n (change)=\"onAttachmentFilesSelected($event)\"\n >\n <button\n mat-stroked-button\n type=\"button\"\n [disabled]=\"busy\"\n (click)=\"onAttachClick(attachmentInput)\"\n [attr.data-testid]=\"testIdPrefix + '-attach'\"\n >\n <mat-icon>attach_file</mat-icon>\n {{ resolvedLabels.attach }}\n </button>\n </ng-container>\n <button\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n class=\"praxis-ai-assistant-shell__action praxis-ai-assistant-shell__action--primary\"\n [class.praxis-ai-assistant-shell__action--icon-only]=\"getPrimaryAction().iconOnly\"\n [matTooltip]=\"getPrimaryActionTooltip(getPrimaryAction())\"\n [ngClass]=\"'praxis-ai-assistant-shell__action--tone-' + getShellActionTone(getPrimaryAction())\"\n [disabled]=\"isShellActionDisabled(getPrimaryAction())\"\n (click)=\"onShellAction(getPrimaryAction())\"\n [attr.data-testid]=\"getPrimaryAction().testId || (submitTestId || (testIdPrefix + '-submit'))\"\n [attr.aria-label]=\"getPrimaryAction().ariaLabel || getPrimaryAction().label\"\n >\n <mat-icon *ngIf=\"getPrimaryAction().icon\" aria-hidden=\"true\">{{ getPrimaryAction().icon }}</mat-icon>\n <span *ngIf=\"!getPrimaryAction().iconOnly\">{{ getPrimaryAction().label }}</span>\n </button>\n <button\n *ngFor=\"let action of getSecondaryActions(); trackBy: trackShellAction\"\n mat-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__action praxis-ai-assistant-shell__action--secondary\"\n [ngClass]=\"'praxis-ai-assistant-shell__action--tone-' + getShellActionTone(action)\"\n [disabled]=\"isShellActionDisabled(action)\"\n (click)=\"onShellAction(action)\"\n [attr.data-testid]=\"action.testId || (testIdPrefix + '-action-' + action.id)\"\n [attr.aria-label]=\"action.ariaLabel || action.label\"\n >\n <mat-icon *ngIf=\"action.icon\" aria-hidden=\"true\">{{ action.icon }}</mat-icon>\n {{ action.label }}\n </button>\n <mat-spinner *ngIf=\"busy\" diameter=\"20\" [attr.data-testid]=\"testIdPrefix + '-spinner'\"></mat-spinner>\n </div>\n </div>\n </footer>\n\n <ng-container *ngIf=\"resizable\">\n <span\n *ngFor=\"let direction of resizeHandles; trackBy: trackResizeHandle\"\n class=\"praxis-ai-assistant-shell__resize-handle praxis-ai-assistant-shell__resize-handle--{{ direction }}\"\n [attr.data-testid]=\"direction === 'se' ? testIdPrefix + '-resize-handle' : testIdPrefix + '-resize-handle-' + direction\"\n aria-hidden=\"true\"\n role=\"presentation\"\n (pointerdown)=\"startResize(direction, $event)\"\n ></span>\n </ng-container>\n</section>\n", styles: [":host{display:block}.praxis-ai-assistant-shell{--praxis-ai-assistant-shell-shadow-color: var(--md-sys-color-shadow);--praxis-ai-assistant-shell-highlight-color: var(--md-sys-color-on-surface);--praxis-ai-assistant-shell-tone-analytics: var(--md-sys-color-primary);--praxis-ai-assistant-shell-tone-resource: var(--md-sys-color-tertiary);--praxis-ai-assistant-shell-tone-success: var(--md-sys-color-tertiary);--praxis-ai-assistant-shell-tone-warning: var(--md-sys-color-secondary);--praxis-ai-assistant-shell-tone-danger: var(--md-sys-color-error);--praxis-ai-assistant-shell-tone-neutral: var(--md-sys-color-outline);position:fixed;box-sizing:border-box;min-width:360px;min-height:360px;display:flex;flex-direction:column;overflow:hidden;color:var(--md-sys-color-on-surface);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface);box-shadow:0 24px 60px color-mix(in srgb,var(--praxis-ai-assistant-shell-shadow-color) 40%,transparent);z-index:var(--praxis-ai-assistant-shell-z-index, 1200)}.praxis-ai-assistant-shell__header{flex:0 0 auto;display:flex;align-items:flex-start;gap:9px;padding:10px 10px 9px;border-color:color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent);background:var(--md-sys-color-surface-container)}.praxis-ai-assistant-shell__header{justify-content:flex-start;border-bottom:1px solid;cursor:move;touch-action:none}.praxis-ai-assistant-shell__identity{flex:0 0 auto;display:grid;place-items:center;width:30px;height:30px;border-radius:8px;background:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary);box-shadow:0 6px 16px color-mix(in srgb,var(--md-sys-color-primary) 22%,transparent)}.praxis-ai-assistant-shell__identity mat-icon{width:18px;height:18px;font-size:18px}.praxis-ai-assistant-shell__title-group{min-width:0;flex:1 1 auto;display:grid;gap:4px}.praxis-ai-assistant-shell__title-row{min-width:0;display:flex;align-items:center;gap:8px}.praxis-ai-assistant-shell__badges{flex:0 0 auto;display:flex;align-items:center;justify-content:flex-end;gap:4px;min-width:0;flex-wrap:wrap}.praxis-ai-assistant-shell__badge{display:inline-flex;align-items:center;gap:5px;min-height:20px;max-width:120px;padding:2px 7px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 80%,transparent);border-radius:8px;color:var(--md-sys-color-on-surface-variant);background:var(--md-sys-color-surface-container-high);font-size:11px;line-height:1.2;overflow-wrap:anywhere}.praxis-ai-assistant-shell__badge--context{color:var(--md-sys-color-on-surface);background:color-mix(in srgb,var(--md-sys-color-primary) 9%,var(--md-sys-color-surface-container-high))}.praxis-ai-assistant-shell__badge--state{border-color:transparent;background:transparent;color:var(--md-sys-color-on-surface-variant);padding-inline:3px}.praxis-ai-assistant-shell__badge--error{color:var(--md-sys-color-error);border-color:color-mix(in srgb,var(--md-sys-color-error) 60%,transparent)}.praxis-ai-assistant-shell__state-dot{flex:0 0 auto;width:6px;height:6px;border-radius:999px;background:var(--md-sys-color-primary);box-shadow:0 0 0 2px color-mix(in srgb,var(--md-sys-color-primary) 16%,transparent)}.praxis-ai-assistant-shell__badge--error .praxis-ai-assistant-shell__state-dot{background:var(--md-sys-color-error);box-shadow:0 0 0 2px color-mix(in srgb,var(--md-sys-color-error) 16%,transparent)}.praxis-ai-assistant-shell__title-group strong,.praxis-ai-assistant-shell__title-group p{min-width:0;margin:0;overflow-wrap:anywhere}.praxis-ai-assistant-shell__title-group strong{flex:1 1 auto;font-size:13px;line-height:1.2}.praxis-ai-assistant-shell__title-group p{color:var(--md-sys-color-on-surface-variant);font-size:11.5px;line-height:1.3}.praxis-ai-assistant-shell__header-actions{flex:0 0 auto;display:flex;align-items:center;gap:2px;margin-top:-3px}.praxis-ai-assistant-shell__header-actions button{width:34px;height:34px;color:var(--md-sys-color-on-surface-variant);opacity:.78}.praxis-ai-assistant-shell__header-actions button:hover,.praxis-ai-assistant-shell__header-actions button:focus-visible{opacity:1}.praxis-ai-assistant-shell__header-actions mat-icon{width:18px;height:18px;font-size:18px}.praxis-ai-assistant-shell__body{min-height:0;flex:1 1 auto;display:flex;flex-direction:column;gap:10px;padding:12px 12px 10px;overflow:auto;background:linear-gradient(180deg,var(--md-sys-color-surface-container-low),var(--md-sys-color-surface))}.praxis-ai-assistant-shell__context,.praxis-ai-assistant-shell__attachments{flex:0 0 auto;display:flex;align-items:center;gap:8px;overflow-x:auto}.praxis-ai-assistant-shell__context-item{flex:0 0 auto;display:inline-flex;align-items:center;gap:5px;max-width:240px;padding:5px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface-container-high);font-size:12px;line-height:1.25}.praxis-ai-assistant-shell__context-item mat-icon{width:16px;height:16px;font-size:16px}.praxis-ai-assistant-shell__context-label,.praxis-ai-assistant-shell__context-value{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.praxis-ai-assistant-shell__context-label{color:var(--md-sys-color-on-surface)}.praxis-ai-assistant-shell__context-value{color:var(--md-sys-color-on-surface-variant)}.praxis-ai-assistant-shell__label{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.praxis-ai-assistant-shell__prompt{box-sizing:border-box;width:100%;min-height:46px;max-height:96px;resize:none;border:0;padding:10px 12px 8px;color:var(--md-sys-color-on-surface);background:transparent;font:inherit;line-height:1.45;outline:none}.praxis-ai-assistant-shell__conversation{min-height:0;flex:1 1 auto;display:flex;flex-direction:column;gap:8px;overflow:auto;padding:2px}.praxis-ai-assistant-shell__message{max-width:86%;align-self:flex-start;padding:9px 11px;border-radius:8px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface);font-size:13px;line-height:1.35;overflow-wrap:anywhere}.praxis-ai-assistant-shell__message-content{white-space:normal}.praxis-ai-assistant-shell__message-content :where(p,ul,h3,h4,h5){margin:0}.praxis-ai-assistant-shell__message-content :where(p,ul,h3,h4,h5)+:where(p,ul,h3,h4,h5){margin-top:8px}.praxis-ai-assistant-shell__message-content ul{padding-left:18px}.praxis-ai-assistant-shell__message-content li+li{margin-top:4px}.praxis-ai-assistant-shell__message-content code{padding:1px 4px;border-radius:4px;background:color-mix(in srgb,var(--md-sys-color-on-surface) 10%,transparent);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.94em}.praxis-ai-assistant-shell__message-actions{display:flex;align-items:center;gap:4px;flex-wrap:wrap;margin-top:8px}.praxis-ai-assistant-shell__message-action{min-height:28px;padding:0 8px;border-radius:8px;font-size:12px}.praxis-ai-assistant-shell__message-action--icon{width:30px;min-width:30px;height:30px;padding:0;color:var(--md-sys-color-on-surface-variant)}.praxis-ai-assistant-shell__message-action--icon mat-icon{width:17px;height:17px;font-size:17px}.praxis-ai-assistant-shell__message--assistant{border-bottom-left-radius:2px}.praxis-ai-assistant-shell__message--user{align-self:flex-end;border-bottom-right-radius:2px;background:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container)}.praxis-ai-assistant-shell__message--status{color:var(--md-sys-color-on-surface-variant)}.praxis-ai-assistant-shell__message--error,.praxis-ai-assistant-shell__error{color:var(--md-sys-color-error)}.praxis-ai-assistant-shell__quick-replies{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,520px),1fr));gap:8px;align-items:stretch;padding-bottom:4px}.praxis-ai-assistant-shell__attachment{flex:0 0 auto;display:inline-flex;align-items:center;gap:7px;max-width:260px;min-height:34px;padding:4px 4px 4px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface-container-high)}.praxis-ai-assistant-shell__attachment--error{border-color:color-mix(in srgb,var(--md-sys-color-error) 60%,transparent)}.praxis-ai-assistant-shell__attachment-preview{flex:0 0 auto;width:28px;height:28px;border-radius:6px;object-fit:cover}.praxis-ai-assistant-shell__attachment-name,.praxis-ai-assistant-shell__attachment-kind{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px}.praxis-ai-assistant-shell__attachment-name{color:var(--md-sys-color-on-surface)}.praxis-ai-assistant-shell__attachment-kind{color:var(--md-sys-color-on-surface-variant)}.praxis-ai-assistant-shell__quick-reply{--praxis-ai-assistant-shell-quick-reply-accent: var(--md-sys-color-primary);--praxis-ai-assistant-shell-quick-reply-background: color-mix( in srgb, var(--praxis-ai-assistant-shell-quick-reply-accent) 7%, var(--md-sys-color-surface-container-high) );--praxis-ai-assistant-shell-quick-reply-foreground: var(--md-sys-color-on-surface);width:100%;max-width:100%;height:auto;min-height:0;position:relative;overflow:hidden;padding:15px 16px;align-items:stretch;border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 36%,transparent);border-radius:22px;color:var(--praxis-ai-assistant-shell-quick-reply-foreground);background:linear-gradient(135deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 16%,transparent),transparent 46%),radial-gradient(circle at 92% 10%,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 22%,transparent),transparent 32%),var(--praxis-ai-assistant-shell-quick-reply-background);box-shadow:0 18px 42px color-mix(in srgb,var(--praxis-ai-assistant-shell-shadow-color) 22%,transparent),inset 0 1px color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 16%,transparent);letter-spacing:normal;white-space:normal;text-align:left;text-transform:none;-webkit-user-select:none;user-select:none;transition:border-color .16s ease,box-shadow .16s ease,transform .16s ease,background .16s ease;--mdc-outlined-button-container-height: auto;--mat-outlined-button-horizontal-padding: 0}.praxis-ai-assistant-shell__quick-reply:hover:not(:disabled),.praxis-ai-assistant-shell__quick-reply:focus-visible{border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 74%,transparent);box-shadow:0 18px 42px color-mix(in srgb,var(--praxis-ai-assistant-shell-shadow-color) 24%,transparent),0 0 0 3px color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 18%,transparent),inset 0 1px color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 18%,transparent);transform:translateY(-1px)}.praxis-ai-assistant-shell__quick-reply--contextual-action{padding:10px 12px;border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 34%,transparent);border-radius:8px;background:linear-gradient(90deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 15%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-high) 92%,transparent)),var(--md-sys-color-surface-container-high);box-shadow:none}.praxis-ai-assistant-shell__quick-reply--guided-action{padding:10px 12px;border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 30%,transparent);border-radius:8px;background:linear-gradient(90deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 10%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-high) 96%,transparent)),var(--md-sys-color-surface-container-high);box-shadow:none}.praxis-ai-assistant-shell__quick-reply--contextual-action:hover:not(:disabled),.praxis-ai-assistant-shell__quick-reply--contextual-action:focus-visible,.praxis-ai-assistant-shell__quick-reply--guided-action:hover:not(:disabled),.praxis-ai-assistant-shell__quick-reply--guided-action:focus-visible{border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 62%,transparent);box-shadow:0 0 0 2px color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 15%,transparent);transform:none}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-ambient,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-ambient{display:none}.praxis-ai-assistant-shell__quick-reply--contextual-action ::ng-deep .mdc-button__label,.praxis-ai-assistant-shell__quick-reply--guided-action ::ng-deep .mdc-button__label{gap:10px}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-icon-frame,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-icon-frame{width:34px;height:34px;border-radius:8px;box-shadow:none}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-icon,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-icon{width:19px;height:19px;font-size:19px}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-copy,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-copy{gap:6px}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-label,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-label{font-size:13.5px;font-weight:760;letter-spacing:0}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-description,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-description{display:-webkit-box;overflow:hidden;font-size:12px;line-height:1.34;-webkit-box-orient:vertical;-webkit-line-clamp:2}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-badge,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-badge{border-radius:8px;font-size:10px;letter-spacing:0}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-context-chip{border-radius:8px;padding:4px 7px;font-size:10.5px;font-weight:650}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-cta,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-cta{font-size:11.5px}.praxis-ai-assistant-shell__quick-reply--compact{justify-self:start;width:fit-content;min-width:min(100%,210px);max-width:min(100%,320px);padding:9px 11px;border-radius:16px;background:linear-gradient(135deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 10%,transparent),transparent 55%),var(--md-sys-color-surface-container-high);box-shadow:0 8px 18px color-mix(in srgb,var(--praxis-ai-assistant-shell-shadow-color) 16%,transparent),inset 0 1px color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 10%,transparent)}.praxis-ai-assistant-shell__quick-reply.praxis-ai-assistant-shell__quick-reply--compact ::ng-deep .mdc-button__label{align-items:center;gap:10px}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-icon-frame{width:34px;height:34px;border-radius:12px}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-icon{width:19px;height:19px;font-size:19px}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-copy{gap:4px}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-header{align-items:center}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-label{font-size:13px;line-height:1.2}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-badge,.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-cta{display:none}.praxis-ai-assistant-shell__quick-reply ::ng-deep .mdc-button__label{position:relative;z-index:1;min-width:0;display:grid;grid-template-columns:auto minmax(0,1fr);align-items:flex-start;gap:14px;width:100%;height:auto;line-height:normal}.praxis-ai-assistant-shell__quick-reply-ambient{position:absolute;inset:0;pointer-events:none}.praxis-ai-assistant-shell__quick-reply-ambient:before{content:\"\";position:absolute;inset:0 18px auto;height:1px;border-radius:999px;background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 90%,var(--praxis-ai-assistant-shell-highlight-color)),transparent);opacity:.58}.praxis-ai-assistant-shell__quick-reply-ambient:after{content:\"\";position:absolute;top:-34px;right:-44px;width:150px;height:150px;border-radius:999px;background:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 13%,transparent);filter:blur(18px)}.praxis-ai-assistant-shell__quick-reply ::ng-deep .mat-mdc-button-touch-target{height:100%;min-height:48px}.praxis-ai-assistant-shell__quick-reply-icon-frame{flex:0 0 auto;width:46px;height:46px;display:inline-grid;place-items:center;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 34%,transparent);border-radius:17px;color:var(--praxis-ai-assistant-shell-quick-reply-accent);background:linear-gradient(145deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 24%,transparent),color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 6%,transparent));box-shadow:inset 0 1px color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 18%,transparent),0 10px 24px color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 12%,transparent)}.praxis-ai-assistant-shell__quick-reply-icon{width:24px;height:24px;font-size:24px}.praxis-ai-assistant-shell__quick-reply-details{flex:0 0 auto;width:24px;height:24px;display:inline-grid;place-items:center;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 14%,transparent);border-radius:50%;color:var(--md-sys-color-on-surface-variant);background:color-mix(in srgb,var(--md-sys-color-outline) 14%,transparent);font-size:17px;opacity:.9}.praxis-ai-assistant-shell__quick-reply-copy{min-width:0;display:grid;gap:10px;flex:1 1 auto}.praxis-ai-assistant-shell__quick-reply-header{min-width:0;display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.praxis-ai-assistant-shell__quick-reply-heading{min-width:0;display:grid;gap:5px}.praxis-ai-assistant-shell__quick-reply-actions{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:flex-end;gap:7px;max-width:46%}.praxis-ai-assistant-shell__quick-reply-label,.praxis-ai-assistant-shell__quick-reply-description{min-width:0;overflow-wrap:anywhere}.praxis-ai-assistant-shell__quick-reply-label{color:var(--md-sys-color-on-surface);font-size:17px;font-weight:760;letter-spacing:.005em;line-height:1.18;text-transform:none}.praxis-ai-assistant-shell__quick-reply-badge{flex:0 0 auto;max-width:100%;padding:4px 8px;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 28%,transparent);border-radius:999px;color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 86%,var(--praxis-ai-assistant-shell-highlight-color));background:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 11%,transparent);font-size:10.5px;font-weight:700;letter-spacing:.02em;line-height:1.1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.praxis-ai-assistant-shell__quick-reply-description{color:color-mix(in srgb,var(--md-sys-color-on-surface) 80%,transparent);font-size:13px;line-height:1.46}.praxis-ai-assistant-shell__quick-reply-context{display:flex;flex-wrap:wrap;gap:7px;align-items:center}.praxis-ai-assistant-shell__quick-reply-context-chip{min-width:0;display:inline-flex;align-items:center;gap:4px;max-width:100%;padding:5px 8px;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 22%,transparent);border-radius:999px;color:color-mix(in srgb,var(--md-sys-color-on-surface) 82%,transparent);background:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 9%,transparent);font-size:11px;font-weight:650;line-height:1.15}.praxis-ai-assistant-shell__quick-reply-context-chip mat-icon{width:14px;height:14px;color:var(--praxis-ai-assistant-shell-quick-reply-accent);font-size:14px}.praxis-ai-assistant-shell__quick-reply-context-chip span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.praxis-ai-assistant-shell__quick-reply-insights{display:grid;grid-template-columns:repeat(auto-fit,minmax(145px,1fr));gap:8px;padding:8px;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 16%,transparent);border-radius:16px;background:linear-gradient(180deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 5%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-lowest) 26%,transparent))}.praxis-ai-assistant-shell__quick-reply-insight{min-width:0;display:grid;grid-template-columns:20px minmax(0,1fr);gap:8px;align-items:start;padding:8px;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 10%,transparent);border-radius:13px;color:color-mix(in srgb,var(--md-sys-color-on-surface) 86%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container-high) 44%,transparent);font-size:12px;line-height:1.35}.praxis-ai-assistant-shell__quick-reply-insight mat-icon{width:17px;height:17px;color:var(--praxis-ai-assistant-shell-quick-reply-accent);font-size:17px;opacity:.9}.praxis-ai-assistant-shell__quick-reply-insight-copy{min-width:0;display:grid;gap:1px}.praxis-ai-assistant-shell__quick-reply-insight-label{color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 82%,var(--praxis-ai-assistant-shell-highlight-color));font-size:10.5px;font-weight:760;letter-spacing:.045em;line-height:1.2;text-transform:uppercase}.praxis-ai-assistant-shell__quick-reply-insight-value{min-width:0;overflow-wrap:anywhere}.praxis-ai-assistant-shell__quick-reply-cta{display:inline-flex;align-items:center;justify-self:start;gap:5px;padding:3px 0;color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 84%,var(--praxis-ai-assistant-shell-highlight-color));font-size:12px;font-weight:760;letter-spacing:.01em;line-height:1.2}.praxis-ai-assistant-shell__quick-reply-cta mat-icon{width:15px;height:15px;font-size:15px;transition:transform .16s ease}.praxis-ai-assistant-shell__quick-reply:hover:not(:disabled) .praxis-ai-assistant-shell__quick-reply-cta mat-icon,.praxis-ai-assistant-shell__quick-reply:focus-visible .praxis-ai-assistant-shell__quick-reply-cta mat-icon{transform:translate(2px)}.praxis-ai-assistant-shell__quick-reply--tone-analytics{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-analytics)}.praxis-ai-assistant-shell__quick-reply--tone-resource{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-resource)}.praxis-ai-assistant-shell__quick-reply--tone-warning{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-warning)}.praxis-ai-assistant-shell__quick-reply--tone-success{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-success)}.praxis-ai-assistant-shell__quick-reply--tone-danger{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-danger)}.praxis-ai-assistant-shell__quick-reply--tone-neutral{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-neutral)}@media(max-width:640px){.praxis-ai-assistant-shell__quick-reply{padding:13px;border-radius:19px}.praxis-ai-assistant-shell__quick-reply ::ng-deep .mdc-button__label{grid-template-columns:minmax(0,1fr);gap:10px}.praxis-ai-assistant-shell__quick-reply-icon-frame{width:38px;height:38px;border-radius:14px}.praxis-ai-assistant-shell__quick-reply-header{display:grid}.praxis-ai-assistant-shell__quick-reply-actions{justify-content:flex-start;max-width:100%}.praxis-ai-assistant-shell__quick-reply-insights{grid-template-columns:minmax(0,1fr)}}.praxis-ai-assistant-shell__status,.praxis-ai-assistant-shell__error{margin:0;font-size:13px;line-height:1.35;overflow-wrap:anywhere}.praxis-ai-assistant-shell__footer{flex:0 0 auto;padding:8px 10px 10px;border-top:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent);background:var(--md-sys-color-surface-container-low)}.praxis-ai-assistant-shell__composer{display:grid;gap:8px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-lowest);box-shadow:inset 0 1px color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 4%,transparent)}.praxis-ai-assistant-shell__composer:focus-within{border-color:var(--md-sys-color-primary);box-shadow:0 0 0 2px color-mix(in srgb,var(--md-sys-color-primary) 16%,transparent)}.praxis-ai-assistant-shell__composer-actions{display:flex;align-items:center;justify-content:flex-end;gap:8px;padding:0 8px 7px;flex-wrap:wrap}.praxis-ai-assistant-shell__action{min-height:36px;border-radius:10px;font-weight:650}.praxis-ai-assistant-shell__action mat-icon{width:18px;height:18px;margin-right:6px;font-size:18px}.praxis-ai-assistant-shell__action--icon-only{width:40px;min-width:40px;height:40px;padding-inline:0;border-radius:50%}.praxis-ai-assistant-shell__action--icon-only mat-icon{margin-right:0}.praxis-ai-assistant-shell__action--secondary{color:var(--md-sys-color-on-surface-variant)}.praxis-ai-assistant-shell__action--tone-governance{color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent)}.praxis-ai-assistant-shell__action--tone-success{color:var(--praxis-ai-assistant-shell-tone-success);background:color-mix(in srgb,var(--praxis-ai-assistant-shell-tone-success) 10%,transparent)}.praxis-ai-assistant-shell__action--tone-warning{color:var(--praxis-ai-assistant-shell-tone-warning);background:color-mix(in srgb,var(--praxis-ai-assistant-shell-tone-warning) 10%,transparent)}.praxis-ai-assistant-shell__action--tone-danger{color:var(--md-sys-color-error);background:color-mix(in srgb,var(--md-sys-color-error) 10%,transparent)}.praxis-ai-assistant-shell__resize-handle{position:absolute;z-index:2;border:0;background:transparent;touch-action:none}.praxis-ai-assistant-shell__resize-handle--n,.praxis-ai-assistant-shell__resize-handle--s{left:16px;right:16px;height:10px;cursor:ns-resize}.praxis-ai-assistant-shell__resize-handle--n{top:-5px}.praxis-ai-assistant-shell__resize-handle--s{bottom:-5px}.praxis-ai-assistant-shell__resize-handle--e,.praxis-ai-assistant-shell__resize-handle--w{top:16px;bottom:16px;width:10px;cursor:ew-resize}.praxis-ai-assistant-shell__resize-handle--e{right:-5px}.praxis-ai-assistant-shell__resize-handle--w{left:-5px}.praxis-ai-assistant-shell__resize-handle--ne,.praxis-ai-assistant-shell__resize-handle--nw,.praxis-ai-assistant-shell__resize-handle--se,.praxis-ai-assistant-shell__resize-handle--sw{width:22px;height:22px}.praxis-ai-assistant-shell__resize-handle--ne{top:-5px;right:-5px;cursor:nesw-resize}.praxis-ai-assistant-shell__resize-handle--nw{top:-5px;left:-5px;cursor:nwse-resize}.praxis-ai-assistant-shell__resize-handle--se{right:-5px;bottom:-5px;cursor:nwse-resize}.praxis-ai-assistant-shell__resize-handle--sw{bottom:-5px;left:-5px;cursor:nesw-resize}.praxis-ai-assistant-shell__resize-handle--se:after{content:\"\";position:absolute;right:8px;bottom:8px;width:10px;height:10px;border-right:2px solid var(--md-sys-color-outline);border-bottom:2px solid var(--md-sys-color-outline)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i8.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i9.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
7908
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.17", type: PraxisAiAssistantShellComponent, isStandalone: true, selector: "praxis-ai-assistant-shell", inputs: { labels: "labels", mode: "mode", state: "state", contextItems: "contextItems", attachments: "attachments", messages: "messages", quickReplies: "quickReplies", prompt: "prompt", statusText: "statusText", errorText: "errorText", testIdPrefix: "testIdPrefix", panelTestId: "panelTestId", submitTestId: "submitTestId", applyTestId: "applyTestId", primaryAction: "primaryAction", secondaryActions: "secondaryActions", governanceActions: "governanceActions", busy: "busy", canSubmit: "canSubmit", canApply: "canApply", submitOnEnter: "submitOnEnter", showAttachAction: "showAttachAction", enablePastedAttachments: "enablePastedAttachments", enableFileAttachments: "enableFileAttachments", attachmentAccept: "attachmentAccept", attachmentMultiple: "attachmentMultiple", draggable: "draggable", resizable: "resizable", minWidth: "minWidth", minHeight: "minHeight", margin: "margin", layout: "layout" }, outputs: { promptChange: "promptChange", submitPrompt: "submitPrompt", apply: "apply", retryTurn: "retryTurn", cancelTurn: "cancelTurn", shellAction: "shellAction", close: "close", attach: "attach", attachmentsPasted: "attachmentsPasted", attachmentsSelected: "attachmentsSelected", removeAttachment: "removeAttachment", messageAction: "messageAction", editMessage: "editMessage", resendMessage: "resendMessage", quickReply: "quickReply", layoutChange: "layoutChange" }, viewQueries: [{ propertyName: "panel", first: true, predicate: ["panel"], descendants: true, static: true }, { propertyName: "conversation", first: true, predicate: ["conversation"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<section\n #panel\n class=\"praxis-ai-assistant-shell\"\n role=\"dialog\"\n [attr.aria-label]=\"resolvedLabels.title\"\n [attr.aria-busy]=\"busy ? 'true' : null\"\n [style.left.px]=\"currentLayout.left\"\n [style.top.px]=\"currentLayout.top\"\n [style.width.px]=\"currentLayout.width\"\n [style.height.px]=\"currentLayout.height\"\n [attr.data-testid]=\"panelTestId || testIdPrefix\"\n>\n <header\n class=\"praxis-ai-assistant-shell__header\"\n [attr.data-testid]=\"testIdPrefix + '-drag-handle'\"\n [attr.aria-label]=\"resolvedLabels.dragHandleAria\"\n (pointerdown)=\"startDrag($event)\"\n >\n <div class=\"praxis-ai-assistant-shell__identity\" aria-hidden=\"true\">\n <mat-icon>auto_awesome</mat-icon>\n </div>\n <div class=\"praxis-ai-assistant-shell__title-group\">\n <div class=\"praxis-ai-assistant-shell__title-row\">\n <strong>{{ resolvedLabels.title }}</strong>\n <div class=\"praxis-ai-assistant-shell__badges\" aria-hidden=\"true\">\n <span class=\"praxis-ai-assistant-shell__badge praxis-ai-assistant-shell__badge--context\">\n {{ getModeLabel() }}\n </span>\n <span\n class=\"praxis-ai-assistant-shell__badge praxis-ai-assistant-shell__badge--state\"\n [class.praxis-ai-assistant-shell__badge--error]=\"state === 'error'\"\n >\n <span class=\"praxis-ai-assistant-shell__state-dot\" aria-hidden=\"true\"></span>\n {{ getStateLabel() }}\n </span>\n </div>\n </div>\n <p *ngIf=\"resolvedLabels.subtitle\">{{ resolvedLabels.subtitle }}</p>\n </div>\n <div class=\"praxis-ai-assistant-shell__header-actions\">\n <button\n mat-icon-button\n type=\"button\"\n [matTooltip]=\"resolvedLabels.close\"\n [attr.aria-label]=\"resolvedLabels.close\"\n (pointerdown)=\"$event.stopPropagation()\"\n (click)=\"close.emit()\"\n [attr.data-testid]=\"testIdPrefix + '-close'\"\n >\n <mat-icon>{{ getCloseIcon() }}</mat-icon>\n </button>\n </div>\n </header>\n\n <div class=\"praxis-ai-assistant-shell__body\">\n <div\n *ngIf=\"contextItems.length\"\n class=\"praxis-ai-assistant-shell__context\"\n [attr.aria-label]=\"resolvedLabels.contextAria\"\n [attr.data-testid]=\"testIdPrefix + '-context'\"\n >\n <span\n *ngFor=\"let item of contextItems; trackBy: trackContextItem\"\n class=\"praxis-ai-assistant-shell__context-item\"\n [attr.data-testid]=\"testIdPrefix + '-context-' + item.id\"\n >\n <mat-icon *ngIf=\"item.icon\" aria-hidden=\"true\">{{ item.icon }}</mat-icon>\n <span class=\"praxis-ai-assistant-shell__context-label\">{{ item.label }}</span>\n <span *ngIf=\"item.value\" class=\"praxis-ai-assistant-shell__context-value\">{{ item.value }}</span>\n </span>\n </div>\n\n <div\n #conversation\n class=\"praxis-ai-assistant-shell__conversation\"\n [attr.data-testid]=\"testIdPrefix + '-conversation'\"\n [attr.aria-label]=\"resolvedLabels.conversationAria\"\n >\n <article\n *ngIf=\"!messages.length\"\n class=\"praxis-ai-assistant-shell__message praxis-ai-assistant-shell__message--assistant\"\n [attr.data-testid]=\"testIdPrefix + '-message-assistant-empty'\"\n >\n {{ resolvedLabels.emptyConversation }}\n </article>\n <article\n *ngFor=\"let message of messages; trackBy: trackMessage\"\n class=\"praxis-ai-assistant-shell__message\"\n [class.praxis-ai-assistant-shell__message--user]=\"message.role === 'user'\"\n [class.praxis-ai-assistant-shell__message--assistant]=\"message.role === 'assistant'\"\n [class.praxis-ai-assistant-shell__message--status]=\"message.role === 'status'\"\n [class.praxis-ai-assistant-shell__message--error]=\"message.role === 'error'\"\n [attr.data-testid]=\"testIdPrefix + '-message-' + message.role\"\n >\n <div\n class=\"praxis-ai-assistant-shell__message-content\"\n [innerHTML]=\"renderMessageText(message.text)\"\n ></div>\n <div\n *ngIf=\"message.actions?.length || message.editable || message.resendable\"\n class=\"praxis-ai-assistant-shell__message-actions\"\n >\n <button\n *ngIf=\"message.editable\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.editMessage\"\n [attr.aria-label]=\"resolvedLabels.editMessage\"\n [attr.data-testid]=\"testIdPrefix + '-message-edit-' + message.id\"\n (click)=\"onMessageAction(message, { id: 'edit', label: resolvedLabels.editMessage, kind: 'edit' })\"\n >\n <mat-icon aria-hidden=\"true\">edit</mat-icon>\n </button>\n <button\n *ngIf=\"message.resendable\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.resendMessage\"\n [attr.aria-label]=\"resolvedLabels.resendMessage\"\n [attr.data-testid]=\"testIdPrefix + '-message-resend-' + message.id\"\n (click)=\"onMessageAction(message, { id: 'resend', label: resolvedLabels.resendMessage, kind: 'resend' })\"\n >\n <mat-icon aria-hidden=\"true\">replay</mat-icon>\n </button>\n <ng-container *ngFor=\"let action of message.actions || []; trackBy: trackMessageAction\">\n <button\n *ngIf=\"isMessageActionIconOnly(action); else textualMessageAction\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy || action.disabled\"\n [matTooltip]=\"getMessageActionLabel(action)\"\n [attr.aria-label]=\"getMessageActionLabel(action)\"\n [attr.data-testid]=\"testIdPrefix + '-message-action-' + message.id + '-' + action.id\"\n (click)=\"onMessageAction(message, action)\"\n >\n <mat-icon aria-hidden=\"true\">{{ getMessageActionIcon(action) }}</mat-icon>\n </button>\n <ng-template #textualMessageAction>\n <button\n mat-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action\"\n [disabled]=\"busy || action.disabled\"\n [attr.aria-label]=\"getMessageActionLabel(action)\"\n [attr.data-testid]=\"testIdPrefix + '-message-action-' + message.id + '-' + action.id\"\n (click)=\"onMessageAction(message, action)\"\n >\n {{ action.label }}\n </button>\n </ng-template>\n </ng-container>\n </div>\n </article>\n </div>\n\n <div\n *ngIf=\"attachments.length\"\n class=\"praxis-ai-assistant-shell__attachments\"\n [attr.aria-label]=\"resolvedLabels.attachmentsAria\"\n [attr.data-testid]=\"testIdPrefix + '-attachments'\"\n >\n <div\n *ngFor=\"let attachment of attachments; trackBy: trackAttachment\"\n class=\"praxis-ai-assistant-shell__attachment\"\n [class.praxis-ai-assistant-shell__attachment--error]=\"attachment.status === 'error'\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-' + attachment.id\"\n >\n <img\n *ngIf=\"attachment.previewUrl && attachment.kind === 'image'\"\n class=\"praxis-ai-assistant-shell__attachment-preview\"\n [src]=\"attachment.previewUrl\"\n [alt]=\"attachment.name\"\n >\n <span class=\"praxis-ai-assistant-shell__attachment-name\">{{ attachment.name }}</span>\n <span class=\"praxis-ai-assistant-shell__attachment-kind\">{{ attachment.kind }}</span>\n <button\n mat-icon-button\n type=\"button\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.removeAttachment\"\n [attr.aria-label]=\"resolvedLabels.removeAttachment + ': ' + attachment.name\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-remove-' + attachment.id\"\n (click)=\"onRemoveAttachment(attachment)\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n\n <div\n *ngIf=\"quickReplies.length\"\n class=\"praxis-ai-assistant-shell__quick-replies\"\n [class.praxis-ai-assistant-shell__quick-replies--inline]=\"shouldUseInlineQuickReplies()\"\n [attr.data-testid]=\"testIdPrefix + '-quick-replies'\"\n [attr.aria-label]=\"resolvedLabels.quickRepliesAria\"\n >\n <button\n *ngFor=\"let reply of quickReplies; trackBy: trackQuickReply\"\n mat-stroked-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__quick-reply\"\n [class.praxis-ai-assistant-shell__quick-reply--compact]=\"!isRichQuickReply(reply)\"\n [class.praxis-ai-assistant-shell__quick-reply--guided-action]=\"isGuidedActionQuickReply(reply)\"\n [class.praxis-ai-assistant-shell__quick-reply--contextual-action]=\"isContextualPreviewActionQuickReply(reply)\"\n [ngClass]=\"'praxis-ai-assistant-shell__quick-reply--tone-' + getQuickReplyTone(reply)\"\n [attr.data-testid]=\"testIdPrefix + '-quick-reply-' + (reply.id || reply.kind)\"\n [attr.aria-label]=\"getQuickReplyAriaLabel(reply)\"\n [disabled]=\"busy\"\n (click)=\"onQuickReply(reply)\"\n >\n <span class=\"praxis-ai-assistant-shell__quick-reply-ambient\" aria-hidden=\"true\"></span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-icon-frame\" aria-hidden=\"true\">\n <mat-icon\n class=\"praxis-ai-assistant-shell__quick-reply-icon\"\n >\n {{ getQuickReplyIcon(reply) }}\n </mat-icon>\n </span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-copy\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-header\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-heading\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-label\">{{ reply.label }}</span>\n <span\n *ngIf=\"getQuickReplyDescription(reply)\"\n class=\"praxis-ai-assistant-shell__quick-reply-description\"\n >\n {{ getQuickReplyDescription(reply) }}\n </span>\n </span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-actions\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-badge\">\n {{ getQuickReplyCategoryLabel(reply) }}\n </span>\n <mat-icon\n *ngIf=\"getQuickReplyTechnicalDetails(reply)\"\n class=\"praxis-ai-assistant-shell__quick-reply-details\"\n [matTooltip]=\"getQuickReplyTechnicalDetails(reply)\"\n [attr.aria-label]=\"resolvedLabels.quickReplyDetails\"\n >\n info\n </mat-icon>\n </span>\n </span>\n <span\n *ngIf=\"getQuickReplyContextChips(reply).length\"\n class=\"praxis-ai-assistant-shell__quick-reply-context\"\n >\n <span\n *ngFor=\"let chip of getQuickReplyContextChips(reply)\"\n class=\"praxis-ai-assistant-shell__quick-reply-context-chip\"\n [attr.aria-label]=\"chip.ariaLabel\"\n >\n <mat-icon aria-hidden=\"true\">{{ chip.icon }}</mat-icon>\n <span>{{ chip.value }}</span>\n </span>\n </span>\n <span\n *ngIf=\"getQuickReplyPresentationItems(reply).length\"\n class=\"praxis-ai-assistant-shell__quick-reply-insights\"\n >\n <span\n *ngFor=\"let item of getQuickReplyPresentationItems(reply)\"\n class=\"praxis-ai-assistant-shell__quick-reply-insight\"\n >\n <mat-icon aria-hidden=\"true\">{{ item.icon }}</mat-icon>\n <span class=\"praxis-ai-assistant-shell__quick-reply-insight-copy\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-insight-label\">\n {{ item.label }}\n </span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-insight-value\">\n {{ item.value }}\n </span>\n </span>\n </span>\n </span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-cta\">\n {{ getQuickReplyCtaLabel(reply) }}\n <mat-icon aria-hidden=\"true\">arrow_forward</mat-icon>\n </span>\n </span>\n </button>\n </div>\n <p\n *ngIf=\"shouldShowStatusText()\"\n class=\"praxis-ai-assistant-shell__status\"\n [attr.data-testid]=\"testIdPrefix + '-status'\"\n >\n {{ statusText }}\n </p>\n <p\n *ngIf=\"shouldShowErrorText()\"\n class=\"praxis-ai-assistant-shell__error\"\n [attr.data-testid]=\"testIdPrefix + '-error'\"\n >\n {{ errorText }}\n </p>\n </div>\n\n <footer class=\"praxis-ai-assistant-shell__footer\">\n <label class=\"praxis-ai-assistant-shell__label\" for=\"praxis-ai-assistant-shell-prompt\">\n {{ resolvedLabels.prompt }}\n </label>\n <div class=\"praxis-ai-assistant-shell__composer\">\n <textarea\n id=\"praxis-ai-assistant-shell-prompt\"\n class=\"praxis-ai-assistant-shell__prompt\"\n [attr.data-testid]=\"testIdPrefix + '-prompt'\"\n [placeholder]=\"resolvedLabels.promptPlaceholder\"\n [ngModel]=\"currentPrompt\"\n [disabled]=\"busy\"\n (ngModelChange)=\"onPromptInput($event)\"\n (keydown)=\"onPromptKeydown($event)\"\n (paste)=\"onPromptPaste($event)\"\n ></textarea>\n <div class=\"praxis-ai-assistant-shell__composer-actions\">\n <ng-container *ngIf=\"showAttachAction\">\n <input\n #attachmentInput\n type=\"file\"\n hidden\n [attr.accept]=\"attachmentAccept || null\"\n [attr.multiple]=\"attachmentMultiple ? '' : null\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-input'\"\n (change)=\"onAttachmentFilesSelected($event)\"\n >\n <button\n mat-stroked-button\n type=\"button\"\n [disabled]=\"busy\"\n (click)=\"onAttachClick(attachmentInput)\"\n [attr.data-testid]=\"testIdPrefix + '-attach'\"\n >\n <mat-icon>attach_file</mat-icon>\n {{ resolvedLabels.attach }}\n </button>\n </ng-container>\n <button\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n class=\"praxis-ai-assistant-shell__action praxis-ai-assistant-shell__action--primary\"\n [class.praxis-ai-assistant-shell__action--icon-only]=\"getPrimaryAction().iconOnly\"\n [matTooltip]=\"getPrimaryActionTooltip(getPrimaryAction())\"\n [ngClass]=\"'praxis-ai-assistant-shell__action--tone-' + getShellActionTone(getPrimaryAction())\"\n [disabled]=\"isShellActionDisabled(getPrimaryAction())\"\n (click)=\"onShellAction(getPrimaryAction())\"\n [attr.data-testid]=\"getPrimaryAction().testId || (submitTestId || (testIdPrefix + '-submit'))\"\n [attr.aria-label]=\"getPrimaryAction().ariaLabel || getPrimaryAction().label\"\n >\n <mat-icon *ngIf=\"getPrimaryAction().icon\" aria-hidden=\"true\">{{ getPrimaryAction().icon }}</mat-icon>\n <span *ngIf=\"!getPrimaryAction().iconOnly\">{{ getPrimaryAction().label }}</span>\n </button>\n <button\n *ngFor=\"let action of getSecondaryActions(); trackBy: trackShellAction\"\n mat-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__action praxis-ai-assistant-shell__action--secondary\"\n [ngClass]=\"'praxis-ai-assistant-shell__action--tone-' + getShellActionTone(action)\"\n [disabled]=\"isShellActionDisabled(action)\"\n (click)=\"onShellAction(action)\"\n [attr.data-testid]=\"action.testId || (testIdPrefix + '-action-' + action.id)\"\n [attr.aria-label]=\"action.ariaLabel || action.label\"\n >\n <mat-icon *ngIf=\"action.icon\" aria-hidden=\"true\">{{ action.icon }}</mat-icon>\n {{ action.label }}\n </button>\n <mat-spinner *ngIf=\"busy\" diameter=\"20\" [attr.data-testid]=\"testIdPrefix + '-spinner'\"></mat-spinner>\n </div>\n </div>\n </footer>\n\n <ng-container *ngIf=\"resizable\">\n <span\n *ngFor=\"let direction of resizeHandles; trackBy: trackResizeHandle\"\n class=\"praxis-ai-assistant-shell__resize-handle praxis-ai-assistant-shell__resize-handle--{{ direction }}\"\n [attr.data-testid]=\"direction === 'se' ? testIdPrefix + '-resize-handle' : testIdPrefix + '-resize-handle-' + direction\"\n aria-hidden=\"true\"\n role=\"presentation\"\n (pointerdown)=\"startResize(direction, $event)\"\n ></span>\n </ng-container>\n</section>\n", styles: [":host{display:block}.praxis-ai-assistant-shell{--praxis-ai-assistant-shell-shadow-color: var(--md-sys-color-shadow);--praxis-ai-assistant-shell-highlight-color: var(--md-sys-color-on-surface);--praxis-ai-assistant-shell-tone-analytics: var(--md-sys-color-primary);--praxis-ai-assistant-shell-tone-resource: var(--md-sys-color-tertiary);--praxis-ai-assistant-shell-tone-success: var(--md-sys-color-tertiary);--praxis-ai-assistant-shell-tone-warning: var(--md-sys-color-secondary);--praxis-ai-assistant-shell-tone-danger: var(--md-sys-color-error);--praxis-ai-assistant-shell-tone-neutral: var(--md-sys-color-outline);position:fixed;box-sizing:border-box;min-width:360px;min-height:360px;display:flex;flex-direction:column;overflow:hidden;color:var(--md-sys-color-on-surface);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface);box-shadow:0 24px 60px color-mix(in srgb,var(--praxis-ai-assistant-shell-shadow-color) 40%,transparent);z-index:var(--praxis-ai-assistant-shell-z-index, 1200)}.praxis-ai-assistant-shell__header{flex:0 0 auto;display:flex;align-items:flex-start;gap:9px;padding:10px 10px 9px;border-color:color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent);background:var(--md-sys-color-surface-container)}.praxis-ai-assistant-shell__header{justify-content:flex-start;border-bottom:1px solid;cursor:move;touch-action:none}.praxis-ai-assistant-shell__identity{flex:0 0 auto;display:grid;place-items:center;width:30px;height:30px;border-radius:8px;background:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary);box-shadow:0 6px 16px color-mix(in srgb,var(--md-sys-color-primary) 22%,transparent)}.praxis-ai-assistant-shell__identity mat-icon{width:18px;height:18px;font-size:18px}.praxis-ai-assistant-shell__title-group{min-width:0;flex:1 1 auto;display:grid;gap:4px}.praxis-ai-assistant-shell__title-row{min-width:0;display:flex;align-items:center;gap:8px}.praxis-ai-assistant-shell__badges{flex:0 0 auto;display:flex;align-items:center;justify-content:flex-end;gap:4px;min-width:0;flex-wrap:wrap}.praxis-ai-assistant-shell__badge{display:inline-flex;align-items:center;gap:5px;min-height:20px;max-width:120px;padding:2px 7px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 80%,transparent);border-radius:8px;color:var(--md-sys-color-on-surface-variant);background:var(--md-sys-color-surface-container-high);font-size:11px;line-height:1.2;overflow-wrap:anywhere}.praxis-ai-assistant-shell__badge--context{color:var(--md-sys-color-on-surface);background:color-mix(in srgb,var(--md-sys-color-primary) 9%,var(--md-sys-color-surface-container-high))}.praxis-ai-assistant-shell__badge--state{border-color:transparent;background:transparent;color:var(--md-sys-color-on-surface-variant);padding-inline:3px}.praxis-ai-assistant-shell__badge--error{color:var(--md-sys-color-error);border-color:color-mix(in srgb,var(--md-sys-color-error) 60%,transparent)}.praxis-ai-assistant-shell__state-dot{flex:0 0 auto;width:6px;height:6px;border-radius:999px;background:var(--md-sys-color-primary);box-shadow:0 0 0 2px color-mix(in srgb,var(--md-sys-color-primary) 16%,transparent)}.praxis-ai-assistant-shell__badge--error .praxis-ai-assistant-shell__state-dot{background:var(--md-sys-color-error);box-shadow:0 0 0 2px color-mix(in srgb,var(--md-sys-color-error) 16%,transparent)}.praxis-ai-assistant-shell__title-group strong,.praxis-ai-assistant-shell__title-group p{min-width:0;margin:0;overflow-wrap:anywhere}.praxis-ai-assistant-shell__title-group strong{flex:1 1 auto;font-size:13px;line-height:1.2}.praxis-ai-assistant-shell__title-group p{color:var(--md-sys-color-on-surface-variant);font-size:11.5px;line-height:1.3}.praxis-ai-assistant-shell__header-actions{flex:0 0 auto;display:flex;align-items:center;gap:2px;margin-top:-3px}.praxis-ai-assistant-shell__header-actions button{display:inline-grid;place-items:center;width:34px;height:34px;padding:0;color:var(--md-sys-color-on-surface-variant);line-height:1;opacity:.78}.praxis-ai-assistant-shell__header-actions button:hover,.praxis-ai-assistant-shell__header-actions button:focus-visible{opacity:1}.praxis-ai-assistant-shell__header-actions mat-icon{display:block;width:18px;height:18px;font-size:18px;line-height:18px}.praxis-ai-assistant-shell__body{min-height:0;flex:1 1 auto;display:flex;flex-direction:column;gap:10px;padding:12px 12px 10px;overflow:auto;background:linear-gradient(180deg,var(--md-sys-color-surface-container-low),var(--md-sys-color-surface))}.praxis-ai-assistant-shell__context,.praxis-ai-assistant-shell__attachments{flex:0 0 auto;display:flex;align-items:center;gap:8px;overflow-x:auto}.praxis-ai-assistant-shell__context-item{flex:0 0 auto;display:inline-flex;align-items:center;gap:5px;max-width:240px;padding:5px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface-container-high);font-size:12px;line-height:1.25}.praxis-ai-assistant-shell__context-item mat-icon{width:16px;height:16px;font-size:16px}.praxis-ai-assistant-shell__context-label,.praxis-ai-assistant-shell__context-value{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.praxis-ai-assistant-shell__context-label{color:var(--md-sys-color-on-surface)}.praxis-ai-assistant-shell__context-value{color:var(--md-sys-color-on-surface-variant)}.praxis-ai-assistant-shell__label{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.praxis-ai-assistant-shell__prompt{box-sizing:border-box;width:100%;min-height:46px;max-height:96px;resize:none;border:0;padding:10px 12px 8px;color:var(--md-sys-color-on-surface);background:transparent;font:inherit;line-height:1.45;outline:none}.praxis-ai-assistant-shell__conversation{min-height:0;flex:1 1 auto;display:flex;flex-direction:column;gap:8px;overflow:auto;padding:2px}.praxis-ai-assistant-shell__message{max-width:86%;align-self:flex-start;padding:9px 11px;border-radius:8px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface);font-size:13px;line-height:1.35;overflow-wrap:anywhere}.praxis-ai-assistant-shell__message-content{white-space:normal}.praxis-ai-assistant-shell__message-content :where(p,ul,h3,h4,h5){margin:0}.praxis-ai-assistant-shell__message-content :where(p,ul,h3,h4,h5)+:where(p,ul,h3,h4,h5){margin-top:8px}.praxis-ai-assistant-shell__message-content ul{padding-left:18px}.praxis-ai-assistant-shell__message-content li+li{margin-top:4px}.praxis-ai-assistant-shell__message-content code{padding:1px 4px;border-radius:4px;background:color-mix(in srgb,var(--md-sys-color-on-surface) 10%,transparent);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.94em}.praxis-ai-assistant-shell__message-actions{display:flex;align-items:center;gap:4px;flex-wrap:wrap;margin-top:8px}.praxis-ai-assistant-shell__message-action{min-height:28px;padding:0 8px;border-radius:8px;font-size:12px}.praxis-ai-assistant-shell__message-action--icon{width:30px;min-width:30px;height:30px;padding:0;color:var(--md-sys-color-on-surface-variant)}.praxis-ai-assistant-shell__message-action--icon mat-icon{width:17px;height:17px;font-size:17px}.praxis-ai-assistant-shell__message--assistant{border-bottom-left-radius:2px}.praxis-ai-assistant-shell__message--user{align-self:flex-end;border-bottom-right-radius:2px;background:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container)}.praxis-ai-assistant-shell__message--status{color:var(--md-sys-color-on-surface-variant)}.praxis-ai-assistant-shell__message--error,.praxis-ai-assistant-shell__error{color:var(--md-sys-color-error)}.praxis-ai-assistant-shell__quick-replies{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,520px),1fr));gap:8px;align-items:stretch;padding-bottom:4px}.praxis-ai-assistant-shell__quick-replies--inline{display:flex;flex-wrap:wrap;align-items:center;gap:6px}.praxis-ai-assistant-shell__attachment{flex:0 0 auto;display:inline-flex;align-items:center;gap:7px;max-width:260px;min-height:34px;padding:4px 4px 4px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface-container-high)}.praxis-ai-assistant-shell__attachment--error{border-color:color-mix(in srgb,var(--md-sys-color-error) 60%,transparent)}.praxis-ai-assistant-shell__attachment-preview{flex:0 0 auto;width:28px;height:28px;border-radius:6px;object-fit:cover}.praxis-ai-assistant-shell__attachment-name,.praxis-ai-assistant-shell__attachment-kind{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px}.praxis-ai-assistant-shell__attachment-name{color:var(--md-sys-color-on-surface)}.praxis-ai-assistant-shell__attachment-kind{color:var(--md-sys-color-on-surface-variant)}.praxis-ai-assistant-shell__quick-reply{--praxis-ai-assistant-shell-quick-reply-accent: var(--md-sys-color-primary);--praxis-ai-assistant-shell-quick-reply-background: color-mix( in srgb, var(--praxis-ai-assistant-shell-quick-reply-accent) 7%, var(--md-sys-color-surface-container-high) );--praxis-ai-assistant-shell-quick-reply-foreground: var(--md-sys-color-on-surface);width:100%;max-width:100%;height:auto;min-height:0;position:relative;overflow:hidden;padding:15px 16px;align-items:stretch;border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 36%,transparent);border-radius:22px;color:var(--praxis-ai-assistant-shell-quick-reply-foreground);background:linear-gradient(135deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 16%,transparent),transparent 46%),radial-gradient(circle at 92% 10%,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 22%,transparent),transparent 32%),var(--praxis-ai-assistant-shell-quick-reply-background);box-shadow:0 18px 42px color-mix(in srgb,var(--praxis-ai-assistant-shell-shadow-color) 22%,transparent),inset 0 1px color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 16%,transparent);letter-spacing:normal;white-space:normal;text-align:left;text-transform:none;-webkit-user-select:none;user-select:none;transition:border-color .16s ease,box-shadow .16s ease,transform .16s ease,background .16s ease;--mdc-outlined-button-container-height: auto;--mat-outlined-button-horizontal-padding: 0}.praxis-ai-assistant-shell__quick-reply:hover:not(:disabled),.praxis-ai-assistant-shell__quick-reply:focus-visible{border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 74%,transparent);box-shadow:0 18px 42px color-mix(in srgb,var(--praxis-ai-assistant-shell-shadow-color) 24%,transparent),0 0 0 3px color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 18%,transparent),inset 0 1px color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 18%,transparent);transform:translateY(-1px)}.praxis-ai-assistant-shell__quick-reply--contextual-action{padding:10px 12px;border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 34%,transparent);border-radius:8px;background:linear-gradient(90deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 15%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-high) 92%,transparent)),var(--md-sys-color-surface-container-high);box-shadow:none}.praxis-ai-assistant-shell__quick-reply--guided-action{padding:10px 12px;border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 30%,transparent);border-radius:8px;background:linear-gradient(90deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 10%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-high) 96%,transparent)),var(--md-sys-color-surface-container-high);box-shadow:none}.praxis-ai-assistant-shell__quick-reply--contextual-action:hover:not(:disabled),.praxis-ai-assistant-shell__quick-reply--contextual-action:focus-visible,.praxis-ai-assistant-shell__quick-reply--guided-action:hover:not(:disabled),.praxis-ai-assistant-shell__quick-reply--guided-action:focus-visible{border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 62%,transparent);box-shadow:0 0 0 2px color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 15%,transparent);transform:none}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-ambient,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-ambient{display:none}.praxis-ai-assistant-shell__quick-reply--contextual-action ::ng-deep .mdc-button__label,.praxis-ai-assistant-shell__quick-reply--guided-action ::ng-deep .mdc-button__label{gap:10px}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-icon-frame,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-icon-frame{width:34px;height:34px;border-radius:8px;box-shadow:none}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-icon,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-icon{width:19px;height:19px;font-size:19px}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-copy,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-copy{gap:6px}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-label,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-label{font-size:13.5px;font-weight:760;letter-spacing:0}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-description,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-description{display:-webkit-box;overflow:hidden;font-size:12px;line-height:1.34;-webkit-box-orient:vertical;-webkit-line-clamp:2}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-badge,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-badge{border-radius:8px;font-size:10px;letter-spacing:0}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-context-chip{border-radius:8px;padding:4px 7px;font-size:10.5px;font-weight:650}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-cta,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-cta{font-size:11.5px}.praxis-ai-assistant-shell__quick-reply--compact{justify-self:start;width:fit-content;min-width:min(100%,210px);max-width:min(100%,320px);padding:9px 11px;border-radius:16px;background:linear-gradient(135deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 10%,transparent),transparent 55%),var(--md-sys-color-surface-container-high);box-shadow:0 8px 18px color-mix(in srgb,var(--praxis-ai-assistant-shell-shadow-color) 16%,transparent),inset 0 1px color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 10%,transparent)}.praxis-ai-assistant-shell__quick-reply.praxis-ai-assistant-shell__quick-reply--compact ::ng-deep .mdc-button__label{align-items:center;gap:10px}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-icon-frame{width:34px;height:34px;border-radius:12px}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-icon{width:19px;height:19px;font-size:19px}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-copy{gap:4px}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-header{align-items:center}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-label{font-size:13px;line-height:1.2}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-badge,.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-cta{display:none}.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply{width:auto;min-width:0;max-width:100%;padding:6px 10px;border-radius:999px;box-shadow:none}.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply--guided-action{border-color:color-mix(in srgb,var(--md-sys-color-outline-variant) 76%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container-high) 96%,transparent)}.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply--guided-action:hover:not(:disabled),.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply--guided-action:focus-visible{border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 52%,transparent);background:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 9%,var(--md-sys-color-surface-container-high));box-shadow:0 0 0 2px color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 12%,transparent)}.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply ::ng-deep .mdc-button__label{display:inline-flex;grid-template-columns:none;align-items:center;gap:6px;width:auto}.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply ::ng-deep .mat-mdc-button-touch-target{min-height:34px}.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply-icon-frame{width:18px;height:18px;border:0;border-radius:0;background:transparent;box-shadow:none}.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply-icon{width:16px;height:16px;color:var(--praxis-ai-assistant-shell-quick-reply-accent);font-size:16px}.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply-copy,.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply-heading,.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply-header{display:inline-flex;align-items:center;gap:0}.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply-label{color:var(--md-sys-color-on-surface);font-size:12.5px;font-weight:650;line-height:1.2;white-space:nowrap}.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply-description,.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply-actions,.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply-badge,.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply-cta{display:none}.praxis-ai-assistant-shell__quick-reply ::ng-deep .mdc-button__label{position:relative;z-index:1;min-width:0;display:grid;grid-template-columns:auto minmax(0,1fr);align-items:flex-start;gap:14px;width:100%;height:auto;line-height:normal}.praxis-ai-assistant-shell__quick-reply-ambient{position:absolute;inset:0;pointer-events:none}.praxis-ai-assistant-shell__quick-reply-ambient:before{content:\"\";position:absolute;inset:0 18px auto;height:1px;border-radius:999px;background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 90%,var(--praxis-ai-assistant-shell-highlight-color)),transparent);opacity:.58}.praxis-ai-assistant-shell__quick-reply-ambient:after{content:\"\";position:absolute;top:-34px;right:-44px;width:150px;height:150px;border-radius:999px;background:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 13%,transparent);filter:blur(18px)}.praxis-ai-assistant-shell__quick-reply ::ng-deep .mat-mdc-button-touch-target{height:100%;min-height:48px}.praxis-ai-assistant-shell__quick-reply-icon-frame{flex:0 0 auto;width:46px;height:46px;display:inline-grid;place-items:center;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 34%,transparent);border-radius:17px;color:var(--praxis-ai-assistant-shell-quick-reply-accent);background:linear-gradient(145deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 24%,transparent),color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 6%,transparent));box-shadow:inset 0 1px color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 18%,transparent),0 10px 24px color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 12%,transparent)}.praxis-ai-assistant-shell__quick-reply-icon{width:24px;height:24px;font-size:24px}.praxis-ai-assistant-shell__quick-reply-details{flex:0 0 auto;width:24px;height:24px;display:inline-grid;place-items:center;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 14%,transparent);border-radius:50%;color:var(--md-sys-color-on-surface-variant);background:color-mix(in srgb,var(--md-sys-color-outline) 14%,transparent);font-size:17px;opacity:.9}.praxis-ai-assistant-shell__quick-reply-copy{min-width:0;display:grid;gap:10px;flex:1 1 auto}.praxis-ai-assistant-shell__quick-reply-header{min-width:0;display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.praxis-ai-assistant-shell__quick-reply-heading{min-width:0;display:grid;gap:5px}.praxis-ai-assistant-shell__quick-reply-actions{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:flex-end;gap:7px;max-width:46%}.praxis-ai-assistant-shell__quick-reply-label,.praxis-ai-assistant-shell__quick-reply-description{min-width:0;overflow-wrap:anywhere}.praxis-ai-assistant-shell__quick-reply-label{color:var(--md-sys-color-on-surface);font-size:17px;font-weight:760;letter-spacing:.005em;line-height:1.18;text-transform:none}.praxis-ai-assistant-shell__quick-reply-badge{flex:0 0 auto;max-width:100%;padding:4px 8px;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 28%,transparent);border-radius:999px;color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 86%,var(--praxis-ai-assistant-shell-highlight-color));background:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 11%,transparent);font-size:10.5px;font-weight:700;letter-spacing:.02em;line-height:1.1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.praxis-ai-assistant-shell__quick-reply-description{color:color-mix(in srgb,var(--md-sys-color-on-surface) 80%,transparent);font-size:13px;line-height:1.46}.praxis-ai-assistant-shell__quick-reply-context{display:flex;flex-wrap:wrap;gap:7px;align-items:center}.praxis-ai-assistant-shell__quick-reply-context-chip{min-width:0;display:inline-flex;align-items:center;gap:4px;max-width:100%;padding:5px 8px;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 22%,transparent);border-radius:999px;color:color-mix(in srgb,var(--md-sys-color-on-surface) 82%,transparent);background:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 9%,transparent);font-size:11px;font-weight:650;line-height:1.15}.praxis-ai-assistant-shell__quick-reply-context-chip mat-icon{width:14px;height:14px;color:var(--praxis-ai-assistant-shell-quick-reply-accent);font-size:14px}.praxis-ai-assistant-shell__quick-reply-context-chip span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.praxis-ai-assistant-shell__quick-reply-insights{display:grid;grid-template-columns:repeat(auto-fit,minmax(145px,1fr));gap:8px;padding:8px;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 16%,transparent);border-radius:16px;background:linear-gradient(180deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 5%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-lowest) 26%,transparent))}.praxis-ai-assistant-shell__quick-reply-insight{min-width:0;display:grid;grid-template-columns:20px minmax(0,1fr);gap:8px;align-items:start;padding:8px;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 10%,transparent);border-radius:13px;color:color-mix(in srgb,var(--md-sys-color-on-surface) 86%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container-high) 44%,transparent);font-size:12px;line-height:1.35}.praxis-ai-assistant-shell__quick-reply-insight mat-icon{width:17px;height:17px;color:var(--praxis-ai-assistant-shell-quick-reply-accent);font-size:17px;opacity:.9}.praxis-ai-assistant-shell__quick-reply-insight-copy{min-width:0;display:grid;gap:1px}.praxis-ai-assistant-shell__quick-reply-insight-label{color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 82%,var(--praxis-ai-assistant-shell-highlight-color));font-size:10.5px;font-weight:760;letter-spacing:.045em;line-height:1.2;text-transform:uppercase}.praxis-ai-assistant-shell__quick-reply-insight-value{min-width:0;overflow-wrap:anywhere}.praxis-ai-assistant-shell__quick-reply-cta{display:inline-flex;align-items:center;justify-self:start;gap:5px;padding:3px 0;color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 84%,var(--praxis-ai-assistant-shell-highlight-color));font-size:12px;font-weight:760;letter-spacing:.01em;line-height:1.2}.praxis-ai-assistant-shell__quick-reply-cta mat-icon{width:15px;height:15px;font-size:15px;transition:transform .16s ease}.praxis-ai-assistant-shell__quick-reply:hover:not(:disabled) .praxis-ai-assistant-shell__quick-reply-cta mat-icon,.praxis-ai-assistant-shell__quick-reply:focus-visible .praxis-ai-assistant-shell__quick-reply-cta mat-icon{transform:translate(2px)}.praxis-ai-assistant-shell__quick-reply--tone-analytics{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-analytics)}.praxis-ai-assistant-shell__quick-reply--tone-resource{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-resource)}.praxis-ai-assistant-shell__quick-reply--tone-warning{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-warning)}.praxis-ai-assistant-shell__quick-reply--tone-success{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-success)}.praxis-ai-assistant-shell__quick-reply--tone-danger{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-danger)}.praxis-ai-assistant-shell__quick-reply--tone-neutral{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-neutral)}@media(max-width:640px){.praxis-ai-assistant-shell__quick-reply{padding:13px;border-radius:19px}.praxis-ai-assistant-shell__quick-reply ::ng-deep .mdc-button__label{grid-template-columns:minmax(0,1fr);gap:10px}.praxis-ai-assistant-shell__quick-reply-icon-frame{width:38px;height:38px;border-radius:14px}.praxis-ai-assistant-shell__quick-reply-header{display:grid}.praxis-ai-assistant-shell__quick-reply-actions{justify-content:flex-start;max-width:100%}.praxis-ai-assistant-shell__quick-reply-insights{grid-template-columns:minmax(0,1fr)}}.praxis-ai-assistant-shell__status,.praxis-ai-assistant-shell__error{margin:0;font-size:13px;line-height:1.35;overflow-wrap:anywhere}.praxis-ai-assistant-shell__footer{flex:0 0 auto;padding:8px 10px 10px;border-top:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent);background:var(--md-sys-color-surface-container-low)}.praxis-ai-assistant-shell__composer{display:grid;gap:8px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-lowest);box-shadow:inset 0 1px color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 4%,transparent)}.praxis-ai-assistant-shell__composer:focus-within{border-color:var(--md-sys-color-primary);box-shadow:0 0 0 2px color-mix(in srgb,var(--md-sys-color-primary) 16%,transparent)}.praxis-ai-assistant-shell__composer-actions{display:flex;align-items:center;justify-content:flex-end;gap:8px;padding:0 8px 7px;flex-wrap:wrap}.praxis-ai-assistant-shell__action{min-height:36px;border-radius:10px;font-weight:650}.praxis-ai-assistant-shell__action mat-icon{width:18px;height:18px;margin-right:6px;font-size:18px}.praxis-ai-assistant-shell__action--icon-only{width:40px;min-width:40px;height:40px;padding-inline:0;border-radius:50%}.praxis-ai-assistant-shell__action--icon-only mat-icon{margin-right:0}.praxis-ai-assistant-shell__action--secondary{color:var(--md-sys-color-on-surface-variant)}.praxis-ai-assistant-shell__action--tone-governance{color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent)}.praxis-ai-assistant-shell__action--tone-success{color:var(--praxis-ai-assistant-shell-tone-success);background:color-mix(in srgb,var(--praxis-ai-assistant-shell-tone-success) 10%,transparent)}.praxis-ai-assistant-shell__action--tone-warning{color:var(--praxis-ai-assistant-shell-tone-warning);background:color-mix(in srgb,var(--praxis-ai-assistant-shell-tone-warning) 10%,transparent)}.praxis-ai-assistant-shell__action--tone-danger{color:var(--md-sys-color-error);background:color-mix(in srgb,var(--md-sys-color-error) 10%,transparent)}.praxis-ai-assistant-shell__resize-handle{position:absolute;z-index:2;border:0;background:transparent;touch-action:none}.praxis-ai-assistant-shell__resize-handle--n,.praxis-ai-assistant-shell__resize-handle--s{left:16px;right:16px;height:10px;cursor:ns-resize}.praxis-ai-assistant-shell__resize-handle--n{top:-5px}.praxis-ai-assistant-shell__resize-handle--s{bottom:-5px}.praxis-ai-assistant-shell__resize-handle--e,.praxis-ai-assistant-shell__resize-handle--w{top:16px;bottom:16px;width:10px;cursor:ew-resize}.praxis-ai-assistant-shell__resize-handle--e{right:-5px}.praxis-ai-assistant-shell__resize-handle--w{left:-5px}.praxis-ai-assistant-shell__resize-handle--ne,.praxis-ai-assistant-shell__resize-handle--nw,.praxis-ai-assistant-shell__resize-handle--se,.praxis-ai-assistant-shell__resize-handle--sw{width:22px;height:22px}.praxis-ai-assistant-shell__resize-handle--ne{top:-5px;right:-5px;cursor:nesw-resize}.praxis-ai-assistant-shell__resize-handle--nw{top:-5px;left:-5px;cursor:nwse-resize}.praxis-ai-assistant-shell__resize-handle--se{right:-5px;bottom:-5px;cursor:nwse-resize}.praxis-ai-assistant-shell__resize-handle--sw{bottom:-5px;left:-5px;cursor:nesw-resize}.praxis-ai-assistant-shell__resize-handle--se:after{content:\"\";position:absolute;right:8px;bottom:8px;width:10px;height:10px;border-right:2px solid var(--md-sys-color-outline);border-bottom:2px solid var(--md-sys-color-outline)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i4.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i1.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i7.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i8.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i9.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
7824
7909
|
}
|
|
7825
7910
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisAiAssistantShellComponent, decorators: [{
|
|
7826
7911
|
type: Component,
|
|
@@ -7831,7 +7916,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
7831
7916
|
MatIconModule,
|
|
7832
7917
|
MatProgressSpinnerModule,
|
|
7833
7918
|
MatTooltipModule,
|
|
7834
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<section\n #panel\n class=\"praxis-ai-assistant-shell\"\n role=\"dialog\"\n [attr.aria-label]=\"resolvedLabels.title\"\n [attr.aria-busy]=\"busy ? 'true' : null\"\n [style.left.px]=\"currentLayout.left\"\n [style.top.px]=\"currentLayout.top\"\n [style.width.px]=\"currentLayout.width\"\n [style.height.px]=\"currentLayout.height\"\n [attr.data-testid]=\"panelTestId || testIdPrefix\"\n>\n <header\n class=\"praxis-ai-assistant-shell__header\"\n [attr.data-testid]=\"testIdPrefix + '-drag-handle'\"\n [attr.aria-label]=\"resolvedLabels.dragHandleAria\"\n (pointerdown)=\"startDrag($event)\"\n >\n <div class=\"praxis-ai-assistant-shell__identity\" aria-hidden=\"true\">\n <mat-icon>auto_awesome</mat-icon>\n </div>\n <div class=\"praxis-ai-assistant-shell__title-group\">\n <div class=\"praxis-ai-assistant-shell__title-row\">\n <strong>{{ resolvedLabels.title }}</strong>\n <div class=\"praxis-ai-assistant-shell__badges\" aria-hidden=\"true\">\n <span class=\"praxis-ai-assistant-shell__badge praxis-ai-assistant-shell__badge--context\">\n {{ getModeLabel() }}\n </span>\n <span\n class=\"praxis-ai-assistant-shell__badge praxis-ai-assistant-shell__badge--state\"\n [class.praxis-ai-assistant-shell__badge--error]=\"state === 'error'\"\n >\n <span class=\"praxis-ai-assistant-shell__state-dot\" aria-hidden=\"true\"></span>\n {{ getStateLabel() }}\n </span>\n </div>\n </div>\n <p *ngIf=\"resolvedLabels.subtitle\">{{ resolvedLabels.subtitle }}</p>\n </div>\n <div class=\"praxis-ai-assistant-shell__header-actions\">\n <button\n mat-icon-button\n type=\"button\"\n [matTooltip]=\"resolvedLabels.close\"\n [attr.aria-label]=\"resolvedLabels.close\"\n (pointerdown)=\"$event.stopPropagation()\"\n (click)=\"close.emit()\"\n [attr.data-testid]=\"testIdPrefix + '-close'\"\n >\n <mat-icon>{{ getCloseIcon() }}</mat-icon>\n </button>\n </div>\n </header>\n\n <div class=\"praxis-ai-assistant-shell__body\">\n <div\n *ngIf=\"contextItems.length\"\n class=\"praxis-ai-assistant-shell__context\"\n [attr.aria-label]=\"resolvedLabels.contextAria\"\n [attr.data-testid]=\"testIdPrefix + '-context'\"\n >\n <span\n *ngFor=\"let item of contextItems; trackBy: trackContextItem\"\n class=\"praxis-ai-assistant-shell__context-item\"\n [attr.data-testid]=\"testIdPrefix + '-context-' + item.id\"\n >\n <mat-icon *ngIf=\"item.icon\" aria-hidden=\"true\">{{ item.icon }}</mat-icon>\n <span class=\"praxis-ai-assistant-shell__context-label\">{{ item.label }}</span>\n <span *ngIf=\"item.value\" class=\"praxis-ai-assistant-shell__context-value\">{{ item.value }}</span>\n </span>\n </div>\n\n <div\n #conversation\n class=\"praxis-ai-assistant-shell__conversation\"\n [attr.data-testid]=\"testIdPrefix + '-conversation'\"\n [attr.aria-label]=\"resolvedLabels.conversationAria\"\n >\n <article\n *ngIf=\"!messages.length\"\n class=\"praxis-ai-assistant-shell__message praxis-ai-assistant-shell__message--assistant\"\n [attr.data-testid]=\"testIdPrefix + '-message-assistant-empty'\"\n >\n {{ resolvedLabels.emptyConversation }}\n </article>\n <article\n *ngFor=\"let message of messages; trackBy: trackMessage\"\n class=\"praxis-ai-assistant-shell__message\"\n [class.praxis-ai-assistant-shell__message--user]=\"message.role === 'user'\"\n [class.praxis-ai-assistant-shell__message--assistant]=\"message.role === 'assistant'\"\n [class.praxis-ai-assistant-shell__message--status]=\"message.role === 'status'\"\n [class.praxis-ai-assistant-shell__message--error]=\"message.role === 'error'\"\n [attr.data-testid]=\"testIdPrefix + '-message-' + message.role\"\n >\n <div\n class=\"praxis-ai-assistant-shell__message-content\"\n [innerHTML]=\"renderMessageText(message.text)\"\n ></div>\n <div\n *ngIf=\"message.actions?.length || message.editable || message.resendable\"\n class=\"praxis-ai-assistant-shell__message-actions\"\n >\n <button\n *ngIf=\"message.editable\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.editMessage\"\n [attr.aria-label]=\"resolvedLabels.editMessage\"\n [attr.data-testid]=\"testIdPrefix + '-message-edit-' + message.id\"\n (click)=\"onMessageAction(message, { id: 'edit', label: resolvedLabels.editMessage, kind: 'edit' })\"\n >\n <mat-icon aria-hidden=\"true\">edit</mat-icon>\n </button>\n <button\n *ngIf=\"message.resendable\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.resendMessage\"\n [attr.aria-label]=\"resolvedLabels.resendMessage\"\n [attr.data-testid]=\"testIdPrefix + '-message-resend-' + message.id\"\n (click)=\"onMessageAction(message, { id: 'resend', label: resolvedLabels.resendMessage, kind: 'resend' })\"\n >\n <mat-icon aria-hidden=\"true\">replay</mat-icon>\n </button>\n <ng-container *ngFor=\"let action of message.actions || []; trackBy: trackMessageAction\">\n <button\n *ngIf=\"isMessageActionIconOnly(action); else textualMessageAction\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy || action.disabled\"\n [matTooltip]=\"getMessageActionLabel(action)\"\n [attr.aria-label]=\"getMessageActionLabel(action)\"\n [attr.data-testid]=\"testIdPrefix + '-message-action-' + message.id + '-' + action.id\"\n (click)=\"onMessageAction(message, action)\"\n >\n <mat-icon aria-hidden=\"true\">{{ getMessageActionIcon(action) }}</mat-icon>\n </button>\n <ng-template #textualMessageAction>\n <button\n mat-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action\"\n [disabled]=\"busy || action.disabled\"\n [attr.aria-label]=\"getMessageActionLabel(action)\"\n [attr.data-testid]=\"testIdPrefix + '-message-action-' + message.id + '-' + action.id\"\n (click)=\"onMessageAction(message, action)\"\n >\n {{ action.label }}\n </button>\n </ng-template>\n </ng-container>\n </div>\n </article>\n </div>\n\n <div\n *ngIf=\"attachments.length\"\n class=\"praxis-ai-assistant-shell__attachments\"\n [attr.aria-label]=\"resolvedLabels.attachmentsAria\"\n [attr.data-testid]=\"testIdPrefix + '-attachments'\"\n >\n <div\n *ngFor=\"let attachment of attachments; trackBy: trackAttachment\"\n class=\"praxis-ai-assistant-shell__attachment\"\n [class.praxis-ai-assistant-shell__attachment--error]=\"attachment.status === 'error'\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-' + attachment.id\"\n >\n <img\n *ngIf=\"attachment.previewUrl && attachment.kind === 'image'\"\n class=\"praxis-ai-assistant-shell__attachment-preview\"\n [src]=\"attachment.previewUrl\"\n [alt]=\"attachment.name\"\n >\n <span class=\"praxis-ai-assistant-shell__attachment-name\">{{ attachment.name }}</span>\n <span class=\"praxis-ai-assistant-shell__attachment-kind\">{{ attachment.kind }}</span>\n <button\n mat-icon-button\n type=\"button\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.removeAttachment\"\n [attr.aria-label]=\"resolvedLabels.removeAttachment + ': ' + attachment.name\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-remove-' + attachment.id\"\n (click)=\"onRemoveAttachment(attachment)\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n\n <div\n *ngIf=\"quickReplies.length\"\n class=\"praxis-ai-assistant-shell__quick-replies\"\n [attr.data-testid]=\"testIdPrefix + '-quick-replies'\"\n [attr.aria-label]=\"resolvedLabels.quickRepliesAria\"\n >\n <button\n *ngFor=\"let reply of quickReplies; trackBy: trackQuickReply\"\n mat-stroked-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__quick-reply\"\n [class.praxis-ai-assistant-shell__quick-reply--compact]=\"!isRichQuickReply(reply)\"\n [class.praxis-ai-assistant-shell__quick-reply--guided-action]=\"isGuidedActionQuickReply(reply)\"\n [class.praxis-ai-assistant-shell__quick-reply--contextual-action]=\"isContextualPreviewActionQuickReply(reply)\"\n [ngClass]=\"'praxis-ai-assistant-shell__quick-reply--tone-' + getQuickReplyTone(reply)\"\n [attr.data-testid]=\"testIdPrefix + '-quick-reply-' + (reply.id || reply.kind)\"\n [attr.aria-label]=\"getQuickReplyAriaLabel(reply)\"\n [disabled]=\"busy\"\n (click)=\"onQuickReply(reply)\"\n >\n <span class=\"praxis-ai-assistant-shell__quick-reply-ambient\" aria-hidden=\"true\"></span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-icon-frame\" aria-hidden=\"true\">\n <mat-icon\n class=\"praxis-ai-assistant-shell__quick-reply-icon\"\n >\n {{ getQuickReplyIcon(reply) }}\n </mat-icon>\n </span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-copy\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-header\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-heading\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-label\">{{ reply.label }}</span>\n <span\n *ngIf=\"getQuickReplyDescription(reply)\"\n class=\"praxis-ai-assistant-shell__quick-reply-description\"\n >\n {{ getQuickReplyDescription(reply) }}\n </span>\n </span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-actions\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-badge\">\n {{ getQuickReplyCategoryLabel(reply) }}\n </span>\n <mat-icon\n *ngIf=\"getQuickReplyTechnicalDetails(reply)\"\n class=\"praxis-ai-assistant-shell__quick-reply-details\"\n [matTooltip]=\"getQuickReplyTechnicalDetails(reply)\"\n [attr.aria-label]=\"resolvedLabels.quickReplyDetails\"\n >\n info\n </mat-icon>\n </span>\n </span>\n <span\n *ngIf=\"getQuickReplyContextChips(reply).length\"\n class=\"praxis-ai-assistant-shell__quick-reply-context\"\n >\n <span\n *ngFor=\"let chip of getQuickReplyContextChips(reply)\"\n class=\"praxis-ai-assistant-shell__quick-reply-context-chip\"\n [attr.aria-label]=\"chip.ariaLabel\"\n >\n <mat-icon aria-hidden=\"true\">{{ chip.icon }}</mat-icon>\n <span>{{ chip.value }}</span>\n </span>\n </span>\n <span\n *ngIf=\"getQuickReplyPresentationItems(reply).length\"\n class=\"praxis-ai-assistant-shell__quick-reply-insights\"\n >\n <span\n *ngFor=\"let item of getQuickReplyPresentationItems(reply)\"\n class=\"praxis-ai-assistant-shell__quick-reply-insight\"\n >\n <mat-icon aria-hidden=\"true\">{{ item.icon }}</mat-icon>\n <span class=\"praxis-ai-assistant-shell__quick-reply-insight-copy\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-insight-label\">\n {{ item.label }}\n </span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-insight-value\">\n {{ item.value }}\n </span>\n </span>\n </span>\n </span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-cta\">\n {{ getQuickReplyCtaLabel(reply) }}\n <mat-icon aria-hidden=\"true\">arrow_forward</mat-icon>\n </span>\n </span>\n </button>\n </div>\n <p\n *ngIf=\"shouldShowStatusText()\"\n class=\"praxis-ai-assistant-shell__status\"\n [attr.data-testid]=\"testIdPrefix + '-status'\"\n >\n {{ statusText }}\n </p>\n <p\n *ngIf=\"shouldShowErrorText()\"\n class=\"praxis-ai-assistant-shell__error\"\n [attr.data-testid]=\"testIdPrefix + '-error'\"\n >\n {{ errorText }}\n </p>\n </div>\n\n <footer class=\"praxis-ai-assistant-shell__footer\">\n <label class=\"praxis-ai-assistant-shell__label\" for=\"praxis-ai-assistant-shell-prompt\">\n {{ resolvedLabels.prompt }}\n </label>\n <div class=\"praxis-ai-assistant-shell__composer\">\n <textarea\n id=\"praxis-ai-assistant-shell-prompt\"\n class=\"praxis-ai-assistant-shell__prompt\"\n [attr.data-testid]=\"testIdPrefix + '-prompt'\"\n [placeholder]=\"resolvedLabels.promptPlaceholder\"\n [ngModel]=\"currentPrompt\"\n [disabled]=\"busy\"\n (ngModelChange)=\"onPromptInput($event)\"\n (keydown)=\"onPromptKeydown($event)\"\n (paste)=\"onPromptPaste($event)\"\n ></textarea>\n <div class=\"praxis-ai-assistant-shell__composer-actions\">\n <ng-container *ngIf=\"showAttachAction\">\n <input\n #attachmentInput\n type=\"file\"\n hidden\n [attr.accept]=\"attachmentAccept || null\"\n [attr.multiple]=\"attachmentMultiple ? '' : null\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-input'\"\n (change)=\"onAttachmentFilesSelected($event)\"\n >\n <button\n mat-stroked-button\n type=\"button\"\n [disabled]=\"busy\"\n (click)=\"onAttachClick(attachmentInput)\"\n [attr.data-testid]=\"testIdPrefix + '-attach'\"\n >\n <mat-icon>attach_file</mat-icon>\n {{ resolvedLabels.attach }}\n </button>\n </ng-container>\n <button\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n class=\"praxis-ai-assistant-shell__action praxis-ai-assistant-shell__action--primary\"\n [class.praxis-ai-assistant-shell__action--icon-only]=\"getPrimaryAction().iconOnly\"\n [matTooltip]=\"getPrimaryActionTooltip(getPrimaryAction())\"\n [ngClass]=\"'praxis-ai-assistant-shell__action--tone-' + getShellActionTone(getPrimaryAction())\"\n [disabled]=\"isShellActionDisabled(getPrimaryAction())\"\n (click)=\"onShellAction(getPrimaryAction())\"\n [attr.data-testid]=\"getPrimaryAction().testId || (submitTestId || (testIdPrefix + '-submit'))\"\n [attr.aria-label]=\"getPrimaryAction().ariaLabel || getPrimaryAction().label\"\n >\n <mat-icon *ngIf=\"getPrimaryAction().icon\" aria-hidden=\"true\">{{ getPrimaryAction().icon }}</mat-icon>\n <span *ngIf=\"!getPrimaryAction().iconOnly\">{{ getPrimaryAction().label }}</span>\n </button>\n <button\n *ngFor=\"let action of getSecondaryActions(); trackBy: trackShellAction\"\n mat-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__action praxis-ai-assistant-shell__action--secondary\"\n [ngClass]=\"'praxis-ai-assistant-shell__action--tone-' + getShellActionTone(action)\"\n [disabled]=\"isShellActionDisabled(action)\"\n (click)=\"onShellAction(action)\"\n [attr.data-testid]=\"action.testId || (testIdPrefix + '-action-' + action.id)\"\n [attr.aria-label]=\"action.ariaLabel || action.label\"\n >\n <mat-icon *ngIf=\"action.icon\" aria-hidden=\"true\">{{ action.icon }}</mat-icon>\n {{ action.label }}\n </button>\n <mat-spinner *ngIf=\"busy\" diameter=\"20\" [attr.data-testid]=\"testIdPrefix + '-spinner'\"></mat-spinner>\n </div>\n </div>\n </footer>\n\n <ng-container *ngIf=\"resizable\">\n <span\n *ngFor=\"let direction of resizeHandles; trackBy: trackResizeHandle\"\n class=\"praxis-ai-assistant-shell__resize-handle praxis-ai-assistant-shell__resize-handle--{{ direction }}\"\n [attr.data-testid]=\"direction === 'se' ? testIdPrefix + '-resize-handle' : testIdPrefix + '-resize-handle-' + direction\"\n aria-hidden=\"true\"\n role=\"presentation\"\n (pointerdown)=\"startResize(direction, $event)\"\n ></span>\n </ng-container>\n</section>\n", styles: [":host{display:block}.praxis-ai-assistant-shell{--praxis-ai-assistant-shell-shadow-color: var(--md-sys-color-shadow);--praxis-ai-assistant-shell-highlight-color: var(--md-sys-color-on-surface);--praxis-ai-assistant-shell-tone-analytics: var(--md-sys-color-primary);--praxis-ai-assistant-shell-tone-resource: var(--md-sys-color-tertiary);--praxis-ai-assistant-shell-tone-success: var(--md-sys-color-tertiary);--praxis-ai-assistant-shell-tone-warning: var(--md-sys-color-secondary);--praxis-ai-assistant-shell-tone-danger: var(--md-sys-color-error);--praxis-ai-assistant-shell-tone-neutral: var(--md-sys-color-outline);position:fixed;box-sizing:border-box;min-width:360px;min-height:360px;display:flex;flex-direction:column;overflow:hidden;color:var(--md-sys-color-on-surface);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface);box-shadow:0 24px 60px color-mix(in srgb,var(--praxis-ai-assistant-shell-shadow-color) 40%,transparent);z-index:var(--praxis-ai-assistant-shell-z-index, 1200)}.praxis-ai-assistant-shell__header{flex:0 0 auto;display:flex;align-items:flex-start;gap:9px;padding:10px 10px 9px;border-color:color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent);background:var(--md-sys-color-surface-container)}.praxis-ai-assistant-shell__header{justify-content:flex-start;border-bottom:1px solid;cursor:move;touch-action:none}.praxis-ai-assistant-shell__identity{flex:0 0 auto;display:grid;place-items:center;width:30px;height:30px;border-radius:8px;background:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary);box-shadow:0 6px 16px color-mix(in srgb,var(--md-sys-color-primary) 22%,transparent)}.praxis-ai-assistant-shell__identity mat-icon{width:18px;height:18px;font-size:18px}.praxis-ai-assistant-shell__title-group{min-width:0;flex:1 1 auto;display:grid;gap:4px}.praxis-ai-assistant-shell__title-row{min-width:0;display:flex;align-items:center;gap:8px}.praxis-ai-assistant-shell__badges{flex:0 0 auto;display:flex;align-items:center;justify-content:flex-end;gap:4px;min-width:0;flex-wrap:wrap}.praxis-ai-assistant-shell__badge{display:inline-flex;align-items:center;gap:5px;min-height:20px;max-width:120px;padding:2px 7px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 80%,transparent);border-radius:8px;color:var(--md-sys-color-on-surface-variant);background:var(--md-sys-color-surface-container-high);font-size:11px;line-height:1.2;overflow-wrap:anywhere}.praxis-ai-assistant-shell__badge--context{color:var(--md-sys-color-on-surface);background:color-mix(in srgb,var(--md-sys-color-primary) 9%,var(--md-sys-color-surface-container-high))}.praxis-ai-assistant-shell__badge--state{border-color:transparent;background:transparent;color:var(--md-sys-color-on-surface-variant);padding-inline:3px}.praxis-ai-assistant-shell__badge--error{color:var(--md-sys-color-error);border-color:color-mix(in srgb,var(--md-sys-color-error) 60%,transparent)}.praxis-ai-assistant-shell__state-dot{flex:0 0 auto;width:6px;height:6px;border-radius:999px;background:var(--md-sys-color-primary);box-shadow:0 0 0 2px color-mix(in srgb,var(--md-sys-color-primary) 16%,transparent)}.praxis-ai-assistant-shell__badge--error .praxis-ai-assistant-shell__state-dot{background:var(--md-sys-color-error);box-shadow:0 0 0 2px color-mix(in srgb,var(--md-sys-color-error) 16%,transparent)}.praxis-ai-assistant-shell__title-group strong,.praxis-ai-assistant-shell__title-group p{min-width:0;margin:0;overflow-wrap:anywhere}.praxis-ai-assistant-shell__title-group strong{flex:1 1 auto;font-size:13px;line-height:1.2}.praxis-ai-assistant-shell__title-group p{color:var(--md-sys-color-on-surface-variant);font-size:11.5px;line-height:1.3}.praxis-ai-assistant-shell__header-actions{flex:0 0 auto;display:flex;align-items:center;gap:2px;margin-top:-3px}.praxis-ai-assistant-shell__header-actions button{width:34px;height:34px;color:var(--md-sys-color-on-surface-variant);opacity:.78}.praxis-ai-assistant-shell__header-actions button:hover,.praxis-ai-assistant-shell__header-actions button:focus-visible{opacity:1}.praxis-ai-assistant-shell__header-actions mat-icon{width:18px;height:18px;font-size:18px}.praxis-ai-assistant-shell__body{min-height:0;flex:1 1 auto;display:flex;flex-direction:column;gap:10px;padding:12px 12px 10px;overflow:auto;background:linear-gradient(180deg,var(--md-sys-color-surface-container-low),var(--md-sys-color-surface))}.praxis-ai-assistant-shell__context,.praxis-ai-assistant-shell__attachments{flex:0 0 auto;display:flex;align-items:center;gap:8px;overflow-x:auto}.praxis-ai-assistant-shell__context-item{flex:0 0 auto;display:inline-flex;align-items:center;gap:5px;max-width:240px;padding:5px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface-container-high);font-size:12px;line-height:1.25}.praxis-ai-assistant-shell__context-item mat-icon{width:16px;height:16px;font-size:16px}.praxis-ai-assistant-shell__context-label,.praxis-ai-assistant-shell__context-value{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.praxis-ai-assistant-shell__context-label{color:var(--md-sys-color-on-surface)}.praxis-ai-assistant-shell__context-value{color:var(--md-sys-color-on-surface-variant)}.praxis-ai-assistant-shell__label{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.praxis-ai-assistant-shell__prompt{box-sizing:border-box;width:100%;min-height:46px;max-height:96px;resize:none;border:0;padding:10px 12px 8px;color:var(--md-sys-color-on-surface);background:transparent;font:inherit;line-height:1.45;outline:none}.praxis-ai-assistant-shell__conversation{min-height:0;flex:1 1 auto;display:flex;flex-direction:column;gap:8px;overflow:auto;padding:2px}.praxis-ai-assistant-shell__message{max-width:86%;align-self:flex-start;padding:9px 11px;border-radius:8px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface);font-size:13px;line-height:1.35;overflow-wrap:anywhere}.praxis-ai-assistant-shell__message-content{white-space:normal}.praxis-ai-assistant-shell__message-content :where(p,ul,h3,h4,h5){margin:0}.praxis-ai-assistant-shell__message-content :where(p,ul,h3,h4,h5)+:where(p,ul,h3,h4,h5){margin-top:8px}.praxis-ai-assistant-shell__message-content ul{padding-left:18px}.praxis-ai-assistant-shell__message-content li+li{margin-top:4px}.praxis-ai-assistant-shell__message-content code{padding:1px 4px;border-radius:4px;background:color-mix(in srgb,var(--md-sys-color-on-surface) 10%,transparent);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.94em}.praxis-ai-assistant-shell__message-actions{display:flex;align-items:center;gap:4px;flex-wrap:wrap;margin-top:8px}.praxis-ai-assistant-shell__message-action{min-height:28px;padding:0 8px;border-radius:8px;font-size:12px}.praxis-ai-assistant-shell__message-action--icon{width:30px;min-width:30px;height:30px;padding:0;color:var(--md-sys-color-on-surface-variant)}.praxis-ai-assistant-shell__message-action--icon mat-icon{width:17px;height:17px;font-size:17px}.praxis-ai-assistant-shell__message--assistant{border-bottom-left-radius:2px}.praxis-ai-assistant-shell__message--user{align-self:flex-end;border-bottom-right-radius:2px;background:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container)}.praxis-ai-assistant-shell__message--status{color:var(--md-sys-color-on-surface-variant)}.praxis-ai-assistant-shell__message--error,.praxis-ai-assistant-shell__error{color:var(--md-sys-color-error)}.praxis-ai-assistant-shell__quick-replies{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,520px),1fr));gap:8px;align-items:stretch;padding-bottom:4px}.praxis-ai-assistant-shell__attachment{flex:0 0 auto;display:inline-flex;align-items:center;gap:7px;max-width:260px;min-height:34px;padding:4px 4px 4px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface-container-high)}.praxis-ai-assistant-shell__attachment--error{border-color:color-mix(in srgb,var(--md-sys-color-error) 60%,transparent)}.praxis-ai-assistant-shell__attachment-preview{flex:0 0 auto;width:28px;height:28px;border-radius:6px;object-fit:cover}.praxis-ai-assistant-shell__attachment-name,.praxis-ai-assistant-shell__attachment-kind{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px}.praxis-ai-assistant-shell__attachment-name{color:var(--md-sys-color-on-surface)}.praxis-ai-assistant-shell__attachment-kind{color:var(--md-sys-color-on-surface-variant)}.praxis-ai-assistant-shell__quick-reply{--praxis-ai-assistant-shell-quick-reply-accent: var(--md-sys-color-primary);--praxis-ai-assistant-shell-quick-reply-background: color-mix( in srgb, var(--praxis-ai-assistant-shell-quick-reply-accent) 7%, var(--md-sys-color-surface-container-high) );--praxis-ai-assistant-shell-quick-reply-foreground: var(--md-sys-color-on-surface);width:100%;max-width:100%;height:auto;min-height:0;position:relative;overflow:hidden;padding:15px 16px;align-items:stretch;border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 36%,transparent);border-radius:22px;color:var(--praxis-ai-assistant-shell-quick-reply-foreground);background:linear-gradient(135deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 16%,transparent),transparent 46%),radial-gradient(circle at 92% 10%,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 22%,transparent),transparent 32%),var(--praxis-ai-assistant-shell-quick-reply-background);box-shadow:0 18px 42px color-mix(in srgb,var(--praxis-ai-assistant-shell-shadow-color) 22%,transparent),inset 0 1px color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 16%,transparent);letter-spacing:normal;white-space:normal;text-align:left;text-transform:none;-webkit-user-select:none;user-select:none;transition:border-color .16s ease,box-shadow .16s ease,transform .16s ease,background .16s ease;--mdc-outlined-button-container-height: auto;--mat-outlined-button-horizontal-padding: 0}.praxis-ai-assistant-shell__quick-reply:hover:not(:disabled),.praxis-ai-assistant-shell__quick-reply:focus-visible{border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 74%,transparent);box-shadow:0 18px 42px color-mix(in srgb,var(--praxis-ai-assistant-shell-shadow-color) 24%,transparent),0 0 0 3px color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 18%,transparent),inset 0 1px color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 18%,transparent);transform:translateY(-1px)}.praxis-ai-assistant-shell__quick-reply--contextual-action{padding:10px 12px;border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 34%,transparent);border-radius:8px;background:linear-gradient(90deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 15%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-high) 92%,transparent)),var(--md-sys-color-surface-container-high);box-shadow:none}.praxis-ai-assistant-shell__quick-reply--guided-action{padding:10px 12px;border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 30%,transparent);border-radius:8px;background:linear-gradient(90deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 10%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-high) 96%,transparent)),var(--md-sys-color-surface-container-high);box-shadow:none}.praxis-ai-assistant-shell__quick-reply--contextual-action:hover:not(:disabled),.praxis-ai-assistant-shell__quick-reply--contextual-action:focus-visible,.praxis-ai-assistant-shell__quick-reply--guided-action:hover:not(:disabled),.praxis-ai-assistant-shell__quick-reply--guided-action:focus-visible{border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 62%,transparent);box-shadow:0 0 0 2px color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 15%,transparent);transform:none}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-ambient,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-ambient{display:none}.praxis-ai-assistant-shell__quick-reply--contextual-action ::ng-deep .mdc-button__label,.praxis-ai-assistant-shell__quick-reply--guided-action ::ng-deep .mdc-button__label{gap:10px}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-icon-frame,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-icon-frame{width:34px;height:34px;border-radius:8px;box-shadow:none}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-icon,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-icon{width:19px;height:19px;font-size:19px}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-copy,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-copy{gap:6px}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-label,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-label{font-size:13.5px;font-weight:760;letter-spacing:0}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-description,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-description{display:-webkit-box;overflow:hidden;font-size:12px;line-height:1.34;-webkit-box-orient:vertical;-webkit-line-clamp:2}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-badge,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-badge{border-radius:8px;font-size:10px;letter-spacing:0}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-context-chip{border-radius:8px;padding:4px 7px;font-size:10.5px;font-weight:650}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-cta,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-cta{font-size:11.5px}.praxis-ai-assistant-shell__quick-reply--compact{justify-self:start;width:fit-content;min-width:min(100%,210px);max-width:min(100%,320px);padding:9px 11px;border-radius:16px;background:linear-gradient(135deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 10%,transparent),transparent 55%),var(--md-sys-color-surface-container-high);box-shadow:0 8px 18px color-mix(in srgb,var(--praxis-ai-assistant-shell-shadow-color) 16%,transparent),inset 0 1px color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 10%,transparent)}.praxis-ai-assistant-shell__quick-reply.praxis-ai-assistant-shell__quick-reply--compact ::ng-deep .mdc-button__label{align-items:center;gap:10px}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-icon-frame{width:34px;height:34px;border-radius:12px}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-icon{width:19px;height:19px;font-size:19px}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-copy{gap:4px}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-header{align-items:center}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-label{font-size:13px;line-height:1.2}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-badge,.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-cta{display:none}.praxis-ai-assistant-shell__quick-reply ::ng-deep .mdc-button__label{position:relative;z-index:1;min-width:0;display:grid;grid-template-columns:auto minmax(0,1fr);align-items:flex-start;gap:14px;width:100%;height:auto;line-height:normal}.praxis-ai-assistant-shell__quick-reply-ambient{position:absolute;inset:0;pointer-events:none}.praxis-ai-assistant-shell__quick-reply-ambient:before{content:\"\";position:absolute;inset:0 18px auto;height:1px;border-radius:999px;background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 90%,var(--praxis-ai-assistant-shell-highlight-color)),transparent);opacity:.58}.praxis-ai-assistant-shell__quick-reply-ambient:after{content:\"\";position:absolute;top:-34px;right:-44px;width:150px;height:150px;border-radius:999px;background:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 13%,transparent);filter:blur(18px)}.praxis-ai-assistant-shell__quick-reply ::ng-deep .mat-mdc-button-touch-target{height:100%;min-height:48px}.praxis-ai-assistant-shell__quick-reply-icon-frame{flex:0 0 auto;width:46px;height:46px;display:inline-grid;place-items:center;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 34%,transparent);border-radius:17px;color:var(--praxis-ai-assistant-shell-quick-reply-accent);background:linear-gradient(145deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 24%,transparent),color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 6%,transparent));box-shadow:inset 0 1px color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 18%,transparent),0 10px 24px color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 12%,transparent)}.praxis-ai-assistant-shell__quick-reply-icon{width:24px;height:24px;font-size:24px}.praxis-ai-assistant-shell__quick-reply-details{flex:0 0 auto;width:24px;height:24px;display:inline-grid;place-items:center;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 14%,transparent);border-radius:50%;color:var(--md-sys-color-on-surface-variant);background:color-mix(in srgb,var(--md-sys-color-outline) 14%,transparent);font-size:17px;opacity:.9}.praxis-ai-assistant-shell__quick-reply-copy{min-width:0;display:grid;gap:10px;flex:1 1 auto}.praxis-ai-assistant-shell__quick-reply-header{min-width:0;display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.praxis-ai-assistant-shell__quick-reply-heading{min-width:0;display:grid;gap:5px}.praxis-ai-assistant-shell__quick-reply-actions{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:flex-end;gap:7px;max-width:46%}.praxis-ai-assistant-shell__quick-reply-label,.praxis-ai-assistant-shell__quick-reply-description{min-width:0;overflow-wrap:anywhere}.praxis-ai-assistant-shell__quick-reply-label{color:var(--md-sys-color-on-surface);font-size:17px;font-weight:760;letter-spacing:.005em;line-height:1.18;text-transform:none}.praxis-ai-assistant-shell__quick-reply-badge{flex:0 0 auto;max-width:100%;padding:4px 8px;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 28%,transparent);border-radius:999px;color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 86%,var(--praxis-ai-assistant-shell-highlight-color));background:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 11%,transparent);font-size:10.5px;font-weight:700;letter-spacing:.02em;line-height:1.1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.praxis-ai-assistant-shell__quick-reply-description{color:color-mix(in srgb,var(--md-sys-color-on-surface) 80%,transparent);font-size:13px;line-height:1.46}.praxis-ai-assistant-shell__quick-reply-context{display:flex;flex-wrap:wrap;gap:7px;align-items:center}.praxis-ai-assistant-shell__quick-reply-context-chip{min-width:0;display:inline-flex;align-items:center;gap:4px;max-width:100%;padding:5px 8px;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 22%,transparent);border-radius:999px;color:color-mix(in srgb,var(--md-sys-color-on-surface) 82%,transparent);background:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 9%,transparent);font-size:11px;font-weight:650;line-height:1.15}.praxis-ai-assistant-shell__quick-reply-context-chip mat-icon{width:14px;height:14px;color:var(--praxis-ai-assistant-shell-quick-reply-accent);font-size:14px}.praxis-ai-assistant-shell__quick-reply-context-chip span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.praxis-ai-assistant-shell__quick-reply-insights{display:grid;grid-template-columns:repeat(auto-fit,minmax(145px,1fr));gap:8px;padding:8px;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 16%,transparent);border-radius:16px;background:linear-gradient(180deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 5%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-lowest) 26%,transparent))}.praxis-ai-assistant-shell__quick-reply-insight{min-width:0;display:grid;grid-template-columns:20px minmax(0,1fr);gap:8px;align-items:start;padding:8px;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 10%,transparent);border-radius:13px;color:color-mix(in srgb,var(--md-sys-color-on-surface) 86%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container-high) 44%,transparent);font-size:12px;line-height:1.35}.praxis-ai-assistant-shell__quick-reply-insight mat-icon{width:17px;height:17px;color:var(--praxis-ai-assistant-shell-quick-reply-accent);font-size:17px;opacity:.9}.praxis-ai-assistant-shell__quick-reply-insight-copy{min-width:0;display:grid;gap:1px}.praxis-ai-assistant-shell__quick-reply-insight-label{color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 82%,var(--praxis-ai-assistant-shell-highlight-color));font-size:10.5px;font-weight:760;letter-spacing:.045em;line-height:1.2;text-transform:uppercase}.praxis-ai-assistant-shell__quick-reply-insight-value{min-width:0;overflow-wrap:anywhere}.praxis-ai-assistant-shell__quick-reply-cta{display:inline-flex;align-items:center;justify-self:start;gap:5px;padding:3px 0;color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 84%,var(--praxis-ai-assistant-shell-highlight-color));font-size:12px;font-weight:760;letter-spacing:.01em;line-height:1.2}.praxis-ai-assistant-shell__quick-reply-cta mat-icon{width:15px;height:15px;font-size:15px;transition:transform .16s ease}.praxis-ai-assistant-shell__quick-reply:hover:not(:disabled) .praxis-ai-assistant-shell__quick-reply-cta mat-icon,.praxis-ai-assistant-shell__quick-reply:focus-visible .praxis-ai-assistant-shell__quick-reply-cta mat-icon{transform:translate(2px)}.praxis-ai-assistant-shell__quick-reply--tone-analytics{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-analytics)}.praxis-ai-assistant-shell__quick-reply--tone-resource{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-resource)}.praxis-ai-assistant-shell__quick-reply--tone-warning{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-warning)}.praxis-ai-assistant-shell__quick-reply--tone-success{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-success)}.praxis-ai-assistant-shell__quick-reply--tone-danger{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-danger)}.praxis-ai-assistant-shell__quick-reply--tone-neutral{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-neutral)}@media(max-width:640px){.praxis-ai-assistant-shell__quick-reply{padding:13px;border-radius:19px}.praxis-ai-assistant-shell__quick-reply ::ng-deep .mdc-button__label{grid-template-columns:minmax(0,1fr);gap:10px}.praxis-ai-assistant-shell__quick-reply-icon-frame{width:38px;height:38px;border-radius:14px}.praxis-ai-assistant-shell__quick-reply-header{display:grid}.praxis-ai-assistant-shell__quick-reply-actions{justify-content:flex-start;max-width:100%}.praxis-ai-assistant-shell__quick-reply-insights{grid-template-columns:minmax(0,1fr)}}.praxis-ai-assistant-shell__status,.praxis-ai-assistant-shell__error{margin:0;font-size:13px;line-height:1.35;overflow-wrap:anywhere}.praxis-ai-assistant-shell__footer{flex:0 0 auto;padding:8px 10px 10px;border-top:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent);background:var(--md-sys-color-surface-container-low)}.praxis-ai-assistant-shell__composer{display:grid;gap:8px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-lowest);box-shadow:inset 0 1px color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 4%,transparent)}.praxis-ai-assistant-shell__composer:focus-within{border-color:var(--md-sys-color-primary);box-shadow:0 0 0 2px color-mix(in srgb,var(--md-sys-color-primary) 16%,transparent)}.praxis-ai-assistant-shell__composer-actions{display:flex;align-items:center;justify-content:flex-end;gap:8px;padding:0 8px 7px;flex-wrap:wrap}.praxis-ai-assistant-shell__action{min-height:36px;border-radius:10px;font-weight:650}.praxis-ai-assistant-shell__action mat-icon{width:18px;height:18px;margin-right:6px;font-size:18px}.praxis-ai-assistant-shell__action--icon-only{width:40px;min-width:40px;height:40px;padding-inline:0;border-radius:50%}.praxis-ai-assistant-shell__action--icon-only mat-icon{margin-right:0}.praxis-ai-assistant-shell__action--secondary{color:var(--md-sys-color-on-surface-variant)}.praxis-ai-assistant-shell__action--tone-governance{color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent)}.praxis-ai-assistant-shell__action--tone-success{color:var(--praxis-ai-assistant-shell-tone-success);background:color-mix(in srgb,var(--praxis-ai-assistant-shell-tone-success) 10%,transparent)}.praxis-ai-assistant-shell__action--tone-warning{color:var(--praxis-ai-assistant-shell-tone-warning);background:color-mix(in srgb,var(--praxis-ai-assistant-shell-tone-warning) 10%,transparent)}.praxis-ai-assistant-shell__action--tone-danger{color:var(--md-sys-color-error);background:color-mix(in srgb,var(--md-sys-color-error) 10%,transparent)}.praxis-ai-assistant-shell__resize-handle{position:absolute;z-index:2;border:0;background:transparent;touch-action:none}.praxis-ai-assistant-shell__resize-handle--n,.praxis-ai-assistant-shell__resize-handle--s{left:16px;right:16px;height:10px;cursor:ns-resize}.praxis-ai-assistant-shell__resize-handle--n{top:-5px}.praxis-ai-assistant-shell__resize-handle--s{bottom:-5px}.praxis-ai-assistant-shell__resize-handle--e,.praxis-ai-assistant-shell__resize-handle--w{top:16px;bottom:16px;width:10px;cursor:ew-resize}.praxis-ai-assistant-shell__resize-handle--e{right:-5px}.praxis-ai-assistant-shell__resize-handle--w{left:-5px}.praxis-ai-assistant-shell__resize-handle--ne,.praxis-ai-assistant-shell__resize-handle--nw,.praxis-ai-assistant-shell__resize-handle--se,.praxis-ai-assistant-shell__resize-handle--sw{width:22px;height:22px}.praxis-ai-assistant-shell__resize-handle--ne{top:-5px;right:-5px;cursor:nesw-resize}.praxis-ai-assistant-shell__resize-handle--nw{top:-5px;left:-5px;cursor:nwse-resize}.praxis-ai-assistant-shell__resize-handle--se{right:-5px;bottom:-5px;cursor:nwse-resize}.praxis-ai-assistant-shell__resize-handle--sw{bottom:-5px;left:-5px;cursor:nesw-resize}.praxis-ai-assistant-shell__resize-handle--se:after{content:\"\";position:absolute;right:8px;bottom:8px;width:10px;height:10px;border-right:2px solid var(--md-sys-color-outline);border-bottom:2px solid var(--md-sys-color-outline)}\n"] }]
|
|
7919
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<section\n #panel\n class=\"praxis-ai-assistant-shell\"\n role=\"dialog\"\n [attr.aria-label]=\"resolvedLabels.title\"\n [attr.aria-busy]=\"busy ? 'true' : null\"\n [style.left.px]=\"currentLayout.left\"\n [style.top.px]=\"currentLayout.top\"\n [style.width.px]=\"currentLayout.width\"\n [style.height.px]=\"currentLayout.height\"\n [attr.data-testid]=\"panelTestId || testIdPrefix\"\n>\n <header\n class=\"praxis-ai-assistant-shell__header\"\n [attr.data-testid]=\"testIdPrefix + '-drag-handle'\"\n [attr.aria-label]=\"resolvedLabels.dragHandleAria\"\n (pointerdown)=\"startDrag($event)\"\n >\n <div class=\"praxis-ai-assistant-shell__identity\" aria-hidden=\"true\">\n <mat-icon>auto_awesome</mat-icon>\n </div>\n <div class=\"praxis-ai-assistant-shell__title-group\">\n <div class=\"praxis-ai-assistant-shell__title-row\">\n <strong>{{ resolvedLabels.title }}</strong>\n <div class=\"praxis-ai-assistant-shell__badges\" aria-hidden=\"true\">\n <span class=\"praxis-ai-assistant-shell__badge praxis-ai-assistant-shell__badge--context\">\n {{ getModeLabel() }}\n </span>\n <span\n class=\"praxis-ai-assistant-shell__badge praxis-ai-assistant-shell__badge--state\"\n [class.praxis-ai-assistant-shell__badge--error]=\"state === 'error'\"\n >\n <span class=\"praxis-ai-assistant-shell__state-dot\" aria-hidden=\"true\"></span>\n {{ getStateLabel() }}\n </span>\n </div>\n </div>\n <p *ngIf=\"resolvedLabels.subtitle\">{{ resolvedLabels.subtitle }}</p>\n </div>\n <div class=\"praxis-ai-assistant-shell__header-actions\">\n <button\n mat-icon-button\n type=\"button\"\n [matTooltip]=\"resolvedLabels.close\"\n [attr.aria-label]=\"resolvedLabels.close\"\n (pointerdown)=\"$event.stopPropagation()\"\n (click)=\"close.emit()\"\n [attr.data-testid]=\"testIdPrefix + '-close'\"\n >\n <mat-icon>{{ getCloseIcon() }}</mat-icon>\n </button>\n </div>\n </header>\n\n <div class=\"praxis-ai-assistant-shell__body\">\n <div\n *ngIf=\"contextItems.length\"\n class=\"praxis-ai-assistant-shell__context\"\n [attr.aria-label]=\"resolvedLabels.contextAria\"\n [attr.data-testid]=\"testIdPrefix + '-context'\"\n >\n <span\n *ngFor=\"let item of contextItems; trackBy: trackContextItem\"\n class=\"praxis-ai-assistant-shell__context-item\"\n [attr.data-testid]=\"testIdPrefix + '-context-' + item.id\"\n >\n <mat-icon *ngIf=\"item.icon\" aria-hidden=\"true\">{{ item.icon }}</mat-icon>\n <span class=\"praxis-ai-assistant-shell__context-label\">{{ item.label }}</span>\n <span *ngIf=\"item.value\" class=\"praxis-ai-assistant-shell__context-value\">{{ item.value }}</span>\n </span>\n </div>\n\n <div\n #conversation\n class=\"praxis-ai-assistant-shell__conversation\"\n [attr.data-testid]=\"testIdPrefix + '-conversation'\"\n [attr.aria-label]=\"resolvedLabels.conversationAria\"\n >\n <article\n *ngIf=\"!messages.length\"\n class=\"praxis-ai-assistant-shell__message praxis-ai-assistant-shell__message--assistant\"\n [attr.data-testid]=\"testIdPrefix + '-message-assistant-empty'\"\n >\n {{ resolvedLabels.emptyConversation }}\n </article>\n <article\n *ngFor=\"let message of messages; trackBy: trackMessage\"\n class=\"praxis-ai-assistant-shell__message\"\n [class.praxis-ai-assistant-shell__message--user]=\"message.role === 'user'\"\n [class.praxis-ai-assistant-shell__message--assistant]=\"message.role === 'assistant'\"\n [class.praxis-ai-assistant-shell__message--status]=\"message.role === 'status'\"\n [class.praxis-ai-assistant-shell__message--error]=\"message.role === 'error'\"\n [attr.data-testid]=\"testIdPrefix + '-message-' + message.role\"\n >\n <div\n class=\"praxis-ai-assistant-shell__message-content\"\n [innerHTML]=\"renderMessageText(message.text)\"\n ></div>\n <div\n *ngIf=\"message.actions?.length || message.editable || message.resendable\"\n class=\"praxis-ai-assistant-shell__message-actions\"\n >\n <button\n *ngIf=\"message.editable\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.editMessage\"\n [attr.aria-label]=\"resolvedLabels.editMessage\"\n [attr.data-testid]=\"testIdPrefix + '-message-edit-' + message.id\"\n (click)=\"onMessageAction(message, { id: 'edit', label: resolvedLabels.editMessage, kind: 'edit' })\"\n >\n <mat-icon aria-hidden=\"true\">edit</mat-icon>\n </button>\n <button\n *ngIf=\"message.resendable\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.resendMessage\"\n [attr.aria-label]=\"resolvedLabels.resendMessage\"\n [attr.data-testid]=\"testIdPrefix + '-message-resend-' + message.id\"\n (click)=\"onMessageAction(message, { id: 'resend', label: resolvedLabels.resendMessage, kind: 'resend' })\"\n >\n <mat-icon aria-hidden=\"true\">replay</mat-icon>\n </button>\n <ng-container *ngFor=\"let action of message.actions || []; trackBy: trackMessageAction\">\n <button\n *ngIf=\"isMessageActionIconOnly(action); else textualMessageAction\"\n mat-icon-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action praxis-ai-assistant-shell__message-action--icon\"\n [disabled]=\"busy || action.disabled\"\n [matTooltip]=\"getMessageActionLabel(action)\"\n [attr.aria-label]=\"getMessageActionLabel(action)\"\n [attr.data-testid]=\"testIdPrefix + '-message-action-' + message.id + '-' + action.id\"\n (click)=\"onMessageAction(message, action)\"\n >\n <mat-icon aria-hidden=\"true\">{{ getMessageActionIcon(action) }}</mat-icon>\n </button>\n <ng-template #textualMessageAction>\n <button\n mat-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__message-action\"\n [disabled]=\"busy || action.disabled\"\n [attr.aria-label]=\"getMessageActionLabel(action)\"\n [attr.data-testid]=\"testIdPrefix + '-message-action-' + message.id + '-' + action.id\"\n (click)=\"onMessageAction(message, action)\"\n >\n {{ action.label }}\n </button>\n </ng-template>\n </ng-container>\n </div>\n </article>\n </div>\n\n <div\n *ngIf=\"attachments.length\"\n class=\"praxis-ai-assistant-shell__attachments\"\n [attr.aria-label]=\"resolvedLabels.attachmentsAria\"\n [attr.data-testid]=\"testIdPrefix + '-attachments'\"\n >\n <div\n *ngFor=\"let attachment of attachments; trackBy: trackAttachment\"\n class=\"praxis-ai-assistant-shell__attachment\"\n [class.praxis-ai-assistant-shell__attachment--error]=\"attachment.status === 'error'\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-' + attachment.id\"\n >\n <img\n *ngIf=\"attachment.previewUrl && attachment.kind === 'image'\"\n class=\"praxis-ai-assistant-shell__attachment-preview\"\n [src]=\"attachment.previewUrl\"\n [alt]=\"attachment.name\"\n >\n <span class=\"praxis-ai-assistant-shell__attachment-name\">{{ attachment.name }}</span>\n <span class=\"praxis-ai-assistant-shell__attachment-kind\">{{ attachment.kind }}</span>\n <button\n mat-icon-button\n type=\"button\"\n [disabled]=\"busy\"\n [matTooltip]=\"resolvedLabels.removeAttachment\"\n [attr.aria-label]=\"resolvedLabels.removeAttachment + ': ' + attachment.name\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-remove-' + attachment.id\"\n (click)=\"onRemoveAttachment(attachment)\"\n >\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n\n <div\n *ngIf=\"quickReplies.length\"\n class=\"praxis-ai-assistant-shell__quick-replies\"\n [class.praxis-ai-assistant-shell__quick-replies--inline]=\"shouldUseInlineQuickReplies()\"\n [attr.data-testid]=\"testIdPrefix + '-quick-replies'\"\n [attr.aria-label]=\"resolvedLabels.quickRepliesAria\"\n >\n <button\n *ngFor=\"let reply of quickReplies; trackBy: trackQuickReply\"\n mat-stroked-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__quick-reply\"\n [class.praxis-ai-assistant-shell__quick-reply--compact]=\"!isRichQuickReply(reply)\"\n [class.praxis-ai-assistant-shell__quick-reply--guided-action]=\"isGuidedActionQuickReply(reply)\"\n [class.praxis-ai-assistant-shell__quick-reply--contextual-action]=\"isContextualPreviewActionQuickReply(reply)\"\n [ngClass]=\"'praxis-ai-assistant-shell__quick-reply--tone-' + getQuickReplyTone(reply)\"\n [attr.data-testid]=\"testIdPrefix + '-quick-reply-' + (reply.id || reply.kind)\"\n [attr.aria-label]=\"getQuickReplyAriaLabel(reply)\"\n [disabled]=\"busy\"\n (click)=\"onQuickReply(reply)\"\n >\n <span class=\"praxis-ai-assistant-shell__quick-reply-ambient\" aria-hidden=\"true\"></span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-icon-frame\" aria-hidden=\"true\">\n <mat-icon\n class=\"praxis-ai-assistant-shell__quick-reply-icon\"\n >\n {{ getQuickReplyIcon(reply) }}\n </mat-icon>\n </span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-copy\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-header\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-heading\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-label\">{{ reply.label }}</span>\n <span\n *ngIf=\"getQuickReplyDescription(reply)\"\n class=\"praxis-ai-assistant-shell__quick-reply-description\"\n >\n {{ getQuickReplyDescription(reply) }}\n </span>\n </span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-actions\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-badge\">\n {{ getQuickReplyCategoryLabel(reply) }}\n </span>\n <mat-icon\n *ngIf=\"getQuickReplyTechnicalDetails(reply)\"\n class=\"praxis-ai-assistant-shell__quick-reply-details\"\n [matTooltip]=\"getQuickReplyTechnicalDetails(reply)\"\n [attr.aria-label]=\"resolvedLabels.quickReplyDetails\"\n >\n info\n </mat-icon>\n </span>\n </span>\n <span\n *ngIf=\"getQuickReplyContextChips(reply).length\"\n class=\"praxis-ai-assistant-shell__quick-reply-context\"\n >\n <span\n *ngFor=\"let chip of getQuickReplyContextChips(reply)\"\n class=\"praxis-ai-assistant-shell__quick-reply-context-chip\"\n [attr.aria-label]=\"chip.ariaLabel\"\n >\n <mat-icon aria-hidden=\"true\">{{ chip.icon }}</mat-icon>\n <span>{{ chip.value }}</span>\n </span>\n </span>\n <span\n *ngIf=\"getQuickReplyPresentationItems(reply).length\"\n class=\"praxis-ai-assistant-shell__quick-reply-insights\"\n >\n <span\n *ngFor=\"let item of getQuickReplyPresentationItems(reply)\"\n class=\"praxis-ai-assistant-shell__quick-reply-insight\"\n >\n <mat-icon aria-hidden=\"true\">{{ item.icon }}</mat-icon>\n <span class=\"praxis-ai-assistant-shell__quick-reply-insight-copy\">\n <span class=\"praxis-ai-assistant-shell__quick-reply-insight-label\">\n {{ item.label }}\n </span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-insight-value\">\n {{ item.value }}\n </span>\n </span>\n </span>\n </span>\n <span class=\"praxis-ai-assistant-shell__quick-reply-cta\">\n {{ getQuickReplyCtaLabel(reply) }}\n <mat-icon aria-hidden=\"true\">arrow_forward</mat-icon>\n </span>\n </span>\n </button>\n </div>\n <p\n *ngIf=\"shouldShowStatusText()\"\n class=\"praxis-ai-assistant-shell__status\"\n [attr.data-testid]=\"testIdPrefix + '-status'\"\n >\n {{ statusText }}\n </p>\n <p\n *ngIf=\"shouldShowErrorText()\"\n class=\"praxis-ai-assistant-shell__error\"\n [attr.data-testid]=\"testIdPrefix + '-error'\"\n >\n {{ errorText }}\n </p>\n </div>\n\n <footer class=\"praxis-ai-assistant-shell__footer\">\n <label class=\"praxis-ai-assistant-shell__label\" for=\"praxis-ai-assistant-shell-prompt\">\n {{ resolvedLabels.prompt }}\n </label>\n <div class=\"praxis-ai-assistant-shell__composer\">\n <textarea\n id=\"praxis-ai-assistant-shell-prompt\"\n class=\"praxis-ai-assistant-shell__prompt\"\n [attr.data-testid]=\"testIdPrefix + '-prompt'\"\n [placeholder]=\"resolvedLabels.promptPlaceholder\"\n [ngModel]=\"currentPrompt\"\n [disabled]=\"busy\"\n (ngModelChange)=\"onPromptInput($event)\"\n (keydown)=\"onPromptKeydown($event)\"\n (paste)=\"onPromptPaste($event)\"\n ></textarea>\n <div class=\"praxis-ai-assistant-shell__composer-actions\">\n <ng-container *ngIf=\"showAttachAction\">\n <input\n #attachmentInput\n type=\"file\"\n hidden\n [attr.accept]=\"attachmentAccept || null\"\n [attr.multiple]=\"attachmentMultiple ? '' : null\"\n [attr.data-testid]=\"testIdPrefix + '-attachment-input'\"\n (change)=\"onAttachmentFilesSelected($event)\"\n >\n <button\n mat-stroked-button\n type=\"button\"\n [disabled]=\"busy\"\n (click)=\"onAttachClick(attachmentInput)\"\n [attr.data-testid]=\"testIdPrefix + '-attach'\"\n >\n <mat-icon>attach_file</mat-icon>\n {{ resolvedLabels.attach }}\n </button>\n </ng-container>\n <button\n mat-flat-button\n color=\"primary\"\n type=\"button\"\n class=\"praxis-ai-assistant-shell__action praxis-ai-assistant-shell__action--primary\"\n [class.praxis-ai-assistant-shell__action--icon-only]=\"getPrimaryAction().iconOnly\"\n [matTooltip]=\"getPrimaryActionTooltip(getPrimaryAction())\"\n [ngClass]=\"'praxis-ai-assistant-shell__action--tone-' + getShellActionTone(getPrimaryAction())\"\n [disabled]=\"isShellActionDisabled(getPrimaryAction())\"\n (click)=\"onShellAction(getPrimaryAction())\"\n [attr.data-testid]=\"getPrimaryAction().testId || (submitTestId || (testIdPrefix + '-submit'))\"\n [attr.aria-label]=\"getPrimaryAction().ariaLabel || getPrimaryAction().label\"\n >\n <mat-icon *ngIf=\"getPrimaryAction().icon\" aria-hidden=\"true\">{{ getPrimaryAction().icon }}</mat-icon>\n <span *ngIf=\"!getPrimaryAction().iconOnly\">{{ getPrimaryAction().label }}</span>\n </button>\n <button\n *ngFor=\"let action of getSecondaryActions(); trackBy: trackShellAction\"\n mat-button\n type=\"button\"\n class=\"praxis-ai-assistant-shell__action praxis-ai-assistant-shell__action--secondary\"\n [ngClass]=\"'praxis-ai-assistant-shell__action--tone-' + getShellActionTone(action)\"\n [disabled]=\"isShellActionDisabled(action)\"\n (click)=\"onShellAction(action)\"\n [attr.data-testid]=\"action.testId || (testIdPrefix + '-action-' + action.id)\"\n [attr.aria-label]=\"action.ariaLabel || action.label\"\n >\n <mat-icon *ngIf=\"action.icon\" aria-hidden=\"true\">{{ action.icon }}</mat-icon>\n {{ action.label }}\n </button>\n <mat-spinner *ngIf=\"busy\" diameter=\"20\" [attr.data-testid]=\"testIdPrefix + '-spinner'\"></mat-spinner>\n </div>\n </div>\n </footer>\n\n <ng-container *ngIf=\"resizable\">\n <span\n *ngFor=\"let direction of resizeHandles; trackBy: trackResizeHandle\"\n class=\"praxis-ai-assistant-shell__resize-handle praxis-ai-assistant-shell__resize-handle--{{ direction }}\"\n [attr.data-testid]=\"direction === 'se' ? testIdPrefix + '-resize-handle' : testIdPrefix + '-resize-handle-' + direction\"\n aria-hidden=\"true\"\n role=\"presentation\"\n (pointerdown)=\"startResize(direction, $event)\"\n ></span>\n </ng-container>\n</section>\n", styles: [":host{display:block}.praxis-ai-assistant-shell{--praxis-ai-assistant-shell-shadow-color: var(--md-sys-color-shadow);--praxis-ai-assistant-shell-highlight-color: var(--md-sys-color-on-surface);--praxis-ai-assistant-shell-tone-analytics: var(--md-sys-color-primary);--praxis-ai-assistant-shell-tone-resource: var(--md-sys-color-tertiary);--praxis-ai-assistant-shell-tone-success: var(--md-sys-color-tertiary);--praxis-ai-assistant-shell-tone-warning: var(--md-sys-color-secondary);--praxis-ai-assistant-shell-tone-danger: var(--md-sys-color-error);--praxis-ai-assistant-shell-tone-neutral: var(--md-sys-color-outline);position:fixed;box-sizing:border-box;min-width:360px;min-height:360px;display:flex;flex-direction:column;overflow:hidden;color:var(--md-sys-color-on-surface);border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface);box-shadow:0 24px 60px color-mix(in srgb,var(--praxis-ai-assistant-shell-shadow-color) 40%,transparent);z-index:var(--praxis-ai-assistant-shell-z-index, 1200)}.praxis-ai-assistant-shell__header{flex:0 0 auto;display:flex;align-items:flex-start;gap:9px;padding:10px 10px 9px;border-color:color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent);background:var(--md-sys-color-surface-container)}.praxis-ai-assistant-shell__header{justify-content:flex-start;border-bottom:1px solid;cursor:move;touch-action:none}.praxis-ai-assistant-shell__identity{flex:0 0 auto;display:grid;place-items:center;width:30px;height:30px;border-radius:8px;background:var(--md-sys-color-primary);color:var(--md-sys-color-on-primary);box-shadow:0 6px 16px color-mix(in srgb,var(--md-sys-color-primary) 22%,transparent)}.praxis-ai-assistant-shell__identity mat-icon{width:18px;height:18px;font-size:18px}.praxis-ai-assistant-shell__title-group{min-width:0;flex:1 1 auto;display:grid;gap:4px}.praxis-ai-assistant-shell__title-row{min-width:0;display:flex;align-items:center;gap:8px}.praxis-ai-assistant-shell__badges{flex:0 0 auto;display:flex;align-items:center;justify-content:flex-end;gap:4px;min-width:0;flex-wrap:wrap}.praxis-ai-assistant-shell__badge{display:inline-flex;align-items:center;gap:5px;min-height:20px;max-width:120px;padding:2px 7px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 80%,transparent);border-radius:8px;color:var(--md-sys-color-on-surface-variant);background:var(--md-sys-color-surface-container-high);font-size:11px;line-height:1.2;overflow-wrap:anywhere}.praxis-ai-assistant-shell__badge--context{color:var(--md-sys-color-on-surface);background:color-mix(in srgb,var(--md-sys-color-primary) 9%,var(--md-sys-color-surface-container-high))}.praxis-ai-assistant-shell__badge--state{border-color:transparent;background:transparent;color:var(--md-sys-color-on-surface-variant);padding-inline:3px}.praxis-ai-assistant-shell__badge--error{color:var(--md-sys-color-error);border-color:color-mix(in srgb,var(--md-sys-color-error) 60%,transparent)}.praxis-ai-assistant-shell__state-dot{flex:0 0 auto;width:6px;height:6px;border-radius:999px;background:var(--md-sys-color-primary);box-shadow:0 0 0 2px color-mix(in srgb,var(--md-sys-color-primary) 16%,transparent)}.praxis-ai-assistant-shell__badge--error .praxis-ai-assistant-shell__state-dot{background:var(--md-sys-color-error);box-shadow:0 0 0 2px color-mix(in srgb,var(--md-sys-color-error) 16%,transparent)}.praxis-ai-assistant-shell__title-group strong,.praxis-ai-assistant-shell__title-group p{min-width:0;margin:0;overflow-wrap:anywhere}.praxis-ai-assistant-shell__title-group strong{flex:1 1 auto;font-size:13px;line-height:1.2}.praxis-ai-assistant-shell__title-group p{color:var(--md-sys-color-on-surface-variant);font-size:11.5px;line-height:1.3}.praxis-ai-assistant-shell__header-actions{flex:0 0 auto;display:flex;align-items:center;gap:2px;margin-top:-3px}.praxis-ai-assistant-shell__header-actions button{display:inline-grid;place-items:center;width:34px;height:34px;padding:0;color:var(--md-sys-color-on-surface-variant);line-height:1;opacity:.78}.praxis-ai-assistant-shell__header-actions button:hover,.praxis-ai-assistant-shell__header-actions button:focus-visible{opacity:1}.praxis-ai-assistant-shell__header-actions mat-icon{display:block;width:18px;height:18px;font-size:18px;line-height:18px}.praxis-ai-assistant-shell__body{min-height:0;flex:1 1 auto;display:flex;flex-direction:column;gap:10px;padding:12px 12px 10px;overflow:auto;background:linear-gradient(180deg,var(--md-sys-color-surface-container-low),var(--md-sys-color-surface))}.praxis-ai-assistant-shell__context,.praxis-ai-assistant-shell__attachments{flex:0 0 auto;display:flex;align-items:center;gap:8px;overflow-x:auto}.praxis-ai-assistant-shell__context-item{flex:0 0 auto;display:inline-flex;align-items:center;gap:5px;max-width:240px;padding:5px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface-container-high);font-size:12px;line-height:1.25}.praxis-ai-assistant-shell__context-item mat-icon{width:16px;height:16px;font-size:16px}.praxis-ai-assistant-shell__context-label,.praxis-ai-assistant-shell__context-value{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.praxis-ai-assistant-shell__context-label{color:var(--md-sys-color-on-surface)}.praxis-ai-assistant-shell__context-value{color:var(--md-sys-color-on-surface-variant)}.praxis-ai-assistant-shell__label{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.praxis-ai-assistant-shell__prompt{box-sizing:border-box;width:100%;min-height:46px;max-height:96px;resize:none;border:0;padding:10px 12px 8px;color:var(--md-sys-color-on-surface);background:transparent;font:inherit;line-height:1.45;outline:none}.praxis-ai-assistant-shell__conversation{min-height:0;flex:1 1 auto;display:flex;flex-direction:column;gap:8px;overflow:auto;padding:2px}.praxis-ai-assistant-shell__message{max-width:86%;align-self:flex-start;padding:9px 11px;border-radius:8px;background:var(--md-sys-color-surface-container-high);color:var(--md-sys-color-on-surface);font-size:13px;line-height:1.35;overflow-wrap:anywhere}.praxis-ai-assistant-shell__message-content{white-space:normal}.praxis-ai-assistant-shell__message-content :where(p,ul,h3,h4,h5){margin:0}.praxis-ai-assistant-shell__message-content :where(p,ul,h3,h4,h5)+:where(p,ul,h3,h4,h5){margin-top:8px}.praxis-ai-assistant-shell__message-content ul{padding-left:18px}.praxis-ai-assistant-shell__message-content li+li{margin-top:4px}.praxis-ai-assistant-shell__message-content code{padding:1px 4px;border-radius:4px;background:color-mix(in srgb,var(--md-sys-color-on-surface) 10%,transparent);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.94em}.praxis-ai-assistant-shell__message-actions{display:flex;align-items:center;gap:4px;flex-wrap:wrap;margin-top:8px}.praxis-ai-assistant-shell__message-action{min-height:28px;padding:0 8px;border-radius:8px;font-size:12px}.praxis-ai-assistant-shell__message-action--icon{width:30px;min-width:30px;height:30px;padding:0;color:var(--md-sys-color-on-surface-variant)}.praxis-ai-assistant-shell__message-action--icon mat-icon{width:17px;height:17px;font-size:17px}.praxis-ai-assistant-shell__message--assistant{border-bottom-left-radius:2px}.praxis-ai-assistant-shell__message--user{align-self:flex-end;border-bottom-right-radius:2px;background:var(--md-sys-color-primary-container);color:var(--md-sys-color-on-primary-container)}.praxis-ai-assistant-shell__message--status{color:var(--md-sys-color-on-surface-variant)}.praxis-ai-assistant-shell__message--error,.praxis-ai-assistant-shell__error{color:var(--md-sys-color-error)}.praxis-ai-assistant-shell__quick-replies{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,520px),1fr));gap:8px;align-items:stretch;padding-bottom:4px}.praxis-ai-assistant-shell__quick-replies--inline{display:flex;flex-wrap:wrap;align-items:center;gap:6px}.praxis-ai-assistant-shell__attachment{flex:0 0 auto;display:inline-flex;align-items:center;gap:7px;max-width:260px;min-height:34px;padding:4px 4px 4px 8px;border:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 70%,transparent);border-radius:8px;background:var(--md-sys-color-surface-container-high)}.praxis-ai-assistant-shell__attachment--error{border-color:color-mix(in srgb,var(--md-sys-color-error) 60%,transparent)}.praxis-ai-assistant-shell__attachment-preview{flex:0 0 auto;width:28px;height:28px;border-radius:6px;object-fit:cover}.praxis-ai-assistant-shell__attachment-name,.praxis-ai-assistant-shell__attachment-kind{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px}.praxis-ai-assistant-shell__attachment-name{color:var(--md-sys-color-on-surface)}.praxis-ai-assistant-shell__attachment-kind{color:var(--md-sys-color-on-surface-variant)}.praxis-ai-assistant-shell__quick-reply{--praxis-ai-assistant-shell-quick-reply-accent: var(--md-sys-color-primary);--praxis-ai-assistant-shell-quick-reply-background: color-mix( in srgb, var(--praxis-ai-assistant-shell-quick-reply-accent) 7%, var(--md-sys-color-surface-container-high) );--praxis-ai-assistant-shell-quick-reply-foreground: var(--md-sys-color-on-surface);width:100%;max-width:100%;height:auto;min-height:0;position:relative;overflow:hidden;padding:15px 16px;align-items:stretch;border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 36%,transparent);border-radius:22px;color:var(--praxis-ai-assistant-shell-quick-reply-foreground);background:linear-gradient(135deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 16%,transparent),transparent 46%),radial-gradient(circle at 92% 10%,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 22%,transparent),transparent 32%),var(--praxis-ai-assistant-shell-quick-reply-background);box-shadow:0 18px 42px color-mix(in srgb,var(--praxis-ai-assistant-shell-shadow-color) 22%,transparent),inset 0 1px color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 16%,transparent);letter-spacing:normal;white-space:normal;text-align:left;text-transform:none;-webkit-user-select:none;user-select:none;transition:border-color .16s ease,box-shadow .16s ease,transform .16s ease,background .16s ease;--mdc-outlined-button-container-height: auto;--mat-outlined-button-horizontal-padding: 0}.praxis-ai-assistant-shell__quick-reply:hover:not(:disabled),.praxis-ai-assistant-shell__quick-reply:focus-visible{border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 74%,transparent);box-shadow:0 18px 42px color-mix(in srgb,var(--praxis-ai-assistant-shell-shadow-color) 24%,transparent),0 0 0 3px color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 18%,transparent),inset 0 1px color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 18%,transparent);transform:translateY(-1px)}.praxis-ai-assistant-shell__quick-reply--contextual-action{padding:10px 12px;border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 34%,transparent);border-radius:8px;background:linear-gradient(90deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 15%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-high) 92%,transparent)),var(--md-sys-color-surface-container-high);box-shadow:none}.praxis-ai-assistant-shell__quick-reply--guided-action{padding:10px 12px;border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 30%,transparent);border-radius:8px;background:linear-gradient(90deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 10%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-high) 96%,transparent)),var(--md-sys-color-surface-container-high);box-shadow:none}.praxis-ai-assistant-shell__quick-reply--contextual-action:hover:not(:disabled),.praxis-ai-assistant-shell__quick-reply--contextual-action:focus-visible,.praxis-ai-assistant-shell__quick-reply--guided-action:hover:not(:disabled),.praxis-ai-assistant-shell__quick-reply--guided-action:focus-visible{border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 62%,transparent);box-shadow:0 0 0 2px color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 15%,transparent);transform:none}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-ambient,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-ambient{display:none}.praxis-ai-assistant-shell__quick-reply--contextual-action ::ng-deep .mdc-button__label,.praxis-ai-assistant-shell__quick-reply--guided-action ::ng-deep .mdc-button__label{gap:10px}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-icon-frame,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-icon-frame{width:34px;height:34px;border-radius:8px;box-shadow:none}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-icon,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-icon{width:19px;height:19px;font-size:19px}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-copy,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-copy{gap:6px}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-label,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-label{font-size:13.5px;font-weight:760;letter-spacing:0}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-description,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-description{display:-webkit-box;overflow:hidden;font-size:12px;line-height:1.34;-webkit-box-orient:vertical;-webkit-line-clamp:2}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-badge,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-badge{border-radius:8px;font-size:10px;letter-spacing:0}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-context-chip{border-radius:8px;padding:4px 7px;font-size:10.5px;font-weight:650}.praxis-ai-assistant-shell__quick-reply--contextual-action .praxis-ai-assistant-shell__quick-reply-cta,.praxis-ai-assistant-shell__quick-reply--guided-action .praxis-ai-assistant-shell__quick-reply-cta{font-size:11.5px}.praxis-ai-assistant-shell__quick-reply--compact{justify-self:start;width:fit-content;min-width:min(100%,210px);max-width:min(100%,320px);padding:9px 11px;border-radius:16px;background:linear-gradient(135deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 10%,transparent),transparent 55%),var(--md-sys-color-surface-container-high);box-shadow:0 8px 18px color-mix(in srgb,var(--praxis-ai-assistant-shell-shadow-color) 16%,transparent),inset 0 1px color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 10%,transparent)}.praxis-ai-assistant-shell__quick-reply.praxis-ai-assistant-shell__quick-reply--compact ::ng-deep .mdc-button__label{align-items:center;gap:10px}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-icon-frame{width:34px;height:34px;border-radius:12px}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-icon{width:19px;height:19px;font-size:19px}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-copy{gap:4px}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-header{align-items:center}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-label{font-size:13px;line-height:1.2}.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-badge,.praxis-ai-assistant-shell__quick-reply--compact .praxis-ai-assistant-shell__quick-reply-cta{display:none}.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply{width:auto;min-width:0;max-width:100%;padding:6px 10px;border-radius:999px;box-shadow:none}.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply--guided-action{border-color:color-mix(in srgb,var(--md-sys-color-outline-variant) 76%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container-high) 96%,transparent)}.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply--guided-action:hover:not(:disabled),.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply--guided-action:focus-visible{border-color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 52%,transparent);background:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 9%,var(--md-sys-color-surface-container-high));box-shadow:0 0 0 2px color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 12%,transparent)}.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply ::ng-deep .mdc-button__label{display:inline-flex;grid-template-columns:none;align-items:center;gap:6px;width:auto}.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply ::ng-deep .mat-mdc-button-touch-target{min-height:34px}.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply-icon-frame{width:18px;height:18px;border:0;border-radius:0;background:transparent;box-shadow:none}.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply-icon{width:16px;height:16px;color:var(--praxis-ai-assistant-shell-quick-reply-accent);font-size:16px}.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply-copy,.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply-heading,.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply-header{display:inline-flex;align-items:center;gap:0}.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply-label{color:var(--md-sys-color-on-surface);font-size:12.5px;font-weight:650;line-height:1.2;white-space:nowrap}.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply-description,.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply-actions,.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply-badge,.praxis-ai-assistant-shell__quick-replies--inline .praxis-ai-assistant-shell__quick-reply-cta{display:none}.praxis-ai-assistant-shell__quick-reply ::ng-deep .mdc-button__label{position:relative;z-index:1;min-width:0;display:grid;grid-template-columns:auto minmax(0,1fr);align-items:flex-start;gap:14px;width:100%;height:auto;line-height:normal}.praxis-ai-assistant-shell__quick-reply-ambient{position:absolute;inset:0;pointer-events:none}.praxis-ai-assistant-shell__quick-reply-ambient:before{content:\"\";position:absolute;inset:0 18px auto;height:1px;border-radius:999px;background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 90%,var(--praxis-ai-assistant-shell-highlight-color)),transparent);opacity:.58}.praxis-ai-assistant-shell__quick-reply-ambient:after{content:\"\";position:absolute;top:-34px;right:-44px;width:150px;height:150px;border-radius:999px;background:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 13%,transparent);filter:blur(18px)}.praxis-ai-assistant-shell__quick-reply ::ng-deep .mat-mdc-button-touch-target{height:100%;min-height:48px}.praxis-ai-assistant-shell__quick-reply-icon-frame{flex:0 0 auto;width:46px;height:46px;display:inline-grid;place-items:center;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 34%,transparent);border-radius:17px;color:var(--praxis-ai-assistant-shell-quick-reply-accent);background:linear-gradient(145deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 24%,transparent),color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 6%,transparent));box-shadow:inset 0 1px color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 18%,transparent),0 10px 24px color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 12%,transparent)}.praxis-ai-assistant-shell__quick-reply-icon{width:24px;height:24px;font-size:24px}.praxis-ai-assistant-shell__quick-reply-details{flex:0 0 auto;width:24px;height:24px;display:inline-grid;place-items:center;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 14%,transparent);border-radius:50%;color:var(--md-sys-color-on-surface-variant);background:color-mix(in srgb,var(--md-sys-color-outline) 14%,transparent);font-size:17px;opacity:.9}.praxis-ai-assistant-shell__quick-reply-copy{min-width:0;display:grid;gap:10px;flex:1 1 auto}.praxis-ai-assistant-shell__quick-reply-header{min-width:0;display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.praxis-ai-assistant-shell__quick-reply-heading{min-width:0;display:grid;gap:5px}.praxis-ai-assistant-shell__quick-reply-actions{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:flex-end;gap:7px;max-width:46%}.praxis-ai-assistant-shell__quick-reply-label,.praxis-ai-assistant-shell__quick-reply-description{min-width:0;overflow-wrap:anywhere}.praxis-ai-assistant-shell__quick-reply-label{color:var(--md-sys-color-on-surface);font-size:17px;font-weight:760;letter-spacing:.005em;line-height:1.18;text-transform:none}.praxis-ai-assistant-shell__quick-reply-badge{flex:0 0 auto;max-width:100%;padding:4px 8px;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 28%,transparent);border-radius:999px;color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 86%,var(--praxis-ai-assistant-shell-highlight-color));background:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 11%,transparent);font-size:10.5px;font-weight:700;letter-spacing:.02em;line-height:1.1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.praxis-ai-assistant-shell__quick-reply-description{color:color-mix(in srgb,var(--md-sys-color-on-surface) 80%,transparent);font-size:13px;line-height:1.46}.praxis-ai-assistant-shell__quick-reply-context{display:flex;flex-wrap:wrap;gap:7px;align-items:center}.praxis-ai-assistant-shell__quick-reply-context-chip{min-width:0;display:inline-flex;align-items:center;gap:4px;max-width:100%;padding:5px 8px;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 22%,transparent);border-radius:999px;color:color-mix(in srgb,var(--md-sys-color-on-surface) 82%,transparent);background:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 9%,transparent);font-size:11px;font-weight:650;line-height:1.15}.praxis-ai-assistant-shell__quick-reply-context-chip mat-icon{width:14px;height:14px;color:var(--praxis-ai-assistant-shell-quick-reply-accent);font-size:14px}.praxis-ai-assistant-shell__quick-reply-context-chip span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.praxis-ai-assistant-shell__quick-reply-insights{display:grid;grid-template-columns:repeat(auto-fit,minmax(145px,1fr));gap:8px;padding:8px;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 16%,transparent);border-radius:16px;background:linear-gradient(180deg,color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 5%,transparent),color-mix(in srgb,var(--md-sys-color-surface-container-lowest) 26%,transparent))}.praxis-ai-assistant-shell__quick-reply-insight{min-width:0;display:grid;grid-template-columns:20px minmax(0,1fr);gap:8px;align-items:start;padding:8px;border:1px solid color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 10%,transparent);border-radius:13px;color:color-mix(in srgb,var(--md-sys-color-on-surface) 86%,transparent);background:color-mix(in srgb,var(--md-sys-color-surface-container-high) 44%,transparent);font-size:12px;line-height:1.35}.praxis-ai-assistant-shell__quick-reply-insight mat-icon{width:17px;height:17px;color:var(--praxis-ai-assistant-shell-quick-reply-accent);font-size:17px;opacity:.9}.praxis-ai-assistant-shell__quick-reply-insight-copy{min-width:0;display:grid;gap:1px}.praxis-ai-assistant-shell__quick-reply-insight-label{color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 82%,var(--praxis-ai-assistant-shell-highlight-color));font-size:10.5px;font-weight:760;letter-spacing:.045em;line-height:1.2;text-transform:uppercase}.praxis-ai-assistant-shell__quick-reply-insight-value{min-width:0;overflow-wrap:anywhere}.praxis-ai-assistant-shell__quick-reply-cta{display:inline-flex;align-items:center;justify-self:start;gap:5px;padding:3px 0;color:color-mix(in srgb,var(--praxis-ai-assistant-shell-quick-reply-accent) 84%,var(--praxis-ai-assistant-shell-highlight-color));font-size:12px;font-weight:760;letter-spacing:.01em;line-height:1.2}.praxis-ai-assistant-shell__quick-reply-cta mat-icon{width:15px;height:15px;font-size:15px;transition:transform .16s ease}.praxis-ai-assistant-shell__quick-reply:hover:not(:disabled) .praxis-ai-assistant-shell__quick-reply-cta mat-icon,.praxis-ai-assistant-shell__quick-reply:focus-visible .praxis-ai-assistant-shell__quick-reply-cta mat-icon{transform:translate(2px)}.praxis-ai-assistant-shell__quick-reply--tone-analytics{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-analytics)}.praxis-ai-assistant-shell__quick-reply--tone-resource{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-resource)}.praxis-ai-assistant-shell__quick-reply--tone-warning{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-warning)}.praxis-ai-assistant-shell__quick-reply--tone-success{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-success)}.praxis-ai-assistant-shell__quick-reply--tone-danger{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-danger)}.praxis-ai-assistant-shell__quick-reply--tone-neutral{--praxis-ai-assistant-shell-quick-reply-accent: var(--praxis-ai-assistant-shell-tone-neutral)}@media(max-width:640px){.praxis-ai-assistant-shell__quick-reply{padding:13px;border-radius:19px}.praxis-ai-assistant-shell__quick-reply ::ng-deep .mdc-button__label{grid-template-columns:minmax(0,1fr);gap:10px}.praxis-ai-assistant-shell__quick-reply-icon-frame{width:38px;height:38px;border-radius:14px}.praxis-ai-assistant-shell__quick-reply-header{display:grid}.praxis-ai-assistant-shell__quick-reply-actions{justify-content:flex-start;max-width:100%}.praxis-ai-assistant-shell__quick-reply-insights{grid-template-columns:minmax(0,1fr)}}.praxis-ai-assistant-shell__status,.praxis-ai-assistant-shell__error{margin:0;font-size:13px;line-height:1.35;overflow-wrap:anywhere}.praxis-ai-assistant-shell__footer{flex:0 0 auto;padding:8px 10px 10px;border-top:1px solid color-mix(in srgb,var(--md-sys-color-outline-variant) 72%,transparent);background:var(--md-sys-color-surface-container-low)}.praxis-ai-assistant-shell__composer{display:grid;gap:8px;border:1px solid var(--md-sys-color-outline-variant);border-radius:8px;background:var(--md-sys-color-surface-container-lowest);box-shadow:inset 0 1px color-mix(in srgb,var(--praxis-ai-assistant-shell-highlight-color) 4%,transparent)}.praxis-ai-assistant-shell__composer:focus-within{border-color:var(--md-sys-color-primary);box-shadow:0 0 0 2px color-mix(in srgb,var(--md-sys-color-primary) 16%,transparent)}.praxis-ai-assistant-shell__composer-actions{display:flex;align-items:center;justify-content:flex-end;gap:8px;padding:0 8px 7px;flex-wrap:wrap}.praxis-ai-assistant-shell__action{min-height:36px;border-radius:10px;font-weight:650}.praxis-ai-assistant-shell__action mat-icon{width:18px;height:18px;margin-right:6px;font-size:18px}.praxis-ai-assistant-shell__action--icon-only{width:40px;min-width:40px;height:40px;padding-inline:0;border-radius:50%}.praxis-ai-assistant-shell__action--icon-only mat-icon{margin-right:0}.praxis-ai-assistant-shell__action--secondary{color:var(--md-sys-color-on-surface-variant)}.praxis-ai-assistant-shell__action--tone-governance{color:var(--md-sys-color-primary);background:color-mix(in srgb,var(--md-sys-color-primary) 10%,transparent)}.praxis-ai-assistant-shell__action--tone-success{color:var(--praxis-ai-assistant-shell-tone-success);background:color-mix(in srgb,var(--praxis-ai-assistant-shell-tone-success) 10%,transparent)}.praxis-ai-assistant-shell__action--tone-warning{color:var(--praxis-ai-assistant-shell-tone-warning);background:color-mix(in srgb,var(--praxis-ai-assistant-shell-tone-warning) 10%,transparent)}.praxis-ai-assistant-shell__action--tone-danger{color:var(--md-sys-color-error);background:color-mix(in srgb,var(--md-sys-color-error) 10%,transparent)}.praxis-ai-assistant-shell__resize-handle{position:absolute;z-index:2;border:0;background:transparent;touch-action:none}.praxis-ai-assistant-shell__resize-handle--n,.praxis-ai-assistant-shell__resize-handle--s{left:16px;right:16px;height:10px;cursor:ns-resize}.praxis-ai-assistant-shell__resize-handle--n{top:-5px}.praxis-ai-assistant-shell__resize-handle--s{bottom:-5px}.praxis-ai-assistant-shell__resize-handle--e,.praxis-ai-assistant-shell__resize-handle--w{top:16px;bottom:16px;width:10px;cursor:ew-resize}.praxis-ai-assistant-shell__resize-handle--e{right:-5px}.praxis-ai-assistant-shell__resize-handle--w{left:-5px}.praxis-ai-assistant-shell__resize-handle--ne,.praxis-ai-assistant-shell__resize-handle--nw,.praxis-ai-assistant-shell__resize-handle--se,.praxis-ai-assistant-shell__resize-handle--sw{width:22px;height:22px}.praxis-ai-assistant-shell__resize-handle--ne{top:-5px;right:-5px;cursor:nesw-resize}.praxis-ai-assistant-shell__resize-handle--nw{top:-5px;left:-5px;cursor:nwse-resize}.praxis-ai-assistant-shell__resize-handle--se{right:-5px;bottom:-5px;cursor:nwse-resize}.praxis-ai-assistant-shell__resize-handle--sw{bottom:-5px;left:-5px;cursor:nesw-resize}.praxis-ai-assistant-shell__resize-handle--se:after{content:\"\";position:absolute;right:8px;bottom:8px;width:10px;height:10px;border-right:2px solid var(--md-sys-color-outline);border-bottom:2px solid var(--md-sys-color-outline)}\n"] }]
|
|
7835
7920
|
}], propDecorators: { labels: [{
|
|
7836
7921
|
type: Input
|
|
7837
7922
|
}], mode: [{
|
|
@@ -8128,11 +8213,14 @@ class PraxisAiAssistantSessionHostComponent {
|
|
|
8128
8213
|
ownerType = null;
|
|
8129
8214
|
ownerId = null;
|
|
8130
8215
|
visibility = 'minimized';
|
|
8216
|
+
includeOriginAnchored = false;
|
|
8131
8217
|
sessionOpen = new EventEmitter();
|
|
8132
8218
|
visibleSessions() {
|
|
8133
8219
|
return this.registry.sessions().filter((session) => {
|
|
8134
8220
|
if (this.visibility !== 'all' && session.visibility !== this.visibility)
|
|
8135
8221
|
return false;
|
|
8222
|
+
if (!this.includeOriginAnchored && session.presence === 'origin-anchor')
|
|
8223
|
+
return false;
|
|
8136
8224
|
if (this.ownerType && session.ownerType !== this.ownerType)
|
|
8137
8225
|
return false;
|
|
8138
8226
|
if (this.ownerId && session.ownerId !== this.ownerId)
|
|
@@ -8163,7 +8251,7 @@ class PraxisAiAssistantSessionHostComponent {
|
|
|
8163
8251
|
return value.replace(/[^a-zA-Z0-9_-]+/g, '-');
|
|
8164
8252
|
}
|
|
8165
8253
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.17", ngImport: i0, type: PraxisAiAssistantSessionHostComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8166
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
8254
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "20.3.17", type: PraxisAiAssistantSessionHostComponent, isStandalone: true, selector: "praxis-ai-assistant-session-host", inputs: { testId: "testId", dockTestIdPrefix: "dockTestIdPrefix", ariaLabel: "ariaLabel", openAriaLabel: "openAriaLabel", openTooltip: "openTooltip", ownerType: "ownerType", ownerId: "ownerId", visibility: "visibility", includeOriginAnchored: ["includeOriginAnchored", "includeOriginAnchored", booleanAttribute] }, outputs: { sessionOpen: "sessionOpen" }, ngImport: i0, template: `
|
|
8167
8255
|
<section
|
|
8168
8256
|
*ngIf="visibleSessions().length"
|
|
8169
8257
|
class="praxis-ai-assistant-session-host"
|
|
@@ -8228,6 +8316,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
8228
8316
|
type: Input
|
|
8229
8317
|
}], visibility: [{
|
|
8230
8318
|
type: Input
|
|
8319
|
+
}], includeOriginAnchored: [{
|
|
8320
|
+
type: Input,
|
|
8321
|
+
args: [{ transform: booleanAttribute }]
|
|
8231
8322
|
}], sessionOpen: [{
|
|
8232
8323
|
type: Output
|
|
8233
8324
|
}] } });
|
|
@@ -9029,4 +9120,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.17", ngImpo
|
|
|
9029
9120
|
* Generated bundle index. Do not edit.
|
|
9030
9121
|
*/
|
|
9031
9122
|
|
|
9032
|
-
export { AI_BACKEND_CONFIG_STORE, AI_BACKEND_ENDPOINTS, AI_BACKEND_STORAGE_OPTIONS, AI_CONTRACT_SCHEMA_HASH, AI_CONTRACT_VERSION, AI_INTENT_CONTRACT_SCHEMA_HASH, AI_INTENT_CONTRACT_VERSION, AI_STREAM_EVENT_SCHEMA_VERSION, AI_STREAM_EVENT_TYPES, AiBackendApiService, AiPatchStreamConnectionError, AiResponseValidatorService, AiRuleWizardDialogComponent, BaseAiAdapter, PRAXIS_ASSISTANT_CONTEXT_ATTACHMENT_LIMIT, PRAXIS_ASSISTANT_CONTEXT_ITEM_LIMIT, PRAXIS_ASSISTANT_CONTEXT_SCHEMA_FIELD_LIMIT, PRAXIS_ASSISTANT_CONTEXT_TEXT_LIMIT, PraxisAi, PraxisAiAssistantComponent, PraxisAiAssistantDockComponent, PraxisAiAssistantSessionHostComponent, PraxisAiAssistantShellComponent, PraxisAiService, PraxisAssistantSessionRegistryService, PraxisAssistantTurnController, PraxisAssistantTurnOrchestratorService, SchemaMinifierService, createPraxisAssistantViewportLayout, normalizeAuthoringPrompt, normalizePraxisAssistantAttachmentSummary, normalizePraxisAssistantContextSnapshot, sanitizePraxisAssistantText, shouldRoutePromptToGovernedDecision, toPraxisAssistantConversationMessages };
|
|
9123
|
+
export { AI_BACKEND_CONFIG_STORE, AI_BACKEND_ENDPOINTS, AI_BACKEND_STORAGE_OPTIONS, AI_CONTRACT_SCHEMA_HASH, AI_CONTRACT_VERSION, AI_INTENT_CONTRACT_SCHEMA_HASH, AI_INTENT_CONTRACT_VERSION, AI_STREAM_EVENT_SCHEMA_VERSION, AI_STREAM_EVENT_TYPES, AiBackendApiService, AiPatchStreamConnectionError, AiResponseValidatorService, AiRuleWizardDialogComponent, BaseAiAdapter, PRAXIS_ASSISTANT_CONTEXT_ATTACHMENT_LIMIT, PRAXIS_ASSISTANT_CONTEXT_ITEM_LIMIT, PRAXIS_ASSISTANT_CONTEXT_SCHEMA_FIELD_LIMIT, PRAXIS_ASSISTANT_CONTEXT_TEXT_LIMIT, PraxisAi, PraxisAiAssistantComponent, PraxisAiAssistantDockComponent, PraxisAiAssistantSessionHostComponent, PraxisAiAssistantShellComponent, PraxisAiService, PraxisAssistantSessionRegistryService, PraxisAssistantTurnController, PraxisAssistantTurnOrchestratorService, SchemaMinifierService, createComponentAuthoringContext, createPraxisAssistantViewportLayout, normalizeAuthoringPrompt, normalizePraxisAssistantAttachmentSummary, normalizePraxisAssistantContextSnapshot, sanitizePraxisAssistantText, shouldRoutePromptToGovernedDecision, toAiJsonObject, toPraxisAssistantConversationMessages };
|