loadout-ai 0.1.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 (125) hide show
  1. package/LICENSE +21 -0
  2. package/MASTER_PLAN.md +1711 -0
  3. package/README.md +453 -0
  4. package/SECURITY.md +18 -0
  5. package/SIMPLE_PLAN.md +44 -0
  6. package/catalog/discovered.json +10469 -0
  7. package/catalog/packages.json +1150 -0
  8. package/dashboard/app.js +607 -0
  9. package/dashboard/index.html +249 -0
  10. package/dashboard/styles.css +384 -0
  11. package/dist/src/cli.js +2735 -0
  12. package/dist/src/core/active-policy.js +233 -0
  13. package/dist/src/core/active-set.js +382 -0
  14. package/dist/src/core/adapters.js +254 -0
  15. package/dist/src/core/adopt.js +92 -0
  16. package/dist/src/core/agent-health-score.js +475 -0
  17. package/dist/src/core/agent-inspection.js +152 -0
  18. package/dist/src/core/agent-versions.js +131 -0
  19. package/dist/src/core/api.js +90 -0
  20. package/dist/src/core/atomic-file.js +22 -0
  21. package/dist/src/core/audit.js +174 -0
  22. package/dist/src/core/benchmark-campaign.js +496 -0
  23. package/dist/src/core/benchmark-evidence.js +458 -0
  24. package/dist/src/core/benchmark-fixtures.js +1157 -0
  25. package/dist/src/core/benchmark-runner.js +301 -0
  26. package/dist/src/core/benchmark-trust.js +795 -0
  27. package/dist/src/core/canary.js +77 -0
  28. package/dist/src/core/candidate-intelligence.js +661 -0
  29. package/dist/src/core/catalog-coverage.js +85 -0
  30. package/dist/src/core/catalog-install.js +186 -0
  31. package/dist/src/core/catalog-release.js +286 -0
  32. package/dist/src/core/catalog.js +327 -0
  33. package/dist/src/core/codex-mcp.js +122 -0
  34. package/dist/src/core/community.js +86 -0
  35. package/dist/src/core/compatibility-intelligence.js +465 -0
  36. package/dist/src/core/completion.js +160 -0
  37. package/dist/src/core/components.js +138 -0
  38. package/dist/src/core/conversion.js +56 -0
  39. package/dist/src/core/credentials.js +377 -0
  40. package/dist/src/core/demo.js +136 -0
  41. package/dist/src/core/diff.js +83 -0
  42. package/dist/src/core/discovery-connector.js +165 -0
  43. package/dist/src/core/doctor.js +95 -0
  44. package/dist/src/core/ecosystem-import.js +1072 -0
  45. package/dist/src/core/evaluate.js +72 -0
  46. package/dist/src/core/file-lock.js +140 -0
  47. package/dist/src/core/freshness-alerts.js +230 -0
  48. package/dist/src/core/github-discovery.js +97 -0
  49. package/dist/src/core/github.js +148 -0
  50. package/dist/src/core/head-to-head.js +437 -0
  51. package/dist/src/core/health-score-evidence.js +169 -0
  52. package/dist/src/core/health.js +129 -0
  53. package/dist/src/core/improve.js +223 -0
  54. package/dist/src/core/install.js +233 -0
  55. package/dist/src/core/intelligence-feed-build.js +59 -0
  56. package/dist/src/core/intelligence-feed.js +353 -0
  57. package/dist/src/core/loadout-badge.js +55 -0
  58. package/dist/src/core/loadout-card.js +87 -0
  59. package/dist/src/core/manifest.js +307 -0
  60. package/dist/src/core/mcp-recipes.js +419 -0
  61. package/dist/src/core/mcp-registry-discovery.js +455 -0
  62. package/dist/src/core/mcp.js +287 -0
  63. package/dist/src/core/model-config.js +102 -0
  64. package/dist/src/core/observations.js +87 -0
  65. package/dist/src/core/outcomes.js +164 -0
  66. package/dist/src/core/package.js +225 -0
  67. package/dist/src/core/paths.js +214 -0
  68. package/dist/src/core/portable.js +130 -0
  69. package/dist/src/core/private-discovery.js +45 -0
  70. package/dist/src/core/profiles.js +255 -0
  71. package/dist/src/core/provenance.js +278 -0
  72. package/dist/src/core/ranking.js +104 -0
  73. package/dist/src/core/recommend.js +181 -0
  74. package/dist/src/core/registry-api.js +97 -0
  75. package/dist/src/core/registry.js +316 -0
  76. package/dist/src/core/release-claims.js +175 -0
  77. package/dist/src/core/remove.js +122 -0
  78. package/dist/src/core/review-queue.js +200 -0
  79. package/dist/src/core/runtime-tool-recipe.js +315 -0
  80. package/dist/src/core/runtime-tools.js +453 -0
  81. package/dist/src/core/safety.js +234 -0
  82. package/dist/src/core/sandbox.js +78 -0
  83. package/dist/src/core/scheduler.js +264 -0
  84. package/dist/src/core/share-report.js +85 -0
  85. package/dist/src/core/signing.js +115 -0
  86. package/dist/src/core/skill-compare.js +239 -0
  87. package/dist/src/core/skill-inventory.js +193 -0
  88. package/dist/src/core/skill-security.js +340 -0
  89. package/dist/src/core/skills-sh-discovery.js +336 -0
  90. package/dist/src/core/skills.js +208 -0
  91. package/dist/src/core/snapshot.js +210 -0
  92. package/dist/src/core/source.js +305 -0
  93. package/dist/src/core/state.js +300 -0
  94. package/dist/src/core/sync.js +348 -0
  95. package/dist/src/core/terminal.js +53 -0
  96. package/dist/src/core/transaction.js +211 -0
  97. package/dist/src/core/update-watch.js +39 -0
  98. package/dist/src/core/update.js +216 -0
  99. package/dist/src/core/upgrade.js +207 -0
  100. package/dist/src/dashboard.js +418 -0
  101. package/dist/src/shared/schemas.js +336 -0
  102. package/dist/src/shared/types.js +1 -0
  103. package/docs/ACTIVE_SET.md +53 -0
  104. package/docs/ACTIVE_SET_POLICY.md +45 -0
  105. package/docs/CANDIDATE_INTELLIGENCE.md +139 -0
  106. package/docs/CATALOG.md +78 -0
  107. package/docs/CATALOG_POLICY.md +41 -0
  108. package/docs/COMMUNITY_DISCOVERY.md +14 -0
  109. package/docs/COMPATIBILITY_POLICY.md +22 -0
  110. package/docs/CONVERSION_AND_SANDBOX.md +27 -0
  111. package/docs/CREDENTIAL_AND_UPDATE_POLICY.md +31 -0
  112. package/docs/DISCOVERED.md +280 -0
  113. package/docs/EVALUATION_PROTOCOL.md +40 -0
  114. package/docs/EVALUATION_PROTOCOL_V1.md +300 -0
  115. package/docs/FEATURE_TEST_MATRIX.md +802 -0
  116. package/docs/GITHUB_AUTHORIZATION.md +38 -0
  117. package/docs/HEAD_TO_HEAD_EVALUATION.md +79 -0
  118. package/docs/PROVENANCE_AND_COMPARISON.md +72 -0
  119. package/docs/PROVIDER_CONFIGURATION.md +45 -0
  120. package/docs/RELEASE_REVIEW.md +117 -0
  121. package/docs/SAFE_UPDATE_DEMO.md +25 -0
  122. package/docs/SCHEMA_DECISIONS.md +25 -0
  123. package/docs/TEAM_POLICY.md +18 -0
  124. package/docs/TESTING.md +190 -0
  125. package/package.json +82 -0
