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.section {
142 margin-top: 30px;
143}
144
145/* Left align the advance options section */
146.show-advance {
147 text-align: left;
148}
149
150.made-by-blur {
151 font-size: 0.9em;
152 color: rgba(127, 127, 127, 0.9);
153 margin-bottom: 12px;
154}
155
156h1 {
157 font-size: 3.2em;
158 line-height: 1.1;
159 margin-bottom: 20px;
160}
161
162.error-message {
163 color: red;
164 font-size: 1.2em;
165 margin-top: 10px;
166}
167
168.status-message {
169 display: block;
170 margin: 15px auto;
171 padding: 10px;
172 background-color: #4a5568;
173 color: white;
174 border-radius: 5px;
175 /*font-weight: bold;*/
176 text-align: center;
177 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
178}
179
180.form-checkbox {
181 font-size: 2rem;
182 font-weight: bold;
183 line-height: 1.1;
184 display: grid;
185 grid-template-columns: 1em auto;
186 gap: 0.5em;
187}
188
189/* Navbar styles */
190body {
191 padding-top: 64px; /* space for fixed navbar */
192}
193
194.navbar {
195 position: fixed;
196 top: 0;
197 left: 0;
198 right: 0;
199 z-index: 1000;
200 backdrop-filter: saturate(180%) blur(10px);
201 background: rgba(36, 36, 36, 0.7);
202 border-bottom: 1px solid rgba(255, 255, 255, 0.08);
203}
204
205.bar {
206 color: #ffffff;
207}
208
209@media (prefers-color-scheme: light) {
210 .navbar {
211 background: rgba(255, 255, 255, 0.7);
212 border-bottom-color: rgba(0, 0, 0, 0.08);
213 }
214}
215
216.navbar-inner {
217 max-width: 1000px;
218 margin: 0 auto;
219 padding: 10px 16px;
220 display: flex;
221 align-items: center;
222 justify-content: space-between;
223 gap: 12px;
224}
225
226.brand {
227 font-weight: 800;
228 letter-spacing: 0.3px;
229 color: inherit;
230 text-decoration: none;
231}
232
233.nav-links {
234 display: flex;
235 align-items: center;
236 gap: 6px;
237 flex-wrap: wrap;
238}
239
240.nav-links a {
241 color: inherit;
242 text-decoration: none;
243 padding: 6px 10px;
244 border-radius: 8px;
245 transition:
246 background-color 0.2s ease,
247 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(
330 36,
331 36,
332 36,
333 0.95
334 ); /* solid enough to not bleed into title */
335 backdrop-filter: saturate(180%) blur(10px);
336 border-bottom: 1px solid rgba(255, 255, 255, 0.08);
337 z-index: 1001; /* above page content */
338 box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
339 }
340
341 @media (prefers-color-scheme: light) {
342 .nav-links {
343 border-bottom-color: rgba(0, 0, 0, 0.08);
344 background: rgba(255, 255, 255, 0.98);
345 box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
346 }
347 }
348 .nav-links.open {
349 display: flex;
350 }
351}
352
353/* Support buttons row */
354.support-buttons {
355 display: inline-flex;
356 /*align-items: flex-end; !* bottom-align Ko-fi and GitHub buttons *!*/
357 gap: 8px;
358 justify-content: center;
359 flex-wrap: wrap;
360 margin-top: 8px;
361}
362
363/* Try to coerce Ko-fi generated button to sit inline */
364.support-buttons a.kofi-button, /* common class name used by Ko-fi */
365.support-buttons .kofiwidget, /* fallback */
366.support-buttons .btn-kofi, /* another fallback */
367.support-buttons span.kofi-slot > * {
368 display: inline-block !important;
369 vertical-align: middle;
370}
371
372.support-buttons iframe {
373 vertical-align: middle;
374}
375
376.moove-checkbox-label {
377 display: inline-flex;
378 align-items: center;
379 gap: 0.5rem;
380 white-space: nowrap;
381}
382
383.bold {
384 font-weight: bold;
385}
386
387/* Align action buttons in a row with spacing */
388.actions {
389 display: inline-flex;
390 align-items: center;
391 gap: 8px; /* little bit of spacing between buttons */
392 flex-wrap: wrap; /* stay responsive on very small screens */
393}
394
395/* Refresh button near header */
396.section-header {
397 display: flex;
398 align-items: center;
399 justify-content: space-between;
400 gap: 0.75rem;
401 margin-bottom: 0.5rem;
402 /*flex-wrap: nowrap; !* keep header and button on the same line when possible *!*/
403}
404
405.section-header .icon-button {
406 display: inline-flex;
407 align-items: center;
408 justify-content: center;
409 width: 36px;
410 height: 36px;
411 padding: 0;
412 border-radius: 50%;
413 border: 1px solid transparent;
414 background-color: #1a1a1a;
415 color: #ffffff; /* make SVG icon white via currentColor */
416}
417
418.section-header .icon-button .icon {
419 width: 20px;
420 height: 20px;
421 fill: currentColor;
422}
423
424.section-header .icon-button:hover {
425 border-color: #646cff;
426}
427
428@media (prefers-color-scheme: light) {
429 .section-header .icon-button {
430 background-color: #1a1a1a; /* keep contrast for white icon */
431 }
432}
433
434/* Stats grid and cards for the index page */
435.stats-grid {
436 display: grid;
437 grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
438 gap: 12px;
439}
440
441.stat-card {
442 border: 1px solid rgba(128, 128, 128, 0.35);
443 border-radius: 10px;
444 padding: 14px;
445 background: rgba(0, 0, 0, 0.05);
446}
447
448.stat-label {
449 font-size: 0.9rem;
450 opacity: 0.8;
451}
452
453.stat-value {
454 font-size: 1.4rem;
455 font-weight: 700;
456 margin-top: 4px;
457}
458
459.stat-value--small {
460 font-size: 1rem;
461 font-weight: 600;
462 word-break: break-word;
463}
464
465.stat-sub {
466 font-size: 0.85rem;
467 opacity: 0.7;
468 margin-top: 6px;
469}
470
471.warning {
472 /*text-decoration: underline;*/
473 font-weight: bold;
474}