maquito-chat-plugin 1.1.5 → 1.1.6

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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, NgZone, Injectable, ElementRef, signal, computed, Input, ViewChild, Component } from '@angular/core';
2
+ import { inject, NgZone, Injectable, ElementRef, signal, computed, HostListener, Input, ViewChild, Component } from '@angular/core';
3
3
  import { HttpClient, HttpHeaders } from '@angular/common/http';
4
4
  import { Observable } from 'rxjs';
5
5
  import * as i1 from '@angular/common';
@@ -218,6 +218,11 @@ class IntelligentChatPluginComponent {
218
218
  STORAGE_PREFIX = 'iq_chat_session_';
219
219
  sessionKey = '';
220
220
  storageListener = (e) => this.onStorageChange(e);
221
+ // ─── Debug Menu ──────────────────────────────────
222
+ showDebugMenu = signal(false, ...(ngDevMode ? [{ debugName: "showDebugMenu" }] : []));
223
+ titleTouchTimer = null;
224
+ shakeHandler = null;
225
+ lastShakeTime = 0;
221
226
  /** Resolved config with defaults applied */
222
227
  sanitizer = inject(DomSanitizer);
223
228
  resolvedConfig = signal({
@@ -244,7 +249,9 @@ class IntelligentChatPluginComponent {
244
249
  allowExpand: false,
245
250
  theme: {},
246
251
  userName: '',
247
- personality: ''
252
+ personality: '',
253
+ enableDebugMenu: false,
254
+ debugKeyCombo: 'ctrl+shift+d'
248
255
  }, ...(ngDevMode ? [{ debugName: "resolvedConfig" }] : []));
249
256
  /** Map theme object → CSS variable overrides */
250
257
  themeStyles = computed(() => {
@@ -283,10 +290,13 @@ class IntelligentChatPluginComponent {
283
290
  this.setHostScrollLock(false);
284
291
  this.currentSubscription?.unsubscribe();
285
292
  this.currentSubscription = undefined;
293
+ // Setup shake detection for mobile debug log download
294
+ this.setupShakeDetection();
286
295
  }
287
296
  ngOnDestroy() {
288
297
  window.removeEventListener('storage', this.storageListener);
289
- this.cancelQuery();
298
+ this.currentSubscription?.unsubscribe();
299
+ this.teardownShakeDetection();
290
300
  }
291
301
  ngOnChanges(changes) {
292
302
  if (changes['config'] && this.config) {
@@ -314,7 +324,9 @@ class IntelligentChatPluginComponent {
314
324
  allowExpand: this.config.allowExpand ?? false,
315
325
  theme: this.config.theme || {},
316
326
  userName: this.config.userName || '',
317
- personality: this.config.personality || ''
327
+ personality: this.config.personality || '',
328
+ enableDebugMenu: this.config.enableDebugMenu ?? false,
329
+ debugKeyCombo: this.config.debugKeyCombo || 'ctrl+shift+d'
318
330
  });
319
331
  // Cancel any in-flight query when config changes
320
332
  this.cancelQuery();
@@ -535,6 +547,166 @@ class IntelligentChatPluginComponent {
535
547
  closeTrace() {
536
548
  this.selectedTrace.set(null);
537
549
  }
550
+ /** Split combined multi-model query into labeled sections */
551
+ getQuerySections() {
552
+ const raw = this.selectedTrace()?.query;
553
+ if (!raw)
554
+ return [];
555
+ // Multi-model queries are separated by "-- [ModelName]" headers
556
+ const parts = raw.split(/^-- \[(.+?)\]$/m);
557
+ if (parts.length <= 1) {
558
+ // Single query, no model headers
559
+ return [{ model: null, query: raw.trim() }];
560
+ }
561
+ const sections = [];
562
+ // parts = ["", "MaquitoFactura", "\nSELECT...", "MaquitoPedido", "\nSELECT..."]
563
+ for (let i = 1; i < parts.length; i += 2) {
564
+ const modelName = parts[i]?.trim();
565
+ const queryText = parts[i + 1]?.trim();
566
+ if (modelName && queryText) {
567
+ sections.push({ model: modelName, query: queryText });
568
+ }
569
+ }
570
+ return sections.length > 0 ? sections : [{ model: null, query: raw.trim() }];
571
+ }
572
+ // ─── Debug Menu & Log Download ────────────────────
573
+ toggleDebugMenu() {
574
+ this.showDebugMenu.set(!this.showDebugMenu());
575
+ }
576
+ /** Secret keyboard shortcut — works even if debug menu is disabled */
577
+ onDebugKeydown(event) {
578
+ const combo = (this.resolvedConfig().debugKeyCombo || 'ctrl+shift+d').toLowerCase();
579
+ const parts = combo.split('+');
580
+ const needCtrl = parts.includes('ctrl');
581
+ const needShift = parts.includes('shift');
582
+ const needAlt = parts.includes('alt');
583
+ const key = parts.filter(p => !['ctrl', 'shift', 'alt'].includes(p))[0];
584
+ if ((!needCtrl || event.ctrlKey) &&
585
+ (!needShift || event.shiftKey) &&
586
+ (!needAlt || event.altKey) &&
587
+ event.key.toLowerCase() === key) {
588
+ event.preventDefault();
589
+ this.downloadConversationLog();
590
+ }
591
+ }
592
+ /** Long-press on title (mobile) — 3 seconds */
593
+ onTitleTouchStart(event) {
594
+ this.titleTouchTimer = setTimeout(() => {
595
+ this.downloadConversationLog();
596
+ }, 3000);
597
+ }
598
+ onTitleTouchEnd() {
599
+ if (this.titleTouchTimer) {
600
+ clearTimeout(this.titleTouchTimer);
601
+ this.titleTouchTimer = null;
602
+ }
603
+ }
604
+ /** Setup device shake detection for mobile */
605
+ setupShakeDetection() {
606
+ if (typeof DeviceMotionEvent === 'undefined')
607
+ return;
608
+ const SHAKE_THRESHOLD = 25;
609
+ let lastX = 0, lastY = 0, lastZ = 0;
610
+ let lastUpdate = 0;
611
+ this.shakeHandler = (event) => {
612
+ const acc = event.accelerationIncludingGravity;
613
+ if (!acc || acc.x == null || acc.y == null || acc.z == null)
614
+ return;
615
+ const now = Date.now();
616
+ if ((now - lastUpdate) < 100)
617
+ return;
618
+ const diffTime = now - lastUpdate;
619
+ lastUpdate = now;
620
+ const speed = Math.abs(acc.x + acc.y + acc.z - lastX - lastY - lastZ) / diffTime * 10000;
621
+ lastX = acc.x;
622
+ lastY = acc.y;
623
+ lastZ = acc.z;
624
+ if (speed > SHAKE_THRESHOLD && (now - this.lastShakeTime) > 5000) {
625
+ this.lastShakeTime = now;
626
+ this.downloadConversationLog();
627
+ }
628
+ };
629
+ window.addEventListener('devicemotion', this.shakeHandler);
630
+ }
631
+ teardownShakeDetection() {
632
+ if (this.shakeHandler) {
633
+ window.removeEventListener('devicemotion', this.shakeHandler);
634
+ this.shakeHandler = null;
635
+ }
636
+ }
637
+ /** Generate and download a comprehensive conversation log as .txt */
638
+ downloadConversationLog() {
639
+ const cfg = this.resolvedConfig();
640
+ const msgs = this.messages();
641
+ const now = new Date();
642
+ const pad = (n) => n.toString().padStart(2, '0');
643
+ const ts = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`;
644
+ let log = '';
645
+ log += '═══════════════════════════════════════════════════\n';
646
+ log += ' MAQUITO CHAT — LOG DE CONVERSACIÓN\n';
647
+ log += ` Fecha de descarga: ${ts}\n`;
648
+ log += ` Sistema: ${cfg.systemId}\n`;
649
+ log += ` Session Key: ${this.sessionKey || 'N/A'}\n`;
650
+ log += ` Título: ${cfg.title}\n`;
651
+ log += ` Total Mensajes: ${msgs.length}\n`;
652
+ if (cfg.userName)
653
+ log += ` Usuario: ${cfg.userName}\n`;
654
+ if (cfg.baseContext)
655
+ log += ` Contexto Base: ${cfg.baseContext.substring(0, 100)}...\n`;
656
+ log += '═══════════════════════════════════════════════════\n\n';
657
+ for (const msg of msgs) {
658
+ const t = new Date(msg.timestamp);
659
+ const time = `${pad(t.getHours())}:${pad(t.getMinutes())}:${pad(t.getSeconds())}`;
660
+ const icon = msg.sender === 'user' ? '👤 USUARIO' : '🤖 BOT';
661
+ log += `[${time}] ${icon}:\n`;
662
+ // Strip HTML tags for plain text
663
+ const plainText = msg.text.replace(/<[^>]*>/g, '').trim();
664
+ log += `${plainText}\n`;
665
+ // Include trace data if available (bot messages)
666
+ if (msg.traceData && msg.sender === 'bot') {
667
+ log += ' ┌─── Traza ───────────────────────\n';
668
+ const td = msg.traceData;
669
+ if (td.traceId)
670
+ log += ` │ TraceId: ${td.traceId}\n`;
671
+ if (td.origin)
672
+ log += ` │ Origen: ${td.origin}\n`;
673
+ if (td.query)
674
+ log += ` │ Query: ${td.query}\n`;
675
+ if (td.model)
676
+ log += ` │ Modelo: ${td.model}\n`;
677
+ if (td.rowCount !== undefined)
678
+ log += ` │ Filas: ${td.rowCount}\n`;
679
+ if (td.explanation)
680
+ log += ` │ Explicación: ${td.explanation}\n`;
681
+ if (td.durationMs)
682
+ log += ` │ Duración: ${td.durationMs}ms\n`;
683
+ // Include full raw trace for deep debugging
684
+ try {
685
+ const raw = JSON.stringify(td, null, 2);
686
+ log += ` │ Raw Trace:\n`;
687
+ for (const line of raw.split('\n')) {
688
+ log += ` │ ${line}\n`;
689
+ }
690
+ }
691
+ catch { }
692
+ log += ' └─────────────────────────────────\n';
693
+ }
694
+ log += '\n';
695
+ }
696
+ log += '═══════════════════════════════════════════════════\n';
697
+ log += ` FIN DEL LOG — ${msgs.length} mensajes\n`;
698
+ log += '═══════════════════════════════════════════════════\n';
699
+ // Download as .txt file
700
+ const blob = new Blob([log], { type: 'text/plain;charset=utf-8' });
701
+ const url = URL.createObjectURL(blob);
702
+ const a = document.createElement('a');
703
+ a.href = url;
704
+ a.download = `maquito-chat-log_${now.getFullYear()}${pad(now.getMonth() + 1)}${pad(now.getDate())}_${pad(now.getHours())}${pad(now.getMinutes())}.txt`;
705
+ document.body.appendChild(a);
706
+ a.click();
707
+ document.body.removeChild(a);
708
+ URL.revokeObjectURL(url);
709
+ }
538
710
  // ─── Link Modal ────────────────────────────────
539
711
  openLinkModal(url) {
540
712
  this.modalLoading.set(true);
@@ -800,7 +972,7 @@ class IntelligentChatPluginComponent {
800
972
  this.shouldScroll = true;
801
973
  }
802
974
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: IntelligentChatPluginComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
803
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: IntelligentChatPluginComponent, isStandalone: true, selector: "intelligent-chat-plugin", inputs: { config: "config" }, viewQueries: [{ propertyName: "chatContainer", first: true, predicate: ["chatContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
975
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: IntelligentChatPluginComponent, isStandalone: true, selector: "intelligent-chat-plugin", inputs: { config: "config" }, host: { listeners: { "window:keydown": "onDebugKeydown($event)" } }, viewQueries: [{ propertyName: "chatContainer", first: true, predicate: ["chatContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
804
976
  <!-- Host theme overrides -->
805
977
  <div class="iq-theme-host" [ngStyle]="themeStyles()">
806
978
 
@@ -843,8 +1015,24 @@ class IntelligentChatPluginComponent {
843
1015
  >
844
1016
  <!-- Header -->
845
1017
  <div class="iq-header">
846
- <span class="iq-header-title">{{ resolvedConfig().title }}</span>
1018
+ <span class="iq-header-title"
1019
+ (touchstart)="onTitleTouchStart($event)"
1020
+ (touchend)="onTitleTouchEnd()"
1021
+ (touchcancel)="onTitleTouchEnd()"
1022
+ >{{ resolvedConfig().title }}</span>
847
1023
  <div class="iq-header-actions">
1024
+ @if (resolvedConfig().enableDebugMenu) {
1025
+ <div class="iq-debug-menu-wrapper">
1026
+ <button class="iq-header-btn" (click)="toggleDebugMenu()" title="Opciones">⋯</button>
1027
+ @if (showDebugMenu()) {
1028
+ <div class="iq-debug-dropdown">
1029
+ <button class="iq-debug-option" (click)="downloadConversationLog(); toggleDebugMenu()">
1030
+ 📥 Descargar Log
1031
+ </button>
1032
+ </div>
1033
+ }
1034
+ </div>
1035
+ }
848
1036
  <button class="iq-header-btn" (click)="clearChat()" title="Limpiar chat">🗑️</button>
849
1037
  @if (resolvedConfig().allowExpand) {
850
1038
  <button class="iq-header-btn iq-btn-expand" (click)="toggleExpand()" [title]="isExpanded() ? 'Contraer' : 'Expandir'">
@@ -947,8 +1135,13 @@ class IntelligentChatPluginComponent {
947
1135
  }
948
1136
  @if (selectedTrace()?.query) {
949
1137
  <div class="iq-trace-item">
950
- <label>Query Generada</label>
951
- <pre class="iq-query-code">{{ selectedTrace()?.query }}</pre>
1138
+ <label>{{ getQuerySections().length > 1 ? 'Queries Generadas (' + getQuerySections().length + ')' : 'Query Generada' }}</label>
1139
+ @for (section of getQuerySections(); track $index) {
1140
+ @if (section.model) {
1141
+ <div style="color: #4ecdc4; font-size: 11px; font-weight: bold; margin-top: 8px;">📋 {{ section.model }}</div>
1142
+ }
1143
+ <pre class="iq-query-code" style="margin-top: 4px;">{{ section.query }}</pre>
1144
+ }
952
1145
  </div>
953
1146
  }
954
1147
  @if (selectedTrace()?.explanation) {
@@ -1008,7 +1201,7 @@ class IntelligentChatPluginComponent {
1008
1201
  }
1009
1202
 
1010
1203
  </div><!-- /iq-theme-host -->
1011
- `, isInline: true, styles: [":host{--iq-primary: #1a3a5c;--iq-primary-light: #2a5a8c;--iq-accent: #00d4aa;--iq-accent-light: #33e0be;--iq-bg: #1e1e2f;--iq-bg-card: #252538;--iq-bg-tertiary: #35354a;--iq-text: #ffffff;--iq-text-secondary: #a0a0b0;--iq-text-muted: #6c6c7c;--iq-border: #3a3a4d;--iq-radius: 12px;--iq-bubble-size: 56px;--iq-panel-width: 400px;--iq-panel-height: 520px;--iq-z: 10000;--iq-font: \"Inter\", \"Roboto\", -apple-system, BlinkMacSystemFont, sans-serif;font-family:var(--iq-font)}.iq-bubble{position:fixed;bottom:24px;right:24px;z-index:var(--iq-z);width:var(--iq-bubble-size);height:var(--iq-bubble-size);border-radius:50%;border:none;background:linear-gradient(135deg,var(--iq-accent),var(--iq-accent-light));color:var(--iq-bg);font-size:1.6rem;cursor:pointer;box-shadow:0 4px 16px #00d4aa66;transition:all .3s cubic-bezier(.4,0,.2,1);display:flex;align-items:center;justify-content:center}.iq-bubble:hover{transform:scale(1.1);box-shadow:0 6px 24px #00d4aa80}.iq-bubble .iq-bubble-icon{font-size:1.5rem;pointer-events:none}.iq-bubble-img{width:60%;height:60%;object-fit:contain;border-radius:50%;pointer-events:none}.iq-bubble-svg{width:60%;height:60%;display:flex;align-items:center;justify-content:center;pointer-events:none}.iq-bubble-svg :deep(svg){width:100%;height:100%}.iq-bubble.iq-open{background:var(--iq-bg-tertiary);color:var(--iq-text);box-shadow:0 4px 12px #0000004d;font-size:1.2rem}.iq-bubble.iq-bottom-left{right:auto;left:24px}.iq-bubble-icon{line-height:1}.iq-panel{position:fixed;bottom:92px;right:24px;z-index:var(--iq-z);width:var(--iq-panel-width);height:var(--iq-panel-height);background:var(--iq-bg);border:1px solid var(--iq-border);border-radius:var(--iq-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 12px 40px #00000080;animation:iq-slide-up .3s cubic-bezier(.4,0,.2,1)}.iq-panel.iq-bottom-left{right:auto;left:24px}.iq-panel.iq-expanded{width:100vw!important;height:100vh!important;inset:0!important;border:none;border-radius:0;overflow:clip;z-index:calc(var(--iq-z) + 5);animation:iq-expand .3s cubic-bezier(.4,0,.2,1)}.iq-btn-expand{font-size:1.1rem!important}@keyframes iq-expand{0%{opacity:.8;transform:scale(.95)}to{opacity:1;transform:scale(1)}}@keyframes iq-slide-up{0%{opacity:0;transform:translateY(16px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}.iq-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--iq-border);background:var(--iq-bg-card)}.iq-header-title{font-weight:600;font-size:.95rem;color:var(--iq-text)}.iq-header-actions{display:flex;gap:4px}.iq-header-btn{background:none;border:none;color:var(--iq-text-muted);cursor:pointer;font-size:1rem;padding:4px 6px;border-radius:4px;transition:all .15s}.iq-header-btn:hover{color:var(--iq-text);background:#ffffff14}.iq-auth-error{display:flex;align-items:center;gap:8px;padding:10px 16px;background:#dc354526;color:#ff6b7a;font-size:.8rem;border-bottom:1px solid rgba(220,53,69,.25)}.iq-messages{flex:1;min-height:0;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:10px}.iq-empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;color:var(--iq-text-secondary)}.iq-empty-icon{font-size:3rem;margin-bottom:8px;display:flex;align-items:center;justify-content:center}.iq-empty-img{width:48px;height:48px;object-fit:contain;border-radius:8px}.iq-empty-svg{width:48px;height:48px;display:flex;align-items:center;justify-content:center}.iq-empty-svg :deep(svg){width:100%;height:100%}.iq-empty p{font-size:.95rem;margin:2px 0}.iq-text-muted{color:var(--iq-text-muted)!important;font-size:.8rem!important}.iq-msg{display:flex;flex-direction:column;max-width:85%}.iq-msg-user{align-self:flex-end}.iq-msg-bot{align-self:flex-start;max-width:100%}.iq-msg-user .iq-msg-content{background:linear-gradient(135deg,var(--iq-primary),var(--iq-primary-light));border-radius:12px 12px 0}.iq-msg-bot .iq-msg-content{background:var(--iq-bg-tertiary);border-radius:12px 12px 12px 0}.iq-msg-content{padding:10px 14px;color:var(--iq-text);font-size:.85rem;line-height:1.45}.iq-msg-content p{margin:0;white-space:pre-wrap}.iq-msg-time{display:block;margin-top:4px;font-size:.65rem;color:#ffffff80}.iq-md{line-height:1.5;overflow-x:auto;max-width:100%}.iq-md :first-child{margin-top:0}.iq-md :last-child{margin-bottom:0}.iq-md p{margin:0 0 .4em}.iq-md p:last-child{margin-bottom:0}.iq-md strong{color:var(--iq-accent)}.iq-md ul,.iq-md ol{margin:.3em 0;padding-left:1.2em}.iq-md li{margin:.15em 0}.iq-md code{background:#0000004d;padding:.15em .4em;border-radius:3px;font-size:.82em}.iq-md pre{background:#0000004d;padding:.8em;border-radius:6px;overflow-x:auto;font-size:.78em;margin:.4em 0}.iq-md pre code{background:none;padding:0}.iq-md table{width:max-content;min-width:100%;border-collapse:separate;border-spacing:0;margin:.5em 0;font-size:.75rem;border-radius:6px;overflow:hidden}.iq-md thead th{background:#6366f12e;color:#a5b4fc;font-weight:600;text-align:left;padding:.5em .8em;border-bottom:2px solid rgba(99,102,241,.3);white-space:nowrap;font-size:.7rem;text-transform:uppercase;letter-spacing:.05em}.iq-md tbody td{padding:.4em .8em;border-bottom:1px solid rgba(255,255,255,.06);white-space:nowrap;color:var(--iq-text-secondary)}.iq-md tbody tr:hover{background:#6366f114}.iq-md img{max-height:80px;max-width:120px;object-fit:cover;border-radius:8px;margin:6px 4px 6px 0;display:inline-block;vertical-align:middle;border:1px solid rgba(255,255,255,.15);box-shadow:0 1px 4px #00000040;cursor:pointer;transition:transform .15s,box-shadow .15s}.iq-md img:hover{transform:scale(1.05);box-shadow:0 3px 12px #6366f159;border-color:var(--iq-accent)}.iq-md img[alt*=logo],.iq-md img[alt*=marca]{max-height:28px;max-width:90px;object-fit:contain;border:none;box-shadow:none;border-radius:4px;background:#ffffffe6;padding:2px 6px}.iq-btn-trace{align-self:flex-start;margin-top:4px;background:transparent;border:1px solid var(--iq-border);color:var(--iq-text-secondary);font-size:.7rem;padding:3px 8px;border-radius:4px;cursor:pointer;transition:all .15s}.iq-btn-trace:hover{border-color:var(--iq-accent);color:var(--iq-accent)}.iq-pipeline{display:flex;align-items:center;gap:8px;animation:iq-fade-in .3s ease-out}.iq-dot{width:8px;height:8px;border-radius:50%;background:var(--iq-accent);animation:iq-pulse 1s ease-in-out infinite}.iq-pipeline-text{font-size:.8rem;color:var(--iq-text-muted);font-style:italic;flex:1}.iq-cancel-btn{background:transparent;border:1px solid var(--iq-border);color:var(--iq-text-muted);font-size:.7rem;padding:2px 8px;border-radius:4px;cursor:pointer;transition:all .15s;flex-shrink:0}.iq-cancel-btn:hover{border-color:#ff6b6b;color:#ff6b6b;background:#ff6b6b1a}@keyframes iq-pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(.7)}}@keyframes iq-fade-in{0%{opacity:0;transform:translate(-6px)}to{opacity:1;transform:translate(0)}}.iq-input-bar{display:flex;gap:8px;padding:10px 12px;border-top:1px solid var(--iq-border);background:var(--iq-bg-card)}.iq-input-bar input{flex:1;padding:8px 12px;background:var(--iq-bg-tertiary);border:1px solid var(--iq-border);border-radius:8px;color:var(--iq-text);font-size:.85rem;font-family:var(--iq-font);outline:none;transition:border-color .15s}.iq-input-bar input:focus{border-color:var(--iq-accent)}.iq-input-bar input::placeholder{color:var(--iq-text-muted)}.iq-input-bar input:disabled{opacity:.5}.iq-btn-send{width:36px;height:36px;border-radius:8px;border:none;background:linear-gradient(135deg,var(--iq-accent),var(--iq-accent-light));color:var(--iq-bg);font-size:1rem;cursor:pointer;transition:all .2s;display:flex;align-items:center;justify-content:center}.iq-btn-send:hover:not(:disabled){box-shadow:0 0 12px #00d4aa66;transform:translateY(-1px)}.iq-btn-send:disabled{opacity:.4;cursor:not-allowed}.iq-trace-overlay{position:fixed;inset:0;z-index:calc(var(--iq-z) + 10);background:#0009;display:flex;align-items:center;justify-content:center;animation:iq-fade-in .2s ease-out}.iq-trace-modal{width:90%;max-width:520px;max-height:80vh;background:var(--iq-bg);border:1px solid var(--iq-border);border-radius:var(--iq-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 20px 50px #0009}.iq-trace-header{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;border-bottom:1px solid var(--iq-border)}.iq-trace-header h3{margin:0;font-size:.95rem;color:var(--iq-text)}.iq-trace-body{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px}.iq-trace-item label{display:block;font-size:.7rem;color:var(--iq-text-muted);margin-bottom:4px;text-transform:uppercase;letter-spacing:.05em}.iq-trace-item code{display:block;padding:8px;background:var(--iq-bg-tertiary);border-radius:4px;font-family:monospace;font-size:.8rem;color:var(--iq-accent);word-break:break-all}.iq-trace-item pre{margin:0;padding:8px;background:var(--iq-bg-tertiary);border-radius:4px;font-family:monospace;font-size:.7rem;overflow-x:auto;max-height:180px;color:var(--iq-text-secondary)}.iq-cache-hit{background:#10b98126!important;color:#10b981!important}.iq-query-code{color:var(--iq-accent)!important}.iq-link-overlay{position:fixed;inset:0;z-index:calc(var(--iq-z) + 20);background:#000000b3;display:flex;align-items:center;justify-content:center;animation:iq-fade-in .2s ease-out;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.iq-link-modal{width:94vw;height:92vh;background:var(--iq-bg);border:1px solid var(--iq-border);border-radius:var(--iq-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 24px 60px #000000b3;animation:iq-expand .25s cubic-bezier(.4,0,.2,1)}.iq-link-header{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;border-bottom:1px solid var(--iq-border);background:var(--iq-bg-card);gap:12px;min-height:44px}.iq-link-title{flex:1;font-size:.78rem;color:var(--iq-text-secondary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-family:monospace}.iq-link-actions{display:flex;gap:4px;flex-shrink:0}.iq-link-actions a{text-decoration:none}.iq-back-btn{flex-shrink:0;font-size:1.1rem;transition:transform .15s ease}.iq-back-btn:hover{transform:translate(-2px)}.iq-iframe-wrapper{flex:1;position:relative;overflow:hidden}.iq-link-iframe{width:100%;height:100%;border:none;background:#fff;transition:opacity .3s ease}.iq-iframe-hidden{opacity:0}.iq-modal-img{width:100%;height:100%;object-fit:contain;background:#1a1a2e}.iq-iframe-loader{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:var(--iq-bg);gap:16px;z-index:2}.iq-spinner{width:40px;height:40px;border:3px solid var(--iq-border);border-top-color:var(--iq-accent);border-radius:50%;animation:iq-spin .8s linear infinite}.iq-loader-text{font-size:.85rem;color:var(--iq-text-secondary);font-weight:500}@keyframes iq-spin{to{transform:rotate(360deg)}}.iq-md a{color:var(--iq-accent);text-decoration:underline;cursor:pointer;transition:color .15s}.iq-md a:hover{color:var(--iq-accent-light)}@media(max-width:480px){.iq-link-modal{width:100vw;height:100dvh;border-radius:0}.iq-link-header{padding:8px 12px}.iq-link-title{font-size:.7rem}}.iq-messages::-webkit-scrollbar{width:5px}.iq-messages::-webkit-scrollbar-track{background:transparent}.iq-messages::-webkit-scrollbar-thumb{background:var(--iq-border);border-radius:4px}.iq-trace-body::-webkit-scrollbar{width:5px}.iq-trace-body::-webkit-scrollbar-track{background:transparent}.iq-trace-body::-webkit-scrollbar-thumb{background:var(--iq-border);border-radius:4px}.iq-expanded .iq-messages::-webkit-scrollbar{width:8px}.iq-expanded .iq-messages{scrollbar-gutter:stable}@media(max-width:480px){.iq-bubble{bottom:16px;right:16px;width:48px;height:48px;font-size:1.3rem}.iq-bubble.iq-bottom-left{left:16px}.iq-bubble .iq-bubble-icon{font-size:1.2rem}.iq-panel{right:8px;left:8px;bottom:72px;width:auto!important;max-width:calc(100vw - 16px);height:calc(100dvh - 90px);max-height:calc(100dvh - 90px)}.iq-panel.iq-bottom-left{left:8px;right:8px}.iq-panel.iq-expanded{inset:0!important;width:100vw!important;height:100dvh!important;max-height:100dvh!important;max-width:100vw!important;border-radius:0}.iq-header{padding:10px 12px}.iq-header-title{font-size:.85rem}.iq-header-btn{padding:6px 8px;min-width:32px;min-height:32px}.iq-messages{padding:8px;gap:8px}.iq-msg{max-width:92%}.iq-msg-bot{max-width:100%}.iq-msg-content{padding:8px 10px;font-size:.8rem}.iq-md{overflow-x:auto;-webkit-overflow-scrolling:touch}.iq-md table{font-size:.65rem;min-width:unset}.iq-md thead th{padding:.35em .5em;font-size:.6rem}.iq-md tbody td{padding:.3em .5em;font-size:.65rem}.iq-empty-icon{font-size:2.5rem}.iq-empty p{font-size:.85rem}.iq-input-bar{padding:8px 10px;gap:6px}.iq-input-bar input{font-size:16px;padding:8px 10px}.iq-btn-send{width:38px;height:38px;flex-shrink:0}.iq-trace-modal{width:calc(100vw - 24px);max-height:90dvh}.iq-trace-header{padding:12px}.iq-trace-header h3{font-size:.85rem}.iq-trace-body{padding:12px}.iq-trace-item pre{font-size:.65rem;max-height:140px}}@media(max-height:500px)and (orientation:landscape){.iq-bubble{bottom:8px;right:8px;width:44px;height:44px;font-size:1.1rem}.iq-bubble.iq-bottom-left{left:8px}.iq-panel{inset:8px 60px 8px 8px;width:auto!important;max-width:calc(100vw - 76px);height:auto!important;max-height:calc(100dvh - 16px);border-radius:var(--iq-radius)}.iq-panel.iq-bottom-left{left:60px;right:8px}.iq-panel.iq-expanded{inset:0!important;width:100vw!important;height:100dvh!important;max-height:100dvh!important;max-width:100vw!important;border-radius:0}.iq-header{padding:6px 12px}.iq-header-title{font-size:.8rem}.iq-messages{padding:6px 10px;gap:6px}.iq-empty-icon{font-size:1.8rem;margin-bottom:4px}.iq-empty p{font-size:.78rem;margin:1px 0}.iq-input-bar{padding:6px 10px}.iq-input-bar input{font-size:16px;padding:6px 10px}.iq-btn-send{width:32px;height:32px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "pipe", type: i1.JsonPipe, name: "json" }] });
1204
+ `, isInline: true, styles: [":host{--iq-primary: #1a3a5c;--iq-primary-light: #2a5a8c;--iq-accent: #00d4aa;--iq-accent-light: #33e0be;--iq-bg: #1e1e2f;--iq-bg-card: #252538;--iq-bg-tertiary: #35354a;--iq-text: #ffffff;--iq-text-secondary: #a0a0b0;--iq-text-muted: #6c6c7c;--iq-border: #3a3a4d;--iq-radius: 12px;--iq-bubble-size: 56px;--iq-panel-width: 400px;--iq-panel-height: 520px;--iq-z: 10000;--iq-font: \"Inter\", \"Roboto\", -apple-system, BlinkMacSystemFont, sans-serif;font-family:var(--iq-font)}.iq-bubble{position:fixed;bottom:24px;right:24px;z-index:var(--iq-z);width:var(--iq-bubble-size);height:var(--iq-bubble-size);border-radius:50%;border:none;background:linear-gradient(135deg,var(--iq-accent),var(--iq-accent-light));color:var(--iq-bg);font-size:1.6rem;cursor:pointer;box-shadow:0 4px 16px #00d4aa66;transition:all .3s cubic-bezier(.4,0,.2,1);display:flex;align-items:center;justify-content:center}.iq-bubble:hover{transform:scale(1.1);box-shadow:0 6px 24px #00d4aa80}.iq-bubble .iq-bubble-icon{font-size:1.5rem;pointer-events:none}.iq-bubble-img{width:60%;height:60%;object-fit:contain;border-radius:50%;pointer-events:none}.iq-bubble-svg{width:60%;height:60%;display:flex;align-items:center;justify-content:center;pointer-events:none}.iq-bubble-svg :deep(svg){width:100%;height:100%}.iq-bubble.iq-open{background:var(--iq-bg-tertiary);color:var(--iq-text);box-shadow:0 4px 12px #0000004d;font-size:1.2rem}.iq-bubble.iq-bottom-left{right:auto;left:24px}.iq-bubble-icon{line-height:1}.iq-panel{position:fixed;bottom:92px;right:24px;z-index:var(--iq-z);width:var(--iq-panel-width);height:var(--iq-panel-height);background:var(--iq-bg);border:1px solid var(--iq-border);border-radius:var(--iq-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 12px 40px #00000080;animation:iq-slide-up .3s cubic-bezier(.4,0,.2,1)}.iq-panel.iq-bottom-left{right:auto;left:24px}.iq-panel.iq-expanded{width:100vw!important;height:100vh!important;inset:0!important;border:none;border-radius:0;overflow:clip;z-index:calc(var(--iq-z) + 5);animation:iq-expand .3s cubic-bezier(.4,0,.2,1)}.iq-btn-expand{font-size:1.1rem!important}@keyframes iq-expand{0%{opacity:.8;transform:scale(.95)}to{opacity:1;transform:scale(1)}}@keyframes iq-slide-up{0%{opacity:0;transform:translateY(16px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}.iq-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--iq-border);background:var(--iq-bg-card)}.iq-header-title{font-weight:600;font-size:.95rem;color:var(--iq-text)}.iq-header-actions{display:flex;gap:4px}.iq-header-btn{background:none;border:none;color:var(--iq-text-muted);cursor:pointer;font-size:1rem;padding:4px 6px;border-radius:4px;transition:all .15s}.iq-header-btn:hover{color:var(--iq-text);background:#ffffff14}.iq-debug-menu-wrapper{position:relative}.iq-debug-dropdown{position:absolute;top:100%;right:0;margin-top:4px;min-width:180px;background:var(--iq-bg-card);border:1px solid var(--iq-border);border-radius:8px;box-shadow:0 8px 24px #0006;z-index:calc(var(--iq-z) + 10);padding:4px;animation:iq-dropdown-in .15s ease-out}@keyframes iq-dropdown-in{0%{opacity:0;transform:translateY(-4px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}.iq-debug-option{display:flex;align-items:center;gap:8px;width:100%;padding:8px 12px;background:none;border:none;color:var(--iq-text);font-size:.85rem;cursor:pointer;border-radius:6px;transition:background .15s;text-align:left}.iq-debug-option:hover{background:#ffffff14}.iq-auth-error{display:flex;align-items:center;gap:8px;padding:10px 16px;background:#dc354526;color:#ff6b7a;font-size:.8rem;border-bottom:1px solid rgba(220,53,69,.25)}.iq-messages{flex:1;min-height:0;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:10px}.iq-empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;color:var(--iq-text-secondary)}.iq-empty-icon{font-size:3rem;margin-bottom:8px;display:flex;align-items:center;justify-content:center}.iq-empty-img{width:48px;height:48px;object-fit:contain;border-radius:8px}.iq-empty-svg{width:48px;height:48px;display:flex;align-items:center;justify-content:center}.iq-empty-svg :deep(svg){width:100%;height:100%}.iq-empty p{font-size:.95rem;margin:2px 0}.iq-text-muted{color:var(--iq-text-muted)!important;font-size:.8rem!important}.iq-msg{display:flex;flex-direction:column;max-width:85%}.iq-msg-user{align-self:flex-end}.iq-msg-bot{align-self:flex-start;max-width:100%}.iq-msg-user .iq-msg-content{background:linear-gradient(135deg,var(--iq-primary),var(--iq-primary-light));border-radius:12px 12px 0}.iq-msg-bot .iq-msg-content{background:var(--iq-bg-tertiary);border-radius:12px 12px 12px 0}.iq-msg-content{padding:10px 14px;color:var(--iq-text);font-size:.85rem;line-height:1.45}.iq-msg-content p{margin:0;white-space:pre-wrap}.iq-msg-time{display:block;margin-top:4px;font-size:.65rem;color:#ffffff80}.iq-md{line-height:1.5;overflow-x:auto;max-width:100%}.iq-md :first-child{margin-top:0}.iq-md :last-child{margin-bottom:0}.iq-md p{margin:0 0 .4em}.iq-md p:last-child{margin-bottom:0}.iq-md strong{color:var(--iq-accent)}.iq-md ul,.iq-md ol{margin:.3em 0;padding-left:1.2em}.iq-md li{margin:.15em 0}.iq-md code{background:#0000004d;padding:.15em .4em;border-radius:3px;font-size:.82em}.iq-md pre{background:#0000004d;padding:.8em;border-radius:6px;overflow-x:auto;font-size:.78em;margin:.4em 0}.iq-md pre code{background:none;padding:0}.iq-md table{width:max-content;min-width:100%;border-collapse:separate;border-spacing:0;margin:.5em 0;font-size:.75rem;border-radius:6px;overflow:hidden}.iq-md thead th{background:#6366f12e;color:#a5b4fc;font-weight:600;text-align:left;padding:.5em .8em;border-bottom:2px solid rgba(99,102,241,.3);white-space:nowrap;font-size:.7rem;text-transform:uppercase;letter-spacing:.05em}.iq-md tbody td{padding:.4em .8em;border-bottom:1px solid rgba(255,255,255,.06);white-space:nowrap;color:var(--iq-text-secondary)}.iq-md tbody tr:hover{background:#6366f114}.iq-md img{max-height:80px;max-width:120px;object-fit:cover;border-radius:8px;margin:6px 4px 6px 0;display:inline-block;vertical-align:middle;border:1px solid rgba(255,255,255,.15);box-shadow:0 1px 4px #00000040;cursor:pointer;transition:transform .15s,box-shadow .15s}.iq-md img:hover{transform:scale(1.05);box-shadow:0 3px 12px #6366f159;border-color:var(--iq-accent)}.iq-md img[alt*=logo],.iq-md img[alt*=marca]{max-height:28px;max-width:90px;object-fit:contain;border:none;box-shadow:none;border-radius:4px;background:#ffffffe6;padding:2px 6px}.iq-btn-trace{align-self:flex-start;margin-top:4px;background:transparent;border:1px solid var(--iq-border);color:var(--iq-text-secondary);font-size:.7rem;padding:3px 8px;border-radius:4px;cursor:pointer;transition:all .15s}.iq-btn-trace:hover{border-color:var(--iq-accent);color:var(--iq-accent)}.iq-pipeline{display:flex;align-items:center;gap:8px;animation:iq-fade-in .3s ease-out}.iq-dot{width:8px;height:8px;border-radius:50%;background:var(--iq-accent);animation:iq-pulse 1s ease-in-out infinite}.iq-pipeline-text{font-size:.8rem;color:var(--iq-text-muted);font-style:italic;flex:1}.iq-cancel-btn{background:transparent;border:1px solid var(--iq-border);color:var(--iq-text-muted);font-size:.7rem;padding:2px 8px;border-radius:4px;cursor:pointer;transition:all .15s;flex-shrink:0}.iq-cancel-btn:hover{border-color:#ff6b6b;color:#ff6b6b;background:#ff6b6b1a}@keyframes iq-pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(.7)}}@keyframes iq-fade-in{0%{opacity:0;transform:translate(-6px)}to{opacity:1;transform:translate(0)}}.iq-input-bar{display:flex;gap:8px;padding:10px 12px;border-top:1px solid var(--iq-border);background:var(--iq-bg-card)}.iq-input-bar input{flex:1;padding:8px 12px;background:var(--iq-bg-tertiary);border:1px solid var(--iq-border);border-radius:8px;color:var(--iq-text);font-size:.85rem;font-family:var(--iq-font);outline:none;transition:border-color .15s}.iq-input-bar input:focus{border-color:var(--iq-accent)}.iq-input-bar input::placeholder{color:var(--iq-text-muted)}.iq-input-bar input:disabled{opacity:.5}.iq-btn-send{width:36px;height:36px;border-radius:8px;border:none;background:linear-gradient(135deg,var(--iq-accent),var(--iq-accent-light));color:var(--iq-bg);font-size:1rem;cursor:pointer;transition:all .2s;display:flex;align-items:center;justify-content:center}.iq-btn-send:hover:not(:disabled){box-shadow:0 0 12px #00d4aa66;transform:translateY(-1px)}.iq-btn-send:disabled{opacity:.4;cursor:not-allowed}.iq-trace-overlay{position:fixed;inset:0;z-index:calc(var(--iq-z) + 10);background:#0009;display:flex;align-items:center;justify-content:center;animation:iq-fade-in .2s ease-out}.iq-trace-modal{width:90%;max-width:520px;max-height:80vh;background:var(--iq-bg);border:1px solid var(--iq-border);border-radius:var(--iq-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 20px 50px #0009}.iq-trace-header{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;border-bottom:1px solid var(--iq-border)}.iq-trace-header h3{margin:0;font-size:.95rem;color:var(--iq-text)}.iq-trace-body{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px}.iq-trace-item label{display:block;font-size:.7rem;color:var(--iq-text-muted);margin-bottom:4px;text-transform:uppercase;letter-spacing:.05em}.iq-trace-item code{display:block;padding:8px;background:var(--iq-bg-tertiary);border-radius:4px;font-family:monospace;font-size:.8rem;color:var(--iq-accent);word-break:break-all}.iq-trace-item pre{margin:0;padding:8px;background:var(--iq-bg-tertiary);border-radius:4px;font-family:monospace;font-size:.7rem;overflow-x:auto;max-height:180px;color:var(--iq-text-secondary)}.iq-cache-hit{background:#10b98126!important;color:#10b981!important}.iq-query-code{color:var(--iq-accent)!important}.iq-link-overlay{position:fixed;inset:0;z-index:calc(var(--iq-z) + 20);background:#000000b3;display:flex;align-items:center;justify-content:center;animation:iq-fade-in .2s ease-out;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.iq-link-modal{width:94vw;height:92vh;background:var(--iq-bg);border:1px solid var(--iq-border);border-radius:var(--iq-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 24px 60px #000000b3;animation:iq-expand .25s cubic-bezier(.4,0,.2,1)}.iq-link-header{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;border-bottom:1px solid var(--iq-border);background:var(--iq-bg-card);gap:12px;min-height:44px}.iq-link-title{flex:1;font-size:.78rem;color:var(--iq-text-secondary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-family:monospace}.iq-link-actions{display:flex;gap:4px;flex-shrink:0}.iq-link-actions a{text-decoration:none}.iq-back-btn{flex-shrink:0;font-size:1.1rem;transition:transform .15s ease}.iq-back-btn:hover{transform:translate(-2px)}.iq-iframe-wrapper{flex:1;position:relative;overflow:hidden}.iq-link-iframe{width:100%;height:100%;border:none;background:#fff;transition:opacity .3s ease}.iq-iframe-hidden{opacity:0}.iq-modal-img{width:100%;height:100%;object-fit:contain;background:#1a1a2e}.iq-iframe-loader{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:var(--iq-bg);gap:16px;z-index:2}.iq-spinner{width:40px;height:40px;border:3px solid var(--iq-border);border-top-color:var(--iq-accent);border-radius:50%;animation:iq-spin .8s linear infinite}.iq-loader-text{font-size:.85rem;color:var(--iq-text-secondary);font-weight:500}@keyframes iq-spin{to{transform:rotate(360deg)}}.iq-md a{color:var(--iq-accent);text-decoration:underline;cursor:pointer;transition:color .15s}.iq-md a:hover{color:var(--iq-accent-light)}@media(max-width:480px){.iq-link-modal{width:100vw;height:100dvh;border-radius:0}.iq-link-header{padding:8px 12px}.iq-link-title{font-size:.7rem}}.iq-messages::-webkit-scrollbar{width:5px}.iq-messages::-webkit-scrollbar-track{background:transparent}.iq-messages::-webkit-scrollbar-thumb{background:var(--iq-border);border-radius:4px}.iq-trace-body::-webkit-scrollbar{width:5px}.iq-trace-body::-webkit-scrollbar-track{background:transparent}.iq-trace-body::-webkit-scrollbar-thumb{background:var(--iq-border);border-radius:4px}.iq-expanded .iq-messages::-webkit-scrollbar{width:8px}.iq-expanded .iq-messages{scrollbar-gutter:stable}@media(max-width:480px){.iq-bubble{bottom:16px;right:16px;width:48px;height:48px;font-size:1.3rem}.iq-bubble.iq-bottom-left{left:16px}.iq-bubble .iq-bubble-icon{font-size:1.2rem}.iq-panel{right:8px;left:8px;bottom:72px;width:auto!important;max-width:calc(100vw - 16px);height:calc(100dvh - 90px);max-height:calc(100dvh - 90px)}.iq-panel.iq-bottom-left{left:8px;right:8px}.iq-panel.iq-expanded{inset:0!important;width:100vw!important;height:100dvh!important;max-height:100dvh!important;max-width:100vw!important;border-radius:0}.iq-header{padding:10px 12px}.iq-header-title{font-size:.85rem}.iq-header-btn{padding:6px 8px;min-width:32px;min-height:32px}.iq-messages{padding:8px;gap:8px}.iq-msg{max-width:92%}.iq-msg-bot{max-width:100%}.iq-msg-content{padding:8px 10px;font-size:.8rem}.iq-md{overflow-x:auto;-webkit-overflow-scrolling:touch}.iq-md table{font-size:.65rem;min-width:unset}.iq-md thead th{padding:.35em .5em;font-size:.6rem}.iq-md tbody td{padding:.3em .5em;font-size:.65rem}.iq-empty-icon{font-size:2.5rem}.iq-empty p{font-size:.85rem}.iq-input-bar{padding:8px 10px;gap:6px}.iq-input-bar input{font-size:16px;padding:8px 10px}.iq-btn-send{width:38px;height:38px;flex-shrink:0}.iq-trace-modal{width:calc(100vw - 24px);max-height:90dvh}.iq-trace-header{padding:12px}.iq-trace-header h3{font-size:.85rem}.iq-trace-body{padding:12px}.iq-trace-item pre{font-size:.65rem;max-height:140px}}@media(max-height:500px)and (orientation:landscape){.iq-bubble{bottom:8px;right:8px;width:44px;height:44px;font-size:1.1rem}.iq-bubble.iq-bottom-left{left:8px}.iq-panel{inset:8px 60px 8px 8px;width:auto!important;max-width:calc(100vw - 76px);height:auto!important;max-height:calc(100dvh - 16px);border-radius:var(--iq-radius)}.iq-panel.iq-bottom-left{left:60px;right:8px}.iq-panel.iq-expanded{inset:0!important;width:100vw!important;height:100dvh!important;max-height:100dvh!important;max-width:100vw!important;border-radius:0}.iq-header{padding:6px 12px}.iq-header-title{font-size:.8rem}.iq-messages{padding:6px 10px;gap:6px}.iq-empty-icon{font-size:1.8rem;margin-bottom:4px}.iq-empty p{font-size:.78rem;margin:1px 0}.iq-input-bar{padding:6px 10px}.iq-input-bar input{font-size:16px;padding:6px 10px}.iq-btn-send{width:32px;height:32px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.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: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "pipe", type: i1.JsonPipe, name: "json" }] });
1012
1205
  }
1013
1206
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: IntelligentChatPluginComponent, decorators: [{
1014
1207
  type: Component,
@@ -1055,8 +1248,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImpor
1055
1248
  >
1056
1249
  <!-- Header -->
1057
1250
  <div class="iq-header">
1058
- <span class="iq-header-title">{{ resolvedConfig().title }}</span>
1251
+ <span class="iq-header-title"
1252
+ (touchstart)="onTitleTouchStart($event)"
1253
+ (touchend)="onTitleTouchEnd()"
1254
+ (touchcancel)="onTitleTouchEnd()"
1255
+ >{{ resolvedConfig().title }}</span>
1059
1256
  <div class="iq-header-actions">
1257
+ @if (resolvedConfig().enableDebugMenu) {
1258
+ <div class="iq-debug-menu-wrapper">
1259
+ <button class="iq-header-btn" (click)="toggleDebugMenu()" title="Opciones">⋯</button>
1260
+ @if (showDebugMenu()) {
1261
+ <div class="iq-debug-dropdown">
1262
+ <button class="iq-debug-option" (click)="downloadConversationLog(); toggleDebugMenu()">
1263
+ 📥 Descargar Log
1264
+ </button>
1265
+ </div>
1266
+ }
1267
+ </div>
1268
+ }
1060
1269
  <button class="iq-header-btn" (click)="clearChat()" title="Limpiar chat">🗑️</button>
1061
1270
  @if (resolvedConfig().allowExpand) {
1062
1271
  <button class="iq-header-btn iq-btn-expand" (click)="toggleExpand()" [title]="isExpanded() ? 'Contraer' : 'Expandir'">
@@ -1159,8 +1368,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImpor
1159
1368
  }
1160
1369
  @if (selectedTrace()?.query) {
1161
1370
  <div class="iq-trace-item">
1162
- <label>Query Generada</label>
1163
- <pre class="iq-query-code">{{ selectedTrace()?.query }}</pre>
1371
+ <label>{{ getQuerySections().length > 1 ? 'Queries Generadas (' + getQuerySections().length + ')' : 'Query Generada' }}</label>
1372
+ @for (section of getQuerySections(); track $index) {
1373
+ @if (section.model) {
1374
+ <div style="color: #4ecdc4; font-size: 11px; font-weight: bold; margin-top: 8px;">📋 {{ section.model }}</div>
1375
+ }
1376
+ <pre class="iq-query-code" style="margin-top: 4px;">{{ section.query }}</pre>
1377
+ }
1164
1378
  </div>
1165
1379
  }
1166
1380
  @if (selectedTrace()?.explanation) {
@@ -1220,12 +1434,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImpor
1220
1434
  }
1221
1435
 
1222
1436
  </div><!-- /iq-theme-host -->
1223
- `, styles: [":host{--iq-primary: #1a3a5c;--iq-primary-light: #2a5a8c;--iq-accent: #00d4aa;--iq-accent-light: #33e0be;--iq-bg: #1e1e2f;--iq-bg-card: #252538;--iq-bg-tertiary: #35354a;--iq-text: #ffffff;--iq-text-secondary: #a0a0b0;--iq-text-muted: #6c6c7c;--iq-border: #3a3a4d;--iq-radius: 12px;--iq-bubble-size: 56px;--iq-panel-width: 400px;--iq-panel-height: 520px;--iq-z: 10000;--iq-font: \"Inter\", \"Roboto\", -apple-system, BlinkMacSystemFont, sans-serif;font-family:var(--iq-font)}.iq-bubble{position:fixed;bottom:24px;right:24px;z-index:var(--iq-z);width:var(--iq-bubble-size);height:var(--iq-bubble-size);border-radius:50%;border:none;background:linear-gradient(135deg,var(--iq-accent),var(--iq-accent-light));color:var(--iq-bg);font-size:1.6rem;cursor:pointer;box-shadow:0 4px 16px #00d4aa66;transition:all .3s cubic-bezier(.4,0,.2,1);display:flex;align-items:center;justify-content:center}.iq-bubble:hover{transform:scale(1.1);box-shadow:0 6px 24px #00d4aa80}.iq-bubble .iq-bubble-icon{font-size:1.5rem;pointer-events:none}.iq-bubble-img{width:60%;height:60%;object-fit:contain;border-radius:50%;pointer-events:none}.iq-bubble-svg{width:60%;height:60%;display:flex;align-items:center;justify-content:center;pointer-events:none}.iq-bubble-svg :deep(svg){width:100%;height:100%}.iq-bubble.iq-open{background:var(--iq-bg-tertiary);color:var(--iq-text);box-shadow:0 4px 12px #0000004d;font-size:1.2rem}.iq-bubble.iq-bottom-left{right:auto;left:24px}.iq-bubble-icon{line-height:1}.iq-panel{position:fixed;bottom:92px;right:24px;z-index:var(--iq-z);width:var(--iq-panel-width);height:var(--iq-panel-height);background:var(--iq-bg);border:1px solid var(--iq-border);border-radius:var(--iq-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 12px 40px #00000080;animation:iq-slide-up .3s cubic-bezier(.4,0,.2,1)}.iq-panel.iq-bottom-left{right:auto;left:24px}.iq-panel.iq-expanded{width:100vw!important;height:100vh!important;inset:0!important;border:none;border-radius:0;overflow:clip;z-index:calc(var(--iq-z) + 5);animation:iq-expand .3s cubic-bezier(.4,0,.2,1)}.iq-btn-expand{font-size:1.1rem!important}@keyframes iq-expand{0%{opacity:.8;transform:scale(.95)}to{opacity:1;transform:scale(1)}}@keyframes iq-slide-up{0%{opacity:0;transform:translateY(16px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}.iq-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--iq-border);background:var(--iq-bg-card)}.iq-header-title{font-weight:600;font-size:.95rem;color:var(--iq-text)}.iq-header-actions{display:flex;gap:4px}.iq-header-btn{background:none;border:none;color:var(--iq-text-muted);cursor:pointer;font-size:1rem;padding:4px 6px;border-radius:4px;transition:all .15s}.iq-header-btn:hover{color:var(--iq-text);background:#ffffff14}.iq-auth-error{display:flex;align-items:center;gap:8px;padding:10px 16px;background:#dc354526;color:#ff6b7a;font-size:.8rem;border-bottom:1px solid rgba(220,53,69,.25)}.iq-messages{flex:1;min-height:0;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:10px}.iq-empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;color:var(--iq-text-secondary)}.iq-empty-icon{font-size:3rem;margin-bottom:8px;display:flex;align-items:center;justify-content:center}.iq-empty-img{width:48px;height:48px;object-fit:contain;border-radius:8px}.iq-empty-svg{width:48px;height:48px;display:flex;align-items:center;justify-content:center}.iq-empty-svg :deep(svg){width:100%;height:100%}.iq-empty p{font-size:.95rem;margin:2px 0}.iq-text-muted{color:var(--iq-text-muted)!important;font-size:.8rem!important}.iq-msg{display:flex;flex-direction:column;max-width:85%}.iq-msg-user{align-self:flex-end}.iq-msg-bot{align-self:flex-start;max-width:100%}.iq-msg-user .iq-msg-content{background:linear-gradient(135deg,var(--iq-primary),var(--iq-primary-light));border-radius:12px 12px 0}.iq-msg-bot .iq-msg-content{background:var(--iq-bg-tertiary);border-radius:12px 12px 12px 0}.iq-msg-content{padding:10px 14px;color:var(--iq-text);font-size:.85rem;line-height:1.45}.iq-msg-content p{margin:0;white-space:pre-wrap}.iq-msg-time{display:block;margin-top:4px;font-size:.65rem;color:#ffffff80}.iq-md{line-height:1.5;overflow-x:auto;max-width:100%}.iq-md :first-child{margin-top:0}.iq-md :last-child{margin-bottom:0}.iq-md p{margin:0 0 .4em}.iq-md p:last-child{margin-bottom:0}.iq-md strong{color:var(--iq-accent)}.iq-md ul,.iq-md ol{margin:.3em 0;padding-left:1.2em}.iq-md li{margin:.15em 0}.iq-md code{background:#0000004d;padding:.15em .4em;border-radius:3px;font-size:.82em}.iq-md pre{background:#0000004d;padding:.8em;border-radius:6px;overflow-x:auto;font-size:.78em;margin:.4em 0}.iq-md pre code{background:none;padding:0}.iq-md table{width:max-content;min-width:100%;border-collapse:separate;border-spacing:0;margin:.5em 0;font-size:.75rem;border-radius:6px;overflow:hidden}.iq-md thead th{background:#6366f12e;color:#a5b4fc;font-weight:600;text-align:left;padding:.5em .8em;border-bottom:2px solid rgba(99,102,241,.3);white-space:nowrap;font-size:.7rem;text-transform:uppercase;letter-spacing:.05em}.iq-md tbody td{padding:.4em .8em;border-bottom:1px solid rgba(255,255,255,.06);white-space:nowrap;color:var(--iq-text-secondary)}.iq-md tbody tr:hover{background:#6366f114}.iq-md img{max-height:80px;max-width:120px;object-fit:cover;border-radius:8px;margin:6px 4px 6px 0;display:inline-block;vertical-align:middle;border:1px solid rgba(255,255,255,.15);box-shadow:0 1px 4px #00000040;cursor:pointer;transition:transform .15s,box-shadow .15s}.iq-md img:hover{transform:scale(1.05);box-shadow:0 3px 12px #6366f159;border-color:var(--iq-accent)}.iq-md img[alt*=logo],.iq-md img[alt*=marca]{max-height:28px;max-width:90px;object-fit:contain;border:none;box-shadow:none;border-radius:4px;background:#ffffffe6;padding:2px 6px}.iq-btn-trace{align-self:flex-start;margin-top:4px;background:transparent;border:1px solid var(--iq-border);color:var(--iq-text-secondary);font-size:.7rem;padding:3px 8px;border-radius:4px;cursor:pointer;transition:all .15s}.iq-btn-trace:hover{border-color:var(--iq-accent);color:var(--iq-accent)}.iq-pipeline{display:flex;align-items:center;gap:8px;animation:iq-fade-in .3s ease-out}.iq-dot{width:8px;height:8px;border-radius:50%;background:var(--iq-accent);animation:iq-pulse 1s ease-in-out infinite}.iq-pipeline-text{font-size:.8rem;color:var(--iq-text-muted);font-style:italic;flex:1}.iq-cancel-btn{background:transparent;border:1px solid var(--iq-border);color:var(--iq-text-muted);font-size:.7rem;padding:2px 8px;border-radius:4px;cursor:pointer;transition:all .15s;flex-shrink:0}.iq-cancel-btn:hover{border-color:#ff6b6b;color:#ff6b6b;background:#ff6b6b1a}@keyframes iq-pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(.7)}}@keyframes iq-fade-in{0%{opacity:0;transform:translate(-6px)}to{opacity:1;transform:translate(0)}}.iq-input-bar{display:flex;gap:8px;padding:10px 12px;border-top:1px solid var(--iq-border);background:var(--iq-bg-card)}.iq-input-bar input{flex:1;padding:8px 12px;background:var(--iq-bg-tertiary);border:1px solid var(--iq-border);border-radius:8px;color:var(--iq-text);font-size:.85rem;font-family:var(--iq-font);outline:none;transition:border-color .15s}.iq-input-bar input:focus{border-color:var(--iq-accent)}.iq-input-bar input::placeholder{color:var(--iq-text-muted)}.iq-input-bar input:disabled{opacity:.5}.iq-btn-send{width:36px;height:36px;border-radius:8px;border:none;background:linear-gradient(135deg,var(--iq-accent),var(--iq-accent-light));color:var(--iq-bg);font-size:1rem;cursor:pointer;transition:all .2s;display:flex;align-items:center;justify-content:center}.iq-btn-send:hover:not(:disabled){box-shadow:0 0 12px #00d4aa66;transform:translateY(-1px)}.iq-btn-send:disabled{opacity:.4;cursor:not-allowed}.iq-trace-overlay{position:fixed;inset:0;z-index:calc(var(--iq-z) + 10);background:#0009;display:flex;align-items:center;justify-content:center;animation:iq-fade-in .2s ease-out}.iq-trace-modal{width:90%;max-width:520px;max-height:80vh;background:var(--iq-bg);border:1px solid var(--iq-border);border-radius:var(--iq-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 20px 50px #0009}.iq-trace-header{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;border-bottom:1px solid var(--iq-border)}.iq-trace-header h3{margin:0;font-size:.95rem;color:var(--iq-text)}.iq-trace-body{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px}.iq-trace-item label{display:block;font-size:.7rem;color:var(--iq-text-muted);margin-bottom:4px;text-transform:uppercase;letter-spacing:.05em}.iq-trace-item code{display:block;padding:8px;background:var(--iq-bg-tertiary);border-radius:4px;font-family:monospace;font-size:.8rem;color:var(--iq-accent);word-break:break-all}.iq-trace-item pre{margin:0;padding:8px;background:var(--iq-bg-tertiary);border-radius:4px;font-family:monospace;font-size:.7rem;overflow-x:auto;max-height:180px;color:var(--iq-text-secondary)}.iq-cache-hit{background:#10b98126!important;color:#10b981!important}.iq-query-code{color:var(--iq-accent)!important}.iq-link-overlay{position:fixed;inset:0;z-index:calc(var(--iq-z) + 20);background:#000000b3;display:flex;align-items:center;justify-content:center;animation:iq-fade-in .2s ease-out;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.iq-link-modal{width:94vw;height:92vh;background:var(--iq-bg);border:1px solid var(--iq-border);border-radius:var(--iq-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 24px 60px #000000b3;animation:iq-expand .25s cubic-bezier(.4,0,.2,1)}.iq-link-header{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;border-bottom:1px solid var(--iq-border);background:var(--iq-bg-card);gap:12px;min-height:44px}.iq-link-title{flex:1;font-size:.78rem;color:var(--iq-text-secondary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-family:monospace}.iq-link-actions{display:flex;gap:4px;flex-shrink:0}.iq-link-actions a{text-decoration:none}.iq-back-btn{flex-shrink:0;font-size:1.1rem;transition:transform .15s ease}.iq-back-btn:hover{transform:translate(-2px)}.iq-iframe-wrapper{flex:1;position:relative;overflow:hidden}.iq-link-iframe{width:100%;height:100%;border:none;background:#fff;transition:opacity .3s ease}.iq-iframe-hidden{opacity:0}.iq-modal-img{width:100%;height:100%;object-fit:contain;background:#1a1a2e}.iq-iframe-loader{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:var(--iq-bg);gap:16px;z-index:2}.iq-spinner{width:40px;height:40px;border:3px solid var(--iq-border);border-top-color:var(--iq-accent);border-radius:50%;animation:iq-spin .8s linear infinite}.iq-loader-text{font-size:.85rem;color:var(--iq-text-secondary);font-weight:500}@keyframes iq-spin{to{transform:rotate(360deg)}}.iq-md a{color:var(--iq-accent);text-decoration:underline;cursor:pointer;transition:color .15s}.iq-md a:hover{color:var(--iq-accent-light)}@media(max-width:480px){.iq-link-modal{width:100vw;height:100dvh;border-radius:0}.iq-link-header{padding:8px 12px}.iq-link-title{font-size:.7rem}}.iq-messages::-webkit-scrollbar{width:5px}.iq-messages::-webkit-scrollbar-track{background:transparent}.iq-messages::-webkit-scrollbar-thumb{background:var(--iq-border);border-radius:4px}.iq-trace-body::-webkit-scrollbar{width:5px}.iq-trace-body::-webkit-scrollbar-track{background:transparent}.iq-trace-body::-webkit-scrollbar-thumb{background:var(--iq-border);border-radius:4px}.iq-expanded .iq-messages::-webkit-scrollbar{width:8px}.iq-expanded .iq-messages{scrollbar-gutter:stable}@media(max-width:480px){.iq-bubble{bottom:16px;right:16px;width:48px;height:48px;font-size:1.3rem}.iq-bubble.iq-bottom-left{left:16px}.iq-bubble .iq-bubble-icon{font-size:1.2rem}.iq-panel{right:8px;left:8px;bottom:72px;width:auto!important;max-width:calc(100vw - 16px);height:calc(100dvh - 90px);max-height:calc(100dvh - 90px)}.iq-panel.iq-bottom-left{left:8px;right:8px}.iq-panel.iq-expanded{inset:0!important;width:100vw!important;height:100dvh!important;max-height:100dvh!important;max-width:100vw!important;border-radius:0}.iq-header{padding:10px 12px}.iq-header-title{font-size:.85rem}.iq-header-btn{padding:6px 8px;min-width:32px;min-height:32px}.iq-messages{padding:8px;gap:8px}.iq-msg{max-width:92%}.iq-msg-bot{max-width:100%}.iq-msg-content{padding:8px 10px;font-size:.8rem}.iq-md{overflow-x:auto;-webkit-overflow-scrolling:touch}.iq-md table{font-size:.65rem;min-width:unset}.iq-md thead th{padding:.35em .5em;font-size:.6rem}.iq-md tbody td{padding:.3em .5em;font-size:.65rem}.iq-empty-icon{font-size:2.5rem}.iq-empty p{font-size:.85rem}.iq-input-bar{padding:8px 10px;gap:6px}.iq-input-bar input{font-size:16px;padding:8px 10px}.iq-btn-send{width:38px;height:38px;flex-shrink:0}.iq-trace-modal{width:calc(100vw - 24px);max-height:90dvh}.iq-trace-header{padding:12px}.iq-trace-header h3{font-size:.85rem}.iq-trace-body{padding:12px}.iq-trace-item pre{font-size:.65rem;max-height:140px}}@media(max-height:500px)and (orientation:landscape){.iq-bubble{bottom:8px;right:8px;width:44px;height:44px;font-size:1.1rem}.iq-bubble.iq-bottom-left{left:8px}.iq-panel{inset:8px 60px 8px 8px;width:auto!important;max-width:calc(100vw - 76px);height:auto!important;max-height:calc(100dvh - 16px);border-radius:var(--iq-radius)}.iq-panel.iq-bottom-left{left:60px;right:8px}.iq-panel.iq-expanded{inset:0!important;width:100vw!important;height:100dvh!important;max-height:100dvh!important;max-width:100vw!important;border-radius:0}.iq-header{padding:6px 12px}.iq-header-title{font-size:.8rem}.iq-messages{padding:6px 10px;gap:6px}.iq-empty-icon{font-size:1.8rem;margin-bottom:4px}.iq-empty p{font-size:.78rem;margin:1px 0}.iq-input-bar{padding:6px 10px}.iq-input-bar input{font-size:16px;padding:6px 10px}.iq-btn-send{width:32px;height:32px}}\n"] }]
1437
+ `, styles: [":host{--iq-primary: #1a3a5c;--iq-primary-light: #2a5a8c;--iq-accent: #00d4aa;--iq-accent-light: #33e0be;--iq-bg: #1e1e2f;--iq-bg-card: #252538;--iq-bg-tertiary: #35354a;--iq-text: #ffffff;--iq-text-secondary: #a0a0b0;--iq-text-muted: #6c6c7c;--iq-border: #3a3a4d;--iq-radius: 12px;--iq-bubble-size: 56px;--iq-panel-width: 400px;--iq-panel-height: 520px;--iq-z: 10000;--iq-font: \"Inter\", \"Roboto\", -apple-system, BlinkMacSystemFont, sans-serif;font-family:var(--iq-font)}.iq-bubble{position:fixed;bottom:24px;right:24px;z-index:var(--iq-z);width:var(--iq-bubble-size);height:var(--iq-bubble-size);border-radius:50%;border:none;background:linear-gradient(135deg,var(--iq-accent),var(--iq-accent-light));color:var(--iq-bg);font-size:1.6rem;cursor:pointer;box-shadow:0 4px 16px #00d4aa66;transition:all .3s cubic-bezier(.4,0,.2,1);display:flex;align-items:center;justify-content:center}.iq-bubble:hover{transform:scale(1.1);box-shadow:0 6px 24px #00d4aa80}.iq-bubble .iq-bubble-icon{font-size:1.5rem;pointer-events:none}.iq-bubble-img{width:60%;height:60%;object-fit:contain;border-radius:50%;pointer-events:none}.iq-bubble-svg{width:60%;height:60%;display:flex;align-items:center;justify-content:center;pointer-events:none}.iq-bubble-svg :deep(svg){width:100%;height:100%}.iq-bubble.iq-open{background:var(--iq-bg-tertiary);color:var(--iq-text);box-shadow:0 4px 12px #0000004d;font-size:1.2rem}.iq-bubble.iq-bottom-left{right:auto;left:24px}.iq-bubble-icon{line-height:1}.iq-panel{position:fixed;bottom:92px;right:24px;z-index:var(--iq-z);width:var(--iq-panel-width);height:var(--iq-panel-height);background:var(--iq-bg);border:1px solid var(--iq-border);border-radius:var(--iq-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 12px 40px #00000080;animation:iq-slide-up .3s cubic-bezier(.4,0,.2,1)}.iq-panel.iq-bottom-left{right:auto;left:24px}.iq-panel.iq-expanded{width:100vw!important;height:100vh!important;inset:0!important;border:none;border-radius:0;overflow:clip;z-index:calc(var(--iq-z) + 5);animation:iq-expand .3s cubic-bezier(.4,0,.2,1)}.iq-btn-expand{font-size:1.1rem!important}@keyframes iq-expand{0%{opacity:.8;transform:scale(.95)}to{opacity:1;transform:scale(1)}}@keyframes iq-slide-up{0%{opacity:0;transform:translateY(16px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}.iq-header{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--iq-border);background:var(--iq-bg-card)}.iq-header-title{font-weight:600;font-size:.95rem;color:var(--iq-text)}.iq-header-actions{display:flex;gap:4px}.iq-header-btn{background:none;border:none;color:var(--iq-text-muted);cursor:pointer;font-size:1rem;padding:4px 6px;border-radius:4px;transition:all .15s}.iq-header-btn:hover{color:var(--iq-text);background:#ffffff14}.iq-debug-menu-wrapper{position:relative}.iq-debug-dropdown{position:absolute;top:100%;right:0;margin-top:4px;min-width:180px;background:var(--iq-bg-card);border:1px solid var(--iq-border);border-radius:8px;box-shadow:0 8px 24px #0006;z-index:calc(var(--iq-z) + 10);padding:4px;animation:iq-dropdown-in .15s ease-out}@keyframes iq-dropdown-in{0%{opacity:0;transform:translateY(-4px) scale(.95)}to{opacity:1;transform:translateY(0) scale(1)}}.iq-debug-option{display:flex;align-items:center;gap:8px;width:100%;padding:8px 12px;background:none;border:none;color:var(--iq-text);font-size:.85rem;cursor:pointer;border-radius:6px;transition:background .15s;text-align:left}.iq-debug-option:hover{background:#ffffff14}.iq-auth-error{display:flex;align-items:center;gap:8px;padding:10px 16px;background:#dc354526;color:#ff6b7a;font-size:.8rem;border-bottom:1px solid rgba(220,53,69,.25)}.iq-messages{flex:1;min-height:0;overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:10px}.iq-empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;color:var(--iq-text-secondary)}.iq-empty-icon{font-size:3rem;margin-bottom:8px;display:flex;align-items:center;justify-content:center}.iq-empty-img{width:48px;height:48px;object-fit:contain;border-radius:8px}.iq-empty-svg{width:48px;height:48px;display:flex;align-items:center;justify-content:center}.iq-empty-svg :deep(svg){width:100%;height:100%}.iq-empty p{font-size:.95rem;margin:2px 0}.iq-text-muted{color:var(--iq-text-muted)!important;font-size:.8rem!important}.iq-msg{display:flex;flex-direction:column;max-width:85%}.iq-msg-user{align-self:flex-end}.iq-msg-bot{align-self:flex-start;max-width:100%}.iq-msg-user .iq-msg-content{background:linear-gradient(135deg,var(--iq-primary),var(--iq-primary-light));border-radius:12px 12px 0}.iq-msg-bot .iq-msg-content{background:var(--iq-bg-tertiary);border-radius:12px 12px 12px 0}.iq-msg-content{padding:10px 14px;color:var(--iq-text);font-size:.85rem;line-height:1.45}.iq-msg-content p{margin:0;white-space:pre-wrap}.iq-msg-time{display:block;margin-top:4px;font-size:.65rem;color:#ffffff80}.iq-md{line-height:1.5;overflow-x:auto;max-width:100%}.iq-md :first-child{margin-top:0}.iq-md :last-child{margin-bottom:0}.iq-md p{margin:0 0 .4em}.iq-md p:last-child{margin-bottom:0}.iq-md strong{color:var(--iq-accent)}.iq-md ul,.iq-md ol{margin:.3em 0;padding-left:1.2em}.iq-md li{margin:.15em 0}.iq-md code{background:#0000004d;padding:.15em .4em;border-radius:3px;font-size:.82em}.iq-md pre{background:#0000004d;padding:.8em;border-radius:6px;overflow-x:auto;font-size:.78em;margin:.4em 0}.iq-md pre code{background:none;padding:0}.iq-md table{width:max-content;min-width:100%;border-collapse:separate;border-spacing:0;margin:.5em 0;font-size:.75rem;border-radius:6px;overflow:hidden}.iq-md thead th{background:#6366f12e;color:#a5b4fc;font-weight:600;text-align:left;padding:.5em .8em;border-bottom:2px solid rgba(99,102,241,.3);white-space:nowrap;font-size:.7rem;text-transform:uppercase;letter-spacing:.05em}.iq-md tbody td{padding:.4em .8em;border-bottom:1px solid rgba(255,255,255,.06);white-space:nowrap;color:var(--iq-text-secondary)}.iq-md tbody tr:hover{background:#6366f114}.iq-md img{max-height:80px;max-width:120px;object-fit:cover;border-radius:8px;margin:6px 4px 6px 0;display:inline-block;vertical-align:middle;border:1px solid rgba(255,255,255,.15);box-shadow:0 1px 4px #00000040;cursor:pointer;transition:transform .15s,box-shadow .15s}.iq-md img:hover{transform:scale(1.05);box-shadow:0 3px 12px #6366f159;border-color:var(--iq-accent)}.iq-md img[alt*=logo],.iq-md img[alt*=marca]{max-height:28px;max-width:90px;object-fit:contain;border:none;box-shadow:none;border-radius:4px;background:#ffffffe6;padding:2px 6px}.iq-btn-trace{align-self:flex-start;margin-top:4px;background:transparent;border:1px solid var(--iq-border);color:var(--iq-text-secondary);font-size:.7rem;padding:3px 8px;border-radius:4px;cursor:pointer;transition:all .15s}.iq-btn-trace:hover{border-color:var(--iq-accent);color:var(--iq-accent)}.iq-pipeline{display:flex;align-items:center;gap:8px;animation:iq-fade-in .3s ease-out}.iq-dot{width:8px;height:8px;border-radius:50%;background:var(--iq-accent);animation:iq-pulse 1s ease-in-out infinite}.iq-pipeline-text{font-size:.8rem;color:var(--iq-text-muted);font-style:italic;flex:1}.iq-cancel-btn{background:transparent;border:1px solid var(--iq-border);color:var(--iq-text-muted);font-size:.7rem;padding:2px 8px;border-radius:4px;cursor:pointer;transition:all .15s;flex-shrink:0}.iq-cancel-btn:hover{border-color:#ff6b6b;color:#ff6b6b;background:#ff6b6b1a}@keyframes iq-pulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(.7)}}@keyframes iq-fade-in{0%{opacity:0;transform:translate(-6px)}to{opacity:1;transform:translate(0)}}.iq-input-bar{display:flex;gap:8px;padding:10px 12px;border-top:1px solid var(--iq-border);background:var(--iq-bg-card)}.iq-input-bar input{flex:1;padding:8px 12px;background:var(--iq-bg-tertiary);border:1px solid var(--iq-border);border-radius:8px;color:var(--iq-text);font-size:.85rem;font-family:var(--iq-font);outline:none;transition:border-color .15s}.iq-input-bar input:focus{border-color:var(--iq-accent)}.iq-input-bar input::placeholder{color:var(--iq-text-muted)}.iq-input-bar input:disabled{opacity:.5}.iq-btn-send{width:36px;height:36px;border-radius:8px;border:none;background:linear-gradient(135deg,var(--iq-accent),var(--iq-accent-light));color:var(--iq-bg);font-size:1rem;cursor:pointer;transition:all .2s;display:flex;align-items:center;justify-content:center}.iq-btn-send:hover:not(:disabled){box-shadow:0 0 12px #00d4aa66;transform:translateY(-1px)}.iq-btn-send:disabled{opacity:.4;cursor:not-allowed}.iq-trace-overlay{position:fixed;inset:0;z-index:calc(var(--iq-z) + 10);background:#0009;display:flex;align-items:center;justify-content:center;animation:iq-fade-in .2s ease-out}.iq-trace-modal{width:90%;max-width:520px;max-height:80vh;background:var(--iq-bg);border:1px solid var(--iq-border);border-radius:var(--iq-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 20px 50px #0009}.iq-trace-header{display:flex;align-items:center;justify-content:space-between;padding:14px 16px;border-bottom:1px solid var(--iq-border)}.iq-trace-header h3{margin:0;font-size:.95rem;color:var(--iq-text)}.iq-trace-body{flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px}.iq-trace-item label{display:block;font-size:.7rem;color:var(--iq-text-muted);margin-bottom:4px;text-transform:uppercase;letter-spacing:.05em}.iq-trace-item code{display:block;padding:8px;background:var(--iq-bg-tertiary);border-radius:4px;font-family:monospace;font-size:.8rem;color:var(--iq-accent);word-break:break-all}.iq-trace-item pre{margin:0;padding:8px;background:var(--iq-bg-tertiary);border-radius:4px;font-family:monospace;font-size:.7rem;overflow-x:auto;max-height:180px;color:var(--iq-text-secondary)}.iq-cache-hit{background:#10b98126!important;color:#10b981!important}.iq-query-code{color:var(--iq-accent)!important}.iq-link-overlay{position:fixed;inset:0;z-index:calc(var(--iq-z) + 20);background:#000000b3;display:flex;align-items:center;justify-content:center;animation:iq-fade-in .2s ease-out;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.iq-link-modal{width:94vw;height:92vh;background:var(--iq-bg);border:1px solid var(--iq-border);border-radius:var(--iq-radius);display:flex;flex-direction:column;overflow:hidden;box-shadow:0 24px 60px #000000b3;animation:iq-expand .25s cubic-bezier(.4,0,.2,1)}.iq-link-header{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;border-bottom:1px solid var(--iq-border);background:var(--iq-bg-card);gap:12px;min-height:44px}.iq-link-title{flex:1;font-size:.78rem;color:var(--iq-text-secondary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-family:monospace}.iq-link-actions{display:flex;gap:4px;flex-shrink:0}.iq-link-actions a{text-decoration:none}.iq-back-btn{flex-shrink:0;font-size:1.1rem;transition:transform .15s ease}.iq-back-btn:hover{transform:translate(-2px)}.iq-iframe-wrapper{flex:1;position:relative;overflow:hidden}.iq-link-iframe{width:100%;height:100%;border:none;background:#fff;transition:opacity .3s ease}.iq-iframe-hidden{opacity:0}.iq-modal-img{width:100%;height:100%;object-fit:contain;background:#1a1a2e}.iq-iframe-loader{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:var(--iq-bg);gap:16px;z-index:2}.iq-spinner{width:40px;height:40px;border:3px solid var(--iq-border);border-top-color:var(--iq-accent);border-radius:50%;animation:iq-spin .8s linear infinite}.iq-loader-text{font-size:.85rem;color:var(--iq-text-secondary);font-weight:500}@keyframes iq-spin{to{transform:rotate(360deg)}}.iq-md a{color:var(--iq-accent);text-decoration:underline;cursor:pointer;transition:color .15s}.iq-md a:hover{color:var(--iq-accent-light)}@media(max-width:480px){.iq-link-modal{width:100vw;height:100dvh;border-radius:0}.iq-link-header{padding:8px 12px}.iq-link-title{font-size:.7rem}}.iq-messages::-webkit-scrollbar{width:5px}.iq-messages::-webkit-scrollbar-track{background:transparent}.iq-messages::-webkit-scrollbar-thumb{background:var(--iq-border);border-radius:4px}.iq-trace-body::-webkit-scrollbar{width:5px}.iq-trace-body::-webkit-scrollbar-track{background:transparent}.iq-trace-body::-webkit-scrollbar-thumb{background:var(--iq-border);border-radius:4px}.iq-expanded .iq-messages::-webkit-scrollbar{width:8px}.iq-expanded .iq-messages{scrollbar-gutter:stable}@media(max-width:480px){.iq-bubble{bottom:16px;right:16px;width:48px;height:48px;font-size:1.3rem}.iq-bubble.iq-bottom-left{left:16px}.iq-bubble .iq-bubble-icon{font-size:1.2rem}.iq-panel{right:8px;left:8px;bottom:72px;width:auto!important;max-width:calc(100vw - 16px);height:calc(100dvh - 90px);max-height:calc(100dvh - 90px)}.iq-panel.iq-bottom-left{left:8px;right:8px}.iq-panel.iq-expanded{inset:0!important;width:100vw!important;height:100dvh!important;max-height:100dvh!important;max-width:100vw!important;border-radius:0}.iq-header{padding:10px 12px}.iq-header-title{font-size:.85rem}.iq-header-btn{padding:6px 8px;min-width:32px;min-height:32px}.iq-messages{padding:8px;gap:8px}.iq-msg{max-width:92%}.iq-msg-bot{max-width:100%}.iq-msg-content{padding:8px 10px;font-size:.8rem}.iq-md{overflow-x:auto;-webkit-overflow-scrolling:touch}.iq-md table{font-size:.65rem;min-width:unset}.iq-md thead th{padding:.35em .5em;font-size:.6rem}.iq-md tbody td{padding:.3em .5em;font-size:.65rem}.iq-empty-icon{font-size:2.5rem}.iq-empty p{font-size:.85rem}.iq-input-bar{padding:8px 10px;gap:6px}.iq-input-bar input{font-size:16px;padding:8px 10px}.iq-btn-send{width:38px;height:38px;flex-shrink:0}.iq-trace-modal{width:calc(100vw - 24px);max-height:90dvh}.iq-trace-header{padding:12px}.iq-trace-header h3{font-size:.85rem}.iq-trace-body{padding:12px}.iq-trace-item pre{font-size:.65rem;max-height:140px}}@media(max-height:500px)and (orientation:landscape){.iq-bubble{bottom:8px;right:8px;width:44px;height:44px;font-size:1.1rem}.iq-bubble.iq-bottom-left{left:8px}.iq-panel{inset:8px 60px 8px 8px;width:auto!important;max-width:calc(100vw - 76px);height:auto!important;max-height:calc(100dvh - 16px);border-radius:var(--iq-radius)}.iq-panel.iq-bottom-left{left:60px;right:8px}.iq-panel.iq-expanded{inset:0!important;width:100vw!important;height:100dvh!important;max-height:100dvh!important;max-width:100vw!important;border-radius:0}.iq-header{padding:6px 12px}.iq-header-title{font-size:.8rem}.iq-messages{padding:6px 10px;gap:6px}.iq-empty-icon{font-size:1.8rem;margin-bottom:4px}.iq-empty p{font-size:.78rem;margin:1px 0}.iq-input-bar{padding:6px 10px}.iq-input-bar input{font-size:16px;padding:6px 10px}.iq-btn-send{width:32px;height:32px}}\n"] }]
1224
1438
  }], propDecorators: { chatContainer: [{
1225
1439
  type: ViewChild,
1226
1440
  args: ['chatContainer']
1227
1441
  }], config: [{
1228
1442
  type: Input
1443
+ }], onDebugKeydown: [{
1444
+ type: HostListener,
1445
+ args: ['window:keydown', ['$event']]
1229
1446
  }] } });
1230
1447
 
1231
1448
  /*
@@ -1 +1 @@
1
- {"version":3,"file":"maquito-chat-plugin.mjs","sources":["../../../frontend/maquito-chat-plugin/src/lib/intelligent-chat.service.ts","../../../frontend/maquito-chat-plugin/src/lib/intelligent-chat-plugin.component.ts","../../../frontend/maquito-chat-plugin/src/public-api.ts","../../../frontend/maquito-chat-plugin/src/maquito-chat-plugin.ts"],"sourcesContent":["import { Injectable, inject, NgZone } from '@angular/core';\r\nimport { HttpClient, HttpHeaders } from '@angular/common/http';\r\nimport { Observable } from 'rxjs';\r\n\r\n/**\r\n * Standalone HTTP service for the Maquito Chat Plugin.\r\n * Decoupled from any host app service — uses apiUrl + token from config.\r\n * Replicates exactly the same endpoints used by the Maquito Core API.\r\n *\r\n * IMPORTANT: The SSE streaming method runs OUTSIDE Angular Zone to prevent\r\n * change detection storms that freeze the host application's UI.\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class IntelligentChatService {\r\n\r\n private http = inject(HttpClient);\r\n private ngZone = inject(NgZone);\r\n\r\n /**\r\n * Execute an intelligent query (POST /api/query).\r\n * Auth via X-Api-Key header.\r\n */\r\n executeIntelligentQuery(\r\n apiUrl: string,\r\n token: string,\r\n systemId: string,\r\n question: string,\r\n conversationHistory: { role: string; content: string }[] = [],\r\n baseContext?: string,\r\n skipPatternCache?: boolean,\r\n preferTableFormat?: boolean,\r\n userName?: string,\r\n personality?: string\r\n ): Observable<any> {\r\n const headers = this.buildHeaders(token);\r\n const body: any = { systemId, question, conversationHistory };\r\n if (baseContext) body.baseContext = baseContext;\r\n if (skipPatternCache) body.skipPatternCache = skipPatternCache;\r\n if (preferTableFormat !== undefined) body.preferTableFormat = preferTableFormat;\r\n if (userName) body.userName = userName;\r\n if (personality) body.personality = personality;\r\n return this.http.post<any>(`${apiUrl}/query`, body, { headers });\r\n }\r\n\r\n /**\r\n * Execute an intelligent query with SSE streaming progress.\r\n * Emits: { type: 'progress', step: string, message: string }\r\n * { type: 'result', data: any }\r\n *\r\n * The fetch + reader loop runs OUTSIDE Angular Zone to avoid\r\n * triggering change detection on every microtask (which would\r\n * freeze the host app). Emissions re-enter the zone via ngZone.run().\r\n */\r\n executeIntelligentQueryStream(\r\n apiUrl: string,\r\n token: string,\r\n systemId: string,\r\n question: string,\r\n conversationHistory: { role: string; content: string }[] = [],\r\n baseContext?: string,\r\n skipPatternCache?: boolean,\r\n preferTableFormat?: boolean,\r\n userName?: string,\r\n personality?: string\r\n ): Observable<{ type: 'progress' | 'result'; step?: string; message?: string; data?: any }> {\r\n const body: any = { systemId, question, conversationHistory };\r\n if (baseContext) body.baseContext = baseContext;\r\n if (skipPatternCache) body.skipPatternCache = skipPatternCache;\r\n if (preferTableFormat !== undefined) body.preferTableFormat = preferTableFormat;\r\n if (userName) body.userName = userName;\r\n if (personality) body.personality = personality;\r\n\r\n const FETCH_TIMEOUT_MS = 120_000; // 2 min max for the entire request\r\n const INACTIVITY_TIMEOUT_MS = 60_000; // 60s without data = abort\r\n const zone = this.ngZone;\r\n\r\n return new Observable(observer => {\r\n const abortController = new AbortController();\r\n\r\n // Run the entire fetch + SSE loop OUTSIDE Angular Zone\r\n // to prevent change detection storms that freeze the UI\r\n zone.runOutsideAngular(() => {\r\n // Combine user abort + global timeout\r\n let signal: AbortSignal;\r\n if (typeof AbortSignal.any === 'function') {\r\n signal = AbortSignal.any([abortController.signal, AbortSignal.timeout(FETCH_TIMEOUT_MS)]);\r\n } else {\r\n signal = abortController.signal;\r\n setTimeout(() => abortController.abort(), FETCH_TIMEOUT_MS);\r\n }\r\n\r\n fetch(`${apiUrl}/query/stream`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json', 'X-Api-Key': token },\r\n body: JSON.stringify(body),\r\n signal\r\n }).then(async response => {\r\n if (!response.ok || !response.body) {\r\n zone.run(() => observer.error(new Error(`HTTP ${response.status}`)));\r\n return;\r\n }\r\n const reader = response.body.getReader();\r\n const decoder = new TextDecoder();\r\n let buffer = '';\r\n let lastDataTime = Date.now();\r\n\r\n while (true) {\r\n // Race reader vs inactivity timeout\r\n const readPromise = reader.read();\r\n const timeoutPromise = new Promise<never>((_, reject) => {\r\n const elapsed = Date.now() - lastDataTime;\r\n const remaining = Math.max(INACTIVITY_TIMEOUT_MS - elapsed, 100);\r\n setTimeout(() => reject(new Error('SSE inactivity timeout: no data received for 60s')), remaining);\r\n });\r\n\r\n let result: ReadableStreamReadResult<Uint8Array>;\r\n try {\r\n result = await Promise.race([readPromise, timeoutPromise]);\r\n } catch (err) {\r\n reader.cancel();\r\n abortController.abort();\r\n zone.run(() => observer.error(err));\r\n return;\r\n }\r\n\r\n const { done, value } = result;\r\n if (done) break;\r\n lastDataTime = Date.now();\r\n buffer += decoder.decode(value, { stream: true });\r\n\r\n const parts = buffer.split('\\n\\n');\r\n buffer = parts.pop() || '';\r\n for (const part of parts) {\r\n const lines = part.split('\\n');\r\n let eventType = '';\r\n let eventData = '';\r\n for (const line of lines) {\r\n if (line.startsWith('event: ')) eventType = line.slice(7);\r\n else if (line.startsWith('data: ')) eventData = line.slice(6);\r\n }\r\n if (!eventType || !eventData) continue;\r\n try {\r\n const parsed = JSON.parse(eventData);\r\n if (eventType === 'progress') {\r\n // Emit progress WITHOUT re-entering Angular zone.\r\n // The component debounces these via requestAnimationFrame.\r\n observer.next({ type: 'progress', step: parsed.step, message: parsed.message });\r\n } else if (eventType === 'result') {\r\n zone.run(() => {\r\n observer.next({ type: 'result', data: parsed });\r\n observer.complete();\r\n });\r\n } else if (eventType === 'error') {\r\n zone.run(() => observer.error(parsed));\r\n }\r\n } catch { /* skip malformed JSON */ }\r\n }\r\n }\r\n if (!observer.closed) {\r\n zone.run(() => observer.complete());\r\n }\r\n }).catch(err => {\r\n if (err.name !== 'AbortError') {\r\n zone.run(() => observer.error(err));\r\n }\r\n });\r\n }); // end runOutsideAngular\r\n\r\n return () => abortController.abort();\r\n });\r\n }\r\n\r\n /**\r\n * Standard orchestration ask (POST /api/cortex/ask).\r\n * Used when intelligent query mode is disabled.\r\n */\r\n ask(apiUrl: string, token: string, text: string): Observable<any> {\r\n const headers = this.buildHeaders(token);\r\n return this.http.post<any>(`${apiUrl}/cortex/ask`, { text }, { headers });\r\n }\r\n\r\n private buildHeaders(token: string): HttpHeaders {\r\n return new HttpHeaders({ 'X-Api-Key': token });\r\n }\r\n}\r\n","import {\r\n Component, Input, inject, signal, computed, ViewChild, ElementRef,\r\n AfterViewChecked, OnChanges, OnInit, OnDestroy, SimpleChanges, HostListener\r\n} from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { DomSanitizer, SafeHtml, SafeResourceUrl } from '@angular/platform-browser';\r\nimport { marked } from 'marked';\r\nimport { Subscription } from 'rxjs';\r\nimport { IntelligentChatConfig, ChatMessage, PluginTheme } from './intelligent-chat.models';\r\nimport { IntelligentChatService } from './intelligent-chat.service';\r\n\r\n@Component({\r\n selector: 'intelligent-chat-plugin',\r\n standalone: true,\r\n imports: [CommonModule, FormsModule],\r\n template: `\r\n <!-- Host theme overrides -->\r\n <div class=\"iq-theme-host\" [ngStyle]=\"themeStyles()\">\r\n\r\n <!-- Floating Bubble Button (hidden when expanded) -->\r\n @if (!isExpanded()) {\r\n <button\r\n class=\"iq-bubble\"\r\n [class.iq-bottom-left]=\"resolvedConfig().position === 'bottom-left'\"\r\n [class.iq-open]=\"isOpen()\"\r\n [style.position]=\"resolvedConfig().stickyBubble ? 'fixed' : 'absolute'\"\r\n (click)=\"toggleChat()\"\r\n [attr.aria-label]=\"isOpen() ? 'Cerrar chat' : 'Abrir chat'\"\r\n >\r\n @if (isOpen()) {\r\n <span class=\"iq-bubble-icon\">✕</span>\r\n } @else {\r\n @switch (resolvedConfig().bubbleIconType) {\r\n @case ('image') {\r\n <img [src]=\"resolvedConfig().bubbleImageUrl\" alt=\"Chat\" class=\"iq-bubble-img\" />\r\n }\r\n @case ('svg') {\r\n <span class=\"iq-bubble-svg\" [innerHTML]=\"sanitizedBubbleSvg()\"></span>\r\n }\r\n @default {\r\n <span class=\"iq-bubble-icon\">{{ resolvedConfig().bubbleIcon }}</span>\r\n }\r\n }\r\n }\r\n </button>\r\n }\r\n\r\n <!-- Chat Panel -->\r\n @if (isOpen()) {\r\n <div\r\n class=\"iq-panel\"\r\n [class.iq-bottom-left]=\"resolvedConfig().position === 'bottom-left'\"\r\n [class.iq-expanded]=\"isExpanded()\"\r\n [class]=\"resolvedConfig().themeClass || ''\"\r\n [style.position]=\"resolvedConfig().stickyBubble ? 'fixed' : 'absolute'\"\r\n >\r\n <!-- Header -->\r\n <div class=\"iq-header\">\r\n <span class=\"iq-header-title\">{{ resolvedConfig().title }}</span>\r\n <div class=\"iq-header-actions\">\r\n <button class=\"iq-header-btn\" (click)=\"clearChat()\" title=\"Limpiar chat\">🗑️</button>\r\n @if (resolvedConfig().allowExpand) {\r\n <button class=\"iq-header-btn iq-btn-expand\" (click)=\"toggleExpand()\" [title]=\"isExpanded() ? 'Contraer' : 'Expandir'\">\r\n {{ isExpanded() ? '⊡' : '⛶' }}\r\n </button>\r\n }\r\n <button class=\"iq-header-btn\" (click)=\"isExpanded() ? toggleExpand() : toggleChat()\">✕</button>\r\n </div>\r\n </div>\r\n\r\n <!-- Auth Error Banner -->\r\n @if (authError()) {\r\n <div class=\"iq-auth-error\">\r\n <span>🔒</span>\r\n <span>{{ authError() }}</span>\r\n </div>\r\n }\r\n\r\n <!-- Messages -->\r\n <div class=\"iq-messages\" #chatContainer>\r\n @if (messages().length === 0 && !authError()) {\r\n <div class=\"iq-empty\">\r\n <div class=\"iq-empty-icon\">\r\n @switch (resolvedConfig().bubbleIconType) {\r\n @case ('image') {\r\n <img [src]=\"resolvedConfig().bubbleImageUrl\" alt=\"\" class=\"iq-empty-img\" />\r\n }\r\n @case ('svg') {\r\n <span class=\"iq-empty-svg\" [innerHTML]=\"sanitizedBubbleSvg()\"></span>\r\n }\r\n @default {\r\n <span>{{ resolvedConfig().bubbleIcon }}</span>\r\n }\r\n }\r\n </div>\r\n <p>{{ resolvedConfig().welcomeTitle }}</p>\r\n <p class=\"iq-text-muted\">{{ resolvedConfig().welcomeSubtitle }}</p>\r\n </div>\r\n }\r\n\r\n @for (msg of messages(); track msg.id) {\r\n <div class=\"iq-msg\" [class.iq-msg-user]=\"msg.sender === 'user'\" [class.iq-msg-bot]=\"msg.sender === 'bot'\">\r\n <div class=\"iq-msg-content\">\r\n @if (msg.sender === 'bot') {\r\n <div class=\"iq-md\" [innerHTML]=\"renderMarkdown(msg.text)\" (click)=\"onMessageClick($event)\"></div>\r\n } @else {\r\n <p>{{ msg.text }}</p>\r\n }\r\n <span class=\"iq-msg-time\">{{ formatTime(msg.timestamp) }}</span>\r\n </div>\r\n @if (msg.sender === 'bot' && msg.traceData && resolvedConfig().showTrace) {\r\n <button class=\"iq-btn-trace\" (click)=\"showTrace(msg)\">🔍 Ver Traza</button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Pipeline progress -->\r\n @if (isLoading()) {\r\n <div class=\"iq-msg iq-msg-bot\">\r\n <div class=\"iq-msg-content iq-pipeline\">\r\n <span class=\"iq-dot\"></span>\r\n <span class=\"iq-pipeline-text\">{{ pipelineStep }}</span>\r\n <button class=\"iq-cancel-btn\" (click)=\"cancelQuery()\" title=\"Cancelar consulta\">✕</button>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Input -->\r\n <form class=\"iq-input-bar\" (ngSubmit)=\"sendMessage()\">\r\n <input\r\n type=\"text\"\r\n [(ngModel)]=\"inputText\"\r\n name=\"message\"\r\n [placeholder]=\"resolvedConfig().placeholder!\"\r\n [disabled]=\"isLoading() || !!authError()\"\r\n autocomplete=\"off\"\r\n />\r\n <button type=\"submit\" class=\"iq-btn-send\" [disabled]=\"isLoading() || !inputText.trim() || !!authError()\">\r\n ➤\r\n </button>\r\n </form>\r\n </div>\r\n }\r\n\r\n <!-- Trace Modal Overlay -->\r\n @if (selectedTrace()) {\r\n <div class=\"iq-trace-overlay\" (click)=\"closeTrace()\">\r\n <div class=\"iq-trace-modal\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"iq-trace-header\">\r\n <h3>🔍 Detalle de Traza</h3>\r\n <button class=\"iq-header-btn\" (click)=\"closeTrace()\">✕</button>\r\n </div>\r\n <div class=\"iq-trace-body\">\r\n @if (selectedTrace()?.fromCache !== undefined) {\r\n <div class=\"iq-trace-item\">\r\n <label>Origen</label>\r\n <code [class.iq-cache-hit]=\"selectedTrace()?.fromCache\">{{ selectedTrace()?.fromCache ? '📚 Desde Caché' : '🤖 Generado por GPT' }}</code>\r\n </div>\r\n }\r\n @if (selectedTrace()?.query) {\r\n <div class=\"iq-trace-item\">\r\n <label>Query Generada</label>\r\n <pre class=\"iq-query-code\">{{ selectedTrace()?.query }}</pre>\r\n </div>\r\n }\r\n @if (selectedTrace()?.explanation) {\r\n <div class=\"iq-trace-item\">\r\n <label>Explicación</label>\r\n <code>{{ selectedTrace()?.explanation }}</code>\r\n </div>\r\n }\r\n @if (selectedTrace()?.traceId) {\r\n <div class=\"iq-trace-item\">\r\n <label>Trace ID</label>\r\n <code>{{ selectedTrace()?.traceId }}</code>\r\n </div>\r\n }\r\n @if (selectedTrace()?.data) {\r\n <div class=\"iq-trace-item\">\r\n <label>Datos Retornados</label>\r\n <pre>{{ selectedTrace()?.data | json }}</pre>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Link Modal Overlay -->\r\n @if (modalUrl()) {\r\n <div class=\"iq-link-overlay\" (click)=\"closeLinkModal()\">\r\n <div class=\"iq-link-modal\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"iq-link-header\">\r\n @if (showHomeBtn()) {\r\n <button class=\"iq-header-btn iq-back-btn\" (click)=\"iframeGoHome()\" title=\"Volver al inicio\">🏠</button>\r\n }\r\n <span class=\"iq-link-title\" [title]=\"modalUrl()!\">{{ modalUrl() }}</span>\r\n <div class=\"iq-link-actions\">\r\n <a [href]=\"modalUrl()!\" target=\"_blank\" rel=\"noopener\" class=\"iq-header-btn\" title=\"Abrir en nueva pestaña\">↗</a>\r\n <button class=\"iq-header-btn\" (click)=\"closeLinkModal()\">✕</button>\r\n </div>\r\n </div>\r\n <div class=\"iq-iframe-wrapper\">\r\n @if (isModalImage()) {\r\n <img [src]=\"modalUrl()!\" class=\"iq-modal-img\" alt=\"Imagen\" />\r\n } @else {\r\n @if (modalLoading()) {\r\n <div class=\"iq-iframe-loader\">\r\n <div class=\"iq-spinner\"></div>\r\n <span class=\"iq-loader-text\">Cargando...</span>\r\n </div>\r\n }\r\n <iframe #linkIframe [src]=\"sanitizedModalUrl()\" class=\"iq-link-iframe\"\r\n [class.iq-iframe-hidden]=\"modalLoading()\"\r\n (load)=\"onIframeLoaded()\"></iframe>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n </div><!-- /iq-theme-host -->\r\n `,\r\n styles: [`\r\n /* ========= CSS Custom Properties (overridable by host) ========= */\r\n :host {\r\n --iq-primary: #1a3a5c;\r\n --iq-primary-light: #2a5a8c;\r\n --iq-accent: #00d4aa;\r\n --iq-accent-light: #33e0be;\r\n --iq-bg: #1e1e2f;\r\n --iq-bg-card: #252538;\r\n --iq-bg-tertiary: #35354a;\r\n --iq-text: #ffffff;\r\n --iq-text-secondary: #a0a0b0;\r\n --iq-text-muted: #6c6c7c;\r\n --iq-border: #3a3a4d;\r\n --iq-radius: 12px;\r\n --iq-bubble-size: 56px;\r\n --iq-panel-width: 400px;\r\n --iq-panel-height: 520px;\r\n --iq-z: 10000;\r\n --iq-font: 'Inter', 'Roboto', -apple-system, BlinkMacSystemFont, sans-serif;\r\n font-family: var(--iq-font);\r\n }\r\n\r\n /* ========= Bubble ========= */\r\n .iq-bubble {\r\n position: fixed;\r\n bottom: 24px;\r\n right: 24px;\r\n z-index: var(--iq-z);\r\n width: var(--iq-bubble-size);\r\n height: var(--iq-bubble-size);\r\n border-radius: 50%;\r\n border: none;\r\n background: linear-gradient(135deg, var(--iq-accent), var(--iq-accent-light));\r\n color: var(--iq-bg);\r\n font-size: 1.6rem;\r\n cursor: pointer;\r\n box-shadow: 0 4px 16px rgba(0, 212, 170, 0.4);\r\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n }\r\n .iq-bubble:hover {\r\n transform: scale(1.1);\r\n box-shadow: 0 6px 24px rgba(0, 212, 170, 0.5);\r\n }\r\n .iq-bubble .iq-bubble-icon {\r\n font-size: 1.5rem;\r\n pointer-events: none;\r\n }\r\n\r\n .iq-bubble-img {\r\n width: 60%; height: 60%;\r\n object-fit: contain; border-radius: 50%;\r\n pointer-events: none;\r\n }\r\n\r\n .iq-bubble-svg {\r\n width: 60%; height: 60%;\r\n display: flex; align-items: center; justify-content: center;\r\n pointer-events: none;\r\n }\r\n .iq-bubble-svg :deep(svg) { width: 100%; height: 100%; }\r\n\r\n .iq-bubble.iq-open {\r\n background: var(--iq-bg-tertiary);\r\n color: var(--iq-text);\r\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\r\n font-size: 1.2rem;\r\n }\r\n .iq-bubble.iq-bottom-left {\r\n right: auto;\r\n left: 24px;\r\n }\r\n .iq-bubble-icon { line-height: 1; }\r\n\r\n /* ========= Panel ========= */\r\n .iq-panel {\r\n position: fixed;\r\n bottom: 92px;\r\n right: 24px;\r\n z-index: var(--iq-z);\r\n width: var(--iq-panel-width);\r\n height: var(--iq-panel-height);\r\n background: var(--iq-bg);\r\n border: 1px solid var(--iq-border);\r\n border-radius: var(--iq-radius);\r\n display: flex;\r\n flex-direction: column;\r\n overflow: hidden;\r\n box-shadow: 0 12px 40px rgba(0,0,0,0.5);\r\n animation: iq-slide-up 0.3s cubic-bezier(0.4, 0, 0.2, 1);\r\n }\r\n .iq-panel.iq-bottom-left {\r\n right: auto;\r\n left: 24px;\r\n }\r\n /* ========= Expanded / Fullscreen ========= */\r\n .iq-panel.iq-expanded {\r\n width: 100vw !important;\r\n height: 100vh !important;\r\n top: 0 !important;\r\n left: 0 !important;\r\n right: 0 !important;\r\n bottom: 0 !important;\r\n border: none;\r\n border-radius: 0;\r\n overflow: clip;\r\n z-index: calc(var(--iq-z) + 5);\r\n animation: iq-expand 0.3s cubic-bezier(0.4, 0, 0.2, 1);\r\n }\r\n .iq-btn-expand {\r\n font-size: 1.1rem !important;\r\n }\r\n @keyframes iq-expand {\r\n from { opacity: 0.8; transform: scale(0.95); }\r\n to { opacity: 1; transform: scale(1); }\r\n }\r\n @keyframes iq-slide-up {\r\n from { opacity: 0; transform: translateY(16px) scale(0.96); }\r\n to { opacity: 1; transform: translateY(0) scale(1); }\r\n }\r\n\r\n /* ========= Header ========= */\r\n .iq-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 12px 16px;\r\n border-bottom: 1px solid var(--iq-border);\r\n background: var(--iq-bg-card);\r\n }\r\n .iq-header-title {\r\n font-weight: 600;\r\n font-size: 0.95rem;\r\n color: var(--iq-text);\r\n }\r\n .iq-header-actions {\r\n display: flex;\r\n gap: 4px;\r\n }\r\n .iq-header-btn {\r\n background: none;\r\n border: none;\r\n color: var(--iq-text-muted);\r\n cursor: pointer;\r\n font-size: 1rem;\r\n padding: 4px 6px;\r\n border-radius: 4px;\r\n transition: all 0.15s;\r\n }\r\n .iq-header-btn:hover {\r\n color: var(--iq-text);\r\n background: rgba(255,255,255,0.08);\r\n }\r\n\r\n /* ========= Auth Error ========= */\r\n .iq-auth-error {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 10px 16px;\r\n background: rgba(220, 53, 69, 0.15);\r\n color: #ff6b7a;\r\n font-size: 0.8rem;\r\n border-bottom: 1px solid rgba(220, 53, 69, 0.25);\r\n }\r\n\r\n /* ========= Messages ========= */\r\n .iq-messages {\r\n flex: 1;\r\n min-height: 0;\r\n overflow-y: auto;\r\n padding: 12px;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 10px;\r\n }\r\n\r\n .iq-empty {\r\n flex: 1;\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: center;\r\n text-align: center;\r\n color: var(--iq-text-secondary);\r\n }\r\n .iq-empty-icon { font-size: 3rem; margin-bottom: 8px; display: flex; align-items: center; justify-content: center; }\r\n .iq-empty-img { width: 48px; height: 48px; object-fit: contain; border-radius: 8px; }\r\n .iq-empty-svg { width: 48px; height: 48px; display: flex; align-items: center; justify-content: center; }\r\n .iq-empty-svg :deep(svg) { width: 100%; height: 100%; }\r\n .iq-empty p { font-size: 0.95rem; margin: 2px 0; }\r\n .iq-text-muted { color: var(--iq-text-muted) !important; font-size: 0.8rem !important; }\r\n\r\n .iq-msg { display: flex; flex-direction: column; max-width: 85%; }\r\n .iq-msg-user { align-self: flex-end; }\r\n .iq-msg-bot { align-self: flex-start; max-width: 100%; }\r\n\r\n .iq-msg-user .iq-msg-content {\r\n background: linear-gradient(135deg, var(--iq-primary), var(--iq-primary-light));\r\n border-radius: 12px 12px 0 12px;\r\n }\r\n .iq-msg-bot .iq-msg-content {\r\n background: var(--iq-bg-tertiary);\r\n border-radius: 12px 12px 12px 0;\r\n }\r\n .iq-msg-content {\r\n padding: 10px 14px;\r\n color: var(--iq-text);\r\n font-size: 0.85rem;\r\n line-height: 1.45;\r\n }\r\n .iq-msg-content p { margin: 0; white-space: pre-wrap; }\r\n .iq-msg-time {\r\n display: block;\r\n margin-top: 4px;\r\n font-size: 0.65rem;\r\n color: rgba(255,255,255,0.5);\r\n }\r\n\r\n /* Markdown rendered content */\r\n .iq-md { line-height: 1.5; overflow-x: auto; max-width: 100%; }\r\n .iq-md :first-child { margin-top: 0; }\r\n .iq-md :last-child { margin-bottom: 0; }\r\n .iq-md p { margin: 0 0 0.4em 0; }\r\n .iq-md p:last-child { margin-bottom: 0; }\r\n .iq-md strong { color: var(--iq-accent); }\r\n .iq-md ul, .iq-md ol { margin: 0.3em 0; padding-left: 1.2em; }\r\n .iq-md li { margin: 0.15em 0; }\r\n .iq-md code {\r\n background: rgba(0,0,0,0.3);\r\n padding: 0.15em 0.4em;\r\n border-radius: 3px;\r\n font-size: 0.82em;\r\n }\r\n .iq-md pre {\r\n background: rgba(0,0,0,0.3);\r\n padding: 0.8em;\r\n border-radius: 6px;\r\n overflow-x: auto;\r\n font-size: 0.78em;\r\n margin: 0.4em 0;\r\n }\r\n .iq-md pre code { background: none; padding: 0; }\r\n .iq-md table {\r\n width: max-content; min-width: 100%;\r\n border-collapse: separate; border-spacing: 0;\r\n margin: 0.5em 0; font-size: 0.75rem;\r\n border-radius: 6px; overflow: hidden;\r\n }\r\n .iq-md thead th {\r\n background: rgba(99,102,241,0.18); color: #a5b4fc;\r\n font-weight: 600; text-align: left;\r\n padding: 0.5em 0.8em; border-bottom: 2px solid rgba(99,102,241,0.3);\r\n white-space: nowrap; font-size: 0.7rem;\r\n text-transform: uppercase; letter-spacing: 0.05em;\r\n }\r\n .iq-md tbody td {\r\n padding: 0.4em 0.8em; border-bottom: 1px solid rgba(255,255,255,0.06);\r\n white-space: nowrap; color: var(--iq-text-secondary);\r\n }\r\n .iq-md tbody tr:hover { background: rgba(99,102,241,0.08); }\r\n\r\n /* Inline images in bot messages – small thumbnails, click to enlarge */\r\n .iq-md img {\r\n max-height: 80px; max-width: 120px; object-fit: cover;\r\n border-radius: 8px; margin: 6px 4px 6px 0;\r\n display: inline-block; vertical-align: middle;\r\n border: 1px solid rgba(255,255,255,0.15);\r\n box-shadow: 0 1px 4px rgba(0,0,0,0.25);\r\n cursor: pointer; transition: transform 0.15s, box-shadow 0.15s;\r\n }\r\n .iq-md img:hover {\r\n transform: scale(1.05);\r\n box-shadow: 0 3px 12px rgba(99,102,241,0.35);\r\n border-color: var(--iq-accent);\r\n }\r\n .iq-md img[alt*=\"logo\"], .iq-md img[alt*=\"marca\"] {\r\n max-height: 28px; max-width: 90px; object-fit: contain;\r\n border: none; box-shadow: none; border-radius: 4px;\r\n background: rgba(255,255,255,0.9); padding: 2px 6px;\r\n }\r\n /* Trace button */\r\n .iq-btn-trace {\r\n align-self: flex-start; margin-top: 4px;\r\n background: transparent; border: 1px solid var(--iq-border);\r\n color: var(--iq-text-secondary); font-size: 0.7rem;\r\n padding: 3px 8px; border-radius: 4px; cursor: pointer;\r\n transition: all 0.15s;\r\n }\r\n .iq-btn-trace:hover { border-color: var(--iq-accent); color: var(--iq-accent); }\r\n\r\n /* Pipeline loading indicator */\r\n .iq-pipeline {\r\n display: flex; align-items: center; gap: 8px;\r\n animation: iq-fade-in 0.3s ease-out;\r\n }\r\n .iq-dot {\r\n width: 8px; height: 8px; border-radius: 50%;\r\n background: var(--iq-accent);\r\n animation: iq-pulse 1s ease-in-out infinite;\r\n }\r\n .iq-pipeline-text {\r\n font-size: 0.8rem; color: var(--iq-text-muted); font-style: italic;\r\n flex: 1;\r\n }\r\n .iq-cancel-btn {\r\n background: transparent; border: 1px solid var(--iq-border);\r\n color: var(--iq-text-muted); font-size: 0.7rem;\r\n padding: 2px 8px; border-radius: 4px; cursor: pointer;\r\n transition: all 0.15s; flex-shrink: 0;\r\n }\r\n .iq-cancel-btn:hover {\r\n border-color: #ff6b6b; color: #ff6b6b; background: rgba(255, 107, 107, 0.1);\r\n }\r\n @keyframes iq-pulse {\r\n 0%, 100% { opacity: 1; transform: scale(1); }\r\n 50% { opacity: 0.4; transform: scale(0.7); }\r\n }\r\n @keyframes iq-fade-in {\r\n from { opacity: 0; transform: translateX(-6px); }\r\n to { opacity: 1; transform: translateX(0); }\r\n }\r\n\r\n /* ========= Input Bar ========= */\r\n .iq-input-bar {\r\n display: flex; gap: 8px;\r\n padding: 10px 12px;\r\n border-top: 1px solid var(--iq-border);\r\n background: var(--iq-bg-card);\r\n }\r\n .iq-input-bar input {\r\n flex: 1; padding: 8px 12px;\r\n background: var(--iq-bg-tertiary);\r\n border: 1px solid var(--iq-border);\r\n border-radius: 8px;\r\n color: var(--iq-text);\r\n font-size: 0.85rem;\r\n font-family: var(--iq-font);\r\n outline: none;\r\n transition: border-color 0.15s;\r\n }\r\n .iq-input-bar input:focus { border-color: var(--iq-accent); }\r\n .iq-input-bar input::placeholder { color: var(--iq-text-muted); }\r\n .iq-input-bar input:disabled { opacity: 0.5; }\r\n .iq-btn-send {\r\n width: 36px; height: 36px;\r\n border-radius: 8px; border: none;\r\n background: linear-gradient(135deg, var(--iq-accent), var(--iq-accent-light));\r\n color: var(--iq-bg); font-size: 1rem;\r\n cursor: pointer; transition: all 0.2s;\r\n display: flex; align-items: center; justify-content: center;\r\n }\r\n .iq-btn-send:hover:not(:disabled) { box-shadow: 0 0 12px rgba(0,212,170,0.4); transform: translateY(-1px); }\r\n .iq-btn-send:disabled { opacity: 0.4; cursor: not-allowed; }\r\n\r\n /* ========= Trace Modal ========= */\r\n .iq-trace-overlay {\r\n position: fixed; inset: 0;\r\n z-index: calc(var(--iq-z) + 10);\r\n background: rgba(0,0,0,0.6);\r\n display: flex; align-items: center; justify-content: center;\r\n animation: iq-fade-in 0.2s ease-out;\r\n }\r\n .iq-trace-modal {\r\n width: 90%; max-width: 520px; max-height: 80vh;\r\n background: var(--iq-bg); border: 1px solid var(--iq-border);\r\n border-radius: var(--iq-radius);\r\n display: flex; flex-direction: column; overflow: hidden;\r\n box-shadow: 0 20px 50px rgba(0,0,0,0.6);\r\n }\r\n .iq-trace-header {\r\n display: flex; align-items: center; justify-content: space-between;\r\n padding: 14px 16px; border-bottom: 1px solid var(--iq-border);\r\n }\r\n .iq-trace-header h3 { margin: 0; font-size: 0.95rem; color: var(--iq-text); }\r\n .iq-trace-body {\r\n flex: 1; overflow-y: auto; padding: 16px;\r\n display: flex; flex-direction: column; gap: 12px;\r\n }\r\n .iq-trace-item label {\r\n display: block; font-size: 0.7rem; color: var(--iq-text-muted);\r\n margin-bottom: 4px; text-transform: uppercase; letter-spacing: 0.05em;\r\n }\r\n .iq-trace-item code {\r\n display: block; padding: 8px;\r\n background: var(--iq-bg-tertiary); border-radius: 4px;\r\n font-family: monospace; font-size: 0.8rem; color: var(--iq-accent);\r\n word-break: break-all;\r\n }\r\n .iq-trace-item pre {\r\n margin: 0; padding: 8px;\r\n background: var(--iq-bg-tertiary); border-radius: 4px;\r\n font-family: monospace; font-size: 0.7rem;\r\n overflow-x: auto; max-height: 180px; color: var(--iq-text-secondary);\r\n }\r\n .iq-cache-hit { background: rgba(16,185,129,0.15) !important; color: #10b981 !important; }\r\n .iq-query-code { color: var(--iq-accent) !important; }\r\n\r\n /* ========= Link Modal ========= */\r\n .iq-link-overlay {\r\n position: fixed; inset: 0;\r\n z-index: calc(var(--iq-z) + 20);\r\n background: rgba(0,0,0,0.7);\r\n display: flex; align-items: center; justify-content: center;\r\n animation: iq-fade-in 0.2s ease-out;\r\n backdrop-filter: blur(4px);\r\n }\r\n .iq-link-modal {\r\n width: 94vw; height: 92vh;\r\n background: var(--iq-bg); border: 1px solid var(--iq-border);\r\n border-radius: var(--iq-radius);\r\n display: flex; flex-direction: column; overflow: hidden;\r\n box-shadow: 0 24px 60px rgba(0,0,0,0.7);\r\n animation: iq-expand 0.25s cubic-bezier(0.4, 0, 0.2, 1);\r\n }\r\n .iq-link-header {\r\n display: flex; align-items: center; justify-content: space-between;\r\n padding: 10px 16px; border-bottom: 1px solid var(--iq-border);\r\n background: var(--iq-bg-card); gap: 12px; min-height: 44px;\r\n }\r\n .iq-link-title {\r\n flex: 1; font-size: 0.78rem; color: var(--iq-text-secondary);\r\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\r\n font-family: monospace;\r\n }\r\n .iq-link-actions {\r\n display: flex; gap: 4px; flex-shrink: 0;\r\n }\r\n .iq-link-actions a {\r\n text-decoration: none;\r\n }\r\n .iq-back-btn {\r\n flex-shrink: 0; font-size: 1.1rem;\r\n transition: transform 0.15s ease;\r\n }\r\n .iq-back-btn:hover {\r\n transform: translateX(-2px);\r\n }\r\n .iq-iframe-wrapper {\r\n flex: 1; position: relative; overflow: hidden;\r\n }\r\n .iq-link-iframe {\r\n width: 100%; height: 100%; border: none;\r\n background: #fff;\r\n transition: opacity 0.3s ease;\r\n }\r\n .iq-iframe-hidden {\r\n opacity: 0;\r\n }\r\n .iq-modal-img {\r\n width: 100%; height: 100%;\r\n object-fit: contain;\r\n background: #1a1a2e;\r\n }\r\n .iq-iframe-loader {\r\n position: absolute; inset: 0;\r\n display: flex; flex-direction: column;\r\n align-items: center; justify-content: center;\r\n background: var(--iq-bg);\r\n gap: 16px; z-index: 2;\r\n }\r\n .iq-spinner {\r\n width: 40px; height: 40px;\r\n border: 3px solid var(--iq-border);\r\n border-top-color: var(--iq-accent);\r\n border-radius: 50%;\r\n animation: iq-spin 0.8s linear infinite;\r\n }\r\n .iq-loader-text {\r\n font-size: 0.85rem; color: var(--iq-text-secondary);\r\n font-weight: 500;\r\n }\r\n @keyframes iq-spin {\r\n to { transform: rotate(360deg); }\r\n }\r\n\r\n /* ========= Link Modal — markdown link styling ========= */\r\n .iq-md a {\r\n color: var(--iq-accent); text-decoration: underline;\r\n cursor: pointer; transition: color 0.15s;\r\n }\r\n .iq-md a:hover {\r\n color: var(--iq-accent-light);\r\n }\r\n\r\n @media (max-width: 480px) {\r\n .iq-link-modal {\r\n width: 100vw; height: 100dvh;\r\n border-radius: 0;\r\n }\r\n .iq-link-header { padding: 8px 12px; }\r\n .iq-link-title { font-size: 0.7rem; }\r\n }\r\n\r\n /* ========= Scrollbar ========= */\r\n .iq-messages::-webkit-scrollbar { width: 5px; }\r\n .iq-messages::-webkit-scrollbar-track { background: transparent; }\r\n .iq-messages::-webkit-scrollbar-thumb { background: var(--iq-border); border-radius: 4px; }\r\n .iq-trace-body::-webkit-scrollbar { width: 5px; }\r\n .iq-trace-body::-webkit-scrollbar-track { background: transparent; }\r\n .iq-trace-body::-webkit-scrollbar-thumb { background: var(--iq-border); border-radius: 4px; }\r\n /* Wider scrollbar in fullscreen for easier grabbing */\r\n .iq-expanded .iq-messages::-webkit-scrollbar { width: 8px; }\r\n .iq-expanded .iq-messages { scrollbar-gutter: stable; }\r\n\r\n /* ========= Mobile Small Screens ========= */\r\n @media (max-width: 480px) {\r\n .iq-bubble {\r\n bottom: 16px;\r\n right: 16px;\r\n width: 48px;\r\n height: 48px;\r\n font-size: 1.3rem;\r\n }\r\n .iq-bubble.iq-bottom-left {\r\n left: 16px;\r\n }\r\n .iq-bubble .iq-bubble-icon { font-size: 1.2rem; }\r\n\r\n .iq-panel {\r\n right: 8px;\r\n left: 8px;\r\n bottom: 72px;\r\n width: auto !important;\r\n max-width: calc(100vw - 16px);\r\n height: calc(100dvh - 90px);\r\n max-height: calc(100dvh - 90px);\r\n }\r\n .iq-panel.iq-bottom-left {\r\n left: 8px;\r\n right: 8px;\r\n }\r\n .iq-panel.iq-expanded {\r\n top: 0 !important;\r\n left: 0 !important;\r\n right: 0 !important;\r\n bottom: 0 !important;\r\n width: 100vw !important;\r\n height: 100dvh !important;\r\n max-height: 100dvh !important;\r\n max-width: 100vw !important;\r\n border-radius: 0;\r\n }\r\n\r\n .iq-header {\r\n padding: 10px 12px;\r\n }\r\n .iq-header-title { font-size: 0.85rem; }\r\n .iq-header-btn { padding: 6px 8px; min-width: 32px; min-height: 32px; }\r\n\r\n .iq-messages { padding: 8px; gap: 8px; }\r\n\r\n .iq-msg { max-width: 92%; }\r\n .iq-msg-bot { max-width: 100%; }\r\n .iq-msg-content { padding: 8px 10px; font-size: 0.8rem; }\r\n\r\n .iq-md { overflow-x: auto; -webkit-overflow-scrolling: touch; }\r\n .iq-md table { font-size: 0.65rem; min-width: unset; }\r\n .iq-md thead th { padding: 0.35em 0.5em; font-size: 0.6rem; }\r\n .iq-md tbody td { padding: 0.3em 0.5em; font-size: 0.65rem; }\r\n\r\n .iq-empty-icon { font-size: 2.5rem; }\r\n .iq-empty p { font-size: 0.85rem; }\r\n\r\n .iq-input-bar { padding: 8px 10px; gap: 6px; }\r\n .iq-input-bar input { font-size: 16px; padding: 8px 10px; }\r\n .iq-btn-send { width: 38px; height: 38px; flex-shrink: 0; }\r\n\r\n .iq-trace-modal {\r\n width: calc(100vw - 24px);\r\n max-height: 90dvh;\r\n }\r\n .iq-trace-header { padding: 12px; }\r\n .iq-trace-header h3 { font-size: 0.85rem; }\r\n .iq-trace-body { padding: 12px; }\r\n .iq-trace-item pre { font-size: 0.65rem; max-height: 140px; }\r\n }\r\n\r\n /* ========= Landscape Mobile — fit floating panel ========= */\r\n @media (max-height: 500px) and (orientation: landscape) {\r\n .iq-bubble {\r\n bottom: 8px;\r\n right: 8px;\r\n width: 44px;\r\n height: 44px;\r\n font-size: 1.1rem;\r\n }\r\n .iq-bubble.iq-bottom-left { left: 8px; }\r\n\r\n .iq-panel {\r\n right: 60px;\r\n left: 8px;\r\n bottom: 8px;\r\n top: 8px;\r\n width: auto !important;\r\n max-width: calc(100vw - 76px);\r\n height: auto !important;\r\n max-height: calc(100dvh - 16px);\r\n border-radius: var(--iq-radius);\r\n }\r\n .iq-panel.iq-bottom-left {\r\n left: 60px;\r\n right: 8px;\r\n }\r\n .iq-panel.iq-expanded {\r\n top: 0 !important;\r\n left: 0 !important;\r\n right: 0 !important;\r\n bottom: 0 !important;\r\n width: 100vw !important;\r\n height: 100dvh !important;\r\n max-height: 100dvh !important;\r\n max-width: 100vw !important;\r\n border-radius: 0;\r\n }\r\n\r\n .iq-header { padding: 6px 12px; }\r\n .iq-header-title { font-size: 0.8rem; }\r\n .iq-messages { padding: 6px 10px; gap: 6px; }\r\n .iq-empty-icon { font-size: 1.8rem; margin-bottom: 4px; }\r\n .iq-empty p { font-size: 0.78rem; margin: 1px 0; }\r\n .iq-input-bar { padding: 6px 10px; }\r\n .iq-input-bar input { font-size: 16px; padding: 6px 10px; }\r\n .iq-btn-send { width: 32px; height: 32px; }\r\n }\r\n `]\r\n})\r\nexport class IntelligentChatPluginComponent implements AfterViewChecked, OnChanges, OnInit, OnDestroy {\r\n @ViewChild('chatContainer') private chatContainer!: ElementRef;\r\n\r\n @Input() config!: IntelligentChatConfig;\r\n\r\n private chatService = inject(IntelligentChatService);\r\n private hostEl = inject(ElementRef);\r\n\r\n // State\r\n isOpen = signal(false);\r\n isExpanded = signal(false);\r\n messages = signal<ChatMessage[]>([]);\r\n isLoading = signal(false);\r\n selectedTrace = signal<any>(null);\r\n authError = signal<string | null>(null);\r\n modalUrl = signal<string | null>(null);\r\n isModalImage = computed(() => {\r\n const url = this.modalUrl();\r\n if (!url) return false;\r\n return /\\.(jpg|jpeg|png|gif|webp|svg|bmp)(\\?.*)?$/i.test(url);\r\n });\r\n modalLoading = signal(false);\r\n showHomeBtn = signal(false);\r\n private originalModalUrl = '';\r\n private modalReadyForNav = false;\r\n private navReadyTimer: any = null;\r\n inputText = '';\r\n private currentSubscription?: Subscription;\r\n\r\n // Pipeline step (driven by real SSE events from backend)\r\n pipelineStep = '';\r\n\r\n private messageId = 0;\r\n private shouldScroll = false;\r\n\r\n // ─── Markdown Cache (avoids re-parsing on every CD cycle) ────\r\n private mdCache = new Map<string, SafeHtml>();\r\n // ─── Debounce progress updates to avoid CD storms ────\r\n private pendingPipelineStep: string | null = null;\r\n private rafId: number | null = null;\r\n\r\n // ─── Session Persistence ──────────────────────────\r\n private readonly STORAGE_PREFIX = 'iq_chat_session_';\r\n private sessionKey = '';\r\n private storageListener = (e: StorageEvent) => this.onStorageChange(e);\r\n\r\n /** Resolved config with defaults applied */\r\n private sanitizer = inject(DomSanitizer);\r\n\r\n resolvedConfig = signal<Required<IntelligentChatConfig>>({\r\n apiUrl: '',\r\n systemId: '',\r\n token: '',\r\n useIntelligentQuery: true,\r\n skipPatterns: true,\r\n baseContext: '',\r\n showTrace: false,\r\n showPipelineSteps: true,\r\n preferTableFormat: true,\r\n title: 'Maquito Chat',\r\n placeholder: 'Escribe tu consulta aquí...',\r\n welcomeTitle: '¡Hola! Soy Maquito.',\r\n welcomeSubtitle: 'Escribe tu consulta para comenzar.',\r\n position: 'bottom-right',\r\n bubbleIcon: '🤖',\r\n bubbleIconType: 'emoji',\r\n bubbleImageUrl: '',\r\n bubbleSvg: '',\r\n themeClass: '',\r\n stickyBubble: true,\r\n allowExpand: false,\r\n theme: {},\r\n userName: '',\r\n personality: ''\r\n });\r\n\r\n /** Map theme object → CSS variable overrides */\r\n themeStyles = computed(() => {\r\n const t = this.resolvedConfig().theme || {};\r\n const map: Record<string, string> = {};\r\n const pairs: [keyof PluginTheme, string][] = [\r\n ['primary', '--iq-primary'], ['primaryLight', '--iq-primary-light'],\r\n ['accent', '--iq-accent'], ['accentLight', '--iq-accent-light'],\r\n ['bg', '--iq-bg'], ['bgCard', '--iq-bg-card'], ['bgTertiary', '--iq-bg-tertiary'],\r\n ['text', '--iq-text'], ['textSecondary', '--iq-text-secondary'],\r\n ['textMuted', '--iq-text-muted'], ['border', '--iq-border']\r\n ];\r\n for (const [key, cssVar] of pairs) {\r\n if (t[key]) map[cssVar] = t[key]!;\r\n }\r\n return map;\r\n });\r\n\r\n /** Sanitised SVG HTML for bubble */\r\n sanitizedBubbleSvg = computed<SafeHtml>(() => {\r\n const raw = this.resolvedConfig().bubbleSvg || '';\r\n return this.sanitizer.bypassSecurityTrustHtml(raw);\r\n });\r\n\r\n /** Sanitised URL for the link modal iframe */\r\n sanitizedModalUrl = computed<SafeResourceUrl>(() => {\r\n const url = this.modalUrl() || '';\r\n return this.sanitizer.bypassSecurityTrustResourceUrl(url);\r\n });\r\n\r\n ngOnInit(): void {\r\n window.addEventListener('storage', this.storageListener);\r\n // Self-heal: always reset transient state on init to prevent\r\n // corrupted sessions from freezing the page\r\n this.isLoading.set(false);\r\n this.pipelineStep = '';\r\n this.isExpanded.set(false);\r\n this.setHostScrollLock(false);\r\n this.currentSubscription?.unsubscribe();\r\n this.currentSubscription = undefined;\r\n }\r\n\r\n ngOnDestroy(): void {\r\n window.removeEventListener('storage', this.storageListener);\r\n this.cancelQuery();\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if (changes['config'] && this.config) {\r\n this.resolvedConfig.set({\r\n apiUrl: this.config.apiUrl || '',\r\n systemId: this.config.systemId || '',\r\n token: this.config.token || '',\r\n useIntelligentQuery: this.config.useIntelligentQuery ?? true,\r\n skipPatterns: this.config.skipPatterns ?? true,\r\n baseContext: this.config.baseContext || '',\r\n showTrace: this.config.showTrace ?? false,\r\n showPipelineSteps: this.config.showPipelineSteps ?? true,\r\n preferTableFormat: this.config.preferTableFormat ?? true,\r\n title: this.config.title || 'Maquito Chat',\r\n placeholder: this.config.placeholder || 'Escribe tu consulta aquí...',\r\n welcomeTitle: this.config.welcomeTitle || '¡Hola! Soy Maquito.',\r\n welcomeSubtitle: this.config.welcomeSubtitle || 'Escribe tu consulta para comenzar.',\r\n position: this.config.position || 'bottom-right',\r\n bubbleIcon: this.config.bubbleIcon || '🤖',\r\n bubbleIconType: this.config.bubbleIconType || 'emoji',\r\n bubbleImageUrl: this.config.bubbleImageUrl || '',\r\n bubbleSvg: this.config.bubbleSvg || '',\r\n themeClass: this.config.themeClass || '',\r\n stickyBubble: this.config.stickyBubble ?? true,\r\n allowExpand: this.config.allowExpand ?? false,\r\n theme: this.config.theme || {},\r\n userName: this.config.userName || '',\r\n personality: this.config.personality || ''\r\n });\r\n // Cancel any in-flight query when config changes\r\n this.cancelQuery();\r\n // Rebuild session key when config changes\r\n const newKey = this.buildSessionKey();\r\n if (newKey !== this.sessionKey) {\r\n this.sessionKey = newKey;\r\n this.loadSession();\r\n }\r\n // Clear auth error when config changes (user may be testing a new token)\r\n this.authError.set(null);\r\n }\r\n }\r\n\r\n ngAfterViewChecked(): void {\r\n if (this.shouldScroll) {\r\n this.scrollToBottom();\r\n this.shouldScroll = false;\r\n }\r\n }\r\n\r\n toggleChat(): void {\r\n this.isOpen.update(v => !v);\r\n if (!this.isOpen()) {\r\n this.isExpanded.set(false);\r\n this.setHostScrollLock(false);\r\n this.cancelQuery();\r\n }\r\n if (this.isOpen()) this.shouldScroll = true;\r\n }\r\n\r\n toggleExpand(): void {\r\n this.isExpanded.update(v => !v);\r\n this.setHostScrollLock(this.isExpanded());\r\n }\r\n\r\n /** Lock/unlock the host page scroll to prevent its scrollbar from overlapping ours */\r\n private setHostScrollLock(lock: boolean): void {\r\n document.body.style.overflow = lock ? 'hidden' : '';\r\n // Also target common host containers\r\n const mc = document.querySelector('.main-container') as HTMLElement;\r\n if (mc) mc.style.overflow = lock ? 'hidden' : '';\r\n }\r\n\r\n sendMessage(): void {\r\n const text = this.inputText.trim();\r\n if (!text) return;\r\n\r\n const cfg = this.resolvedConfig();\r\n\r\n // Validate required config\r\n if (!cfg.token) {\r\n this.authError.set('Token no configurado. El plugin requiere un token técnico válido.');\r\n return;\r\n }\r\n if (!cfg.apiUrl) {\r\n this.authError.set('API URL no configurada.');\r\n return;\r\n }\r\n\r\n this.authError.set(null);\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text,\r\n sender: 'user',\r\n timestamp: new Date()\r\n }]);\r\n this.saveSession();\r\n this.shouldScroll = true;\r\n this.inputText = '';\r\n this.isLoading.set(true);\r\n\r\n if (cfg.showPipelineSteps) {\r\n this.pipelineStep = '⏳ Procesando...';\r\n } else {\r\n this.pipelineStep = '⏳ Procesando...';\r\n }\r\n\r\n if (cfg.useIntelligentQuery && cfg.systemId) {\r\n // Build conversation history from previous messages (last 6 pairs)\r\n const history = this.messages()\r\n .filter(m => m.sender === 'user' || m.sender === 'bot')\r\n .slice(-12)\r\n .map(msg => ({\r\n role: msg.sender === 'user' ? 'user' : 'assistant',\r\n content: msg.text\r\n }));\r\n\r\n const ctx = cfg.baseContext?.trim() || undefined;\r\n\r\n if (cfg.showPipelineSteps) {\r\n // Use SSE streaming for real-time pipeline progress\r\n this.currentSubscription = this.chatService.executeIntelligentQueryStream(\r\n cfg.apiUrl, cfg.token, cfg.systemId, text, history, ctx, cfg.skipPatterns, cfg.preferTableFormat,\r\n cfg.userName || undefined, cfg.personality || undefined\r\n ).subscribe({\r\n next: (event) => {\r\n if (event.type === 'progress') {\r\n // Debounce progress updates — queue for next animation frame\r\n // to avoid triggering Angular CD on every SSE chunk\r\n this.pendingPipelineStep = event.message || '';\r\n if (this.rafId === null) {\r\n this.rafId = requestAnimationFrame(() => {\r\n this.rafId = null;\r\n if (this.pendingPipelineStep !== null) {\r\n this.pipelineStep = this.pendingPipelineStep;\r\n this.pendingPipelineStep = null;\r\n }\r\n });\r\n }\r\n return;\r\n } else if (event.type === 'result') {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n const response = event.data;\r\n const responseText = response.success\r\n ? (response.response || 'Consulta ejecutada correctamente')\r\n : (response.error || 'Error en la consulta');\r\n\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text: responseText,\r\n sender: 'bot',\r\n timestamp: new Date(),\r\n traceData: {\r\n traceId: response.traceId,\r\n fromCache: response.fromCache,\r\n fromContext: response.fromContext,\r\n query: response.query,\r\n explanation: response.explanation,\r\n patternId: response.patternId,\r\n data: response.data\r\n }\r\n }]);\r\n this.saveSession();\r\n this.shouldScroll = true;\r\n }\r\n },\r\n error: (error) => {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n this.setHostScrollLock(false);\r\n this.handleError(error);\r\n }\r\n });\r\n } else {\r\n // Fallback: use standard non-streaming endpoint\r\n this.currentSubscription = this.chatService.executeIntelligentQuery(\r\n cfg.apiUrl, cfg.token, cfg.systemId, text, history, ctx, cfg.skipPatterns, cfg.preferTableFormat,\r\n cfg.userName || undefined, cfg.personality || undefined\r\n ).subscribe({\r\n next: (response: any) => {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n const responseText = response.success\r\n ? (response.response || 'Consulta ejecutada correctamente')\r\n : (response.error || 'Error en la consulta');\r\n\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text: responseText,\r\n sender: 'bot',\r\n timestamp: new Date(),\r\n traceData: {\r\n traceId: response.traceId,\r\n fromCache: response.fromCache,\r\n fromContext: response.fromContext,\r\n query: response.query,\r\n explanation: response.explanation,\r\n patternId: response.patternId,\r\n data: response.data\r\n }\r\n }]);\r\n this.saveSession();\r\n this.shouldScroll = true;\r\n },\r\n error: (error) => {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n this.setHostScrollLock(false);\r\n this.handleError(error);\r\n }\r\n });\r\n }\r\n } else {\r\n // Standard orchestration (non-intelligent)\r\n this.currentSubscription = this.chatService.ask(cfg.apiUrl, cfg.token, text).subscribe({\r\n next: (response) => {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text: response.data?.response || 'Sin respuesta',\r\n sender: 'bot',\r\n timestamp: new Date(),\r\n traceData: {\r\n traceId: response.traceId,\r\n responseTime: response.data?.processingTime,\r\n appliedRules: response.data?.appliedRules,\r\n decisions: response.data?.decisions\r\n }\r\n }]);\r\n this.saveSession();\r\n this.shouldScroll = true;\r\n },\r\n error: (error) => {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n this.setHostScrollLock(false);\r\n this.handleError(error);\r\n }\r\n });\r\n }\r\n }\r\n\r\n cancelQuery(): void {\r\n this.currentSubscription?.unsubscribe();\r\n this.currentSubscription = undefined;\r\n this.isLoading.set(false);\r\n this.pipelineStep = '';\r\n this.setHostScrollLock(false);\r\n }\r\n\r\n clearChat(): void {\r\n this.messages.set([]);\r\n this.selectedTrace.set(null);\r\n this.authError.set(null);\r\n this.clearSession();\r\n }\r\n\r\n showTrace(msg: ChatMessage): void {\r\n this.selectedTrace.set(msg.traceData);\r\n }\r\n\r\n closeTrace(): void {\r\n this.selectedTrace.set(null);\r\n }\r\n\r\n // ─── Link Modal ────────────────────────────────\r\n openLinkModal(url: string): void {\r\n this.modalLoading.set(true);\r\n this.showHomeBtn.set(false);\r\n this.modalReadyForNav = false;\r\n clearTimeout(this.navReadyTimer);\r\n this.originalModalUrl = url;\r\n this.modalUrl.set(url);\r\n }\r\n\r\n closeLinkModal(): void {\r\n this.modalUrl.set(null);\r\n this.modalLoading.set(false);\r\n this.showHomeBtn.set(false);\r\n this.modalReadyForNav = false;\r\n clearTimeout(this.navReadyTimer);\r\n this.originalModalUrl = '';\r\n }\r\n\r\n onIframeLoaded(): void {\r\n this.modalLoading.set(false);\r\n if (this.modalReadyForNav) {\r\n // A load AFTER the initial page settled = real navigation\r\n this.showHomeBtn.set(true);\r\n } else {\r\n // Initial page load (may fire multiple times for SPAs/redirects)\r\n // Wait 1s of stability before treating next loads as navigation\r\n clearTimeout(this.navReadyTimer);\r\n this.navReadyTimer = setTimeout(() => { this.modalReadyForNav = true; }, 1000);\r\n }\r\n }\r\n\r\n iframeGoHome(): void {\r\n const iframe = this.hostEl.nativeElement.querySelector('.iq-link-iframe') as HTMLIFrameElement;\r\n if (iframe && this.originalModalUrl) {\r\n this.modalLoading.set(true);\r\n this.showHomeBtn.set(false);\r\n this.modalReadyForNav = false;\r\n clearTimeout(this.navReadyTimer);\r\n iframe.src = this.originalModalUrl;\r\n }\r\n }\r\n\r\n /** Intercept clicks on <a> and <img> tags inside rendered markdown */\r\n onMessageClick(event: MouseEvent): void {\r\n const target = event.target as HTMLElement;\r\n\r\n // Clicking an image opens it full-size in the modal\r\n if (target.tagName === 'IMG') {\r\n const src = (target as HTMLImageElement).src;\r\n if (src) {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n this.openLinkModal(src);\r\n return;\r\n }\r\n }\r\n\r\n const anchor = target.closest('a') as HTMLAnchorElement | null;\r\n if (anchor && anchor.href) {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n this.openLinkModal(anchor.href);\r\n }\r\n }\r\n\r\n formatTime(date: Date): string {\r\n return date.toLocaleTimeString('es-CL', { hour: '2-digit', minute: '2-digit' });\r\n }\r\n\r\n renderMarkdown(text: string): SafeHtml {\r\n if (!text) return '';\r\n\r\n // Return cached result if available (avoids re-parsing on every CD cycle)\r\n const cached = this.mdCache.get(text);\r\n if (cached) return cached;\r\n\r\n try {\r\n // Safety valve: if text is extremely long, skip regex-heavy preprocessing\r\n // to avoid catastrophic backtracking that freezes the browser\r\n let preprocessed = text.length < 100_000 ? this.preprocessMarkdownTable(text) : text;\r\n\r\n // Encode spaces in markdown image & link URLs: ![alt](url) and [text](url)\r\n if (preprocessed.length < 100_000) {\r\n preprocessed = preprocessed.replace(/(!?\\[[^\\]]*\\])\\(([^)]+)\\)/g,\r\n (_match, bracket, url) => `${bracket}(${url.replace(/ /g, '%20')})`);\r\n }\r\n\r\n let html = marked.parse(preprocessed, { breaks: true }) as string;\r\n // Inject inline styles + onerror on <img> to force small thumbnails & hide broken ones\r\n const imgStyle = `style=\"max-height:48px;max-width:100px;object-fit:contain;border-radius:6px;cursor:pointer;display:inline-block;vertical-align:middle;margin:2px 4px;border:1px solid rgba(255,255,255,0.15);box-shadow:0 1px 3px rgba(0,0,0,0.2);\"`;\r\n html = html.replace(/<img /g, `<img ${imgStyle} onerror=\"this.style.display='none'\" `);\r\n const result = this.sanitizer.bypassSecurityTrustHtml(html);\r\n this.mdCache.set(text, result);\r\n return result;\r\n } catch {\r\n return text;\r\n }\r\n }\r\n\r\n /**\r\n * Pre-process text to ensure pipe-delimited tables render as HTML tables.\r\n *\r\n * The API often returns header + separator + data on ONE line, e.g.:\r\n * \"| Col1 | Col2 | |---|---| | Val1 | Val2 |\"\r\n *\r\n * Step 1: Find the dash-separator pattern (|---|---|) and break the line\r\n * around it so each part (header / separator / data rows) is its\r\n * own line.\r\n * Step 2: Line-by-line cleanup — ensure a blank line exists before the\r\n * first pipe-row and inject a separator if one is still missing.\r\n */\r\n private preprocessMarkdownTable(text: string): string {\r\n // ── Step 1: Break inline separator onto its own line ───────────\r\n // Pattern: the separator row consists only of |, -, :, and spaces.\r\n // We insert \\n before and after it.\r\n text = text.replace(\r\n /\\s*(\\|(?:\\s*:?-{2,}:?\\s*\\|){2,})\\s*/g,\r\n '\\n$1\\n'\r\n );\r\n // Clean up excess blank lines created by step 1\r\n text = text.replace(/\\n{3,}/g, '\\n\\n');\r\n\r\n // ── Step 2: Line-by-line processing ───────────────────────────\r\n const lines = text.split('\\n');\r\n const result: string[] = [];\r\n let inTable = false;\r\n\r\n const isPipeLine = (l: string) => {\r\n const t = l.trim();\r\n return t.startsWith('|') && t.split('|').length > 3;\r\n };\r\n const isSepLine = (l: string) =>\r\n /^\\|(?:\\s*:?-{2,}:?\\s*\\|){2,}\\s*$/.test(l.trim());\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n const line = lines[i];\r\n const trimmed = line.trim();\r\n\r\n if (isPipeLine(trimmed) && !isSepLine(trimmed)) {\r\n if (!inTable) {\r\n inTable = true;\r\n // Insert blank line before table if preceded by non-empty text\r\n if (result.length > 0 && result[result.length - 1].trim() !== '') {\r\n result.push('');\r\n }\r\n result.push(line);\r\n // Inject separator if the next line isn't one\r\n const next = (i + 1 < lines.length) ? lines[i + 1] : '';\r\n if (!isSepLine(next)) {\r\n const cols = trimmed.split('|').filter(c => c.trim() !== '').length;\r\n result.push('| ' + Array(cols).fill('---').join(' | ') + ' |');\r\n }\r\n } else {\r\n result.push(line); // data row\r\n }\r\n } else if (isSepLine(trimmed)) {\r\n if (!inTable) inTable = true; // edge-case: separator before header\r\n result.push(line);\r\n } else {\r\n inTable = false;\r\n result.push(line);\r\n }\r\n }\r\n\r\n return result.join('\\n');\r\n }\r\n\r\n // ─── Private ───────────────────────────────────────────\r\n\r\n private handleError(error: any): void {\r\n const status = error?.status;\r\n if (status === 401 || status === 403) {\r\n const msg = status === 401 ? 'Token inválido o expirado' : 'Sin permisos para este sistema';\r\n this.authError.set(`🔒 ${msg}`);\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text: `⚠️ ${msg}. Verifica el token y el systemId configurados.`,\r\n sender: 'bot',\r\n timestamp: new Date()\r\n }]);\r\n } else {\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text: `Error: ${error.error?.message || error.error?.error || 'No se pudo procesar la consulta'}`,\r\n sender: 'bot',\r\n timestamp: new Date()\r\n }]);\r\n }\r\n this.saveSession();\r\n this.shouldScroll = true;\r\n }\r\n\r\n private stopPipelineSteps(): void {\r\n this.pipelineStep = '';\r\n }\r\n\r\n private scrollToBottom(): void {\r\n if (this.chatContainer) {\r\n const el = this.chatContainer.nativeElement;\r\n el.scrollTop = el.scrollHeight;\r\n }\r\n }\r\n\r\n // ─── Session Persistence ──────────────────────────\r\n\r\n private buildSessionKey(): string {\r\n const cfg = this.resolvedConfig();\r\n if (!cfg.token || !cfg.systemId) return '';\r\n // Simple hash-like key from systemId + first 8 chars of token\r\n const tokenPrefix = cfg.token.substring(0, 8);\r\n return `${this.STORAGE_PREFIX}${cfg.systemId}_${tokenPrefix}`;\r\n }\r\n\r\n private saveSession(): void {\r\n if (!this.sessionKey) return;\r\n try {\r\n const data = this.messages().map(m => ({\r\n id: m.id,\r\n text: m.text,\r\n sender: m.sender,\r\n timestamp: m.timestamp,\r\n traceData: m.traceData\r\n }));\r\n localStorage.setItem(this.sessionKey, JSON.stringify(data));\r\n } catch { /* ignore quota errors */ }\r\n }\r\n\r\n private loadSession(): void {\r\n if (!this.sessionKey) return;\r\n try {\r\n const raw = localStorage.getItem(this.sessionKey);\r\n if (!raw) { this.messages.set([]); return; }\r\n const data: any[] = JSON.parse(raw);\r\n // Validate data is an array of valid message objects\r\n if (!Array.isArray(data) || data.length === 0) {\r\n this.messages.set([]);\r\n return;\r\n }\r\n const msgs: ChatMessage[] = data\r\n .filter(m => m && typeof m.text === 'string' && typeof m.sender === 'string')\r\n .map(m => ({\r\n ...m,\r\n timestamp: new Date(m.timestamp)\r\n }));\r\n this.messages.set(msgs);\r\n this.messageId = msgs.length > 0 ? Math.max(...msgs.map(m => m.id)) + 1 : 0;\r\n this.shouldScroll = true;\r\n } catch {\r\n // Corrupted session data — wipe it and start fresh\r\n try { localStorage.removeItem(this.sessionKey); } catch { /* ignore */ }\r\n this.messages.set([]);\r\n }\r\n }\r\n\r\n private clearSession(): void {\r\n if (this.sessionKey) {\r\n try { localStorage.removeItem(this.sessionKey); } catch {}\r\n }\r\n }\r\n\r\n /** Called when another tab modifies localStorage */\r\n private onStorageChange(e: StorageEvent): void {\r\n if (!this.sessionKey || e.key !== this.sessionKey) return;\r\n if (e.newValue === null) {\r\n // Session was cleared in another tab\r\n this.messages.set([]);\r\n } else {\r\n this.loadSession();\r\n }\r\n this.shouldScroll = true;\r\n }\r\n}\r\n","/*\r\n * Public API Surface of maquito-chat-plugin\r\n */\r\n\r\nexport type { IntelligentChatConfig, ChatMessage, PluginTheme } from './lib/intelligent-chat.models';\r\nexport { IntelligentChatService } from './lib/intelligent-chat.service';\r\nexport { IntelligentChatPluginComponent } from './lib/intelligent-chat-plugin.component';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;;;;;;;;AAIA;;;;;;;AAOG;MAEU,sBAAsB,CAAA;AAEzB,IAAA,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC;AACzB,IAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AAE/B;;;AAGG;IACH,uBAAuB,CACrB,MAAc,EACd,KAAa,EACb,QAAgB,EAChB,QAAgB,EAChB,mBAAA,GAA2D,EAAE,EAC7D,WAAoB,EACpB,gBAA0B,EAC1B,iBAA2B,EAC3B,QAAiB,EACjB,WAAoB,EAAA;QAEpB,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;QACxC,MAAM,IAAI,GAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,mBAAmB,EAAE;AAC7D,QAAA,IAAI,WAAW;AAAE,YAAA,IAAI,CAAC,WAAW,GAAG,WAAW;AAC/C,QAAA,IAAI,gBAAgB;AAAE,YAAA,IAAI,CAAC,gBAAgB,GAAG,gBAAgB;QAC9D,IAAI,iBAAiB,KAAK,SAAS;AAAE,YAAA,IAAI,CAAC,iBAAiB,GAAG,iBAAiB;AAC/E,QAAA,IAAI,QAAQ;AAAE,YAAA,IAAI,CAAC,QAAQ,GAAG,QAAQ;AACtC,QAAA,IAAI,WAAW;AAAE,YAAA,IAAI,CAAC,WAAW,GAAG,WAAW;AAC/C,QAAA,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAM,CAAA,EAAG,MAAM,CAAA,MAAA,CAAQ,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,CAAC;IAClE;AAEA;;;;;;;;AAQG;IACH,6BAA6B,CAC3B,MAAc,EACd,KAAa,EACb,QAAgB,EAChB,QAAgB,EAChB,mBAAA,GAA2D,EAAE,EAC7D,WAAoB,EACpB,gBAA0B,EAC1B,iBAA2B,EAC3B,QAAiB,EACjB,WAAoB,EAAA;QAEpB,MAAM,IAAI,GAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,mBAAmB,EAAE;AAC7D,QAAA,IAAI,WAAW;AAAE,YAAA,IAAI,CAAC,WAAW,GAAG,WAAW;AAC/C,QAAA,IAAI,gBAAgB;AAAE,YAAA,IAAI,CAAC,gBAAgB,GAAG,gBAAgB;QAC9D,IAAI,iBAAiB,KAAK,SAAS;AAAE,YAAA,IAAI,CAAC,iBAAiB,GAAG,iBAAiB;AAC/E,QAAA,IAAI,QAAQ;AAAE,YAAA,IAAI,CAAC,QAAQ,GAAG,QAAQ;AACtC,QAAA,IAAI,WAAW;AAAE,YAAA,IAAI,CAAC,WAAW,GAAG,WAAW;AAE/C,QAAA,MAAM,gBAAgB,GAAG,OAAO,CAAC;AACjC,QAAA,MAAM,qBAAqB,GAAG,MAAM,CAAC;AACrC,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM;AAExB,QAAA,OAAO,IAAI,UAAU,CAAC,QAAQ,IAAG;AAC/B,YAAA,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE;;;AAI7C,YAAA,IAAI,CAAC,iBAAiB,CAAC,MAAK;;AAE1B,gBAAA,IAAI,MAAmB;AACvB,gBAAA,IAAI,OAAO,WAAW,CAAC,GAAG,KAAK,UAAU,EAAE;AACzC,oBAAA,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,eAAe,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC,CAAC;gBAC3F;qBAAO;AACL,oBAAA,MAAM,GAAG,eAAe,CAAC,MAAM;oBAC/B,UAAU,CAAC,MAAM,eAAe,CAAC,KAAK,EAAE,EAAE,gBAAgB,CAAC;gBAC7D;AAEA,gBAAA,KAAK,CAAC,CAAA,EAAG,MAAM,CAAA,aAAA,CAAe,EAAE;AAC9B,oBAAA,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,WAAW,EAAE,KAAK,EAAE;AACnE,oBAAA,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;oBAC1B;AACD,iBAAA,CAAC,CAAC,IAAI,CAAC,OAAM,QAAQ,KAAG;oBACvB,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE;wBAClC,IAAI,CAAC,GAAG,CAAC,MAAM,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,QAAQ,QAAQ,CAAC,MAAM,CAAA,CAAE,CAAC,CAAC,CAAC;wBACpE;oBACF;oBACA,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE;AACxC,oBAAA,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE;oBACjC,IAAI,MAAM,GAAG,EAAE;AACf,oBAAA,IAAI,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE;oBAE7B,OAAO,IAAI,EAAE;;AAEX,wBAAA,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,EAAE;wBACjC,MAAM,cAAc,GAAG,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,KAAI;4BACtD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,YAAY;AACzC,4BAAA,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,qBAAqB,GAAG,OAAO,EAAE,GAAG,CAAC;AAChE,4BAAA,UAAU,CAAC,MAAM,MAAM,CAAC,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC,EAAE,SAAS,CAAC;AACpG,wBAAA,CAAC,CAAC;AAEF,wBAAA,IAAI,MAA4C;AAChD,wBAAA,IAAI;AACF,4BAAA,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;wBAC5D;wBAAE,OAAO,GAAG,EAAE;4BACZ,MAAM,CAAC,MAAM,EAAE;4BACf,eAAe,CAAC,KAAK,EAAE;AACvB,4BAAA,IAAI,CAAC,GAAG,CAAC,MAAM,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;4BACnC;wBACF;AAEA,wBAAA,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM;AAC9B,wBAAA,IAAI,IAAI;4BAAE;AACV,wBAAA,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE;AACzB,wBAAA,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;wBAEjD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC;AAClC,wBAAA,MAAM,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE;AAC1B,wBAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;4BACxB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;4BAC9B,IAAI,SAAS,GAAG,EAAE;4BAClB,IAAI,SAAS,GAAG,EAAE;AAClB,4BAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;AACxB,gCAAA,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;AAAE,oCAAA,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AACpD,qCAAA,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;AAAE,oCAAA,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;4BAC/D;AACA,4BAAA,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS;gCAAE;AAC9B,4BAAA,IAAI;gCACF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC;AACpC,gCAAA,IAAI,SAAS,KAAK,UAAU,EAAE;;;oCAG5B,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;gCACjF;AAAO,qCAAA,IAAI,SAAS,KAAK,QAAQ,EAAE;AACjC,oCAAA,IAAI,CAAC,GAAG,CAAC,MAAK;AACZ,wCAAA,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;wCAC/C,QAAQ,CAAC,QAAQ,EAAE;AACrB,oCAAA,CAAC,CAAC;gCACJ;AAAO,qCAAA,IAAI,SAAS,KAAK,OAAO,EAAE;AAChC,oCAAA,IAAI,CAAC,GAAG,CAAC,MAAM,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gCACxC;4BACF;AAAE,4BAAA,MAAM,4BAA4B;wBACtC;oBACF;AACA,oBAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE;wBACpB,IAAI,CAAC,GAAG,CAAC,MAAM,QAAQ,CAAC,QAAQ,EAAE,CAAC;oBACrC;AACF,gBAAA,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,IAAG;AACb,oBAAA,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE;AAC7B,wBAAA,IAAI,CAAC,GAAG,CAAC,MAAM,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;oBACrC;AACF,gBAAA,CAAC,CAAC;YACJ,CAAC,CAAC,CAAC;AAEH,YAAA,OAAO,MAAM,eAAe,CAAC,KAAK,EAAE;AACtC,QAAA,CAAC,CAAC;IACJ;AAEA;;;AAGG;AACH,IAAA,GAAG,CAAC,MAAc,EAAE,KAAa,EAAE,IAAY,EAAA;QAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC;AACxC,QAAA,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAM,GAAG,MAAM,CAAA,WAAA,CAAa,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC;IAC3E;AAEQ,IAAA,YAAY,CAAC,KAAa,EAAA;QAChC,OAAO,IAAI,WAAW,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;IAChD;uGA1KW,sBAAsB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAtB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,sBAAsB,cADT,MAAM,EAAA,CAAA;;2FACnB,sBAAsB,EAAA,UAAA,EAAA,CAAA;kBADlC,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;MC20BrB,8BAA8B,CAAA;AACL,IAAA,aAAa;AAExC,IAAA,MAAM;AAEP,IAAA,WAAW,GAAG,MAAM,CAAC,sBAAsB,CAAC;AAC5C,IAAA,MAAM,GAAG,MAAM,CAAC,UAAU,CAAC;;AAGnC,IAAA,MAAM,GAAG,MAAM,CAAC,KAAK,kDAAC;AACtB,IAAA,UAAU,GAAG,MAAM,CAAC,KAAK,sDAAC;AAC1B,IAAA,QAAQ,GAAG,MAAM,CAAgB,EAAE,oDAAC;AACpC,IAAA,SAAS,GAAG,MAAM,CAAC,KAAK,qDAAC;AACzB,IAAA,aAAa,GAAG,MAAM,CAAM,IAAI,yDAAC;AACjC,IAAA,SAAS,GAAG,MAAM,CAAgB,IAAI,qDAAC;AACvC,IAAA,QAAQ,GAAG,MAAM,CAAgB,IAAI,oDAAC;AACtC,IAAA,YAAY,GAAG,QAAQ,CAAC,MAAK;AAC3B,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE;AAC3B,QAAA,IAAI,CAAC,GAAG;AAAE,YAAA,OAAO,KAAK;AACtB,QAAA,OAAO,4CAA4C,CAAC,IAAI,CAAC,GAAG,CAAC;AAC/D,IAAA,CAAC,wDAAC;AACF,IAAA,YAAY,GAAG,MAAM,CAAC,KAAK,wDAAC;AAC5B,IAAA,WAAW,GAAG,MAAM,CAAC,KAAK,uDAAC;IACnB,gBAAgB,GAAG,EAAE;IACrB,gBAAgB,GAAG,KAAK;IACxB,aAAa,GAAQ,IAAI;IACjC,SAAS,GAAG,EAAE;AACN,IAAA,mBAAmB;;IAG3B,YAAY,GAAG,EAAE;IAET,SAAS,GAAG,CAAC;IACb,YAAY,GAAG,KAAK;;AAGpB,IAAA,OAAO,GAAG,IAAI,GAAG,EAAoB;;IAErC,mBAAmB,GAAkB,IAAI;IACzC,KAAK,GAAkB,IAAI;;IAGlB,cAAc,GAAG,kBAAkB;IAC5C,UAAU,GAAG,EAAE;AACf,IAAA,eAAe,GAAG,CAAC,CAAe,KAAK,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC;;AAG9D,IAAA,SAAS,GAAG,MAAM,CAAC,YAAY,CAAC;IAExC,cAAc,GAAG,MAAM,CAAkC;AACvD,QAAA,MAAM,EAAE,EAAE;AACV,QAAA,QAAQ,EAAE,EAAE;AACZ,QAAA,KAAK,EAAE,EAAE;AACT,QAAA,mBAAmB,EAAE,IAAI;AACzB,QAAA,YAAY,EAAE,IAAI;AAClB,QAAA,WAAW,EAAE,EAAE;AACf,QAAA,SAAS,EAAE,KAAK;AAChB,QAAA,iBAAiB,EAAE,IAAI;AACvB,QAAA,iBAAiB,EAAE,IAAI;AACvB,QAAA,KAAK,EAAE,cAAc;AACrB,QAAA,WAAW,EAAE,6BAA6B;AAC1C,QAAA,YAAY,EAAE,qBAAqB;AACnC,QAAA,eAAe,EAAE,oCAAoC;AACrD,QAAA,QAAQ,EAAE,cAAc;AACxB,QAAA,UAAU,EAAE,IAAI;AAChB,QAAA,cAAc,EAAE,OAAO;AACvB,QAAA,cAAc,EAAE,EAAE;AAClB,QAAA,SAAS,EAAE,EAAE;AACb,QAAA,UAAU,EAAE,EAAE;AACd,QAAA,YAAY,EAAE,IAAI;AAClB,QAAA,WAAW,EAAE,KAAK;AAClB,QAAA,KAAK,EAAE,EAAE;AACT,QAAA,QAAQ,EAAE,EAAE;AACZ,QAAA,WAAW,EAAE;AACd,KAAA,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,gBAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CAAC;;AAGF,IAAA,WAAW,GAAG,QAAQ,CAAC,MAAK;QAC1B,MAAM,CAAC,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC,KAAK,IAAI,EAAE;QAC3C,MAAM,GAAG,GAA2B,EAAE;AACtC,QAAA,MAAM,KAAK,GAAkC;YAC3C,CAAC,SAAS,EAAE,cAAc,CAAC,EAAE,CAAC,cAAc,EAAE,oBAAoB,CAAC;YACnE,CAAC,QAAQ,EAAE,aAAa,CAAC,EAAE,CAAC,aAAa,EAAE,mBAAmB,CAAC;AAC/D,YAAA,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,cAAc,CAAC,EAAE,CAAC,YAAY,EAAE,kBAAkB,CAAC;YACjF,CAAC,MAAM,EAAE,WAAW,CAAC,EAAE,CAAC,eAAe,EAAE,qBAAqB,CAAC;YAC/D,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa;SAC3D;QACD,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,KAAK,EAAE;YACjC,IAAI,CAAC,CAAC,GAAG,CAAC;gBAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAE;QACnC;AACA,QAAA,OAAO,GAAG;AACZ,IAAA,CAAC,uDAAC;;AAGF,IAAA,kBAAkB,GAAG,QAAQ,CAAW,MAAK;QAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC,SAAS,IAAI,EAAE;QACjD,OAAO,IAAI,CAAC,SAAS,CAAC,uBAAuB,CAAC,GAAG,CAAC;AACpD,IAAA,CAAC,8DAAC;;AAGF,IAAA,iBAAiB,GAAG,QAAQ,CAAkB,MAAK;QACjD,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE;QACjC,OAAO,IAAI,CAAC,SAAS,CAAC,8BAA8B,CAAC,GAAG,CAAC;AAC3D,IAAA,CAAC,6DAAC;IAEF,QAAQ,GAAA;QACN,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,eAAe,CAAC;;;AAGxD,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACzB,QAAA,IAAI,CAAC,YAAY,GAAG,EAAE;AACtB,QAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;AAC1B,QAAA,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC;AAC7B,QAAA,IAAI,CAAC,mBAAmB,EAAE,WAAW,EAAE;AACvC,QAAA,IAAI,CAAC,mBAAmB,GAAG,SAAS;IACtC;IAEA,WAAW,GAAA;QACT,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,IAAI,CAAC,eAAe,CAAC;QAC3D,IAAI,CAAC,WAAW,EAAE;IACpB;AAEA,IAAA,WAAW,CAAC,OAAsB,EAAA;QAChC,IAAI,OAAO,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE;AACpC,YAAA,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC;AACtB,gBAAA,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE;AAChC,gBAAA,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE;AACpC,gBAAA,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE;AAC9B,gBAAA,mBAAmB,EAAE,IAAI,CAAC,MAAM,CAAC,mBAAmB,IAAI,IAAI;AAC5D,gBAAA,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY,IAAI,IAAI;AAC9C,gBAAA,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE;AAC1C,gBAAA,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,KAAK;AACzC,gBAAA,iBAAiB,EAAE,IAAI,CAAC,MAAM,CAAC,iBAAiB,IAAI,IAAI;AACxD,gBAAA,iBAAiB,EAAE,IAAI,CAAC,MAAM,CAAC,iBAAiB,IAAI,IAAI;AACxD,gBAAA,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,cAAc;AAC1C,gBAAA,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,6BAA6B;AACrE,gBAAA,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY,IAAI,qBAAqB;AAC/D,gBAAA,eAAe,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe,IAAI,oCAAoC;AACpF,gBAAA,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,cAAc;AAChD,gBAAA,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,IAAI;AAC1C,gBAAA,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc,IAAI,OAAO;AACrD,gBAAA,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc,IAAI,EAAE;AAChD,gBAAA,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE;AACtC,gBAAA,UAAU,EAAE,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE;AACxC,gBAAA,YAAY,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY,IAAI,IAAI;AAC9C,gBAAA,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,KAAK;AAC7C,gBAAA,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE;AAC9B,gBAAA,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE;AACpC,gBAAA,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI;AACzC,aAAA,CAAC;;YAEF,IAAI,CAAC,WAAW,EAAE;;AAElB,YAAA,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,EAAE;AACrC,YAAA,IAAI,MAAM,KAAK,IAAI,CAAC,UAAU,EAAE;AAC9B,gBAAA,IAAI,CAAC,UAAU,GAAG,MAAM;gBACxB,IAAI,CAAC,WAAW,EAAE;YACpB;;AAEA,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;QAC1B;IACF;IAEA,kBAAkB,GAAA;AAChB,QAAA,IAAI,IAAI,CAAC,YAAY,EAAE;YACrB,IAAI,CAAC,cAAc,EAAE;AACrB,YAAA,IAAI,CAAC,YAAY,GAAG,KAAK;QAC3B;IACF;IAEA,UAAU,GAAA;AACR,QAAA,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3B,QAAA,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE;AAClB,YAAA,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC;AAC1B,YAAA,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC;YAC7B,IAAI,CAAC,WAAW,EAAE;QACpB;QACA,IAAI,IAAI,CAAC,MAAM,EAAE;AAAE,YAAA,IAAI,CAAC,YAAY,GAAG,IAAI;IAC7C;IAEA,YAAY,GAAA;AACV,QAAA,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAC/B,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;IAC3C;;AAGQ,IAAA,iBAAiB,CAAC,IAAa,EAAA;AACrC,QAAA,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,GAAG,QAAQ,GAAG,EAAE;;QAEnD,MAAM,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,iBAAiB,CAAgB;AACnE,QAAA,IAAI,EAAE;AAAE,YAAA,EAAE,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,GAAG,QAAQ,GAAG,EAAE;IAClD;IAEA,WAAW,GAAA;QACT,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE;AAClC,QAAA,IAAI,CAAC,IAAI;YAAE;AAEX,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,cAAc,EAAE;;AAGjC,QAAA,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE;AACd,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,mEAAmE,CAAC;YACvF;QACF;AACA,QAAA,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE;AACf,YAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,yBAAyB,CAAC;YAC7C;QACF;AAEA,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;AACxB,QAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,GAAG,IAAI,EAAE;AACrC,gBAAA,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE;gBACpB,IAAI;AACJ,gBAAA,MAAM,EAAE,MAAM;gBACd,SAAS,EAAE,IAAI,IAAI;AACpB,aAAA,CAAC,CAAC;QACH,IAAI,CAAC,WAAW,EAAE;AAClB,QAAA,IAAI,CAAC,YAAY,GAAG,IAAI;AACxB,QAAA,IAAI,CAAC,SAAS,GAAG,EAAE;AACnB,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;AAExB,QAAA,IAAI,GAAG,CAAC,iBAAiB,EAAE;AACzB,YAAA,IAAI,CAAC,YAAY,GAAG,iBAAiB;QACvC;aAAO;AACL,YAAA,IAAI,CAAC,YAAY,GAAG,iBAAiB;QACvC;QAEA,IAAI,GAAG,CAAC,mBAAmB,IAAI,GAAG,CAAC,QAAQ,EAAE;;AAE3C,YAAA,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ;AAC1B,iBAAA,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,IAAI,CAAC,CAAC,MAAM,KAAK,KAAK;iBACrD,KAAK,CAAC,CAAC,EAAE;AACT,iBAAA,GAAG,CAAC,GAAG,KAAK;AACX,gBAAA,IAAI,EAAE,GAAG,CAAC,MAAM,KAAK,MAAM,GAAG,MAAM,GAAG,WAAW;gBAClD,OAAO,EAAE,GAAG,CAAC;AACd,aAAA,CAAC,CAAC;YAEL,MAAM,GAAG,GAAG,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,SAAS;AAEhD,YAAA,IAAI,GAAG,CAAC,iBAAiB,EAAE;;gBAEzB,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,WAAW,CAAC,6BAA6B,CACvE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,iBAAiB,EAChG,GAAG,CAAC,QAAQ,IAAI,SAAS,EAAE,GAAG,CAAC,WAAW,IAAI,SAAS,CACxD,CAAC,SAAS,CAAC;AACV,oBAAA,IAAI,EAAE,CAAC,KAAK,KAAI;AAChB,wBAAA,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE;;;4BAG7B,IAAI,CAAC,mBAAmB,GAAG,KAAK,CAAC,OAAO,IAAI,EAAE;AAC9C,4BAAA,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE;AACvB,gCAAA,IAAI,CAAC,KAAK,GAAG,qBAAqB,CAAC,MAAK;AACtC,oCAAA,IAAI,CAAC,KAAK,GAAG,IAAI;AACjB,oCAAA,IAAI,IAAI,CAAC,mBAAmB,KAAK,IAAI,EAAE;AACrC,wCAAA,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,mBAAmB;AAC5C,wCAAA,IAAI,CAAC,mBAAmB,GAAG,IAAI;oCACjC;AACF,gCAAA,CAAC,CAAC;4BACJ;4BACA;wBACF;AAAO,6BAAA,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE;AAChC,4BAAA,IAAI,CAAC,YAAY,GAAG,EAAE;AACtB,4BAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACzB,4BAAA,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI;AAC3B,4BAAA,MAAM,YAAY,GAAG,QAAQ,CAAC;AAC5B,mCAAG,QAAQ,CAAC,QAAQ,IAAI,kCAAkC;mCACvD,QAAQ,CAAC,KAAK,IAAI,sBAAsB,CAAC;AAE9C,4BAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,GAAG,IAAI,EAAE;AACrC,oCAAA,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE;AACpB,oCAAA,IAAI,EAAE,YAAY;AAClB,oCAAA,MAAM,EAAE,KAAK;oCACb,SAAS,EAAE,IAAI,IAAI,EAAE;AACrB,oCAAA,SAAS,EAAE;wCACT,OAAO,EAAE,QAAQ,CAAC,OAAO;wCACzB,SAAS,EAAE,QAAQ,CAAC,SAAS;wCAC7B,WAAW,EAAE,QAAQ,CAAC,WAAW;wCACjC,KAAK,EAAE,QAAQ,CAAC,KAAK;wCACrB,WAAW,EAAE,QAAQ,CAAC,WAAW;wCACjC,SAAS,EAAE,QAAQ,CAAC,SAAS;wCAC7B,IAAI,EAAE,QAAQ,CAAC;AAChB;AACF,iCAAA,CAAC,CAAC;4BACH,IAAI,CAAC,WAAW,EAAE;AAClB,4BAAA,IAAI,CAAC,YAAY,GAAG,IAAI;wBAC1B;oBACF,CAAC;AACD,oBAAA,KAAK,EAAE,CAAC,KAAK,KAAI;AACf,wBAAA,IAAI,CAAC,YAAY,GAAG,EAAE;AACtB,wBAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACzB,wBAAA,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC;AAC7B,wBAAA,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;oBACzB;AACD,iBAAA,CAAC;YACJ;iBAAO;;gBAEL,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,WAAW,CAAC,uBAAuB,CACjE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,YAAY,EAAE,GAAG,CAAC,iBAAiB,EAChG,GAAG,CAAC,QAAQ,IAAI,SAAS,EAAE,GAAG,CAAC,WAAW,IAAI,SAAS,CACxD,CAAC,SAAS,CAAC;AACV,oBAAA,IAAI,EAAE,CAAC,QAAa,KAAI;AACtB,wBAAA,IAAI,CAAC,YAAY,GAAG,EAAE;AACtB,wBAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACzB,wBAAA,MAAM,YAAY,GAAG,QAAQ,CAAC;AAC5B,+BAAG,QAAQ,CAAC,QAAQ,IAAI,kCAAkC;+BACvD,QAAQ,CAAC,KAAK,IAAI,sBAAsB,CAAC;AAE9C,wBAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,GAAG,IAAI,EAAE;AACrC,gCAAA,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE;AACpB,gCAAA,IAAI,EAAE,YAAY;AAClB,gCAAA,MAAM,EAAE,KAAK;gCACb,SAAS,EAAE,IAAI,IAAI,EAAE;AACrB,gCAAA,SAAS,EAAE;oCACT,OAAO,EAAE,QAAQ,CAAC,OAAO;oCACzB,SAAS,EAAE,QAAQ,CAAC,SAAS;oCAC7B,WAAW,EAAE,QAAQ,CAAC,WAAW;oCACjC,KAAK,EAAE,QAAQ,CAAC,KAAK;oCACrB,WAAW,EAAE,QAAQ,CAAC,WAAW;oCACjC,SAAS,EAAE,QAAQ,CAAC,SAAS;oCAC7B,IAAI,EAAE,QAAQ,CAAC;AAChB;AACF,6BAAA,CAAC,CAAC;wBACH,IAAI,CAAC,WAAW,EAAE;AAClB,wBAAA,IAAI,CAAC,YAAY,GAAG,IAAI;oBAC1B,CAAC;AACD,oBAAA,KAAK,EAAE,CAAC,KAAK,KAAI;AACf,wBAAA,IAAI,CAAC,YAAY,GAAG,EAAE;AACtB,wBAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACzB,wBAAA,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC;AAC7B,wBAAA,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;oBACzB;AACD,iBAAA,CAAC;YACJ;QACF;aAAO;;YAEL,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,SAAS,CAAC;AACrF,gBAAA,IAAI,EAAE,CAAC,QAAQ,KAAI;AACjB,oBAAA,IAAI,CAAC,YAAY,GAAG,EAAE;AACtB,oBAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACzB,oBAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,GAAG,IAAI,EAAE;AACrC,4BAAA,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE;AACpB,4BAAA,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,IAAI,eAAe;AAChD,4BAAA,MAAM,EAAE,KAAK;4BACb,SAAS,EAAE,IAAI,IAAI,EAAE;AACrB,4BAAA,SAAS,EAAE;gCACT,OAAO,EAAE,QAAQ,CAAC,OAAO;AACzB,gCAAA,YAAY,EAAE,QAAQ,CAAC,IAAI,EAAE,cAAc;AAC3C,gCAAA,YAAY,EAAE,QAAQ,CAAC,IAAI,EAAE,YAAY;AACzC,gCAAA,SAAS,EAAE,QAAQ,CAAC,IAAI,EAAE;AAC3B;AACF,yBAAA,CAAC,CAAC;oBACH,IAAI,CAAC,WAAW,EAAE;AAClB,oBAAA,IAAI,CAAC,YAAY,GAAG,IAAI;gBAC1B,CAAC;AACD,gBAAA,KAAK,EAAE,CAAC,KAAK,KAAI;AACf,oBAAA,IAAI,CAAC,YAAY,GAAG,EAAE;AACtB,oBAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACzB,oBAAA,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC;AAC7B,oBAAA,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;gBACzB;AACD,aAAA,CAAC;QACJ;IACF;IAEA,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,mBAAmB,EAAE,WAAW,EAAE;AACvC,QAAA,IAAI,CAAC,mBAAmB,GAAG,SAAS;AACpC,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AACzB,QAAA,IAAI,CAAC,YAAY,GAAG,EAAE;AACtB,QAAA,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC;IAC/B;IAEA,SAAS,GAAA;AACP,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;AACrB,QAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;AAC5B,QAAA,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;QACxB,IAAI,CAAC,YAAY,EAAE;IACrB;AAEA,IAAA,SAAS,CAAC,GAAgB,EAAA;QACxB,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC;IACvC;IAEA,UAAU,GAAA;AACR,QAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC;IAC9B;;AAGA,IAAA,aAAa,CAAC,GAAW,EAAA;AACvB,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;AAC3B,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;AAC3B,QAAA,IAAI,CAAC,gBAAgB,GAAG,KAAK;AAC7B,QAAA,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC;AAChC,QAAA,IAAI,CAAC,gBAAgB,GAAG,GAAG;AAC3B,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;IACxB;IAEA,cAAc,GAAA;AACZ,QAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;AACvB,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC;AAC5B,QAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;AAC3B,QAAA,IAAI,CAAC,gBAAgB,GAAG,KAAK;AAC7B,QAAA,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC;AAChC,QAAA,IAAI,CAAC,gBAAgB,GAAG,EAAE;IAC5B;IAEA,cAAc,GAAA;AACZ,QAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC;AAC5B,QAAA,IAAI,IAAI,CAAC,gBAAgB,EAAE;;AAEzB,YAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;QAC5B;aAAO;;;AAGL,YAAA,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC;AAChC,YAAA,IAAI,CAAC,aAAa,GAAG,UAAU,CAAC,MAAK,EAAG,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC;QAChF;IACF;IAEA,YAAY,GAAA;AACV,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC,iBAAiB,CAAsB;AAC9F,QAAA,IAAI,MAAM,IAAI,IAAI,CAAC,gBAAgB,EAAE;AACnC,YAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC;AAC3B,YAAA,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC;AAC3B,YAAA,IAAI,CAAC,gBAAgB,GAAG,KAAK;AAC7B,YAAA,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC;AAChC,YAAA,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC,gBAAgB;QACpC;IACF;;AAGA,IAAA,cAAc,CAAC,KAAiB,EAAA;AAC9B,QAAA,MAAM,MAAM,GAAG,KAAK,CAAC,MAAqB;;AAG1C,QAAA,IAAI,MAAM,CAAC,OAAO,KAAK,KAAK,EAAE;AAC5B,YAAA,MAAM,GAAG,GAAI,MAA2B,CAAC,GAAG;YAC5C,IAAI,GAAG,EAAE;gBACP,KAAK,CAAC,cAAc,EAAE;gBACtB,KAAK,CAAC,eAAe,EAAE;AACvB,gBAAA,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC;gBACvB;YACF;QACF;QAEA,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAA6B;AAC9D,QAAA,IAAI,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE;YACzB,KAAK,CAAC,cAAc,EAAE;YACtB,KAAK,CAAC,eAAe,EAAE;AACvB,YAAA,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC;QACjC;IACF;AAEA,IAAA,UAAU,CAAC,IAAU,EAAA;AACnB,QAAA,OAAO,IAAI,CAAC,kBAAkB,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IACjF;AAEA,IAAA,cAAc,CAAC,IAAY,EAAA;AACzB,QAAA,IAAI,CAAC,IAAI;AAAE,YAAA,OAAO,EAAE;;QAGpB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AACrC,QAAA,IAAI,MAAM;AAAE,YAAA,OAAO,MAAM;AAEzB,QAAA,IAAI;;;YAGF,IAAI,YAAY,GAAG,IAAI,CAAC,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC,GAAG,IAAI;;AAGpF,YAAA,IAAI,YAAY,CAAC,MAAM,GAAG,OAAO,EAAE;AACjC,gBAAA,YAAY,GAAG,YAAY,CAAC,OAAO,CAAC,4BAA4B,EAC9D,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA,CAAA,CAAG,CAAC;YACxE;AAEA,YAAA,IAAI,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,YAAY,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAW;;YAEjE,MAAM,QAAQ,GAAG,CAAA,mOAAA,CAAqO;YACtP,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAA,KAAA,EAAQ,QAAQ,CAAA,qCAAA,CAAuC,CAAC;YACtF,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,uBAAuB,CAAC,IAAI,CAAC;YAC3D,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC;AAC9B,YAAA,OAAO,MAAM;QACf;AAAE,QAAA,MAAM;AACN,YAAA,OAAO,IAAI;QACb;IACF;AAEA;;;;;;;;;;;AAWG;AACK,IAAA,uBAAuB,CAAC,IAAY,EAAA;;;;QAI1C,IAAI,GAAG,IAAI,CAAC,OAAO,CACjB,sCAAsC,EACtC,QAAQ,CACT;;QAED,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC;;QAGtC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;QAC9B,MAAM,MAAM,GAAa,EAAE;QAC3B,IAAI,OAAO,GAAG,KAAK;AAEnB,QAAA,MAAM,UAAU,GAAG,CAAC,CAAS,KAAI;AAC/B,YAAA,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE;AAClB,YAAA,OAAO,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC;AACrD,QAAA,CAAC;AACD,QAAA,MAAM,SAAS,GAAG,CAAC,CAAS,KAC1B,kCAAkC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AAEnD,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AACrC,YAAA,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC;AACrB,YAAA,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE;YAE3B,IAAI,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EAAE;gBAC9C,IAAI,CAAC,OAAO,EAAE;oBACZ,OAAO,GAAG,IAAI;;oBAEd,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;AAChE,wBAAA,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;oBACjB;AACA,oBAAA,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;;oBAEjB,MAAM,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE;AACvD,oBAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE;wBACpB,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM;wBACnE,MAAM,CAAC,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;oBAChE;gBACF;qBAAO;AACL,oBAAA,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACpB;YACF;AAAO,iBAAA,IAAI,SAAS,CAAC,OAAO,CAAC,EAAE;AAC7B,gBAAA,IAAI,CAAC,OAAO;AAAE,oBAAA,OAAO,GAAG,IAAI,CAAC;AAC7B,gBAAA,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;YACnB;iBAAO;gBACL,OAAO,GAAG,KAAK;AACf,gBAAA,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;YACnB;QACF;AAEA,QAAA,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;IAC1B;;AAIQ,IAAA,WAAW,CAAC,KAAU,EAAA;AAC5B,QAAA,MAAM,MAAM,GAAG,KAAK,EAAE,MAAM;QAC5B,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,EAAE;AACpC,YAAA,MAAM,GAAG,GAAG,MAAM,KAAK,GAAG,GAAG,2BAA2B,GAAG,gCAAgC;YAC3F,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA,GAAA,EAAM,GAAG,CAAA,CAAE,CAAC;AAC/B,YAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,GAAG,IAAI,EAAE;AACrC,oBAAA,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE;oBACpB,IAAI,EAAE,CAAA,GAAA,EAAM,GAAG,CAAA,+CAAA,CAAiD;AAChE,oBAAA,MAAM,EAAE,KAAK;oBACb,SAAS,EAAE,IAAI,IAAI;AACpB,iBAAA,CAAC,CAAC;QACL;aAAO;AACL,YAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,GAAG,IAAI,EAAE;AACrC,oBAAA,EAAE,EAAE,IAAI,CAAC,SAAS,EAAE;AACpB,oBAAA,IAAI,EAAE,CAAA,OAAA,EAAU,KAAK,CAAC,KAAK,EAAE,OAAO,IAAI,KAAK,CAAC,KAAK,EAAE,KAAK,IAAI,iCAAiC,CAAA,CAAE;AACjG,oBAAA,MAAM,EAAE,KAAK;oBACb,SAAS,EAAE,IAAI,IAAI;AACpB,iBAAA,CAAC,CAAC;QACL;QACA,IAAI,CAAC,WAAW,EAAE;AAClB,QAAA,IAAI,CAAC,YAAY,GAAG,IAAI;IAC1B;IAEQ,iBAAiB,GAAA;AACvB,QAAA,IAAI,CAAC,YAAY,GAAG,EAAE;IACxB;IAEQ,cAAc,GAAA;AACpB,QAAA,IAAI,IAAI,CAAC,aAAa,EAAE;AACtB,YAAA,MAAM,EAAE,GAAG,IAAI,CAAC,aAAa,CAAC,aAAa;AAC3C,YAAA,EAAE,CAAC,SAAS,GAAG,EAAE,CAAC,YAAY;QAChC;IACF;;IAIQ,eAAe,GAAA;AACrB,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,cAAc,EAAE;QACjC,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,QAAQ;AAAE,YAAA,OAAO,EAAE;;AAE1C,QAAA,MAAM,WAAW,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC;QAC7C,OAAO,CAAA,EAAG,IAAI,CAAC,cAAc,CAAA,EAAG,GAAG,CAAC,QAAQ,CAAA,CAAA,EAAI,WAAW,CAAA,CAAE;IAC/D;IAEQ,WAAW,GAAA;QACjB,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE;AACtB,QAAA,IAAI;AACF,YAAA,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK;gBACrC,EAAE,EAAE,CAAC,CAAC,EAAE;gBACR,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,MAAM,EAAE,CAAC,CAAC,MAAM;gBAChB,SAAS,EAAE,CAAC,CAAC,SAAS;gBACtB,SAAS,EAAE,CAAC,CAAC;AACd,aAAA,CAAC,CAAC;AACH,YAAA,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC7D;AAAE,QAAA,MAAM,4BAA4B;IACtC;IAEQ,WAAW,GAAA;QACjB,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE;AACtB,QAAA,IAAI;YACF,MAAM,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC;YACjD,IAAI,CAAC,GAAG,EAAE;AAAE,gBAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE;YAAQ;YAC3C,MAAM,IAAI,GAAU,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;;AAEnC,YAAA,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE;AAC7C,gBAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBACrB;YACF;YACA,MAAM,IAAI,GAAkB;iBACzB,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ;AAC3E,iBAAA,GAAG,CAAC,CAAC,KAAK;AACT,gBAAA,GAAG,CAAC;AACJ,gBAAA,SAAS,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS;AAChC,aAAA,CAAC,CAAC;AACL,YAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC;AACvB,YAAA,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;AAC3E,YAAA,IAAI,CAAC,YAAY,GAAG,IAAI;QAC1B;AAAE,QAAA,MAAM;;AAEN,YAAA,IAAI;AAAE,gBAAA,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC;YAAE;AAAE,YAAA,MAAM,eAAe;AACvE,YAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB;IACF;IAEQ,YAAY,GAAA;AAClB,QAAA,IAAI,IAAI,CAAC,UAAU,EAAE;AACnB,YAAA,IAAI;AAAE,gBAAA,YAAY,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC;YAAE;YAAE,MAAM,EAAC;QAC3D;IACF;;AAGQ,IAAA,eAAe,CAAC,CAAe,EAAA;QACrC,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,UAAU;YAAE;AACnD,QAAA,IAAI,CAAC,CAAC,QAAQ,KAAK,IAAI,EAAE;;AAEvB,YAAA,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB;aAAO;YACL,IAAI,CAAC,WAAW,EAAE;QACpB;AACA,QAAA,IAAI,CAAC,YAAY,GAAG,IAAI;IAC1B;uGAlpBW,8BAA8B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAA9B,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,8BAA8B,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,yBAAA,EAAA,MAAA,EAAA,EAAA,MAAA,EAAA,QAAA,EAAA,EAAA,WAAA,EAAA,CAAA,EAAA,YAAA,EAAA,eAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,eAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,CAAA,EAAA,aAAA,EAAA,IAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EAv0B/B,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgNT,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,mobAAA,CAAA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAjNS,YAAY,mHAAE,WAAW,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,aAAA,EAAA,QAAA,EAAA,8CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,8MAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,2CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,sGAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,OAAA,EAAA,QAAA,EAAA,qDAAA,EAAA,MAAA,EAAA,CAAA,MAAA,EAAA,UAAA,EAAA,SAAA,EAAA,gBAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,CAAA,EAAA,QAAA,EAAA,CAAA,SAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,QAAA,EAAA,yEAAA,EAAA,MAAA,EAAA,CAAA,eAAA,CAAA,EAAA,OAAA,EAAA,CAAA,UAAA,CAAA,EAAA,QAAA,EAAA,CAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA,EAAA,CAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,EAAA,CAAA;;2FAw0BxB,8BAA8B,EAAA,UAAA,EAAA,CAAA;kBA30B1C,SAAS;+BACE,yBAAyB,EAAA,UAAA,EACvB,IAAI,EAAA,OAAA,EACP,CAAC,YAAY,EAAE,WAAW,CAAC,EAAA,QAAA,EAC1B,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgNT,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,mobAAA,CAAA,EAAA;;sBAwnBA,SAAS;uBAAC,eAAe;;sBAEzB;;;AC11BH;;AAEG;;ACFH;;AAEG;;;;"}
1
+ {"version":3,"file":"maquito-chat-plugin.mjs","sources":["../../../frontend/maquito-chat-plugin/src/lib/intelligent-chat.service.ts","../../../frontend/maquito-chat-plugin/src/lib/intelligent-chat-plugin.component.ts","../../../frontend/maquito-chat-plugin/src/public-api.ts","../../../frontend/maquito-chat-plugin/src/maquito-chat-plugin.ts"],"sourcesContent":["import { Injectable, inject, NgZone } from '@angular/core';\r\nimport { HttpClient, HttpHeaders } from '@angular/common/http';\r\nimport { Observable } from 'rxjs';\r\n\r\n/**\r\n * Standalone HTTP service for the Maquito Chat Plugin.\r\n * Decoupled from any host app service — uses apiUrl + token from config.\r\n * Replicates exactly the same endpoints used by the Maquito Core API.\r\n *\r\n * IMPORTANT: The SSE streaming method runs OUTSIDE Angular Zone to prevent\r\n * change detection storms that freeze the host application's UI.\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class IntelligentChatService {\r\n\r\n private http = inject(HttpClient);\r\n private ngZone = inject(NgZone);\r\n\r\n /**\r\n * Execute an intelligent query (POST /api/query).\r\n * Auth via X-Api-Key header.\r\n */\r\n executeIntelligentQuery(\r\n apiUrl: string,\r\n token: string,\r\n systemId: string,\r\n question: string,\r\n conversationHistory: { role: string; content: string }[] = [],\r\n baseContext?: string,\r\n skipPatternCache?: boolean,\r\n preferTableFormat?: boolean,\r\n userName?: string,\r\n personality?: string\r\n ): Observable<any> {\r\n const headers = this.buildHeaders(token);\r\n const body: any = { systemId, question, conversationHistory };\r\n if (baseContext) body.baseContext = baseContext;\r\n if (skipPatternCache) body.skipPatternCache = skipPatternCache;\r\n if (preferTableFormat !== undefined) body.preferTableFormat = preferTableFormat;\r\n if (userName) body.userName = userName;\r\n if (personality) body.personality = personality;\r\n return this.http.post<any>(`${apiUrl}/query`, body, { headers });\r\n }\r\n\r\n /**\r\n * Execute an intelligent query with SSE streaming progress.\r\n * Emits: { type: 'progress', step: string, message: string }\r\n * { type: 'result', data: any }\r\n *\r\n * The fetch + reader loop runs OUTSIDE Angular Zone to avoid\r\n * triggering change detection on every microtask (which would\r\n * freeze the host app). Emissions re-enter the zone via ngZone.run().\r\n */\r\n executeIntelligentQueryStream(\r\n apiUrl: string,\r\n token: string,\r\n systemId: string,\r\n question: string,\r\n conversationHistory: { role: string; content: string }[] = [],\r\n baseContext?: string,\r\n skipPatternCache?: boolean,\r\n preferTableFormat?: boolean,\r\n userName?: string,\r\n personality?: string\r\n ): Observable<{ type: 'progress' | 'result'; step?: string; message?: string; data?: any }> {\r\n const body: any = { systemId, question, conversationHistory };\r\n if (baseContext) body.baseContext = baseContext;\r\n if (skipPatternCache) body.skipPatternCache = skipPatternCache;\r\n if (preferTableFormat !== undefined) body.preferTableFormat = preferTableFormat;\r\n if (userName) body.userName = userName;\r\n if (personality) body.personality = personality;\r\n\r\n const FETCH_TIMEOUT_MS = 120_000; // 2 min max for the entire request\r\n const INACTIVITY_TIMEOUT_MS = 60_000; // 60s without data = abort\r\n const zone = this.ngZone;\r\n\r\n return new Observable(observer => {\r\n const abortController = new AbortController();\r\n\r\n // Run the entire fetch + SSE loop OUTSIDE Angular Zone\r\n // to prevent change detection storms that freeze the UI\r\n zone.runOutsideAngular(() => {\r\n // Combine user abort + global timeout\r\n let signal: AbortSignal;\r\n if (typeof AbortSignal.any === 'function') {\r\n signal = AbortSignal.any([abortController.signal, AbortSignal.timeout(FETCH_TIMEOUT_MS)]);\r\n } else {\r\n signal = abortController.signal;\r\n setTimeout(() => abortController.abort(), FETCH_TIMEOUT_MS);\r\n }\r\n\r\n fetch(`${apiUrl}/query/stream`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json', 'X-Api-Key': token },\r\n body: JSON.stringify(body),\r\n signal\r\n }).then(async response => {\r\n if (!response.ok || !response.body) {\r\n zone.run(() => observer.error(new Error(`HTTP ${response.status}`)));\r\n return;\r\n }\r\n const reader = response.body.getReader();\r\n const decoder = new TextDecoder();\r\n let buffer = '';\r\n let lastDataTime = Date.now();\r\n\r\n while (true) {\r\n // Race reader vs inactivity timeout\r\n const readPromise = reader.read();\r\n const timeoutPromise = new Promise<never>((_, reject) => {\r\n const elapsed = Date.now() - lastDataTime;\r\n const remaining = Math.max(INACTIVITY_TIMEOUT_MS - elapsed, 100);\r\n setTimeout(() => reject(new Error('SSE inactivity timeout: no data received for 60s')), remaining);\r\n });\r\n\r\n let result: ReadableStreamReadResult<Uint8Array>;\r\n try {\r\n result = await Promise.race([readPromise, timeoutPromise]);\r\n } catch (err) {\r\n reader.cancel();\r\n abortController.abort();\r\n zone.run(() => observer.error(err));\r\n return;\r\n }\r\n\r\n const { done, value } = result;\r\n if (done) break;\r\n lastDataTime = Date.now();\r\n buffer += decoder.decode(value, { stream: true });\r\n\r\n const parts = buffer.split('\\n\\n');\r\n buffer = parts.pop() || '';\r\n for (const part of parts) {\r\n const lines = part.split('\\n');\r\n let eventType = '';\r\n let eventData = '';\r\n for (const line of lines) {\r\n if (line.startsWith('event: ')) eventType = line.slice(7);\r\n else if (line.startsWith('data: ')) eventData = line.slice(6);\r\n }\r\n if (!eventType || !eventData) continue;\r\n try {\r\n const parsed = JSON.parse(eventData);\r\n if (eventType === 'progress') {\r\n // Emit progress WITHOUT re-entering Angular zone.\r\n // The component debounces these via requestAnimationFrame.\r\n observer.next({ type: 'progress', step: parsed.step, message: parsed.message });\r\n } else if (eventType === 'result') {\r\n zone.run(() => {\r\n observer.next({ type: 'result', data: parsed });\r\n observer.complete();\r\n });\r\n } else if (eventType === 'error') {\r\n zone.run(() => observer.error(parsed));\r\n }\r\n } catch { /* skip malformed JSON */ }\r\n }\r\n }\r\n if (!observer.closed) {\r\n zone.run(() => observer.complete());\r\n }\r\n }).catch(err => {\r\n if (err.name !== 'AbortError') {\r\n zone.run(() => observer.error(err));\r\n }\r\n });\r\n }); // end runOutsideAngular\r\n\r\n return () => abortController.abort();\r\n });\r\n }\r\n\r\n /**\r\n * Standard orchestration ask (POST /api/cortex/ask).\r\n * Used when intelligent query mode is disabled.\r\n */\r\n ask(apiUrl: string, token: string, text: string): Observable<any> {\r\n const headers = this.buildHeaders(token);\r\n return this.http.post<any>(`${apiUrl}/cortex/ask`, { text }, { headers });\r\n }\r\n\r\n private buildHeaders(token: string): HttpHeaders {\r\n return new HttpHeaders({ 'X-Api-Key': token });\r\n }\r\n}\r\n","import {\r\n Component, Input, inject, signal, computed, ViewChild, ElementRef,\r\n AfterViewChecked, OnChanges, OnInit, OnDestroy, SimpleChanges, HostListener\r\n} from '@angular/core';\r\nimport { CommonModule } from '@angular/common';\r\nimport { FormsModule } from '@angular/forms';\r\nimport { DomSanitizer, SafeHtml, SafeResourceUrl } from '@angular/platform-browser';\r\nimport { marked } from 'marked';\r\nimport { Subscription } from 'rxjs';\r\nimport { IntelligentChatConfig, ChatMessage, PluginTheme } from './intelligent-chat.models';\r\nimport { IntelligentChatService } from './intelligent-chat.service';\r\n\r\n@Component({\r\n selector: 'intelligent-chat-plugin',\r\n standalone: true,\r\n imports: [CommonModule, FormsModule],\r\n template: `\r\n <!-- Host theme overrides -->\r\n <div class=\"iq-theme-host\" [ngStyle]=\"themeStyles()\">\r\n\r\n <!-- Floating Bubble Button (hidden when expanded) -->\r\n @if (!isExpanded()) {\r\n <button\r\n class=\"iq-bubble\"\r\n [class.iq-bottom-left]=\"resolvedConfig().position === 'bottom-left'\"\r\n [class.iq-open]=\"isOpen()\"\r\n [style.position]=\"resolvedConfig().stickyBubble ? 'fixed' : 'absolute'\"\r\n (click)=\"toggleChat()\"\r\n [attr.aria-label]=\"isOpen() ? 'Cerrar chat' : 'Abrir chat'\"\r\n >\r\n @if (isOpen()) {\r\n <span class=\"iq-bubble-icon\">✕</span>\r\n } @else {\r\n @switch (resolvedConfig().bubbleIconType) {\r\n @case ('image') {\r\n <img [src]=\"resolvedConfig().bubbleImageUrl\" alt=\"Chat\" class=\"iq-bubble-img\" />\r\n }\r\n @case ('svg') {\r\n <span class=\"iq-bubble-svg\" [innerHTML]=\"sanitizedBubbleSvg()\"></span>\r\n }\r\n @default {\r\n <span class=\"iq-bubble-icon\">{{ resolvedConfig().bubbleIcon }}</span>\r\n }\r\n }\r\n }\r\n </button>\r\n }\r\n\r\n <!-- Chat Panel -->\r\n @if (isOpen()) {\r\n <div\r\n class=\"iq-panel\"\r\n [class.iq-bottom-left]=\"resolvedConfig().position === 'bottom-left'\"\r\n [class.iq-expanded]=\"isExpanded()\"\r\n [class]=\"resolvedConfig().themeClass || ''\"\r\n [style.position]=\"resolvedConfig().stickyBubble ? 'fixed' : 'absolute'\"\r\n >\r\n <!-- Header -->\r\n <div class=\"iq-header\">\r\n <span class=\"iq-header-title\"\r\n (touchstart)=\"onTitleTouchStart($event)\"\r\n (touchend)=\"onTitleTouchEnd()\"\r\n (touchcancel)=\"onTitleTouchEnd()\"\r\n >{{ resolvedConfig().title }}</span>\r\n <div class=\"iq-header-actions\">\r\n @if (resolvedConfig().enableDebugMenu) {\r\n <div class=\"iq-debug-menu-wrapper\">\r\n <button class=\"iq-header-btn\" (click)=\"toggleDebugMenu()\" title=\"Opciones\">⋯</button>\r\n @if (showDebugMenu()) {\r\n <div class=\"iq-debug-dropdown\">\r\n <button class=\"iq-debug-option\" (click)=\"downloadConversationLog(); toggleDebugMenu()\">\r\n 📥 Descargar Log\r\n </button>\r\n </div>\r\n }\r\n </div>\r\n }\r\n <button class=\"iq-header-btn\" (click)=\"clearChat()\" title=\"Limpiar chat\">🗑️</button>\r\n @if (resolvedConfig().allowExpand) {\r\n <button class=\"iq-header-btn iq-btn-expand\" (click)=\"toggleExpand()\" [title]=\"isExpanded() ? 'Contraer' : 'Expandir'\">\r\n {{ isExpanded() ? '⊡' : '⛶' }}\r\n </button>\r\n }\r\n <button class=\"iq-header-btn\" (click)=\"isExpanded() ? toggleExpand() : toggleChat()\">✕</button>\r\n </div>\r\n </div>\r\n\r\n <!-- Auth Error Banner -->\r\n @if (authError()) {\r\n <div class=\"iq-auth-error\">\r\n <span>🔒</span>\r\n <span>{{ authError() }}</span>\r\n </div>\r\n }\r\n\r\n <!-- Messages -->\r\n <div class=\"iq-messages\" #chatContainer>\r\n @if (messages().length === 0 && !authError()) {\r\n <div class=\"iq-empty\">\r\n <div class=\"iq-empty-icon\">\r\n @switch (resolvedConfig().bubbleIconType) {\r\n @case ('image') {\r\n <img [src]=\"resolvedConfig().bubbleImageUrl\" alt=\"\" class=\"iq-empty-img\" />\r\n }\r\n @case ('svg') {\r\n <span class=\"iq-empty-svg\" [innerHTML]=\"sanitizedBubbleSvg()\"></span>\r\n }\r\n @default {\r\n <span>{{ resolvedConfig().bubbleIcon }}</span>\r\n }\r\n }\r\n </div>\r\n <p>{{ resolvedConfig().welcomeTitle }}</p>\r\n <p class=\"iq-text-muted\">{{ resolvedConfig().welcomeSubtitle }}</p>\r\n </div>\r\n }\r\n\r\n @for (msg of messages(); track msg.id) {\r\n <div class=\"iq-msg\" [class.iq-msg-user]=\"msg.sender === 'user'\" [class.iq-msg-bot]=\"msg.sender === 'bot'\">\r\n <div class=\"iq-msg-content\">\r\n @if (msg.sender === 'bot') {\r\n <div class=\"iq-md\" [innerHTML]=\"renderMarkdown(msg.text)\" (click)=\"onMessageClick($event)\"></div>\r\n } @else {\r\n <p>{{ msg.text }}</p>\r\n }\r\n <span class=\"iq-msg-time\">{{ formatTime(msg.timestamp) }}</span>\r\n </div>\r\n @if (msg.sender === 'bot' && msg.traceData && resolvedConfig().showTrace) {\r\n <button class=\"iq-btn-trace\" (click)=\"showTrace(msg)\">🔍 Ver Traza</button>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Pipeline progress -->\r\n @if (isLoading()) {\r\n <div class=\"iq-msg iq-msg-bot\">\r\n <div class=\"iq-msg-content iq-pipeline\">\r\n <span class=\"iq-dot\"></span>\r\n <span class=\"iq-pipeline-text\">{{ pipelineStep }}</span>\r\n <button class=\"iq-cancel-btn\" (click)=\"cancelQuery()\" title=\"Cancelar consulta\">✕</button>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Input -->\r\n <form class=\"iq-input-bar\" (ngSubmit)=\"sendMessage()\">\r\n <input\r\n type=\"text\"\r\n [(ngModel)]=\"inputText\"\r\n name=\"message\"\r\n [placeholder]=\"resolvedConfig().placeholder!\"\r\n [disabled]=\"isLoading() || !!authError()\"\r\n autocomplete=\"off\"\r\n />\r\n <button type=\"submit\" class=\"iq-btn-send\" [disabled]=\"isLoading() || !inputText.trim() || !!authError()\">\r\n ➤\r\n </button>\r\n </form>\r\n </div>\r\n }\r\n\r\n <!-- Trace Modal Overlay -->\r\n @if (selectedTrace()) {\r\n <div class=\"iq-trace-overlay\" (click)=\"closeTrace()\">\r\n <div class=\"iq-trace-modal\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"iq-trace-header\">\r\n <h3>🔍 Detalle de Traza</h3>\r\n <button class=\"iq-header-btn\" (click)=\"closeTrace()\">✕</button>\r\n </div>\r\n <div class=\"iq-trace-body\">\r\n @if (selectedTrace()?.fromCache !== undefined) {\r\n <div class=\"iq-trace-item\">\r\n <label>Origen</label>\r\n <code [class.iq-cache-hit]=\"selectedTrace()?.fromCache\">{{ selectedTrace()?.fromCache ? '📚 Desde Caché' : '🤖 Generado por GPT' }}</code>\r\n </div>\r\n }\r\n @if (selectedTrace()?.query) {\r\n <div class=\"iq-trace-item\">\r\n <label>{{ getQuerySections().length > 1 ? 'Queries Generadas (' + getQuerySections().length + ')' : 'Query Generada' }}</label>\r\n @for (section of getQuerySections(); track $index) {\r\n @if (section.model) {\r\n <div style=\"color: #4ecdc4; font-size: 11px; font-weight: bold; margin-top: 8px;\">📋 {{ section.model }}</div>\r\n }\r\n <pre class=\"iq-query-code\" style=\"margin-top: 4px;\">{{ section.query }}</pre>\r\n }\r\n </div>\r\n }\r\n @if (selectedTrace()?.explanation) {\r\n <div class=\"iq-trace-item\">\r\n <label>Explicación</label>\r\n <code>{{ selectedTrace()?.explanation }}</code>\r\n </div>\r\n }\r\n @if (selectedTrace()?.traceId) {\r\n <div class=\"iq-trace-item\">\r\n <label>Trace ID</label>\r\n <code>{{ selectedTrace()?.traceId }}</code>\r\n </div>\r\n }\r\n @if (selectedTrace()?.data) {\r\n <div class=\"iq-trace-item\">\r\n <label>Datos Retornados</label>\r\n <pre>{{ selectedTrace()?.data | json }}</pre>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n <!-- Link Modal Overlay -->\r\n @if (modalUrl()) {\r\n <div class=\"iq-link-overlay\" (click)=\"closeLinkModal()\">\r\n <div class=\"iq-link-modal\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"iq-link-header\">\r\n @if (showHomeBtn()) {\r\n <button class=\"iq-header-btn iq-back-btn\" (click)=\"iframeGoHome()\" title=\"Volver al inicio\">🏠</button>\r\n }\r\n <span class=\"iq-link-title\" [title]=\"modalUrl()!\">{{ modalUrl() }}</span>\r\n <div class=\"iq-link-actions\">\r\n <a [href]=\"modalUrl()!\" target=\"_blank\" rel=\"noopener\" class=\"iq-header-btn\" title=\"Abrir en nueva pestaña\">↗</a>\r\n <button class=\"iq-header-btn\" (click)=\"closeLinkModal()\">✕</button>\r\n </div>\r\n </div>\r\n <div class=\"iq-iframe-wrapper\">\r\n @if (isModalImage()) {\r\n <img [src]=\"modalUrl()!\" class=\"iq-modal-img\" alt=\"Imagen\" />\r\n } @else {\r\n @if (modalLoading()) {\r\n <div class=\"iq-iframe-loader\">\r\n <div class=\"iq-spinner\"></div>\r\n <span class=\"iq-loader-text\">Cargando...</span>\r\n </div>\r\n }\r\n <iframe #linkIframe [src]=\"sanitizedModalUrl()\" class=\"iq-link-iframe\"\r\n [class.iq-iframe-hidden]=\"modalLoading()\"\r\n (load)=\"onIframeLoaded()\"></iframe>\r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n\r\n </div><!-- /iq-theme-host -->\r\n `,\r\n styles: [`\r\n /* ========= CSS Custom Properties (overridable by host) ========= */\r\n :host {\r\n --iq-primary: #1a3a5c;\r\n --iq-primary-light: #2a5a8c;\r\n --iq-accent: #00d4aa;\r\n --iq-accent-light: #33e0be;\r\n --iq-bg: #1e1e2f;\r\n --iq-bg-card: #252538;\r\n --iq-bg-tertiary: #35354a;\r\n --iq-text: #ffffff;\r\n --iq-text-secondary: #a0a0b0;\r\n --iq-text-muted: #6c6c7c;\r\n --iq-border: #3a3a4d;\r\n --iq-radius: 12px;\r\n --iq-bubble-size: 56px;\r\n --iq-panel-width: 400px;\r\n --iq-panel-height: 520px;\r\n --iq-z: 10000;\r\n --iq-font: 'Inter', 'Roboto', -apple-system, BlinkMacSystemFont, sans-serif;\r\n font-family: var(--iq-font);\r\n }\r\n\r\n /* ========= Bubble ========= */\r\n .iq-bubble {\r\n position: fixed;\r\n bottom: 24px;\r\n right: 24px;\r\n z-index: var(--iq-z);\r\n width: var(--iq-bubble-size);\r\n height: var(--iq-bubble-size);\r\n border-radius: 50%;\r\n border: none;\r\n background: linear-gradient(135deg, var(--iq-accent), var(--iq-accent-light));\r\n color: var(--iq-bg);\r\n font-size: 1.6rem;\r\n cursor: pointer;\r\n box-shadow: 0 4px 16px rgba(0, 212, 170, 0.4);\r\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n }\r\n .iq-bubble:hover {\r\n transform: scale(1.1);\r\n box-shadow: 0 6px 24px rgba(0, 212, 170, 0.5);\r\n }\r\n .iq-bubble .iq-bubble-icon {\r\n font-size: 1.5rem;\r\n pointer-events: none;\r\n }\r\n\r\n .iq-bubble-img {\r\n width: 60%; height: 60%;\r\n object-fit: contain; border-radius: 50%;\r\n pointer-events: none;\r\n }\r\n\r\n .iq-bubble-svg {\r\n width: 60%; height: 60%;\r\n display: flex; align-items: center; justify-content: center;\r\n pointer-events: none;\r\n }\r\n .iq-bubble-svg :deep(svg) { width: 100%; height: 100%; }\r\n\r\n .iq-bubble.iq-open {\r\n background: var(--iq-bg-tertiary);\r\n color: var(--iq-text);\r\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\r\n font-size: 1.2rem;\r\n }\r\n .iq-bubble.iq-bottom-left {\r\n right: auto;\r\n left: 24px;\r\n }\r\n .iq-bubble-icon { line-height: 1; }\r\n\r\n /* ========= Panel ========= */\r\n .iq-panel {\r\n position: fixed;\r\n bottom: 92px;\r\n right: 24px;\r\n z-index: var(--iq-z);\r\n width: var(--iq-panel-width);\r\n height: var(--iq-panel-height);\r\n background: var(--iq-bg);\r\n border: 1px solid var(--iq-border);\r\n border-radius: var(--iq-radius);\r\n display: flex;\r\n flex-direction: column;\r\n overflow: hidden;\r\n box-shadow: 0 12px 40px rgba(0,0,0,0.5);\r\n animation: iq-slide-up 0.3s cubic-bezier(0.4, 0, 0.2, 1);\r\n }\r\n .iq-panel.iq-bottom-left {\r\n right: auto;\r\n left: 24px;\r\n }\r\n /* ========= Expanded / Fullscreen ========= */\r\n .iq-panel.iq-expanded {\r\n width: 100vw !important;\r\n height: 100vh !important;\r\n top: 0 !important;\r\n left: 0 !important;\r\n right: 0 !important;\r\n bottom: 0 !important;\r\n border: none;\r\n border-radius: 0;\r\n overflow: clip;\r\n z-index: calc(var(--iq-z) + 5);\r\n animation: iq-expand 0.3s cubic-bezier(0.4, 0, 0.2, 1);\r\n }\r\n .iq-btn-expand {\r\n font-size: 1.1rem !important;\r\n }\r\n @keyframes iq-expand {\r\n from { opacity: 0.8; transform: scale(0.95); }\r\n to { opacity: 1; transform: scale(1); }\r\n }\r\n @keyframes iq-slide-up {\r\n from { opacity: 0; transform: translateY(16px) scale(0.96); }\r\n to { opacity: 1; transform: translateY(0) scale(1); }\r\n }\r\n\r\n /* ========= Header ========= */\r\n .iq-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 12px 16px;\r\n border-bottom: 1px solid var(--iq-border);\r\n background: var(--iq-bg-card);\r\n }\r\n .iq-header-title {\r\n font-weight: 600;\r\n font-size: 0.95rem;\r\n color: var(--iq-text);\r\n }\r\n .iq-header-actions {\r\n display: flex;\r\n gap: 4px;\r\n }\r\n .iq-header-btn {\r\n background: none;\r\n border: none;\r\n color: var(--iq-text-muted);\r\n cursor: pointer;\r\n font-size: 1rem;\r\n padding: 4px 6px;\r\n border-radius: 4px;\r\n transition: all 0.15s;\r\n }\r\n .iq-header-btn:hover {\r\n color: var(--iq-text);\r\n background: rgba(255,255,255,0.08);\r\n }\r\n\r\n /* ========= Debug Menu ========= */\r\n .iq-debug-menu-wrapper {\r\n position: relative;\r\n }\r\n .iq-debug-dropdown {\r\n position: absolute;\r\n top: 100%;\r\n right: 0;\r\n margin-top: 4px;\r\n min-width: 180px;\r\n background: var(--iq-bg-card);\r\n border: 1px solid var(--iq-border);\r\n border-radius: 8px;\r\n box-shadow: 0 8px 24px rgba(0,0,0,0.4);\r\n z-index: calc(var(--iq-z) + 10);\r\n padding: 4px;\r\n animation: iq-dropdown-in 0.15s ease-out;\r\n }\r\n @keyframes iq-dropdown-in {\r\n from { opacity: 0; transform: translateY(-4px) scale(0.95); }\r\n to { opacity: 1; transform: translateY(0) scale(1); }\r\n }\r\n .iq-debug-option {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n width: 100%;\r\n padding: 8px 12px;\r\n background: none;\r\n border: none;\r\n color: var(--iq-text);\r\n font-size: 0.85rem;\r\n cursor: pointer;\r\n border-radius: 6px;\r\n transition: background 0.15s;\r\n text-align: left;\r\n }\r\n .iq-debug-option:hover {\r\n background: rgba(255,255,255,0.08);\r\n }\r\n\r\n /* ========= Auth Error ========= */\r\n .iq-auth-error {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 10px 16px;\r\n background: rgba(220, 53, 69, 0.15);\r\n color: #ff6b7a;\r\n font-size: 0.8rem;\r\n border-bottom: 1px solid rgba(220, 53, 69, 0.25);\r\n }\r\n\r\n /* ========= Messages ========= */\r\n .iq-messages {\r\n flex: 1;\r\n min-height: 0;\r\n overflow-y: auto;\r\n padding: 12px;\r\n display: flex;\r\n flex-direction: column;\r\n gap: 10px;\r\n }\r\n\r\n .iq-empty {\r\n flex: 1;\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: center;\r\n text-align: center;\r\n color: var(--iq-text-secondary);\r\n }\r\n .iq-empty-icon { font-size: 3rem; margin-bottom: 8px; display: flex; align-items: center; justify-content: center; }\r\n .iq-empty-img { width: 48px; height: 48px; object-fit: contain; border-radius: 8px; }\r\n .iq-empty-svg { width: 48px; height: 48px; display: flex; align-items: center; justify-content: center; }\r\n .iq-empty-svg :deep(svg) { width: 100%; height: 100%; }\r\n .iq-empty p { font-size: 0.95rem; margin: 2px 0; }\r\n .iq-text-muted { color: var(--iq-text-muted) !important; font-size: 0.8rem !important; }\r\n\r\n .iq-msg { display: flex; flex-direction: column; max-width: 85%; }\r\n .iq-msg-user { align-self: flex-end; }\r\n .iq-msg-bot { align-self: flex-start; max-width: 100%; }\r\n\r\n .iq-msg-user .iq-msg-content {\r\n background: linear-gradient(135deg, var(--iq-primary), var(--iq-primary-light));\r\n border-radius: 12px 12px 0 12px;\r\n }\r\n .iq-msg-bot .iq-msg-content {\r\n background: var(--iq-bg-tertiary);\r\n border-radius: 12px 12px 12px 0;\r\n }\r\n .iq-msg-content {\r\n padding: 10px 14px;\r\n color: var(--iq-text);\r\n font-size: 0.85rem;\r\n line-height: 1.45;\r\n }\r\n .iq-msg-content p { margin: 0; white-space: pre-wrap; }\r\n .iq-msg-time {\r\n display: block;\r\n margin-top: 4px;\r\n font-size: 0.65rem;\r\n color: rgba(255,255,255,0.5);\r\n }\r\n\r\n /* Markdown rendered content */\r\n .iq-md { line-height: 1.5; overflow-x: auto; max-width: 100%; }\r\n .iq-md :first-child { margin-top: 0; }\r\n .iq-md :last-child { margin-bottom: 0; }\r\n .iq-md p { margin: 0 0 0.4em 0; }\r\n .iq-md p:last-child { margin-bottom: 0; }\r\n .iq-md strong { color: var(--iq-accent); }\r\n .iq-md ul, .iq-md ol { margin: 0.3em 0; padding-left: 1.2em; }\r\n .iq-md li { margin: 0.15em 0; }\r\n .iq-md code {\r\n background: rgba(0,0,0,0.3);\r\n padding: 0.15em 0.4em;\r\n border-radius: 3px;\r\n font-size: 0.82em;\r\n }\r\n .iq-md pre {\r\n background: rgba(0,0,0,0.3);\r\n padding: 0.8em;\r\n border-radius: 6px;\r\n overflow-x: auto;\r\n font-size: 0.78em;\r\n margin: 0.4em 0;\r\n }\r\n .iq-md pre code { background: none; padding: 0; }\r\n .iq-md table {\r\n width: max-content; min-width: 100%;\r\n border-collapse: separate; border-spacing: 0;\r\n margin: 0.5em 0; font-size: 0.75rem;\r\n border-radius: 6px; overflow: hidden;\r\n }\r\n .iq-md thead th {\r\n background: rgba(99,102,241,0.18); color: #a5b4fc;\r\n font-weight: 600; text-align: left;\r\n padding: 0.5em 0.8em; border-bottom: 2px solid rgba(99,102,241,0.3);\r\n white-space: nowrap; font-size: 0.7rem;\r\n text-transform: uppercase; letter-spacing: 0.05em;\r\n }\r\n .iq-md tbody td {\r\n padding: 0.4em 0.8em; border-bottom: 1px solid rgba(255,255,255,0.06);\r\n white-space: nowrap; color: var(--iq-text-secondary);\r\n }\r\n .iq-md tbody tr:hover { background: rgba(99,102,241,0.08); }\r\n\r\n /* Inline images in bot messages – small thumbnails, click to enlarge */\r\n .iq-md img {\r\n max-height: 80px; max-width: 120px; object-fit: cover;\r\n border-radius: 8px; margin: 6px 4px 6px 0;\r\n display: inline-block; vertical-align: middle;\r\n border: 1px solid rgba(255,255,255,0.15);\r\n box-shadow: 0 1px 4px rgba(0,0,0,0.25);\r\n cursor: pointer; transition: transform 0.15s, box-shadow 0.15s;\r\n }\r\n .iq-md img:hover {\r\n transform: scale(1.05);\r\n box-shadow: 0 3px 12px rgba(99,102,241,0.35);\r\n border-color: var(--iq-accent);\r\n }\r\n .iq-md img[alt*=\"logo\"], .iq-md img[alt*=\"marca\"] {\r\n max-height: 28px; max-width: 90px; object-fit: contain;\r\n border: none; box-shadow: none; border-radius: 4px;\r\n background: rgba(255,255,255,0.9); padding: 2px 6px;\r\n }\r\n /* Trace button */\r\n .iq-btn-trace {\r\n align-self: flex-start; margin-top: 4px;\r\n background: transparent; border: 1px solid var(--iq-border);\r\n color: var(--iq-text-secondary); font-size: 0.7rem;\r\n padding: 3px 8px; border-radius: 4px; cursor: pointer;\r\n transition: all 0.15s;\r\n }\r\n .iq-btn-trace:hover { border-color: var(--iq-accent); color: var(--iq-accent); }\r\n\r\n /* Pipeline loading indicator */\r\n .iq-pipeline {\r\n display: flex; align-items: center; gap: 8px;\r\n animation: iq-fade-in 0.3s ease-out;\r\n }\r\n .iq-dot {\r\n width: 8px; height: 8px; border-radius: 50%;\r\n background: var(--iq-accent);\r\n animation: iq-pulse 1s ease-in-out infinite;\r\n }\r\n .iq-pipeline-text {\r\n font-size: 0.8rem; color: var(--iq-text-muted); font-style: italic;\r\n flex: 1;\r\n }\r\n .iq-cancel-btn {\r\n background: transparent; border: 1px solid var(--iq-border);\r\n color: var(--iq-text-muted); font-size: 0.7rem;\r\n padding: 2px 8px; border-radius: 4px; cursor: pointer;\r\n transition: all 0.15s; flex-shrink: 0;\r\n }\r\n .iq-cancel-btn:hover {\r\n border-color: #ff6b6b; color: #ff6b6b; background: rgba(255, 107, 107, 0.1);\r\n }\r\n @keyframes iq-pulse {\r\n 0%, 100% { opacity: 1; transform: scale(1); }\r\n 50% { opacity: 0.4; transform: scale(0.7); }\r\n }\r\n @keyframes iq-fade-in {\r\n from { opacity: 0; transform: translateX(-6px); }\r\n to { opacity: 1; transform: translateX(0); }\r\n }\r\n\r\n /* ========= Input Bar ========= */\r\n .iq-input-bar {\r\n display: flex; gap: 8px;\r\n padding: 10px 12px;\r\n border-top: 1px solid var(--iq-border);\r\n background: var(--iq-bg-card);\r\n }\r\n .iq-input-bar input {\r\n flex: 1; padding: 8px 12px;\r\n background: var(--iq-bg-tertiary);\r\n border: 1px solid var(--iq-border);\r\n border-radius: 8px;\r\n color: var(--iq-text);\r\n font-size: 0.85rem;\r\n font-family: var(--iq-font);\r\n outline: none;\r\n transition: border-color 0.15s;\r\n }\r\n .iq-input-bar input:focus { border-color: var(--iq-accent); }\r\n .iq-input-bar input::placeholder { color: var(--iq-text-muted); }\r\n .iq-input-bar input:disabled { opacity: 0.5; }\r\n .iq-btn-send {\r\n width: 36px; height: 36px;\r\n border-radius: 8px; border: none;\r\n background: linear-gradient(135deg, var(--iq-accent), var(--iq-accent-light));\r\n color: var(--iq-bg); font-size: 1rem;\r\n cursor: pointer; transition: all 0.2s;\r\n display: flex; align-items: center; justify-content: center;\r\n }\r\n .iq-btn-send:hover:not(:disabled) { box-shadow: 0 0 12px rgba(0,212,170,0.4); transform: translateY(-1px); }\r\n .iq-btn-send:disabled { opacity: 0.4; cursor: not-allowed; }\r\n\r\n /* ========= Trace Modal ========= */\r\n .iq-trace-overlay {\r\n position: fixed; inset: 0;\r\n z-index: calc(var(--iq-z) + 10);\r\n background: rgba(0,0,0,0.6);\r\n display: flex; align-items: center; justify-content: center;\r\n animation: iq-fade-in 0.2s ease-out;\r\n }\r\n .iq-trace-modal {\r\n width: 90%; max-width: 520px; max-height: 80vh;\r\n background: var(--iq-bg); border: 1px solid var(--iq-border);\r\n border-radius: var(--iq-radius);\r\n display: flex; flex-direction: column; overflow: hidden;\r\n box-shadow: 0 20px 50px rgba(0,0,0,0.6);\r\n }\r\n .iq-trace-header {\r\n display: flex; align-items: center; justify-content: space-between;\r\n padding: 14px 16px; border-bottom: 1px solid var(--iq-border);\r\n }\r\n .iq-trace-header h3 { margin: 0; font-size: 0.95rem; color: var(--iq-text); }\r\n .iq-trace-body {\r\n flex: 1; overflow-y: auto; padding: 16px;\r\n display: flex; flex-direction: column; gap: 12px;\r\n }\r\n .iq-trace-item label {\r\n display: block; font-size: 0.7rem; color: var(--iq-text-muted);\r\n margin-bottom: 4px; text-transform: uppercase; letter-spacing: 0.05em;\r\n }\r\n .iq-trace-item code {\r\n display: block; padding: 8px;\r\n background: var(--iq-bg-tertiary); border-radius: 4px;\r\n font-family: monospace; font-size: 0.8rem; color: var(--iq-accent);\r\n word-break: break-all;\r\n }\r\n .iq-trace-item pre {\r\n margin: 0; padding: 8px;\r\n background: var(--iq-bg-tertiary); border-radius: 4px;\r\n font-family: monospace; font-size: 0.7rem;\r\n overflow-x: auto; max-height: 180px; color: var(--iq-text-secondary);\r\n }\r\n .iq-cache-hit { background: rgba(16,185,129,0.15) !important; color: #10b981 !important; }\r\n .iq-query-code { color: var(--iq-accent) !important; }\r\n\r\n /* ========= Link Modal ========= */\r\n .iq-link-overlay {\r\n position: fixed; inset: 0;\r\n z-index: calc(var(--iq-z) + 20);\r\n background: rgba(0,0,0,0.7);\r\n display: flex; align-items: center; justify-content: center;\r\n animation: iq-fade-in 0.2s ease-out;\r\n backdrop-filter: blur(4px);\r\n }\r\n .iq-link-modal {\r\n width: 94vw; height: 92vh;\r\n background: var(--iq-bg); border: 1px solid var(--iq-border);\r\n border-radius: var(--iq-radius);\r\n display: flex; flex-direction: column; overflow: hidden;\r\n box-shadow: 0 24px 60px rgba(0,0,0,0.7);\r\n animation: iq-expand 0.25s cubic-bezier(0.4, 0, 0.2, 1);\r\n }\r\n .iq-link-header {\r\n display: flex; align-items: center; justify-content: space-between;\r\n padding: 10px 16px; border-bottom: 1px solid var(--iq-border);\r\n background: var(--iq-bg-card); gap: 12px; min-height: 44px;\r\n }\r\n .iq-link-title {\r\n flex: 1; font-size: 0.78rem; color: var(--iq-text-secondary);\r\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\r\n font-family: monospace;\r\n }\r\n .iq-link-actions {\r\n display: flex; gap: 4px; flex-shrink: 0;\r\n }\r\n .iq-link-actions a {\r\n text-decoration: none;\r\n }\r\n .iq-back-btn {\r\n flex-shrink: 0; font-size: 1.1rem;\r\n transition: transform 0.15s ease;\r\n }\r\n .iq-back-btn:hover {\r\n transform: translateX(-2px);\r\n }\r\n .iq-iframe-wrapper {\r\n flex: 1; position: relative; overflow: hidden;\r\n }\r\n .iq-link-iframe {\r\n width: 100%; height: 100%; border: none;\r\n background: #fff;\r\n transition: opacity 0.3s ease;\r\n }\r\n .iq-iframe-hidden {\r\n opacity: 0;\r\n }\r\n .iq-modal-img {\r\n width: 100%; height: 100%;\r\n object-fit: contain;\r\n background: #1a1a2e;\r\n }\r\n .iq-iframe-loader {\r\n position: absolute; inset: 0;\r\n display: flex; flex-direction: column;\r\n align-items: center; justify-content: center;\r\n background: var(--iq-bg);\r\n gap: 16px; z-index: 2;\r\n }\r\n .iq-spinner {\r\n width: 40px; height: 40px;\r\n border: 3px solid var(--iq-border);\r\n border-top-color: var(--iq-accent);\r\n border-radius: 50%;\r\n animation: iq-spin 0.8s linear infinite;\r\n }\r\n .iq-loader-text {\r\n font-size: 0.85rem; color: var(--iq-text-secondary);\r\n font-weight: 500;\r\n }\r\n @keyframes iq-spin {\r\n to { transform: rotate(360deg); }\r\n }\r\n\r\n /* ========= Link Modal — markdown link styling ========= */\r\n .iq-md a {\r\n color: var(--iq-accent); text-decoration: underline;\r\n cursor: pointer; transition: color 0.15s;\r\n }\r\n .iq-md a:hover {\r\n color: var(--iq-accent-light);\r\n }\r\n\r\n @media (max-width: 480px) {\r\n .iq-link-modal {\r\n width: 100vw; height: 100dvh;\r\n border-radius: 0;\r\n }\r\n .iq-link-header { padding: 8px 12px; }\r\n .iq-link-title { font-size: 0.7rem; }\r\n }\r\n\r\n /* ========= Scrollbar ========= */\r\n .iq-messages::-webkit-scrollbar { width: 5px; }\r\n .iq-messages::-webkit-scrollbar-track { background: transparent; }\r\n .iq-messages::-webkit-scrollbar-thumb { background: var(--iq-border); border-radius: 4px; }\r\n .iq-trace-body::-webkit-scrollbar { width: 5px; }\r\n .iq-trace-body::-webkit-scrollbar-track { background: transparent; }\r\n .iq-trace-body::-webkit-scrollbar-thumb { background: var(--iq-border); border-radius: 4px; }\r\n /* Wider scrollbar in fullscreen for easier grabbing */\r\n .iq-expanded .iq-messages::-webkit-scrollbar { width: 8px; }\r\n .iq-expanded .iq-messages { scrollbar-gutter: stable; }\r\n\r\n /* ========= Mobile Small Screens ========= */\r\n @media (max-width: 480px) {\r\n .iq-bubble {\r\n bottom: 16px;\r\n right: 16px;\r\n width: 48px;\r\n height: 48px;\r\n font-size: 1.3rem;\r\n }\r\n .iq-bubble.iq-bottom-left {\r\n left: 16px;\r\n }\r\n .iq-bubble .iq-bubble-icon { font-size: 1.2rem; }\r\n\r\n .iq-panel {\r\n right: 8px;\r\n left: 8px;\r\n bottom: 72px;\r\n width: auto !important;\r\n max-width: calc(100vw - 16px);\r\n height: calc(100dvh - 90px);\r\n max-height: calc(100dvh - 90px);\r\n }\r\n .iq-panel.iq-bottom-left {\r\n left: 8px;\r\n right: 8px;\r\n }\r\n .iq-panel.iq-expanded {\r\n top: 0 !important;\r\n left: 0 !important;\r\n right: 0 !important;\r\n bottom: 0 !important;\r\n width: 100vw !important;\r\n height: 100dvh !important;\r\n max-height: 100dvh !important;\r\n max-width: 100vw !important;\r\n border-radius: 0;\r\n }\r\n\r\n .iq-header {\r\n padding: 10px 12px;\r\n }\r\n .iq-header-title { font-size: 0.85rem; }\r\n .iq-header-btn { padding: 6px 8px; min-width: 32px; min-height: 32px; }\r\n\r\n .iq-messages { padding: 8px; gap: 8px; }\r\n\r\n .iq-msg { max-width: 92%; }\r\n .iq-msg-bot { max-width: 100%; }\r\n .iq-msg-content { padding: 8px 10px; font-size: 0.8rem; }\r\n\r\n .iq-md { overflow-x: auto; -webkit-overflow-scrolling: touch; }\r\n .iq-md table { font-size: 0.65rem; min-width: unset; }\r\n .iq-md thead th { padding: 0.35em 0.5em; font-size: 0.6rem; }\r\n .iq-md tbody td { padding: 0.3em 0.5em; font-size: 0.65rem; }\r\n\r\n .iq-empty-icon { font-size: 2.5rem; }\r\n .iq-empty p { font-size: 0.85rem; }\r\n\r\n .iq-input-bar { padding: 8px 10px; gap: 6px; }\r\n .iq-input-bar input { font-size: 16px; padding: 8px 10px; }\r\n .iq-btn-send { width: 38px; height: 38px; flex-shrink: 0; }\r\n\r\n .iq-trace-modal {\r\n width: calc(100vw - 24px);\r\n max-height: 90dvh;\r\n }\r\n .iq-trace-header { padding: 12px; }\r\n .iq-trace-header h3 { font-size: 0.85rem; }\r\n .iq-trace-body { padding: 12px; }\r\n .iq-trace-item pre { font-size: 0.65rem; max-height: 140px; }\r\n }\r\n\r\n /* ========= Landscape Mobile — fit floating panel ========= */\r\n @media (max-height: 500px) and (orientation: landscape) {\r\n .iq-bubble {\r\n bottom: 8px;\r\n right: 8px;\r\n width: 44px;\r\n height: 44px;\r\n font-size: 1.1rem;\r\n }\r\n .iq-bubble.iq-bottom-left { left: 8px; }\r\n\r\n .iq-panel {\r\n right: 60px;\r\n left: 8px;\r\n bottom: 8px;\r\n top: 8px;\r\n width: auto !important;\r\n max-width: calc(100vw - 76px);\r\n height: auto !important;\r\n max-height: calc(100dvh - 16px);\r\n border-radius: var(--iq-radius);\r\n }\r\n .iq-panel.iq-bottom-left {\r\n left: 60px;\r\n right: 8px;\r\n }\r\n .iq-panel.iq-expanded {\r\n top: 0 !important;\r\n left: 0 !important;\r\n right: 0 !important;\r\n bottom: 0 !important;\r\n width: 100vw !important;\r\n height: 100dvh !important;\r\n max-height: 100dvh !important;\r\n max-width: 100vw !important;\r\n border-radius: 0;\r\n }\r\n\r\n .iq-header { padding: 6px 12px; }\r\n .iq-header-title { font-size: 0.8rem; }\r\n .iq-messages { padding: 6px 10px; gap: 6px; }\r\n .iq-empty-icon { font-size: 1.8rem; margin-bottom: 4px; }\r\n .iq-empty p { font-size: 0.78rem; margin: 1px 0; }\r\n .iq-input-bar { padding: 6px 10px; }\r\n .iq-input-bar input { font-size: 16px; padding: 6px 10px; }\r\n .iq-btn-send { width: 32px; height: 32px; }\r\n }\r\n `]\r\n})\r\nexport class IntelligentChatPluginComponent implements AfterViewChecked, OnChanges, OnInit, OnDestroy {\r\n @ViewChild('chatContainer') private chatContainer!: ElementRef;\r\n\r\n @Input() config!: IntelligentChatConfig;\r\n\r\n private chatService = inject(IntelligentChatService);\r\n private hostEl = inject(ElementRef);\r\n\r\n // State\r\n isOpen = signal(false);\r\n isExpanded = signal(false);\r\n messages = signal<ChatMessage[]>([]);\r\n isLoading = signal(false);\r\n selectedTrace = signal<any>(null);\r\n authError = signal<string | null>(null);\r\n modalUrl = signal<string | null>(null);\r\n isModalImage = computed(() => {\r\n const url = this.modalUrl();\r\n if (!url) return false;\r\n return /\\.(jpg|jpeg|png|gif|webp|svg|bmp)(\\?.*)?$/i.test(url);\r\n });\r\n modalLoading = signal(false);\r\n showHomeBtn = signal(false);\r\n private originalModalUrl = '';\r\n private modalReadyForNav = false;\r\n private navReadyTimer: any = null;\r\n inputText = '';\r\n private currentSubscription?: Subscription;\r\n\r\n // Pipeline step (driven by real SSE events from backend)\r\n pipelineStep = '';\r\n\r\n private messageId = 0;\r\n private shouldScroll = false;\r\n\r\n // ─── Markdown Cache (avoids re-parsing on every CD cycle) ────\r\n private mdCache = new Map<string, SafeHtml>();\r\n // ─── Debounce progress updates to avoid CD storms ────\r\n private pendingPipelineStep: string | null = null;\r\n private rafId: number | null = null;\r\n\r\n // ─── Session Persistence ──────────────────────────\r\n private readonly STORAGE_PREFIX = 'iq_chat_session_';\r\n private sessionKey = '';\r\n private storageListener = (e: StorageEvent) => this.onStorageChange(e);\r\n\r\n // ─── Debug Menu ──────────────────────────────────\r\n showDebugMenu = signal(false);\r\n private titleTouchTimer: any = null;\r\n private shakeHandler: ((e: DeviceMotionEvent) => void) | null = null;\r\n private lastShakeTime = 0;\r\n\r\n /** Resolved config with defaults applied */\r\n private sanitizer = inject(DomSanitizer);\r\n\r\n resolvedConfig = signal<Required<IntelligentChatConfig>>({\r\n apiUrl: '',\r\n systemId: '',\r\n token: '',\r\n useIntelligentQuery: true,\r\n skipPatterns: true,\r\n baseContext: '',\r\n showTrace: false,\r\n showPipelineSteps: true,\r\n preferTableFormat: true,\r\n title: 'Maquito Chat',\r\n placeholder: 'Escribe tu consulta aquí...',\r\n welcomeTitle: '¡Hola! Soy Maquito.',\r\n welcomeSubtitle: 'Escribe tu consulta para comenzar.',\r\n position: 'bottom-right',\r\n bubbleIcon: '🤖',\r\n bubbleIconType: 'emoji',\r\n bubbleImageUrl: '',\r\n bubbleSvg: '',\r\n themeClass: '',\r\n stickyBubble: true,\r\n allowExpand: false,\r\n theme: {},\r\n userName: '',\r\n personality: '',\r\n enableDebugMenu: false,\r\n debugKeyCombo: 'ctrl+shift+d'\r\n });\r\n\r\n /** Map theme object → CSS variable overrides */\r\n themeStyles = computed(() => {\r\n const t = this.resolvedConfig().theme || {};\r\n const map: Record<string, string> = {};\r\n const pairs: [keyof PluginTheme, string][] = [\r\n ['primary', '--iq-primary'], ['primaryLight', '--iq-primary-light'],\r\n ['accent', '--iq-accent'], ['accentLight', '--iq-accent-light'],\r\n ['bg', '--iq-bg'], ['bgCard', '--iq-bg-card'], ['bgTertiary', '--iq-bg-tertiary'],\r\n ['text', '--iq-text'], ['textSecondary', '--iq-text-secondary'],\r\n ['textMuted', '--iq-text-muted'], ['border', '--iq-border']\r\n ];\r\n for (const [key, cssVar] of pairs) {\r\n if (t[key]) map[cssVar] = t[key]!;\r\n }\r\n return map;\r\n });\r\n\r\n /** Sanitised SVG HTML for bubble */\r\n sanitizedBubbleSvg = computed<SafeHtml>(() => {\r\n const raw = this.resolvedConfig().bubbleSvg || '';\r\n return this.sanitizer.bypassSecurityTrustHtml(raw);\r\n });\r\n\r\n /** Sanitised URL for the link modal iframe */\r\n sanitizedModalUrl = computed<SafeResourceUrl>(() => {\r\n const url = this.modalUrl() || '';\r\n return this.sanitizer.bypassSecurityTrustResourceUrl(url);\r\n });\r\n\r\n ngOnInit(): void {\r\n window.addEventListener('storage', this.storageListener);\r\n // Self-heal: always reset transient state on init to prevent\r\n // corrupted sessions from freezing the page\r\n this.isLoading.set(false);\r\n this.pipelineStep = '';\r\n this.isExpanded.set(false);\r\n this.setHostScrollLock(false);\r\n this.currentSubscription?.unsubscribe();\r\n this.currentSubscription = undefined;\r\n // Setup shake detection for mobile debug log download\r\n this.setupShakeDetection();\r\n }\r\n\r\n ngOnDestroy(): void {\r\n window.removeEventListener('storage', this.storageListener);\r\n this.currentSubscription?.unsubscribe();\r\n this.teardownShakeDetection();\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if (changes['config'] && this.config) {\r\n this.resolvedConfig.set({\r\n apiUrl: this.config.apiUrl || '',\r\n systemId: this.config.systemId || '',\r\n token: this.config.token || '',\r\n useIntelligentQuery: this.config.useIntelligentQuery ?? true,\r\n skipPatterns: this.config.skipPatterns ?? true,\r\n baseContext: this.config.baseContext || '',\r\n showTrace: this.config.showTrace ?? false,\r\n showPipelineSteps: this.config.showPipelineSteps ?? true,\r\n preferTableFormat: this.config.preferTableFormat ?? true,\r\n title: this.config.title || 'Maquito Chat',\r\n placeholder: this.config.placeholder || 'Escribe tu consulta aquí...',\r\n welcomeTitle: this.config.welcomeTitle || '¡Hola! Soy Maquito.',\r\n welcomeSubtitle: this.config.welcomeSubtitle || 'Escribe tu consulta para comenzar.',\r\n position: this.config.position || 'bottom-right',\r\n bubbleIcon: this.config.bubbleIcon || '🤖',\r\n bubbleIconType: this.config.bubbleIconType || 'emoji',\r\n bubbleImageUrl: this.config.bubbleImageUrl || '',\r\n bubbleSvg: this.config.bubbleSvg || '',\r\n themeClass: this.config.themeClass || '',\r\n stickyBubble: this.config.stickyBubble ?? true,\r\n allowExpand: this.config.allowExpand ?? false,\r\n theme: this.config.theme || {},\r\n userName: this.config.userName || '',\r\n personality: this.config.personality || '',\r\n enableDebugMenu: this.config.enableDebugMenu ?? false,\r\n debugKeyCombo: this.config.debugKeyCombo || 'ctrl+shift+d'\r\n });\r\n // Cancel any in-flight query when config changes\r\n this.cancelQuery();\r\n // Rebuild session key when config changes\r\n const newKey = this.buildSessionKey();\r\n if (newKey !== this.sessionKey) {\r\n this.sessionKey = newKey;\r\n this.loadSession();\r\n }\r\n // Clear auth error when config changes (user may be testing a new token)\r\n this.authError.set(null);\r\n }\r\n }\r\n\r\n ngAfterViewChecked(): void {\r\n if (this.shouldScroll) {\r\n this.scrollToBottom();\r\n this.shouldScroll = false;\r\n }\r\n }\r\n\r\n toggleChat(): void {\r\n this.isOpen.update(v => !v);\r\n if (!this.isOpen()) {\r\n this.isExpanded.set(false);\r\n this.setHostScrollLock(false);\r\n this.cancelQuery();\r\n }\r\n if (this.isOpen()) this.shouldScroll = true;\r\n }\r\n\r\n toggleExpand(): void {\r\n this.isExpanded.update(v => !v);\r\n this.setHostScrollLock(this.isExpanded());\r\n }\r\n\r\n /** Lock/unlock the host page scroll to prevent its scrollbar from overlapping ours */\r\n private setHostScrollLock(lock: boolean): void {\r\n document.body.style.overflow = lock ? 'hidden' : '';\r\n // Also target common host containers\r\n const mc = document.querySelector('.main-container') as HTMLElement;\r\n if (mc) mc.style.overflow = lock ? 'hidden' : '';\r\n }\r\n\r\n sendMessage(): void {\r\n const text = this.inputText.trim();\r\n if (!text) return;\r\n\r\n const cfg = this.resolvedConfig();\r\n\r\n // Validate required config\r\n if (!cfg.token) {\r\n this.authError.set('Token no configurado. El plugin requiere un token técnico válido.');\r\n return;\r\n }\r\n if (!cfg.apiUrl) {\r\n this.authError.set('API URL no configurada.');\r\n return;\r\n }\r\n\r\n this.authError.set(null);\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text,\r\n sender: 'user',\r\n timestamp: new Date()\r\n }]);\r\n this.saveSession();\r\n this.shouldScroll = true;\r\n this.inputText = '';\r\n this.isLoading.set(true);\r\n\r\n if (cfg.showPipelineSteps) {\r\n this.pipelineStep = '⏳ Procesando...';\r\n } else {\r\n this.pipelineStep = '⏳ Procesando...';\r\n }\r\n\r\n if (cfg.useIntelligentQuery && cfg.systemId) {\r\n // Build conversation history from previous messages (last 6 pairs)\r\n const history = this.messages()\r\n .filter(m => m.sender === 'user' || m.sender === 'bot')\r\n .slice(-12)\r\n .map(msg => ({\r\n role: msg.sender === 'user' ? 'user' : 'assistant',\r\n content: msg.text\r\n }));\r\n\r\n const ctx = cfg.baseContext?.trim() || undefined;\r\n\r\n if (cfg.showPipelineSteps) {\r\n // Use SSE streaming for real-time pipeline progress\r\n this.currentSubscription = this.chatService.executeIntelligentQueryStream(\r\n cfg.apiUrl, cfg.token, cfg.systemId, text, history, ctx, cfg.skipPatterns, cfg.preferTableFormat,\r\n cfg.userName || undefined, cfg.personality || undefined\r\n ).subscribe({\r\n next: (event) => {\r\n if (event.type === 'progress') {\r\n // Debounce progress updates — queue for next animation frame\r\n // to avoid triggering Angular CD on every SSE chunk\r\n this.pendingPipelineStep = event.message || '';\r\n if (this.rafId === null) {\r\n this.rafId = requestAnimationFrame(() => {\r\n this.rafId = null;\r\n if (this.pendingPipelineStep !== null) {\r\n this.pipelineStep = this.pendingPipelineStep;\r\n this.pendingPipelineStep = null;\r\n }\r\n });\r\n }\r\n return;\r\n } else if (event.type === 'result') {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n const response = event.data;\r\n const responseText = response.success\r\n ? (response.response || 'Consulta ejecutada correctamente')\r\n : (response.error || 'Error en la consulta');\r\n\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text: responseText,\r\n sender: 'bot',\r\n timestamp: new Date(),\r\n traceData: {\r\n traceId: response.traceId,\r\n fromCache: response.fromCache,\r\n fromContext: response.fromContext,\r\n query: response.query,\r\n explanation: response.explanation,\r\n patternId: response.patternId,\r\n data: response.data\r\n }\r\n }]);\r\n this.saveSession();\r\n this.shouldScroll = true;\r\n }\r\n },\r\n error: (error) => {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n this.setHostScrollLock(false);\r\n this.handleError(error);\r\n }\r\n });\r\n } else {\r\n // Fallback: use standard non-streaming endpoint\r\n this.currentSubscription = this.chatService.executeIntelligentQuery(\r\n cfg.apiUrl, cfg.token, cfg.systemId, text, history, ctx, cfg.skipPatterns, cfg.preferTableFormat,\r\n cfg.userName || undefined, cfg.personality || undefined\r\n ).subscribe({\r\n next: (response: any) => {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n const responseText = response.success\r\n ? (response.response || 'Consulta ejecutada correctamente')\r\n : (response.error || 'Error en la consulta');\r\n\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text: responseText,\r\n sender: 'bot',\r\n timestamp: new Date(),\r\n traceData: {\r\n traceId: response.traceId,\r\n fromCache: response.fromCache,\r\n fromContext: response.fromContext,\r\n query: response.query,\r\n explanation: response.explanation,\r\n patternId: response.patternId,\r\n data: response.data\r\n }\r\n }]);\r\n this.saveSession();\r\n this.shouldScroll = true;\r\n },\r\n error: (error) => {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n this.setHostScrollLock(false);\r\n this.handleError(error);\r\n }\r\n });\r\n }\r\n } else {\r\n // Standard orchestration (non-intelligent)\r\n this.currentSubscription = this.chatService.ask(cfg.apiUrl, cfg.token, text).subscribe({\r\n next: (response) => {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text: response.data?.response || 'Sin respuesta',\r\n sender: 'bot',\r\n timestamp: new Date(),\r\n traceData: {\r\n traceId: response.traceId,\r\n responseTime: response.data?.processingTime,\r\n appliedRules: response.data?.appliedRules,\r\n decisions: response.data?.decisions\r\n }\r\n }]);\r\n this.saveSession();\r\n this.shouldScroll = true;\r\n },\r\n error: (error) => {\r\n this.pipelineStep = '';\r\n this.isLoading.set(false);\r\n this.setHostScrollLock(false);\r\n this.handleError(error);\r\n }\r\n });\r\n }\r\n }\r\n\r\n cancelQuery(): void {\r\n this.currentSubscription?.unsubscribe();\r\n this.currentSubscription = undefined;\r\n this.isLoading.set(false);\r\n this.pipelineStep = '';\r\n this.setHostScrollLock(false);\r\n }\r\n\r\n clearChat(): void {\r\n this.messages.set([]);\r\n this.selectedTrace.set(null);\r\n this.authError.set(null);\r\n this.clearSession();\r\n }\r\n\r\n showTrace(msg: ChatMessage): void {\r\n this.selectedTrace.set(msg.traceData);\r\n }\r\n\r\n closeTrace(): void {\r\n this.selectedTrace.set(null);\r\n }\r\n\r\n /** Split combined multi-model query into labeled sections */\r\n getQuerySections(): { model: string | null; query: string }[] {\r\n const raw = this.selectedTrace()?.query;\r\n if (!raw) return [];\r\n\r\n // Multi-model queries are separated by \"-- [ModelName]\" headers\r\n const parts = raw.split(/^-- \\[(.+?)\\]$/m);\r\n if (parts.length <= 1) {\r\n // Single query, no model headers\r\n return [{ model: null, query: raw.trim() }];\r\n }\r\n\r\n const sections: { model: string | null; query: string }[] = [];\r\n // parts = [\"\", \"MaquitoFactura\", \"\\nSELECT...\", \"MaquitoPedido\", \"\\nSELECT...\"]\r\n for (let i = 1; i < parts.length; i += 2) {\r\n const modelName = parts[i]?.trim();\r\n const queryText = parts[i + 1]?.trim();\r\n if (modelName && queryText) {\r\n sections.push({ model: modelName, query: queryText });\r\n }\r\n }\r\n return sections.length > 0 ? sections : [{ model: null, query: raw.trim() }];\r\n }\r\n\r\n // ─── Debug Menu & Log Download ────────────────────\r\n\r\n toggleDebugMenu(): void {\r\n this.showDebugMenu.set(!this.showDebugMenu());\r\n }\r\n\r\n /** Secret keyboard shortcut — works even if debug menu is disabled */\r\n @HostListener('window:keydown', ['$event'])\r\n onDebugKeydown(event: KeyboardEvent): void {\r\n const combo = (this.resolvedConfig().debugKeyCombo || 'ctrl+shift+d').toLowerCase();\r\n const parts = combo.split('+');\r\n const needCtrl = parts.includes('ctrl');\r\n const needShift = parts.includes('shift');\r\n const needAlt = parts.includes('alt');\r\n const key = parts.filter(p => !['ctrl', 'shift', 'alt'].includes(p))[0];\r\n if ((!needCtrl || event.ctrlKey) &&\r\n (!needShift || event.shiftKey) &&\r\n (!needAlt || event.altKey) &&\r\n event.key.toLowerCase() === key) {\r\n event.preventDefault();\r\n this.downloadConversationLog();\r\n }\r\n }\r\n\r\n /** Long-press on title (mobile) — 3 seconds */\r\n onTitleTouchStart(event: TouchEvent): void {\r\n this.titleTouchTimer = setTimeout(() => {\r\n this.downloadConversationLog();\r\n }, 3000);\r\n }\r\n\r\n onTitleTouchEnd(): void {\r\n if (this.titleTouchTimer) {\r\n clearTimeout(this.titleTouchTimer);\r\n this.titleTouchTimer = null;\r\n }\r\n }\r\n\r\n /** Setup device shake detection for mobile */\r\n private setupShakeDetection(): void {\r\n if (typeof DeviceMotionEvent === 'undefined') return;\r\n const SHAKE_THRESHOLD = 25;\r\n let lastX = 0, lastY = 0, lastZ = 0;\r\n let lastUpdate = 0;\r\n\r\n this.shakeHandler = (event: DeviceMotionEvent) => {\r\n const acc = event.accelerationIncludingGravity;\r\n if (!acc || acc.x == null || acc.y == null || acc.z == null) return;\r\n const now = Date.now();\r\n if ((now - lastUpdate) < 100) return;\r\n const diffTime = now - lastUpdate;\r\n lastUpdate = now;\r\n const speed = Math.abs(acc.x + acc.y + acc.z - lastX - lastY - lastZ) / diffTime * 10000;\r\n lastX = acc.x; lastY = acc.y; lastZ = acc.z;\r\n if (speed > SHAKE_THRESHOLD && (now - this.lastShakeTime) > 5000) {\r\n this.lastShakeTime = now;\r\n this.downloadConversationLog();\r\n }\r\n };\r\n window.addEventListener('devicemotion', this.shakeHandler);\r\n }\r\n\r\n private teardownShakeDetection(): void {\r\n if (this.shakeHandler) {\r\n window.removeEventListener('devicemotion', this.shakeHandler);\r\n this.shakeHandler = null;\r\n }\r\n }\r\n\r\n /** Generate and download a comprehensive conversation log as .txt */\r\n downloadConversationLog(): void {\r\n const cfg = this.resolvedConfig();\r\n const msgs = this.messages();\r\n const now = new Date();\r\n const pad = (n: number) => n.toString().padStart(2, '0');\r\n const ts = `${now.getFullYear()}-${pad(now.getMonth()+1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`;\r\n\r\n let log = '';\r\n log += '═══════════════════════════════════════════════════\\n';\r\n log += ' MAQUITO CHAT — LOG DE CONVERSACIÓN\\n';\r\n log += ` Fecha de descarga: ${ts}\\n`;\r\n log += ` Sistema: ${cfg.systemId}\\n`;\r\n log += ` Session Key: ${this.sessionKey || 'N/A'}\\n`;\r\n log += ` Título: ${cfg.title}\\n`;\r\n log += ` Total Mensajes: ${msgs.length}\\n`;\r\n if (cfg.userName) log += ` Usuario: ${cfg.userName}\\n`;\r\n if (cfg.baseContext) log += ` Contexto Base: ${cfg.baseContext.substring(0, 100)}...\\n`;\r\n log += '═══════════════════════════════════════════════════\\n\\n';\r\n\r\n for (const msg of msgs) {\r\n const t = new Date(msg.timestamp);\r\n const time = `${pad(t.getHours())}:${pad(t.getMinutes())}:${pad(t.getSeconds())}`;\r\n const icon = msg.sender === 'user' ? '👤 USUARIO' : '🤖 BOT';\r\n log += `[${time}] ${icon}:\\n`;\r\n // Strip HTML tags for plain text\r\n const plainText = msg.text.replace(/<[^>]*>/g, '').trim();\r\n log += `${plainText}\\n`;\r\n\r\n // Include trace data if available (bot messages)\r\n if (msg.traceData && msg.sender === 'bot') {\r\n log += ' ┌─── Traza ───────────────────────\\n';\r\n const td = msg.traceData;\r\n if (td.traceId) log += ` │ TraceId: ${td.traceId}\\n`;\r\n if (td.origin) log += ` │ Origen: ${td.origin}\\n`;\r\n if (td.query) log += ` │ Query: ${td.query}\\n`;\r\n if (td.model) log += ` │ Modelo: ${td.model}\\n`;\r\n if (td.rowCount !== undefined) log += ` │ Filas: ${td.rowCount}\\n`;\r\n if (td.explanation) log += ` │ Explicación: ${td.explanation}\\n`;\r\n if (td.durationMs) log += ` │ Duración: ${td.durationMs}ms\\n`;\r\n // Include full raw trace for deep debugging\r\n try {\r\n const raw = JSON.stringify(td, null, 2);\r\n log += ` │ Raw Trace:\\n`;\r\n for (const line of raw.split('\\n')) {\r\n log += ` │ ${line}\\n`;\r\n }\r\n } catch {}\r\n log += ' └─────────────────────────────────\\n';\r\n }\r\n log += '\\n';\r\n }\r\n\r\n log += '═══════════════════════════════════════════════════\\n';\r\n log += ` FIN DEL LOG — ${msgs.length} mensajes\\n`;\r\n log += '═══════════════════════════════════════════════════\\n';\r\n\r\n // Download as .txt file\r\n const blob = new Blob([log], { type: 'text/plain;charset=utf-8' });\r\n const url = URL.createObjectURL(blob);\r\n const a = document.createElement('a');\r\n a.href = url;\r\n a.download = `maquito-chat-log_${now.getFullYear()}${pad(now.getMonth()+1)}${pad(now.getDate())}_${pad(now.getHours())}${pad(now.getMinutes())}.txt`;\r\n document.body.appendChild(a);\r\n a.click();\r\n document.body.removeChild(a);\r\n URL.revokeObjectURL(url);\r\n }\r\n\r\n // ─── Link Modal ────────────────────────────────\r\n openLinkModal(url: string): void {\r\n this.modalLoading.set(true);\r\n this.showHomeBtn.set(false);\r\n this.modalReadyForNav = false;\r\n clearTimeout(this.navReadyTimer);\r\n this.originalModalUrl = url;\r\n this.modalUrl.set(url);\r\n }\r\n\r\n closeLinkModal(): void {\r\n this.modalUrl.set(null);\r\n this.modalLoading.set(false);\r\n this.showHomeBtn.set(false);\r\n this.modalReadyForNav = false;\r\n clearTimeout(this.navReadyTimer);\r\n this.originalModalUrl = '';\r\n }\r\n\r\n onIframeLoaded(): void {\r\n this.modalLoading.set(false);\r\n if (this.modalReadyForNav) {\r\n // A load AFTER the initial page settled = real navigation\r\n this.showHomeBtn.set(true);\r\n } else {\r\n // Initial page load (may fire multiple times for SPAs/redirects)\r\n // Wait 1s of stability before treating next loads as navigation\r\n clearTimeout(this.navReadyTimer);\r\n this.navReadyTimer = setTimeout(() => { this.modalReadyForNav = true; }, 1000);\r\n }\r\n }\r\n\r\n iframeGoHome(): void {\r\n const iframe = this.hostEl.nativeElement.querySelector('.iq-link-iframe') as HTMLIFrameElement;\r\n if (iframe && this.originalModalUrl) {\r\n this.modalLoading.set(true);\r\n this.showHomeBtn.set(false);\r\n this.modalReadyForNav = false;\r\n clearTimeout(this.navReadyTimer);\r\n iframe.src = this.originalModalUrl;\r\n }\r\n }\r\n\r\n /** Intercept clicks on <a> and <img> tags inside rendered markdown */\r\n onMessageClick(event: MouseEvent): void {\r\n const target = event.target as HTMLElement;\r\n\r\n // Clicking an image opens it full-size in the modal\r\n if (target.tagName === 'IMG') {\r\n const src = (target as HTMLImageElement).src;\r\n if (src) {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n this.openLinkModal(src);\r\n return;\r\n }\r\n }\r\n\r\n const anchor = target.closest('a') as HTMLAnchorElement | null;\r\n if (anchor && anchor.href) {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n this.openLinkModal(anchor.href);\r\n }\r\n }\r\n\r\n formatTime(date: Date): string {\r\n return date.toLocaleTimeString('es-CL', { hour: '2-digit', minute: '2-digit' });\r\n }\r\n\r\n renderMarkdown(text: string): SafeHtml {\r\n if (!text) return '';\r\n\r\n // Return cached result if available (avoids re-parsing on every CD cycle)\r\n const cached = this.mdCache.get(text);\r\n if (cached) return cached;\r\n\r\n try {\r\n // Safety valve: if text is extremely long, skip regex-heavy preprocessing\r\n // to avoid catastrophic backtracking that freezes the browser\r\n let preprocessed = text.length < 100_000 ? this.preprocessMarkdownTable(text) : text;\r\n\r\n // Encode spaces in markdown image & link URLs: ![alt](url) and [text](url)\r\n if (preprocessed.length < 100_000) {\r\n preprocessed = preprocessed.replace(/(!?\\[[^\\]]*\\])\\(([^)]+)\\)/g,\r\n (_match, bracket, url) => `${bracket}(${url.replace(/ /g, '%20')})`);\r\n }\r\n\r\n let html = marked.parse(preprocessed, { breaks: true }) as string;\r\n // Inject inline styles + onerror on <img> to force small thumbnails & hide broken ones\r\n const imgStyle = `style=\"max-height:48px;max-width:100px;object-fit:contain;border-radius:6px;cursor:pointer;display:inline-block;vertical-align:middle;margin:2px 4px;border:1px solid rgba(255,255,255,0.15);box-shadow:0 1px 3px rgba(0,0,0,0.2);\"`;\r\n html = html.replace(/<img /g, `<img ${imgStyle} onerror=\"this.style.display='none'\" `);\r\n const result = this.sanitizer.bypassSecurityTrustHtml(html);\r\n this.mdCache.set(text, result);\r\n return result;\r\n } catch {\r\n return text;\r\n }\r\n }\r\n\r\n /**\r\n * Pre-process text to ensure pipe-delimited tables render as HTML tables.\r\n *\r\n * The API often returns header + separator + data on ONE line, e.g.:\r\n * \"| Col1 | Col2 | |---|---| | Val1 | Val2 |\"\r\n *\r\n * Step 1: Find the dash-separator pattern (|---|---|) and break the line\r\n * around it so each part (header / separator / data rows) is its\r\n * own line.\r\n * Step 2: Line-by-line cleanup — ensure a blank line exists before the\r\n * first pipe-row and inject a separator if one is still missing.\r\n */\r\n private preprocessMarkdownTable(text: string): string {\r\n // ── Step 1: Break inline separator onto its own line ───────────\r\n // Pattern: the separator row consists only of |, -, :, and spaces.\r\n // We insert \\n before and after it.\r\n text = text.replace(\r\n /\\s*(\\|(?:\\s*:?-{2,}:?\\s*\\|){2,})\\s*/g,\r\n '\\n$1\\n'\r\n );\r\n // Clean up excess blank lines created by step 1\r\n text = text.replace(/\\n{3,}/g, '\\n\\n');\r\n\r\n // ── Step 2: Line-by-line processing ───────────────────────────\r\n const lines = text.split('\\n');\r\n const result: string[] = [];\r\n let inTable = false;\r\n\r\n const isPipeLine = (l: string) => {\r\n const t = l.trim();\r\n return t.startsWith('|') && t.split('|').length > 3;\r\n };\r\n const isSepLine = (l: string) =>\r\n /^\\|(?:\\s*:?-{2,}:?\\s*\\|){2,}\\s*$/.test(l.trim());\r\n\r\n for (let i = 0; i < lines.length; i++) {\r\n const line = lines[i];\r\n const trimmed = line.trim();\r\n\r\n if (isPipeLine(trimmed) && !isSepLine(trimmed)) {\r\n if (!inTable) {\r\n inTable = true;\r\n // Insert blank line before table if preceded by non-empty text\r\n if (result.length > 0 && result[result.length - 1].trim() !== '') {\r\n result.push('');\r\n }\r\n result.push(line);\r\n // Inject separator if the next line isn't one\r\n const next = (i + 1 < lines.length) ? lines[i + 1] : '';\r\n if (!isSepLine(next)) {\r\n const cols = trimmed.split('|').filter(c => c.trim() !== '').length;\r\n result.push('| ' + Array(cols).fill('---').join(' | ') + ' |');\r\n }\r\n } else {\r\n result.push(line); // data row\r\n }\r\n } else if (isSepLine(trimmed)) {\r\n if (!inTable) inTable = true; // edge-case: separator before header\r\n result.push(line);\r\n } else {\r\n inTable = false;\r\n result.push(line);\r\n }\r\n }\r\n\r\n return result.join('\\n');\r\n }\r\n\r\n // ─── Private ───────────────────────────────────────────\r\n\r\n private handleError(error: any): void {\r\n const status = error?.status;\r\n if (status === 401 || status === 403) {\r\n const msg = status === 401 ? 'Token inválido o expirado' : 'Sin permisos para este sistema';\r\n this.authError.set(`🔒 ${msg}`);\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text: `⚠️ ${msg}. Verifica el token y el systemId configurados.`,\r\n sender: 'bot',\r\n timestamp: new Date()\r\n }]);\r\n } else {\r\n this.messages.update(msgs => [...msgs, {\r\n id: this.messageId++,\r\n text: `Error: ${error.error?.message || error.error?.error || 'No se pudo procesar la consulta'}`,\r\n sender: 'bot',\r\n timestamp: new Date()\r\n }]);\r\n }\r\n this.saveSession();\r\n this.shouldScroll = true;\r\n }\r\n\r\n private stopPipelineSteps(): void {\r\n this.pipelineStep = '';\r\n }\r\n\r\n private scrollToBottom(): void {\r\n if (this.chatContainer) {\r\n const el = this.chatContainer.nativeElement;\r\n el.scrollTop = el.scrollHeight;\r\n }\r\n }\r\n\r\n // ─── Session Persistence ──────────────────────────\r\n\r\n private buildSessionKey(): string {\r\n const cfg = this.resolvedConfig();\r\n if (!cfg.token || !cfg.systemId) return '';\r\n // Simple hash-like key from systemId + first 8 chars of token\r\n const tokenPrefix = cfg.token.substring(0, 8);\r\n return `${this.STORAGE_PREFIX}${cfg.systemId}_${tokenPrefix}`;\r\n }\r\n\r\n private saveSession(): void {\r\n if (!this.sessionKey) return;\r\n try {\r\n const data = this.messages().map(m => ({\r\n id: m.id,\r\n text: m.text,\r\n sender: m.sender,\r\n timestamp: m.timestamp,\r\n traceData: m.traceData\r\n }));\r\n localStorage.setItem(this.sessionKey, JSON.stringify(data));\r\n } catch { /* ignore quota errors */ }\r\n }\r\n\r\n private loadSession(): void {\r\n if (!this.sessionKey) return;\r\n try {\r\n const raw = localStorage.getItem(this.sessionKey);\r\n if (!raw) { this.messages.set([]); return; }\r\n const data: any[] = JSON.parse(raw);\r\n // Validate data is an array of valid message objects\r\n if (!Array.isArray(data) || data.length === 0) {\r\n this.messages.set([]);\r\n return;\r\n }\r\n const msgs: ChatMessage[] = data\r\n .filter(m => m && typeof m.text === 'string' && typeof m.sender === 'string')\r\n .map(m => ({\r\n ...m,\r\n timestamp: new Date(m.timestamp)\r\n }));\r\n this.messages.set(msgs);\r\n this.messageId = msgs.length > 0 ? Math.max(...msgs.map(m => m.id)) + 1 : 0;\r\n this.shouldScroll = true;\r\n } catch {\r\n // Corrupted session data — wipe it and start fresh\r\n try { localStorage.removeItem(this.sessionKey); } catch { /* ignore */ }\r\n this.messages.set([]);\r\n }\r\n }\r\n\r\n private clearSession(): void {\r\n if (this.sessionKey) {\r\n try { localStorage.removeItem(this.sessionKey); } catch {}\r\n }\r\n }\r\n\r\n /** Called when another tab modifies localStorage */\r\n private onStorageChange(e: StorageEvent): void {\r\n if (!this.sessionKey || e.key !== this.sessionKey) return;\r\n if (e.newValue === null) {\r\n // Session was cleared in another tab\r\n this.messages.set([]);\r\n } else {\r\n this.loadSession();\r\n }\r\n this.shouldScroll = true;\r\n }\r\n}\r\n","/*\r\n * Public API Surface of maquito-chat-plugin\r\n */\r\n\r\nexport type { IntelligentChatConfig, ChatMessage, PluginTheme } from './lib/intelligent-chat.models';\r\nexport { IntelligentChatService } from './lib/intelligent-chat.service';\r\nexport { IntelligentChatPluginComponent } from './lib/intelligent-chat-plugin.component';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "maquito-chat-plugin",
3
- "version": "1.1.5",
3
+ "version": "1.1.6",
4
4
  "description": "Maquito Intelligent Chat Plugin - Widget de chat flotante para consultas inteligentes",
5
5
  "author": "INDESAD",
6
6
  "license": "MIT",
@@ -58,6 +58,10 @@ interface IntelligentChatConfig {
58
58
  userName?: string;
59
59
  /** AI personality instructions (e.g. "Eres Maquito de Tagler Maq...") */
60
60
  personality?: string;
61
+ /** Show debug menu (⋯) in the header with "Download Log" option. Default: false */
62
+ enableDebugMenu?: boolean;
63
+ /** Keyboard shortcut to download conversation log (works even if debug menu is hidden). Default: 'ctrl+shift+d' */
64
+ debugKeyCombo?: string;
61
65
  }
62
66
  /** All customisable plugin colours (map 1-to-1 to --iq-* CSS vars) */
63
67
  interface PluginTheme {
@@ -158,6 +162,10 @@ declare class IntelligentChatPluginComponent implements AfterViewChecked, OnChan
158
162
  private readonly STORAGE_PREFIX;
159
163
  private sessionKey;
160
164
  private storageListener;
165
+ showDebugMenu: _angular_core.WritableSignal<boolean>;
166
+ private titleTouchTimer;
167
+ private shakeHandler;
168
+ private lastShakeTime;
161
169
  /** Resolved config with defaults applied */
162
170
  private sanitizer;
163
171
  resolvedConfig: _angular_core.WritableSignal<Required<IntelligentChatConfig>>;
@@ -180,6 +188,22 @@ declare class IntelligentChatPluginComponent implements AfterViewChecked, OnChan
180
188
  clearChat(): void;
181
189
  showTrace(msg: ChatMessage): void;
182
190
  closeTrace(): void;
191
+ /** Split combined multi-model query into labeled sections */
192
+ getQuerySections(): {
193
+ model: string | null;
194
+ query: string;
195
+ }[];
196
+ toggleDebugMenu(): void;
197
+ /** Secret keyboard shortcut — works even if debug menu is disabled */
198
+ onDebugKeydown(event: KeyboardEvent): void;
199
+ /** Long-press on title (mobile) — 3 seconds */
200
+ onTitleTouchStart(event: TouchEvent): void;
201
+ onTitleTouchEnd(): void;
202
+ /** Setup device shake detection for mobile */
203
+ private setupShakeDetection;
204
+ private teardownShakeDetection;
205
+ /** Generate and download a comprehensive conversation log as .txt */
206
+ downloadConversationLog(): void;
183
207
  openLinkModal(url: string): void;
184
208
  closeLinkModal(): void;
185
209
  onIframeLoaded(): void;