petter2025 commited on
Commit
1ee33ac
·
verified ·
1 Parent(s): 364218e

Update ui/modern_components.py

Browse files
Files changed (1) hide show
  1. ui/modern_components.py +935 -1109
ui/modern_components.py CHANGED
@@ -1,27 +1,24 @@
1
  """
2
- ui/modern_components.py
3
- 🚀 Modern UI Components for ARF v3.3.9
4
- Enhanced with design system, accessibility, and performance features
5
-
6
  Features:
7
  1. Design token system with CSS variables
8
- 2. Responsive, mobile-first components
9
  3. Accessibility (ARIA labels, keyboard nav)
10
  4. Performance optimizations
11
  5. Dark mode support
12
- 6. Progressive enhancement
13
  """
14
 
15
  import json
16
- from datetime import datetime
17
  from typing import Dict, List, Any, Optional, Tuple
18
  import plotly.graph_objects as go
19
  import plotly.express as px
20
  import numpy as np
21
- import pandas as pd
22
 
23
  # ===========================================
24
- # DESIGN TOKEN SYSTEM (CSS Variables in JavaScript)
25
  # ===========================================
26
  DESIGN_TOKENS = {
27
  "colors": {
@@ -31,7 +28,7 @@ DESIGN_TOKENS = {
31
  "200": "#bfdbfe",
32
  "300": "#93c5fd",
33
  "400": "#60a5fa",
34
- "500": "#3b82f6",
35
  "600": "#2563eb",
36
  "700": "#1d4ed8",
37
  "800": "#1e40af",
@@ -43,7 +40,7 @@ DESIGN_TOKENS = {
43
  "200": "#bbf7d0",
44
  "300": "#86efac",
45
  "400": "#4ade80",
46
- "500": "#22c55e",
47
  "600": "#16a34a",
48
  "700": "#15803d",
49
  "800": "#166534",
@@ -55,7 +52,7 @@ DESIGN_TOKENS = {
55
  "200": "#fde68a",
56
  "300": "#fcd34d",
57
  "400": "#fbbf24",
58
- "500": "#f59e0b",
59
  "600": "#d97706",
60
  "700": "#b45309",
61
  "800": "#92400e",
@@ -67,7 +64,7 @@ DESIGN_TOKENS = {
67
  "200": "#fecaca",
68
  "300": "#fca5a5",
69
  "400": "#f87171",
70
- "500": "#ef4444",
71
  "600": "#dc2626",
72
  "700": "#b91c1c",
73
  "800": "#991b1b",
@@ -164,11 +161,16 @@ def inject_design_tokens() -> str:
164
  :root {{
165
  {chr(10).join(css_variables)}
166
 
167
- /* Semantic aliases */
168
- --color-primary: var(--colors-primary-500);
169
  --color-success: var(--colors-success-500);
170
  --color-warning: var(--colors-warning-500);
171
  --color-danger: var(--colors-danger-500);
 
 
 
 
 
172
 
173
  /* Spacing aliases */
174
  --spacing-xs: var(--spacing-2);
@@ -178,13 +180,13 @@ def inject_design_tokens() -> str:
178
  --spacing-xl: var(--spacing-8);
179
 
180
  /* Font families */
181
- --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
182
  --font-mono: 'JetBrains Mono', 'SF Mono', Monaco, 'Cascadia Code', monospace;
183
 
184
- /* Transitions */
185
  --transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
186
- --transition-normal: 250ms cubic-bezier(0.4, 0, 0.2, 1);
187
- --transition-slow: 350ms cubic-bezier(0.4, 0, 0.2, 1);
188
  }}
189
 
190
  /* Dark mode overrides */
@@ -215,7 +217,7 @@ def inject_design_tokens() -> str:
215
  }}
216
 
217
  .focus-ring {{
218
- outline: 2px solid var(--color-primary);
219
  outline-offset: 2px;
220
  }}
221
 
@@ -343,180 +345,15 @@ class Card(ModernComponent):
343
  </div>
344
  """
345
 
346
- class Button(ModernComponent):
347
- """Accessible button component with variants"""
348
-
349
- @staticmethod
350
- def create(text: str, **kwargs) -> str:
351
- """Create a styled button"""
352
- variant = kwargs.get('variant', 'primary') # primary, secondary, danger, ghost
353
- size = kwargs.get('size', 'md') # sm, md, lg
354
- disabled = kwargs.get('disabled', False)
355
- full_width = kwargs.get('full_width', False)
356
-
357
- variant_classes = {
358
- 'primary': 'btn-primary',
359
- 'secondary': 'btn-secondary',
360
- 'danger': 'btn-danger',
361
- 'ghost': 'btn-ghost'
362
- }
363
-
364
- size_classes = {
365
- 'sm': 'btn-sm',
366
- 'md': 'btn-md',
367
- 'lg': 'btn-lg'
368
- }
369
-
370
- classes = [
371
- 'btn',
372
- variant_classes.get(variant, 'btn-primary'),
373
- size_classes.get(size, 'btn-md'),
374
- 'full-width' if full_width else ''
375
- ]
376
-
377
- disabled_attr = 'disabled aria-disabled="true"' if disabled else ''
378
-
379
- return f"""
380
- <button class="{' '.join(classes)}" {disabled_attr}>
381
- {text}
382
- </button>
383
- """
384
-
385
- @staticmethod
386
- def create_icon_button(icon: str, label: str, **kwargs) -> str:
387
- """Create an icon-only button with proper accessibility"""
388
- return f"""
389
- <button class="btn-icon" aria-label="{label}">
390
- <span class="btn-icon-inner">{icon}</span>
391
- </button>
392
- """
393
-
394
- class Badge(ModernComponent):
395
- """Badge component for status, tags, etc."""
396
-
397
- @staticmethod
398
- def create(text: str, **kwargs) -> str:
399
- """Create a badge"""
400
- variant = kwargs.get('variant', 'default') # default, success, warning, danger
401
- size = kwargs.get('size', 'md') # sm, md, lg
402
-
403
- variant_classes = {
404
- 'default': 'badge-default',
405
- 'success': 'badge-success',
406
- 'warning': 'badge-warning',
407
- 'danger': 'badge-danger'
408
- }
409
-
410
- size_classes = {
411
- 'sm': 'badge-sm',
412
- 'md': 'badge-md',
413
- 'lg': 'badge-lg'
414
- }
415
-
416
- return f"""
417
- <span class="badge {variant_classes.get(variant, 'badge-default')} {size_classes.get(size, 'badge-md')}">
418
- {text}
419
- </span>
420
- """
421
-
422
- # ===========================================
423
- # LAYOUT COMPONENTS
424
- # ===========================================
425
- class Grid(ModernComponent):
426
- """Responsive grid system"""
427
-
428
- @staticmethod
429
- def create(children: List[str], **kwargs) -> str:
430
- """Create a responsive grid"""
431
- columns = kwargs.get('columns', { # responsive column definitions
432
- 'default': 1,
433
- 'sm': 2,
434
- 'lg': 3
435
- })
436
-
437
- gap = kwargs.get('gap', 'var(--spacing-4)')
438
-
439
- # Convert columns dict to CSS
440
- grid_template = []
441
- for breakpoint, col_count in columns.items():
442
- if breakpoint == 'default':
443
- grid_template.append(f"grid-template-columns: repeat({col_count}, 1fr);")
444
- else:
445
- grid_template.append(f"@media (min-width: {DESIGN_TOKENS['breakpoints'][breakpoint]}) {{")
446
- grid_template.append(f" grid-template-columns: repeat({col_count}, 1fr);")
447
- grid_template.append("}")
448
-
449
- return f"""
450
- <div class="grid" style="gap: {gap};">
451
- {''.join(children)}
452
- </div>
453
-
454
- <style>
455
- .grid {{
456
- display: grid;
457
- {grid_template[0] if grid_template else ''}
458
- }}
459
-
460
- {''.join(grid_template[1:]) if len(grid_template) > 1 else ''}
461
- </style>
462
- """
463
-
464
- @staticmethod
465
- def create_metric_grid(metrics: List[Dict[str, Any]]) -> str:
466
- """Create a grid of metric cards"""
467
- metric_cards = []
468
- for metric in metrics:
469
- metric_cards.append(
470
- Card.create_metric(
471
- value=metric.get('value', ''),
472
- label=metric.get('label', ''),
473
- trend=metric.get('trend'),
474
- change=metric.get('change', '')
475
- )
476
- )
477
-
478
- return Grid.create(
479
- children=metric_cards,
480
- columns={'default': 2, 'sm': 2, 'lg': 4}
481
- )
482
-
483
- class Stack(ModernComponent):
484
- """Vertical stack layout"""
485
-
486
- @staticmethod
487
- def create(children: List[str], **kwargs) -> str:
488
- """Create a vertical stack"""
489
- spacing = kwargs.get('spacing', 'var(--spacing-4)')
490
- align = kwargs.get('align', 'stretch') # start, center, end, stretch
491
-
492
- return f"""
493
- <div class="stack" style="--spacing: {spacing}; --align: {align};">
494
- {''.join([f'<div class="stack-item">{child}</div>' for child in children])}
495
- </div>
496
-
497
- <style>
498
- .stack {{
499
- display: flex;
500
- flex-direction: column;
501
- align-items: var(--align);
502
- gap: var(--spacing);
503
- }}
504
-
505
- .stack-item {{
506
- width: 100%;
507
- }}
508
- </style>
509
- """
510
-
511
  # ===========================================
512
- # SPECIALIZED ARF COMPONENTS
513
  # ===========================================
514
  class ObservationGate(ModernComponent):
515
- """Observation gate component showing system restraint"""
516
 
517
  @staticmethod
518
  def create(confidence: float = 65.0, **kwargs) -> str:
519
- """Create observation gate display"""
520
  reason = kwargs.get('reason', 'uncertainty_too_high_for_action')
521
  frozen_until = kwargs.get('frozen_until', '')
522
 
@@ -526,20 +363,52 @@ class ObservationGate(ModernComponent):
526
  # Format countdown if available
527
  countdown_html = ""
528
  if frozen_until:
529
- countdown_html = f"""
530
- <div class="countdown">
531
- <span class="countdown-label">Next evaluation:</span>
532
- <span class="countdown-timer" data-until="{frozen_until}">5:00</span>
533
- </div>
534
- """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
535
 
536
  status_text = "Observation Gate: Awaiting confirmation" if is_blocked else "Observation Gate Cleared"
537
  status_color = "var(--color-warning)" if is_blocked else "var(--color-success)"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
538
 
539
  return f"""
540
  <div class="observation-gate" style="--status-color: {status_color};">
541
  <div class="observation-gate-header">
542
- <div class="observation-icon"></div>
543
  <div class="observation-title">
544
  <h3>{status_text}</h3>
545
  <p>System restraint engaged</p>
@@ -550,12 +419,7 @@ class ObservationGate(ModernComponent):
550
  </div>
551
 
552
  <div class="observation-content">
553
- <div class="observation-message">
554
- <h4>Decision Intentionally Deferred</h4>
555
- <p>The system has detected uncertainty (<strong>{confidence:.1f}% confidence</strong>)
556
- and has chosen to observe rather than act. Historical evidence indicates
557
- premature action increases risk by <strong>47%</strong>.</p>
558
- </div>
559
 
560
  <div class="confidence-comparison">
561
  <div class="confidence-item">
@@ -567,19 +431,19 @@ class ObservationGate(ModernComponent):
567
  <div class="confidence-item">
568
  <div class="confidence-label">Current Confidence</div>
569
  <div class="confidence-value" style="color: {status_color};">{confidence:.1f}%</div>
570
- <div class="confidence-note">Below threshold → Observe</div>
571
  </div>
572
  </div>
573
 
574
  <div class="confidence-visualization">
575
  <div class="confidence-scale">
576
  <div class="scale-marker" style="left: {confidence}%;"></div>
577
- <div class="scale-bar" style="width: {confidence}%;"></div>
578
  </div>
579
  <div class="scale-labels">
580
- <span>Observe ({confidence:.1f}%)</span>
581
  <span>Threshold ({threshold}%)</span>
582
- <span>Act (75%+)</span>
583
  </div>
584
  </div>
585
 
@@ -598,11 +462,19 @@ class ObservationGate(ModernComponent):
598
  """
599
 
600
  class SequencingFlow(ModernComponent):
601
- """Visualization of policy-enforced sequencing"""
602
 
603
  @staticmethod
604
- def create(steps: List[Dict[str, Any]], **kwargs) -> str:
605
  """Create sequencing flow visualization"""
 
 
 
 
 
 
 
 
606
  current_step = kwargs.get('current_step', 0)
607
 
608
  steps_html = []
@@ -651,14 +523,15 @@ class SequencingFlow(ModernComponent):
651
  <h4>Doctrinal Constraint: Scaling Cannot Appear First</h4>
652
  <p>If retry amplification is detected, scaling is <strong>contraindicated entirely</strong>.
653
  The system must observe stabilization before considering capacity increases.
654
- Historical evidence shows scaling-first fails 76% of the time during amplification.</p>
 
655
  </div>
656
  </div>
657
  </div>
658
  """
659
 
660
  class ProcessDisplay(ModernComponent):
661
- """Display for ARF processes (Detection, Recall, Decision)"""
662
 
663
  @staticmethod
664
  def create(process_type: str, data: Dict[str, Any]) -> str:
@@ -707,6 +580,19 @@ class ProcessDisplay(ModernComponent):
707
  </div>
708
  """
709
 
 
 
 
 
 
 
 
 
 
 
 
 
 
710
  return f"""
711
  <div class="process-card" data-process="{process_type}" data-status="{status}">
712
  <div class="process-header">
@@ -722,687 +608,389 @@ class ProcessDisplay(ModernComponent):
722
 
723
  <div class="process-body">
724
  {metrics_html}
725
-
726
- {data.get('content', '')}
727
-
728
  {next_step_html}
729
  </div>
730
  </div>
731
  """
732
 
733
- # ===========================================
734
- # DATA VISUALIZATION COMPONENTS
735
- # ===========================================
736
- class Chart(ModernComponent):
737
- """Wrapper for Plotly charts with consistent styling"""
738
-
739
- @staticmethod
740
- def create_line(data: Dict[str, Any], **kwargs) -> go.Figure:
741
- """Create a line chart with ARF styling"""
742
- title = kwargs.get('title', '')
743
- height = kwargs.get('height', 300)
744
-
745
- fig = go.Figure()
746
-
747
- # Add traces
748
- for trace in data.get('traces', []):
749
- fig.add_trace(go.Scatter(
750
- x=trace.get('x', []),
751
- y=trace.get('y', []),
752
- mode=trace.get('mode', 'lines'),
753
- name=trace.get('name', ''),
754
- line=dict(
755
- color=trace.get('color', 'var(--color-primary)'),
756
- width=trace.get('width', 3)
757
- ),
758
- fill=trace.get('fill', None)
759
- ))
760
-
761
- # Update layout
762
- fig.update_layout(
763
- title={
764
- 'text': title,
765
- 'font': {
766
- 'size': 18,
767
- 'color': 'var(--colors-neutral-900)',
768
- 'family': 'var(--font-sans)'
769
- }
770
- },
771
- height=height,
772
- plot_bgcolor='white',
773
- paper_bgcolor='white',
774
- font={
775
- 'family': 'var(--font-sans)',
776
- 'color': 'var(--colors-neutral-700)'
777
- },
778
- margin=dict(l=40, r=20, t=60, b=40),
779
- hovermode='x unified',
780
- showlegend=kwargs.get('show_legend', True),
781
- legend=dict(
782
- orientation="h",
783
- yanchor="bottom",
784
- y=1.02,
785
- xanchor="center",
786
- x=0.5
787
- )
788
- )
789
-
790
- # Update axes
791
- fig.update_xaxes(
792
- gridcolor='var(--colors-neutral-200)',
793
- linecolor='var(--colors-neutral-300)',
794
- title_font=dict(size=12)
795
- )
796
-
797
- fig.update_yaxes(
798
- gridcolor='var(--colors-neutral-200)',
799
- linecolor='var(--colors-neutral-300)',
800
- title_font=dict(size=12)
801
- )
802
-
803
- return fig
804
 
805
  @staticmethod
806
- def create_gauge(value: float, **kwargs) -> go.Figure:
807
- """Create a gauge chart for metrics"""
808
- title = kwargs.get('title', '')
809
- min_val = kwargs.get('min', 0)
810
- max_val = kwargs.get('max', 100)
811
-
812
- fig = go.Figure(go.Indicator(
813
- mode="gauge+number",
814
- value=value,
815
- domain={'x': [0, 1], 'y': [0, 1]},
816
- title={
817
- 'text': title,
818
- 'font': {
819
- 'size': 16,
820
- 'family': 'var(--font-sans)'
821
- }
822
- },
823
- number={
824
- 'font': {
825
- 'size': 28,
826
- 'family': 'var(--font-sans)'
827
- }
828
- },
829
- gauge={
830
- 'axis': {
831
- 'range': [min_val, max_val],
832
- 'tickwidth': 1,
833
- 'tickcolor': "var(--colors-neutral-700)"
834
- },
835
- 'bar': {'color': "var(--color-primary)"},
836
- 'bgcolor': "white",
837
- 'borderwidth': 2,
838
- 'bordercolor': "var(--colors-neutral-300)",
839
- 'steps': [
840
  {
841
- 'range': [min_val, max_val * 0.3],
842
- 'color': 'var(--color-success)'
 
 
 
843
  },
844
  {
845
- 'range': [max_val * 0.3, max_val * 0.7],
846
- 'color': 'var(--color-warning)'
 
 
 
 
 
 
 
 
 
 
 
 
847
  },
848
  {
849
- 'range': [max_val * 0.7, max_val],
850
- 'color': 'var(--color-danger)'
 
 
 
851
  }
852
- ],
853
- 'threshold': {
854
- 'line': {'color': "var(--colors-neutral-900)", 'width': 4},
855
- 'thickness': 0.75,
856
- 'value': value
857
- }
858
- }
859
- ))
860
-
861
- fig.update_layout(
862
- height=300,
863
- margin=dict(l=30, r=30, t=70, b=30),
864
- paper_bgcolor='white',
865
- font={
866
- 'family': 'var(--font-sans)'
867
- }
868
- )
869
-
870
- return fig
871
-
872
- # ===========================================
873
- # RESPONSIVE UTILITIES
874
- # ===========================================
875
- class ResponsiveUtils:
876
- """Responsive design utilities"""
877
-
878
- @staticmethod
879
- def create_responsive_styles() -> str:
880
- """Generate responsive CSS utilities"""
881
- return """
882
- <style>
883
- /* Container utilities */
884
- .container {
885
- width: 100%;
886
- margin-left: auto;
887
- margin-right: auto;
888
- padding-left: var(--spacing-4);
889
- padding-right: var(--spacing-4);
890
- }
891
-
892
- @media (min-width: 640px) {
893
- .container {
894
- max-width: 640px;
895
- }
896
- }
897
-
898
- @media (min-width: 768px) {
899
- .container {
900
- max-width: 768px;
901
- }
902
- }
903
-
904
- @media (min-width: 1024px) {
905
- .container {
906
- max-width: 1024px;
907
- }
908
- }
909
-
910
- @media (min-width: 1280px) {
911
- .container {
912
- max-width: 1280px;
913
- }
914
- }
915
-
916
- /* Responsive hide/show */
917
- .hide-on-mobile {
918
- display: none;
919
- }
920
-
921
- .show-on-mobile {
922
- display: block;
923
- }
924
-
925
- @media (min-width: 768px) {
926
- .hide-on-mobile {
927
- display: block;
928
- }
929
-
930
- .show-on-mobile {
931
- display: none;
932
- }
933
- }
934
-
935
- /* Responsive text sizes */
936
- .text-responsive {
937
- font-size: var(--typography-fontSizes-sm);
938
- }
939
-
940
- @media (min-width: 768px) {
941
- .text-responsive {
942
- font-size: var(--typography-fontSizes-base);
943
- }
944
- }
945
-
946
- @media (min-width: 1024px) {
947
- .text-responsive {
948
- font-size: var(--typography-fontSizes-lg);
949
- }
950
- }
951
-
952
- /* Responsive spacing */
953
- .responsive-padding {
954
- padding: var(--spacing-2);
955
- }
956
-
957
- @media (min-width: 768px) {
958
- .responsive-padding {
959
- padding: var(--spacing-4);
960
  }
961
- }
962
 
963
- @media (min-width: 1024px) {
964
- .responsive-padding {
965
- padding: var(--spacing-6);
966
- }
967
- }
968
- </style>
969
- """
970
-
971
- @staticmethod
972
- def create_mobile_navigation() -> str:
973
- """Create mobile-friendly navigation toggle"""
974
- return """
975
- <style>
976
- /* Mobile navigation */
977
- .mobile-nav-toggle {
978
- display: none;
979
- position: fixed;
980
- top: 20px;
981
- right: 20px;
982
- z-index: 1000;
983
- width: 50px;
984
- height: 50px;
985
- border-radius: 50%;
986
- background: var(--color-primary);
987
- color: white;
988
- border: none;
989
- font-size: 24px;
990
- cursor: pointer;
991
- align-items: center;
992
- justify-content: center;
993
- box-shadow: var(--shadows-md);
994
- }
995
 
996
- @media (max-width: 768px) {
997
- .mobile-nav-toggle {
998
- display: flex;
999
- }
1000
-
1001
- .main-nav {
1002
- position: fixed;
1003
- top: 0;
1004
- left: 0;
1005
- right: 0;
1006
- bottom: 0;
1007
- background: var(--colors-neutral-50);
1008
- padding: 80px 20px 20px;
1009
- transform: translateX(-100%);
1010
- transition: transform var(--transition-normal);
1011
- z-index: 999;
1012
- overflow-y: auto;
1013
- }
1014
-
1015
- .main-nav.open {
1016
- transform: translateX(0);
1017
- }
1018
- }
1019
 
1020
- /* Touch-friendly buttons */
1021
- @media (hover: none) and (pointer: coarse) {
1022
- .btn, button, [role="button"] {
1023
- min-height: 44px;
1024
- min-width: 44px;
1025
- }
 
 
 
 
 
1026
 
1027
- input, select, textarea {
1028
- font-size: 16px; /* Prevents iOS zoom */
1029
- }
1030
- }
1031
- </style>
1032
-
1033
- <button class="mobile-nav-toggle" id="mobileNavToggle" aria-label="Toggle navigation">
1034
-
1035
- </button>
1036
-
1037
- <script>
1038
- document.getElementById('mobileNavToggle').addEventListener('click', function() {
1039
- const nav = document.querySelector('.main-nav');
1040
- nav.classList.toggle('open');
1041
- this.setAttribute('aria-expanded', nav.classList.contains('open'));
1042
- });
1043
-
1044
- // Close mobile nav when clicking outside
1045
- document.addEventListener('click', function(event) {
1046
- const nav = document.querySelector('.main-nav');
1047
- const toggle = document.getElementById('mobileNavToggle');
 
 
 
 
1048
 
1049
- if (nav && nav.classList.contains('open') &&
1050
- !nav.contains(event.target) &&
1051
- !toggle.contains(event.target)) {
1052
- nav.classList.remove('open');
1053
- toggle.setAttribute('aria-expanded', 'false');
1054
- }
1055
- });
1056
- </script>
 
 
1057
  """
1058
 
1059
- # ===========================================
1060
- # ACCESSIBILITY ENHANCEMENTS
1061
- # ===========================================
1062
- class Accessibility:
1063
- """Accessibility enhancements"""
1064
 
1065
  @staticmethod
1066
- def create_skip_link() -> str:
1067
- """Create skip to content link for keyboard users"""
1068
- return """
1069
- <a href="#main-content" class="skip-link">
1070
- Skip to main content
1071
- </a>
1072
-
1073
- <style>
1074
- .skip-link {
1075
- position: absolute;
1076
- top: -40px;
1077
- left: 0;
1078
- background: var(--color-primary);
1079
- color: white;
1080
- padding: 8px 16px;
1081
- text-decoration: none;
1082
- z-index: 9999;
1083
- border-radius: 0 0 var(--borderRadius-md) 0;
1084
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1085
 
1086
- .skip-link:focus {
1087
- top: 0;
1088
- }
1089
- </style>
1090
- """
1091
-
1092
- @staticmethod
1093
- def create_focus_management() -> str:
1094
- """Focus management for modals and dialogs"""
1095
- return """
1096
- <script>
1097
- // Focus trap for modals
1098
- class FocusTrap {
1099
- constructor(container) {
1100
- this.container = container;
1101
- this.firstFocusable = null;
1102
- this.lastFocusable = null;
1103
- this.previousFocus = null;
 
1104
 
1105
- this.init();
1106
- }
 
 
 
 
 
1107
 
1108
- init() {
1109
- const focusableElements = this.container.querySelectorAll(
1110
- 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
1111
- );
 
 
 
1112
 
1113
- if (focusableElements.length > 0) {
1114
- this.firstFocusable = focusableElements[0];
1115
- this.lastFocusable = focusableElements[focusableElements.length - 1];
1116
- this.previousFocus = document.activeElement;
1117
-
1118
- this.firstFocusable.focus();
1119
-
1120
- // Add keydown listener for trap
1121
- this.container.addEventListener('keydown', (e) => this.handleKeyDown(e));
1122
- }
1123
- }
 
 
 
1124
 
1125
- handleKeyDown(e) {
1126
- if (e.key === 'Tab') {
1127
- if (e.shiftKey) {
1128
- // Shift + Tab
1129
- if (document.activeElement === this.firstFocusable) {
1130
- e.preventDefault();
1131
- this.lastFocusable.focus();
1132
- }
1133
- } else {
1134
- // Tab
1135
- if (document.activeElement === this.lastFocusable) {
1136
- e.preventDefault();
1137
- this.firstFocusable.focus();
1138
- }
1139
- }
1140
- } else if (e.key === 'Escape') {
1141
- // Close modal and return focus
1142
- this.close();
1143
- }
1144
- }
1145
 
1146
- close() {
1147
- if (this.previousFocus) {
1148
- this.previousFocus.focus();
1149
- }
1150
- this.container.removeEventListener('keydown', this.handleKeyDown);
1151
- }
1152
- }
1153
-
1154
- // Initialize focus traps for all modals
1155
- document.addEventListener('DOMContentLoaded', () => {
1156
- document.querySelectorAll('[role="dialog"]').forEach(modal => {
1157
- new FocusTrap(modal);
1158
- });
1159
- });
1160
- </script>
1161
- """
1162
-
1163
- @staticmethod
1164
- def create_aria_live_regions() -> str:
1165
- """Create ARIA live regions for dynamic content"""
1166
- return """
1167
- <div aria-live="polite" aria-atomic="true" class="sr-only" id="status-announcements">
1168
- <!-- Status messages will be injected here -->
1169
- </div>
1170
-
1171
- <div aria-live="assertive" aria-atomic="true" class="sr-only" id="alert-announcements">
1172
- <!-- Alert messages will be injected here -->
1173
  </div>
1174
-
1175
- <script>
1176
- // Utility functions for announcing messages
1177
- const AriaAnnouncer = {
1178
- announceStatus(message) {
1179
- const region = document.getElementById('status-announcements');
1180
- region.textContent = message;
1181
-
1182
- // Clear after announcement
1183
- setTimeout(() => {
1184
- region.textContent = '';
1185
- }, 1000);
1186
- },
1187
-
1188
- announceAlert(message) {
1189
- const region = document.getElementById('alert-announcements');
1190
- region.textContent = message;
1191
-
1192
- // Clear after announcement
1193
- setTimeout(() => {
1194
- region.textContent = '';
1195
- }, 1000);
1196
- }
1197
- };
1198
-
1199
- // Example usage:
1200
- // AriaAnnouncer.announceStatus('Analysis complete');
1201
- // AriaAnnouncer.announceAlert('Error detected');
1202
- </script>
1203
  """
1204
 
1205
  # ===========================================
1206
- # DARK MODE SUPPORT
1207
  # ===========================================
1208
- class DarkMode:
1209
- """Dark mode toggle and management"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1210
 
1211
- @staticmethod
1212
- def create_toggle() -> str:
1213
- """Create dark mode toggle with system preference detection"""
1214
- return """
1215
- <button class="dark-mode-toggle" id="darkModeToggle" aria-label="Toggle dark mode">
1216
- <span class="light-icon">☀️</span>
1217
- <span class="dark-icon">🌙</span>
1218
- </button>
1219
-
1220
- <script>
1221
- class DarkModeManager {
1222
- constructor() {
1223
- this.toggle = document.getElementById('darkModeToggle');
1224
- this.prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
1225
- this.savedTheme = localStorage.getItem('theme');
1226
-
1227
- this.init();
1228
- }
1229
-
1230
- init() {
1231
- // Set initial theme
1232
- const initialTheme = this.savedTheme ||
1233
- (this.prefersDark.matches ? 'dark' : 'light');
1234
- this.setTheme(initialTheme);
1235
-
1236
- // Add click listener
1237
- this.toggle.addEventListener('click', () => this.toggleTheme());
1238
-
1239
- // Listen for system preference changes
1240
- this.prefersDark.addEventListener('change', (e) => {
1241
- if (!this.savedTheme) {
1242
- this.setTheme(e.matches ? 'dark' : 'light');
1243
- }
1244
- });
1245
- }
1246
-
1247
- setTheme(theme) {
1248
- document.documentElement.setAttribute('data-theme', theme);
1249
- localStorage.setItem('theme', theme);
1250
-
1251
- // Update toggle state
1252
- if (theme === 'dark') {
1253
- this.toggle.classList.add('dark');
1254
- this.toggle.setAttribute('aria-label', 'Switch to light mode');
1255
- } else {
1256
- this.toggle.classList.remove('dark');
1257
- this.toggle.setAttribute('aria-label', 'Switch to dark mode');
1258
- }
1259
- }
1260
-
1261
- toggleTheme() {
1262
- const currentTheme = document.documentElement.getAttribute('data-theme');
1263
- const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
1264
-
1265
- this.setTheme(newTheme);
1266
- this.savedTheme = newTheme;
1267
- }
1268
- }
1269
-
1270
- // Initialize when DOM is ready
1271
- if (document.readyState === 'loading') {
1272
- document.addEventListener('DOMContentLoaded', () => new DarkModeManager());
1273
- } else {
1274
- new DarkModeManager();
1275
- }
1276
- </script>
1277
-
1278
- <style>
1279
- .dark-mode-toggle {
1280
- position: fixed;
1281
- bottom: 20px;
1282
- right: 20px;
1283
- width: 50px;
1284
- height: 50px;
1285
- border-radius: 50%;
1286
- background: var(--colors-neutral-100);
1287
- border: 2px solid var(--colors-neutral-300);
1288
- color: var(--colors-neutral-700);
1289
- cursor: pointer;
1290
- display: flex;
1291
- align-items: center;
1292
- justify-content: center;
1293
- font-size: 20px;
1294
- transition: all var(--transition-normal);
1295
- z-index: 1000;
1296
- }
1297
-
1298
- .dark-mode-toggle:hover {
1299
- transform: scale(1.1);
1300
- box-shadow: var(--shadows-md);
1301
- }
1302
-
1303
- .dark-mode-toggle.dark {
1304
- background: var(--colors-neutral-800);
1305
- border-color: var(--colors-neutral-600);
1306
- color: var(--colors-neutral-300);
1307
- }
1308
-
1309
- .dark-icon {
1310
- display: none;
1311
- }
1312
-
1313
- .dark-mode-toggle.dark .light-icon {
1314
- display: none;
1315
- }
1316
-
1317
- .dark-mode-toggle.dark .dark-icon {
1318
- display: inline;
1319
- }
1320
-
1321
- /* Smooth transitions for theme changes */
1322
- * {
1323
- transition: background-color var(--transition-normal),
1324
- border-color var(--transition-normal),
1325
- color var(--transition-normal);
1326
- }
1327
- </style>
1328
- """
1329
-
1330
- # ===========================================
1331
- # COMPONENT STYLES (CSS)
1332
- # ===========================================
1333
- def create_component_styles() -> str:
1334
- """Create all component styles in one place"""
1335
- return """
1336
- <style>
1337
  /* Card styles */
1338
  .card {
1339
- background: var(--colors-neutral-50);
1340
  border-radius: var(--borderRadius-lg);
1341
  padding: var(--spacing-6);
1342
  border: 1px solid var(--border-color, var(--colors-neutral-200));
1343
  transition: box-shadow var(--transition-normal);
 
 
 
 
 
 
 
1344
  }
1345
 
1346
  .card:hover {
1347
  box-shadow: var(--shadows-md);
1348
  }
1349
 
1350
- .card-elevated {
1351
- box-shadow: var(--shadows-lg);
1352
- border: none;
 
 
 
 
 
 
 
1353
  }
1354
 
1355
- .card-outlined {
1356
- border: 2px solid var(--border-color, var(--color-primary));
1357
- background: transparent;
1358
  }
1359
 
1360
- .card-filled {
1361
- background: var(--color-primary);
1362
- color: white;
1363
- border: none;
 
1364
  }
1365
 
1366
- .card-header {
1367
- margin-bottom: var(--spacing-4);
1368
- border-bottom: 1px solid var(--colors-neutral-200);
1369
- padding-bottom: var(--spacing-3);
1370
  }
1371
 
1372
- .card-title {
1373
  margin: 0;
1374
- font-size: var(--typography-fontSizes-xl);
1375
- font-weight: var(--typography-fontWeights-semibold);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1376
  color: var(--colors-neutral-900);
 
1377
  }
1378
 
1379
- .card-body {
 
1380
  color: var(--colors-neutral-700);
 
1381
  }
1382
 
1383
- .card-footer {
1384
- margin-top: var(--spacing-4);
1385
- padding-top: var(--spacing-3);
1386
- border-top: 1px solid var(--colors-neutral-200);
1387
  color: var(--colors-neutral-600);
1388
- font-size: var(--typography-fontSizes-sm);
 
 
1389
  }
1390
 
1391
- /* Metric card */
1392
- .card-metric {
1393
- text-align: center;
 
 
 
 
 
 
 
1394
  padding: var(--spacing-4);
 
 
1395
  }
1396
 
1397
- .metric-value {
1398
- font-size: var(--typography-fontSizes-3xl);
1399
- font-weight: var(--typography-fontWeights-bold);
1400
- color: var(--colors-neutral-900);
1401
- margin-bottom: var(--spacing-2);
1402
- font-family: var(--font-mono);
1403
  }
1404
 
1405
- .metric-label {
1406
  font-size: var(--typography-fontSizes-sm);
1407
  color: var(--colors-neutral-600);
1408
  text-transform: uppercase;
@@ -1410,301 +998,609 @@ def create_component_styles() -> str:
1410
  margin-bottom: var(--spacing-2);
1411
  }
1412
 
1413
- .metric-trend {
1414
- font-size: var(--typography-fontSizes-sm);
1415
- font-weight: var(--typography-fontWeights-semibold);
 
1416
  }
1417
 
1418
- /* Button styles */
1419
- .btn {
1420
- display: inline-flex;
1421
- align-items: center;
1422
- justify-content: center;
1423
- padding: var(--spacing-2) var(--spacing-4);
1424
- border-radius: var(--borderRadius-md);
1425
- font-weight: var(--typography-fontWeights-medium);
1426
- font-size: var(--typography-fontSizes-sm);
1427
- border: none;
1428
- cursor: pointer;
1429
- transition: all var(--transition-fast);
1430
- text-decoration: none;
1431
- gap: var(--spacing-2);
1432
  }
1433
 
1434
- .btn:disabled {
1435
- opacity: 0.5;
1436
- cursor: not-allowed;
1437
  }
1438
 
1439
- .btn-primary {
1440
- background: var(--color-primary);
1441
- color: white;
 
 
 
1442
  }
1443
 
1444
- .btn-primary:hover:not(:disabled) {
1445
- background: var(--colors-primary-600);
 
 
1446
  }
1447
 
1448
- .btn-secondary {
1449
- background: var(--colors-neutral-100);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1450
  color: var(--colors-neutral-700);
1451
- border: 1px solid var(--colors-neutral-300);
 
 
1452
  }
1453
 
1454
- .btn-secondary:hover:not(:disabled) {
1455
- background: var(--colors-neutral-200);
 
 
1456
  }
1457
 
1458
- .btn-danger {
 
1459
  background: var(--color-danger);
1460
  color: white;
 
 
 
1461
  }
1462
 
1463
- .btn-danger:hover:not(:disabled) {
1464
- background: var(--colors-danger-600);
 
 
 
 
 
1465
  }
1466
 
1467
- .btn-ghost {
1468
- background: transparent;
1469
- color: var(--colors-neutral-700);
1470
  }
1471
 
1472
- .btn-ghost:hover:not(:disabled) {
1473
- background: var(--colors-neutral-100);
 
1474
  }
1475
 
1476
- .btn-sm {
1477
- padding: var(--spacing-1) var(--spacing-3);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1478
  font-size: var(--typography-fontSizes-xs);
 
 
 
1479
  }
1480
 
1481
- .btn-lg {
1482
- padding: var(--spacing-3) var(--spacing-6);
1483
- font-size: var(--typography-fontSizes-base);
 
 
 
1484
  }
1485
 
1486
- .btn.full-width {
1487
- width: 100%;
 
 
 
 
 
 
1488
  }
1489
 
1490
- .btn-icon {
1491
- width: 40px;
1492
- height: 40px;
1493
- border-radius: var(--borderRadius-md);
1494
- background: transparent;
1495
- border: none;
1496
- cursor: pointer;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1497
  display: flex;
1498
  align-items: center;
1499
  justify-content: center;
1500
- transition: background var(--transition-fast);
 
 
 
 
1501
  }
1502
 
1503
- .btn-icon:hover {
1504
- background: var(--colors-neutral-100);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1505
  }
1506
 
1507
- /* Badge styles */
1508
- .badge {
1509
  display: inline-block;
1510
- padding: var(--spacing-1) var(--spacing-2);
 
 
1511
  border-radius: var(--borderRadius-full);
1512
  font-size: var(--typography-fontSizes-xs);
1513
- font-weight: var(--typography-fontWeights-medium);
1514
- text-transform: uppercase;
1515
- letter-spacing: 0.05em;
1516
  }
1517
 
1518
- .badge-default {
1519
- background: var(--colors-neutral-100);
1520
- color: var(--colors-neutral-700);
1521
  }
1522
 
1523
- .badge-success {
1524
- background: var(--colors-success-100);
1525
- color: var(--colors-success-700);
 
 
 
1526
  }
1527
 
1528
- .badge-warning {
1529
- background: var(--colors-warning-100);
1530
- color: var(--colors-warning-700);
1531
  }
1532
 
1533
- .badge-danger {
1534
- background: var(--colors-danger-100);
1535
- color: var(--colors-danger-700);
 
1536
  }
1537
 
1538
- .badge-sm {
1539
- padding: 2px 6px;
1540
- font-size: 10px;
 
1541
  }
1542
 
1543
- .badge-lg {
1544
- padding: var(--spacing-1) var(--spacing-3);
1545
- font-size: var(--typography-fontSizes-sm);
 
1546
  }
1547
 
1548
- /* Observation gate styles */
1549
- .observation-gate {
1550
- border: 3px solid var(--status-color, var(--color-warning));
1551
  border-radius: var(--borderRadius-xl);
1552
  padding: var(--spacing-6);
1553
- background: linear-gradient(135deg,
1554
- color-mix(in srgb, var(--status-color, var(--color-warning)) 5%, transparent),
1555
- color-mix(in srgb, var(--status-color, var(--color-warning)) 10%, transparent));
1556
- margin: var(--spacing-4) 0;
1557
  }
1558
 
1559
- .observation-gate-header {
 
 
 
 
1560
  display: flex;
 
1561
  align-items: center;
1562
- gap: var(--spacing-4);
1563
- margin-bottom: var(--spacing-4);
1564
  }
1565
 
1566
- .observation-icon {
1567
- font-size: 48px;
1568
- color: var(--status-color, var(--color-warning));
 
1569
  }
1570
 
1571
- .observation-title h3 {
1572
  margin: 0;
1573
- color: color-mix(in srgb, var(--status-color, var(--color-warning)) 90%, black);
1574
- font-size: var(--typography-fontSizes-2xl);
1575
- }
1576
-
1577
- .observation-title p {
1578
- margin: var(--spacing-1) 0 0 0;
1579
- color: color-mix(in srgb, var(--status-color, var(--color-warning)) 70%, black);
1580
  }
1581
 
1582
- .observation-badge {
1583
- margin-left: auto;
1584
  padding: var(--spacing-2) var(--spacing-4);
1585
- background: var(--status-color, var(--color-warning));
1586
  color: white;
1587
  border-radius: var(--borderRadius-full);
1588
  font-size: var(--typography-fontSizes-xs);
1589
  font-weight: var(--typography-fontWeights-bold);
1590
- text-transform: uppercase;
1591
- letter-spacing: 1px;
1592
  }
1593
 
1594
- .confidence-comparison {
1595
  display: grid;
1596
  grid-template-columns: 1fr 1fr;
 
 
 
 
 
 
 
1597
  gap: var(--spacing-4);
1598
- margin: var(--spacing-4) 0;
1599
  }
1600
 
1601
- .confidence-item {
1602
- background: white;
1603
- border-radius: var(--borderRadius-lg);
1604
- padding: var(--spacing-4);
1605
- text-align: center;
1606
- border: 1px solid var(--colors-neutral-200);
 
1607
  }
1608
 
1609
- .confidence-label {
1610
- font-size: var(--typography-fontSizes-sm);
1611
- color: var(--colors-neutral-600);
1612
- text-transform: uppercase;
1613
- letter-spacing: 0.05em;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1614
  margin-bottom: var(--spacing-2);
1615
  }
1616
 
1617
- .confidence-value {
1618
- font-size: var(--typography-fontSizes-3xl);
 
 
 
 
 
 
 
 
1619
  font-weight: var(--typography-fontWeights-bold);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1620
  margin-bottom: var(--spacing-1);
1621
  }
1622
 
1623
- .confidence-note {
1624
- font-size: var(--typography-fontSizes-xs);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1625
  color: var(--colors-neutral-500);
 
 
 
 
 
 
 
 
1626
  }
1627
 
1628
- /* Process display styles */
1629
- .process-card {
1630
- border: 2px solid var(--colors-neutral-300);
1631
  border-radius: var(--borderRadius-lg);
1632
  padding: var(--spacing-4);
1633
- margin: var(--spacing-3) 0;
1634
- background: var(--colors-neutral-50);
1635
  }
1636
 
1637
- .process-card[data-status="active"] {
1638
- border-color: var(--color-success);
1639
- background: color-mix(in srgb, var(--color-success) 5%, transparent);
1640
  }
1641
 
1642
- .process-card[data-status="error"] {
1643
- border-color: var(--color-danger);
1644
- background: color-mix(in srgb, var(--color-danger) 5%, transparent);
 
1645
  }
1646
 
1647
- .process-header {
1648
- display: flex;
1649
- align-items: center;
1650
- gap: var(--spacing-3);
1651
- margin-bottom: var(--spacing-3);
 
 
 
 
 
1652
  }
1653
 
1654
- .process-icon {
1655
- font-size: 32px;
 
 
 
 
 
1656
  }
1657
 
1658
- .process-title h4 {
1659
- margin: 0;
1660
- font-size: var(--typography-fontSizes-lg);
 
 
 
 
 
 
 
 
 
 
 
 
1661
  color: var(--colors-neutral-900);
 
1662
  }
1663
 
1664
- .process-title p {
1665
- margin: var(--spacing-1) 0 0 0;
1666
- font-size: var(--typography-fontSizes-sm);
1667
  color: var(--colors-neutral-600);
1668
  }
1669
 
1670
- .process-status {
1671
- margin-left: auto;
1672
- padding: var(--spacing-1) var(--spacing-3);
1673
- background: var(--status-color, var(--colors-neutral-300));
1674
  color: white;
1675
  border-radius: var(--borderRadius-full);
1676
- font-size: var(--typography-fontSizes-xs);
1677
  font-weight: var(--typography-fontWeights-bold);
1678
  text-transform: uppercase;
1679
  letter-spacing: 0.05em;
1680
  }
1681
 
1682
- .process-metrics {
1683
  display: grid;
1684
- grid-template-columns: repeat(2, 1fr);
1685
- gap: var(--spacing-3);
1686
- margin-bottom: var(--spacing-3);
1687
  }
1688
 
1689
- .process-metric {
1690
- background: white;
1691
- border-radius: var(--borderRadius-md);
1692
- padding: var(--spacing-2);
1693
- border: 1px solid var(--colors-neutral-200);
1694
  }
1695
 
1696
- .metric-key {
1697
- font-size: var(--typography-fontSizes-xs);
 
 
 
 
1698
  color: var(--colors-neutral-600);
1699
  text-transform: uppercase;
1700
  letter-spacing: 0.05em;
 
1701
  }
1702
 
1703
- .metric-value {
1704
- font-size: var(--typography-fontSizes-lg);
1705
- font-weight: var(--typography-fontWeights-semibold);
1706
  color: var(--colors-neutral-900);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1707
  font-family: var(--font-mono);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1708
  }
1709
 
1710
  /* Responsive adjustments */
@@ -1713,10 +1609,29 @@ def create_component_styles() -> str:
1713
  grid-template-columns: 1fr;
1714
  }
1715
 
1716
- .process-metrics {
 
 
 
 
 
 
 
 
 
 
 
 
 
1717
  grid-template-columns: 1fr;
1718
  }
1719
 
 
 
 
 
 
 
1720
  .observation-gate-header {
1721
  flex-direction: column;
1722
  text-align: center;
@@ -1727,20 +1642,16 @@ def create_component_styles() -> str:
1727
  margin-left: 0;
1728
  margin-top: var(--spacing-2);
1729
  }
1730
- }
1731
-
1732
- @media (max-width: 480px) {
1733
  .card {
1734
  padding: var(--spacing-3);
1735
  }
1736
 
1737
- .observation-gate {
 
 
1738
  padding: var(--spacing-3);
1739
  }
1740
-
1741
- .metric-value {
1742
- font-size: var(--typography-fontSizes-2xl);
1743
- }
1744
  }
1745
  </style>
1746
  """
@@ -1753,132 +1664,47 @@ def initialize_modern_ui() -> str:
1753
  components = [
1754
  inject_design_tokens(),
1755
  create_component_styles(),
1756
- ResponsiveUtils.create_responsive_styles(),
1757
- Accessibility.create_skip_link(),
1758
- Accessibility.create_aria_live_regions(),
1759
- DarkMode.create_toggle(),
1760
- ResponsiveUtils.create_mobile_navigation(),
1761
- Accessibility.create_focus_management()
1762
- ]
1763
-
1764
- return "\n".join(components)
1765
-
1766
- # ===========================================
1767
- # EXAMPLE USAGE (for documentation)
1768
- # ===========================================
1769
- def create_example_dashboard() -> str:
1770
- """Create an example dashboard using modern components"""
1771
-
1772
- # Example metrics
1773
- metrics = [
1774
- {"value": "42s", "label": "Detection Time", "trend": "down", "change": "↓ 90%"},
1775
- {"value": "94%", "label": "Recall Quality", "trend": "up", "change": "↑ 8%"},
1776
- {"value": "87%", "label": "Confidence Score", "trend": "neutral", "change": "→"},
1777
- {"value": "Dampening", "label": "Sequencing Stage", "trend": None}
1778
- ]
1779
-
1780
- # Example process data
1781
- detection_process = {
1782
- "status": "active",
1783
- "title": "Detection Process",
1784
- "description": "Telemetry analysis & pattern recognition",
1785
- "metrics": {
1786
- "Pattern Match": "Retry Amplification",
1787
- "Confidence": "92.7%",
1788
- "Detection Time": "0.8 seconds",
1789
- "Severity": "HIGH_VARIANCE"
1790
- },
1791
- "content": """
1792
- <div class="success-message">
1793
- ✅ Detected: Retry amplification pattern with exponential growth (r=1.8)
1794
- </div>
1795
- """,
1796
- "next_step": "Activate recall process"
1797
- }
1798
-
1799
- # Build dashboard
1800
- dashboard = f"""
1801
- {initialize_modern_ui()}
1802
-
1803
- <div class="container" style="max-width: 1200px; margin: 0 auto;">
1804
- <h1>Modern ARF Dashboard</h1>
1805
-
1806
- <!-- Metric Grid -->
1807
- {Grid.create_metric_grid(metrics)}
1808
-
1809
- <!-- Observation Gate -->
1810
- {ObservationGate.create(confidence=65.0)}
1811
-
1812
- <!-- Process Display -->
1813
- {ProcessDisplay.create('detection', detection_process)}
1814
 
1815
- <!-- Sequencing Flow -->
1816
- {SequencingFlow.create([
1817
- {"title": "Dampening", "description": "Prevent amplification first", "badge": "REQUIRED"},
1818
- {"title": "Concurrency", "description": "Manage load, then observe", "badge": "REQUIRED"},
1819
- {"title": "Observe", "description": "Validate trends for 5+ minutes", "badge": "REQUIRED"},
1820
- {"title": "Scale", "description": "Only if all previous succeed", "badge": "OPTIONAL"}
1821
- ])}
1822
 
1823
- <!-- Example Cards -->
1824
- <div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; margin-top: 30px;">
1825
- {Card.create(
1826
- title="OSS Analysis",
1827
- content="Open source advisory intelligence",
1828
- footer="Apache 2.0 License",
1829
- variant="outlined",
1830
- border_color="var(--color-success)"
1831
- )}
1832
-
1833
- {Card.create(
1834
- title="Enterprise Execution",
1835
- content="Commercial autonomous execution",
1836
- footer="Requires License",
1837
- variant="elevated"
1838
- )}
1839
- </div>
1840
- </div>
1841
- """
1842
 
1843
- return dashboard
1844
 
1845
  # ===========================================
1846
  # EXPORT LIST
1847
  # ===========================================
1848
  __all__ = [
1849
  # Core components
1850
- 'ModernComponent', 'Card', 'Button', 'Badge',
1851
- 'Grid', 'Stack',
1852
 
1853
- # ARF-specific components
1854
  'ObservationGate', 'SequencingFlow', 'ProcessDisplay',
 
1855
 
1856
- # Visualization
1857
- 'Chart',
1858
-
1859
- # Utilities
1860
- 'ResponsiveUtils', 'Accessibility', 'DarkMode',
1861
 
1862
  # Initialization
1863
- 'initialize_modern_ui', 'create_example_dashboard',
1864
-
1865
- # Constants
1866
- 'DESIGN_TOKENS'
1867
- ]
1868
-
1869
- # ===========================================
1870
- # TESTING CODE (Remove in production)
1871
- # ===========================================
1872
- if __name__ == "__main__":
1873
- # Test that components can be created
1874
- print("Testing modern components...")
1875
-
1876
- # Create example dashboard
1877
- example = create_example_dashboard()
1878
-
1879
- # Save to file for inspection
1880
- with open("modern_dashboard_example.html", "w") as f:
1881
- f.write(example)
1882
-
1883
- print("✅ Modern components created successfully")
1884
- print("📄 Example saved to: modern_dashboard_example.html")
 
1
  """
2
+ ui/modern_components.py - ENHANCED VERSION
3
+ 🚀 Modern UI Components for ARF v3.3.9 with Complete Psychological Integration
 
 
4
  Features:
5
  1. Design token system with CSS variables
6
+ 2. All psychological features (observation gate, sequencing, historical evidence, healing intent)
7
  3. Accessibility (ARIA labels, keyboard nav)
8
  4. Performance optimizations
9
  5. Dark mode support
10
+ 6. Integration with arf_modern_ui.py systems
11
  """
12
 
13
  import json
14
+ from datetime import datetime, timezone
15
  from typing import Dict, List, Any, Optional, Tuple
16
  import plotly.graph_objects as go
17
  import plotly.express as px
18
  import numpy as np
 
19
 
20
  # ===========================================
21
+ # DESIGN TOKEN SYSTEM - ALIGNED WITH arf_modern_ui.py
22
  # ===========================================
23
  DESIGN_TOKENS = {
24
  "colors": {
 
28
  "200": "#bfdbfe",
29
  "300": "#93c5fd",
30
  "400": "#60a5fa",
31
+ "500": "#3b82f6", # enterprise_primary
32
  "600": "#2563eb",
33
  "700": "#1d4ed8",
34
  "800": "#1e40af",
 
40
  "200": "#bbf7d0",
41
  "300": "#86efac",
42
  "400": "#4ade80",
43
+ "500": "#22c55e", # success
44
  "600": "#16a34a",
45
  "700": "#15803d",
46
  "800": "#166534",
 
52
  "200": "#fde68a",
53
  "300": "#fcd34d",
54
  "400": "#fbbf24",
55
+ "500": "#f59e0b", # warning
56
  "600": "#d97706",
57
  "700": "#b45309",
58
  "800": "#92400e",
 
64
  "200": "#fecaca",
65
  "300": "#fca5a5",
66
  "400": "#f87171",
67
+ "500": "#ef4444", # danger
68
  "600": "#dc2626",
69
  "700": "#b91c1c",
70
  "800": "#991b1b",
 
161
  :root {{
162
  {chr(10).join(css_variables)}
163
 
164
+ /* Semantic aliases matching arf_modern_ui.py */
165
+ --color-enterprise-primary: var(--colors-primary-500);
166
  --color-success: var(--colors-success-500);
167
  --color-warning: var(--colors-warning-500);
168
  --color-danger: var(--colors-danger-500);
169
+ --color-oss-primary: var(--colors-success-500);
170
+ --color-surface-light: #ffffff;
171
+ --color-surface-dark: var(--colors-neutral-800);
172
+ --color-background-light: var(--colors-neutral-50);
173
+ --color-background-dark: var(--colors-neutral-900);
174
 
175
  /* Spacing aliases */
176
  --spacing-xs: var(--spacing-2);
 
180
  --spacing-xl: var(--spacing-8);
181
 
182
  /* Font families */
183
+ --font-sans: system-ui, -apple-system, sans-serif;
184
  --font-mono: 'JetBrains Mono', 'SF Mono', Monaco, 'Cascadia Code', monospace;
185
 
186
+ /* Transitions matching arf_modern_ui.py */
187
  --transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
188
+ --transition-normal: 300ms cubic-bezier(0.4, 0, 0.2, 1);
189
+ --transition-slow: 500ms cubic-bezier(0.4, 0, 0.2, 1);
190
  }}
191
 
192
  /* Dark mode overrides */
 
217
  }}
218
 
219
  .focus-ring {{
220
+ outline: 2px solid var(--color-enterprise-primary);
221
  outline-offset: 2px;
222
  }}
223
 
 
345
  </div>
346
  """
347
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
348
  # ===========================================
349
+ # CRITICAL PSYCHOLOGICAL COMPONENTS
350
  # ===========================================
351
  class ObservationGate(ModernComponent):
352
+ """Observation gate component showing system restraint - PSYCHOLOGICAL CORE"""
353
 
354
  @staticmethod
355
  def create(confidence: float = 65.0, **kwargs) -> str:
356
+ """Create observation gate display with psychological restraint"""
357
  reason = kwargs.get('reason', 'uncertainty_too_high_for_action')
358
  frozen_until = kwargs.get('frozen_until', '')
359
 
 
363
  # Format countdown if available
364
  countdown_html = ""
365
  if frozen_until:
366
+ try:
367
+ frozen_dt = datetime.fromisoformat(frozen_until.replace("Z", "+00:00"))
368
+ now = datetime.now(timezone.utc)
369
+ if frozen_dt.tzinfo is None:
370
+ frozen_dt = frozen_dt.replace(tzinfo=timezone.utc)
371
+ time_left = frozen_dt - now
372
+ minutes_left = max(0, int(time_left.total_seconds() / 60))
373
+ countdown_html = f"""
374
+ <div class="countdown">
375
+ <div class="countdown-label">Next evaluation:</div>
376
+ <div class="countdown-timer">{minutes_left}:00</div>
377
+ </div>
378
+ """
379
+ except:
380
+ countdown_html = """
381
+ <div class="countdown">
382
+ <div class="countdown-label">Next evaluation:</div>
383
+ <div class="countdown-timer">5:00</div>
384
+ </div>
385
+ """
386
 
387
  status_text = "Observation Gate: Awaiting confirmation" if is_blocked else "Observation Gate Cleared"
388
  status_color = "var(--color-warning)" if is_blocked else "var(--color-success)"
389
+ icon = "⏳" if is_blocked else "✅"
390
+
391
+ # Psychological messaging
392
+ restraint_message = """
393
+ <div class="psych-message">
394
+ <h4>Decision Intentionally Deferred</h4>
395
+ <p>The system has detected uncertainty (<strong>{confidence:.1f}% confidence</strong>)
396
+ and has <strong>chosen to observe</strong> rather than act. Historical evidence indicates
397
+ premature action increases risk by <strong>47%</strong>, so the system is enforcing an observation-first policy.</p>
398
+ <p class="psych-note"><em>"What you are seeing is not waiting. It is judgment under uncertainty."</em></p>
399
+ </div>
400
+ """ if is_blocked else """
401
+ <div class="psych-message">
402
+ <h4>Proceed with Policy Action</h4>
403
+ <p>Confidence exceeds threshold. System may proceed with sequenced actions.
404
+ Historical evidence will be consulted before any execution.</p>
405
+ </div>
406
+ """
407
 
408
  return f"""
409
  <div class="observation-gate" style="--status-color: {status_color};">
410
  <div class="observation-gate-header">
411
+ <div class="observation-icon">{icon}</div>
412
  <div class="observation-title">
413
  <h3>{status_text}</h3>
414
  <p>System restraint engaged</p>
 
419
  </div>
420
 
421
  <div class="observation-content">
422
+ {restraint_message}
 
 
 
 
 
423
 
424
  <div class="confidence-comparison">
425
  <div class="confidence-item">
 
431
  <div class="confidence-item">
432
  <div class="confidence-label">Current Confidence</div>
433
  <div class="confidence-value" style="color: {status_color};">{confidence:.1f}%</div>
434
+ <div class="confidence-note">{"Below threshold → Observe" if is_blocked else "Above threshold → Proceed"}</div>
435
  </div>
436
  </div>
437
 
438
  <div class="confidence-visualization">
439
  <div class="confidence-scale">
440
  <div class="scale-marker" style="left: {confidence}%;"></div>
441
+ <div class="scale-bar" style="width: {confidence}%; background: {status_color};"></div>
442
  </div>
443
  <div class="scale-labels">
444
+ <span>{"Observe" if is_blocked else "Ready"} ({confidence:.1f}%)</span>
445
  <span>Threshold ({threshold}%)</span>
446
+ <span>{"Act" if is_blocked else "Proceed"} (75%+)</span>
447
  </div>
448
  </div>
449
 
 
462
  """
463
 
464
  class SequencingFlow(ModernComponent):
465
+ """Visualization of policy-enforced sequencing - PSYCHOLOGICAL CORE"""
466
 
467
  @staticmethod
468
+ def create(steps: List[Dict[str, Any]] = None, **kwargs) -> str:
469
  """Create sequencing flow visualization"""
470
+ if steps is None:
471
+ steps = [
472
+ {"title": "Dampening", "description": "Prevent amplification first", "badge": "REQUIRED"},
473
+ {"title": "Concurrency", "description": "Manage load, then observe", "badge": "REQUIRED"},
474
+ {"title": "Observe", "description": "Validate trends for 5+ minutes", "badge": "REQUIRED"},
475
+ {"title": "Scale", "description": "Only if all previous succeed", "badge": "OPTIONAL"}
476
+ ]
477
+
478
  current_step = kwargs.get('current_step', 0)
479
 
480
  steps_html = []
 
523
  <h4>Doctrinal Constraint: Scaling Cannot Appear First</h4>
524
  <p>If retry amplification is detected, scaling is <strong>contraindicated entirely</strong>.
525
  The system must observe stabilization before considering capacity increases.
526
+ Historical evidence shows scaling-first fails <strong>76%</strong> of the time during amplification.</p>
527
+ <p class="psych-note"><em>"What happened is more important than what might happen."</em></p>
528
  </div>
529
  </div>
530
  </div>
531
  """
532
 
533
  class ProcessDisplay(ModernComponent):
534
+ """Display for ARF processes (Detection, Recall, Decision) - PSYCHOLOGICAL CORE"""
535
 
536
  @staticmethod
537
  def create(process_type: str, data: Dict[str, Any]) -> str:
 
580
  </div>
581
  """
582
 
583
+ # Content with psychological emphasis
584
+ content_html = data.get('content', '')
585
+ if process_type == 'recall' and 'historical_evidence' in data:
586
+ content_html += f"""
587
+ <div class="psych-emphasis">
588
+ <div class="emphasis-icon">🧠</div>
589
+ <div class="emphasis-content">
590
+ <strong>Recall Dominance:</strong> Historical evidence outweighs predictive confidence.
591
+ The system prioritizes what <em>has happened</em> over what <em>might happen</em>.
592
+ </div>
593
+ </div>
594
+ """
595
+
596
  return f"""
597
  <div class="process-card" data-process="{process_type}" data-status="{status}">
598
  <div class="process-header">
 
608
 
609
  <div class="process-body">
610
  {metrics_html}
611
+ {content_html}
 
 
612
  {next_step_html}
613
  </div>
614
  </div>
615
  """
616
 
617
+ class HistoricalEvidencePanel(ModernComponent):
618
+ """Historical evidence panel - PSYCHOLOGICAL CORE (Recall Dominance)"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
619
 
620
  @staticmethod
621
+ def create(evidence_data: Dict[str, Any] = None, **kwargs) -> str:
622
+ """Create historical evidence panel showing recall dominance"""
623
+ if evidence_data is None:
624
+ evidence_data = {
625
+ "scaling_failures": [
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
626
  {
627
+ "date": "2024-11-15",
628
+ "environment": "prod-east",
629
+ "action": "Scale during retry storm",
630
+ "outcome": "Amplification increased 300%",
631
+ "lesson": "Scaling during amplification worsens the problem"
632
  },
633
  {
634
+ "date": "2024-09-22",
635
+ "environment": "staging",
636
+ "action": "Add capacity without dampening",
637
+ "outcome": "45 min outage, $8.2K loss",
638
+ "lesson": "New capacity consumed by amplification loop"
639
+ }
640
+ ],
641
+ "dampening_successes": [
642
+ {
643
+ "date": "2024-12-03",
644
+ "environment": "prod-west",
645
+ "action": "Request coalescing + backoff",
646
+ "outcome": "Resolved in 8 min, $5.1K saved",
647
+ "lesson": "Dampening broke amplification cycle"
648
  },
649
  {
650
+ "date": "2024-10-17",
651
+ "environment": "prod-eu",
652
+ "action": "Circuit breaker + observability",
653
+ "outcome": "12 min recovery, 0 user impact",
654
+ "lesson": "Sequencing prevented escalation"
655
  }
656
+ ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
657
  }
 
658
 
659
+ # Build failures HTML
660
+ failures_html = ""
661
+ for i, failure in enumerate(evidence_data.get('scaling_failures', [])[:3]):
662
+ failures_html += f"""
663
+ <div class="evidence-item evidence-failure">
664
+ <div class="evidence-header">
665
+ <div class="evidence-date">{failure.get('date', 'Unknown')} • {failure.get('environment', 'Unknown')}</div>
666
+ <div class="evidence-badge failure">FAILED</div>
667
+ </div>
668
+ <div class="evidence-content">
669
+ <div class="evidence-action"><strong>Action:</strong> {failure.get('action', 'Unknown')}</div>
670
+ <div class="evidence-outcome"><strong>Outcome:</strong> {failure.get('outcome', 'Unknown')}</div>
671
+ <div class="evidence-lesson">"{failure.get('lesson', 'No lesson captured')}"</div>
672
+ </div>
673
+ </div>
674
+ """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
675
 
676
+ # Build successes HTML
677
+ successes_html = ""
678
+ for i, success in enumerate(evidence_data.get('dampening_successes', [])[:3]):
679
+ successes_html += f"""
680
+ <div class="evidence-item evidence-success">
681
+ <div class="evidence-header">
682
+ <div class="evidence-date">{success.get('date', 'Unknown')} • {success.get('environment', 'Unknown')}</div>
683
+ <div class="evidence-badge success">SUCCESS</div>
684
+ </div>
685
+ <div class="evidence-content">
686
+ <div class="evidence-action"><strong>Action:</strong> {success.get('action', 'Unknown')}</div>
687
+ <div class="evidence-outcome"><strong>Outcome:</strong> {success.get('outcome', 'Unknown')}</div>
688
+ <div class="evidence-lesson">"{success.get('lesson', 'No lesson captured')}"</div>
689
+ </div>
690
+ </div>
691
+ """
 
 
 
 
 
 
 
692
 
693
+ return f"""
694
+ <div class="historical-evidence-panel">
695
+ <div class="evidence-header-main">
696
+ <div>
697
+ <h3>🧠 Historical Evidence (Why Sequencing Matters)</h3>
698
+ <p>Real outcomes from similar incidents—this evidence dominates decision logic</p>
699
+ </div>
700
+ <div class="evidence-dominance-badge">
701
+ Historical evidence outweighs model confidence
702
+ </div>
703
+ </div>
704
 
705
+ <div class="evidence-comparison">
706
+ <div class="evidence-column">
707
+ <div class="column-header failure">
708
+ <span>⛔</span> Scaling-First Failures
709
+ </div>
710
+ {failures_html if failures_html else '''
711
+ <div class="evidence-empty">
712
+ <div class="empty-icon">📊</div>
713
+ <div class="empty-text">Scaling-First Failures (Evidence Present)</div>
714
+ </div>
715
+ '''}
716
+ </div>
717
+
718
+ <div class="evidence-column">
719
+ <div class="column-header success">
720
+ <span>✅</span> Dampening-First Successes
721
+ </div>
722
+ {successes_html if successes_html else '''
723
+ <div class="evidence-empty">
724
+ <div class="empty-icon">📊</div>
725
+ <div class="empty-text">Dampening-First Successes (Evidence Present)</div>
726
+ </div>
727
+ '''}
728
+ </div>
729
+ </div>
730
 
731
+ <div class="psych-principle">
732
+ <div class="principle-icon">🎯</div>
733
+ <div class="principle-content">
734
+ <h4>If history shows failure, the system will not repeat it.</h4>
735
+ <p>The system prioritizes <strong>historical evidence over predictive confidence</strong>.
736
+ If scaling-first failed in similar conditions, scaling is contraindicated regardless of model confidence.</p>
737
+ <p class="psych-note"><em>"What happened is more important than what might happen."</em></p>
738
+ </div>
739
+ </div>
740
+ </div>
741
  """
742
 
743
+ class HealingIntentDisplay(ModernComponent):
744
+ """Formal HealingIntent display - PSYCHOLOGICAL CORE"""
 
 
 
745
 
746
  @staticmethod
747
+ def create(healing_intent: Dict[str, Any], **kwargs) -> str:
748
+ """Create formal HealingIntent display with all fields"""
749
+ confidence = healing_intent.get('confidence', 0.0)
750
+ primary_action = healing_intent.get('primary_action', '')
751
+ sequencing_rule = healing_intent.get('sequencing_rule', '')
752
+ preconditions = healing_intent.get('preconditions', [])
753
+ contraindications = healing_intent.get('contraindications', [])
754
+ reversibility = healing_intent.get('reversibility_statement', '')
755
+ historical_evidence = healing_intent.get('historical_evidence', [])
756
+
757
+ # Preconditions HTML
758
+ preconditions_html = ""
759
+ if preconditions:
760
+ preconditions_html = "<div class='preconditions-list'>"
761
+ for pre in preconditions:
762
+ preconditions_html += f"<div class='precondition-item'>• {pre}</div>"
763
+ preconditions_html += "</div>"
764
+
765
+ # Contraindications HTML
766
+ contraindications_html = ""
767
+ if contraindications:
768
+ contraindications_html = "<div class='contraindications-list'>"
769
+ for contra in contraindications:
770
+ contraindications_html += f"<div class='contraindication-item'>⛔ {contra}</div>"
771
+ contraindications_html += "</div>"
772
+
773
+ # Historical evidence HTML
774
+ historical_html = ""
775
+ if historical_evidence:
776
+ historical_html = "<div class='historical-list'>"
777
+ for evidence in historical_evidence:
778
+ historical_html += f"<div class='historical-item'>📊 {evidence}</div>"
779
+ historical_html += "</div>"
780
 
781
+ return f"""
782
+ <div class="healing-intent-display">
783
+ <div class="intent-header">
784
+ <div>
785
+ <h3>📝 Formal HealingIntent Created</h3>
786
+ <p>Preconditions checked, contraindications listed, reversibility guaranteed</p>
787
+ </div>
788
+ <div class="confidence-badge" style="--confidence-color: {'' if confidence >= 70 else 'var(--color-warning)'};">
789
+ CONFIDENCE: {confidence:.1f}%
790
+ </div>
791
+ </div>
792
+
793
+ <div class="intent-grid">
794
+ <div class="intent-section">
795
+ <div class="section-title">Primary Action</div>
796
+ <div class="section-content primary-action">
797
+ {primary_action}
798
+ </div>
799
+ </div>
800
 
801
+ <div class="intent-section">
802
+ <div class="section-title">Sequencing Rule</div>
803
+ <div class="section-content sequencing-rule">
804
+ {sequencing_rule}
805
+ </div>
806
+ </div>
807
+ </div>
808
 
809
+ <div class="intent-details">
810
+ <div class="detail-section">
811
+ <div class="detail-title">Preconditions</div>
812
+ <div class="detail-content">
813
+ {preconditions_html if preconditions_html else '<div class="empty-detail">No preconditions specified</div>'}
814
+ </div>
815
+ </div>
816
 
817
+ <div class="detail-section">
818
+ <div class="detail-title">Contraindications</div>
819
+ <div class="detail-content">
820
+ {contraindications_html if contraindications_html else '<div class="empty-detail">No contraindications</div>'}
821
+ </div>
822
+ </div>
823
+
824
+ <div class="detail-section">
825
+ <div class="detail-title">Reversibility Statement</div>
826
+ <div class="detail-content reversibility">
827
+ {reversibility if reversibility else '<div class="empty-detail">No reversibility statement</div>'}
828
+ </div>
829
+ </div>
830
+ </div>
831
 
832
+ {historical_html if historical_html else ''}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
833
 
834
+ <div class="psych-doctrine">
835
+ <div class="doctrine-icon">⚖️</div>
836
+ <div class="doctrine-content">
837
+ <h4>Doctrinal Principle: Formal Documentation Prevents Mistakes</h4>
838
+ <p>Every HealingIntent must document preconditions, contraindications, and reversibility.
839
+ This formal structure ensures decisions are reviewable, reversible, and grounded in evidence.</p>
840
+ </div>
841
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
842
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
843
  """
844
 
845
  # ===========================================
846
+ # COMPONENT STYLES (CSS) - ENHANCED
847
  # ===========================================
848
+ def create_component_styles() -> str:
849
+ """Create all component styles with psychological enhancements"""
850
+ return """
851
+ <style>
852
+ /* Base styles */
853
+ body, .gr-box, .gr-form, .gr-panel, .gr-tab, .gr-container {
854
+ background-color: var(--color-background-light) !important;
855
+ color: var(--colors-neutral-900) !important;
856
+ font-family: var(--font-sans);
857
+ }
858
+
859
+ [data-theme="dark"] body,
860
+ [data-theme="dark"] .gr-box,
861
+ [data-theme="dark"] .gr-form,
862
+ [data-theme="dark"] .gr-panel,
863
+ [data-theme="dark"] .gr-tab,
864
+ [data-theme="dark"] .gr-container {
865
+ background-color: var(--color-background-dark) !important;
866
+ color: var(--colors-neutral-100) !important;
867
+ }
868
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
869
  /* Card styles */
870
  .card {
871
+ background: var(--color-surface-light);
872
  border-radius: var(--borderRadius-lg);
873
  padding: var(--spacing-6);
874
  border: 1px solid var(--border-color, var(--colors-neutral-200));
875
  transition: box-shadow var(--transition-normal);
876
+ color: var(--colors-neutral-900);
877
+ }
878
+
879
+ [data-theme="dark"] .card {
880
+ background: var(--color-surface-dark);
881
+ border-color: var(--colors-neutral-700);
882
+ color: var(--colors-neutral-100);
883
  }
884
 
885
  .card:hover {
886
  box-shadow: var(--shadows-md);
887
  }
888
 
889
+ /* Observation gate styles */
890
+ .observation-gate {
891
+ border: 3px solid var(--status-color, var(--color-warning));
892
+ border-radius: var(--borderRadius-xl);
893
+ padding: var(--spacing-6);
894
+ background: linear-gradient(135deg,
895
+ color-mix(in srgb, var(--status-color, var(--color-warning)) 5%, transparent),
896
+ color-mix(in srgb, var(--status-color, var(--color-warning)) 10%, transparent));
897
+ margin: var(--spacing-6) 0;
898
+ color: var(--colors-neutral-900);
899
  }
900
 
901
+ [data-theme="dark"] .observation-gate {
902
+ color: var(--colors-neutral-100);
 
903
  }
904
 
905
+ .observation-gate-header {
906
+ display: flex;
907
+ align-items: center;
908
+ gap: var(--spacing-4);
909
+ margin-bottom: var(--spacing-4);
910
  }
911
 
912
+ .observation-icon {
913
+ font-size: 48px;
914
+ color: var(--status-color, var(--color-warning));
 
915
  }
916
 
917
+ .observation-title h3 {
918
  margin: 0;
919
+ color: color-mix(in srgb, var(--status-color, var(--color-warning)) 90%, var(--colors-neutral-900));
920
+ font-size: var(--typography-fontSizes-2xl);
921
+ font-weight: var(--typography-fontWeights-bold);
922
+ }
923
+
924
+ .observation-title p {
925
+ margin: var(--spacing-1) 0 0 0;
926
+ color: color-mix(in srgb, var(--status-color, var(--color-warning)) 70%, var(--colors-neutral-700));
927
+ }
928
+
929
+ .observation-badge {
930
+ margin-left: auto;
931
+ padding: var(--spacing-2) var(--spacing-4);
932
+ background: var(--status-color, var(--color-warning));
933
+ color: white;
934
+ border-radius: var(--borderRadius-full);
935
+ font-size: var(--typography-fontSizes-xs);
936
+ font-weight: var(--typography-fontWeights-bold);
937
+ text-transform: uppercase;
938
+ letter-spacing: 1px;
939
+ }
940
+
941
+ .psych-message {
942
+ background: white;
943
+ border: 2px solid var(--status-color, var(--color-warning));
944
+ padding: var(--spacing-4);
945
+ margin: var(--spacing-4) 0;
946
+ border-radius: var(--borderRadius-lg);
947
+ }
948
+
949
+ [data-theme="dark"] .psych-message {
950
+ background: var(--colors-neutral-800);
951
+ }
952
+
953
+ .psych-message h4 {
954
+ margin: 0 0 var(--spacing-2) 0;
955
  color: var(--colors-neutral-900);
956
+ font-size: var(--typography-fontSizes-lg);
957
  }
958
 
959
+ .psych-message p {
960
+ margin: var(--spacing-2) 0;
961
  color: var(--colors-neutral-700);
962
+ line-height: 1.6;
963
  }
964
 
965
+ .psych-note {
966
+ font-style: italic;
 
 
967
  color: var(--colors-neutral-600);
968
+ margin-top: var(--spacing-2);
969
+ border-left: 3px solid var(--status-color, var(--color-warning));
970
+ padding-left: var(--spacing-3);
971
  }
972
 
973
+ .confidence-comparison {
974
+ display: grid;
975
+ grid-template-columns: 1fr 1fr;
976
+ gap: var(--spacing-4);
977
+ margin: var(--spacing-4) 0;
978
+ }
979
+
980
+ .confidence-item {
981
+ background: var(--color-surface-light);
982
+ border-radius: var(--borderRadius-lg);
983
  padding: var(--spacing-4);
984
+ text-align: center;
985
+ border: 1px solid var(--colors-neutral-200);
986
  }
987
 
988
+ [data-theme="dark"] .confidence-item {
989
+ background: var(--colors-neutral-800);
990
+ border-color: var(--colors-neutral-700);
 
 
 
991
  }
992
 
993
+ .confidence-label {
994
  font-size: var(--typography-fontSizes-sm);
995
  color: var(--colors-neutral-600);
996
  text-transform: uppercase;
 
998
  margin-bottom: var(--spacing-2);
999
  }
1000
 
1001
+ .confidence-value {
1002
+ font-size: var(--typography-fontSizes-3xl);
1003
+ font-weight: var(--typography-fontWeights-bold);
1004
+ margin-bottom: var(--spacing-1);
1005
  }
1006
 
1007
+ .confidence-note {
1008
+ font-size: var(--typography-fontSizes-xs);
1009
+ color: var(--colors-neutral-500);
 
 
 
 
 
 
 
 
 
 
 
1010
  }
1011
 
1012
+ .confidence-visualization {
1013
+ margin: var(--spacing-6) 0;
 
1014
  }
1015
 
1016
+ .confidence-scale {
1017
+ height: 8px;
1018
+ background: var(--colors-neutral-200);
1019
+ border-radius: var(--borderRadius-full);
1020
+ position: relative;
1021
+ margin: var(--spacing-4) 0 var(--spacing-2);
1022
  }
1023
 
1024
+ .scale-bar {
1025
+ height: 100%;
1026
+ border-radius: var(--borderRadius-full);
1027
+ transition: width var(--transition-normal);
1028
  }
1029
 
1030
+ .scale-marker {
1031
+ position: absolute;
1032
+ top: -4px;
1033
+ width: 16px;
1034
+ height: 16px;
1035
+ background: white;
1036
+ border: 2px solid var(--colors-neutral-900);
1037
+ border-radius: 50%;
1038
+ transform: translateX(-50%);
1039
+ }
1040
+
1041
+ .scale-labels {
1042
+ display: flex;
1043
+ justify-content: space-between;
1044
+ font-size: var(--typography-fontSizes-xs);
1045
+ color: var(--colors-neutral-600);
1046
+ }
1047
+
1048
+ .prevented-actions {
1049
+ margin-top: var(--spacing-6);
1050
+ padding-top: var(--spacing-4);
1051
+ border-top: 2px solid var(--colors-neutral-200);
1052
+ }
1053
+
1054
+ .prevented-actions h5 {
1055
+ margin: 0 0 var(--spacing-3) 0;
1056
  color: var(--colors-neutral-700);
1057
+ font-size: var(--typography-fontSizes-sm);
1058
+ text-transform: uppercase;
1059
+ letter-spacing: 0.05em;
1060
  }
1061
 
1062
+ .action-tags {
1063
+ display: flex;
1064
+ flex-wrap: wrap;
1065
+ gap: var(--spacing-2);
1066
  }
1067
 
1068
+ .action-tag {
1069
+ padding: var(--spacing-1) var(--spacing-3);
1070
  background: var(--color-danger);
1071
  color: white;
1072
+ border-radius: var(--borderRadius-full);
1073
+ font-size: var(--typography-fontSizes-xs);
1074
+ font-weight: var(--typography-fontWeights-medium);
1075
  }
1076
 
1077
+ /* Sequencing flow styles */
1078
+ .sequencing-flow {
1079
+ background: var(--color-surface-light);
1080
+ border: 2px solid var(--color-enterprise-primary);
1081
+ border-radius: var(--borderRadius-xl);
1082
+ padding: var(--spacing-6);
1083
+ margin: var(--spacing-6) 0;
1084
  }
1085
 
1086
+ [data-theme="dark"] .sequencing-flow {
1087
+ background: var(--colors-neutral-800);
 
1088
  }
1089
 
1090
+ .sequencing-header {
1091
+ margin-bottom: var(--spacing-6);
1092
+ text-align: center;
1093
  }
1094
 
1095
+ .sequencing-header h3 {
1096
+ margin: 0 0 var(--spacing-2) 0;
1097
+ color: var(--colors-neutral-900);
1098
+ font-size: var(--typography-fontSizes-xl);
1099
+ }
1100
+
1101
+ .sequencing-header p {
1102
+ margin: 0;
1103
+ color: var(--colors-neutral-600);
1104
+ }
1105
+
1106
+ .policy-badge {
1107
+ display: inline-block;
1108
+ margin-top: var(--spacing-3);
1109
+ padding: var(--spacing-2) var(--spacing-4);
1110
+ background: var(--color-enterprise-primary);
1111
+ color: white;
1112
+ border-radius: var(--borderRadius-full);
1113
  font-size: var(--typography-fontSizes-xs);
1114
+ font-weight: var(--typography-fontWeights-bold);
1115
+ text-transform: uppercase;
1116
+ letter-spacing: 1px;
1117
  }
1118
 
1119
+ .sequencing-steps {
1120
+ display: flex;
1121
+ justify-content: space-between;
1122
+ align-items: center;
1123
+ position: relative;
1124
+ margin: var(--spacing-8) 0;
1125
  }
1126
 
1127
+ .step-connectors {
1128
+ position: absolute;
1129
+ top: 30px;
1130
+ left: 60px;
1131
+ right: 60px;
1132
+ display: flex;
1133
+ justify-content: space-between;
1134
+ z-index: 1;
1135
  }
1136
 
1137
+ .step-connector {
1138
+ flex: 1;
1139
+ height: 3px;
1140
+ background: var(--colors-neutral-300);
1141
+ margin: 0 var(--spacing-2);
1142
+ }
1143
+
1144
+ .step-connector.completed {
1145
+ background: linear-gradient(90deg, var(--color-enterprise-primary), var(--color-success));
1146
+ }
1147
+
1148
+ .sequencing-step {
1149
+ text-align: center;
1150
+ position: relative;
1151
+ z-index: 2;
1152
+ flex: 1;
1153
+ }
1154
+
1155
+ .step-number {
1156
+ width: 60px;
1157
+ height: 60px;
1158
+ background: var(--colors-neutral-100);
1159
+ color: var(--colors-neutral-700);
1160
+ border-radius: 50%;
1161
  display: flex;
1162
  align-items: center;
1163
  justify-content: center;
1164
+ margin: 0 auto var(--spacing-3);
1165
+ font-size: var(--typography-fontSizes-xl);
1166
+ font-weight: var(--typography-fontWeights-bold);
1167
+ border: 4px solid white;
1168
+ transition: all var(--transition-normal);
1169
  }
1170
 
1171
+ .sequencing-step.current .step-number {
1172
+ background: var(--color-enterprise-primary);
1173
+ color: white;
1174
+ box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
1175
+ }
1176
+
1177
+ .sequencing-step.completed .step-number {
1178
+ background: var(--color-success);
1179
+ color: white;
1180
+ }
1181
+
1182
+ .step-title {
1183
+ font-size: var(--typography-fontSizes-base);
1184
+ font-weight: var(--typography-fontWeights-bold);
1185
+ color: var(--colors-neutral-900);
1186
+ margin-bottom: var(--spacing-1);
1187
+ }
1188
+
1189
+ .step-description {
1190
+ font-size: var(--typography-fontSizes-sm);
1191
+ color: var(--colors-neutral-600);
1192
+ margin-bottom: var(--spacing-2);
1193
+ max-width: 180px;
1194
+ margin: 0 auto;
1195
  }
1196
 
1197
+ .step-badge {
 
1198
  display: inline-block;
1199
+ padding: var(--spacing-1) var(--spacing-3);
1200
+ background: var(--colors-neutral-100);
1201
+ color: var(--colors-neutral-700);
1202
  border-radius: var(--borderRadius-full);
1203
  font-size: var(--typography-fontSizes-xs);
1204
+ font-weight: var(--typography-fontWeights-bold);
1205
+ margin-top: var(--spacing-2);
 
1206
  }
1207
 
1208
+ .sequencing-step.current .step-badge {
1209
+ background: var(--color-enterprise-primary);
1210
+ color: white;
1211
  }
1212
 
1213
+ .sequencing-constraint {
1214
+ background: var(--colors-neutral-50);
1215
+ border-radius: var(--borderRadius-lg);
1216
+ padding: var(--spacing-4);
1217
+ border-left: 4px solid var(--color-enterprise-primary);
1218
+ margin-top: var(--spacing-6);
1219
  }
1220
 
1221
+ [data-theme="dark"] .sequencing-constraint {
1222
+ background: var(--colors-neutral-800);
 
1223
  }
1224
 
1225
+ .constraint-icon {
1226
+ font-size: 24px;
1227
+ color: var(--color-enterprise-primary);
1228
+ margin-bottom: var(--spacing-2);
1229
  }
1230
 
1231
+ .constraint-content h4 {
1232
+ margin: 0 0 var(--spacing-2) 0;
1233
+ color: var(--colors-neutral-900);
1234
+ font-size: var(--typography-fontSizes-lg);
1235
  }
1236
 
1237
+ .constraint-content p {
1238
+ margin: 0;
1239
+ color: var(--colors-neutral-700);
1240
+ line-height: 1.6;
1241
  }
1242
 
1243
+ /* Historical evidence panel styles */
1244
+ .historical-evidence-panel {
1245
+ border: 3px solid var(--color-enterprise-primary);
1246
  border-radius: var(--borderRadius-xl);
1247
  padding: var(--spacing-6);
1248
+ margin: var(--spacing-6) 0;
1249
+ background: var(--color-surface-light);
 
 
1250
  }
1251
 
1252
+ [data-theme="dark"] .historical-evidence-panel {
1253
+ background: var(--colors-neutral-800);
1254
+ }
1255
+
1256
+ .evidence-header-main {
1257
  display: flex;
1258
+ justify-content: space-between;
1259
  align-items: center;
1260
+ margin-bottom: var(--spacing-6);
 
1261
  }
1262
 
1263
+ .evidence-header-main h3 {
1264
+ margin: 0 0 var(--spacing-2) 0;
1265
+ color: var(--colors-neutral-900);
1266
+ font-size: var(--typography-fontSizes-xl);
1267
  }
1268
 
1269
+ .evidence-header-main p {
1270
  margin: 0;
1271
+ color: var(--colors-neutral-600);
 
 
 
 
 
 
1272
  }
1273
 
1274
+ .evidence-dominance-badge {
 
1275
  padding: var(--spacing-2) var(--spacing-4);
1276
+ background: var(--color-enterprise-primary);
1277
  color: white;
1278
  border-radius: var(--borderRadius-full);
1279
  font-size: var(--typography-fontSizes-xs);
1280
  font-weight: var(--typography-fontWeights-bold);
 
 
1281
  }
1282
 
1283
+ .evidence-comparison {
1284
  display: grid;
1285
  grid-template-columns: 1fr 1fr;
1286
+ gap: var(--spacing-6);
1287
+ margin-bottom: var(--spacing-6);
1288
+ }
1289
+
1290
+ .evidence-column {
1291
+ display: flex;
1292
+ flex-direction: column;
1293
  gap: var(--spacing-4);
 
1294
  }
1295
 
1296
+ .column-header {
1297
+ font-size: var(--typography-fontSizes-lg);
1298
+ font-weight: var(--typography-fontWeights-bold);
1299
+ margin-bottom: var(--spacing-2);
1300
+ display: flex;
1301
+ align-items: center;
1302
+ gap: var(--spacing-2);
1303
  }
1304
 
1305
+ .column-header.failure {
1306
+ color: var(--color-danger);
1307
+ }
1308
+
1309
+ .column-header.success {
1310
+ color: var(--color-success);
1311
+ }
1312
+
1313
+ .evidence-item {
1314
+ border-left: 4px solid;
1315
+ padding-left: var(--spacing-4);
1316
+ margin-bottom: var(--spacing-3);
1317
+ }
1318
+
1319
+ .evidence-failure {
1320
+ border-left-color: var(--color-danger);
1321
+ }
1322
+
1323
+ .evidence-success {
1324
+ border-left-color: var(--color-success);
1325
+ }
1326
+
1327
+ .evidence-header {
1328
+ display: flex;
1329
+ justify-content: space-between;
1330
+ align-items: flex-start;
1331
  margin-bottom: var(--spacing-2);
1332
  }
1333
 
1334
+ .evidence-date {
1335
+ font-size: var(--typography-fontSizes-sm);
1336
+ font-weight: var(--typography-fontWeights-semibold);
1337
+ color: var(--colors-neutral-900);
1338
+ }
1339
+
1340
+ .evidence-badge {
1341
+ padding: 2px 8px;
1342
+ border-radius: var(--borderRadius-full);
1343
+ font-size: var(--typography-fontSizes-xs);
1344
  font-weight: var(--typography-fontWeights-bold);
1345
+ }
1346
+
1347
+ .evidence-badge.failure {
1348
+ background: var(--color-danger);
1349
+ color: white;
1350
+ }
1351
+
1352
+ .evidence-badge.success {
1353
+ background: var(--color-success);
1354
+ color: white;
1355
+ }
1356
+
1357
+ .evidence-content {
1358
+ font-size: var(--typography-fontSizes-sm);
1359
+ }
1360
+
1361
+ .evidence-action {
1362
+ color: var(--colors-neutral-700);
1363
  margin-bottom: var(--spacing-1);
1364
  }
1365
 
1366
+ .evidence-outcome {
1367
+ color: var(--colors-neutral-600);
1368
+ margin-bottom: var(--spacing-2);
1369
+ font-weight: var(--typography-fontWeights-medium);
1370
+ }
1371
+
1372
+ .evidence-failure .evidence-outcome {
1373
+ color: var(--color-danger);
1374
+ }
1375
+
1376
+ .evidence-success .evidence-outcome {
1377
+ color: var(--color-success);
1378
+ }
1379
+
1380
+ .evidence-lesson {
1381
+ font-style: italic;
1382
  color: var(--colors-neutral-500);
1383
+ background: var(--colors-neutral-50);
1384
+ padding: var(--spacing-2);
1385
+ border-radius: var(--borderRadius-md);
1386
+ font-size: var(--typography-fontSizes-xs);
1387
+ }
1388
+
1389
+ [data-theme="dark"] .evidence-lesson {
1390
+ background: var(--colors-neutral-700);
1391
  }
1392
 
1393
+ .psych-principle {
1394
+ background: linear-gradient(135deg, var(--colors-primary-50), var(--colors-neutral-50));
 
1395
  border-radius: var(--borderRadius-lg);
1396
  padding: var(--spacing-4);
1397
+ border: 2px solid var(--colors-primary-300);
1398
+ margin-top: var(--spacing-6);
1399
  }
1400
 
1401
+ [data-theme="dark"] .psych-principle {
1402
+ background: linear-gradient(135deg, var(--colors-primary-900), var(--colors-neutral-800));
1403
+ border-color: var(--colors-primary-700);
1404
  }
1405
 
1406
+ .principle-icon {
1407
+ font-size: 28px;
1408
+ color: var(--color-enterprise-primary);
1409
+ margin-bottom: var(--spacing-2);
1410
  }
1411
 
1412
+ .principle-content h4 {
1413
+ margin: 0 0 var(--spacing-2) 0;
1414
+ color: var(--colors-neutral-900);
1415
+ font-size: var(--typography-fontSizes-lg);
1416
+ }
1417
+
1418
+ .principle-content p {
1419
+ margin: 0;
1420
+ color: var(--colors-neutral-700);
1421
+ line-height: 1.6;
1422
  }
1423
 
1424
+ /* Healing intent display styles */
1425
+ .healing-intent-display {
1426
+ background: var(--color-surface-light);
1427
+ border: 2px solid var(--color-success);
1428
+ border-radius: var(--borderRadius-xl);
1429
+ padding: var(--spacing-6);
1430
+ margin: var(--spacing-6) 0;
1431
  }
1432
 
1433
+ [data-theme="dark"] .healing-intent-display {
1434
+ background: var(--colors-neutral-800);
1435
+ }
1436
+
1437
+ .intent-header {
1438
+ display: flex;
1439
+ justify-content: space-between;
1440
+ align-items: center;
1441
+ margin-bottom: var(--spacing-6);
1442
+ padding-bottom: var(--spacing-4);
1443
+ border-bottom: 2px solid var(--colors-neutral-200);
1444
+ }
1445
+
1446
+ .intent-header h3 {
1447
+ margin: 0 0 var(--spacing-2) 0;
1448
  color: var(--colors-neutral-900);
1449
+ font-size: var(--typography-fontSizes-xl);
1450
  }
1451
 
1452
+ .intent-header p {
1453
+ margin: 0;
 
1454
  color: var(--colors-neutral-600);
1455
  }
1456
 
1457
+ .confidence-badge {
1458
+ padding: var(--spacing-2) var(--spacing-4);
1459
+ background: var(--confidence-color, var(--color-success));
 
1460
  color: white;
1461
  border-radius: var(--borderRadius-full);
1462
+ font-size: var(--typography-fontSizes-sm);
1463
  font-weight: var(--typography-fontWeights-bold);
1464
  text-transform: uppercase;
1465
  letter-spacing: 0.05em;
1466
  }
1467
 
1468
+ .intent-grid {
1469
  display: grid;
1470
+ grid-template-columns: 1fr 1fr;
1471
+ gap: var(--spacing-4);
1472
+ margin-bottom: var(--spacing-6);
1473
  }
1474
 
1475
+ .intent-section {
1476
+ background: var(--colors-neutral-50);
1477
+ border-radius: var(--borderRadius-lg);
1478
+ padding: var(--spacing-4);
 
1479
  }
1480
 
1481
+ [data-theme="dark"] .intent-section {
1482
+ background: var(--colors-neutral-700);
1483
+ }
1484
+
1485
+ .section-title {
1486
+ font-size: var(--typography-fontSizes-sm);
1487
  color: var(--colors-neutral-600);
1488
  text-transform: uppercase;
1489
  letter-spacing: 0.05em;
1490
+ margin-bottom: var(--spacing-2);
1491
  }
1492
 
1493
+ .section-content {
1494
+ font-size: var(--typography-fontSizes-base);
 
1495
  color: var(--colors-neutral-900);
1496
+ font-weight: var(--typography-fontWeights-medium);
1497
+ }
1498
+
1499
+ [data-theme="dark"] .section-content {
1500
+ color: var(--colors-neutral-100);
1501
+ }
1502
+
1503
+ .primary-action {
1504
+ color: var(--color-success);
1505
+ font-weight: var(--typography-fontWeights-semibold);
1506
+ }
1507
+
1508
+ .sequencing-rule {
1509
+ color: var(--color-enterprise-primary);
1510
  font-family: var(--font-mono);
1511
+ font-size: var(--typography-fontSizes-sm);
1512
+ }
1513
+
1514
+ .intent-details {
1515
+ display: grid;
1516
+ grid-template-columns: repeat(3, 1fr);
1517
+ gap: var(--spacing-4);
1518
+ margin-bottom: var(--spacing-6);
1519
+ }
1520
+
1521
+ .detail-section {
1522
+ background: var(--colors-neutral-50);
1523
+ border-radius: var(--borderRadius-lg);
1524
+ padding: var(--spacing-4);
1525
+ }
1526
+
1527
+ [data-theme="dark"] .detail-section {
1528
+ background: var(--colors-neutral-700);
1529
+ }
1530
+
1531
+ .detail-title {
1532
+ font-size: var(--typography-fontSizes-sm);
1533
+ color: var(--colors-neutral-600);
1534
+ text-transform: uppercase;
1535
+ letter-spacing: 0.05em;
1536
+ margin-bottom: var(--spacing-2);
1537
+ }
1538
+
1539
+ .detail-content {
1540
+ font-size: var(--typography-fontSizes-sm);
1541
+ color: var(--colors-neutral-700);
1542
+ line-height: 1.5;
1543
+ }
1544
+
1545
+ [data-theme="dark"] .detail-content {
1546
+ color: var(--colors-neutral-300);
1547
+ }
1548
+
1549
+ .preconditions-list {
1550
+ display: flex;
1551
+ flex-direction: column;
1552
+ gap: var(--spacing-1);
1553
+ }
1554
+
1555
+ .precondition-item {
1556
+ color: var(--colors-neutral-700);
1557
+ }
1558
+
1559
+ .contraindications-list {
1560
+ display: flex;
1561
+ flex-direction: column;
1562
+ gap: var(--spacing-1);
1563
+ }
1564
+
1565
+ .contraindication-item {
1566
+ color: var(--color-danger);
1567
+ font-weight: var(--typography-fontWeights-medium);
1568
+ }
1569
+
1570
+ .reversibility {
1571
+ color: var(--color-success);
1572
+ font-style: italic;
1573
+ }
1574
+
1575
+ .psych-doctrine {
1576
+ background: linear-gradient(135deg, var(--colors-success-50), var(--colors-neutral-50));
1577
+ border-radius: var(--borderRadius-lg);
1578
+ padding: var(--spacing-4);
1579
+ border: 2px solid var(--colors-success-300);
1580
+ margin-top: var(--spacing-6);
1581
+ }
1582
+
1583
+ [data-theme="dark"] .psych-doctrine {
1584
+ background: linear-gradient(135deg, var(--colors-success-900), var(--colors-neutral-800));
1585
+ border-color: var(--colors-success-700);
1586
+ }
1587
+
1588
+ .doctrine-icon {
1589
+ font-size: 28px;
1590
+ color: var(--color-success);
1591
+ margin-bottom: var(--spacing-2);
1592
+ }
1593
+
1594
+ .doctrine-content h4 {
1595
+ margin: 0 0 var(--spacing-2) 0;
1596
+ color: var(--colors-neutral-900);
1597
+ font-size: var(--typography-fontSizes-lg);
1598
+ }
1599
+
1600
+ .doctrine-content p {
1601
+ margin: 0;
1602
+ color: var(--colors-neutral-700);
1603
+ line-height: 1.6;
1604
  }
1605
 
1606
  /* Responsive adjustments */
 
1609
  grid-template-columns: 1fr;
1610
  }
1611
 
1612
+ .sequencing-steps {
1613
+ flex-direction: column;
1614
+ gap: var(--spacing-6);
1615
+ }
1616
+
1617
+ .step-connectors {
1618
+ display: none;
1619
+ }
1620
+
1621
+ .evidence-comparison {
1622
+ grid-template-columns: 1fr;
1623
+ }
1624
+
1625
+ .intent-grid {
1626
  grid-template-columns: 1fr;
1627
  }
1628
 
1629
+ .intent-details {
1630
+ grid-template-columns: 1fr;
1631
+ }
1632
+ }
1633
+
1634
+ @media (max-width: 480px) {
1635
  .observation-gate-header {
1636
  flex-direction: column;
1637
  text-align: center;
 
1642
  margin-left: 0;
1643
  margin-top: var(--spacing-2);
1644
  }
1645
+
 
 
1646
  .card {
1647
  padding: var(--spacing-3);
1648
  }
1649
 
1650
+ .sequencing-flow,
1651
+ .historical-evidence-panel,
1652
+ .healing-intent-display {
1653
  padding: var(--spacing-3);
1654
  }
 
 
 
 
1655
  }
1656
  </style>
1657
  """
 
1664
  components = [
1665
  inject_design_tokens(),
1666
  create_component_styles(),
1667
+ """
1668
+ <style>
1669
+ /* Additional responsive utilities */
1670
+ .container {
1671
+ width: 100%;
1672
+ max-width: 1200px;
1673
+ margin: 0 auto;
1674
+ padding: 0 var(--spacing-4);
1675
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1676
 
1677
+ @media (min-width: 768px) {
1678
+ .container {
1679
+ padding: 0 var(--spacing-6);
1680
+ }
1681
+ }
 
 
1682
 
1683
+ @media (min-width: 1024px) {
1684
+ .container {
1685
+ padding: 0 var(--spacing-8);
1686
+ }
1687
+ }
1688
+ </style>
1689
+ """
1690
+ ]
 
 
 
 
 
 
 
 
 
 
 
1691
 
1692
+ return "\n".join(components)
1693
 
1694
  # ===========================================
1695
  # EXPORT LIST
1696
  # ===========================================
1697
  __all__ = [
1698
  # Core components
1699
+ 'ModernComponent', 'Card',
 
1700
 
1701
+ # CRITICAL PSYCHOLOGICAL COMPONENTS
1702
  'ObservationGate', 'SequencingFlow', 'ProcessDisplay',
1703
+ 'HistoricalEvidencePanel', 'HealingIntentDisplay',
1704
 
1705
+ # Design system
1706
+ 'DESIGN_TOKENS',
 
 
 
1707
 
1708
  # Initialization
1709
+ 'initialize_modern_ui', 'inject_design_tokens', 'create_component_styles'
1710
+ ]