collavre 0.3.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/collavre/actiontext.css +73 -71
  3. data/app/assets/stylesheets/collavre/activity_logs.css +18 -45
  4. data/app/assets/stylesheets/collavre/comments_popup.css +197 -35
  5. data/app/assets/stylesheets/collavre/creatives.css +101 -51
  6. data/app/assets/stylesheets/collavre/dark_mode.css +221 -88
  7. data/app/assets/stylesheets/collavre/design_tokens.css +334 -0
  8. data/app/assets/stylesheets/collavre/mention_menu.css +13 -9
  9. data/app/assets/stylesheets/collavre/popup.css +57 -27
  10. data/app/assets/stylesheets/collavre/slide_view.css +6 -6
  11. data/app/assets/stylesheets/collavre/user_menu.css +4 -5
  12. data/app/components/collavre/plans_timeline_component.html.erb +2 -2
  13. data/app/controllers/collavre/admin/orchestration_controller.rb +9 -2
  14. data/app/controllers/collavre/admin/settings_controller.rb +199 -0
  15. data/app/controllers/collavre/comments/reactions_controller.rb +1 -9
  16. data/app/controllers/collavre/comments_controller.rb +39 -162
  17. data/app/controllers/collavre/creatives_controller.rb +18 -58
  18. data/app/controllers/collavre/users_controller.rb +31 -3
  19. data/app/helpers/collavre/application_helper.rb +97 -0
  20. data/app/helpers/collavre/creatives_helper.rb +10 -202
  21. data/app/javascript/collavre.js +0 -1
  22. data/app/javascript/components/creative_tree_row.js +3 -2
  23. data/app/javascript/controllers/comment_controller.js +309 -4
  24. data/app/javascript/controllers/comments/form_controller.js +52 -0
  25. data/app/javascript/controllers/comments/presence_controller.js +13 -0
  26. data/app/javascript/controllers/creatives/tree_controller.js +2 -1
  27. data/app/javascript/controllers/link_creative_controller.js +29 -3
  28. data/app/javascript/lib/__tests__/html_code_block_wrapper.test.js +201 -0
  29. data/app/javascript/lib/html_code_block_wrapper.js +168 -0
  30. data/app/javascript/lib/utils/markdown.js +2 -1
  31. data/app/javascript/modules/creative_row_editor.js +5 -1
  32. data/app/javascript/utils/emoji_parser.js +21 -0
  33. data/app/jobs/collavre/ai_agent_job.rb +6 -2
  34. data/app/jobs/collavre/cron_action_job.rb +18 -6
  35. data/app/jobs/collavre/cron_scheduler_job.rb +112 -0
  36. data/app/models/collavre/comment/approvable.rb +50 -0
  37. data/app/models/collavre/comment/broadcastable.rb +119 -0
  38. data/app/models/collavre/comment/notifiable.rb +111 -0
  39. data/app/models/collavre/comment.rb +13 -258
  40. data/app/models/collavre/comment_reaction.rb +15 -0
  41. data/app/models/collavre/creative/describable.rb +86 -0
  42. data/app/models/collavre/creative/linkable.rb +77 -0
  43. data/app/models/collavre/creative/permissible.rb +103 -0
  44. data/app/models/collavre/creative.rb +3 -289
  45. data/app/models/collavre/orchestrator_policy.rb +1 -1
  46. data/app/models/collavre/system_setting.rb +27 -1
  47. data/app/models/collavre/user.rb +42 -0
  48. data/app/models/collavre/user_theme.rb +10 -0
  49. data/app/services/collavre/ai_agent/approval_handler.rb +110 -0
  50. data/app/services/collavre/ai_agent/message_builder.rb +129 -0
  51. data/app/services/collavre/ai_agent/review_handler.rb +70 -0
  52. data/app/services/collavre/ai_agent_service.rb +93 -150
  53. data/app/services/collavre/ai_client.rb +23 -4
  54. data/app/services/collavre/auto_theme_generator.rb +168 -50
  55. data/app/services/collavre/command_menu_service.rb +70 -0
  56. data/app/services/collavre/comment_move_service.rb +94 -0
  57. data/app/services/collavre/comments/action_executor.rb +10 -0
  58. data/app/services/collavre/comments/mcp_command.rb +1 -2
  59. data/app/services/collavre/creatives/create_service.rb +86 -0
  60. data/app/services/collavre/creatives/destroy_service.rb +41 -0
  61. data/app/services/collavre/creatives/index_query.rb +3 -0
  62. data/app/services/collavre/markdown_converter.rb +240 -0
  63. data/app/services/collavre/mention_parser.rb +63 -0
  64. data/app/services/collavre/orchestration/agent_context_builder.rb +24 -8
  65. data/app/services/collavre/orchestration/agent_orchestrator.rb +59 -10
  66. data/app/services/collavre/orchestration/loop_breaker.rb +12 -7
  67. data/app/services/collavre/orchestration/policy_resolver.rb +16 -2
  68. data/app/services/collavre/orchestration/scheduler.rb +4 -3
  69. data/app/services/collavre/orchestration/stuck_detector.rb +1 -1
  70. data/app/services/collavre/system_events/context_builder.rb +1 -6
  71. data/app/services/collavre/tools/creative_batch_service.rb +107 -0
  72. data/app/services/collavre/tools/creative_update_service.rb +17 -12
  73. data/app/services/collavre/tools/cron_create_service.rb +17 -5
  74. data/app/views/admin/shared/_tabs.html.erb +2 -1
  75. data/app/views/collavre/admin/orchestration/show.html.erb +11 -0
  76. data/app/views/collavre/admin/settings/_system_tab.html.erb +138 -0
  77. data/app/views/collavre/admin/settings/_uiux_tab.html.erb +44 -0
  78. data/app/views/collavre/admin/settings/index.html.erb +11 -0
  79. data/app/views/collavre/admin/settings/uiux.html.erb +11 -0
  80. data/app/views/collavre/comments/_comment.html.erb +15 -5
  81. data/app/views/collavre/comments/_comments_popup.html.erb +9 -2
  82. data/app/views/collavre/creatives/_mobile_actions_menu.html.erb +0 -3
  83. data/app/views/collavre/creatives/_share_button.html.erb +0 -52
  84. data/app/views/collavre/creatives/_share_modal.html.erb +52 -0
  85. data/app/views/collavre/creatives/index.html.erb +5 -8
  86. data/app/views/collavre/shared/navigation/_panels.html.erb +2 -2
  87. data/app/views/collavre/user_themes/index.html.erb +7 -9
  88. data/app/views/collavre/users/_contact_management.html.erb +2 -1
  89. data/app/views/collavre/users/edit_ai.html.erb +7 -0
  90. data/app/views/collavre/users/index.html.erb +16 -1
  91. data/app/views/collavre/users/new_ai.html.erb +18 -8
  92. data/app/views/collavre/users/passkeys.html.erb +1 -1
  93. data/app/views/collavre/users/show.html.erb +1 -1
  94. data/app/views/layouts/collavre/slide.html.erb +8 -1
  95. data/config/locales/admin.en.yml +88 -0
  96. data/config/locales/admin.ko.yml +88 -0
  97. data/config/locales/ai_agent.en.yml +5 -1
  98. data/config/locales/ai_agent.ko.yml +5 -1
  99. data/config/locales/comments.en.yml +5 -1
  100. data/config/locales/comments.ko.yml +5 -1
  101. data/config/locales/orchestration.en.yml +8 -0
  102. data/config/locales/orchestration.ko.yml +8 -0
  103. data/config/locales/users.en.yml +12 -0
  104. data/config/locales/users.ko.yml +12 -0
  105. data/config/routes.rb +7 -1
  106. data/db/migrate/20260212011655_add_quoted_comment_to_comments.rb +7 -0
  107. data/db/migrate/20260213044247_add_agent_conf_to_users.rb +5 -0
  108. data/lib/collavre/engine.rb +25 -0
  109. data/lib/collavre/version.rb +1 -1
  110. metadata +32 -1
