a personal site
at main 867 lines 16 kB view raw
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}*/