prompt_engine 1.0.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 (97) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +67 -0
  4. data/Rakefile +22 -0
  5. data/app/assets/stylesheets/prompt_engine/application.css +22 -0
  6. data/app/assets/stylesheets/prompt_engine/buttons.css +124 -0
  7. data/app/assets/stylesheets/prompt_engine/cards.css +63 -0
  8. data/app/assets/stylesheets/prompt_engine/comparison.css +244 -0
  9. data/app/assets/stylesheets/prompt_engine/components/_test_runs.css +144 -0
  10. data/app/assets/stylesheets/prompt_engine/dashboard.css +343 -0
  11. data/app/assets/stylesheets/prompt_engine/evaluations.css +124 -0
  12. data/app/assets/stylesheets/prompt_engine/forms.css +198 -0
  13. data/app/assets/stylesheets/prompt_engine/foundation.css +182 -0
  14. data/app/assets/stylesheets/prompt_engine/layout.css +75 -0
  15. data/app/assets/stylesheets/prompt_engine/loading.css +229 -0
  16. data/app/assets/stylesheets/prompt_engine/notifications.css +78 -0
  17. data/app/assets/stylesheets/prompt_engine/overrides.css +42 -0
  18. data/app/assets/stylesheets/prompt_engine/prompts.css +237 -0
  19. data/app/assets/stylesheets/prompt_engine/sidebar.css +90 -0
  20. data/app/assets/stylesheets/prompt_engine/tables.css +250 -0
  21. data/app/assets/stylesheets/prompt_engine/utilities.css +52 -0
  22. data/app/assets/stylesheets/prompt_engine/versions.css +370 -0
  23. data/app/clients/prompt_engine/open_ai_evals_client.rb +135 -0
  24. data/app/controllers/prompt_engine/admin/base_controller.rb +7 -0
  25. data/app/controllers/prompt_engine/application_controller.rb +4 -0
  26. data/app/controllers/prompt_engine/dashboard_controller.rb +24 -0
  27. data/app/controllers/prompt_engine/eval_runs_controller.rb +23 -0
  28. data/app/controllers/prompt_engine/eval_sets_controller.rb +200 -0
  29. data/app/controllers/prompt_engine/evaluations_controller.rb +32 -0
  30. data/app/controllers/prompt_engine/playground_controller.rb +57 -0
  31. data/app/controllers/prompt_engine/playground_run_results_controller.rb +41 -0
  32. data/app/controllers/prompt_engine/prompts_controller.rb +70 -0
  33. data/app/controllers/prompt_engine/settings_controller.rb +28 -0
  34. data/app/controllers/prompt_engine/test_cases_controller.rb +231 -0
  35. data/app/controllers/prompt_engine/versions_controller.rb +90 -0
  36. data/app/helpers/prompt_engine/application_helper.rb +4 -0
  37. data/app/jobs/prompt_engine/application_job.rb +4 -0
  38. data/app/mailers/prompt_engine/application_mailer.rb +6 -0
  39. data/app/models/prompt_engine/application_record.rb +5 -0
  40. data/app/models/prompt_engine/eval_result.rb +19 -0
  41. data/app/models/prompt_engine/eval_run.rb +40 -0
  42. data/app/models/prompt_engine/eval_set.rb +97 -0
  43. data/app/models/prompt_engine/parameter.rb +126 -0
  44. data/app/models/prompt_engine/parameter_parser.rb +39 -0
  45. data/app/models/prompt_engine/playground_run_result.rb +20 -0
  46. data/app/models/prompt_engine/prompt.rb +192 -0
  47. data/app/models/prompt_engine/prompt_version.rb +72 -0
  48. data/app/models/prompt_engine/setting.rb +45 -0
  49. data/app/models/prompt_engine/test_case.rb +29 -0
  50. data/app/services/prompt_engine/evaluation_runner.rb +258 -0
  51. data/app/services/prompt_engine/playground_executor.rb +124 -0
  52. data/app/services/prompt_engine/variable_detector.rb +97 -0
  53. data/app/views/layouts/prompt_engine/admin.html.erb +65 -0
  54. data/app/views/layouts/prompt_engine/application.html.erb +17 -0
  55. data/app/views/prompt_engine/dashboard/index.html.erb +230 -0
  56. data/app/views/prompt_engine/eval_runs/show.html.erb +204 -0
  57. data/app/views/prompt_engine/eval_sets/compare.html.erb +229 -0
  58. data/app/views/prompt_engine/eval_sets/edit.html.erb +111 -0
  59. data/app/views/prompt_engine/eval_sets/index.html.erb +63 -0
  60. data/app/views/prompt_engine/eval_sets/metrics.html.erb +371 -0
  61. data/app/views/prompt_engine/eval_sets/new.html.erb +113 -0
  62. data/app/views/prompt_engine/eval_sets/show.html.erb +235 -0
  63. data/app/views/prompt_engine/evaluations/index.html.erb +194 -0
  64. data/app/views/prompt_engine/playground/result.html.erb +58 -0
  65. data/app/views/prompt_engine/playground/show.html.erb +129 -0
  66. data/app/views/prompt_engine/playground_run_results/index.html.erb +99 -0
  67. data/app/views/prompt_engine/playground_run_results/show.html.erb +123 -0
  68. data/app/views/prompt_engine/prompts/_form.html.erb +224 -0
  69. data/app/views/prompt_engine/prompts/edit.html.erb +9 -0
  70. data/app/views/prompt_engine/prompts/index.html.erb +80 -0
  71. data/app/views/prompt_engine/prompts/new.html.erb +9 -0
  72. data/app/views/prompt_engine/prompts/show.html.erb +297 -0
  73. data/app/views/prompt_engine/settings/edit.html.erb +93 -0
  74. data/app/views/prompt_engine/shared/_form_errors.html.erb +16 -0
  75. data/app/views/prompt_engine/test_cases/edit.html.erb +72 -0
  76. data/app/views/prompt_engine/test_cases/import.html.erb +92 -0
  77. data/app/views/prompt_engine/test_cases/import_preview.html.erb +103 -0
  78. data/app/views/prompt_engine/test_cases/new.html.erb +79 -0
  79. data/app/views/prompt_engine/versions/_version_card.html.erb +56 -0
  80. data/app/views/prompt_engine/versions/compare.html.erb +82 -0
  81. data/app/views/prompt_engine/versions/index.html.erb +96 -0
  82. data/app/views/prompt_engine/versions/show.html.erb +98 -0
  83. data/config/routes.rb +61 -0
  84. data/db/migrate/20250124000001_create_eval_tables.rb +43 -0
  85. data/db/migrate/20250124000002_add_open_ai_fields_to_evals.rb +11 -0
  86. data/db/migrate/20250125000001_add_grader_fields_to_eval_sets.rb +8 -0
  87. data/db/migrate/20250723161909_create_prompts.rb +17 -0
  88. data/db/migrate/20250723184757_create_prompt_engine_versions.rb +24 -0
  89. data/db/migrate/20250723203838_create_prompt_engine_parameters.rb +20 -0
  90. data/db/migrate/20250724160623_create_prompt_engine_playground_run_results.rb +30 -0
  91. data/db/migrate/20250724165118_create_prompt_engine_settings.rb +14 -0
  92. data/lib/prompt_engine/engine.rb +25 -0
  93. data/lib/prompt_engine/version.rb +3 -0
  94. data/lib/prompt_engine.rb +33 -0
  95. data/lib/tasks/active_prompt_tasks.rake +32 -0
  96. data/lib/tasks/eval_demo.rake +149 -0
  97. metadata +293 -0