@@ -1,100 +1,97 @@
1
- /* 다크모드 변수 및 스타일 */
1
+ /*
2
+ * Theme Application
3
+ *
4
+ * Maps semantic tokens from design_tokens.css to legacy variable names
5
+ * (for backward compatibility) and applies base element styles.
6
+ *
7
+ * NEW CODE should use semantic tokens directly (e.g. var(--surface-bg)).
8
+ * Legacy aliases below will be removed once all CSS files are migrated.
9
+ */
10
+
11
+ /* ============================================================================
12
+ * LEGACY ALIASES → Semantic Tokens
13
+ * These keep existing CSS working while we migrate file-by-file.
14
+ *
15
+ * NOTE: Legacy aliases use var() to reference semantic tokens. Because CSS
16
+ * custom properties resolve var() at computed-value time on the element where
17
+ * they are defined, aliases on :root resolve against :root's own token values
18
+ * (light). To make them pick up dark-mode overrides, we must ALSO redefine
19
+ * them inside body.dark-mode and the prefers-color-scheme media query.
20
+ * ============================================================================ */
2
21
  :root {
3
- --font-sans: "Inter", system-ui, -apple-system, "Segoe UI", Helvetica, Arial,
4
- sans-serif;
5
- --color-bg: #f7f7f8;
6
- --color-text: #202123;
7
- --color-link: #185ABC;
8
- --color-nav-bg: #ffffff;
9
- --color-section-bg: #ffffff;
10
- --color-btn-bg: #f1f2f4;
11
- --color-btn-text: #202123;
12
- --color-border: #e0e0e0;
13
- --color-muted: #666;
14
- --color-complete: oklch(60% 0.4 145);
15
- --color-chip-bg: var(--color-complete);
16
- --color-drag-over: #e0e0e0;
17
- --color-drag-over-edge: #bbb;
18
- --hover-brightness: 90%;
19
- --color-badge-bg: red;
20
- --color-badge-bg: red;
21
- --color-badge-text: white;
22
- --color-secondary-active: #007bff;
23
- --color-secondary-background: #ffffff;
24
- --color-nav-btn-text: #202123;
25
- --color-chat-btn-text: #666;
26
- --color-input-bg: #f7f7f8;
27
- --color-input-bg: #f7f7f8;
28
- --color-input-text: #202123;
29
- --color-nav-text: #202123;
30
- --max-width: 960px;
31
- --paragraph-space-1: 0.75rem;
22
+ /* Surface aliases */
23
+ --color-bg: var(--surface-bg);
24
+ --color-nav-bg: var(--surface-nav);
25
+ --color-section-bg: var(--surface-section);
26
+ --color-input-bg: var(--surface-input);
27
+ --color-btn-bg: var(--surface-btn);
28
+ --color-secondary-background: var(--surface-secondary);
29
+
30
+ /* Text aliases */
31
+ --color-text: var(--text-primary);
32
+ --color-muted: var(--text-muted);
33
+ --color-btn-text: var(--text-on-btn);
34
+ --color-nav-text: var(--text-nav);
35
+ --color-nav-btn-text: var(--text-nav-btn);
36
+ --color-chat-btn-text: var(--text-chat-btn);
37
+ --color-badge-text: var(--text-on-badge);
38
+ --color-input-text: var(--text-input);
39
+
40
+ /* Interactive aliases */
41
+ --color-complete: var(--color-brand);
42
+ --color-chip-bg: var(--color-brand);
43
+ --color-secondary-active: var(--color-active);
44
+
45
+ /* Border aliases */
46
+ --color-border: var(--border-color);
47
+ --color-drag-over: var(--border-drag-over);
48
+ --color-drag-over-edge: var(--border-drag-edge);
49
+
50
+ /* Layout aliases */
51
+ --paragraph-space-1: var(--paragraph-space);
32
52
  }
