max / makenotwork
2 files changed,
+306 insertions,
-115 deletions
| @@ -92,6 +92,31 @@ | |||
| 92 | 92 | /* Aliases used by git browser */ | |
| 93 | 93 | --secondary-bg: #f4f0eb; | |
| 94 | 94 | --text: #3d3530; | |
| 95 | + | ||
| 96 | + | /* Legacy aliases — defined to end silent var() fallback failures | |
| 97 | + | in inline-styled templates. Consolidate during phase 2.12. */ | |
| 98 | + | --accent: var(--highlight); | |
| 99 | + | --accent-color: var(--highlight); | |
| 100 | + | --border-color: var(--border); | |
| 101 | + | --background-color: var(--background); | |
| 102 | + | ||
| 103 | + | /* Spacing scale (charter: docs/design-system.md) */ | |
| 104 | + | --space-1: 0.25rem; | |
| 105 | + | --space-2: 0.5rem; | |
| 106 | + | --space-3: 0.75rem; | |
| 107 | + | --space-4: 1rem; | |
| 108 | + | --space-5: 1.5rem; | |
| 109 | + | --space-6: 2rem; | |
| 110 | + | ||
| 111 | + | /* Radius scale */ | |
| 112 | + | --radius-sm: 2px; | |
| 113 | + | --radius-md: 4px; | |
| 114 | + | --radius-round: 50%; | |
| 115 | + | ||
| 116 | + | /* Shadow scale */ | |
| 117 | + | --shadow-1: 0 1px 3px rgba(0, 0, 0, 0.06); | |
| 118 | + | --shadow-2: 0 2px 8px rgba(0, 0, 0, 0.10); | |
| 119 | + | --shadow-3: 0 4px 12px rgba(0, 0, 0, 0.15); | |
| 95 | 120 | } | |
| 96 | 121 | ||
| 97 | 122 | /* Reset */ | |
| @@ -129,6 +154,11 @@ body { | |||
| 129 | 154 | font-size: 4.5rem; | |
| 130 | 155 | } | |
| 131 | 156 | ||
| 157 | + | .message-container { | |
| 158 | + | max-width: 500px; | |
| 159 | + | text-align: center; | |
| 160 | + | } | |
| 161 | + | ||
| 132 | 162 | .centered-wrapper { | |
| 133 | 163 | justify-content: center; | |
| 134 | 164 | text-align: center; | |
| @@ -244,6 +274,65 @@ button.danger:hover, | |||
| 244 | 274 | opacity: 0.8; | |
| 245 | 275 | } | |
| 246 | 276 | ||
| 277 | + | /* Disabled state for all button variants (charter rule). | |
| 278 | + | Applies whether disabled via attribute or aria-disabled. */ | |
| 279 | + | button:disabled, | |
| 280 | + | button[aria-disabled="true"], | |
| 281 | + | .btn-primary:disabled, | |
| 282 | + | .btn-secondary:disabled, | |
| 283 | + | .btn-danger:disabled { | |
| 284 | + | opacity: 0.5; | |
| 285 | + | cursor: not-allowed; | |
| 286 | + | } | |
| 287 | + | ||
| 288 | + | /* Button size + style modifiers (charter: docs/design-system.md). | |
| 289 | + | Use these on top of .btn-primary / -secondary / -danger. | |
| 290 | + | ||
| 291 | + | .btn--large — large CTA padding bump. | |
| 292 | + | .btn--icon — square icon-only / micro button (small padding, | |
| 293 | + | tight line-height). | |
| 294 | + | .btn--link — visually a link, semantically a button (no bg/ | |
| 295 | + | border, opacity-fade hover, mono). | |
| 296 | + | ||
| 297 | + | Some surfaces have tuned button variants that are NOT compositions | |
| 298 | + | of these modifiers and keep their own classes: | |
| 299 | + | .big-button — Young Serif 200×60 anchor on splash pages. | |
| 300 | + | .paywall-btn — wider primary CTA (anchor) on paywalls. | |
| 301 | + | .notify-btn — small inverted notify pill in dashboards. | |
| 302 | + | .order-btn — list reorder up/down (with active flash). | |
| 303 | + | .play-button — circular media-player play control. | |
| 304 | + | .speed-button — segment in media-player speed group. | |
| 305 | + | .shortcuts-help-btn — 1.5rem square help glyph in toolbars. | |
| 306 | + | .toast-retry-btn — inline bordered button inside a toast, | |
| 307 | + | uses currentColor to inherit toast tone. | |
| 308 | + | These are documented variants, not deprecation targets. */ | |
| 309 | + | .btn--large { | |
| 310 | + | padding: 1rem 2.25rem; | |
| 311 | + | font-size: 1.125rem; | |
| 312 | + | } | |
| 313 | + | ||
| 314 | + | .btn--icon { | |
| 315 | + | padding: var(--space-1) var(--space-2); | |
| 316 | + | font-size: 0.85rem; | |
| 317 | + | line-height: 1; | |
| 318 | + | min-width: 1.75rem; | |
| 319 | + | } | |
| 320 | + | ||
| 321 | + | .btn--link { | |
| 322 | + | background: none; | |
| 323 | + | color: var(--detail); | |
| 324 | + | border: none; | |
| 325 | + | padding: 0; | |
| 326 | + | font-family: var(--font-mono); | |
| 327 | + | font-size: 1rem; | |
| 328 | + | cursor: pointer; | |
| 329 | + | transition: opacity 0.2s ease; | |
| 330 | + | } | |
| 331 | + | ||
| 332 | + | .btn--link:hover { | |
| 333 | + | opacity: 0.6; | |
| 334 | + | } | |
| 335 | + | ||
| 247 | 336 | /* =========================================== | |
| 248 | 337 | FORMS | |
| 249 | 338 | =========================================== */ | |
| @@ -351,6 +440,51 @@ form button:hover { | |||
| 351 | 440 | margin-top: 0.5rem; | |
| 352 | 441 | } | |
| 353 | 442 | ||
| 443 | + | /* Field-level validation error, paired with .form-group--error. | |
| 444 | + | Canonical: `partials/_ui.html` ui::form_field macro. */ | |
| 445 | + | .form-group--error label { | |
| 446 | + | color: var(--error); | |
| 447 | + | } | |
| 448 | + | ||
| 449 | + | .form-group--error input, | |
| 450 | + | .form-group--error textarea, | |
| 451 | + | .form-group--error select { | |
| 452 | + | border-color: var(--error); | |
| 453 | + | } | |
| 454 | + | ||
| 455 | + | .field-error { | |
| 456 | + | font-size: 0.85rem; | |
| 457 | + | color: var(--error); | |
| 458 | + | margin-top: var(--space-2); | |
| 459 | + | } | |
| 460 | + | ||
| 461 | + | /* Loading skeleton placeholder. | |
| 462 | + | Canonical: `partials/_ui.html` ui::loading_skeleton macro. */ | |
| 463 | + | .loading-skeleton { | |
| 464 | + | background: var(--surface-muted); | |
| 465 | + | border-radius: var(--radius-md); | |
| 466 | + | animation: skeleton-pulse 1.2s ease-in-out infinite; | |
| 467 | + | } | |
| 468 | + | ||
| 469 | + | .loading-skeleton--row { | |
| 470 | + | height: 1.25rem; | |
| 471 | + | margin: var(--space-2) 0; | |
| 472 | + | } | |
| 473 | + | ||
| 474 | + | .loading-skeleton--card { | |
| 475 | + | height: 8rem; | |
| 476 | + | margin: var(--space-3) 0; | |
| 477 | + | } | |
| 478 | + | ||
| 479 | + | .loading-skeleton--list .loading-skeleton--row + .loading-skeleton--row { | |
| 480 | + | margin-top: var(--space-2); | |
| 481 | + | } | |
| 482 | + | ||
| 483 | + | @keyframes skeleton-pulse { | |
| 484 | + | 0%, 100% { opacity: 0.5; } | |
| 485 | + | 50% { opacity: 0.9; } | |
| 486 | + | } | |
| 487 | + | ||
| 354 | 488 | /* Checkbox group */ | |
| 355 | 489 | .checkbox-group { | |
| 356 | 490 | display: flex; | |
| @@ -450,7 +584,7 @@ form button:hover { | |||
| 450 | 584 | flex-shrink: 0; | |
| 451 | 585 | } | |
| 452 | 586 | ||
| 453 | - | .tab.active { | |
| 587 | + | .tab.is-selected { | |
| 454 | 588 | background: var(--light-background); | |
| 455 | 589 | opacity: 1; | |
| 456 | 590 | } | |
| @@ -487,7 +621,7 @@ form button:hover { | |||
| 487 | 621 | opacity: 1; | |
| 488 | 622 | } | |
| 489 | 623 | ||
| 490 | - | .tab-overflow-menu .tab.active { | |
| 624 | + | .tab-overflow-menu .tab.is-selected { | |
| 491 | 625 | opacity: 1; | |
| 492 | 626 | } | |
| 493 | 627 | ||
| @@ -595,14 +729,42 @@ form button:hover { | |||
| 595 | 729 | .text-xs { font-size: 0.8rem; } | |
| 596 | 730 | .muted { opacity: 0.7; } | |
| 597 | 731 | .dimmed { opacity: 0.6; } | |
| 732 | + | .dimmer { opacity: 0.5; } | |
| 598 | 733 | .meta { font-size: 0.85rem; opacity: 0.7; } | |
| 599 | 734 | .nowrap { white-space: nowrap; } | |
| 600 | 735 | .scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; } | |
| 601 | 736 | .text-center { text-align: center; } | |
| 737 | + | .text-right { text-align: right; } | |
| 738 | + | .fw-bold { font-weight: bold; } | |
| 739 | + | .unstyled-link { text-decoration: none; color: inherit; } | |
| 740 | + | .square-cover { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; } | |
| 741 | + | ||
| 742 | + | /* Spacing utilities (mapped to --space-* scale). | |
| 743 | + | mt = margin-top, mb = margin-bottom, my = vertical, mx = horizontal, | |
| 744 | + | m0 = margin reset. Use sparingly; prefer parent layout primitives. */ | |
| 745 | + | .m-0 { margin: 0; } | |
| 746 | + | .mt-0 { margin-top: 0; } | |
| 747 | + | .mt-2 { margin-top: var(--space-2); } | |
| 748 | + | .mt-3 { margin-top: var(--space-3); } | |
| 749 | + | .mt-4 { margin-top: var(--space-4); } | |
| 750 | + | .mt-5 { margin-top: var(--space-5); } | |
| 751 | + | .mt-6 { margin-top: var(--space-6); } | |
| 752 | + | .mb-0 { margin-bottom: 0; } | |
| 753 | + | .mb-2 { margin-bottom: var(--space-2); } | |
| 754 | + | .mb-3 { margin-bottom: var(--space-3); } | |
| 755 | + | .mb-4 { margin-bottom: var(--space-4); } | |
| 756 | + | .mb-5 { margin-bottom: var(--space-5); } | |
| 757 | + | .mb-6 { margin-bottom: var(--space-6); } | |
| 602 | 758 | ||
| 603 | 759 | .small { padding: 0.25rem 0.6rem; font-size: 0.8rem; } | |
| 604 | 760 | ||
| 761 | + | /* Canonical empty-state primitive. Use modifiers for tight/sized contexts. | |
| 762 | + | Markup: <div class="empty-state">…</div> (optionally with .empty-state--compact | |
| 763 | + | inside dropdowns or .empty-state--chart inside a fixed-height chart slot). */ | |
| 605 | 764 | .empty-state { text-align: center; padding: 2rem; opacity: 0.6; } | |
| 765 | + | .empty-state--compact { padding: 0.75rem; font-size: 0.9rem; } | |
| 766 | + | .empty-state--chart { height: 200px; padding: 0; display: flex; align-items: center; justify-content: center; opacity: 0.5; } | |
| 767 | + | .empty-state-hint { font-family: var(--font-mono); font-size: 0.8rem; margin-top: 0.5rem; opacity: 0.6; } | |
| 606 | 768 | ||
| 607 | 769 | .tab-docs { | |
| 608 | 770 | display: flex; | |
| @@ -713,6 +875,16 @@ form button:hover { | |||
| 713 | 875 | CARDS | |
| 714 | 876 | =========================================== */ | |
| 715 | 877 | ||
| 878 | + | /* Canonical card primitive (charter: docs/design-system.md). | |
| 879 | + | Variants: | |
| 880 | + | .card — filled, hover-step (default content card). | |
| 881 | + | .card.card-muted — surface-muted fill, no hover (dashboard stat / analytics blocks). | |
| 882 | + | .card.card--bordered — bordered, padded, no fill (marketing cards: feature/tier/use-case). | |
| 883 | + | .card.card--selectable — radio-card pattern; pair with .is-selected. | |
| 884 | + | .card.card--grid — grid-cell card (discover grid). | |
| 885 | + | Legacy class names (.stat-card, .analytics-card, .feature-card, .tier-card, | |
| 886 | + | .use-case-card) are aliased to these recipes below — templates migrate at | |
| 887 | + | their own pace. */ | |
| 716 | 888 | .card { | |
| 717 | 889 | background: var(--light-background); | |
| 718 | 890 | padding: 1.5rem; | |
| @@ -727,11 +899,20 @@ form button:hover { | |||
| 727 | 899 | background: var(--surface-muted); | |
| 728 | 900 | } | |
| 729 | 901 | ||
| 730 | - | .card-muted { | |
| 902 | + | .card-muted, | |
| 903 | + | .stat-card, | |
| 904 | + | .analytics-card { | |
| 731 | 905 | background: var(--surface-muted); | |
| 732 | 906 | padding: 1.5rem; | |
| 733 | 907 | } | |
| 734 | 908 | ||
| 909 | + | .card--bordered { | |
| 910 | + | background: transparent; | |
| 911 | + | padding: 1rem; | |
| 912 | + | border: 1px solid var(--border); | |
| 913 | + | margin-bottom: 0; | |
| 914 | + | } | |
| 915 | + | ||
| 735 | 916 | .card-title { | |
| 736 | 917 | font-size: 1.2rem; | |
| 737 | 918 | margin-bottom: 0.5rem; | |
| @@ -786,10 +967,7 @@ form button:hover { | |||
| 786 | 967 | opacity: 0.7; | |
| 787 | 968 | } | |
| 788 | 969 | ||
| 789 | - | .stat-card { | |
| 790 | - | background: var(--surface-muted); | |
| 791 | - | padding: 1.5rem; | |
| 792 | - | } | |
| 970 | + | /* .stat-card base recipe defined above with .card-muted */ | |
| 793 | 971 | ||
| 794 | 972 | .stat-label { | |
| 795 | 973 | font-size: 0.85rem; | |
| @@ -920,3478 +1098,8162 @@ form button:hover { | |||
| 920 | 1098 | display: none; | |
| 921 | 1099 | } | |
| 922 | 1100 | ||
| 923 | - | /* =========================================== | |
| 924 | - | SECTIONS | |
| 925 | - | =========================================== */ | |
| 926 | - | ||
| 927 | - | .section-header { | |
| 928 | - | font-size: 1.5rem; | |
| 929 | - | font-weight: normal; | |
| 930 | - | margin-bottom: 1rem; | |
| 931 | - | padding-bottom: 0.5rem; | |
| 932 | - | border-bottom: 1px solid var(--border); | |
| 933 | - | font-family: var(--font-mono); | |
| 934 | - | } | |
| 935 | - | ||
| 936 | - | .content-section { | |
| 937 | - | background: var(--light-background); | |
| 938 | - | padding: 2rem; | |
| 939 | - | margin-bottom: 2rem; | |
| 1101 | + | /* Full-page error layout (templates/pages/error.html). Distinct from | |
| 1102 | + | the inline `.error-message` form-error class above; named to avoid | |
| 1103 | + | collision. */ | |
| 1104 | + | .error-page { | |
| 1105 | + | min-height: 100vh; | |
| 1106 | + | display: flex; | |
| 1107 | + | align-items: center; | |
| 1108 | + | justify-content: center; | |
| 1109 | + | padding: var(--space-6); | |
| 1110 | + | background: var(--background); | |
| 940 | 1111 | } | |
| 941 | 1112 | ||
| 942 | - | .form-section { | |
| 943 | - | margin-bottom: 2rem; | |
| 1113 | + | .error-container { | |
| 1114 | + | text-align: center; | |
| 1115 | + | max-width: 560px; | |
| 944 | 1116 | } | |
| 945 | 1117 | ||
| 946 | - | .section-group-label { | |
| 947 | - | font-family: var(--font-mono); | |
| 948 | - | font-size: 0.8rem; | |
| 949 | - | font-weight: bold; | |
| 1118 | + | .error-status { | |
| 1119 | + | font-size: 0.85rem; | |
| 1120 | + | font-weight: 600; | |
| 1121 | + | letter-spacing: 0.08em; | |
| 950 | 1122 | text-transform: uppercase; | |
| 951 | - | letter-spacing: 0.05em; | |
| 952 | 1123 | color: var(--text-muted); | |
| 953 | - | margin: 2.5rem 0 1rem 0; | |
| 954 | - | padding-top: 1.5rem; | |
| 955 | - | border-top: 2px solid var(--border); | |
| 1124 | + | margin-bottom: var(--space-4); | |
| 956 | 1125 | } | |
| 957 | 1126 | ||
| 958 | - | .form-section h2 { | |
| 959 | - | font-size: 1.3rem; | |
| 960 | - | font-weight: normal; | |
| 961 | - | margin-bottom: 1rem; | |
| 962 | - | padding-bottom: 0.5rem; | |
| 963 | - | border-bottom: 1px solid var(--border); | |
| 1127 | + | .error-page-message { | |
| 1128 | + | font-size: 1.5rem; | |
| 1129 | + | line-height: 1.4; | |
| 1130 | + | color: var(--detail); | |
| 1131 | + | margin-bottom: var(--space-6); | |
| 964 | 1132 | } | |
| 965 | 1133 | ||
| 966 | - | details.form-section > summary { | |
| 967 | - | cursor: pointer; | |
| 968 | - | list-style: disclosure-closed; | |
| 1134 | + | .error-actions { | |
| 1135 | + | display: flex; | |
| 1136 | + | gap: var(--space-4); | |
| 1137 | + | justify-content: center; | |
| 969 | 1138 | } | |
| 970 | 1139 | ||
| 971 | - | details.form-section[open] > summary { | |
| 972 | - | list-style: disclosure-open; | |
| 973 | - | margin-bottom: 1rem; | |
| 1140 | + | .error-actions a.primary, | |
| 1141 | + | .error-actions a.secondary { | |
| 1142 | + | text-decoration: none; | |
| 974 | 1143 | } | |
| 975 | 1144 | ||
| 976 | - | details.form-section > summary > h2 { | |
| 977 | - | display: inline; | |
| 1145 | + | /* Minimal direct-purchase page (templates/pages/buy.html). Standalone | |
| 1146 | + | page used for link-in-bio sharing — no site chrome, just a card. | |
| 1147 | + | Scoped under .buy-page so the rules don't bleed into the rest of | |
| 1148 | + | the app. Tokenized; previously lived as a page-isolated <style>. */ | |
| 1149 | + | .buy-page { | |
| 1150 | + | min-height: 100vh; | |
| 1151 | + | display: flex; | |
| 1152 | + | align-items: center; | |
| 1153 | + | justify-content: center; | |
| 1154 | + | padding: var(--space-6); | |
| 978 | 1155 | } | |
| 979 | 1156 | ||
| 980 | - | details.form-section > summary:hover > h2 { | |
| 981 | - | color: var(--detail); | |
| 1157 | + | .buy-page .buy-card { | |
| 1158 | + | background: var(--light-background); | |
| 1159 | + | border-radius: 12px; | |
| 1160 | + | padding: var(--space-6); | |
| 1161 | + | max-width: 420px; | |
| 1162 | + | width: 100%; | |
| 1163 | + | box-shadow: var(--shadow-3); | |
| 982 | 1164 | } | |
| 983 | 1165 | ||
| 984 | - | /* =========================================== | |
| 985 | - | NAVIGATION | |
| 986 | - | =========================================== */ | |
| 1166 | + | .buy-page .cover, | |
| 1167 | + | .buy-page .no-cover { | |
| 1168 | + | width: 100%; | |
| 1169 | + | aspect-ratio: 1; | |
| 1170 | + | max-height: 280px; | |
| 1171 | + | border-radius: 8px; | |
| 1172 | + | margin-bottom: var(--space-5); | |
| 1173 | + | background: var(--surface-raised); | |
| 1174 | + | } | |
| 987 | 1175 | ||
| 988 | - | nav { | |
| 989 | - | margin-bottom: 2rem; | |
| 1176 | + | .buy-page .cover { | |
| 1177 | + | object-fit: cover; | |
| 990 | 1178 | } | |
| 991 | 1179 | ||
| 992 | - | .nav-links { | |
| 1180 | + | .buy-page .no-cover { | |
| 993 | 1181 | display: flex; | |
| 994 | - | gap: 2rem; | |
| 995 | - | flex-wrap: wrap; | |
| 1182 | + | align-items: center; | |
| 1183 | + | justify-content: center; | |
| 1184 | + | font-size: 3rem; | |
| 1185 | + | opacity: 0.2; | |
| 996 | 1186 | } | |
| 997 | 1187 | ||
| 998 | - | .nav-links a { | |
| 999 | - | color: var(--detail); | |
| 1000 | - | text-decoration: none; | |
| 1001 | - | font-family: var(--font-mono); | |
| 1002 | - | transition: opacity 0.2s ease; | |
| 1188 | + | .buy-page h1 { | |
| 1189 | + | text-align: left; | |
| 1190 | + | font-size: 1.4rem; | |
| 1191 | + | margin-bottom: var(--space-1); | |
| 1003 | 1192 | } | |
| 1004 | 1193 | ||
| 1005 | - | .nav-links a:hover { | |
| 1194 | + | .buy-page .creator { | |
| 1195 | + | font-family: var(--font-mono); | |
| 1196 | + | font-size: 0.85rem; | |
| 1006 | 1197 | opacity: 0.6; | |
| 1198 | + | margin-bottom: var(--space-5); | |
| 1007 | 1199 | } | |
| 1008 | 1200 | ||
| 1009 | - | .shortcuts-help-btn { | |
| 1010 | - | font-family: var(--font-mono); | |
| 1011 | - | color: var(--text-muted); | |
| 1012 | - | font-size: 0.85rem; | |
| 1013 | - | width: 1.5rem; | |
| 1014 | - | height: 1.5rem; | |
| 1015 | - | border: 1px solid var(--border); | |
| 1016 | - | border-radius: 3px; | |
| 1017 | - | display: inline-flex; | |
| 1018 | - | align-items: center; | |
| 1019 | - | justify-content: center; | |
| 1020 | - | cursor: pointer; | |
| 1021 | - | transition: opacity 0.2s ease; | |
| 1022 | - | padding: 0; | |
| 1023 | - | background: none; | |
| 1201 | + | .buy-page .creator a { | |
| 1202 | + | color: inherit; | |
| 1024 | 1203 | } | |
| 1025 | 1204 | ||
| 1026 | - | .shortcuts-help-btn:hover { | |
| 1027 | - | opacity: 0.6; | |
| 1205 | + | .buy-page .price { | |
| 1206 | + | font-family: var(--font-mono); | |
| 1207 | + | font-size: 1.3rem; | |
| 1208 | + | margin-bottom: var(--space-5); | |
| 1028 | 1209 | } | |
| 1029 | 1210 | ||
| 1030 | - | .breadcrumb { | |
| 1211 | + | .buy-page .description { | |
| 1031 | 1212 | font-size: 0.9rem; | |
| 1032 | - | color: var(--text-muted); | |
| 1033 | - | margin-bottom: 0.5rem; | |
| 1034 | - | font-family: var(--font-mono); | |
| 1213 | + | line-height: 1.5; | |
| 1214 | + | opacity: 0.8; | |
| 1215 | + | margin-bottom: var(--space-5); | |
| 1216 | + | max-height: 4.5em; | |
| 1217 | + | overflow: hidden; | |
| 1035 | 1218 | } | |
| 1036 | 1219 | ||
| 1037 | - | .breadcrumb a { | |
| 1038 | - | color: var(--detail); | |
| 1220 | + | .buy-page .buy-btn { | |
| 1221 | + | display: block; | |
| 1222 | + | width: 100%; | |
| 1223 | + | padding: 14px; | |
| 1224 | + | background: var(--highlight); | |
| 1225 | + | color: var(--primary-light); | |
| 1226 | + | border: none; | |
| 1227 | + | border-radius: 6px; | |
| 1228 | + | font-size: 1rem; | |
| 1229 | + | font-weight: 600; | |
| 1230 | + | cursor: pointer; | |
| 1231 | + | text-align: center; | |
| 1039 | 1232 | text-decoration: none; | |
| 1233 | + | transition: opacity 0.2s ease; | |
| 1040 | 1234 | } | |
| 1041 | 1235 | ||
| 1042 | - | .breadcrumb a:hover { | |
| 1043 | - | text-decoration: underline; | |
| 1236 | + | .buy-page .buy-btn:hover { | |
| 1237 | + | opacity: 0.85; | |
| 1044 | 1238 | } | |
| 1045 | 1239 | ||
| 1046 | - | /* =========================================== | |
| 1047 | - | HEADER & FOOTER | |
| 1048 | - | =========================================== */ | |
| 1240 | + | .buy-page .buy-btn:disabled { | |
| 1241 | + | opacity: 0.6; | |
| 1242 | + | cursor: wait; | |
| 1243 | + | } | |
| 1049 | 1244 | ||
| 1050 | - | header { | |
| 1051 | - | background: transparent; | |
| 1052 | - | border-bottom: none; | |
| 1053 | - | padding: 0; |
Lines truncated
| @@ -1,7 +1,7 @@ | |||
| 1 | 1 | <div class="version-upload" id="version-upload" data-item-id="{{ item.id }}"> | |
| 2 | 2 | ||
| 3 | 3 | {% if versions.is_empty() %} | |
| 4 | - | <div style="text-align: center; padding: 2rem 1rem; opacity: 0.6;"> | |
| 4 | + | <div class="item-version-upload-empty"> | |
| 5 | 5 | <p>No versions uploaded yet. Create your first version below.</p> | |
| 6 | 6 | </div> | |
| 7 | 7 | {% else %} | |
| @@ -20,19 +20,19 @@ | |||
| 20 | 20 | {% for version in versions %} | |
| 21 | 21 | <tr> | |
| 22 | 22 | <td><span class="badge{% if version.is_current %} current{% endif %}">v{{ version.number }}</span></td> | |
| 23 | - | <td style="font-size: 0.85rem;">{% if let Some(label) = version.label %}{{ label }}{% endif %}</td> | |
| 24 | - | <td style="font-size: 0.85rem;">{% if version.has_file %}{% match version.file_name %}{% when Some with (name) %}{{ name }}{% when None %}1 file{% endmatch %}{% else %}<span style="opacity: 0.5;">No file</span>{% endif %}</td> | |
| 23 | + | <td class="item-version-upload-cell-sm">{% if let Some(label) = version.label %}{{ label }}{% endif %}</td> | |
| 24 | + | <td class="item-version-upload-cell-sm">{% if version.has_file %}{% match version.file_name %}{% when Some with (name) %}{{ name }}{% when None %}1 file{% endmatch %}{% else %}<span class="item-version-upload-no-file">No file</span>{% endif %}</td> | |
| 25 | 25 | <td>{{ version.size }}</td> | |
| 26 | 26 | <td>{{ version.downloads }}</td> | |
| 27 | 27 | <td> | |
| 28 | 28 | {% if version.has_file %} | |
| 29 | - | <button class="secondary download-version-btn" style="padding: 0.4rem 0.8rem; font-size: 0.85rem;" | |
| 29 | + | <button class="secondary download-version-btn item-version-upload-btn" | |
| 30 | 30 | data-version-id="{{ version.id }}">Download</button> | |
| 31 | 31 | {% else %} | |
| 32 | - | <button class="secondary upload-to-version-btn" style="padding: 0.4rem 0.8rem; font-size: 0.85rem;" | |
| 32 | + | <button class="secondary upload-to-version-btn item-version-upload-btn" | |
| 33 | 33 | data-version-id="{{ version.id }}">Upload File</button> | |
| 34 | 34 | {% endif %} | |
| 35 | - | <button class="secondary delete-version-btn" style="padding: 0.4rem 0.8rem; font-size: 0.85rem;" | |
| 35 | + | <button class="secondary delete-version-btn item-version-upload-btn" | |
| 36 | 36 | data-version-id="{{ version.id }}">Delete</button> | |
| 37 | 37 | </td> | |
| 38 | 38 | </tr> | |
| @@ -43,7 +43,7 @@ | |||
| 43 | 43 | ||
| 44 | 44 | <!-- New Version Form --> | |
| 45 | 45 | <div id="new-version-form"> | |
| 46 | - | <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 1rem;"> | |
| 46 | + | <div class="item-version-upload-grid"> | |
| 47 | 47 | <div class="form-group"> | |
| 48 | 48 | <label for="new-version-number">Version Number</label> | |
| 49 | 49 | <input type="text" id="new-version-number" placeholder="e.g., 1.0"> | |
| @@ -56,23 +56,23 @@ | |||
| 56 | 56 | ||
| 57 | 57 | <div class="form-group"> | |
| 58 | 58 | <label>Files</label> | |
| 59 | - | <div class="upload-hint" style="margin-bottom: 0.5rem;">Add one file per platform. Each gets its own label (e.g. "macOS (arm)", "Linux (x86_64)").</div> | |
| 59 | + | <div class="upload-hint item-version-upload-hint">Add one file per platform. Each gets its own label (e.g. "macOS (arm)", "Linux (x86_64)").</div> | |
| 60 | 60 | ||
| 61 | - | <table style="width: 100%; border-collapse: collapse;" id="version-file-table"> | |
| 61 | + | <table class="item-version-upload-file-table" id="version-file-table"> | |
| 62 | 62 | <thead> | |
| 63 | - | <tr style="text-align: left; font-size: 0.8rem; opacity: 0.7; text-transform: uppercase; letter-spacing: 0.03em;"> | |
| 64 | - | <th style="padding: 0.4rem 0.5rem 0.4rem 0;">File</th> | |
| 65 | - | <th style="padding: 0.4rem 0.5rem;">Label</th> | |
| 66 | - | <th style="padding: 0.4rem 0.5rem; width: 40px;"></th> | |
| 63 | + | <tr> | |
| 64 | + | <th>File</th> | |
| 65 | + | <th>Label</th> | |
| 66 | + | <th></th> | |
| 67 | 67 | </tr> | |
| 68 | 68 | </thead> | |
| 69 | 69 | <tbody id="version-file-rows"></tbody> | |
| 70 | 70 | </table> | |
| 71 | 71 | ||
| 72 | - | <div style="margin-top: 0.5rem;"> | |
| 73 | - | <input type="file" id="version-file-input" style="display: none;" | |
| 72 | + | <div class="item-version-upload-add-row"> | |
| 73 | + | <input type="file" id="version-file-input" class="hidden" | |
| 74 | 74 | accept=".zip,.dmg,.exe,.appimage,.deb,.tar.gz,.clap,.vst3" multiple> | |
| 75 | - | <button type="button" class="secondary" id="add-version-file-btn" style="padding: 0.4rem 0.8rem;">Add Files</button> | |
| 75 | + | <button type="button" class="secondary item-version-upload-add-btn" id="add-version-file-btn">Add Files</button> | |
| 76 | 76 | </div> | |
| 77 | 77 | </div> | |
| 78 | 78 | ||
| @@ -84,7 +84,7 @@ | |||
| 84 | 84 | <div class="file-upload-area" id="existing-version-dropzone"> | |
| 85 | 85 | <div class="upload-text">Drop file to upload for this version</div> | |
| 86 | 86 | <div class="upload-hint">ZIP, DMG, EXE, AppImage, DEB, tar.gz, CLAP, VST3</div> | |
| 87 | - | <input type="file" id="existing-version-file-input" style="display: none;" | |
| 87 | + | <input type="file" id="existing-version-file-input" class="hidden" | |
| 88 | 88 | accept=".zip,.dmg,.exe,.appimage,.deb,.tar.gz,.clap,.vst3"> | |
| 89 | 89 | </div> | |
| 90 | 90 | <button class="secondary" id="cancel-existing-upload-btn">Cancel</button> | |
| @@ -92,7 +92,7 @@ | |||
| 92 | 92 | ||
| 93 | 93 | <!-- Shared upload progress/status (outside both forms so always visible) --> | |
| 94 | 94 | <div class="upload-progress hidden" id="version-upload-progress"> | |
| 95 | - | <div id="version-upload-queue" style="margin-bottom: 0.75rem;"></div> | |
| 95 | + | <div class="item-version-upload-queue" id="version-upload-queue"></div> | |
| 96 | 96 | <div class="progress-info"> | |
| 97 | 97 | <span id="version-upload-filename">filename.zip</span> | |
| 98 | 98 | <span id="version-upload-percent">0%</span> | |
| @@ -100,7 +100,7 @@ | |||
| 100 | 100 | <div class="progress-bar-container"> | |
| 101 | 101 | <div class="progress-bar" id="version-progress-bar" style="width: 0%;"></div> | |
| 102 | 102 | </div> | |
| 103 | - | <div id="version-upload-speed" style="font-size: 0.8rem; opacity: 0.6; margin-top: 0.25rem;"></div> | |
| 103 | + | <div class="item-version-upload-speed" id="version-upload-speed"></div> | |
| 104 | 104 | <button type="button" class="secondary" id="cancel-version-upload-btn">Cancel</button> | |
| 105 | 105 | </div> | |
| 106 | 106 |