Our Personal Data Server from scratch!
at fix/code-quality-in-general 895 lines 16 kB view raw
1@import "./tokens.css"; 2 3@property --accent { 4 syntax: "<color>"; 5 inherits: true; 6 initial-value: #1a1d1d; 7} 8 9@property --secondary { 10 syntax: "<color>"; 11 inherits: true; 12 initial-value: #1a1d1d; 13} 14 15*, 16*::before, 17*::after { 18 box-sizing: border-box; 19} 20 21body { 22 margin: 0; 23 font-family: 24 "Space Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; 25 font-size: var(--text-base); 26 line-height: var(--leading-normal); 27 color: var(--text-primary); 28 background: var(--bg-primary); 29 -webkit-font-smoothing: antialiased; 30 -moz-osx-font-smoothing: grayscale; 31 transition: background-color 0.3s ease; 32 overflow-wrap: anywhere; 33 word-break: break-word; 34} 35 36h1, h2, h3, h4, h5, h6 { 37 margin: 0; 38 line-height: var(--leading-tight); 39} 40 41h1 { 42 font-size: var(--text-2xl); 43} 44h2 { 45 font-size: var(--text-xl); 46} 47h3 { 48 font-size: var(--text-lg); 49} 50h4 { 51 font-size: var(--text-base); 52} 53 54p { 55 margin: 0; 56} 57 58a { 59 color: var(--accent); 60 text-decoration: underline; 61 text-underline-offset: 2px; 62} 63 64a:hover { 65 color: var(--accent-hover); 66} 67 68::selection { 69 background: var(--secondary-muted); 70} 71 72input, 73select, 74textarea { 75 font-family: inherit; 76 font-size: var(--text-base); 77 line-height: var(--leading-normal); 78 padding: var(--space-4); 79 border: 1px solid var(--border-dark); 80 border-radius: var(--radius-md); 81 background: var(--bg-input); 82 color: var(--text-primary); 83 transition: 84 border-color var(--transition-normal), 85 box-shadow var(--transition-normal); 86 width: 100%; 87} 88 89input:focus, 90select:focus, 91textarea:focus { 92 outline: none; 93 border-color: var(--accent); 94 box-shadow: var(--shadow-focus); 95} 96 97input:disabled, 98select:disabled, 99textarea:disabled { 100 background: var(--bg-input-disabled); 101 color: var(--text-muted); 102 cursor: not-allowed; 103} 104 105input::placeholder, 106textarea::placeholder { 107 color: var(--text-muted); 108} 109 110select { 111 cursor: pointer; 112 appearance: none; 113 background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23666' d='M6 8L1 3h10z'/%3E%3C/svg%3E"); 114 background-repeat: no-repeat; 115 background-position: right var(--space-4) center; 116 padding-right: var(--space-7); 117} 118 119button { 120 font-family: inherit; 121 font-size: var(--text-base); 122 font-weight: var(--font-medium); 123 line-height: var(--leading-normal); 124 padding: var(--space-4) var(--space-6); 125 border: none; 126 border-radius: var(--radius-md); 127 cursor: pointer; 128 transition: 129 background var(--transition-normal), 130 border-color var(--transition-normal), 131 opacity var(--transition-normal); 132 background: var(--accent); 133 color: var(--text-inverse); 134} 135 136button:hover:not(:disabled) { 137 background: var(--accent-hover); 138} 139 140button:disabled { 141 opacity: 0.6; 142 cursor: not-allowed; 143} 144 145button.secondary { 146 background: transparent; 147 color: var(--accent); 148 border: 1px solid var(--accent); 149} 150 151button.secondary:hover:not(:disabled) { 152 background: var(--accent); 153 color: var(--text-inverse); 154} 155 156button.tertiary { 157 background: transparent; 158 color: var(--text-secondary); 159 padding: var(--space-3) var(--space-4); 160} 161 162button.tertiary:hover:not(:disabled) { 163 color: var(--text-primary); 164 background: var(--bg-tertiary); 165} 166 167button.danger { 168 background: var(--error-text); 169} 170 171button.danger:hover:not(:disabled) { 172 background: #900; 173} 174 175button.danger-outline { 176 background: transparent; 177 border: 1px solid var(--error-border); 178 color: var(--error-text); 179} 180 181button.danger-outline:hover:not(:disabled) { 182 background: var(--error-bg); 183 border-color: var(--error-text); 184} 185 186button.ghost { 187 background: transparent; 188 color: var(--text-secondary); 189 border: 1px solid var(--border-dark); 190} 191 192button.ghost:hover:not(:disabled) { 193 background: var(--bg-secondary); 194 color: var(--text-primary); 195} 196 197button.link { 198 background: none; 199 border: none; 200 color: var(--accent); 201 padding: var(--space-2); 202 font-size: var(--text-sm); 203 font-weight: var(--font-normal); 204} 205 206button.link:hover:not(:disabled) { 207 background: none; 208 text-decoration: underline; 209} 210 211button.sm { 212 padding: var(--space-2) var(--space-3); 213 font-size: var(--text-xs); 214} 215 216button.icon { 217 background: none; 218 border: none; 219 color: var(--text-secondary); 220 padding: var(--space-1); 221 font-size: var(--text-base); 222} 223 224button.icon:hover:not(:disabled) { 225 background: none; 226 color: var(--text-primary); 227} 228 229label { 230 display: block; 231 font-size: var(--text-sm); 232 font-weight: var(--font-medium); 233 color: var(--text-primary); 234 margin-bottom: var(--space-2); 235} 236 237fieldset { 238 border: none; 239 border-left: 3px solid var(--accent); 240 border-radius: var(--radius-lg); 241 padding: var(--space-5); 242 padding-left: var(--space-6); 243 margin: 0; 244 background: var(--bg-secondary); 245} 246 247fieldset legend { 248 font-size: var(--text-xs); 249 font-weight: var(--font-semibold); 250 text-transform: uppercase; 251 letter-spacing: 0.05em; 252 padding: 0; 253 margin-left: calc(-1 * var(--space-1)); 254 margin-bottom: var(--space-3); 255 color: var(--text-secondary); 256 float: left; 257 width: 100%; 258} 259 260fieldset legend + * { 261 clear: both; 262} 263 264code { 265 font-family: var(--font-mono); 266 font-size: 0.9em; 267 background: var(--bg-tertiary); 268 padding: var(--space-1) var(--space-2); 269 border-radius: var(--radius-sm); 270} 271 272pre { 273 font-family: var(--font-mono); 274 font-size: var(--text-sm); 275 background: var(--bg-tertiary); 276 padding: var(--space-4); 277 border-radius: var(--radius-md); 278 overflow-x: auto; 279 margin: 0; 280} 281 282hr { 283 border: none; 284 border-top: 1px solid var(--border-color); 285 margin: var(--space-6) 0; 286} 287 288.field { 289 display: flex; 290 flex-direction: column; 291 gap: var(--space-2); 292} 293 294.field + .field { 295 margin-top: var(--space-5); 296} 297 298.form-row .field + .field { 299 margin-top: 0; 300} 301 302.hint { 303 font-size: var(--text-xs); 304 color: var(--text-secondary); 305 margin-top: var(--space-1); 306} 307 308.hint.warning { 309 color: var(--warning-text); 310} 311 312.hint.error { 313 color: var(--error-text); 314} 315 316.hint.success { 317 color: var(--success-text); 318} 319 320.message { 321 padding: var(--space-4); 322 border-radius: var(--radius-md); 323 font-size: var(--text-sm); 324} 325 326.message.success { 327 background: var(--success-bg); 328 border: 1px solid var(--success-border); 329 color: var(--success-text); 330} 331 332.message.error { 333 background: var(--error-bg); 334 border: 1px solid var(--error-border); 335 color: var(--error-text); 336} 337 338.message.warning { 339 background: var(--warning-bg); 340 border: 1px solid var(--warning-border); 341 color: var(--warning-text); 342} 343 344.badge { 345 display: inline-block; 346 padding: var(--space-1) var(--space-3); 347 border-radius: var(--radius-md); 348 font-size: var(--text-xs); 349 font-weight: var(--font-medium); 350} 351 352.badge.success { 353 background: var(--success-bg); 354 color: var(--success-text); 355} 356 357.badge.warning { 358 background: var(--warning-bg); 359 color: var(--warning-text); 360} 361 362.badge.error { 363 background: var(--error-bg); 364 color: var(--error-text); 365} 366 367.badge.accent { 368 background: var(--accent); 369 color: var(--text-inverse); 370} 371 372.card { 373 background: var(--bg-card); 374 border: 1px solid var(--border-color); 375 border-radius: var(--radius-xl); 376 padding: var(--space-6); 377 overflow: hidden; 378 min-width: 0; 379} 380 381.section { 382 background: var(--bg-secondary); 383 border-radius: var(--radius-xl); 384 padding: var(--space-6); 385 overflow: hidden; 386 min-width: 0; 387} 388 389.section + .section { 390 margin-top: var(--space-6); 391} 392 393.page { 394 max-width: var(--width-lg); 395 margin: 0 auto; 396 padding: var(--space-7); 397} 398 399.page-sm { 400 max-width: var(--width-md); 401 margin: 0 auto; 402 padding: var(--space-7); 403} 404 405.page-lg { 406 max-width: var(--width-xl); 407 margin: 0 auto; 408 padding: var(--space-7); 409} 410 411.page-header { 412 margin-bottom: var(--space-6); 413} 414 415.page-header h1 { 416 margin: 0 0 var(--space-3) 0; 417} 418 419.page-header .subtitle { 420 color: var(--text-secondary); 421 margin: 0; 422} 423 424.loading { 425 display: flex; 426 flex-direction: column; 427 align-items: center; 428 gap: var(--space-4); 429 padding: var(--space-8); 430} 431 432.loading p { 433 color: var(--text-secondary); 434 margin: 0; 435} 436 437.back-link { 438 display: inline-block; 439 color: var(--text-secondary); 440 font-size: var(--text-sm); 441 margin-bottom: var(--space-3); 442 text-decoration: none; 443} 444 445.back-link:hover { 446 color: var(--accent); 447 text-decoration: none; 448} 449 450.text-muted { 451 color: var(--text-muted); 452} 453 454.text-secondary { 455 color: var(--text-secondary); 456} 457 458.text-sm { 459 font-size: var(--text-sm); 460} 461 462.text-xs { 463 font-size: var(--text-xs); 464} 465 466.text-center { 467 text-align: center; 468} 469 470.mono { 471 font-family: var(--font-mono); 472} 473 474.mt-4 { 475 margin-top: var(--space-4); 476} 477.mt-5 { 478 margin-top: var(--space-5); 479} 480.mt-6 { 481 margin-top: var(--space-6); 482} 483.mb-4 { 484 margin-bottom: var(--space-4); 485} 486.mb-5 { 487 margin-bottom: var(--space-5); 488} 489.mb-6 { 490 margin-bottom: var(--space-6); 491} 492 493.split-layout { 494 display: grid; 495 grid-template-columns: 1fr; 496 gap: var(--space-6); 497} 498 499@media (min-width: 800px) { 500 .split-layout { 501 grid-template-columns: 1fr 1fr; 502 align-items: start; 503 } 504 .split-layout.sidebar-right { 505 grid-template-columns: 1.5fr 1fr; 506 } 507 .split-layout.sidebar-left { 508 grid-template-columns: 1fr 1.5fr; 509 } 510} 511 512.split-layout > * { 513 min-width: 0; 514} 515 516.form-row { 517 display: grid; 518 grid-template-columns: 1fr; 519 gap: var(--space-4); 520} 521 522@media (min-width: 600px) { 523 .form-row { 524 grid-template-columns: repeat(2, 1fr); 525 } 526 .form-row.thirds { 527 grid-template-columns: repeat(3, 1fr); 528 } 529} 530 531.full-width { 532 grid-column: 1 / -1; 533} 534 535.info-panel { 536 background: var(--bg-secondary); 537 border-radius: var(--radius-xl); 538 padding: var(--space-6); 539 height: fit-content; 540 overflow: hidden; 541 min-width: 0; 542} 543 544.info-panel h3 { 545 margin: 0 0 var(--space-3) 0; 546 font-size: var(--text-base); 547 font-weight: var(--font-semibold); 548} 549 550.info-panel p { 551 margin: 0 0 var(--space-4) 0; 552 font-size: var(--text-sm); 553 color: var(--text-secondary); 554} 555 556.info-panel p:last-child { 557 margin-bottom: 0; 558} 559 560.spinner { 561 width: 40px; 562 height: 40px; 563 border: 3px solid var(--border-color); 564 border-top-color: var(--accent); 565 border-radius: 50%; 566 animation: spin 1s linear infinite; 567} 568 569.spinner.sm { 570 width: 20px; 571 height: 20px; 572 border-width: 2px; 573} 574 575.spinner.md { 576 width: 32px; 577 height: 32px; 578} 579 580.spinner.lg { 581 width: 60px; 582 height: 60px; 583 border-width: 4px; 584} 585 586@keyframes spin { 587 to { 588 transform: rotate(360deg); 589 } 590} 591 592.skeleton { 593 background: var(--bg-secondary); 594 border-radius: var(--radius-md); 595 animation: skeleton-pulse 1.5s ease-in-out infinite; 596} 597 598.skeleton-card { 599 height: 100px; 600 background: var(--bg-secondary); 601 border: 1px solid var(--border-color); 602 border-radius: var(--radius-xl); 603 animation: skeleton-pulse 1.5s ease-in-out infinite; 604} 605 606.skeleton-line { 607 height: var(--space-4); 608 background: var(--bg-secondary); 609 border-radius: var(--radius-sm); 610 animation: skeleton-pulse 1.5s ease-in-out infinite; 611} 612 613@keyframes skeleton-pulse { 614 0%, 100% { opacity: 1; } 615 50% { opacity: 0.5; } 616} 617 618.section-hint { 619 font-size: var(--text-sm); 620 color: var(--text-secondary); 621 margin: 0 0 var(--space-5) 0; 622} 623 624.radio-group { 625 display: flex; 626 flex-direction: column; 627 gap: var(--space-4); 628} 629 630.radio-label { 631 display: flex; 632 align-items: flex-start; 633 gap: var(--space-3); 634 cursor: pointer; 635 font-size: var(--text-base); 636 font-weight: var(--font-normal); 637 margin-bottom: 0; 638} 639 640.radio-label input[type="radio"] { 641 margin-top: var(--space-1); 642 width: auto; 643} 644 645.radio-content { 646 display: flex; 647 flex-direction: column; 648 gap: var(--space-1); 649} 650 651.radio-hint { 652 font-size: var(--text-xs); 653 color: var(--text-secondary); 654} 655 656.radio-label.disabled { 657 opacity: 0.5; 658 cursor: not-allowed; 659} 660 661.radio-hint.disabled-hint { 662 color: var(--warning-text); 663} 664 665.warning-box { 666 margin-top: var(--space-5); 667 padding: var(--space-5); 668 background: var(--warning-bg); 669 border: 1px solid var(--warning-border); 670 border-radius: var(--radius-lg); 671 font-size: var(--text-sm); 672} 673 674.warning-box strong { 675 display: block; 676 margin-bottom: var(--space-3); 677 color: var(--warning-text); 678} 679 680.warning-box ul { 681 margin: var(--space-4) 0 0 0; 682 padding-left: var(--space-5); 683} 684 685.warning-box li { 686 margin-bottom: var(--space-3); 687 line-height: var(--leading-normal); 688} 689 690.warning-box li:last-child { 691 margin-bottom: 0; 692} 693 694.migrate-callout { 695 display: flex; 696 gap: var(--space-4); 697 padding: var(--space-5); 698 background: var(--accent-muted); 699 border: 1px solid var(--accent); 700 border-radius: var(--radius-xl); 701 margin-bottom: var(--space-6); 702} 703 704.migrate-icon { 705 font-size: var(--text-2xl); 706 line-height: 1; 707 color: var(--accent); 708} 709 710.migrate-content { 711 flex: 1; 712} 713 714.migrate-content strong { 715 display: block; 716 color: var(--text-primary); 717 margin-bottom: var(--space-2); 718} 719 720.migrate-content p { 721 margin: 0 0 var(--space-3) 0; 722 font-size: var(--text-sm); 723 color: var(--text-secondary); 724 line-height: var(--leading-relaxed); 725} 726 727.migrate-link { 728 font-size: var(--text-sm); 729 font-weight: var(--font-medium); 730 color: var(--accent); 731 text-decoration: none; 732} 733 734.migrate-link:hover { 735 text-decoration: underline; 736} 737 738.app-password-step { 739 display: flex; 740 flex-direction: column; 741 gap: var(--space-5); 742 max-width: var(--width-md); 743 margin: 0 auto; 744} 745 746.app-password-step .warning-box { 747 margin-top: 0; 748} 749 750.app-password-step .warning-box p { 751 margin: 0; 752 color: var(--warning-text); 753} 754 755.app-password-display { 756 background: var(--bg-card); 757 border: 2px solid var(--accent); 758 border-radius: var(--radius-xl); 759 padding: var(--space-6); 760 text-align: center; 761} 762 763.app-password-label { 764 font-size: var(--text-sm); 765 color: var(--text-secondary); 766 margin-bottom: var(--space-4); 767} 768 769.app-password-code { 770 display: block; 771 font-size: var(--text-xl); 772 font-family: var(--font-mono); 773 letter-spacing: 0.1em; 774 padding: var(--space-5); 775 background: var(--bg-input); 776 border-radius: var(--radius-md); 777 margin-bottom: var(--space-4); 778 user-select: all; 779} 780 781.copy-btn { 782 padding: var(--space-3) var(--space-5); 783 font-size: var(--text-sm); 784} 785 786.checkbox-label { 787 display: flex; 788 align-items: center; 789 gap: var(--space-3); 790 cursor: pointer; 791 font-weight: var(--font-normal); 792} 793 794.checkbox-label input[type="checkbox"] { 795 width: auto; 796 padding: 0; 797} 798 799.form-section { 800 min-width: 0; 801} 802 803.form-links { 804 margin-top: var(--space-6); 805} 806 807.form-links .link-text { 808 text-align: center; 809 color: var(--text-secondary); 810} 811 812.form-links .link-text a { 813 color: var(--accent); 814} 815 816.contact-fields { 817 display: flex; 818 flex-direction: column; 819 gap: var(--space-4); 820} 821 822.contact-fields .field { 823 margin-bottom: 0; 824} 825 826.provider-badge { 827 display: flex; 828 align-items: center; 829 gap: var(--space-3); 830 padding: var(--space-4); 831 background: var(--bg-secondary); 832 border-radius: var(--radius-md); 833} 834 835.provider-details { 836 display: flex; 837 flex-direction: column; 838} 839 840.provider-name { 841 font-weight: var(--font-semibold); 842} 843 844.provider-username { 845 font-size: var(--text-sm); 846 color: var(--text-secondary); 847} 848 849.error-container { 850 text-align: center; 851 padding: var(--space-8); 852} 853 854.error-icon { 855 width: 48px; 856 height: 48px; 857 border-radius: 50%; 858 background: var(--error-text); 859 color: var(--text-inverse); 860 display: flex; 861 align-items: center; 862 justify-content: center; 863 font-size: var(--text-xl); 864 font-weight: var(--font-bold); 865 margin: 0 auto var(--space-4); 866} 867 868.error-container h2 { 869 margin-bottom: var(--space-2); 870} 871 872.error-container p { 873 color: var(--text-secondary); 874 margin-bottom: var(--space-6); 875} 876 877.info-list { 878 margin: 0; 879 padding-left: var(--space-5); 880} 881 882.info-list li { 883 margin-bottom: var(--space-2); 884 font-size: var(--text-sm); 885 color: var(--text-secondary); 886 line-height: var(--leading-relaxed); 887} 888 889.info-list li:last-child { 890 margin-bottom: 0; 891} 892 893.required { 894 color: var(--error-text); 895}