33
53
 
54
+ /* Dark-mode legacy aliases — must mirror :root aliases so var() resolves
55
+ against body.dark-mode's semantic token values, not :root's. */
34
56
  body.dark-mode {
35
- --color-bg: #212121;
36
- --color-text: #eaeaea;
37
- --color-link: #185ABC;
38
- --color-nav-bg: #181818;
39
- --color-section-bg: #181818;
40
- --color-btn-bg: #333543;
41
- --color-btn-text: #eaeaea;
42
- --color-border: #333333;
43
- --color-muted: #aaaaaa;
44
- --color-complete: oklch(50% 0.4 145);
45
- --color-chip-bg: var(--color-complete);
46
- --color-drag-over: #383a40;
47
- --color-drag-over-edge: #777;
48
- --hover-brightness: 110%;
49
- --color-badge-bg: red;
50
- --color-badge-text: white;
51
- --color-secondary-active: #6a9eff;
52
- --color-secondary-background: #181818;
53
- --color-nav-btn-text: #eaeaea;
54
- --color-chat-btn-text: #aaaaaa;
55
- --color-input-bg: #212121;
56
- --color-input-bg: #212121;
57
- --color-input-text: #eaeaea;
58
- --color-nav-text: #eaeaea;
59
- }
60
-
61
- @media (prefers-color-scheme: dark) {
62
- body:not(.light-mode):not(.dark-mode) {
63
- --color-bg: #212121;
64
- --color-text: #eaeaea;
65
- --color-link: #185ABC;
66
- --color-nav-bg: #181818;
67
- --color-section-bg: #181818;
68
- --color-btn-bg: #333543;
69
- --color-btn-text: #eaeaea;
70
- --color-border: #333333;
71
- --color-muted: #aaaaaa;
72
- --color-complete: oklch(50% 0.4 145);
73
- --color-chip-bg: var(--color-complete);
74
- --color-drag-over: #383a40;
75
- --color-drag-over-edge: #777;
76
- --hover-brightness: 110%;
77
- --color-badge-bg: red;
78
- --color-badge-text: white;
79
- --color-secondary-active: #6a9eff;
80
- --color-secondary-background: #181818;
81
- --color-nav-btn-text: #eaeaea;
82
- --color-chat-btn-text: #aaaaaa;
83
- --color-input-bg: #212121;
84
- --color-input-bg: #212121;
85
- --color-input-text: #eaeaea;
86
- --color-nav-text: #eaeaea;
87
- }
57
+ --color-bg: var(--surface-bg);
58
+ --color-nav-bg: var(--surface-nav);
59
+ --color-section-bg: var(--surface-section);
60
+ --color-input-bg: var(--surface-input);
61
+ --color-btn-bg: var(--surface-btn);
62
+ --color-secondary-background: var(--surface-secondary);
63
+ --color-text: var(--text-primary);
64
+ --color-muted: var(--text-muted);
65
+ --color-btn-text: var(--text-on-btn);
66
+ --color-nav-text: var(--text-nav);
67
+ --color-nav-btn-text: var(--text-nav-btn);
68
+ --color-chat-btn-text: var(--text-chat-btn);
69
+ --color-badge-text: var(--text-on-badge);
70
+ --color-input-text: var(--text-input);
71
+ --color-complete: var(--color-brand);
72
+ --color-chip-bg: var(--color-brand);
73
+ --color-secondary-active: var(--color-active);
74
+ --color-border: var(--border-color);
75
+ --color-drag-over: var(--border-drag-over);
76
+ --color-drag-over-edge: var(--border-drag-edge);
88
77
  }
