Atproto AMA app
1/* ============================================================================
2 Design Tokens
3 ========================================================================= */
4
5:root {
6 /* Spacing Scale - Fibonacci Sequence */
7 --space-1: 1px;
8 --space-2: 2px;
9 --space-3: 3px;
10 --space-5: 5px;
11 --space-8: 8px;
12 --space-13: 13px;
13 --space-21: 21px;
14 --space-34: 34px;
15 --space-55: 55px;
16 --space-89: 89px;
17
18 /* Semantic Spacing Aliases */
19 --space-xs: var(--space-3);
20 --space-sm: var(--space-8);
21 --space-md: var(--space-13);
22 --space-lg: var(--space-21);
23 --space-xl: var(--space-34);
24 --space-2xl: var(--space-55);
25 --space-3xl: var(--space-89);
26
27 /* Colors - Neutrals */
28 --color-white: #ffffff;
29 --color-gray-50: #f9fafb;
30 --color-gray-100: #f3f4f6;
31 --color-gray-200: #e5e7eb;
32 --color-gray-300: #d1d5db;
33 --color-gray-400: #9ca3af;
34 --color-gray-500: #6b7280;
35 --color-gray-600: #4b5563;
36 --color-gray-700: #374151;
37 --color-gray-800: #1f2937;
38 --color-gray-900: #111827;
39
40 /* Colors - Primary (Blue) */
41 --color-blue-50: #eff6ff;
42 --color-blue-100: #dbeafe;
43 --color-blue-500: #3b82f6;
44 --color-blue-600: #2563eb;
45 --color-blue-700: #1d4ed8;
46
47 /* Colors - Semantic (Success) */
48 --color-green-50: #f0fdf4;
49 --color-green-100: #dcfce7;
50 --color-green-200: #bbf7d0;
51 --color-green-300: #86efac;
52 --color-green-500: #22c55e;
53 --color-green-600: #16a34a;
54 --color-green-700: #15803d;
55 --color-green-800: #166534;
56
57 /* Colors - Semantic (Danger/Error) */
58 --color-red-50: #fef2f2;
59 --color-red-500: #ef4444;
60 --color-red-600: #dc2626;
61
62 /* Colors - Semantic (Warning) */
63 --color-yellow-100: #fef3c7;
64 --color-yellow-800: #92400e;
65
66 /* Typography */
67 --font-family-base: Gordita, Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
68 --font-size-xs: 0.75rem; /* 12px */
69 --font-size-sm: 0.875rem; /* 14px */
70 --font-size-base: 1rem; /* 16px */
71 --font-size-lg: 1.125rem; /* 18px */
72 --font-size-xl: 1.25rem; /* 20px */
73 --font-size-2xl: 1.5rem; /* 24px */
74 --font-size-3xl: 1.875rem; /* 30px */
75 --font-size-4xl: 2.25rem; /* 36px */
76
77 --font-weight-normal: 400;
78 --font-weight-medium: 500;
79 --font-weight-semibold: 600;
80 --font-weight-bold: 700;
81
82 --line-height-tight: 1.1;
83 --line-height-normal: 1.35;
84 --line-height-relaxed: 1.5;
85
86 /* Border Radius */
87 --radius-sm: 0.25rem; /* 4px */
88 --radius-md: 0.375rem; /* 6px */
89 --radius-lg: 0.5rem; /* 8px */
90 --radius-full: 9999px;
91
92 /* Borders */
93 --border-width: 1px;
94 --border-color: var(--color-gray-200);
95 --border: var(--border-width) solid var(--border-color);
96
97 /* Layout */
98 --container-max-width: 42rem; /* max-w-2xl equivalent */
99 --container-max-width-lg: 56rem; /* max-w-4xl equivalent */
100 --container-padding: var(--space-md);
101
102 /* Transitions */
103 --transition-base: 150ms ease-in-out;
104}
105
106/* ============================================================================
107 Layer Declarations
108 ========================================================================= */
109
110@layer base, components, utilities;
111
112/* ============================================================================
113 Base Layer
114 ========================================================================= */
115
116@layer base {
117 *,
118 *::before,
119 *::after {
120 box-sizing: border-box;
121 }
122
123 body {
124 margin: 0;
125 font-family: var(--font-family-base);
126 font-size: var(--font-size-base);
127 line-height: var(--line-height-relaxed);
128 color: var(--color-gray-900);
129 background-color: var(--color-gray-50);
130 }
131
132 a {
133 margin-right: 1rem;
134 }
135
136 main {
137 text-align: center;
138 padding: 1em;
139 margin: 0 auto;
140 }
141
142 /* Preserve existing h1 styles */
143 h1 {
144 color: #335d92;
145 text-transform: uppercase;
146 font-size: 4rem;
147 font-weight: 100;
148 line-height: var(--line-height-tight);
149 margin: 4rem auto;
150 max-width: 14rem;
151 }
152
153 p {
154 max-width: 14rem;
155 margin: 2rem auto;
156 line-height: var(--line-height-normal);
157 }
158
159 @media (min-width: 480px) {
160 h1 {
161 max-width: none;
162 }
163
164 p {
165 max-width: none;
166 }
167 }
168}
169
170/* ============================================================================
171 Components Layer
172 ========================================================================= */
173
174@layer components {
175
176 /* App Root */
177 .app-root {
178 min-height: 100vh;
179 background-color: var(--color-gray-50);
180 }
181
182 /* -------------------------------------------------------------------------
183 Layout Components
184 ---------------------------------------------------------------------- */
185
186 .container {
187 width: 100%;
188 max-width: var(--container-max-width);
189 margin-left: auto;
190 margin-right: auto;
191 padding: var(--container-padding);
192 }
193
194 .container--lg {
195 max-width: var(--container-max-width-lg);
196 }
197
198 .feed {
199 display: flex;
200 flex-direction: column;
201 gap: var(--space-md);
202 }
203
204 .feed--lg {
205 gap: var(--space-lg);
206 }
207
208 .feed__empty {
209 padding: var(--space-xl);
210 text-align: center;
211 color: var(--color-gray-500);
212 }
213
214 .stack {
215 display: flex;
216 flex-direction: column;
217 }
218
219 .stack--xs { gap: var(--space-xs); }
220 .stack--sm { gap: var(--space-sm); }
221 .stack--md { gap: var(--space-md); }
222 .stack--lg { gap: var(--space-lg); }
223 .stack--xl { gap: var(--space-xl); }
224
225 /* -------------------------------------------------------------------------
226 Header Component
227 ---------------------------------------------------------------------- */
228
229 .header {
230 background-color: var(--color-white);
231 border-bottom: var(--border);
232 }
233
234 .header__content {
235 max-width: var(--container-max-width);
236 margin: 0 auto;
237 padding: var(--space-md) var(--container-padding);
238 display: flex;
239 align-items: center;
240 justify-content: space-between;
241 }
242
243 .header__brand {
244 font-size: var(--font-size-xl);
245 font-weight: var(--font-weight-bold);
246 color: var(--color-gray-900);
247 text-decoration: none;
248 margin-right: 0;
249 }
250
251 .header__brand:hover {
252 color: var(--color-gray-700);
253 }
254
255 .header__nav {
256 display: flex;
257 align-items: center;
258 gap: var(--space-md);
259 }
260
261 .header__user {
262 display: flex;
263 align-items: center;
264 gap: var(--space-sm);
265 text-decoration: none;
266 margin-right: 0;
267 }
268
269 .header__user:hover {
270 opacity: 0.8;
271 }
272
273 .header__handle {
274 font-size: var(--font-size-sm);
275 color: var(--color-gray-600);
276 }
277
278 /* -------------------------------------------------------------------------
279 Avatar Component
280 ---------------------------------------------------------------------- */
281
282 .avatar {
283 display: inline-flex;
284 align-items: center;
285 justify-content: center;
286 border-radius: var(--radius-full);
287 object-fit: cover;
288 font-weight: var(--font-weight-medium);
289 overflow: hidden;
290 flex-shrink: 0;
291 }
292
293 .avatar--sm {
294 width: var(--space-lg);
295 height: var(--space-lg);
296 font-size: var(--font-size-xs);
297 }
298
299 .avatar--md {
300 width: var(--space-xl);
301 height: var(--space-xl);
302 font-size: var(--font-size-sm);
303 }
304
305 .avatar--lg {
306 width: 3rem;
307 height: 3rem;
308 font-size: var(--font-size-base);
309 }
310
311 .avatar__fallback {
312 background-color: var(--color-gray-200);
313 color: var(--color-gray-600);
314 }
315
316 /* -------------------------------------------------------------------------
317 QuestionCard Component
318 ---------------------------------------------------------------------- */
319
320 .question-card {
321 background-color: var(--color-white);
322 border: var(--border);
323 border-radius: var(--radius-lg);
324 padding: var(--space-md);
325 }
326
327 .question-card__section {
328 display: flex;
329 flex-direction: column;
330 gap: var(--space-sm);
331 }
332
333 .question-card__section + .question-card__section {
334 margin-top: var(--space-md);
335 padding-top: var(--space-md);
336 border-top: var(--border);
337 }
338
339 .question-card__metadata {
340 display: flex;
341 align-items: center;
342 gap: var(--space-sm);
343 font-size: var(--font-size-sm);
344 color: var(--color-gray-500);
345 }
346
347 .question-card__metadata-name {
348 font-weight: var(--font-weight-medium);
349 color: var(--color-gray-700);
350 }
351
352 .question-card__metadata-link {
353 font-weight: var(--font-weight-medium);
354 color: var(--color-blue-600);
355 text-decoration: none;
356 margin-right: 0;
357 }
358
359 .question-card__metadata-link:hover {
360 text-decoration: underline;
361 }
362
363 .question-card__metadata-date {
364 color: var(--color-gray-400);
365 }
366
367 .question-card__content {
368 color: var(--color-gray-800);
369 padding-left: var(--space-xl);
370 }
371
372 /* Success variant for answered questions */
373 .question-card--success {
374 border-color: var(--color-green-300);
375 background-color: var(--color-green-50);
376 position: relative;
377 overflow: hidden;
378 }
379
380 .question-card__success-header {
381 display: flex;
382 align-items: center;
383 justify-content: space-between;
384 margin-bottom: var(--space-md);
385 }
386
387 .question-card__success-icon {
388 display: flex;
389 align-items: center;
390 gap: var(--space-sm);
391 color: var(--color-green-700);
392 font-weight: var(--font-weight-medium);
393 font-size: var(--font-size-sm);
394 }
395
396 .question-card__success-icon svg {
397 width: var(--space-lg);
398 height: var(--space-lg);
399 }
400
401 .question-card__delete-btn {
402 padding: 0;
403 background: none;
404 border: none;
405 color: var(--color-gray-600);
406 cursor: pointer;
407 display: flex;
408 align-items: center;
409 justify-content: center;
410 }
411
412 .question-card__delete-btn:hover {
413 color: var(--color-gray-800);
414 }
415
416 .question-card__delete-btn svg {
417 width: var(--space-lg);
418 height: var(--space-lg);
419 }
420
421 .question-card__progress-bar {
422 position: absolute;
423 bottom: 0;
424 left: 0;
425 right: 0;
426 height: var(--space-2);
427 background-color: var(--color-green-200);
428 }
429
430 .question-card__progress-fill {
431 height: 100%;
432 background-color: var(--color-green-500);
433 animation: shrink-width 5s linear forwards;
434 }
435
436 .question-card__answer-form {
437 display: flex;
438 flex-direction: column;
439 gap: var(--space-sm);
440 margin-top: var(--space-md);
441 padding-top: var(--space-md);
442 border-top: var(--border);
443 }
444
445 .question-card__answer-actions {
446 display: flex;
447 align-items: center;
448 justify-content: space-between;
449 }
450
451 .question-card__answer-meta {
452 font-size: var(--font-size-xs);
453 color: var(--color-gray-400);
454 }
455
456 /* -------------------------------------------------------------------------
457 Form Components
458 ---------------------------------------------------------------------- */
459
460 .form-group {
461 display: flex;
462 flex-direction: column;
463 gap: var(--space-xs);
464 }
465
466 .form-label {
467 display: block;
468 font-size: var(--font-size-sm);
469 font-weight: var(--font-weight-medium);
470 color: var(--color-gray-700);
471 }
472
473 .form-input,
474 .form-textarea {
475 width: 100%;
476 padding: var(--space-sm) var(--space-md);
477 border: var(--border);
478 border-color: var(--color-gray-300);
479 border-radius: var(--radius-md);
480 font-size: var(--font-size-sm);
481 line-height: var(--line-height-normal);
482 transition: all var(--transition-base);
483 font-family: var(--font-family-base);
484 }
485
486 .form-input:focus,
487 .form-textarea:focus {
488 outline: none;
489 border-color: var(--color-blue-500);
490 box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
491 }
492
493 .form-hint {
494 font-size: var(--font-size-sm);
495 color: var(--color-gray-500);
496 margin-top: var(--space-xs);
497 }
498
499 /* -------------------------------------------------------------------------
500 Button Component
501 ---------------------------------------------------------------------- */
502
503 .btn {
504 display: inline-flex;
505 align-items: center;
506 justify-content: center;
507 padding: var(--space-sm) var(--space-md);
508 font-size: var(--font-size-sm);
509 font-weight: var(--font-weight-medium);
510 border-radius: var(--radius-md);
511 border: none;
512 cursor: pointer;
513 transition: all var(--transition-base);
514 text-decoration: none;
515 margin-right: 0;
516 }
517
518 .btn:focus {
519 outline: none;
520 box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
521 }
522
523 .btn:disabled {
524 opacity: 0.5;
525 cursor: not-allowed;
526 }
527
528 /* Button Variants */
529 .btn--primary {
530 background-color: var(--color-blue-500);
531 color: var(--color-white);
532 }
533
534 .btn--primary:hover:not(:disabled) {
535 background-color: var(--color-blue-600);
536 }
537
538 .btn--secondary {
539 background-color: transparent;
540 color: var(--color-gray-500);
541 padding: var(--space-sm) var(--space-md);
542 }
543
544 .btn--secondary:hover:not(:disabled) {
545 color: var(--color-gray-700);
546 }
547
548 .btn--success {
549 background-color: var(--color-green-500);
550 color: var(--color-white);
551 }
552
553 .btn--success:hover:not(:disabled) {
554 background-color: var(--color-green-600);
555 }
556
557 .btn--danger {
558 background-color: var(--color-red-500);
559 color: var(--color-white);
560 }
561
562 .btn--danger:hover:not(:disabled) {
563 background-color: var(--color-red-600);
564 }
565
566 /* Button Sizes */
567 .btn--sm {
568 padding: var(--space-xs) var(--space-md);
569 font-size: var(--font-size-xs);
570 }
571
572 .btn--full {
573 width: 100%;
574 }
575
576 /* -------------------------------------------------------------------------
577 Card Component
578 ---------------------------------------------------------------------- */
579
580 .card {
581 background-color: var(--color-white);
582 border: var(--border);
583 border-radius: var(--radius-lg);
584 padding: var(--space-lg);
585 }
586
587 .card--center {
588 text-align: center;
589 }
590
591 /* -------------------------------------------------------------------------
592 Typography Components
593 ---------------------------------------------------------------------- */
594
595 .page-title {
596 font-size: var(--font-size-2xl);
597 font-weight: var(--font-weight-bold);
598 color: var(--color-gray-900);
599 margin-bottom: var(--space-xs);
600 }
601
602 .page-subtitle {
603 font-size: var(--font-size-sm);
604 color: var(--color-gray-600);
605 }
606
607 .section-title {
608 font-size: var(--font-size-lg);
609 font-weight: var(--font-weight-semibold);
610 color: var(--color-gray-700);
611 }
612
613 .text-link {
614 color: var(--color-blue-600);
615 text-decoration: none;
616 margin-right: 0;
617 }
618
619 .text-link:hover {
620 text-decoration: underline;
621 }
622
623 .text-link--back {
624 font-size: var(--font-size-sm);
625 }
626
627 .text-link--inline {
628 color: var(--color-blue-500);
629 }
630
631 .text-muted {
632 color: var(--color-gray-600);
633 }
634
635 .text-sm {
636 font-size: var(--font-size-sm);
637 }
638
639 .text-xs {
640 font-size: var(--font-size-xs);
641 }
642
643 .text-center {
644 text-align: center;
645 }
646
647 /* -------------------------------------------------------------------------
648 Status Badge Component
649 ---------------------------------------------------------------------- */
650
651 .status-badge {
652 display: inline-flex;
653 align-items: center;
654 gap: var(--space-sm);
655 padding: var(--space-xs) var(--space-md);
656 border-radius: var(--radius-full);
657 font-size: var(--font-size-sm);
658 font-weight: var(--font-weight-medium);
659 }
660
661 .status-badge--open,
662 .status-badge--success {
663 background-color: var(--color-green-100);
664 color: var(--color-green-800);
665 }
666
667 .status-badge--closed {
668 background-color: var(--color-gray-100);
669 color: var(--color-gray-800);
670 }
671
672 .status-badge--pending,
673 .status-badge--warning {
674 background-color: var(--color-yellow-100);
675 color: var(--color-yellow-800);
676 }
677
678 /* -------------------------------------------------------------------------
679 Thread/AMA Components
680 ---------------------------------------------------------------------- */
681
682 .ama-header {
683 display: flex;
684 align-items: center;
685 justify-content: space-between;
686 margin-bottom: var(--space-md);
687 }
688
689 .ama-actions {
690 display: flex;
691 gap: var(--space-sm);
692 }
693
694 .thread-item {
695 background-color: var(--color-white);
696 border: var(--border);
697 border-radius: var(--radius-lg);
698 padding: var(--space-md);
699 }
700
701 .thread-item__header {
702 display: flex;
703 align-items: start;
704 justify-content: space-between;
705 margin-bottom: var(--space-sm);
706 }
707
708 .thread-item__content {
709 flex: 1;
710 }
711
712 .thread-item__meta {
713 display: flex;
714 flex-direction: column;
715 gap: var(--space-xs);
716 }
717
718 .thread-item__asker {
719 font-size: var(--font-size-sm);
720 color: var(--color-gray-600);
721 }
722
723 .thread-item__date {
724 font-size: var(--font-size-sm);
725 color: var(--color-gray-500);
726 }
727
728 .thread-item__status-badge {
729 padding: var(--space-xs) var(--space-sm);
730 border-radius: var(--radius-sm);
731 font-size: var(--font-size-xs);
732 font-weight: var(--font-weight-medium);
733 }
734
735 /* -------------------------------------------------------------------------
736 Utility Classes
737 ---------------------------------------------------------------------- */
738
739 .error-text {
740 color: var(--color-red-500);
741 font-size: var(--font-size-sm);
742 }
743
744 .flex {
745 display: flex;
746 }
747
748 .flex-col {
749 flex-direction: column;
750 }
751
752 .items-center {
753 align-items: center;
754 }
755
756 .items-start {
757 align-items: flex-start;
758 }
759
760 .justify-between {
761 justify-content: space-between;
762 }
763
764 .gap-2 {
765 gap: var(--space-sm);
766 }
767
768 .gap-3 {
769 gap: var(--space-md);
770 }
771
772 .gap-4 {
773 gap: var(--space-lg);
774 }
775
776 .mb-4 {
777 margin-bottom: var(--space-md);
778 }
779
780 .mt-1 {
781 margin-top: var(--space-xs);
782 }
783
784 .block {
785 display: block;
786 }
787
788 .inline-block {
789 display: inline-block;
790 }
791}
792
793/* ============================================================================
794 Animations
795 ========================================================================= */
796
797@keyframes shrink-width {
798 from {
799 width: 100%;
800 }
801 to {
802 width: 0%;
803 }
804}