@@ -0,0 +1,249 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Loadout dashboard</title>
7
+ <link rel="stylesheet" href="/styles.css" />
8
+ </head>
9
+ <body>
10
+ <a class="skip-link" href="#dashboard-content">Skip to dashboard content</a>
11
+ <main id="dashboard-content" tabindex="-1">
12
+ <header aria-labelledby="page-title">
13
+ <p class="eyebrow">LOADOUT</p>
14
+ <h1 id="page-title">Your agent control center.</h1>
15
+ <p class="subhead">
16
+ Health, safe updates, tested setups, and real packages from this
17
+ machine.
18
+ </p>
19
+ <nav class="dashboard-nav" aria-label="Dashboard views">
20
+ <a href="#home" data-route="home">Home</a>
21
+ <a href="#discover" data-route="discover">Discover</a>
22
+ <a href="#installed" data-route="installed">Installed</a>
23
+ <a href="#updates" data-route="updates">Updates</a>
24
+ </nav>
25
+ <div class="refresh-row">
26
+ <button
27
+ id="refresh-dashboard"
28
+ type="button"
29
+ aria-describedby="refresh-help"
30
+ >
31
+ Refresh dashboard
32
+ </button>
33
+ <span id="refresh-help" class="muted"
34
+ >Reads local Loadout data only. It does not install, update, or send
35
+ anything.</span
36
+ >
37
+ </div>
38
+ <p
39
+ id="dashboard-notice"
40
+ class="sr-only"
41
+ role="status"
42
+ aria-live="polite"
43
+ ></p>
44
+ </header>
45
+
46
+ <section id="home" data-screen aria-labelledby="status-heading">
47
+ <div class="section-title">
48
+ <h2 id="status-heading">Agent status</h2>
49
+ </div>
50
+ <div
51
+ id="status"
52
+ class="state"
53
+ role="status"
54
+ aria-live="polite"
55
+ aria-busy="true"
56
+ >
57
+ Loading agent status…
58
+ </div>
59
+ </section>
60
+
61
+ <section data-screen="home" aria-labelledby="sync-heading">
62
+ <div class="section-title">
63
+ <h2 id="sync-heading">Synchronize</h2>
64
+ <span>Explicit approval required</span>
65
+ </div>
66
+ <div
67
+ class="action-bar"
68
+ role="group"
69
+ aria-label="Synchronize manifest actions"
70
+ >
71
+ <button id="preview-sync" type="button" aria-describedby="sync-help">
72
+ Preview manifest
73
+ </button>
74
+ <button id="apply-sync" type="button" disabled>
75
+ Apply safe plan
76
+ </button>
77
+ <button id="rollback-sync" class="secondary" type="button" disabled>
78
+ Undo last dashboard change
79
+ </button>
80
+ </div>
81
+ <p id="sync-help" class="muted">
82
+ Preview is read-only. Applying remains disabled until a safe plan is
83
+ reviewed and acknowledged.
84
+ </p>
85
+ <label class="approval-control" for="sync-acknowledgement"
86
+ ><input id="sync-acknowledgement" type="checkbox" disabled /> I
87
+ reviewed this safe plan and want to apply it.</label
88
+ >
89
+ <div id="sync-result" class="state" role="status" aria-live="polite">
90
+ Preview <code>loadout.json</code> before applying anything.
91
+ </div>
92
+ </section>
93
+
94
+ <section data-screen="home" aria-labelledby="health-heading">
95
+ <div class="section-title">
96
+ <h2 id="health-heading">Health</h2>
97
+ <span id="health-label"></span>
98
+ </div>
99
+ <div
100
+ id="health"
101
+ class="state"
102
+ role="status"
103
+ aria-live="polite"
104
+ aria-busy="true"
105
+ >
106
+ Checking setup health…
107
+ </div>
108
+ </section>
109
+
110
+ <section id="updates" data-screen aria-labelledby="updates-heading">
111
+ <div class="section-title">
112
+ <h2 id="updates-heading">Updates</h2>
113
+ <span id="updates-count"></span>
114
+ </div>
115
+ <div
116
+ id="updates-list"
117
+ class="state"
118
+ role="status"
119
+ aria-live="polite"
120
+ aria-busy="true"
121
+ >
122
+ Checking installed packages…
123
+ </div>
124
+ </section>
125
+
126
+ <section data-screen="home" aria-labelledby="recommendations-heading">
127
+ <div class="section-title">
128
+ <h2 id="recommendations-heading">Recommended for this project</h2>
129
+ <span id="project-signals"></span>
130
+ </div>
131
+ <div
132
+ id="recommendations"
133
+ class="grid state"
134
+ role="status"
135
+ aria-live="polite"
136
+ aria-busy="true"
137
+ >
138
+ Reading local project signals…
139
+ </div>
140
+ </section>
141
+
142
+ <section data-screen="home" aria-labelledby="profiles-heading">
143
+ <div class="section-title">
144
+ <h2 id="profiles-heading">Tested profiles</h2>
145
+ <span>Preview only</span>
146
+ </div>
147
+ <div
148
+ id="profiles"
149
+ class="grid state"
150
+ role="status"
151
+ aria-live="polite"
152
+ aria-busy="true"
153
+ >
154
+ Loading profiles…
155
+ </div>
156
+ </section>
157
+
158
+ <section id="discover" data-screen aria-labelledby="catalog-heading">
159
+ <div class="section-title">
160
+ <h2 id="catalog-heading">Discover packages</h2>
161
+ <span id="catalog-count"></span>
162
+ </div>
163
+ <p class="muted">
164
+ Browse verified catalog records already available in this local
165
+ checkout. Package details are read-only; add a package to
166
+ <code>loadout.json</code>, then preview it before any write.
167
+ </p>
168
+ <div
169
+ class="catalog-filters"
170
+ role="search"
171
+ aria-label="Filter catalog packages"
172
+ >
173
+ <label for="catalog-search"
174
+ >Search
175
+ <input
176
+ id="catalog-search"
177
+ type="search"
178
+ autocomplete="off"
179
+ placeholder="Name, category, or repository"
180
+ /></label>
181
+ <label for="catalog-tier"
182
+ >Trust tier
183
+ <select id="catalog-tier">
184
+ <option value="">All tiers</option>
185
+ <option value="official">Official</option>
186
+ <option value="stable">Stable</option>
187
+ <option value="trending">Trending</option>
188
+ <option value="community">Community</option>
189
+ </select></label
190
+ >
191
+ <label for="catalog-category"
192
+ >Outcome
193
+ <select id="catalog-category">
194
+ <option value="">All outcomes</option>
195
+ </select></label
196
+ >
197
+ </div>
198
+ <div
199
+ id="catalog"
200
+ class="grid state"
201
+ role="status"
202
+ aria-live="polite"
203
+ aria-busy="true"
204
+ >
205
+ Loading catalog…
206
+ </div>
207
+ </section>
208
+
209
+ <section data-screen="discover" aria-labelledby="registry-heading">
210
+ <div class="section-title">
211
+ <h2 id="registry-heading">Local registry</h2>
212
+ <span id="registry-count"></span>
213
+ </div>
214
+ <div
215
+ id="registry"
216
+ class="grid state"
217
+ role="status"
218
+ aria-live="polite"
219
+ aria-busy="true"
220
+ >
221
+ Loading locally published packages…
222
+ </div>
223
+ </section>
224
+
225
+ <section id="installed" data-screen aria-labelledby="installed-heading">
226
+ <div class="section-title">
227
+ <h2 id="installed-heading">Installed packages</h2>
228
+ <span id="installed-count"></span>
229
+ </div>
230
+ <p id="last-snapshot" class="muted"></p>
231
+ <div
232
+ id="installed-list"
233
+ class="grid state"
234
+ role="status"
235
+ aria-live="polite"
236
+ aria-busy="true"
237
+ >
238
+ Reading managed package state…
239
+ </div>
240
+ </section>
241
+
242
+ <footer>
243
+ Dashboard mutations require a private session token, an explicit
244
+ preview, and acknowledgement. Risky plans remain CLI-only.
245
+ </footer>
246
+ </main>
247
+ <script type="module" src="/app.js"></script>
248
+ </body>
249
+ </html>
@@ -0,0 +1,384 @@
1
+ :root {
2
+ color-scheme: dark;
3
+ font-family: Inter, ui-sans-serif, system-ui, sans-serif;
4
+ background: #101114;
5
+ color: #f4f4f5;
6
+ }
7
+ body {
8
+ margin: 0;
9
+ line-height: 1.5;
10
+ }
11
+ main {
12
+ max-width: 960px;
13
+ margin: 0 auto;
14
+ padding: 64px 24px;
15
+ }
16
+ header {
17
+ margin-bottom: 44px;
18
+ }
19
+ .eyebrow {
20
+ color: #a78bfa;
21
+ letter-spacing: 0.18em;
22
+ font-size: 12px;
23
+ font-weight: 700;
24
+ }
25
+ h1 {
26
+ font-size: clamp(2.3rem, 7vw, 5rem);
27
+ line-height: 0.98;
28
+ max-width: 720px;
29
+ margin: 12px 0;
30
+ }
31
+ .subhead {
32
+ color: #a1a1aa;
33
+ font-size: 18px;
34
+ }
35
+ h2 {
36
+ font-size: 24px;
37
+ }
38
+ .dashboard-nav {
39
+ display: flex;
40
+ flex-wrap: wrap;
41
+ gap: 8px;
42
+ margin-top: 24px;
43
+ }
44
+ .dashboard-nav a {
45
+ border: 1px solid #3f3f46;
46
+ border-radius: 999px;
47
+ color: #d4d4d8;
48
+ padding: 7px 12px;
49
+ text-decoration: none;
50
+ }
51
+ .dashboard-nav a[aria-current="page"] {
52
+ border-color: #8b5cf6;
53
+ background: #2e1065;
54
+ color: #ede9fe;
55
+ }
56
+ .dashboard-nav a:focus-visible {
57
+ outline: 3px solid #c4b5fd;
58
+ outline-offset: 2px;
59
+ }
60
+ .skip-link {
61
+ position: fixed;
62
+ z-index: 10;
63
+ top: 12px;
64
+ left: 12px;
65
+ transform: translateY(-160%);
66
+ border-radius: 8px;
67
+ background: #f4f4f5;
68
+ color: #18181b;
69
+ padding: 8px 12px;
70
+ font-weight: 700;
71
+ text-decoration: none;
72
+ }
73
+ .skip-link:focus {
74
+ transform: translateY(0);
75
+ outline: 3px solid #c4b5fd;
76
+ outline-offset: 2px;
77
+ }
78
+ .sr-only {
79
+ position: absolute;
80
+ width: 1px;
81
+ height: 1px;
82
+ padding: 0;
83
+ margin: -1px;
84
+ overflow: hidden;
85
+ clip: rect(0, 0, 0, 0);
86
+ white-space: nowrap;
87
+ border: 0;
88
+ }
89
+ .section-title {
90
+ display: flex;
91
+ align-items: baseline;
92
+ justify-content: space-between;
93
+ }
94
+ .section-title span,
95
+ small,
96
+ .muted {
97
+ color: #b4b4bc;
98
+ }
99
+ .state {
100
+ border: 1px solid #27272a;
101
+ border-radius: 14px;
102
+ padding: 18px;
103
+ color: #a1a1aa;
104
+ display: flex;
105
+ gap: 12px;
106
+ flex-wrap: wrap;
107
+ }
108
+ .success {
109
+ border-color: #14532d;
110
+ color: #bbf7d0;
111
+ }
112
+ .error {
113
+ border-color: #7f1d1d;
114
+ color: #fecaca;
115
+ }
116
+ .attention {
117
+ border-color: #854d0e;
118
+ color: #fef3c7;
119
+ }
120
+ .grid {
121
+ display: grid;
122
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
123
+ gap: 14px;
124
+ }
125
+ section[hidden] {
126
+ display: none;
127
+ }
128
+ article {
129
+ border: 1px solid #27272a;
130
+ border-radius: 14px;
131
+ padding: 18px;
132
+ background: #18181b;
133
+ }
134
+ article h3 {
135
+ margin: 0 0 8px;
136
+ }
137
+ article p {
138
+ min-height: 42px;
139
+ color: #d4d4d8;
140
+ line-height: 1.4;
141
+ }
142
+ small {
143
+ font-size: 12px;
144
+ }
145
+ .updates-grid {
146
+ display: grid;
147
+ gap: 12px;
148
+ }
149
+ .update-heading {
150
+ display: flex;
151
+ align-items: center;
152
+ justify-content: space-between;
153
+ gap: 12px;
154
+ }
155
+ .card-heading {
156
+ display: flex;
157
+ align-items: center;
158
+ justify-content: space-between;
159
+ gap: 12px;
160
+ }
161
+ .update-heading h3 {
162
+ margin: 0;
163
+ }
164
+ .badge {
165
+ border-radius: 999px;
166
+ padding: 4px 9px;
167
+ font-size: 11px;
168
+ color: #d4d4d8;
169
+ background: #27272a;
170
+ }
171
+ .badge.official {
172
+ background: #164e63;
173
+ color: #cffafe;
174
+ }
175
+ .badge.stable,
176
+ .badge.native {
177
+ background: #14532d;
178
+ color: #bbf7d0;
179
+ }
180
+ .badge.trending,
181
+ .badge.adapted {
182
+ background: #713f12;
183
+ color: #fef3c7;
184
+ }
185
+ .badge.community,
186
+ .badge.unsupported {
187
+ background: #3f3f46;
188
+ color: #e4e4e7;
189
+ }
190
+ .update-available {
191
+ border-color: #854d0e;
192
+ }
193
+ .update-available .badge {
194
+ color: #fef3c7;
195
+ background: #713f12;
196
+ }
197
+ .up-to-date .badge {
198
+ color: #bbf7d0;
199
+ background: #14532d;
200
+ }
201
+ .error-text {
202
+ color: #fecaca !important;
203
+ min-height: auto;
204
+ }
205
+ details {
206
+ margin-top: 10px;
207
+ color: #d4d4d8;
208
+ }
209
+ summary {
210
+ cursor: pointer;
211
+ }
212
+ summary:focus-visible {
213
+ outline: 3px solid #c4b5fd;
214
+ outline-offset: 3px;
215
+ border-radius: 4px;
216
+ }
217
+ li {
218
+ margin: 5px 0;
219
+ }
220
+ dl {
221
+ display: grid;
222
+ grid-template-columns: max-content 1fr;
223
+ gap: 6px 12px;
224
+ margin: 12px 0;
225
+ }
226
+ dt {
227
+ color: #a1a1aa;
228
+ }
229
+ dd {
230
+ margin: 0;
231
+ overflow-wrap: anywhere;
232
+ }
233
+ .safety {
234
+ border-left: 3px solid #f59e0b;
235
+ padding-left: 10px;
236
+ }
237
+ .health-list {
238
+ border: 1px solid #27272a;
239
+ border-radius: 14px;
240
+ padding: 18px;
241
+ }
242
+ .health-list p {
243
+ margin: 10px 0 0;
244
+ color: #d4d4d8;
245
+ }
246
+ .metric-row {
247
+ display: flex;
248
+ align-items: baseline;
249
+ gap: 8px;
250
+ flex-wrap: wrap;
251
+ }
252
+ .metric-row strong {
253
+ font-size: 24px;
254
+ }
255
+ .metric-row span {
256
+ color: #a1a1aa;
257
+ margin-right: 14px;
258
+ }
259
+ .finding-level {
260
+ display: inline-block;
261
+ min-width: 58px;
262
+ color: #a1a1aa;
263
+ text-transform: uppercase;
264
+ font-size: 10px;
265
+ letter-spacing: 0.08em;
266
+ }
267
+ section {
268
+ margin-top: 36px;
269
+ }
270
+ footer {
271
+ margin-top: 52px;
272
+ padding-top: 18px;
273
+ border-top: 1px solid #27272a;
274
+ color: #71717a;
275
+ font-size: 13px;
276
+ }
277
+ .action-bar {
278
+ display: flex;
279
+ flex-wrap: wrap;
280
+ gap: 10px;
281
+ margin-bottom: 12px;
282
+ }
283
+ .refresh-row {
284
+ display: flex;
285
+ align-items: center;
286
+ flex-wrap: wrap;
287
+ gap: 12px;
288
+ margin-top: 20px;
289
+ }
290
+ .refresh-row .muted {
291
+ max-width: 560px;
292
+ font-size: 13px;
293
+ }
294
+ .catalog-filters {
295
+ display: flex;
296
+ flex-wrap: wrap;
297
+ gap: 12px;
298
+ margin: 12px 0 16px;
299
+ }
300
+ .catalog-filters label {
301
+ display: grid;
302
+ gap: 5px;
303
+ color: #d4d4d8;
304
+ font-size: 13px;
305
+ }
306
+ input[type="search"],
307
+ select {
308
+ border: 1px solid #3f3f46;
309
+ border-radius: 8px;
310
+ background: #18181b;
311
+ color: #f4f4f5;
312
+ font: inherit;
313
+ min-height: 38px;
314
+ padding: 0 10px;
315
+ }
316
+ input[type="search"] {
317
+ min-width: min(300px, 75vw);
318
+ }
319
+ .approval-control {
320
+ display: flex;
321
+ align-items: flex-start;
322
+ gap: 8px;
323
+ margin: 14px 0;
324
+ color: #d4d4d8;
325
+ }
326
+ .approval-control input {
327
+ width: 18px;
328
+ height: 18px;
329
+ margin-top: 2px;
330
+ accent-color: #8b5cf6;
331
+ }
332
+ button {
333
+ appearance: none;
334
+ border: 1px solid #7c3aed;
335
+ border-radius: 10px;
336
+ background: #7c3aed;
337
+ color: white;
338
+ padding: 10px 14px;
339
+ font: inherit;
340
+ font-weight: 650;
341
+ cursor: pointer;
342
+ }
343
+ button.secondary {
344
+ background: transparent;
345
+ color: #d4d4d8;
346
+ border-color: #3f3f46;
347
+ }
348
+ button:disabled {
349
+ cursor: not-allowed;
350
+ opacity: 0.45;
351
+ }
352
+ button:focus-visible,
353
+ input:focus-visible {
354
+ outline: 3px solid #c4b5fd;
355
+ outline-offset: 2px;
356
+ }
357
+ code {
358
+ color: #c4b5fd;
359
+ }
360
+ @media (max-width: 560px) {
361
+ main {
362
+ padding: 42px 16px;
363
+ }
364
+ .section-title {
365
+ align-items: flex-start;
366
+ flex-direction: column;
367
+ gap: 2px;
368
+ }
369
+ .section-title h2 {
370
+ margin-bottom: 0;
371
+ }
372
+ .refresh-row {
373
+ align-items: flex-start;
374
+ flex-direction: column;
375
+ }
376
+ .catalog-filters label,
377
+ input[type="search"],
378
+ select {
379
+ width: 100%;
380
+ }
381
+ .action-bar > button {
382
+ flex: 1 1 180px;
383
+ }
384
+ }