Skip to main content

max / makenotwork

12.7 KB · 546 lines History Blame Raw
1 /* ===========================================
2 SECTIONS
3 =========================================== */
4
5 .section-header {
6 font-size: var(--text-head);
7 font-weight: normal;
8 margin-bottom: var(--gap-section);
9 padding-bottom: var(--gap-peer);
10 border-bottom: 1px solid var(--border);
11 font-family: var(--font-mono);
12 }
13
14 /* Canonical "page section box", light-background card with padding + bottom
15 space. One of these in the codebase. Aliased to the per-page class names
16 that were just relabels of this same shape. Templates can use the alias
17 name OR add `.content-section` as a co-class. */
18 /* The canonical panel. Every one of these carries `.raised` in the markup
19 now, so the fill and the bevel come from layout.css and this rule is the
20 spacing only. The background it used to declare was --surface-overlay,
21 which .raised spells --surface-raised; equal on the platform default and a
22 theme may set them apart, the same move .card and .buy-card made. */
23 .content-section,
24 .import-page .import-form,
25 .import-page .import-progress,
26 .library-page .library-section,
27 .library-page .library-downloads,
28 .library-page .downloads-hero,
29 .receipt-page .receipt-box,
30 .stripe-disclaimer-page .disclaimer-box {
31 padding: var(--gap-page);
32 margin-bottom: var(--gap-page);
33 }
34
35 /* Variants of the canonical shape that want top-spacing instead of bottom,
36 or a tighter --gap-pane padding. */
37 .library-page .library-downloads,
38 .receipt-page .receipt-box { margin-bottom: 0; margin-top: var(--gap-pane); }
39 .import-page .import-progress { padding: var(--gap-pane); margin-bottom: var(--gap-section); }
40 .stripe-disclaimer-page .disclaimer-box { margin-bottom: var(--gap-pane); }
41
42 .form-section {
43 margin-bottom: var(--gap-page);
44 }
45
46 .section-group-label {
47 font-family: var(--font-mono);
48 font-size: var(--text-fine);
49 font-weight: bold;
50 text-transform: uppercase;
51 letter-spacing: 0.05em;
52 color: var(--content-muted);
53 margin: var(--gap-page) 0 var(--gap-section) 0;
54 padding-top: var(--gap-pane);
55 border-top: 2px solid var(--border);
56 }
57
58 .form-section h2 {
59 font-size: var(--text-subhead);
60 font-weight: normal;
61 margin-bottom: var(--gap-section);
62 padding-bottom: var(--gap-peer);
63 border-bottom: 1px solid var(--border);
64 }
65
66 details.form-section > summary {
67 cursor: pointer;
68 list-style: disclosure-closed;
69 }
70
71 details.form-section[open] > summary {
72 list-style: disclosure-open;
73 margin-bottom: var(--gap-section);
74 }
75
76 details.form-section > summary > h2 {
77 display: inline;
78 }
79
80 details.form-section > summary:hover > h2 {
81 color: var(--content);
82 }
83
84 /* ===========================================
85 NAVIGATION
86 =========================================== */
87
88 nav {
89 margin-bottom: var(--gap-page);
90 }
91
92 .nav-links {
93 display: flex;
94 gap: var(--gap-page);
95 flex-wrap: wrap;
96 }
97
98 .nav-links a {
99 color: var(--content);
100 text-decoration: none;
101 font-family: var(--font-mono);
102 transition: opacity 0.2s ease;
103 }
104
105 .nav-links a:hover {
106 opacity: 0.6;
107 }
108
109 .shortcuts-help-btn {
110 font-family: var(--font-mono);
111 color: var(--content-muted);
112 font-size: var(--text-note);
113 width: 1.5rem;
114 height: 1.5rem;
115 border: 1px solid var(--border);
116 border-radius: var(--radius-control);
117 display: inline-flex;
118 align-items: center;
119 justify-content: center;
120 cursor: pointer;
121 transition: opacity 0.2s ease;
122 padding: 0;
123 background: none;
124 }
125
126 .shortcuts-help-btn:hover {
127 opacity: 0.6;
128 }
129
130 .breadcrumb {
131 font-size: var(--text-note);
132 color: var(--content-muted);
133 margin-bottom: var(--gap-peer);
134 font-family: var(--font-mono);
135 }
136
137 .breadcrumb a {
138 color: var(--content);
139 text-decoration: none;
140 }
141
142 .breadcrumb a:hover {
143 text-decoration: underline;
144 }
145
146 /* ===========================================
147 HEADER & FOOTER
148 =========================================== */
149
150 header {
151 background: transparent;
152 border-bottom: none;
153 padding: 0;
154 margin-bottom: var(--gap-page);
155 }
156
157 footer {
158 text-align: center;
159 font-family: var(--font-mono);
160 color: var(--content-muted);
161 }
162
163 /* Site-wide header.
164 The class names are quasi-webview's, not this stylesheet's: the header is a
165 `quasi_router::Chrome::band` and `crate::shell::site_header` builds the
166 description rather than the markup. A rule here has to match what that
167 renderer emits, and `quasi_webview::vocabulary` is the list of what it may. */
168 .chrome-band {
169 display: flex;
170 justify-content: space-between;
171 align-items: center;
172 padding: var(--gap-section) var(--gap-pane);
173 margin-bottom: var(--gap-pane);
174 }
175
176 .chrome-band .chrome-nav {
177 margin: 0;
178 }
179
180 /* The places are a `ul` of `li`, which is what a nav of addresses is. The
181 markers and the indent go; the row is the layout. */
182 .chrome-nav ul {
183 display: flex;
184 gap: var(--gap-pane);
185 flex-wrap: wrap;
186 list-style: none;
187 margin: 0;
188 padding: 0;
189 }
190
191 .chrome-place {
192 color: var(--content);
193 text-decoration: none;
194 font-family: var(--font-mono);
195 cursor: pointer;
196 transition: opacity 0.2s ease;
197 }
198
199 .chrome-place:hover {
200 opacity: 0.6;
201 }
202
203 /* The cart place is offered on every signed-in page and drawn only when the
204 cart holds something. How many items that is is not known when the document
205 is rendered, so `core/cart-badge.js` asks `/api/cart/count` and writes the
206 answer onto the place as `data-count`; the presence is that answer, rather
207 than a class the markup ships hidden and a script takes off.
208 The `li` is what hides, not the anchor: an empty item in a flex row still
209 pays its gap. */
210 .chrome-nav li:has(> [data-place="cart"]) {
211 display: none;
212 }
213
214 .chrome-nav li:has(> [data-place="cart"][data-count]) {
215 display: block;
216 }
217
218 .chrome-brand {
219 font-family: var(--font-display);
220 font-size: var(--text-subhead);
221 text-decoration: none;
222 color: var(--content);
223 }
224
225 .chrome-brand:hover {
226 opacity: 0.8;
227 }
228
229 /* Header search */
230 .chrome-search {
231 flex: 0 1 220px;
232 margin: 0 var(--gap-section);
233 }
234
235 /* The box carries a real `<label>` now, where the hand-written header carried
236 an `aria-label`. Hidden rather than dropped: the same name is read out, and a
237 description that stopped naming its own question would be a worse
238 description for the sake of a stylesheet. */
239 .chrome-search .form-label {
240 position: absolute;
241 width: 1px;
242 height: 1px;
243 padding: 0;
244 margin: -1px;
245 overflow: hidden;
246 clip: rect(0, 0, 0, 0);
247 white-space: nowrap;
248 border: 0;
249 }
250
251 .chrome-search .form-group {
252 margin: 0;
253 }
254
255 /* Only what makeover does not already say about a `.field`. The surface, the
256 text colour and the focus ring are the design system's, and the drift check
257 in `build.rs` fails the build for restating one of them here. The old
258 `.header-search input` rules did restate all four; they were written before
259 the box was a described field. */
260 .chrome-search .field {
261 width: 100%;
262 font-size: var(--text-note);
263 font-family: var(--font-mono);
264 }
265
266 /* The disclosure, hidden by default and shown at 768px. The checkbox holds the
267 state and the label is the control: `Disclose::Narrow` says the places are
268 worth hiding when there is no room, and this is the browser's answer to it. */
269 .chrome-disclose-state {
270 display: none;
271 }
272
273 .chrome-disclose {
274 display: none;
275 cursor: pointer;
276 padding: var(--gap-peer);
277 z-index: var(--z-header);
278 }
279
280 .chrome-disclose span {
281 display: block;
282 width: 22px;
283 height: 2px;
284 background: var(--content);
285 margin: 5px 0;
286 transition: transform 0.2s ease, opacity 0.2s ease;
287 }
288
289 /* ===========================================
290 LAYOUT UTILITIES
291 =========================================== */
292
293 .action-buttons {
294 display: flex;
295 gap: var(--gap-section);
296 flex-wrap: wrap;
297 }
298 /* ===========================================
299 SPECIFIC COMPONENTS
300 =========================================== */
301
302 /* Login container.
303 The id as well as the class: the four auth pages are described screens now
304 (`crate::quasi::auth_pages`) and a description names a region, never a class,
305 so the region's id is what a rule can key off. The class stays for the six
306 templated pages that still write it. */
307 #login-container,
308 .login-container {
309 display: flex;
310 flex-direction: column;
311 max-width: 400px;
312 width: 100%;
313 margin: 0 auto;
314 background: var(--surface-overlay);
315 padding: var(--gap-page);
316 }
317 /* Logo */
318 .logo {
319 font-family: var(--font-display);
320 color: var(--content);
321 font-size: var(--text-head);
322 }
323
324 .tagline {
325 font-family: var(--font-mono);
326 color: var(--content-muted);
327 text-align: center;
328 }
329
330 .centered-page .tagline {
331 margin-bottom: var(--gap-bound);
332 }
333 /* Skip link */
334 .skip-link {
335 text-align: center;
336 margin-top: var(--gap-section);
337 }
338
339 .skip-link a {
340 color: var(--primary-dark);
341 text-decoration: none;
342 font-size: var(--text-note);
343 opacity: 0.7;
344 }
345
346 .skip-link a:hover {
347 text-decoration: underline;
348 }
349
350 /* Footer link */
351 .foot-link {
352 margin-top: 0.5em;
353 }
354
355 /* The described auth pages have no `.foot-link` wrapper: a description says
356 there is a link, and a `div` around it to make it a block is markup with no
357 meaning in it. Stacking them is this stylesheet's answer, which is where a
358 layout question a description declines belongs. */
359 #login-container > .link {
360 display: block;
361 margin-top: 0.5em;
362 }
363
364 /* Status indicators */
365 .status-indicator {
366 display: inline-block;
367 width: 8px;
368 height: 8px;
369 background: var(--primary-dark);
370 margin-right: var(--gap-peer);
371 }
372
373 .status-indicator.active {
374 background: var(--success);
375 }
376
377 /* Amount styling */
378 .amount-in {
379 color: var(--success);
380 }
381
382 .amount-out {
383 opacity: 0.7;
384 }
385
386 /* File upload */
387 .file-upload-area {
388 background: var(--surface-sunken);
389 padding: var(--gap-page);
390 text-align: center;
391 cursor: pointer;
392 transition: background 0.2s ease;
393 margin-bottom: var(--gap-section);
394 }
395
396 .file-upload-area:hover,
397 .file-upload-area.dragover {
398 background: var(--border);
399 }
400 /* Chart placeholder */
401 .chart-container {
402 background: var(--surface-sunken);
403 padding: var(--gap-pane);
404 margin-bottom: var(--gap-pane);
405 }
406
407 .chart-header {
408 display: flex;
409 justify-content: space-between;
410 align-items: center;
411 margin-bottom: var(--gap-section);
412 }
413
414 .chart-header h2 {
415 font-size: var(--text-subhead);
416 font-weight: normal;
417 }
418
419 .chart-bars {
420 display: flex;
421 align-items: flex-end;
422 gap: 2px;
423 height: 200px;
424 padding: 0 var(--gap-peer);
425 }
426
427 .chart-bar-col {
428 flex: 1;
429 display: flex;
430 flex-direction: column;
431 align-items: center;
432 min-width: 0;
433 cursor: default;
434 position: relative;
435 }
436
437 .chart-bar-col[data-tooltip]:hover::before {
438 content: attr(data-tooltip);
439 position: absolute;
440 bottom: 100%;
441 left: 50%;
442 transform: translateX(-50%);
443 background: var(--primary-dark);
444 color: var(--primary-light);
445 font-size: var(--text-fine);
446 font-family: var(--font-mono);
447 padding: var(--gap-bound) var(--gap-peer);
448 white-space: nowrap;
449 z-index: var(--z-dropdown);
450 pointer-events: none;
451 margin-bottom: var(--gap-bound);
452 }
453
454 .chart-bar {
455 width: 100%;
456 height: var(--fill, 0%);
457 background: var(--primary-dark);
458 min-height: 2px;
459 transition: opacity 0.15s;
460 }
461
462 .chart-bar-col:hover .chart-bar {
463 opacity: 0.8;
464 }
465
466 .chart-bar-label {
467 font-size: var(--text-fine);
468 opacity: 0.5;
469 margin-top: var(--gap-bound);
470 white-space: nowrap;
471 overflow: hidden;
472 text-overflow: ellipsis;
473 max-width: 100%;
474 }
475
476 /* Time selector */
477 .time-selector {
478 display: flex;
479 gap: var(--gap-peer);
480 }
481
482 /* The range buttons are makeover's `.segment`, which is what a segmented
483 control is called there, and B3's question about whether this codebase has
484 an analogue: it does, and this is it. Fill, bevel, hover, active and focus
485 are the generated ones; this rule is geometry and type.
486
487 Selection was a --primary-dark fill with a --primary-light label, which is
488 a second thing meaning "chosen" beside the generated `.chosen` (the segment
489 presses IN — well fill, inset bevel). Taking the generated one; only the
490 name stays local, same as the tabs. */
491 .time-selector button {
492 border: none;
493 padding: var(--gap-peer) var(--gap-section);
494 font-family: inherit;
495 font-size: var(--text-note);
496 cursor: pointer;
497 }
498
499 .time-selector button.is-selected {
500 background: var(--surface-well, var(--surface-page));
501 box-shadow: var(--bevel-inset);
502 }
503
504 /* Analytics */
505 .analytics-grid {
506 display: grid;
507 grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
508 gap: var(--gap-pane);
509 margin-bottom: var(--gap-pane);
510 }
511 .analytics-list {
512 list-style: none;
513 }
514
515 .analytics-list li {
516 padding: var(--gap-peer) 0;
517 border-bottom: 1px solid var(--border);
518 display: flex;
519 justify-content: space-between;
520 }
521
522 .analytics-list li:last-child {
523 border-bottom: none;
524 }
525
526 /* Filter controls */
527 .filter-controls {
528 display: flex;
529 gap: var(--gap-section);
530 margin-bottom: var(--gap-section);
531 flex-wrap: wrap;
532 align-items: center;
533 }
534
535 .filter-group {
536 display: flex;
537 gap: var(--gap-peer);
538 align-items: center;
539 }
540 /* UUID styling */
541 .uuid {
542 font-family: inherit;
543 opacity: 0.5;
544 font-size: var(--text-note);
545 }
546