Client side atproto account migrator in your web browser, along with services for backups and adversarial migrations.
pdsmoover.com
pds
atproto
migrations
moo
cow
1:root {
2 font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
3 line-height: 1.5;
4 font-weight: 400;
5
6 color-scheme: light dark;
7 color: rgba(255, 255, 255, 0.87);
8 background-color: #242424;
9
10 font-synthesis: none;
11 text-rendering: optimizeLegibility;
12 -webkit-font-smoothing: antialiased;
13 -moz-osx-font-smoothing: grayscale;
14}
15
16a {
17 font-weight: 500;
18 color: #a2a7ff;
19 text-decoration: inherit;
20 text-decoration: underline;
21}
22
23a:hover {
24 color: #535bf2;
25}
26
27body {
28 margin: 0;
29 min-width: 320px;
30 padding: 24px 0; /*This will help with centering the whole page */
31}
32
33button {
34 border-radius: 8px;
35 border: 1px solid transparent;
36 padding: 0.6em 1.2em;
37 font-size: 1em;
38 font-weight: 500;
39 font-family: inherit;
40 background-color: #1a1a1a;
41 cursor: pointer;
42 transition: border-color 0.25s;
43}
44
45button:hover {
46 border-color: #646cff;
47}
48
49button:focus,
50button:focus-visible {
51 outline: 4px auto -webkit-focus-ring-color;
52}
53
54@media (prefers-color-scheme: light) {
55 :root {
56 color: #213547;
57 background-color: #ffffff;
58 }
59
60 a:hover {
61 color: #747bff;
62 }
63
64 button {
65 background-color: #f9f9f9;
66 }
67}
68
69.container {
70 max-width: 500px;
71 margin: 0 auto;
72 padding: 20px;
73 text-align: center;
74}
75
76.form-group {
77 margin-bottom: 15px;
78 text-align: left;
79}
80
81.form-group label {
82 /*display: block;*/
83 margin-bottom: 5px;
84}
85
86.form-group input {
87 width: 100%;
88 padding: 8px;
89 box-sizing: border-box;
90}
91
92/* Input group for handle with domain dropdown */
93.input-group {
94 display: flex;
95 width: 100%;
96}
97
98.input-group input {
99 flex: 1;
100 border-top-right-radius: 0;
101 border-bottom-right-radius: 0;
102 border-right: none;
103}
104
105.input-group .domain-select {
106 padding: 8px;
107 border: 1px solid rgba(128, 128, 128, 0.5);
108 border-top-left-radius: 0;
109 border-bottom-left-radius: 0;
110 border-top-right-radius: 4px;
111 border-bottom-right-radius: 4px;
112 background-color: #1a1a1a;
113 color: rgba(255, 255, 255, 0.87);
114 cursor: pointer;
115 min-width: 120px;
116}
117
118@media (prefers-color-scheme: light) {
119 .input-group .domain-select {
120 background-color: #f9f9f9;
121 color: #213547;
122 }
123}
124
125.cow-image {
126 height: 150px;
127 margin: 20px 0 8px 0;
128 display: flex;
129 align-items: center;
130 justify-content: center;
131}
132
133.missing-cow-image {
134 height: 300px;
135 margin: 20px 0 8px 0;
136 display: flex;
137 align-items: center;
138 justify-content: center;
139}
140
141
142.section {
143 margin-top: 30px;
144}
145
146/* Left align the advance options section */
147.show-advance {
148 text-align: left;
149}
150
151.made-by-blur {
152 font-size: 0.9em;
153 color: rgba(127, 127, 127, 0.9);
154 margin-bottom: 12px;
155}
156
157h1 {
158 font-size: 3.2em;
159 line-height: 1.1;
160 margin-bottom: 20px;
161}
162
163.error-message {
164 color: red;
165 font-size: 1.2em;
166 margin-top: 10px;
167}
168
169.status-message {
170 display: block;
171 margin: 15px auto;
172 padding: 10px;
173 background-color: #4a5568;
174 color: white;
175 border-radius: 5px;
176 /*font-weight: bold;*/
177 text-align: center;
178 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
179}
180
181.form-checkbox {
182
183 font-size: 2rem;
184 font-weight: bold;
185 line-height: 1.1;
186 display: grid;
187 grid-template-columns: 1em auto;
188 gap: 0.5em;
189}
190
191/* Navbar styles */
192body {
193 padding-top: 64px; /* space for fixed navbar */
194}
195
196.navbar {
197 position: fixed;
198 top: 0;
199 left: 0;
200 right: 0;
201 z-index: 1000;
202 backdrop-filter: saturate(180%) blur(10px);
203 background: rgba(36, 36, 36, 0.7);
204 border-bottom: 1px solid rgba(255, 255, 255, 0.08);
205}
206
207.bar {
208 color: #ffffff;
209}
210
211@media (prefers-color-scheme: light) {
212 .navbar {
213 background: rgba(255, 255, 255, 0.7);
214 border-bottom-color: rgba(0, 0, 0, 0.08);
215 }
216}
217
218.navbar-inner {
219 max-width: 1000px;
220 margin: 0 auto;
221 padding: 10px 16px;
222 display: flex;
223 align-items: center;
224 justify-content: space-between;
225 gap: 12px;
226}
227
228.brand {
229 font-weight: 800;
230 letter-spacing: 0.3px;
231 color: inherit;
232 text-decoration: none;
233}
234
235.nav-links {
236 display: flex;
237 align-items: center;
238 gap: 6px;
239 flex-wrap: wrap;
240}
241
242.nav-links a {
243 color: inherit;
244 text-decoration: none;
245 padding: 6px 10px;
246 border-radius: 8px;
247 transition: background-color 0.2s ease, color 0.2s ease;
248}
249
250.nav-links a:hover,
251.nav-links a:focus-visible {
252 background-color: rgba(100, 108, 255, 0.16);
253}
254
255.page-content {
256 width: 100%;
257}
258
259/* Mobile-friendly navbar additions */
260.navbar-toggle {
261 display: none;
262 align-items: center;
263 justify-content: center;
264 height: 40px;
265 background: transparent;
266 border: 1px solid rgba(255, 255, 255, 0.15);
267 border-radius: 8px;
268 color: #ffffff; /* default white icon */
269 cursor: pointer;
270}
271
272/* Force the toggle icon to be white in all color schemes */
273.navbar .navbar-toggle {
274 color: #ffffff;
275}
276
277.navbar .navbar-toggle svg {
278 width: 22px;
279 height: 22px;
280 display: block;
281}
282
283.navbar .navbar-toggle svg * {
284 fill: currentColor; /* ensure paths use the button color (white) */
285}
286
287@media (prefers-color-scheme: light) {
288 .navbar-toggle {
289 border-color: rgba(0, 0, 0, 0.12);
290 /* keep icon white per request */
291 color: #ffffff;
292 }
293}
294
295.navbar-toggle .bar {
296 display: block;
297 width: 18px;
298 height: 2px;
299 background: currentColor;
300 margin: 2px 0;
301 border-radius: 2px;
302}
303
304/* Active link example styling */
305.nav-links a.active {
306 background-color: rgba(100, 108, 255, 0.28);
307 font-weight: 600;
308}
309
310/* Responsive behavior */
311@media (max-width: 700px) {
312 .navbar-inner {
313 position: relative;
314 }
315
316 .navbar-toggle {
317 display: inline-flex;
318 }
319
320 .nav-links {
321 position: absolute;
322 top: 100%;
323 left: 0;
324 right: 0;
325 display: none;
326 flex-direction: column;
327 gap: 4px;
328 padding: 10px 16px 12px 16px;
329 background: rgba(36, 36, 36, 0.95); /* solid enough to not bleed into title */
330 backdrop-filter: saturate(180%) blur(10px);
331 border-bottom: 1px solid rgba(255, 255, 255, 0.08);
332 z-index: 1001; /* above page content */
333 box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
334 }
335
336 @media (prefers-color-scheme: light) {
337 .nav-links {
338 border-bottom-color: rgba(0, 0, 0, 0.08);
339 background: rgba(255, 255, 255, 0.98);
340 box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
341 }
342 }
343 .nav-links.open {
344 display: flex;
345 }
346}
347
348/* Support buttons row */
349.support-buttons {
350 display: inline-flex;
351 /*align-items: flex-end; !* bottom-align Ko-fi and GitHub buttons *!*/
352 gap: 8px;
353 justify-content: center;
354 flex-wrap: wrap;
355 margin-top: 8px;
356}
357
358/* Try to coerce Ko-fi generated button to sit inline */
359.support-buttons a.kofi-button, /* common class name used by Ko-fi */
360.support-buttons .kofiwidget, /* fallback */
361.support-buttons .btn-kofi, /* another fallback */
362.support-buttons span.kofi-slot > * {
363 display: inline-block !important;
364 vertical-align: middle;
365}
366
367.support-buttons iframe {
368 vertical-align: middle;
369}
370
371.moove-checkbox-label {
372 display: inline-flex;
373 align-items: center;
374 gap: 0.5rem;
375 white-space: nowrap;
376}
377
378.bold {
379 font-weight: bold;
380}
381
382/* Align action buttons in a row with spacing */
383.actions {
384 display: inline-flex;
385 align-items: center;
386 gap: 8px; /* little bit of spacing between buttons */
387 flex-wrap: wrap; /* stay responsive on very small screens */
388}
389
390/* Refresh button near header */
391.section-header {
392 display: flex;
393 align-items: center;
394 justify-content: space-between;
395 gap: 0.75rem;
396 margin-bottom: 0.5rem;
397 /*flex-wrap: nowrap; !* keep header and button on the same line when possible *!*/
398}
399
400.section-header .icon-button {
401 display: inline-flex;
402 align-items: center;
403 justify-content: center;
404 width: 36px;
405 height: 36px;
406 padding: 0;
407 border-radius: 50%;
408 border: 1px solid transparent;
409 background-color: #1a1a1a;
410 color: #ffffff; /* make SVG icon white via currentColor */
411}
412
413.section-header .icon-button .icon {
414 width: 20px;
415 height: 20px;
416 fill: currentColor;
417}
418
419.section-header .icon-button:hover {
420 border-color: #646cff;
421}
422
423@media (prefers-color-scheme: light) {
424 .section-header .icon-button {
425 background-color: #1a1a1a; /* keep contrast for white icon */
426 }
427}
428
429
430/* Stats grid and cards for the index page */
431.stats-grid {
432 display: grid;
433 grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
434 gap: 12px;
435}
436
437.stat-card {
438 border: 1px solid rgba(128, 128, 128, 0.35);
439 border-radius: 10px;
440 padding: 14px;
441 background: rgba(0, 0, 0, 0.05);
442}
443
444.stat-label {
445 font-size: 0.9rem;
446 opacity: 0.8;
447}
448
449.stat-value {
450 font-size: 1.4rem;
451 font-weight: 700;
452 margin-top: 4px;
453}
454
455.stat-value--small {
456 font-size: 1rem;
457 font-weight: 600;
458 word-break: break-word;
459}
460
461.stat-sub {
462 font-size: 0.85rem;
463 opacity: 0.7;
464 margin-top: 6px;
465}