Skip to main content

max / makenotwork

14.4 KB · 540 lines History Blame Raw
1 /* ===========================================
2 ITEM PAGE
3 =========================================== */
4
5 /* Item detail page (templates/pages/item.html). Scoped under .item-page
6 body class so the .item-title / .item-meta / .item-price / .item-footer
7 names don't collide with the store-front item-card on project.html. */
8 .item-page .item-layout {
9 display: grid;
10 grid-template-columns: 400px 1fr;
11 gap: var(--gap-page);
12 margin-bottom: var(--gap-page);
13 }
14
15 .item-page .item-layout.no-media { grid-template-columns: 1fr; }
16
17 .item-page .item-title {
18 font-size: var(--text-title);
19 margin-bottom: var(--gap-peer);
20 }
21
22 .item-page .item-creator {
23 font-size: var(--text-body);
24 opacity: 0.7;
25 margin-bottom: var(--gap-pane);
26 }
27
28 .item-page .item-creator a { color: var(--content); }
29
30 .item-page .item-price {
31 font-size: var(--text-display);
32 margin-bottom: var(--gap-pane);
33 }
34
35 .item-page .item-meta {
36 display: grid;
37 grid-template-columns: 1fr 1fr;
38 gap: var(--gap-section);
39 margin-bottom: var(--gap-pane);
40 padding-bottom: var(--gap-pane);
41 border-bottom: 1px solid var(--border);
42 }
43
44 .item-page .meta-item { font-size: var(--text-note); }
45 .item-page .meta-label { opacity: 0.7; margin-bottom: var(--gap-bound); }
46 .item-page .meta-value { font-weight: bold; }
47
48 .item-page .item-tags { margin-bottom: var(--gap-pane); }
49
50 /* purchase-box uses .card-muted for the box; only its h3/ul/li specifics remain. */
51 .purchase-box h3 {
52 font-size: var(--text-body);
53 font-weight: normal;
54 margin-bottom: var(--gap-section);
55 }
56 .purchase-box ul { list-style: none; margin-bottom: var(--gap-section); }
57 .purchase-box li { padding: var(--gap-bound) 0; }
58 .purchase-box li::before {
59 content: "";
60 opacity: 0.5;
61 }
62
63 .item-page .btn-primary {
64 width: 100%;
65 padding: var(--gap-section) var(--gap-page);
66 font-size: var(--text-lead);
67 }
68
69 .item-page .btn-secondary {
70 width: 100%;
71 margin-top: var(--gap-peer);
72 }
73
74 .item-page .payment-note {
75 font-size: var(--text-note);
76 opacity: 0.6;
77 text-align: center;
78 margin-top: var(--gap-section);
79 }
80
81 /* bundle-child uses .list-row co-class; only the gap-4 override remains. */
82 .bundle-child { gap: var(--gap-section); padding: var(--gap-section) 0; }
83
84 .item-page .bundle-child-type {
85 font-size: var(--text-fine);
86 padding: var(--gap-bound) var(--gap-group);
87 background: var(--surface-sunken);
88 white-space: nowrap;
89 }
90
91 .item-page .bundle-child-title { flex: 1; }
92 .item-page .bundle-child-title a { color: var(--content); }
93 .item-page .bundle-child-price { font-size: var(--text-note); opacity: 0.7; }
94
95 .item-page .bundle-notice {
96 background: var(--surface-sunken);
97 padding: var(--gap-pane);
98 margin-bottom: var(--gap-pane);
99 text-align: center;
100 }
101
102 .item-page .bundle-notice a { color: var(--content); }
103
104 .item-page .item-description p { margin-bottom: var(--gap-section); text-align: left; }
105 .item-page .item-description ul { margin-left: var(--gap-pane); margin-bottom: var(--gap-section); }
106 .item-page .item-description li { margin-bottom: var(--gap-peer); }
107
108 .item-page .features-grid {
109 display: grid;
110 grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
111 gap: var(--gap-pane);
112 }
113 .item-page .version-number { font-size: var(--text-lead); }
114 .item-page .item-footer {
115 margin-top: var(--gap-page);
116 padding-top: var(--gap-page);
117 border-top: 1px solid var(--border);
118 text-align: center;
119 opacity: 0.6;
120 font-size: var(--text-note);
121 }
122
123 .item-page .item-footer a { color: var(--content); }
124
125 @media (max-width: 839px) {
126 .item-page .item-layout { grid-template-columns: 1fr; }
127 }
128
129 @media (max-width: 599px) {
130 .item-page .item-title { font-size: var(--text-head); }
131 .item-page .item-price { font-size: var(--text-title); }
132 .item-page .item-meta { grid-template-columns: 1fr; gap: var(--gap-peer); }
133 .item-page .item-media,
134 .item-page .item-details { padding: var(--gap-section); }
135 .item-page .item-description { padding: var(--gap-section); }
136 .item-page .item-description h2 { font-size: var(--text-subhead); }
137 .item-page .purchase-box { padding: var(--gap-section); }
138 }
139
140 /* ===========================================
141 PROJECT PAGE (store front)
142 ===========================================
143
144 The store front is described (`src/quasi/project.rs`), so the header, the
145 item cards, the two view copies, the tab strip and the tier cards are all
146 the design system's markup now: a rule restating one of them fails the
147 drift check in build.rs. What is this page's rather than the system's is
148 how wide it runs, which is the measure on the body, and nothing else was
149 left. */
150
151 /* ===========================================
152 LIBRARY DOWNLOADS PAGE
153 =========================================== */
154
155 /* Library downloads page (templates/pages/library_downloads.html).
156 Scoped under .library-page body class. Class names like .item-footer,
157 .bundle-child, etc. overlap with .item-page; the scope keeps them
158 distinct. */
159 .library-page .library-header {
160 display: grid;
161 grid-template-columns: 200px 1fr;
162 gap: var(--gap-pane);
163 margin-bottom: var(--gap-page);
164 align-items: center;
165 }
166
167 .library-page .library-header.no-cover { grid-template-columns: 1fr; }
168
169 .library-page .library-cover img {
170 width: 100%;
171 aspect-ratio: 1 / 1;
172 object-fit: cover;
173 display: block;
174 }
175
176 .library-page .library-title {
177 font-size: var(--text-title);
178 margin-bottom: var(--gap-bound);
179 }
180
181 /* Byline sits under the centered H1 (global `h1 { text-align: center }`),
182 so center it too, otherwise it floats flush-left while the title is
183 centered above. Same for the back-link breadcrumb. When a cover is
184 present the grid scope below restores left-alignment in the text column. */
185 .library-page .library-creator {
186 font-size: var(--text-body);
187 opacity: 0.7;
188 margin-bottom: var(--gap-section);
189 text-align: center;
190 }
191
192 .library-page .library-creator a { color: var(--content); }
193
194 .library-page .library-back {
195 font-size: var(--text-note);
196 opacity: 0.7;
197 text-align: center;
198 }
199 .library-page .library-back a { color: var(--content); }
200
201 /* When a cover is present, the title block sits in the right grid column;
202 left-align in that context so the column reads as a coherent block next
203 to the cover instead of a centered island. */
204 .library-page .library-header:not(.no-cover) .library-title,
205 .library-page .library-header:not(.no-cover) .library-creator {
206 text-align: left;
207 }
208
209 .library-page .downloads-hero h2 {
210 font-size: var(--text-head);
211 margin-bottom: var(--gap-section);
212 padding-bottom: var(--gap-peer);
213 border-bottom: 1px solid var(--border);
214 }
215
216 .library-page .download-row {
217 display: flex;
218 align-items: center;
219 gap: var(--gap-section);
220 padding: var(--gap-group) 0;
221 border-bottom: 1px solid var(--border);
222 }
223
224 .library-page .download-row:last-child { border-bottom: none; }
225
226 .library-page .download-version {
227 min-width: 4em;
228 font-family: var(--font-mono);
229 font-size: var(--text-note);
230 }
231
232 .library-page .download-label { flex: 1; }
233
234 .library-page .download-size {
235 font-size: var(--text-note);
236 opacity: 0.6;
237 min-width: 5em;
238 text-align: right;
239 }
240
241 .library-page .download-notice {
242 background: var(--surface-sunken);
243 padding: var(--gap-pane);
244 margin-bottom: var(--gap-page);
245 font-size: var(--text-note);
246 opacity: 0.8;
247 }
248
249 .library-page .download-notice strong { font-family: var(--font-mono); }
250
251 /* Inline download list on library_audio.html / library_video.html
252 (below the media player). */
253
254 .library-page .library-downloads h3 {
255 font-size: var(--text-lead);
256 margin-bottom: var(--gap-section);
257 }
258
259 .library-page .library-section h2 {
260 font-size: var(--text-subhead);
261 margin-bottom: var(--gap-section);
262 padding-bottom: var(--gap-peer);
263 border-bottom: 1px solid var(--border);
264 }
265
266 .library-page .bundle-child {
267 display: flex;
268 align-items: center;
269 gap: var(--gap-section);
270 padding: var(--gap-section) 0;
271 border-bottom: 1px solid var(--border);
272 }
273
274 .library-page .bundle-child:last-child { border-bottom: none; }
275
276 .library-page .bundle-child-type {
277 font-size: var(--text-fine);
278 padding: var(--gap-bound) var(--gap-group);
279 background: var(--surface-sunken);
280 white-space: nowrap;
281 }
282
283 .library-page .bundle-child-title { flex: 1; }
284 .library-page .bundle-child-title a { color: var(--content); }
285
286 .library-page .item-footer {
287 margin-top: var(--gap-page);
288 padding-top: var(--gap-page);
289 border-top: 1px solid var(--border);
290 text-align: center;
291 opacity: 0.6;
292 font-size: var(--text-note);
293 }
294
295 .library-page .item-footer a { color: var(--content); }
296
297 @media (max-width: 599px) {
298 .library-page .library-header { grid-template-columns: 1fr; }
299 .library-page .library-cover img { max-width: 200px; }
300 }
301
302 /* ===========================================
303 ARTICLE & BLOG READER
304 =========================================== */
305
306 /* Article reader pages (templates/pages/text_reader.html, blog_post.html,
307 library_text.html). Long-form article layout, centered narrow column,
308 author header, large heading, magazine-style body type. Scoped under
309 .article-page body class. The container itself takes the shared reading
310 column near the top of this file. */
311
312 .article-page .author-header {
313 display: flex;
314 align-items: center;
315 gap: var(--gap-section);
316 margin-bottom: var(--gap-page);
317 }
318
319 .article-page .author-avatar {
320 width: 48px;
321 height: 48px;
322 background: var(--surface-sunken);
323 border-radius: var(--radius-round);
324 display: flex;
325 align-items: center;
326 justify-content: center;
327 font-family: var(--font-display);
328 font-size: var(--text-subhead);
329 color: var(--content);
330 }
331
332 .article-page .author-info { flex: 1; }
333
334 .article-page .author-name {
335 font-family: var(--font-mono);
336 font-size: var(--text-body);
337 color: var(--content);
338 }
339
340
341 .article-page .author-name a:hover { text-decoration: underline; }
342
343 .article-page .article-meta {
344 font-family: var(--font-mono);
345 font-size: var(--text-note);
346 color: var(--content-muted);
347 }
348
349 .article-page .article-title {
350 font-family: var(--font-display);
351 font-size: var(--text-display);
352 font-weight: normal;
353 line-height: 1.2;
354 margin-bottom: var(--gap-pane);
355 color: var(--content);
356 text-align: left;
357 }
358
359 .article-page .article-deck {
360 font-family: var(--font-mono);
361 font-size: var(--text-subhead);
362 color: var(--content-muted);
363 margin-bottom: var(--gap-page);
364 line-height: 1.6;
365 }
366
367 .article-page .article-body {
368 font-family: var(--font-sans);
369 font-size: var(--text-lead);
370 line-height: 1.9;
371 }
372
373 .article-page .article-body p { margin-bottom: var(--gap-pane); }
374
375 .article-page .article-body h1 {
376 font-family: var(--font-display);
377 font-size: var(--text-title);
378 font-weight: normal;
379 margin-top: var(--gap-page);
380 margin-bottom: var(--gap-section);
381 color: var(--content);
382 text-align: left;
383 }
384
385 .article-page .article-body h2 {
386 font-family: var(--font-mono);
387 font-size: var(--text-head);
388 font-weight: normal;
389 margin-top: var(--gap-page);
390 margin-bottom: var(--gap-section);
391 color: var(--content);
392 }
393
394 .article-page .article-body h3 {
395 font-family: var(--font-mono);
396 font-size: var(--text-subhead);
397 font-weight: normal;
398 margin-top: var(--gap-page);
399 margin-bottom: var(--gap-section);
400 color: var(--content);
401 }
402
403 .article-page .article-body blockquote {
404 border-left: 3px solid var(--action);
405 padding-left: var(--gap-pane);
406 margin: var(--gap-page) 0;
407 font-style: italic;
408 color: var(--content-muted);
409 }
410
411 .article-page .article-body ul,
412 .article-page .article-body ol {
413 margin-bottom: var(--gap-pane);
414 padding-left: var(--gap-pane);
415 }
416
417 .article-page .article-body li { margin-bottom: var(--gap-peer); }
418
419 .article-page .article-body a {
420 color: var(--action);
421 text-decoration: underline;
422 text-decoration-color: color-mix(in oklch, var(--action) 40%, transparent);
423 text-underline-offset: 2px;
424 }
425
426 .article-page .article-body a:hover {
427 text-decoration-color: var(--action);
428 }
429
430 .article-page .article-body strong { font-weight: bold; }
431 .article-page .article-body em { font-style: italic; }
432
433 .article-page .article-body code {
434 font-family: var(--font-mono);
435 background: var(--surface-sunken);
436 padding: var(--gap-bound) var(--gap-peer);
437 font-size: var(--text-body);
438 }
439
440 .article-page .article-body pre {
441 background: var(--surface-sunken);
442 padding: var(--gap-section);
443 overflow-x: auto;
444 margin-bottom: var(--gap-pane);
445 }
446
447 .article-page .article-body pre code {
448 background: none;
449 padding: 0;
450 }
451
452 .article-page .article-body hr {
453 border: none;
454 text-align: center;
455 margin: var(--gap-page) 0;
456 }
457
458 .article-page .article-body hr::before {
459 content: "* * *";
460 color: var(--content-muted);
461 letter-spacing: 1rem;
462 }
463
464 .article-page .article-footer {
465 margin-top: var(--gap-page);
466 padding-top: var(--gap-page);
467 border-top: 1px solid var(--border);
468 }
469
470 .article-page .author-bio {
471 display: flex;
472 gap: var(--gap-section);
473 padding: var(--gap-pane);
474 background: var(--surface-overlay);
475 }
476
477 .article-page .author-bio .author-avatar {
478 width: 64px;
479 height: 64px;
480 font-size: var(--text-head);
481 flex-shrink: 0;
482 }
483
484 .article-page .author-bio-content { flex: 1; }
485
486 .article-page .author-bio-name {
487 font-family: var(--font-mono);
488 font-size: var(--text-lead);
489 margin-bottom: var(--gap-peer);
490 }
491
492
493 .article-page .author-bio-name a:hover { text-decoration: underline; }
494
495 .article-page .article-tags {
496 margin-top: var(--gap-page);
497 display: flex;
498 gap: var(--gap-peer);
499 flex-wrap: wrap;
500 }
501
502 .article-page .article-tag {
503 font-family: var(--font-mono);
504 background: var(--surface-sunken);
505 color: var(--content);
506 padding: var(--gap-peer) var(--gap-section);
507 font-size: var(--text-fine);
508 text-decoration: none;
509 }
510
511 /* Share controls at the end of the article, inside .article-footer beside
512 the tags or the blog crumb. Was a page-bottom footer below the comments
513 until the site-footer consolidation; the control belongs with the piece
514 it copies, not under the discussion. */
515 .article-page .reader-actions {
516 font-family: var(--font-mono);
517 font-size: var(--text-note);
518 margin-top: var(--gap-section);
519 }
520
521 .article-page .reader-actions a { color: var(--content); text-decoration: none; }
522 .article-page .reader-actions a:hover { text-decoration: underline; }
523
524 /* Blog-specific: nav crumb above the article. */
525 .article-page .blog-nav {
526 font-family: var(--font-mono);
527 font-size: var(--text-note);
528 margin-bottom: var(--gap-page);
529 }
530
531 .article-page .blog-nav a { color: var(--content); text-decoration: none; }
532 .article-page .blog-nav a:hover { text-decoration: underline; }
533
534 @media (max-width: 599px) {
535 .article-page .article-title { font-size: var(--text-title); }
536 .article-page .article-deck { font-size: var(--text-lead); }
537 .article-page .article-body { font-size: var(--text-body); }
538 }
539
540