89
78
 
79
+ /* ============================================================================
80
+ * BASE ELEMENT STYLES
81
+ * ============================================================================ */
90
82
  body {
91
- background: var(--color-bg);
92
- color: var(--color-text);
83
+ background: var(--surface-bg);
84
+ color: var(--text-primary);
85
+ color-scheme: var(--color-scheme, light);
93
86
  transition: background 0.3s, color 0.3s;
94
87
  }
95
88
 
89
+ body.dark-mode {
90
+ color-scheme: var(--color-scheme, dark);
91
+ }
92
+
96
93
  nav {
97
- background: var(--color-nav-bg);
94
+ background: var(--surface-nav);
98
95
  }
99
96
 
100
97
  a {
@@ -103,7 +100,7 @@ a {
103
100
 
104
101
  main,
105
102
  section.creative {
106
- background: var(--color-section-bg);
103
+ background: var(--surface-section);
107
104
  }
108
105
 
109
106
  button,
@@ -115,4 +112,140 @@ input[type="submit"] {
115
112
  transition: background 0.3s, color 0.3s;
116
113
  }
117
114
 
118
- /* 기타 요소도 필요에 따라 추가 가능 */
115
+ /* ============================================================================
116
+ * UI COMPONENT CLASSES
117
+ * Reusable button, badge, and chip styles built on design tokens.
118
+ * ============================================================================ */
119
+
120
+ /* --- Buttons --- */
121
+ .btn {
122
+ display: inline-flex;
123
+ align-items: center;
124
+ gap: 0.35em;
125
+ padding: 0.45em 0.9em;
126
+ font-size: 0.875rem;
127
+ font-weight: 500;
128
+ line-height: 1.4;
129
+ border: 1px solid var(--border-color);
130
+ border-radius: var(--radius-2, 4px);
131
+ background: var(--surface-btn);
132
+ color: var(--text-on-btn);
133
+ cursor: pointer;
134
+ text-decoration: none;
135
+ transition: filter 0.15s, background 0.15s;
136
+ }
137
+
138
+ .btn:hover {
139
+ filter: brightness(var(--hover-brightness, 0.95));
140
+ }
141
+
142
+ .btn-primary {
143
+ background: var(--color-brand);
144
+ color: var(--text-on-badge);
145
+ border-color: var(--color-brand);
146
+ }
147
+
148
+ .btn-secondary {
149
+ background: var(--surface-secondary);
150
+ color: var(--text-primary);
151
+ border-color: var(--border-color);
152
+ }
153
+
154
+ .btn-success {
155
+ background: color-mix(in srgb, var(--color-success) 12%, transparent);
156
+ color: var(--color-success);
157
+ border-color: color-mix(in srgb, var(--color-success) 35%, transparent);
158
+ }
159
+
160
+ .btn-success:hover {
161
+ background: var(--color-success);
162
+ color: var(--text-on-badge);
163
+ }
164
+
165
+ .btn-danger {
166
+ background: transparent;
167
+ color: var(--color-danger);
168
+ border-color: var(--color-danger);
169
+ }
170
+
171
+ .btn-danger:hover {
172
+ background: var(--color-danger);
173
+ color: var(--text-on-badge);
174
+ }
175
+
176
+ /* --- Date/time input placeholder text --- */
177
+
178
+ input[type="date"]::-webkit-datetime-edit-text,
179
+ input[type="date"]::-webkit-datetime-edit-month-field,
180
+ input[type="date"]::-webkit-datetime-edit-day-field,
181
+ input[type="date"]::-webkit-datetime-edit-year-field,
182
+ input[type="datetime-local"]::-webkit-datetime-edit-text,
183
+ input[type="datetime-local"]::-webkit-datetime-edit-month-field,
184
+ input[type="datetime-local"]::-webkit-datetime-edit-day-field,
185
+ input[type="datetime-local"]::-webkit-datetime-edit-year-field,
186
+ input[type="datetime-local"]::-webkit-datetime-edit-hour-field,
187
+ input[type="datetime-local"]::-webkit-datetime-edit-minute-field {
188
+ color: var(--text-muted);
189
+ }
190
+
191
+ .btn-sm {
192
+ padding: 0.25em 0.55em;
193
+ font-size: 0.8rem;
194
+ }
195
+
196
+ .btn-xs {
197
+ padding: 0.15em 0.4em;
198
+ font-size: 0.75rem;
199
+ }
200
+
201
+ /* --- Badges --- */
202
+ .badge {
203
+ display: inline-flex;
204
+ align-items: center;
205
+ justify-content: center;
206
+ min-width: 1.2em;
207
+ padding: 0.05em 0.35em;
208
+ font-size: 0.65rem;
209
+ font-weight: 600;
210
+ line-height: 1;
211
+ border-radius: var(--radius-round, 9999px);
212
+ background: var(--color-badge-bg);
213
+ color: var(--text-on-badge);
214
+ }
215
+
216
+ .badge-success {
217
+ background: var(--color-success);
218
+ }
219
+
220
+ .badge-danger {
221
+ background: var(--color-danger);
222
+ }
223
+
224
+ .badge-warning {
225
+ background: var(--color-warning);
226
+ }
227
+
228
+ /* --- Chips (contact tags, etc.) --- */
229
+ .chip {
230
+ display: inline-flex;
231
+ align-items: center;
232
+ gap: 0.3em;
233
+ padding: 0.2em 0.6em;
234
+ font-size: 0.8rem;
235
+ line-height: 1.3;
236
+ border-radius: var(--radius-round, 9999px);
237
+ background: var(--surface-secondary);
238
+ color: var(--text-primary);
239
+ border: 1px solid var(--border-color);
240
+ }
241
+
242
+ .chip-active {
243
+ background: var(--color-brand);
244
+ color: var(--text-on-badge);
245
+ border-color: var(--color-brand);
246
+ }
247
+
248
+ /* --- Inline utility --- */
249
+ .inline-block {
250
+ display: inline-block;
251
+ }
@@ -0,0 +1,334 @@
1
+ /*
2
+ * Collavre Design Tokens
3
+ *
4
+ * Based on Open Props (https://open-props.style) scale system.
5
+ * This file defines all design tokens used across Collavre.
6
+ * DO NOT hardcode raw values in component CSS — use these tokens instead.
7
+ *
8
+ * Enforced by Stylelint (stylelint.config.mjs)
9
+ */
10
+
11
+ /* ============================================================================
12
+ * SPACING (from Open Props --size-*)
13
+ * Usage: padding, margin, gap
14
+ * ============================================================================ */
15
+ :root {
16
+ /* -- Color scheme -- */
17
+ --color-scheme: light; /* light | dark — used by native controls */
18
+
19
+ --space-000: -0.5rem; /* -8px */
20
+ --space-00: -0.25rem; /* -4px */
21
+ --space-1: 0.25rem; /* 4px */
22
+ --space-2: 0.5rem; /* 8px */
23
+ --space-3: 1rem; /* 16px */
24
+ --space-4: 1.25rem; /* 20px */
25
+ --space-5: 1.5rem; /* 24px */
26
+ --space-6: 1.75rem; /* 28px */
27
+ --space-7: 2rem; /* 32px */
28
+ --space-8: 3rem; /* 48px */
29
+ --space-9: 4rem; /* 64px */
30
+ --space-10: 5rem; /* 80px */
31
+ --space-11: 7.5rem; /* 120px */
32
+ --space-12: 10rem; /* 160px */
33
+
34
+ /* Pixel variants (for when rem isn't appropriate) */
35
+ --space-px-1: 4px;
36
+ --space-px-2: 8px;
37
+ --space-px-3: 16px;
38
+ --space-px-4: 20px;
39
+ --space-px-5: 24px;
40
+ --space-px-6: 28px;
41
+ --space-px-7: 32px;
42
+ --space-px-8: 48px;
43
+
44
+ /* ============================================================================
45
+ * TYPOGRAPHY (from Open Props --font-size-*, --font-weight-*, --font-lineheight-*)
46
+ * ============================================================================ */
47
+
48
+ /* Font families */
49
+ --font-sans: "Inter", system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
50
+ --font-mono: "Dank Mono", "Operator Mono", "Inconsolata", "Fira Mono",
51
+ ui-monospace, "SF Mono", Monaco, "Droid Sans Mono", "Source Code Pro",
52
+ "Cascadia Code", Menlo, Consolas, "DejaVu Sans Mono", monospace;
53
+
54
+ /* Font sizes */
55
+ --text-00: 0.5rem; /* 8px — tiny labels */
56
+ --text-0: 0.75rem; /* 12px — small/caption */
57
+ --text-1: 1rem; /* 16px — body (base) */
58
+ --text-2: 1.1rem; /* 17.6px — slightly larger body */
59
+ --text-3: 1.25rem; /* 20px — subheading */
60
+ --text-4: 1.5rem; /* 24px — heading */
61
+ --text-5: 2rem; /* 32px — large heading */
62
+ --text-6: 2.5rem; /* 40px — display */
63
+ --text-7: 3rem; /* 48px — hero */
64
+ --text-8: 3.5rem; /* 56px — jumbo */
65
+
66
+ /* Font weights */
67
+ --weight-1: 100; /* thin */
68
+ --weight-2: 200; /* extra-light */
69
+ --weight-3: 300; /* light */
70
+ --weight-4: 400; /* regular */
71
+ --weight-5: 500; /* medium */
72
+ --weight-6: 600; /* semi-bold */
73
+ --weight-7: 700; /* bold */
74
+ --weight-8: 800; /* extra-bold */
75
+ --weight-9: 900; /* black */
76
+
77
+ /* Line heights */
78
+ --leading-00: 0.95; /* tight — headings */
79
+ --leading-0: 1.1; /* compact */
80
+ --leading-1: 1.25; /* snug */
81
+ --leading-2: 1.375; /* normal */
82
+ --leading-3: 1.5; /* relaxed (default body) */
83
+ --leading-4: 1.75; /* loose */
84
+ --leading-5: 2; /* extra loose */
85
+
86
+ /* ============================================================================
87
+ * BORDERS & RADIUS (from Open Props)
88
+ * ============================================================================ */
89
+ --border-1: 1px;
90
+ --border-2: 2px;
91
+ --border-3: 5px;
92
+ --border-4: 10px;
93
+
94
+ --radius-1: 2px; /* subtle */
95
+ --radius-2: 5px; /* default */
96
+ --radius-3: 1rem; /* medium */
97
+ --radius-4: 2rem; /* large */
98
+ --radius-5: 4rem; /* pill-like */
99
+ --radius-round: 1e5px; /* circle */
100
+
101
+ /* ============================================================================
102
+ * SHADOWS (from Open Props)
103
+ * ============================================================================ */
104
+ --shadow-color: 220 3% 15%;
105
+ --shadow-strength: 1%;
106
+
107
+ --shadow-1: 0 1px 2px -1px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 9%));
108
+ --shadow-2:
109
+ 0 3px 5px -2px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 3%)),
110
+ 0 7px 14px -5px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 5%));
111
+ --shadow-3:
112
+ 0 -1px 3px 0 hsl(var(--shadow-color) / calc(var(--shadow-strength) + 2%)),
113
+ 0 1px 2px -5px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 2%)),
114
+ 0 2px 5px -5px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 4%)),
115
+ 0 4px 12px -5px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 5%)),
116
+ 0 12px 15px -5px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 7%));
117
+ --shadow-4:
118
+ 0 -2px 5px 0 hsl(var(--shadow-color) / calc(var(--shadow-strength) + 2%)),
119
+ 0 1px 1px -2px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 3%)),
120
+ 0 2px 2px -2px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 3%)),
121
+ 0 5px 5px -2px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 4%)),
122
+ 0 9px 9px -2px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 5%)),
123
+ 0 16px 16px -2px hsl(var(--shadow-color) / calc(var(--shadow-strength) + 6%));
124
+
125
+ /* ============================================================================
126
+ * EASING & ANIMATION (from Open Props)
127
+ * ============================================================================ */
128
+ --ease-1: cubic-bezier(0.25, 0, 0.5, 1);
129
+ --ease-2: cubic-bezier(0.25, 0, 0.4, 1);
130
+ --ease-3: cubic-bezier(0.25, 0, 0.3, 1);
131
+ --ease-in-1: cubic-bezier(0.25, 0, 1, 1);
132
+ --ease-in-2: cubic-bezier(0.50, 0, 1, 1);
133
+ --ease-out-1: cubic-bezier(0, 0, 0.75, 1);
134
+ --ease-out-2: cubic-bezier(0, 0, 0.50, 1);
135
+ --ease-out-3: cubic-bezier(0, 0, 0.3, 1);
136
+
137
+ /* ============================================================================
138
+ * Z-INDEX LAYERS
139
+ * ============================================================================ */
140
+ --layer-1: 1;
141
+ --layer-2: 2;
142
+ --layer-3: 3;
143
+ --layer-4: 4;
144
+ --layer-5: 5;
145
+ --layer-popup: 100;
146
+ --layer-modal: 1000;
147
+ --layer-toast: 2000;
148
+ --layer-important: 2147483647;
149
+
150
+ /* ============================================================================
151
+ * BREAKPOINTS (reference only — use in @media queries)
152
+ * ============================================================================ */
153
+ /* --bp-xs: 360px; */
154
+ /* --bp-sm: 480px; */
155
+ /* --bp-md: 768px; */
156
+ /* --bp-lg: 1024px; */
157
+ /* --bp-xl: 1440px; */
158
+
159
+ /* ============================================================================
160
+ * SEMANTIC COLOR TOKENS
161
+ * These map Open Props primitives → meaningful roles.
162
+ * Every token here MUST also be defined in body.dark-mode below.
163
+ * ============================================================================ */
164
+
165
+ /* -- Surfaces (backgrounds) -- */
166
+ --surface-bg: #f7f7f8; /* page background */
167
+ --surface-nav: #ffffff; /* navigation bar */
168
+ --surface-section: #ffffff; /* cards, panels */
169
+ --surface-input: #f7f7f8; /* form inputs */
170
+ --surface-btn: #f1f2f4; /* default button */
171
+ --surface-secondary: #ffffff; /* secondary panels */
172
+
173
+ /* -- Text -- */
174
+ --text-primary: #202123; /* main body text */
175
+ --text-muted: #666666; /* secondary / helper text */
176
+ --text-on-btn: #202123; /* text on default buttons */
177
+ --text-nav: #202123; /* navigation text */
178
+ --text-nav-btn: #202123; /* navigation button text */
179
+ --text-chat-btn: #666666; /* chat action buttons */
180
+ --text-on-badge: white; /* text on badges */
181
+ --text-input: #202123; /* input field text */
182
+
183
+ /* -- Interactive -- */
184
+ --color-link: #185ABC; /* hyperlinks */
185
+ --color-brand: oklch(60% 0.4 145); /* brand / accent / complete */
186
+ --color-active: #007bff; /* active / selected state */
187
+ --color-danger: #dc3545; /* errors, destructive */
188
+ --color-success: oklch(60% 0.4 145); /* success (= brand for now) */
189
+ --color-warning: #f59e0b; /* warnings */
190
+ --color-highlight: #ffff99; /* highlight flash */
191
+ --color-badge-bg: red; /* notification badge */
192
+ --color-accent-border: #7bc4e4; /* active element border */
193
+ --color-accent-text: #03425f; /* active element text */
194
+ --color-code-bg: #f6f8fa; /* code block background */
195
+ --color-code-text: #1f2328; /* code block text */
196
+
197
+ /* -- Borders & Dividers -- */
198
+ --border-color: #e0e0e0; /* default borders */
199
+ --border-drag-over: #e0e0e0; /* drag target highlight */
200
+ --border-drag-edge: #bbbbbb; /* drag edge indicator */
201
+
202
+ /* -- Effects -- */
203
+ --hover-brightness: 90%; /* filter: brightness() on hover */
204
+
205
+ /* -- Layout -- */
206
+ --max-width: 960px; /* content max width */
207
+ --paragraph-space: 0.75rem; /* gap between paragraphs */
208
+ }
209
+
210
+ /* ============================================================================
211
+ * DATE INPUT — Native controls follow the theme's color-scheme token.
212
+ * Each theme sets --color-scheme: light | dark, and the browser renders
213
+ * native icons (calendar picker, dropdown arrows) accordingly.
214
+ * ============================================================================ */
215
+ input[type="date"],
216
+ input[type="datetime-local"] {
217
+ color-scheme: var(--color-scheme, light);
218
+ }
219
+
220
+ /* ============================================================================
221
+ * DARK MODE OVERRIDES
222
+ * Every semantic token that changes in dark mode MUST be listed here.
223
+ * ============================================================================ */
224
+ body.dark-mode {
225
+ --color-scheme: dark;
226
+ --shadow-color: 220 40% 2%;
227
+ --shadow-strength: 25%;
228
+
229
+ /* -- Surfaces -- */
230
+ --surface-bg: #212121;
231
+ --surface-nav: #181818;
232
+ --surface-section: #181818;
233
+ --surface-input: #212121;
234
+ --surface-btn: #333543;
235
+ --surface-secondary: #181818;
236
+
237
+ /* -- Text -- */
238
+ --text-primary: #eaeaea;
239
+ --text-muted: #aaaaaa;
240
+ --text-on-btn: #eaeaea;
241
+ --text-nav: #eaeaea;
242
+ --text-nav-btn: #eaeaea;
243
+ --text-chat-btn: #aaaaaa;
244
+ --text-on-badge: white;
245
+ --text-input: #eaeaea;
246
+
247
+ /* -- Interactive -- */
248
+ --color-link: #185ABC;
249
+ --color-brand: oklch(50% 0.4 145);
250
+ --color-active: #6a9eff;
251
+ --color-badge-bg: red;
252
+ --color-highlight: #665500;
253
+ --color-accent-border: #4a8aaa;
254
+ --color-accent-text: #8ecfef;
255
+ --color-code-bg: #2d2d2d;
256
+ --color-code-text: #e0e0e0;
257
+
258
+ /* -- Borders & Dividers -- */
259
+ --border-color: #333333;
260
+ --border-drag-over: #383a40;
261
+ --border-drag-edge: #777777;
262
+
263
+ /* -- Effects -- */
264
+ --hover-brightness: 110%;
265
+
266
+ }
267
+
268
+ /* ============================================================================
269
+ * SYSTEM DARK MODE (prefers-color-scheme)
270
+ * Mirror of body.dark-mode for users without explicit toggle.
271
+ * ============================================================================ */
272
+ @media (prefers-color-scheme: dark) {
273
+ body:not(.light-mode):not(.dark-mode) {
274
+ color-scheme: dark;
275
+ --color-scheme: dark;
276
+ --shadow-color: 220 40% 2%;
277
+ --shadow-strength: 25%;
278
+
279
+ --surface-bg: #212121;
280
+ --surface-nav: #181818;
281
+ --surface-section: #181818;
282
+ --surface-input: #212121;
283
+ --surface-btn: #333543;
284
+ --surface-secondary: #181818;
285
+
286
+ --text-primary: #eaeaea;
287
+ --text-muted: #aaaaaa;
288
+ --text-on-btn: #eaeaea;
289
+ --text-nav: #eaeaea;
290
+ --text-nav-btn: #eaeaea;
291
+ --text-chat-btn: #aaaaaa;
292
+ --text-on-badge: white;
293
+ --text-input: #eaeaea;
294
+
295
+ --color-link: #185ABC;
296
+ --color-brand: oklch(50% 0.4 145);
297
+ --color-active: #6a9eff;
298
+ --color-badge-bg: red;
299
+ --color-highlight: #665500;
300
+ --color-accent-border: #4a8aaa;
301
+ --color-accent-text: #8ecfef;
302
+ --color-code-bg: #2d2d2d;
303
+ --color-code-text: #e0e0e0;
304
+
305
+ --border-color: #333333;
306
+ --border-drag-over: #383a40;
307
+ --border-drag-edge: #777777;
308
+
309
+ --hover-brightness: 110%;
310
+
311
+ /* Legacy aliases — must be redefined here so var() resolves against
312
+ the dark semantic tokens above, not :root's light values. */
313
+ --color-bg: var(--surface-bg);
314
+ --color-nav-bg: var(--surface-nav);
315
+ --color-section-bg: var(--surface-section);
316
+ --color-input-bg: var(--surface-input);
317
+ --color-btn-bg: var(--surface-btn);
318
+ --color-secondary-background: var(--surface-secondary);
319
+ --color-text: var(--text-primary);
320
+ --color-muted: var(--text-muted);
321
+ --color-btn-text: var(--text-on-btn);
322
+ --color-nav-text: var(--text-nav);
323
+ --color-nav-btn-text: var(--text-nav-btn);
324
+ --color-chat-btn-text: var(--text-chat-btn);
325
+ --color-badge-text: var(--text-on-badge);
326
+ --color-input-text: var(--text-input);
327
+ --color-complete: var(--color-brand);
328
+ --color-chip-bg: var(--color-brand);
329
+ --color-secondary-active: var(--color-active);
330
+ --color-border: var(--border-color);
331
+ --color-drag-over: var(--border-drag-over);
332
+ --color-drag-over-edge: var(--border-drag-edge);
333
+ }
334
+ }