unify styles

This commit is contained in:
overcuriousity 2025-08-17 11:11:26 +02:00
parent 170638a5fa
commit 8bba0eefa9

View File

@ -3,7 +3,6 @@
import { getToolsData } from '../utils/dataService.js';
const data = await getToolsData();
const tools = data.tools;
const phases = data.phases;
@ -13,20 +12,20 @@ const domainAgnosticSoftware = data['domain-agnostic-software'] || [];
<section id="ai-interface" class="ai-interface hidden">
<div class="ai-query-section">
<div class="content-center-lg">
<h2 style="margin-bottom: 1rem; color: var(--color-primary);">
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-right: 0.75rem; vertical-align: middle;">
<h2 class="mb-4 text-primary">
<svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="mr-3 align-middle">
<path d="M9 11H5a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7a2 2 0 0 0-2-2h-4"/>
<path d="M9 11V7a3 3 0 0 1 6 0v4"/>
</svg>
Forensic AI
</h2>
<p id="ai-description" class="text-muted" style="max-width: 700px; margin: 0 auto; line-height: 1.6;">
<p id="ai-description" class="text-muted mx-auto leading-relaxed max-w-lg">
Beschreiben Sie Ihr forensisches Szenario und erhalten Sie maßgeschneiderte Workflow-Empfehlungen
basierend auf bewährten DFIR-Workflows und der verfügbaren Software-Datenbank.
</p>
</div>
<div class="ai-input-container" style="max-width: 1000px; margin: 0 auto;">
<div class="ai-input-container mx-auto max-w-6xl">
<!-- Mode Toggle -->
<div class="ai-mode-toggle">
<span id="workflow-label" class="toggle-label active">
@ -55,10 +54,10 @@ const domainAgnosticSoftware = data['domain-agnostic-software'] || [];
<textarea
id="ai-query-input"
placeholder="Beschreiben Sie Ihr forensisches Szenario..."
style="min-height: 220px; resize: vertical; font-size: 0.9375rem; line-height: 1.5;"
class="w-full"
maxlength="2000"
></textarea>
<div id="ai-char-counter" style="font-size: 0.75rem; color: var(--color-text-secondary); text-align: right; margin-top: 0.25rem;">0/2000</div>
<div id="ai-char-counter" class="text-xs text-secondary text-right mt-1">0/2000</div>
</div>
<div class="ai-suggestions-section">
@ -114,21 +113,21 @@ const domainAgnosticSoftware = data['domain-agnostic-software'] || [];
</div>
<!-- Privacy Notice -->
<div style="margin-top: 0.5rem; margin-bottom: 1rem;">
<p style="font-size: 0.75rem; color: var(--color-text-secondary); text-align: center; line-height: 1.4;">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-right: 0.25rem; vertical-align: middle;">
<div class="mt-2 mb-4">
<p class="text-xs text-secondary text-center leading-normal">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="mr-1 align-middle">
<circle cx="12" cy="12" r="10"/>
<line x1="12" y1="8" x2="12" y2="12"/>
<line x1="12" y1="16" x2="12.01" y2="16"/>
</svg>
Ihre Anfrage wird über die API von mistral.ai übertragen.
<a href="https://mistral.ai/privacy-policy/" target="_blank" rel="noopener noreferrer" style="color: var(--color-primary);">Datenschutzrichtlinien</a>
<a href="https://mistral.ai/privacy-policy/" target="_blank" rel="noopener noreferrer" class="text-primary">Datenschutzrichtlinien</a>
</p>
</div>
<div class="ai-restore-section" style="margin-top: 1rem; margin-bottom: 1.5rem; text-align: center;">
<div style="display: inline-flex; align-items: center; gap: 1rem; padding: 0.75rem 1.5rem; background-color: var(--color-bg-secondary); border: 1px solid var(--color-border); border-radius: 0.5rem;">
<div style="display: flex; align-items: center; gap: 0.5rem; color: var(--color-text-secondary); font-size: 0.875rem;">
<div class="ai-restore-section">
<div class="flex items-center justify-center gap-4 p-3 bg-secondary border rounded-lg">
<div class="flex items-center gap-2 text-secondary text-sm">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="17 8 12 3 7 8"/>
@ -137,8 +136,8 @@ const domainAgnosticSoftware = data['domain-agnostic-software'] || [];
Vorherige Analyse wiederherstellen:
</div>
<label for="upload-previous-analysis" class="btn btn-secondary" style="margin: 0; font-size: 0.875rem; padding: 0.5rem 1rem;">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-right: 0.5rem;">
<label for="upload-previous-analysis" class="btn btn-secondary btn-sm">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="mr-2">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
<polyline points="14 2 14 8 20 8"/>
<path d="M16 13H8"/>
@ -146,19 +145,19 @@ const domainAgnosticSoftware = data['domain-agnostic-software'] || [];
<path d="M10 9H8"/>
</svg>
JSON-Datei hochladen
<input type="file" id="upload-previous-analysis" accept=".json" style="display: none;" />
<input type="file" id="upload-previous-analysis" accept=".json" class="hidden" />
</label>
</div>
<div style="margin-top: 0.5rem; font-size: 0.75rem; color: var(--color-text-secondary);">
<div class="mt-2 text-xs text-secondary text-center">
Laden Sie eine zuvor heruntergeladene Analyse-Datei, um Ergebnisse und Audit-Trail anzuzeigen
</div>
</div>
<!-- Submit Button -->
<div style="display: flex; justify-content: center; gap: 1rem; margin-top: 1rem;">
<button id="ai-submit-btn" class="btn btn-accent" style="padding: 0.75rem 2rem; font-size: 1rem;">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-right: 0.5rem;">
<div class="flex justify-center gap-4 mt-4">
<button id="ai-submit-btn" class="btn btn-accent btn-lg">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="mr-2">
<path d="M14.828 14.828a4 4 0 0 1-5.656 0"/>
<path d="M9 9a3 3 0 1 1 6 0c0 .749-.269 1.433-.73 1.96L11 14v1a1 1 0 0 1-1 1h-1a1 1 0 0 1-1-1v-1l-3.27-3.04A3 3 0 0 1 5 9a3 3 0 0 1 6 0"/>
</svg>
@ -168,9 +167,9 @@ const domainAgnosticSoftware = data['domain-agnostic-software'] || [];
<!-- Loading State -->
<div id="ai-loading" class="ai-loading hidden">
<div style="text-align: center; padding: 2rem;">
<div style="margin-bottom: 1rem;">
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="var(--color-primary)" stroke-width="2" style="animation: pulse 2s ease-in-out infinite;">
<div class="text-center p-8">
<div class="mb-4">
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="var(--color-primary)" stroke-width="2" class="ai-pulse-icon">
<path d="M14.828 14.828a4 4 0 0 1-5.656 0"/>
<path d="M9 9a3 3 0 1 1 6 0c0 .749-.269 1.433-.73 1.96L11 14v1a1 1 0 0 1-1 1h-1a1 1 0 0 1-1-1v-1l-3.27-3.04A3 3 0 0 1 5 9a3 3 0 0 1 6 0"/>
</svg>
@ -228,10 +227,10 @@ const domainAgnosticSoftware = data['domain-agnostic-software'] || [];
<!-- Error State -->
<div id="ai-error" class="ai-error hidden">
<div style="text-align: center; padding: 2rem;">
<div style="background-color: var(--color-error); color: white; padding: 1rem; border-radius: 0.5rem; max-width: 600px; margin: 0 auto;">
<h3 style="margin-bottom: 0.5rem;">Fehler bei der KI-Anfrage</h3>
<p id="ai-error-message" style="margin: 0;">Ein unerwarteter Fehler ist aufgetreten.</p>
<div class="text-center p-8">
<div class="bg-error text-white p-4 rounded-lg max-w-6xl mx-auto">
<h3 class="mb-2">Fehler bei der KI-Anfrage</h3>
<p id="ai-error-message" class="mb-0">Ein unerwarteter Fehler ist aufgetreten.</p>
</div>
</div>
</div>
@ -1652,9 +1651,9 @@ class AIQueryInterface {
renderHeader(title, query) {
return `
<div style="text-align: center; margin-bottom: 2rem; padding: 1.5rem; background: linear-gradient(135deg, var(--color-primary) 0%, #525252 100%); color: white; border-radius: 0.75rem;">
<h3 style="margin: 0 0 0.75rem 0; font-size: 1.5rem;">${title}</h3>
<p style="margin: 0; opacity: 0.9; line-height: 1.5;">
<div class="header-center header-primary rounded-xl mb-8">
<h3 class="text-2xl mb-3">${title}</h3>
<p class="mb-0 leading-relaxed">
Basierend auf Ihrer Anfrage: "<em>${truncateText(query, 100)}</em>"
</p>
</div>
@ -1667,33 +1666,33 @@ class AIQueryInterface {
const analysisField = mode === 'workflow' ? recommendation.scenario_analysis : recommendation.problem_analysis;
if (analysisField) {
html += `
<div class="card contextual-analysis-card scenario">
<h4 style="margin: 0 0 1rem 0; color: var(--color-primary);">
<div class="card contextual-analysis-card scenario mb-6">
<h4 class="mb-4 text-primary">
${mode === 'workflow' ? 'Szenario-Analyse' : 'Problem-Analyse'}
</h4>
<div style="margin: 0; line-height: 1.6; white-space: pre-wrap; word-wrap: break-word;">${sanitizeText(analysisField)}</div>
<div class="leading-relaxed">${sanitizeText(analysisField)}</div>
</div>
`;
}
if (recommendation.investigation_approach) {
html += `
<div class="card contextual-analysis-card approach">
<h4 style="margin: 0 0 1rem 0; color: var(--color-accent);">
<div class="card contextual-analysis-card approach mb-6">
<h4 class="mb-4 text-accent">
${mode === 'workflow' ? 'Untersuchungsansatz' : 'Lösungsansatz'}
</h4>
<div style="margin: 0; line-height: 1.6; white-space: pre-wrap; word-wrap: break-word;">${sanitizeText(recommendation.investigation_approach)}</div>
<div class="leading-relaxed">${sanitizeText(recommendation.investigation_approach)}</div>
</div>
`;
}
if (recommendation.critical_considerations) {
html += `
<div class="card contextual-analysis-card critical">
<h4 style="margin: 0 0 1rem 0; color: var(--color-warning);">
<div class="card contextual-analysis-card critical mb-6">
<h4 class="mb-4 text-warning">
${mode === 'workflow' ? 'Kritische Überlegungen' : 'Wichtige Voraussetzungen'}
</h4>
<div style="margin: 0; line-height: 1.6; white-space: pre-wrap; word-wrap: break-word;">${sanitizeText(recommendation.critical_considerations)}</div>
<div class="leading-relaxed">${sanitizeText(recommendation.critical_considerations)}</div>
</div>
`;
}
@ -1705,28 +1704,71 @@ class AIQueryInterface {
if (!backgroundKnowledge?.length) return '';
const conceptLinks = backgroundKnowledge.map(concept => `
<div style="background-color: var(--color-concept-bg); border: 1px solid var(--color-concept); border-radius: 0.5rem; padding: 1rem; margin-bottom: 0.75rem;">
<div style="display: flex; align-items: center; gap: 0.75rem; margin-bottom: 0.5rem;">
<div class="card-info-sm mb-3 border-l-4" style="border-left-color: var(--color-concept);">
<div class="flex items-center gap-3 mb-2">
<button onclick="window.showToolDetails('${concept.concept_name}', 'secondary')"
style="background: none; border: none; color: var(--color-concept); font-weight: 600; cursor: pointer; text-decoration: underline;">
class="btn-icon text-concept font-semibold">
📚 ${concept.concept_name}
</button>
<span class="badge" style="background-color: var(--color-concept); color: white; font-size: 0.625rem;">Hintergrundwissen</span>
<span class="badge" style="background-color: var(--color-concept); color: white;">Hintergrundwissen</span>
</div>
<div style="margin: 0; font-size: 0.8125rem; line-height: 1.5; color: var(--color-text-secondary); white-space: pre-wrap; word-wrap: break-word;">
<div class="text-sm leading-relaxed text-secondary">
${sanitizeText(concept.relevance)}
</div>
</div>
`).join('');
return `
<div class="card" style="margin-bottom: 2rem; border-left: 4px solid var(--color-concept);">
<h4 style="margin: 0 0 1rem 0; color: var(--color-concept);">Empfohlenes Hintergrundwissen</h4>
<div class="card mb-8 border-l-4" style="border-left-color: var(--color-concept);">
<h4 class="mb-4 text-concept">Empfohlenes Hintergrundwissen</h4>
${conceptLinks}
</div>
`;
}
renderWorkflowTool(tool) {
const priorityColors = {
high: 'var(--color-error)',
medium: 'var(--color-warning)',
low: 'var(--color-accent)'
};
const priority = tool.recommendation ? tool.recommendation.priority : tool.priority;
const confidenceTooltip = tool.confidence ? this.renderConfidenceTooltip(tool.confidence) : '';
const cardClass = this.getToolClass(tool, 'recommendation');
return `
<div class="tool-recommendation ${cardClass}" onclick="window.showToolDetails('${tool.name}')">
<div class="tool-rec-header">
<h4 class="tool-rec-name">
${tool.icon ? `<span class="mr-2 text-lg">${tool.icon}</span>` : ''}
${tool.name}
</h4>
<div class="flex items-center gap-1 flex-shrink-0">
<span class="tool-rec-priority ${priority}" style="background-color: ${priorityColors[priority]};">
${priority}
${confidenceTooltip}
</span>
</div>
</div>
<div class="tool-rec-justification">
"${sanitizeText(tool.justification || (tool.recommendation && tool.recommendation.justification) || `Empfohlen für ${tool.phase}`)}"
</div>
<div class="text-xs text-secondary mt-auto">
<div class="flex flex-wrap gap-1 mb-2">
${this.renderToolBadges(tool)}
</div>
<div class="flex justify-between items-center">
<span>${tool.type === 'method' ? 'Methode' : tool.platforms.slice(0, 2).join(', ')}</span>
<span>${tool.skillLevel}</span>
</div>
</div>
</div>
`;
}
renderWorkflowPhases(toolsByPhase, phaseOrder, phaseNames) {
const phaseColors = [
'var(--color-primary)',
@ -1744,28 +1786,25 @@ class AIQueryInterface {
const phaseColor = phaseColors[index % phaseColors.length];
return `
<div class="workflow-phase" style="margin-bottom: 2rem;">
<div class="phase-header" style="display: flex; align-items: flex-start; gap: 1rem; padding: 1.5rem; background-color: var(--color-bg); border: 2px solid var(--color-border); border-radius: 0.75rem; transition: var(--transition-medium);"
onmouseover="this.style.borderColor='${phaseColor}'; this.style.boxShadow='var(--shadow-md)';"
onmouseout="this.style.borderColor='var(--color-border)'; this.style.boxShadow='';">
<div class="phase-number" style="width: 2rem; height: 2rem; background: ${phaseColor}; color: white; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 600; flex-shrink: 0; box-shadow: var(--shadow-sm);">
<div class="workflow-phase mb-8">
<div class="phase-header" style="--phase-color: ${phaseColor};">
<div class="phase-number" style="background: ${phaseColor};">
${index + 1}
</div>
<div class="phase-info" style="display: flex; flex-direction: column; gap: 0.75rem; flex: 1; min-width: 0;">
<h3 class="phase-title" style="font-weight: 600; margin: 0; color: var(--color-text); font-size: 1.25rem;">
<div class="phase-info">
<h3 class="phase-title">
${phaseNames[phase]}
</h3>
<div class="phase-tools" style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1rem;">
<div class="phase-tools">
${phaseTools.map(tool => this.renderWorkflowTool(tool)).join('')}
</div>
</div>
</div>
${index < phaseOrder.length - 1 ? `
<div class="workflow-arrow" style="display: flex; justify-content: center; margin: 1rem 0; color: ${phaseColor};">
<div class="workflow-arrow" style="color: ${phaseColor};">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<line x1="12" y1="5" x2="12" y2="19"/>
<polyline points="19 12 12 19 5 12"/>
@ -1777,55 +1816,6 @@ class AIQueryInterface {
}).join('');
}
renderWorkflowTool(tool) {
const priorityColors = {
high: 'var(--color-error)',
medium: 'var(--color-warning)',
low: 'var(--color-accent)'
};
const priority = tool.recommendation ? tool.recommendation.priority : tool.priority;
const confidenceTooltip = tool.confidence ? this.renderConfidenceTooltip(tool.confidence) : '';
const cardClass = this.getToolClass(tool, 'recommendation');
return `
<div class="tool-recommendation ${cardClass}" onclick="window.showToolDetails('${tool.name}')"
style="position: relative; cursor: pointer; transition: var(--transition-fast);"
onmouseover="this.style.transform='translateY(-2px)'; this.style.boxShadow='var(--shadow-md)';"
onmouseout="this.style.transform='translateY(0)'; this.style.boxShadow='';">
<div class="tool-rec-header" style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 0.75rem;">
<h4 class="tool-rec-name" style="font-weight: 600; font-size: 1rem; margin: 0; color: var(--color-text); flex: 1; margin-right: 0.75rem;">
${tool.icon ? `<span style="margin-right: 0.5rem; font-size: 1.125rem;">${tool.icon}</span>` : ''}
${tool.name}
</h4>
<div style="display: flex; align-items: center; gap: 0.375rem; flex-shrink: 0;">
<span class="tool-rec-priority ${priority}"
style="background-color: ${priorityColors[priority]}; color: white; padding: 0.25rem 0.5rem; border-radius: 1rem; font-size: 0.75rem; font-weight: 500; text-transform: uppercase; position: relative; display: flex; align-items: center; gap: 0.25rem;">
${priority}
${confidenceTooltip}
</span>
</div>
</div>
<div class="tool-rec-justification" style="background-color: var(--color-bg-tertiary); padding: 0.75rem; border-radius: 0.375rem; border-left: 3px solid var(--color-primary); margin: 0.75rem 0; font-style: italic; white-space: pre-wrap; word-wrap: break-word; font-size: 0.875rem; line-height: 1.5; color: var(--color-text-secondary);">
"${sanitizeText(tool.justification || (tool.recommendation && tool.recommendation.justification) || `Empfohlen für ${tool.phase}`)}"
</div>
<div style="font-size: 0.75rem; color: var(--color-text-secondary); margin-top: auto;">
<div style="display: flex; flex-wrap: wrap; gap: 0.375rem; margin-bottom: 0.5rem;">
${this.renderToolBadges(tool)}
</div>
<div style="display: flex; justify-content: space-between; align-items: center;">
<span>${tool.type === 'method' ? 'Methode' : tool.platforms.slice(0, 2).join(', ')}</span>
<span>${tool.skillLevel}</span>
</div>
</div>
</div>
`;
}
renderToolRecommendations(recommendedTools) {
if (!recommendedTools?.length) return '';
@ -1848,15 +1838,15 @@ class AIQueryInterface {
const confidenceTooltip = recommendation.confidence ? this.renderConfidenceTooltip(recommendation.confidence) : '';
return `
<div class="card ${this.getToolClass(tool, 'card')}" style="cursor: pointer; position: relative;" onclick="window.showToolDetails('${tool.name}')">
<div style="position: absolute; top: -8px; right: -8px; width: 32px; height: 32px; background-color: ${rankColors[rank]}; color: white; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 1.125rem;">
<div class="card ${this.getToolClass(tool, 'card')} cursor-pointer relative" onclick="window.showToolDetails('${tool.name}')">
<div class="absolute -top-2 -right-2 w-8 h-8 text-white rounded-xl flex items-center justify-center font-semibold text-lg" style="background-color: ${rankColors[rank]};">
${rank}
</div>
<div style="margin-bottom: 1rem;">
<h3 style="margin: 0 0 0.5rem 0;">${tool.name}</h3>
<div style="display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-bottom: 0.75rem;">
<span class="badge" style="background-color: ${suitabilityColors[recommendation.suitability_score]}; color: white; position: relative; display: flex; align-items: center; gap: 0.25rem;">
<div class="mb-4">
<h3 class="mb-2">${tool.name}</h3>
<div class="flex flex-wrap gap-2 items-center mb-3">
<span class="badge text-white relative flex items-center gap-1" style="background-color: ${suitabilityColors[recommendation.suitability_score]};">
${this.getSuitabilityText(recommendation.suitability_score)}
${confidenceTooltip}
</span>
@ -1864,13 +1854,13 @@ class AIQueryInterface {
</div>
</div>
<div style="margin-bottom: 1.5rem;">
<h4 style="margin: 0.8rem 0 0.75rem 0; color: var(--color-accent);">Warum diese Methode?</h4>
<div style="margin: 0; line-height: 1.6; white-space: pre-wrap; word-wrap: break-word;">${sanitizeText(recommendation.detailed_explanation)}</div>
<div class="mb-6">
<h4 class="mb-3 text-accent">Warum diese Methode?</h4>
<div class="leading-relaxed">${sanitizeText(recommendation.detailed_explanation)}</div>
${recommendation.implementation_approach ? `
<h4 style="margin: 0.8rem 0 0.75rem 0; color: var(--color-primary);">Anwendungsansatz</h4>
<div style="margin: 0; line-height: 1.6; white-space: pre-wrap; word-wrap: break-word;">${sanitizeText(recommendation.implementation_approach)}</div>
<h4 class="mt-3 mb-3 text-primary">Anwendungsansatz</h4>
<div class="leading-relaxed">${sanitizeText(recommendation.implementation_approach)}</div>
` : ''}
</div>
@ -1887,66 +1877,64 @@ class AIQueryInterface {
const confidenceColor = getConfidenceColor(confidence.overall);
return `
<span class="confidence-tooltip-trigger"
style="display: inline-flex; align-items: center; gap: 0.125rem; cursor: help; margin-left: 0.25rem; position: relative;"
<span class="inline-flex items-center gap-1 cursor-pointer ml-1 relative"
onmouseenter="this.querySelector('.confidence-tooltip').style.display = 'block'"
onmouseleave="this.querySelector('.confidence-tooltip').style.display = 'none'"
onclick="event.stopPropagation();">
<div style="width: 6px; height: 6px; border-radius: 50%; background-color: ${confidenceColor}; flex-shrink: 0;"></div>
<span style="font-size: 0.625rem; color: white; font-weight: 600; text-shadow: 0 1px 2px rgba(0,0,0,0.5);">${confidence.overall}%</span>
<div class="w-1.5 h-1.5 rounded-xl flex-shrink-0" style="background-color: ${confidenceColor};"></div>
<span class="text-xs font-semibold text-white">${confidence.overall}%</span>
<div class="confidence-tooltip"
style="display: none; position: absolute; top: 100%; right: 0; z-index: 1001; background: var(--color-bg); border: 1px solid var(--color-border); border-radius: 0.5rem; padding: 1rem; min-width: 320px; max-width: 400px; box-shadow: var(--shadow-lg); font-size: 0.75rem; color: var(--color-text); margin-top: 0.5rem;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.75rem;">
<strong style="font-size: 0.875rem; color: var(--color-primary);">KI-Vertrauenswertung</strong>
<span style="background-color: ${confidenceColor}; color: white; font-weight: 600; padding: 0.125rem 0.375rem; border-radius: 0.25rem; font-size: 0.625rem;">${confidence.overall}%</span>
<div class="confidence-tooltip hidden absolute top-full right-0 z-50 bg-primary text-white p-4 rounded-lg shadow-lg text-xs" style="min-width: 320px; max-width: 400px; margin-top: 0.5rem;">
<div class="flex justify-between items-center mb-3">
<strong class="text-sm">KI-Vertrauenswertung</strong>
<span class="font-semibold px-2 py-1 rounded text-xs" style="background-color: ${confidenceColor};">${confidence.overall}%</span>
</div>
<div style="display: grid; grid-template-columns: 1fr; gap: 0.625rem; margin-bottom: 0.75rem;">
<div style="background: var(--color-bg-secondary); padding: 0.5rem; border-radius: 0.375rem; border-left: 3px solid var(--color-accent);">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.25rem;">
<span style="font-weight: 600; font-size: 0.6875rem; color: var(--color-text);">🔍 Semantische Relevanz</span>
<strong style="color: var(--color-accent);">${confidence.semanticRelevance}%</strong>
<div class="grid gap-2 mb-3">
<div class="bg-secondary p-2 rounded border-l-4" style="border-left-color: var(--color-accent);">
<div class="flex justify-between items-center mb-1">
<span class="font-semibold text-xs">🔍 Semantische Relevanz</span>
<strong class="text-accent">${confidence.semanticRelevance}%</strong>
</div>
<div style="font-size: 0.625rem; color: var(--color-text-secondary); line-height: 1.3;">
<div class="text-xs text-secondary leading-tight">
Wie gut die Tool-Beschreibung semantisch zu Ihrer Anfrage passt
</div>
</div>
<div style="background: var(--color-bg-secondary); padding: 0.5rem; border-radius: 0.375rem; border-left: 3px solid var(--color-primary);">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.25rem;">
<span style="font-weight: 600; font-size: 0.6875rem; color: var(--color-text);">🎯 Aufgaben-Eignung</span>
<strong style="color: var(--color-primary);">${confidence.taskSuitability}%</strong>
<div class="bg-secondary p-2 rounded border-l-4" style="border-left-color: var(--color-primary);">
<div class="flex justify-between items-center mb-1">
<span class="font-semibold text-xs">🎯 Aufgaben-Eignung</span>
<strong class="text-primary">${confidence.taskSuitability}%</strong>
</div>
<div style="font-size: 0.625rem; color: var(--color-text-secondary); line-height: 1.3;">
<div class="text-xs text-secondary leading-tight">
KI-bewertete Eignung für Ihre spezifische Aufgabenstellung
</div>
</div>
</div>
${confidence.strengthIndicators && confidence.strengthIndicators.length > 0 ? `
<div style="margin-bottom: 0.75rem; padding: 0.5rem; background: var(--color-oss-bg); border-radius: 0.375rem; border-left: 3px solid var(--color-accent);">
<strong style="color: var(--color-accent); font-size: 0.6875rem; display: flex; align-items: center; gap: 0.25rem; margin-bottom: 0.375rem;">
<div class="mb-3 p-2 rounded border-l-4" style="background-color: var(--color-oss-bg); border-left-color: var(--color-accent);">
<strong class="text-accent text-xs flex items-center gap-1 mb-1">
<span>✓</span> Stärken dieser Empfehlung:
</strong>
<ul style="margin: 0; padding-left: 1rem; font-size: 0.625rem; line-height: 1.4; color: var(--color-text);">
${confidence.strengthIndicators.slice(0, 3).map(s => `<li style="margin-bottom: 0.25rem;">${sanitizeText(s)}</li>`).join('')}
<ul class="ml-4 text-xs leading-normal">
${confidence.strengthIndicators.slice(0, 3).map(s => `<li class="mb-1">${sanitizeText(s)}</li>`).join('')}
</ul>
</div>
` : ''}
${confidence.uncertaintyFactors && confidence.uncertaintyFactors.length > 0 ? `
<div style="padding: 0.5rem; background: var(--color-hosted-bg); border-radius: 0.375rem; border-left: 3px solid var(--color-warning);">
<strong style="color: var(--color-warning); font-size: 0.6875rem; display: flex; align-items: center; gap: 0.25rem; margin-bottom: 0.375rem;">
<div class="p-2 rounded border-l-4" style="background-color: var(--color-hosted-bg); border-left-color: var(--color-warning);">
<strong class="text-warning text-xs flex items-center gap-1 mb-1">
<span>⚠</span> Mögliche Einschränkungen:
</strong>
<ul style="margin: 0; padding-left: 1rem; font-size: 0.625rem; line-height: 1.4; color: var(--color-text);">
${confidence.uncertaintyFactors.slice(0, 3).map(f => `<li style="margin-bottom: 0.25rem;">${sanitizeText(f)}</li>`).join('')}
<ul class="ml-4 text-xs leading-normal">
${confidence.uncertaintyFactors.slice(0, 3).map(f => `<li class="mb-1">${sanitizeText(f)}</li>`).join('')}
</ul>
</div>
` : ''}
<div style="margin-top: 0.75rem; padding-top: 0.75rem; border-top: 1px solid var(--color-border); font-size: 0.625rem; color: var(--color-text-secondary); text-align: center;">
<div class="mt-3 pt-3 border-t border-secondary text-xs text-secondary text-center">
Forensisch fundierte KI-Analyse
</div>
</div>
@ -1958,9 +1946,9 @@ class AIQueryInterface {
if (!suggestion) return '';
return `
<div class="card" style="margin-top: 2rem; border-left: 4px solid var(--color-accent);">
<h4 style="margin: 0 0 1rem 0; color: var(--color-accent);">Workflow-Empfehlung</h4>
<div style="margin: 0; line-height: 1.6; white-space: pre-wrap; word-wrap: break-word;">${sanitizeText(suggestion)}</div>
<div class="card mt-8 border-l-4" style="border-left-color: var(--color-accent);">
<h4 class="mb-4 text-accent">Workflow-Empfehlung</h4>
<div class="leading-relaxed">${sanitizeText(suggestion)}</div>
</div>
`;
}
@ -1969,9 +1957,9 @@ class AIQueryInterface {
if (!considerations) return '';
return `
<div class="card" style="margin-top: 2rem; background-color: var(--color-bg-secondary); border-left: 4px solid var(--color-text-secondary);">
<h4 style="margin: 0 0 1rem 0; color: var(--color-text-secondary);">Zusätzliche Überlegungen</h4>
<div style="margin: 0; line-height: 1.6; white-space: pre-wrap; word-wrap: break-word;">${sanitizeText(considerations)}</div>
<div class="card mt-8 bg-secondary border-l-4" style="border-left-color: var(--color-text-secondary);">
<h4 class="mb-4 text-secondary">Zusätzliche Überlegungen</h4>
<div class="leading-relaxed">${sanitizeText(considerations)}</div>
</div>
`;
}
@ -1980,20 +1968,20 @@ class AIQueryInterface {
if (!pros?.length && !cons?.length) return '';
return `
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-bottom: 1.5rem;">
<div class="grid grid-cols-2 gap-4 mb-6">
${pros?.length ? `
<div style="background-color: var(--color-oss-bg); padding: 1rem; border-radius: 0.5rem; border-left: 3px solid var(--color-accent);">
<h5 style="margin: 0 0 0.5rem 0; color: var(--color-accent); font-size: 0.875rem;">✓ Vorteile</h5>
<ul style="margin: 0; padding-left: 1rem;">
${pros.map(pro => `<li style="margin-bottom: 0.25rem;">${sanitizeText(pro)}</li>`).join('')}
<div class="card-info-sm border-l-4" style="border-left-color: var(--color-accent); background-color: var(--color-oss-bg);">
<h5 class="mb-2 text-accent text-sm">✓ Vorteile</h5>
<ul class="ml-4">
${pros.map(pro => `<li class="mb-1">${sanitizeText(pro)}</li>`).join('')}
</ul>
</div>
` : ''}
${cons?.length ? `
<div style="background-color: var(--color-hosted-bg); padding: 1rem; border-radius: 0.5rem; border-left: 3px solid var(--color-warning);">
<h5 style="margin: 0 0 0.5rem 0; color: var(--color-warning); font-size: 0.875rem;">✗ Nachteile</h5>
<ul style="margin: 0; padding-left: 1rem;">
${cons.map(con => `<li style="margin-bottom: 0.25rem;">${sanitizeText(con)}</li>`).join('')}
<div class="card-info-sm border-l-4" style="border-left-color: var(--color-warning); background-color: var(--color-hosted-bg);">
<h5 class="mb-2 text-warning text-sm">✗ Nachteile</h5>
<ul class="ml-4">
${cons.map(con => `<li class="mb-1">${sanitizeText(con)}</li>`).join('')}
</ul>
</div>
` : ''}
@ -2005,7 +1993,7 @@ class AIQueryInterface {
const isMethod = tool.type === 'method';
return `
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 0.75rem; font-size: 0.8125rem; color: var(--color-text-secondary); margin-bottom: 1rem; padding: 0.75rem; background-color: var(--color-bg-secondary); border-radius: 0.375rem;">
<div class="grid grid-auto-fit gap-3 text-sm text-secondary mb-4 p-3 bg-secondary rounded">
${!isMethod ? `<div><strong>Plattformen:</strong> ${tool.platforms.join(', ')}</div>` : ''}
<div><strong>Skill Level:</strong> ${tool.skillLevel}</div>
${!isMethod ? `<div><strong>Lizenz:</strong> ${tool.license}</div>` : ''}
@ -2016,9 +2004,9 @@ class AIQueryInterface {
renderAlternatives(alternatives) {
return `
<div style="background-color: var(--color-bg-secondary); padding: 1rem; border-radius: 0.5rem; margin-bottom: 1rem;">
<h5 style="margin: 0 0 0.5rem 0; color: var(--color-text-secondary); font-size: 0.875rem;">Alternative Ansätze</h5>
<div style="margin: 0; line-height: 1.6; white-space: pre-wrap; word-wrap: break-word;">${sanitizeText(alternatives)}</div>
<div class="bg-secondary p-4 rounded mb-4">
<h5 class="mb-2 text-secondary text-sm">Alternative Ansätze</h5>
<div class="leading-relaxed">${sanitizeText(alternatives)}</div>
</div>
`;
}