a personal site
1/*============================*/
2/* josh comeau css reset */
3/* https://www.joshwcomeau.com/css/custom-css-reset/*/
4/*============================*/
5
6*,
7*::before,
8*::after {
9 box-sizing: border-box;
10}
11
12* {
13 margin: 0;
14}
15
16@media (prefers-reduced-motion: no-preference) {
17 html {
18 interpolate-size: allow-keywords;
19 }
20}
21
22body {
23 line-height: 1.5;
24 -webkit-font-smoothing: antialiased;
25}
26
27img,
28picture,
29video,
30canvas,
31svg {
32 display: block;
33 max-width: 100%;
34}
35
36input,
37button,
38textarea,
39select {
40 font: inherit;
41}
42
43p,
44h1,
45h2,
46h3,
47h4,
48h5,
49h6 {
50 overflow-wrap: break-word;
51}
52
53p {
54 text-wrap: pretty;
55}
56h1,
57h2,
58h3,
59h4,
60h5,
61h6 {
62 text-wrap: balance;
63}
64
65#root,
66#__next {
67 isolation: isolate;
68}
69
70/*============================*/
71/* geist mono font declaration */
72/* variable font - modern browsers*/
73/*============================*/
74
75@font-face {
76 font-family: "Geist Mono";
77 src: url("./src/assets/fonts/geistmono/GeistMono[wght].woff2")
78 format("woff2-variations");
79 font-weight: 100 900;
80 font-style: normal;
81 font-display: swap;
82 font-feature-settings:
83 "liga" 1,
84 "calt" 1;
85}
86
87@font-face {
88 font-family: "Geist Mono";
89 src: url("./src/assets/fonts/geistmono/GeistMono-Italic[wght].woff2")
90 format("woff2-variations");
91 font-weight: 100 900;
92 font-style: italic;
93 font-display: swap;
94 font-feature-settings:
95 "liga" 1,
96 "calt" 1;
97}
98
99/* Static font fallbacks */
100@font-face {
101 font-family: "Geist Mono";
102 src: url("./src/assets/fonts/geistmono/GeistMono-Regular.woff2") format("woff2");
103 font-weight: 400;
104 font-style: normal;
105 font-display: swap;
106 font-feature-settings:
107 "liga" 1,
108 "calt" 1;
109}
110
111@font-face {
112 font-family: "Geist Mono";
113 src: url("./src/assets/fonts/geistmono/GeistMono-Bold.woff2") format("woff2");
114 font-weight: 700;
115 font-style: normal;
116 font-display: swap;
117 font-feature-settings:
118 "liga" 1,
119 "calt" 1;
120}
121
122@font-face {
123 font-family: "Geist Mono";
124 src: url("./src/assets/fonts/geistmono/GeistMono-Italic.woff2") format("woff2");
125 font-weight: 400;
126 font-style: italic;
127 font-display: swap;
128 font-feature-settings:
129 "liga" 1,
130 "calt" 1;
131}
132
133@font-face {
134 font-family: "Geist Mono";
135 src: url("./src/assets/fonts/geistmono/GeistMono-BoldItalic.woff2") format("woff2");
136 font-weight: 700;
137 font-style: italic;
138 font-display: swap;
139 font-feature-settings:
140 "liga" 1,
141 "calt" 1;
142}
143
144/*============================*/
145/* global element styles */
146/* authored css by me*/
147/*============================*/
148html {
149 height: 100%;
150
151 --background-dark: #0e140f;
152 --borders: #273028;
153 --text-headings: #f3f4e2;
154 --text-body: #e0e2ce;
155 --text-secondary: #a8ad98;
156 --accent: #cddc39;
157 --accent-muted: #354037;
158
159 /*test out yellow accent?*/
160 /*--accent: #ffb703;*/
161}
162
163body {
164 max-width: 65ch;
165 margin: 0 auto;
166 padding: min(3rem, 8vw) min(2rem, 4vw);
167 font-family:
168 "Geist Mono", "SF Mono", Monaco, "Cascadia Code", "Roboto Mono",
169 Consolas, "Courier New", monospace;
170 color: var(--text-body);
171 background-color: var(--background-dark);
172 line-height: 1.6;
173}
174
175header {
176 padding: 0.5rem;
177 font-size: 0.9rem;
178 margin-bottom: .8rem;
179}
180
181main {
182 padding: 0.5rem;
183 font-size: 0.9rem;
184}
185
186footer {
187 padding: 0.5rem;
188 font-size: 0.9rem;
189}
190
191nav {
192 display: flex;
193 flex-direction: row;
194}
195
196nav a {
197 margin-right: 1rem;
198}
199
200nav p {
201 margin: 0rem .5rem 0rem 0rem;
202}
203
204h1 {
205 font-size: 1.6rem;
206 color: var(--accent);
207 margin: 0 0 0.3rem 0;
208 font-weight: 700;
209 line-height: 1.2;
210}
211
212h2 {
213 font-size: 1.25rem;
214 color: var(--text-headings);
215 margin: 2.5rem 0 0.75rem 0;
216 font-weight: 600;
217 padding-top: 1.5rem;
218 border-top: 1px solid var(--borders);
219}
220
221h3 {
222 font-size: 1.05rem;
223 color: var(--accent);
224 margin: 1.3rem 0 0.75rem 0;
225 font-weight: 600;
226}
227
228p {
229 margin: 0 0 1rem 0;
230 color: var(--text-body);
231}
232
233a {
234 color: var(--accent);
235 text-decoration: none;
236 border-bottom: 1px solid var(--accent);
237 transition: background-color 0.15s ease, color 0.15s ease;
238}
239
240a:hover {
241 color: #fff;
242 background-color: var(--accent);
243 border-bottom-color: var(--accent);
244}
245
246blockquote {
247 margin: 1.75rem 0;
248 padding-left: 1.2rem;
249 border-left: 3px solid var(--accent);
250 color: var(--text-secondary);
251 font-style: italic;
252}
253
254img {
255 width: 100%;
256 height: auto;
257 border: 1px solid var(--borders);
258 border-radius: 2px;
259}
260
261figcaption {
262 font-size: 0.8rem;
263 color: var(--text-secondary);
264 margin-top: 0.6rem;
265}
266
267code {
268 font-family:
269 "Geist Mono", "SF Mono", Monaco, "Cascadia Code", "Roboto Mono",
270 Consolas, "Courier New", monospace;
271 font-size: 0.88rem;
272 color: var(--text-headings);
273 background: var(--accent-muted);
274 padding: 0.2rem 0.4rem;
275 border-radius: 4px;
276 border: 1px solid var(--borders);
277 box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
278}
279
280pre {
281 margin: 2rem 0;
282 padding: 1.25rem;
283 background: var(--accent-muted);
284 border: 1px solid var(--borders);
285 border-radius: 6px;
286 overflow-x: auto;
287 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
288 position: relative;
289}
290
291pre::before {
292 content: '';
293 position: absolute;
294 top: 0;
295 left: 0;
296 right: 0;
297 height: 3px;
298 border-radius: 6px 6px 0 0;
299}
300
301pre code {
302 background: none;
303 padding: 0;
304 display: block;
305 color: var(--text-body);
306 font-size: 0.85rem;
307 border: none;
308 box-shadow: none;
309 line-height: 1.5;
310}
311
312figure {
313 margin: 1.5rem 0;
314}
315
316ul, ol {
317 margin: 0 0 1.2rem 1.5rem;
318 padding: 0;
319}
320
321li {
322 margin: 0.5rem 0;
323 display: list-item;
324}
325
326hr {
327 border: 0;
328 height: 1px;
329 background: var(--borders);
330 margin-bottom: 0.7rem;
331 width: 13rem;
332}
333
334/*not ready yet*/
335s a {
336 color: var(--accent-muted);
337 text-decoration: none;
338 border-bottom: 1px solid var(--accent-muted);
339 transition: background-color 0.15s ease, color 0.15s ease;
340}
341
342s a:hover {
343 color: #fff;
344 background-color: var(--accent-muted);
345 border-bottom-color: var(--accent-muted);
346}
347
348
349/*============================*/
350/* targeted class styles */
351/* authored css by me*/
352/*============================*/
353
354.title {
355 margin: 0 0 0.3rem 0;
356 font-weight: 700;
357 line-height: 1.6;
358 color: var(--text-body);
359 font-size: 2rem;
360}
361
362.meta {
363 font-size: 0.8rem;
364 color: var(--text-secondary);
365 margin-top: .5rem;
366 margin-bottom: 2.5rem;
367}
368
369.nav-back {
370 font-size: 0.85rem;
371 color: var(--text-secondary);
372 margin-bottom: 1.5rem;
373 display: block;
374}
375
376.nav-back a {
377 color: var(--text-secondary);
378 border-bottom: 1px solid var(--accent-muted);
379}
380
381.nav-back a:hover {
382 color: var(--accent-muted);
383 background: none;
384}
385
386/*============================*/
387/* responsive things */
388/* authored with help from ai*/
389/*============================*/
390
391/* Mobile responsiveness */
392@media (max-width: 480px) {
393 body {
394 padding: min(2rem, 6vw) min(1.5rem, 4vw);
395 }
396
397 h1 {
398 font-size: 1.4rem;
399 }
400
401 h2 {
402 font-size: 1.15rem;
403 margin-top: 2rem;
404 padding-top: 1rem;
405 }
406
407 h3 {
408 font-size: 1rem;
409 margin-top: 1.5rem;
410 }
411
412 nav {
413 flex-wrap: wrap;
414 gap: 0.5rem;
415 }
416
417 nav a {
418 margin-right: 0.5rem;
419 }
420
421 pre {
422 padding: 1rem;
423 margin: 1.5rem -0.5rem;
424 border-radius: 4px;
425 }
426
427 pre code {
428 font-size: 0.8rem;
429 }
430
431 hr {
432 width: 100%;
433 max-width: 13rem;
434 }
435}
436
437@media (max-width: 768px) {
438 body {
439 padding: min(2.5rem, 7vw) min(1.75rem, 4vw);
440 }
441
442 h1 {
443 font-size: 1.5rem;
444 }
445}
446
447/* Focus visible for keyboard navigation */
448a:focus-visible,
449button:focus-visible {
450 outline: 2px solid var(--accent);
451 outline-offset: 2px;
452 border-radius: 2px;
453}
454
455/* Remove default focus for mouse users */
456a:focus:not(:focus-visible),
457button:focus:not(:focus-visible) {
458 outline: none;
459}
460
461/* High contrast mode support */
462@media (prefers-contrast: high) {
463 html {
464 --text-body: #ffffff;
465 --text-secondary: #cccccc;
466 --text-headings: #ffffff;
467 --accent: #ffff00;
468 --borders: #ffffff;
469 --accent-muted: #444444;
470 }
471
472 a {
473 text-decoration: underline;
474 }
475
476 code {
477 border: 2px solid var(--borders);
478 }
479}
480
481/* Reduced motion preferences */
482@media (prefers-reduced-motion: reduce) {
483 *,
484 *::before,
485 *::after {
486 animation-duration: 0.01ms !important;
487 animation-iteration-count: 1 !important;
488 transition-duration: 0.01ms !important;
489 scroll-behavior: auto !important;
490 }
491}
492
493@media (prefers-color-scheme: light) {
494 /* site is dark-only .. for now.. */
495}
496
497/* Print styles */
498@media print {
499 body {
500 background: white;
501 color: black;
502 max-width: none;
503 padding: 1rem;
504 font-size: 11pt;
505 line-height: 1.4;
506 }
507
508 header,
509 main,
510 footer {
511 padding: 0.25rem 0;
512 }
513
514 h1 {
515 font-size: 1.4rem;
516 color: black;
517 page-break-after: avoid;
518 }
519
520 h2, h3 {
521 color: black;
522 page-break-after: avoid;
523 border: none;
524 }
525
526 p, li {
527 orphans: 3;
528 widows: 3;
529 }
530
531 a {
532 color: black;
533 text-decoration: underline;
534 background: none;
535 border: none;
536 }
537
538 a[href^="mailto:"]:after {
539 content: " (" attr(href) ")";
540 font-size: 0.75em;
541 }
542
543 a[href^="http"]:after {
544 content: " (" attr(href) ")";
545 font-size: 0.75em;
546 }
547
548 nav {
549 display: none;
550 }
551
552 pre, code {
553 background: #f5f5f5;
554 border: 1px solid #ccc;
555 }
556
557 blockquote {
558 border-left-color: black;
559 }
560
561 img {
562 border: 1px solid black;
563 page-break-inside: avoid;
564 }
565
566 hr {
567 background: black;
568 border-top: 1px solid black;
569 }
570
571 .meta {
572 color: #666;
573 }
574
575 .nav-back {
576 display: none;
577 }
578}
579
580
581/*============================*/
582/* project page styles */
583/* ai assisted stlying: hover, gradient, transition, glow)*/
584/*============================*/
585.project-card {
586 all:unset;
587
588 display: flex;
589 flex-direction: row;
590
591 margin-bottom: 1rem;
592 border-radius: 16px;
593 padding: 1.25rem;
594
595 border: 1px solid var(--borders);
596
597
598 background: var(--background-dark);
599 box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
600 text-decoration: none;
601 color: inherit;
602
603 /* for overlay + smoothness */
604 position: relative;
605 overflow: hidden;
606 transform: translateZ(0);
607 transform-origin: center;
608
609 /* transitions */
610 transition:
611 transform 220ms ease,
612 box-shadow 220ms ease;
613 will-change: transform;
614}
615
616.project-card h1 {
617 padding: 0rem;
618 margin: 0rem;
619}
620
621.project-card p {
622 padding:0rem;
623 margin: 0rem;
624}
625
626.project-card:hover {
627 background-color:var(--background-dark);
628 border-bottom: 1px solid var(--borders);
629 text-decoration: none;
630
631}
632
633.project-card-left {
634 display: flex;
635 flex-direction: column;
636 justify-content: space-between;
637 margin-right: 1rem;
638}
639.project-card-right {
640 padding: 0rem;
641 margin: 0rem;
642}
643
644/* gradient overlay (so text doesn’t get re-painted weirdly) */
645.project-card::before {
646 content: "";
647 position: absolute;
648 inset: 0;
649 border-radius: inherit;
650
651 /* subtle green-tinted radial glow */
652 background: radial-gradient(
653 ellipse at top left,
654 rgba(205, 220, 57, 0.08),
655 rgba(53, 64, 55, 0.04),
656 transparent 70%
657 );
658
659 opacity: 0;
660 transition: opacity 220ms ease;
661 pointer-events: none;
662}
663
664.project-card:hover {
665 transform: scale(1.05);
666 box-shadow: 0 20px 50px rgba(14, 20, 15, 0.6),
667 0 0 0 1px rgba(205, 220, 57, 0.15);
668
669}
670
671.project-card:hover::before {
672 opacity: 1;
673}
674
675/* keep actual content above overlay */
676.project-card > * {
677 position: relative;
678 z-index: 1;
679}
680
681/* optional: small image polish */
682.project-card-img {
683 width: 30rem;
684 height: auto;
685 display: block;
686 border-radius: 12px;
687 border: 1px solid #3a4a3d;
688 box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5),
689 0 2px 8px rgba(0, 0, 0, 0.3),
690 0 0 0 1px rgba(205, 220, 57, 0.1);
691 transition: transform 220ms ease, box-shadow 220ms ease;
692}
693
694.project-type {
695 font-size: 0.7rem;
696 letter-spacing: 0.1em;
697 color: var(--text-secondary);
698}
699
700.project-card:hover .project-type {
701 color: var(--accent);
702}
703
704.project-card:hover .project-card-img {
705 transform: scale(1.02);
706 box-shadow: 0 12px 32px rgba(0, 0, 0, 0.6),
707 0 4px 12px rgba(0, 0, 0, 0.4),
708 0 0 0 1px rgba(205, 220, 57, 0.25);
709}
710
711/* accessibility: keyboard focus should get the same treatment */
712.project-card:focus-visible {
713 outline: 2px solid currentColor;
714 outline-offset: 4px;
715 transform: scale(1.05);
716}
717
718@media (prefers-reduced-motion: reduce) {
719 .project-card,
720 .project-card::before,
721 .project-card-img {
722 transition: none;
723 }
724}
725
726/*============================*/
727/* project banner styles */
728/* svg html generated entirely by ai*/
729/*all other styles by me*/
730/*============================*/
731.project-banner {
732 position: relative;
733 border: 1px solid var(--text-body);
734 border-radius: 0.75rem;
735 overflow: hidden;
736 background: linear-gradient(135deg, #1a2e1a 0%, #0f1e0f 50%, #1a3520 100%);
737 padding: 2rem;
738 height: 20rem;
739 box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
740}
741
742.project-banner-background {
743 position: absolute;
744 inset: 0;
745}
746
747.project-banner-img {
748 position: relative;
749 display: block;
750 width: 93%;
751 height: auto;
752 margin: 2rem auto 0;
753 border: 3px solid rgba(255, 255, 255, 0.25);
754 border-radius: 0.5rem;
755}
756
757.project-header {
758 display: flex;
759 flex-direction: row;
760 justify-content: space-between;
761 padding-bottom: 1rem;
762 border-bottom: 1px solid var(--borders);
763}
764
765.project-header-title {
766 all:unset;
767 font-size: 2rem;
768 font-weight: 700;
769 color: var(--accent);
770 margin-right: 5rem;
771}
772
773.project-header-desc {
774 font-weight: 300;
775 align-self: center;
776 color: var(--text-secondary)
777}
778
779.project-details {
780 display: flex;
781 flex-direction: row;
782 margin-top: 1rem;
783}
784
785.project-details-left {
786 display: flex;
787 flex-direction: column;
788 padding-right: 1rem;
789 min-width: 12rem;
790}
791
792.project-details-right {
793 display: flex;
794 flex-direction: column;
795 padding-left: 1rem;
796}
797
798.project-details-meta-header {
799 color: var(--text-headings);
800 font-weight: 700;
801}
802
803.project-details-meta-bullet {
804 color: var(--text-body);
805 font-weight: 300;
806}
807
808.project-details-source {
809 /*border: 1px solid red;*/
810 display: inline;
811 width: max-content;
812
813}
814
815
816
817/*============================*/
818/* blog home page styles */
819/*============================*/
820/*
821.blog-home {
822 max-width: 65ch;
823 margin: 0 auto;
824 padding: 0.5rem;
825}
826
827.blog-home h1 {
828 font-size: 1.2rem;
829 color: var(--text-headings);
830 margin: 0 0 2rem 0;
831 font-weight: 700;
832}
833
834.blog-home .post-list {
835 list-style: none;
836 margin: 0;
837 padding: 0;
838}
839
840.blog-home .post-item {
841 display: flex;
842 justify-content: space-between;
843 align-items: baseline;
844 padding: 0.75rem 0;
845 border-bottom: 1px solid var(--borders);
846 gap: 1rem;
847}
848
849.blog-home .post-item:hover {
850 background: var(--accent-muted);
851}
852
853.blog-home .post-title {
854 flex: 1;
855 color: var(--text-body);
856 text-decoration: none;
857}
858
859.blog-home .post-title:hover {
860 color: var(--accent);
861}
862
863.blog-home .post-date {
864 color: var(--text-secondary);
865 font-size: 0.85rem;
866 white-space: nowrap;
867}*/