@@ -0,0 +1,237 @@
1
+ /* Prompt Details */
2
+ .prompt-details {
3
+ margin-top: var(--spacing-xl);
4
+ }
5
+
6
+ .detail-grid {
7
+ display: grid;
8
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
9
+ gap: var(--spacing-lg);
10
+ }
11
+
12
+ .detail-item {
13
+ display: flex;
14
+ flex-direction: column;
15
+ }
16
+
17
+ .detail-label {
18
+ font-size: var(--font-size-sm);
19
+ font-weight: 500;
20
+ color: var(--color-gray-600);
21
+ margin-bottom: var(--spacing-xs);
22
+ }
23
+
24
+ .detail-value {
25
+ font-size: var(--font-size-base);
26
+ color: var(--color-gray-900);
27
+ }
28
+
29
+ /* Prompt Content Display */
30
+ .prompt-content,
31
+ .code-example {
32
+ background-color: var(--color-gray-50);
33
+ border: 1px solid var(--color-gray-200);
34
+ border-radius: var(--radius-md);
35
+ padding: var(--spacing-md);
36
+ font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
37
+ font-size: var(--font-size-sm);
38
+ line-height: var(--line-height-relaxed);
39
+ white-space: pre-wrap;
40
+ word-wrap: break-word;
41
+ margin: 0;
42
+ color: var(--color-gray-800);
43
+ }
44
+
45
+ .code-example {
46
+ background-color: var(--color-gray-900);
47
+ color: var(--color-gray-100);
48
+ border-color: var(--color-gray-700);
49
+ }
50
+
51
+ /* Parameters Section */
52
+ .parameters-section {
53
+ margin-top: var(--spacing-xl);
54
+ padding-top: var(--spacing-xl);
55
+ border-top: 1px solid var(--color-gray-200);
56
+ }
57
+
58
+ .parameters-list {
59
+ margin-top: var(--spacing-lg);
60
+ }
61
+
62
+ .parameters-table {
63
+ display: flex;
64
+ flex-direction: column;
65
+ gap: var(--spacing-md);
66
+ }
67
+
68
+ .parameter-row {
69
+ padding: var(--spacing-md);
70
+ background-color: var(--color-gray-50);
71
+ border-radius: var(--radius-md);
72
+ border: 1px solid var(--color-gray-200);
73
+ }
74
+
75
+ .parameter-name {
76
+ font-family: monospace;
77
+ font-weight: 600;
78
+ color: var(--color-gray-900);
79
+ margin-bottom: var(--spacing-xs);
80
+ }
81
+
82
+ .parameter-details {
83
+ display: flex;
84
+ gap: var(--spacing-lg);
85
+ flex-wrap: wrap;
86
+ align-items: baseline;
87
+ }
88
+
89
+ .parameter-type,
90
+ .parameter-required,
91
+ .parameter-default {
92
+ font-size: var(--font-size-sm);
93
+ color: var(--color-gray-600);
94
+ }
95
+
96
+ .parameter-type {
97
+ font-family: monospace;
98
+ color: var(--color-primary-600);
99
+ }
100
+
101
+ .parameter-required {
102
+ color: var(--color-danger);
103
+ font-weight: 500;
104
+ }
105
+
106
+ .parameter-description {
107
+ margin-top: var(--spacing-xs);
108
+ font-size: var(--font-size-sm);
109
+ color: var(--color-gray-700);
110
+ }
111
+
112
+ /* Parameter Form Fields */
113
+ .parameters-section {
114
+ background-color: var(--color-gray-50);
115
+ border: 1px solid var(--color-gray-200);
116
+ border-radius: var(--radius-md);
117
+ padding: var(--spacing-lg);
118
+ margin-top: var(--spacing-lg);
119
+ }
120
+
121
+ .parameter-fields {
122
+ margin-top: var(--spacing-md);
123
+ padding: var(--spacing-md);
124
+ background-color: var(--color-gray-50);
125
+ border-radius: var(--radius-md);
126
+ border: 1px solid var(--color-gray-200);
127
+ }
128
+
129
+ .parameters-list {
130
+ display: flex;
131
+ flex-direction: column;
132
+ gap: var(--spacing-md);
133
+ }
134
+
135
+ .parameter-item {
136
+ background-color: white;
137
+ border: 1px solid var(--color-gray-200);
138
+ border-radius: var(--radius-md);
139
+ padding: var(--spacing-md);
140
+ display: grid;
141
+ grid-template-columns: 2fr 1fr 1fr 2fr 100px;
142
+ gap: var(--spacing-md);
143
+ align-items: start;
144
+ }
145
+
146
+ .parameter-field {
147
+ display: flex;
148
+ flex-direction: column;
149
+ }
150
+
151
+ .parameter-field label {
152
+ font-size: var(--font-size-xs);
153
+ font-weight: 500;
154
+ color: var(--color-gray-600);
155
+ margin-bottom: var(--spacing-xs);
156
+ }
157
+
158
+ .parameter-field input,
159
+ .parameter-field select {
160
+ font-size: var(--font-size-sm);
161
+ }
162
+
163
+ .parameter-checkbox {
164
+ display: flex;
165
+ align-items: center;
166
+ gap: var(--spacing-xs);
167
+ margin-top: 20px;
168
+ }
169
+
170
+ /* Empty State */
171
+ .empty-state {
172
+ text-align: center;
173
+ padding: var(--spacing-2xl) var(--spacing-lg);
174
+ color: var(--color-gray-500);
175
+ }
176
+
177
+ .empty-state__icon {
178
+ font-size: 3rem;
179
+ margin-bottom: var(--spacing-md);
180
+ opacity: 0.3;
181
+ }
182
+
183
+ .empty-state__title {
184
+ font-size: var(--font-size-lg);
185
+ font-weight: 600;
186
+ color: var(--color-gray-700);
187
+ margin-bottom: var(--spacing-sm);
188
+ }
189
+
190
+ .empty-state__description {
191
+ font-size: var(--font-size-sm);
192
+ color: var(--color-gray-600);
193
+ margin-bottom: var(--spacing-lg);
194
+ }
195
+
196
+ /* Evaluation Sets Summary */
197
+ .eval-sets-summary {
198
+ display: flex;
199
+ flex-direction: column;
200
+ gap: var(--spacing-md);
201
+ }
202
+
203
+ .eval-set-summary-item {
204
+ padding: var(--spacing-md);
205
+ background-color: var(--color-gray-50);
206
+ border: 1px solid var(--color-gray-200);
207
+ border-radius: var(--radius-md);
208
+ }
209
+
210
+ .eval-set-summary__header {
211
+ display: flex;
212
+ justify-content: space-between;
213
+ align-items: center;
214
+ margin-bottom: var(--spacing-sm);
215
+ }
216
+
217
+ .eval-set-summary__title {
218
+ font-size: var(--font-size-base);
219
+ font-weight: 600;
220
+ margin: 0;
221
+ }
222
+
223
+ .eval-set-summary__stats {
224
+ display: flex;
225
+ gap: var(--spacing-sm);
226
+ }
227
+
228
+ .eval-set-summary__description {
229
+ font-size: var(--font-size-sm);
230
+ color: var(--color-gray-600);
231
+ margin: 0 0 var(--spacing-sm) 0;
232
+ }
233
+
234
+ .eval-set-summary__result {
235
+ font-size: var(--font-size-sm);
236
+ color: var(--color-gray-700);
237
+ }
@@ -0,0 +1,90 @@
1
+ /* Sidebar Component */
2
+ .admin-sidebar {
3
+ height: 100%;
4
+ display: flex;
5
+ flex-direction: column;
6
+ }
7
+
8
+ /* Sidebar Header */
9
+ .admin-sidebar__header {
10
+ padding: var(--spacing-lg);
11
+ border-bottom: 1px solid var(--color-gray-800);
12
+ margin-bottom: var(--spacing-md);
13
+ }
14
+
15
+ .admin-sidebar__title {
16
+ font-size: var(--font-size-xl);
17
+ font-weight: 700;
18
+ color: var(--color-gray-100);
19
+ margin: 0;
20
+ letter-spacing: -0.025em;
21
+ }
22
+
23
+ .admin-sidebar__version {
24
+ font-size: var(--font-size-xs);
25
+ color: var(--color-gray-500);
26
+ display: block;
27
+ margin-top: var(--spacing-xs);
28
+ }
29
+
30
+ /* Sidebar Navigation */
31
+ .admin-sidebar__nav {
32
+ flex: 1;
33
+ padding: 0 var(--spacing-md);
34
+ }
35
+
36
+ .admin-nav {
37
+ list-style: none;
38
+ }
39
+
40
+ .admin-nav__item {
41
+ margin-bottom: var(--spacing-xs);
42
+ }
43
+
44
+ .admin-nav__link {
45
+ display: block;
46
+ padding: var(--spacing-sm) var(--spacing-md);
47
+ color: var(--color-gray-300);
48
+ text-decoration: none;
49
+ border-radius: var(--radius-md);
50
+ transition: all var(--transition-fast);
51
+ font-size: var(--font-size-sm);
52
+ font-weight: 500;
53
+ position: relative;
54
+ }
55
+
56
+ .admin-nav__link:hover {
57
+ color: white;
58
+ background-color: var(--color-gray-800);
59
+ text-decoration: none;
60
+ }
61
+
62
+ /* Active Navigation Item */
63
+ .admin-nav__link--active {
64
+ color: white;
65
+ background-color: var(--color-gray-800);
66
+ }
67
+
68
+ .admin-nav__link--active::before {
69
+ content: '';
70
+ position: absolute;
71
+ left: 0;
72
+ top: 50%;
73
+ transform: translateY(-50%);
74
+ width: 3px;
75
+ height: 20px;
76
+ background-color: var(--color-primary-500);
77
+ border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
78
+ }
79
+
80
+ /* Disabled Navigation Item */
81
+ .admin-nav__link--disabled {
82
+ color: var(--color-gray-500);
83
+ cursor: not-allowed;
84
+ opacity: 0.6;
85
+ }
86
+
87
+ .admin-nav__link--disabled:hover {
88
+ color: var(--color-gray-500);
89
+ background-color: transparent;
90
+ }
@@ -0,0 +1,250 @@
1
+ /* Table Components */
2
+ .table-container {
3
+ background-color: white;
4
+ border: 1px solid var(--color-gray-200);
5
+ border-radius: var(--radius-lg);
6
+ overflow: hidden;
7
+ box-shadow: var(--shadow-sm);
8
+ }
9
+
10
+ .table {
11
+ width: 100%;
12
+ border-collapse: collapse;
13
+ font-size: var(--font-size-sm);
14
+ }
15
+
16
+
17
+ .table__row {
18
+ border-bottom: 1px solid var(--color-gray-100);
19
+ transition: background-color var(--transition-fast);
20
+ }
21
+
22
+ .table__row:last-child {
23
+ border-bottom: none;
24
+ }
25
+
26
+ .table__row:hover {
27
+ background-color: var(--color-gray-50);
28
+ }
29
+
30
+ /* Table Cells */
31
+ .table__cell {
32
+ padding: var(--spacing-md);
33
+ text-align: left;
34
+ vertical-align: middle;
35
+ }
36
+
37
+ .table__cell--header {
38
+ font-weight: 600;
39
+ color: var(--color-gray-700);
40
+ white-space: nowrap;
41
+ }
42
+
43
+ .table__cell--center {
44
+ text-align: center;
45
+ }
46
+
47
+ .table__cell--right {
48
+ text-align: right;
49
+ }
50
+
51
+ .table__cell--actions {
52
+ width: 1%;
53
+ white-space: nowrap;
54
+ text-align: right;
55
+ }
56
+
57
+ /* Table Status Badge */
58
+ .table__badge {
59
+ display: inline-flex;
60
+ align-items: center;
61
+ padding: var(--spacing-xs) var(--spacing-sm);
62
+ font-size: var(--font-size-xs);
63
+ font-weight: 500;
64
+ border-radius: var(--radius-md);
65
+ text-transform: capitalize;
66
+ }
67
+
68
+ .table__badge--draft {
69
+ background-color: var(--color-gray-100);
70
+ color: var(--color-gray-700);
71
+ }
72
+
73
+ .table__badge--active {
74
+ background-color: #dcfce7;
75
+ color: #166534;
76
+ }
77
+
78
+ .table__badge--archived {
79
+ background-color: #fef3c7;
80
+ color: #92400e;
81
+ }
82
+
83
+ .table__badge--info {
84
+ background-color: #dbeafe;
85
+ color: #1e40af;
86
+ }
87
+
88
+ .table__badge--warning {
89
+ background-color: #fed7aa;
90
+ color: #c2410c;
91
+ }
92
+
93
+ .table__badge--success {
94
+ background-color: #dcfce7;
95
+ color: #166534;
96
+ }
97
+
98
+ .table__badge--pending {
99
+ background-color: #e5e7eb;
100
+ color: #374151;
101
+ }
102
+
103
+ .table__badge--running {
104
+ background-color: #ddd6fe;
105
+ color: #5b21b6;
106
+ }
107
+
108
+ .table__badge--completed {
109
+ background-color: #d1fae5;
110
+ color: #065f46;
111
+ }
112
+
113
+ .table__badge--failed {
114
+ background-color: #fee2e2;
115
+ color: #991b1b;
116
+ }
117
+
118
+ /* Empty State */
119
+ .table__empty {
120
+ padding: var(--spacing-3xl) var(--spacing-xl);
121
+ text-align: center;
122
+ color: var(--color-gray-500);
123
+ }
124
+
125
+
126
+ .table__empty-title {
127
+ font-size: var(--font-size-lg);
128
+ font-weight: 600;
129
+ color: var(--color-gray-700);
130
+ margin-bottom: var(--spacing-sm);
131
+ }
132
+
133
+ .table__empty-text {
134
+ font-size: var(--font-size-sm);
135
+ margin-bottom: var(--spacing-lg);
136
+ }
137
+
138
+ /* Table empty state */
139
+ .table-empty {
140
+ padding: var(--spacing-xl) var(--spacing-lg);
141
+ text-align: center;
142
+ color: var(--color-gray-600);
143
+ }
144
+
145
+ /* Table text styles */
146
+ .table__primary {
147
+ font-weight: 500;
148
+ color: var(--color-gray-900);
149
+ }
150
+
151
+ .table__secondary {
152
+ color: var(--color-gray-600);
153
+ font-size: var(--font-size-sm);
154
+ }
155
+
156
+ .table__action {
157
+ color: var(--color-primary-600);
158
+ text-decoration: none;
159
+ font-weight: 500;
160
+ transition: color var(--transition-fast);
161
+ }
162
+
163
+ .table__action:hover {
164
+ color: var(--color-primary-700);
165
+ text-decoration: underline;
166
+ }
167
+
168
+ .table__link {
169
+ color: var(--color-primary-600);
170
+ text-decoration: none;
171
+ font-weight: 500;
172
+ transition: color var(--transition-fast);
173
+ }
174
+
175
+ .table__link:hover {
176
+ color: var(--color-primary-700);
177
+ text-decoration: underline;
178
+ }
179
+
180
+ .table__actions {
181
+ text-align: right;
182
+ }
183
+
184
+ .table__actions-header {
185
+ text-align: right;
186
+ }
187
+
188
+ /* Table metrics */
189
+ .table__metric {
190
+ display: inline-flex;
191
+ align-items: baseline;
192
+ gap: 0.125rem;
193
+ }
194
+
195
+ .table__metric-value {
196
+ font-weight: 500;
197
+ color: var(--color-gray-900);
198
+ }
199
+
200
+ .table__metric-unit {
201
+ font-size: var(--font-size-xs);
202
+ color: var(--color-gray-600);
203
+ }
204
+
205
+ /* Compact table variant */
206
+ .table-container--compact {
207
+ border: none;
208
+ box-shadow: none;
209
+ background: transparent;
210
+ }
211
+
212
+ .table-container--compact .table {
213
+ margin: 0;
214
+ }
215
+
216
+ /* Simple table variant (no header) */
217
+ .table--simple tbody tr td {
218
+ padding: 0.5rem 0.75rem;
219
+ border-bottom: 1px solid var(--color-gray-100);
220
+ }
221
+
222
+ .table--simple tbody tr:first-child td {
223
+ padding-top: 0;
224
+ }
225
+
226
+ .table--simple tbody tr:last-child td {
227
+ border-bottom: none;
228
+ padding-bottom: 0;
229
+ }
230
+
231
+ /* Responsive Table */
232
+ @media (max-width: 768px) {
233
+ .table-container {
234
+ border-radius: 0;
235
+ border-left: none;
236
+ border-right: none;
237
+ }
238
+
239
+ .table {
240
+ font-size: var(--font-size-xs);
241
+ }
242
+
243
+ .table__cell {
244
+ padding: var(--spacing-sm);
245
+ }
246
+
247
+ .table__cell--hide-mobile {
248
+ display: none;
249
+ }
250
+ }
@@ -0,0 +1,52 @@
1
+ /* Utility Classes */
2
+ /* Margin utilities */
3
+ .mb-md { margin-bottom: var(--spacing-md); }
4
+ .mb-lg { margin-bottom: var(--spacing-lg); }
5
+ .mt-md { margin-top: var(--spacing-md); }
6
+ .mt-lg { margin-top: var(--spacing-lg); }
7
+ .my-md { margin-top: var(--spacing-md); margin-bottom: var(--spacing-md); }
8
+ .my-lg { margin-top: var(--spacing-lg); margin-bottom: var(--spacing-lg); }
9
+
10
+ /* Text and Link Utilities */
11
+ .text-link {
12
+ color: var(--color-primary);
13
+ text-decoration: none;
14
+ transition: all 0.2s ease;
15
+ }
16
+
17
+ .text-link:hover {
18
+ color: var(--color-primary-dark);
19
+ text-decoration: underline;
20
+ }
21
+
22
+ .text-muted {
23
+ color: var(--color-text-muted);
24
+ }
25
+
26
+ /* Text Alignment */
27
+ .text-center {
28
+ text-align: center;
29
+ }
30
+
31
+ .text-left {
32
+ text-align: left;
33
+ }
34
+
35
+ .text-right {
36
+ text-align: right;
37
+ }
38
+
39
+ /* Padding Utilities */
40
+ .py-lg {
41
+ padding-top: var(--spacing-lg);
42
+ padding-bottom: var(--spacing-lg);
43
+ }
44
+
45
+ .px-lg {
46
+ padding-left: var(--spacing-lg);
47
+ padding-right: var(--spacing-lg);
48
+ }
49
+
50
+ .p-lg {
51
+ padding: var(--spacing-lg);
52
+ }