Agentic-Reliability-Framework-API / ui /modern_components.py
petter2025's picture
Update ui/modern_components.py
1ee33ac verified
raw
history blame
57.6 kB
"""
ui/modern_components.py - ENHANCED VERSION
🚀 Modern UI Components for ARF v3.3.9 with Complete Psychological Integration
Features:
1. Design token system with CSS variables
2. All psychological features (observation gate, sequencing, historical evidence, healing intent)
3. Accessibility (ARIA labels, keyboard nav)
4. Performance optimizations
5. Dark mode support
6. Integration with arf_modern_ui.py systems
"""
import json
from datetime import datetime, timezone
from typing import Dict, List, Any, Optional, Tuple
import plotly.graph_objects as go
import plotly.express as px
import numpy as np
# ===========================================
# DESIGN TOKEN SYSTEM - ALIGNED WITH arf_modern_ui.py
# ===========================================
DESIGN_TOKENS = {
"colors": {
"primary": {
"50": "#eff6ff",
"100": "#dbeafe",
"200": "#bfdbfe",
"300": "#93c5fd",
"400": "#60a5fa",
"500": "#3b82f6", # enterprise_primary
"600": "#2563eb",
"700": "#1d4ed8",
"800": "#1e40af",
"900": "#1e3a8a"
},
"success": {
"50": "#f0fdf4",
"100": "#dcfce7",
"200": "#bbf7d0",
"300": "#86efac",
"400": "#4ade80",
"500": "#22c55e", # success
"600": "#16a34a",
"700": "#15803d",
"800": "#166534",
"900": "#14532d"
},
"warning": {
"50": "#fffbeb",
"100": "#fef3c7",
"200": "#fde68a",
"300": "#fcd34d",
"400": "#fbbf24",
"500": "#f59e0b", # warning
"600": "#d97706",
"700": "#b45309",
"800": "#92400e",
"900": "#78350f"
},
"danger": {
"50": "#fef2f2",
"100": "#fee2e2",
"200": "#fecaca",
"300": "#fca5a5",
"400": "#f87171",
"500": "#ef4444", # danger
"600": "#dc2626",
"700": "#b91c1c",
"800": "#991b1b",
"900": "#7f1d1d"
},
"neutral": {
"50": "#f8fafc",
"100": "#f1f5f9",
"200": "#e2e8f0",
"300": "#cbd5e1",
"400": "#94a3b8",
"500": "#64748b",
"600": "#475569",
"700": "#334155",
"800": "#1e293b",
"900": "#0f172a"
}
},
"spacing": {
"1": "0.25rem",
"2": "0.5rem",
"3": "0.75rem",
"4": "1rem",
"5": "1.25rem",
"6": "1.5rem",
"8": "2rem",
"10": "2.5rem",
"12": "3rem",
"16": "4rem",
"20": "5rem"
},
"typography": {
"fontSizes": {
"xs": "0.75rem",
"sm": "0.875rem",
"base": "1rem",
"lg": "1.125rem",
"xl": "1.25rem",
"2xl": "1.5rem",
"3xl": "1.875rem",
"4xl": "2.25rem"
},
"fontWeights": {
"light": "300",
"normal": "400",
"medium": "500",
"semibold": "600",
"bold": "700",
"extrabold": "800"
}
},
"breakpoints": {
"sm": "640px",
"md": "768px",
"lg": "1024px",
"xl": "1280px",
"2xl": "1536px"
},
"shadows": {
"sm": "0 1px 2px 0 rgb(0 0 0 / 0.05)",
"md": "0 4px 6px -1px rgb(0 0 0 / 0.1)",
"lg": "0 10px 15px -3px rgb(0 0 0 / 0.1)",
"xl": "0 20px 25px -5px rgb(0 0 0 / 0.1)"
},
"borderRadius": {
"sm": "0.25rem",
"md": "0.375rem",
"lg": "0.5rem",
"xl": "0.75rem",
"2xl": "1rem",
"full": "9999px"
}
}
# ===========================================
# CSS VARIABLES INJECTION
# ===========================================
def inject_design_tokens() -> str:
"""Inject CSS variables for design tokens into the page"""
css_variables = []
# Convert design tokens to CSS variables
for category, values in DESIGN_TOKENS.items():
if isinstance(values, dict):
for key, value in values.items():
if isinstance(value, dict):
for subkey, subvalue in value.items():
css_variables.append(f"--{category}-{key}-{subkey}: {subvalue};")
else:
css_variables.append(f"--{category}-{key}: {value};")
return f"""
<style id="design-tokens">
:root {{
{chr(10).join(css_variables)}
/* Semantic aliases matching arf_modern_ui.py */
--color-enterprise-primary: var(--colors-primary-500);
--color-success: var(--colors-success-500);
--color-warning: var(--colors-warning-500);
--color-danger: var(--colors-danger-500);
--color-oss-primary: var(--colors-success-500);
--color-surface-light: #ffffff;
--color-surface-dark: var(--colors-neutral-800);
--color-background-light: var(--colors-neutral-50);
--color-background-dark: var(--colors-neutral-900);
/* Spacing aliases */
--spacing-xs: var(--spacing-2);
--spacing-sm: var(--spacing-3);
--spacing-md: var(--spacing-4);
--spacing-lg: var(--spacing-6);
--spacing-xl: var(--spacing-8);
/* Font families */
--font-sans: system-ui, -apple-system, sans-serif;
--font-mono: 'JetBrains Mono', 'SF Mono', Monaco, 'Cascadia Code', monospace;
/* Transitions matching arf_modern_ui.py */
--transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
--transition-normal: 300ms cubic-bezier(0.4, 0, 0.2, 1);
--transition-slow: 500ms cubic-bezier(0.4, 0, 0.2, 1);
}}
/* Dark mode overrides */
[data-theme="dark"] {{
--colors-neutral-50: #0f172a;
--colors-neutral-100: #1e293b;
--colors-neutral-200: #334155;
--colors-neutral-300: #475569;
--colors-neutral-400: #64748b;
--colors-neutral-500: #94a3b8;
--colors-neutral-600: #cbd5e1;
--colors-neutral-700: #e2e8f0;
--colors-neutral-800: #f1f5f9;
--colors-neutral-900: #f8fafc;
}}
/* Utility classes */
.sr-only {{
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}}
.focus-ring {{
outline: 2px solid var(--color-enterprise-primary);
outline-offset: 2px;
}}
.focus-ring:focus:not(:focus-visible) {{
outline: none;
}}
@media (prefers-reduced-motion: reduce) {{
*,
*::before,
*::after {{
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}}
}}
</style>
"""
# ===========================================
# BASE COMPONENT CLASS
# ===========================================
class ModernComponent:
"""Base class for all modern components with consistent styling"""
def __init__(self):
self.component_id = f"component_{datetime.now().timestamp()}"
@staticmethod
def create_container(children: str, **kwargs) -> str:
"""Create a responsive container"""
classes = kwargs.get('classes', '')
style = kwargs.get('style', '')
return f"""
<div class="container {classes}" style="{style}">
{children}
</div>
"""
@staticmethod
def create_section(title: str = "", children: str = "", **kwargs) -> str:
"""Create a semantic section with optional title"""
section_id = kwargs.get('id', '')
aria_label = kwargs.get('aria_label', title)
title_html = f'<h2 class="section-title">{title}</h2>' if title else ''
return f"""
<section id="{section_id}" class="section" aria-label="{aria_label}">
{title_html}
<div class="section-content">
{children}
</div>
</section>
"""
# ===========================================
# ATOMIC COMPONENTS
# ===========================================
class Card(ModernComponent):
"""Card component with multiple variants"""
@staticmethod
def create(content: str, **kwargs) -> str:
"""Create a card with optional header and footer"""
title = kwargs.get('title', '')
footer = kwargs.get('footer', '')
variant = kwargs.get('variant', 'default') # default, elevated, outlined, filled
border_color = kwargs.get('border_color', 'var(--colors-neutral-200)')
variant_classes = {
'default': 'card-default',
'elevated': 'card-elevated',
'outlined': 'card-outlined',
'filled': 'card-filled'
}
header_html = f"""
<div class="card-header">
<h3 class="card-title">{title}</h3>
</div>
""" if title else ''
footer_html = f"""
<div class="card-footer">
{footer}
</div>
""" if footer else ''
return f"""
<div class="card {variant_classes.get(variant, 'card-default')}"
style="--border-color: {border_color};">
{header_html}
<div class="card-body">
{content}
</div>
{footer_html}
</div>
"""
@staticmethod
def create_metric(value: str, label: str, **kwargs) -> str:
"""Create a metric card for KPIs"""
trend = kwargs.get('trend', None) # 'up', 'down', 'neutral'
change = kwargs.get('change', '')
trend_icon = {
'up': '↗',
'down': '↘',
'neutral': '→'
}.get(trend, '')
trend_color = {
'up': 'var(--color-success)',
'down': 'var(--color-danger)',
'neutral': 'var(--colors-neutral-500)'
}.get(trend, 'var(--colors-neutral-500)')
return f"""
<div class="card card-metric" role="status" aria-label="{label}: {value}">
<div class="metric-value" aria-live="polite">{value}</div>
<div class="metric-label">{label}</div>
{f'<div class="metric-trend" style="color: {trend_color};">{trend_icon} {change}</div>' if trend else ''}
</div>
"""
# ===========================================
# CRITICAL PSYCHOLOGICAL COMPONENTS
# ===========================================
class ObservationGate(ModernComponent):
"""Observation gate component showing system restraint - PSYCHOLOGICAL CORE"""
@staticmethod
def create(confidence: float = 65.0, **kwargs) -> str:
"""Create observation gate display with psychological restraint"""
reason = kwargs.get('reason', 'uncertainty_too_high_for_action')
frozen_until = kwargs.get('frozen_until', '')
threshold = 70.0
is_blocked = confidence < threshold
# Format countdown if available
countdown_html = ""
if frozen_until:
try:
frozen_dt = datetime.fromisoformat(frozen_until.replace("Z", "+00:00"))
now = datetime.now(timezone.utc)
if frozen_dt.tzinfo is None:
frozen_dt = frozen_dt.replace(tzinfo=timezone.utc)
time_left = frozen_dt - now
minutes_left = max(0, int(time_left.total_seconds() / 60))
countdown_html = f"""
<div class="countdown">
<div class="countdown-label">Next evaluation:</div>
<div class="countdown-timer">{minutes_left}:00</div>
</div>
"""
except:
countdown_html = """
<div class="countdown">
<div class="countdown-label">Next evaluation:</div>
<div class="countdown-timer">5:00</div>
</div>
"""
status_text = "Observation Gate: Awaiting confirmation" if is_blocked else "Observation Gate Cleared"
status_color = "var(--color-warning)" if is_blocked else "var(--color-success)"
icon = "⏳" if is_blocked else "✅"
# Psychological messaging
restraint_message = """
<div class="psych-message">
<h4>Decision Intentionally Deferred</h4>
<p>The system has detected uncertainty (<strong>{confidence:.1f}% confidence</strong>)
and has <strong>chosen to observe</strong> rather than act. Historical evidence indicates
premature action increases risk by <strong>47%</strong>, so the system is enforcing an observation-first policy.</p>
<p class="psych-note"><em>"What you are seeing is not waiting. It is judgment under uncertainty."</em></p>
</div>
""" if is_blocked else """
<div class="psych-message">
<h4>Proceed with Policy Action</h4>
<p>Confidence exceeds threshold. System may proceed with sequenced actions.
Historical evidence will be consulted before any execution.</p>
</div>
"""
return f"""
<div class="observation-gate" style="--status-color: {status_color};">
<div class="observation-gate-header">
<div class="observation-icon">{icon}</div>
<div class="observation-title">
<h3>{status_text}</h3>
<p>System restraint engaged</p>
</div>
<div class="observation-badge">
ACTIVE RESTRAINT
</div>
</div>
<div class="observation-content">
{restraint_message}
<div class="confidence-comparison">
<div class="confidence-item">
<div class="confidence-label">Confidence Threshold</div>
<div class="confidence-value">{threshold}%</div>
<div class="confidence-note">Required for action</div>
</div>
<div class="confidence-item">
<div class="confidence-label">Current Confidence</div>
<div class="confidence-value" style="color: {status_color};">{confidence:.1f}%</div>
<div class="confidence-note">{"Below threshold → Observe" if is_blocked else "Above threshold → Proceed"}</div>
</div>
</div>
<div class="confidence-visualization">
<div class="confidence-scale">
<div class="scale-marker" style="left: {confidence}%;"></div>
<div class="scale-bar" style="width: {confidence}%; background: {status_color};"></div>
</div>
<div class="scale-labels">
<span>{"Observe" if is_blocked else "Ready"} ({confidence:.1f}%)</span>
<span>Threshold ({threshold}%)</span>
<span>{"Act" if is_blocked else "Proceed"} (75%+)</span>
</div>
</div>
{countdown_html}
<div class="prevented-actions">
<h5>Prevented Actions (Contraindicated)</h5>
<div class="action-tags">
<span class="action-tag">scale_during_retry_storm</span>
<span class="action-tag">add_capacity_during_amplification</span>
<span class="action-tag">any_action_during_high_uncertainty</span>
</div>
</div>
</div>
</div>
"""
class SequencingFlow(ModernComponent):
"""Visualization of policy-enforced sequencing - PSYCHOLOGICAL CORE"""
@staticmethod
def create(steps: List[Dict[str, Any]] = None, **kwargs) -> str:
"""Create sequencing flow visualization"""
if steps is None:
steps = [
{"title": "Dampening", "description": "Prevent amplification first", "badge": "REQUIRED"},
{"title": "Concurrency", "description": "Manage load, then observe", "badge": "REQUIRED"},
{"title": "Observe", "description": "Validate trends for 5+ minutes", "badge": "REQUIRED"},
{"title": "Scale", "description": "Only if all previous succeed", "badge": "OPTIONAL"}
]
current_step = kwargs.get('current_step', 0)
steps_html = []
for i, step in enumerate(steps):
is_current = i == current_step
is_completed = i < current_step
is_future = i > current_step
status_class = 'completed' if is_completed else 'current' if is_current else 'future'
steps_html.append(f"""
<div class="sequencing-step {status_class}" data-step="{i}">
<div class="step-number">{i + 1}</div>
<div class="step-content">
<div class="step-title">{step.get('title', 'Step')}</div>
<div class="step-description">{step.get('description', '')}</div>
<div class="step-badge">{step.get('badge', 'REQUIRED')}</div>
</div>
</div>
""")
# Add connecting lines
connectors_html = '<div class="step-connectors">'
for i in range(len(steps) - 1):
is_completed = i < current_step
connector_class = 'completed' if is_completed else ''
connectors_html += f'<div class="step-connector {connector_class}"></div>'
connectors_html += '</div>'
return f"""
<div class="sequencing-flow">
<div class="sequencing-header">
<h3>🔄 Doctrinal Sequencing: Policy Over Reaction</h3>
<p>System enforces sequencing regardless of prediction confidence</p>
<div class="policy-badge">POLICY ENFORCED</div>
</div>
<div class="sequencing-steps">
{connectors_html}
{''.join(steps_html)}
</div>
<div class="sequencing-constraint">
<div class="constraint-icon">🎯</div>
<div class="constraint-content">
<h4>Doctrinal Constraint: Scaling Cannot Appear First</h4>
<p>If retry amplification is detected, scaling is <strong>contraindicated entirely</strong>.
The system must observe stabilization before considering capacity increases.
Historical evidence shows scaling-first fails <strong>76%</strong> of the time during amplification.</p>
<p class="psych-note"><em>"What happened is more important than what might happen."</em></p>
</div>
</div>
</div>
"""
class ProcessDisplay(ModernComponent):
"""Display for ARF processes (Detection, Recall, Decision) - PSYCHOLOGICAL CORE"""
@staticmethod
def create(process_type: str, data: Dict[str, Any]) -> str:
"""Create process display card"""
icons = {
'detection': '🕵️‍♂️',
'recall': '🧠',
'decision': '🎯',
'safety': '🛡️',
'execution': '⚡',
'learning': '📚'
}
status_colors = {
'active': 'var(--color-success)',
'inactive': 'var(--colors-neutral-400)',
'error': 'var(--color-danger)'
}
icon = icons.get(process_type, '📊')
status = data.get('status', 'inactive')
title = data.get('title', process_type.title())
description = data.get('description', '')
# Metrics display
metrics_html = ""
if 'metrics' in data:
metrics = data['metrics']
metrics_html = '<div class="process-metrics">'
for key, value in metrics.items():
metrics_html += f"""
<div class="process-metric">
<div class="metric-key">{key}</div>
<div class="metric-value">{value}</div>
</div>
"""
metrics_html += '</div>'
# Next step
next_step_html = ""
if 'next_step' in data:
next_step_html = f"""
<div class="process-next-step">
<div class="next-step-label">Next Step:</div>
<div class="next-step-value">{data['next_step']}</div>
</div>
"""
# Content with psychological emphasis
content_html = data.get('content', '')
if process_type == 'recall' and 'historical_evidence' in data:
content_html += f"""
<div class="psych-emphasis">
<div class="emphasis-icon">🧠</div>
<div class="emphasis-content">
<strong>Recall Dominance:</strong> Historical evidence outweighs predictive confidence.
The system prioritizes what <em>has happened</em> over what <em>might happen</em>.
</div>
</div>
"""
return f"""
<div class="process-card" data-process="{process_type}" data-status="{status}">
<div class="process-header">
<div class="process-icon">{icon}</div>
<div class="process-title">
<h4>{title}</h4>
<p>{description}</p>
</div>
<div class="process-status" style="--status-color: {status_colors.get(status, 'var(--colors-neutral-400)')};">
STATUS: {status.upper()}
</div>
</div>
<div class="process-body">
{metrics_html}
{content_html}
{next_step_html}
</div>
</div>
"""
class HistoricalEvidencePanel(ModernComponent):
"""Historical evidence panel - PSYCHOLOGICAL CORE (Recall Dominance)"""
@staticmethod
def create(evidence_data: Dict[str, Any] = None, **kwargs) -> str:
"""Create historical evidence panel showing recall dominance"""
if evidence_data is None:
evidence_data = {
"scaling_failures": [
{
"date": "2024-11-15",
"environment": "prod-east",
"action": "Scale during retry storm",
"outcome": "Amplification increased 300%",
"lesson": "Scaling during amplification worsens the problem"
},
{
"date": "2024-09-22",
"environment": "staging",
"action": "Add capacity without dampening",
"outcome": "45 min outage, $8.2K loss",
"lesson": "New capacity consumed by amplification loop"
}
],
"dampening_successes": [
{
"date": "2024-12-03",
"environment": "prod-west",
"action": "Request coalescing + backoff",
"outcome": "Resolved in 8 min, $5.1K saved",
"lesson": "Dampening broke amplification cycle"
},
{
"date": "2024-10-17",
"environment": "prod-eu",
"action": "Circuit breaker + observability",
"outcome": "12 min recovery, 0 user impact",
"lesson": "Sequencing prevented escalation"
}
]
}
# Build failures HTML
failures_html = ""
for i, failure in enumerate(evidence_data.get('scaling_failures', [])[:3]):
failures_html += f"""
<div class="evidence-item evidence-failure">
<div class="evidence-header">
<div class="evidence-date">{failure.get('date', 'Unknown')}{failure.get('environment', 'Unknown')}</div>
<div class="evidence-badge failure">FAILED</div>
</div>
<div class="evidence-content">
<div class="evidence-action"><strong>Action:</strong> {failure.get('action', 'Unknown')}</div>
<div class="evidence-outcome"><strong>Outcome:</strong> {failure.get('outcome', 'Unknown')}</div>
<div class="evidence-lesson">"{failure.get('lesson', 'No lesson captured')}"</div>
</div>
</div>
"""
# Build successes HTML
successes_html = ""
for i, success in enumerate(evidence_data.get('dampening_successes', [])[:3]):
successes_html += f"""
<div class="evidence-item evidence-success">
<div class="evidence-header">
<div class="evidence-date">{success.get('date', 'Unknown')}{success.get('environment', 'Unknown')}</div>
<div class="evidence-badge success">SUCCESS</div>
</div>
<div class="evidence-content">
<div class="evidence-action"><strong>Action:</strong> {success.get('action', 'Unknown')}</div>
<div class="evidence-outcome"><strong>Outcome:</strong> {success.get('outcome', 'Unknown')}</div>
<div class="evidence-lesson">"{success.get('lesson', 'No lesson captured')}"</div>
</div>
</div>
"""
return f"""
<div class="historical-evidence-panel">
<div class="evidence-header-main">
<div>
<h3>🧠 Historical Evidence (Why Sequencing Matters)</h3>
<p>Real outcomes from similar incidents—this evidence dominates decision logic</p>
</div>
<div class="evidence-dominance-badge">
Historical evidence outweighs model confidence
</div>
</div>
<div class="evidence-comparison">
<div class="evidence-column">
<div class="column-header failure">
<span>⛔</span> Scaling-First Failures
</div>
{failures_html if failures_html else '''
<div class="evidence-empty">
<div class="empty-icon">📊</div>
<div class="empty-text">Scaling-First Failures (Evidence Present)</div>
</div>
'''}
</div>
<div class="evidence-column">
<div class="column-header success">
<span>✅</span> Dampening-First Successes
</div>
{successes_html if successes_html else '''
<div class="evidence-empty">
<div class="empty-icon">📊</div>
<div class="empty-text">Dampening-First Successes (Evidence Present)</div>
</div>
'''}
</div>
</div>
<div class="psych-principle">
<div class="principle-icon">🎯</div>
<div class="principle-content">
<h4>If history shows failure, the system will not repeat it.</h4>
<p>The system prioritizes <strong>historical evidence over predictive confidence</strong>.
If scaling-first failed in similar conditions, scaling is contraindicated regardless of model confidence.</p>
<p class="psych-note"><em>"What happened is more important than what might happen."</em></p>
</div>
</div>
</div>
"""
class HealingIntentDisplay(ModernComponent):
"""Formal HealingIntent display - PSYCHOLOGICAL CORE"""
@staticmethod
def create(healing_intent: Dict[str, Any], **kwargs) -> str:
"""Create formal HealingIntent display with all fields"""
confidence = healing_intent.get('confidence', 0.0)
primary_action = healing_intent.get('primary_action', '')
sequencing_rule = healing_intent.get('sequencing_rule', '')
preconditions = healing_intent.get('preconditions', [])
contraindications = healing_intent.get('contraindications', [])
reversibility = healing_intent.get('reversibility_statement', '')
historical_evidence = healing_intent.get('historical_evidence', [])
# Preconditions HTML
preconditions_html = ""
if preconditions:
preconditions_html = "<div class='preconditions-list'>"
for pre in preconditions:
preconditions_html += f"<div class='precondition-item'>• {pre}</div>"
preconditions_html += "</div>"
# Contraindications HTML
contraindications_html = ""
if contraindications:
contraindications_html = "<div class='contraindications-list'>"
for contra in contraindications:
contraindications_html += f"<div class='contraindication-item'>⛔ {contra}</div>"
contraindications_html += "</div>"
# Historical evidence HTML
historical_html = ""
if historical_evidence:
historical_html = "<div class='historical-list'>"
for evidence in historical_evidence:
historical_html += f"<div class='historical-item'>📊 {evidence}</div>"
historical_html += "</div>"
return f"""
<div class="healing-intent-display">
<div class="intent-header">
<div>
<h3>📝 Formal HealingIntent Created</h3>
<p>Preconditions checked, contraindications listed, reversibility guaranteed</p>
</div>
<div class="confidence-badge" style="--confidence-color: {'' if confidence >= 70 else 'var(--color-warning)'};">
CONFIDENCE: {confidence:.1f}%
</div>
</div>
<div class="intent-grid">
<div class="intent-section">
<div class="section-title">Primary Action</div>
<div class="section-content primary-action">
{primary_action}
</div>
</div>
<div class="intent-section">
<div class="section-title">Sequencing Rule</div>
<div class="section-content sequencing-rule">
{sequencing_rule}
</div>
</div>
</div>
<div class="intent-details">
<div class="detail-section">
<div class="detail-title">Preconditions</div>
<div class="detail-content">
{preconditions_html if preconditions_html else '<div class="empty-detail">No preconditions specified</div>'}
</div>
</div>
<div class="detail-section">
<div class="detail-title">Contraindications</div>
<div class="detail-content">
{contraindications_html if contraindications_html else '<div class="empty-detail">No contraindications</div>'}
</div>
</div>
<div class="detail-section">
<div class="detail-title">Reversibility Statement</div>
<div class="detail-content reversibility">
{reversibility if reversibility else '<div class="empty-detail">No reversibility statement</div>'}
</div>
</div>
</div>
{historical_html if historical_html else ''}
<div class="psych-doctrine">
<div class="doctrine-icon">⚖️</div>
<div class="doctrine-content">
<h4>Doctrinal Principle: Formal Documentation Prevents Mistakes</h4>
<p>Every HealingIntent must document preconditions, contraindications, and reversibility.
This formal structure ensures decisions are reviewable, reversible, and grounded in evidence.</p>
</div>
</div>
</div>
"""
# ===========================================
# COMPONENT STYLES (CSS) - ENHANCED
# ===========================================
def create_component_styles() -> str:
"""Create all component styles with psychological enhancements"""
return """
<style>
/* Base styles */
body, .gr-box, .gr-form, .gr-panel, .gr-tab, .gr-container {
background-color: var(--color-background-light) !important;
color: var(--colors-neutral-900) !important;
font-family: var(--font-sans);
}
[data-theme="dark"] body,
[data-theme="dark"] .gr-box,
[data-theme="dark"] .gr-form,
[data-theme="dark"] .gr-panel,
[data-theme="dark"] .gr-tab,
[data-theme="dark"] .gr-container {
background-color: var(--color-background-dark) !important;
color: var(--colors-neutral-100) !important;
}
/* Card styles */
.card {
background: var(--color-surface-light);
border-radius: var(--borderRadius-lg);
padding: var(--spacing-6);
border: 1px solid var(--border-color, var(--colors-neutral-200));
transition: box-shadow var(--transition-normal);
color: var(--colors-neutral-900);
}
[data-theme="dark"] .card {
background: var(--color-surface-dark);
border-color: var(--colors-neutral-700);
color: var(--colors-neutral-100);
}
.card:hover {
box-shadow: var(--shadows-md);
}
/* Observation gate styles */
.observation-gate {
border: 3px solid var(--status-color, var(--color-warning));
border-radius: var(--borderRadius-xl);
padding: var(--spacing-6);
background: linear-gradient(135deg,
color-mix(in srgb, var(--status-color, var(--color-warning)) 5%, transparent),
color-mix(in srgb, var(--status-color, var(--color-warning)) 10%, transparent));
margin: var(--spacing-6) 0;
color: var(--colors-neutral-900);
}
[data-theme="dark"] .observation-gate {
color: var(--colors-neutral-100);
}
.observation-gate-header {
display: flex;
align-items: center;
gap: var(--spacing-4);
margin-bottom: var(--spacing-4);
}
.observation-icon {
font-size: 48px;
color: var(--status-color, var(--color-warning));
}
.observation-title h3 {
margin: 0;
color: color-mix(in srgb, var(--status-color, var(--color-warning)) 90%, var(--colors-neutral-900));
font-size: var(--typography-fontSizes-2xl);
font-weight: var(--typography-fontWeights-bold);
}
.observation-title p {
margin: var(--spacing-1) 0 0 0;
color: color-mix(in srgb, var(--status-color, var(--color-warning)) 70%, var(--colors-neutral-700));
}
.observation-badge {
margin-left: auto;
padding: var(--spacing-2) var(--spacing-4);
background: var(--status-color, var(--color-warning));
color: white;
border-radius: var(--borderRadius-full);
font-size: var(--typography-fontSizes-xs);
font-weight: var(--typography-fontWeights-bold);
text-transform: uppercase;
letter-spacing: 1px;
}
.psych-message {
background: white;
border: 2px solid var(--status-color, var(--color-warning));
padding: var(--spacing-4);
margin: var(--spacing-4) 0;
border-radius: var(--borderRadius-lg);
}
[data-theme="dark"] .psych-message {
background: var(--colors-neutral-800);
}
.psych-message h4 {
margin: 0 0 var(--spacing-2) 0;
color: var(--colors-neutral-900);
font-size: var(--typography-fontSizes-lg);
}
.psych-message p {
margin: var(--spacing-2) 0;
color: var(--colors-neutral-700);
line-height: 1.6;
}
.psych-note {
font-style: italic;
color: var(--colors-neutral-600);
margin-top: var(--spacing-2);
border-left: 3px solid var(--status-color, var(--color-warning));
padding-left: var(--spacing-3);
}
.confidence-comparison {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--spacing-4);
margin: var(--spacing-4) 0;
}
.confidence-item {
background: var(--color-surface-light);
border-radius: var(--borderRadius-lg);
padding: var(--spacing-4);
text-align: center;
border: 1px solid var(--colors-neutral-200);
}
[data-theme="dark"] .confidence-item {
background: var(--colors-neutral-800);
border-color: var(--colors-neutral-700);
}
.confidence-label {
font-size: var(--typography-fontSizes-sm);
color: var(--colors-neutral-600);
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: var(--spacing-2);
}
.confidence-value {
font-size: var(--typography-fontSizes-3xl);
font-weight: var(--typography-fontWeights-bold);
margin-bottom: var(--spacing-1);
}
.confidence-note {
font-size: var(--typography-fontSizes-xs);
color: var(--colors-neutral-500);
}
.confidence-visualization {
margin: var(--spacing-6) 0;
}
.confidence-scale {
height: 8px;
background: var(--colors-neutral-200);
border-radius: var(--borderRadius-full);
position: relative;
margin: var(--spacing-4) 0 var(--spacing-2);
}
.scale-bar {
height: 100%;
border-radius: var(--borderRadius-full);
transition: width var(--transition-normal);
}
.scale-marker {
position: absolute;
top: -4px;
width: 16px;
height: 16px;
background: white;
border: 2px solid var(--colors-neutral-900);
border-radius: 50%;
transform: translateX(-50%);
}
.scale-labels {
display: flex;
justify-content: space-between;
font-size: var(--typography-fontSizes-xs);
color: var(--colors-neutral-600);
}
.prevented-actions {
margin-top: var(--spacing-6);
padding-top: var(--spacing-4);
border-top: 2px solid var(--colors-neutral-200);
}
.prevented-actions h5 {
margin: 0 0 var(--spacing-3) 0;
color: var(--colors-neutral-700);
font-size: var(--typography-fontSizes-sm);
text-transform: uppercase;
letter-spacing: 0.05em;
}
.action-tags {
display: flex;
flex-wrap: wrap;
gap: var(--spacing-2);
}
.action-tag {
padding: var(--spacing-1) var(--spacing-3);
background: var(--color-danger);
color: white;
border-radius: var(--borderRadius-full);
font-size: var(--typography-fontSizes-xs);
font-weight: var(--typography-fontWeights-medium);
}
/* Sequencing flow styles */
.sequencing-flow {
background: var(--color-surface-light);
border: 2px solid var(--color-enterprise-primary);
border-radius: var(--borderRadius-xl);
padding: var(--spacing-6);
margin: var(--spacing-6) 0;
}
[data-theme="dark"] .sequencing-flow {
background: var(--colors-neutral-800);
}
.sequencing-header {
margin-bottom: var(--spacing-6);
text-align: center;
}
.sequencing-header h3 {
margin: 0 0 var(--spacing-2) 0;
color: var(--colors-neutral-900);
font-size: var(--typography-fontSizes-xl);
}
.sequencing-header p {
margin: 0;
color: var(--colors-neutral-600);
}
.policy-badge {
display: inline-block;
margin-top: var(--spacing-3);
padding: var(--spacing-2) var(--spacing-4);
background: var(--color-enterprise-primary);
color: white;
border-radius: var(--borderRadius-full);
font-size: var(--typography-fontSizes-xs);
font-weight: var(--typography-fontWeights-bold);
text-transform: uppercase;
letter-spacing: 1px;
}
.sequencing-steps {
display: flex;
justify-content: space-between;
align-items: center;
position: relative;
margin: var(--spacing-8) 0;
}
.step-connectors {
position: absolute;
top: 30px;
left: 60px;
right: 60px;
display: flex;
justify-content: space-between;
z-index: 1;
}
.step-connector {
flex: 1;
height: 3px;
background: var(--colors-neutral-300);
margin: 0 var(--spacing-2);
}
.step-connector.completed {
background: linear-gradient(90deg, var(--color-enterprise-primary), var(--color-success));
}
.sequencing-step {
text-align: center;
position: relative;
z-index: 2;
flex: 1;
}
.step-number {
width: 60px;
height: 60px;
background: var(--colors-neutral-100);
color: var(--colors-neutral-700);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto var(--spacing-3);
font-size: var(--typography-fontSizes-xl);
font-weight: var(--typography-fontWeights-bold);
border: 4px solid white;
transition: all var(--transition-normal);
}
.sequencing-step.current .step-number {
background: var(--color-enterprise-primary);
color: white;
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
}
.sequencing-step.completed .step-number {
background: var(--color-success);
color: white;
}
.step-title {
font-size: var(--typography-fontSizes-base);
font-weight: var(--typography-fontWeights-bold);
color: var(--colors-neutral-900);
margin-bottom: var(--spacing-1);
}
.step-description {
font-size: var(--typography-fontSizes-sm);
color: var(--colors-neutral-600);
margin-bottom: var(--spacing-2);
max-width: 180px;
margin: 0 auto;
}
.step-badge {
display: inline-block;
padding: var(--spacing-1) var(--spacing-3);
background: var(--colors-neutral-100);
color: var(--colors-neutral-700);
border-radius: var(--borderRadius-full);
font-size: var(--typography-fontSizes-xs);
font-weight: var(--typography-fontWeights-bold);
margin-top: var(--spacing-2);
}
.sequencing-step.current .step-badge {
background: var(--color-enterprise-primary);
color: white;
}
.sequencing-constraint {
background: var(--colors-neutral-50);
border-radius: var(--borderRadius-lg);
padding: var(--spacing-4);
border-left: 4px solid var(--color-enterprise-primary);
margin-top: var(--spacing-6);
}
[data-theme="dark"] .sequencing-constraint {
background: var(--colors-neutral-800);
}
.constraint-icon {
font-size: 24px;
color: var(--color-enterprise-primary);
margin-bottom: var(--spacing-2);
}
.constraint-content h4 {
margin: 0 0 var(--spacing-2) 0;
color: var(--colors-neutral-900);
font-size: var(--typography-fontSizes-lg);
}
.constraint-content p {
margin: 0;
color: var(--colors-neutral-700);
line-height: 1.6;
}
/* Historical evidence panel styles */
.historical-evidence-panel {
border: 3px solid var(--color-enterprise-primary);
border-radius: var(--borderRadius-xl);
padding: var(--spacing-6);
margin: var(--spacing-6) 0;
background: var(--color-surface-light);
}
[data-theme="dark"] .historical-evidence-panel {
background: var(--colors-neutral-800);
}
.evidence-header-main {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--spacing-6);
}
.evidence-header-main h3 {
margin: 0 0 var(--spacing-2) 0;
color: var(--colors-neutral-900);
font-size: var(--typography-fontSizes-xl);
}
.evidence-header-main p {
margin: 0;
color: var(--colors-neutral-600);
}
.evidence-dominance-badge {
padding: var(--spacing-2) var(--spacing-4);
background: var(--color-enterprise-primary);
color: white;
border-radius: var(--borderRadius-full);
font-size: var(--typography-fontSizes-xs);
font-weight: var(--typography-fontWeights-bold);
}
.evidence-comparison {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--spacing-6);
margin-bottom: var(--spacing-6);
}
.evidence-column {
display: flex;
flex-direction: column;
gap: var(--spacing-4);
}
.column-header {
font-size: var(--typography-fontSizes-lg);
font-weight: var(--typography-fontWeights-bold);
margin-bottom: var(--spacing-2);
display: flex;
align-items: center;
gap: var(--spacing-2);
}
.column-header.failure {
color: var(--color-danger);
}
.column-header.success {
color: var(--color-success);
}
.evidence-item {
border-left: 4px solid;
padding-left: var(--spacing-4);
margin-bottom: var(--spacing-3);
}
.evidence-failure {
border-left-color: var(--color-danger);
}
.evidence-success {
border-left-color: var(--color-success);
}
.evidence-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: var(--spacing-2);
}
.evidence-date {
font-size: var(--typography-fontSizes-sm);
font-weight: var(--typography-fontWeights-semibold);
color: var(--colors-neutral-900);
}
.evidence-badge {
padding: 2px 8px;
border-radius: var(--borderRadius-full);
font-size: var(--typography-fontSizes-xs);
font-weight: var(--typography-fontWeights-bold);
}
.evidence-badge.failure {
background: var(--color-danger);
color: white;
}
.evidence-badge.success {
background: var(--color-success);
color: white;
}
.evidence-content {
font-size: var(--typography-fontSizes-sm);
}
.evidence-action {
color: var(--colors-neutral-700);
margin-bottom: var(--spacing-1);
}
.evidence-outcome {
color: var(--colors-neutral-600);
margin-bottom: var(--spacing-2);
font-weight: var(--typography-fontWeights-medium);
}
.evidence-failure .evidence-outcome {
color: var(--color-danger);
}
.evidence-success .evidence-outcome {
color: var(--color-success);
}
.evidence-lesson {
font-style: italic;
color: var(--colors-neutral-500);
background: var(--colors-neutral-50);
padding: var(--spacing-2);
border-radius: var(--borderRadius-md);
font-size: var(--typography-fontSizes-xs);
}
[data-theme="dark"] .evidence-lesson {
background: var(--colors-neutral-700);
}
.psych-principle {
background: linear-gradient(135deg, var(--colors-primary-50), var(--colors-neutral-50));
border-radius: var(--borderRadius-lg);
padding: var(--spacing-4);
border: 2px solid var(--colors-primary-300);
margin-top: var(--spacing-6);
}
[data-theme="dark"] .psych-principle {
background: linear-gradient(135deg, var(--colors-primary-900), var(--colors-neutral-800));
border-color: var(--colors-primary-700);
}
.principle-icon {
font-size: 28px;
color: var(--color-enterprise-primary);
margin-bottom: var(--spacing-2);
}
.principle-content h4 {
margin: 0 0 var(--spacing-2) 0;
color: var(--colors-neutral-900);
font-size: var(--typography-fontSizes-lg);
}
.principle-content p {
margin: 0;
color: var(--colors-neutral-700);
line-height: 1.6;
}
/* Healing intent display styles */
.healing-intent-display {
background: var(--color-surface-light);
border: 2px solid var(--color-success);
border-radius: var(--borderRadius-xl);
padding: var(--spacing-6);
margin: var(--spacing-6) 0;
}
[data-theme="dark"] .healing-intent-display {
background: var(--colors-neutral-800);
}
.intent-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--spacing-6);
padding-bottom: var(--spacing-4);
border-bottom: 2px solid var(--colors-neutral-200);
}
.intent-header h3 {
margin: 0 0 var(--spacing-2) 0;
color: var(--colors-neutral-900);
font-size: var(--typography-fontSizes-xl);
}
.intent-header p {
margin: 0;
color: var(--colors-neutral-600);
}
.confidence-badge {
padding: var(--spacing-2) var(--spacing-4);
background: var(--confidence-color, var(--color-success));
color: white;
border-radius: var(--borderRadius-full);
font-size: var(--typography-fontSizes-sm);
font-weight: var(--typography-fontWeights-bold);
text-transform: uppercase;
letter-spacing: 0.05em;
}
.intent-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--spacing-4);
margin-bottom: var(--spacing-6);
}
.intent-section {
background: var(--colors-neutral-50);
border-radius: var(--borderRadius-lg);
padding: var(--spacing-4);
}
[data-theme="dark"] .intent-section {
background: var(--colors-neutral-700);
}
.section-title {
font-size: var(--typography-fontSizes-sm);
color: var(--colors-neutral-600);
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: var(--spacing-2);
}
.section-content {
font-size: var(--typography-fontSizes-base);
color: var(--colors-neutral-900);
font-weight: var(--typography-fontWeights-medium);
}
[data-theme="dark"] .section-content {
color: var(--colors-neutral-100);
}
.primary-action {
color: var(--color-success);
font-weight: var(--typography-fontWeights-semibold);
}
.sequencing-rule {
color: var(--color-enterprise-primary);
font-family: var(--font-mono);
font-size: var(--typography-fontSizes-sm);
}
.intent-details {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: var(--spacing-4);
margin-bottom: var(--spacing-6);
}
.detail-section {
background: var(--colors-neutral-50);
border-radius: var(--borderRadius-lg);
padding: var(--spacing-4);
}
[data-theme="dark"] .detail-section {
background: var(--colors-neutral-700);
}
.detail-title {
font-size: var(--typography-fontSizes-sm);
color: var(--colors-neutral-600);
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: var(--spacing-2);
}
.detail-content {
font-size: var(--typography-fontSizes-sm);
color: var(--colors-neutral-700);
line-height: 1.5;
}
[data-theme="dark"] .detail-content {
color: var(--colors-neutral-300);
}
.preconditions-list {
display: flex;
flex-direction: column;
gap: var(--spacing-1);
}
.precondition-item {
color: var(--colors-neutral-700);
}
.contraindications-list {
display: flex;
flex-direction: column;
gap: var(--spacing-1);
}
.contraindication-item {
color: var(--color-danger);
font-weight: var(--typography-fontWeights-medium);
}
.reversibility {
color: var(--color-success);
font-style: italic;
}
.psych-doctrine {
background: linear-gradient(135deg, var(--colors-success-50), var(--colors-neutral-50));
border-radius: var(--borderRadius-lg);
padding: var(--spacing-4);
border: 2px solid var(--colors-success-300);
margin-top: var(--spacing-6);
}
[data-theme="dark"] .psych-doctrine {
background: linear-gradient(135deg, var(--colors-success-900), var(--colors-neutral-800));
border-color: var(--colors-success-700);
}
.doctrine-icon {
font-size: 28px;
color: var(--color-success);
margin-bottom: var(--spacing-2);
}
.doctrine-content h4 {
margin: 0 0 var(--spacing-2) 0;
color: var(--colors-neutral-900);
font-size: var(--typography-fontSizes-lg);
}
.doctrine-content p {
margin: 0;
color: var(--colors-neutral-700);
line-height: 1.6;
}
/* Responsive adjustments */
@media (max-width: 768px) {
.confidence-comparison {
grid-template-columns: 1fr;
}
.sequencing-steps {
flex-direction: column;
gap: var(--spacing-6);
}
.step-connectors {
display: none;
}
.evidence-comparison {
grid-template-columns: 1fr;
}
.intent-grid {
grid-template-columns: 1fr;
}
.intent-details {
grid-template-columns: 1fr;
}
}
@media (max-width: 480px) {
.observation-gate-header {
flex-direction: column;
text-align: center;
gap: var(--spacing-2);
}
.observation-badge {
margin-left: 0;
margin-top: var(--spacing-2);
}
.card {
padding: var(--spacing-3);
}
.sequencing-flow,
.historical-evidence-panel,
.healing-intent-display {
padding: var(--spacing-3);
}
}
</style>
"""
# ===========================================
# INITIALIZATION FUNCTION
# ===========================================
def initialize_modern_ui() -> str:
"""Initialize all modern UI components and styles"""
components = [
inject_design_tokens(),
create_component_styles(),
"""
<style>
/* Additional responsive utilities */
.container {
width: 100%;
max-width: 1200px;
margin: 0 auto;
padding: 0 var(--spacing-4);
}
@media (min-width: 768px) {
.container {
padding: 0 var(--spacing-6);
}
}
@media (min-width: 1024px) {
.container {
padding: 0 var(--spacing-8);
}
}
</style>
"""
]
return "\n".join(components)
# ===========================================
# EXPORT LIST
# ===========================================
__all__ = [
# Core components
'ModernComponent', 'Card',
# CRITICAL PSYCHOLOGICAL COMPONENTS
'ObservationGate', 'SequencingFlow', 'ProcessDisplay',
'HistoricalEvidencePanel', 'HealingIntentDisplay',
# Design system
'DESIGN_TOKENS',
# Initialization
'initialize_modern_ui', 'inject_design_tokens', 'create_component_styles'
]