Skip to main content

max / makenotwork

26.1 KB · 919 lines History Blame Raw
1 /* ===========================================
2 PROFILE TAB (replaces inline styles in partials/tabs/user_profile.html)
3 =========================================== */
4
5 /* Inline form row: input(s) + button laid out horizontally, bottom-aligned.
6 Distinct from .form-row (which is a 1fr 1fr grid). */
7 .field-row {
8 display: flex;
9 gap: var(--gap-section);
10 align-items: flex-end;
11 }
12 .field-row > .form-group { margin-bottom: 0; }
13 .field-row > .form-group.is-grow { flex: 1; }
14 .field-row > .form-group.is-grow-2 { flex: 2; }
15 .field-row > button { margin-bottom: 0; }
16
17 /* Custom domain section. */
18 .profile-domain-header { margin-bottom: var(--gap-section); }
19 .profile-domain-status {
20 margin-left: var(--gap-peer);
21 }
22 .profile-domain-status.is-verified { color: var(--success); }
23 .profile-domain-status.is-pending { color: var(--warning); }
24
25 .dns-row {
26 display: flex;
27 align-items: center;
28 gap: var(--gap-peer);
29 margin-bottom: var(--gap-peer);
30 }
31 .dns-row:last-of-type { margin-bottom: 0; }
32 .dns-row-label {
33 font-size: var(--text-fine);
34 opacity: 0.7;
35 min-width: 70px;
36 }
37 .dns-row-value {
38 font-size: var(--text-note);
39 flex: 1;
40 }
41 .dns-row-copy {
42 padding: var(--gap-bound) var(--gap-peer);
43 font-size: var(--text-fine);
44 }
45 .profile-domain-actions {
46 display: flex;
47 gap: var(--gap-section);
48 }
49 .profile-domain-result { margin-top: var(--gap-section); }
50 .profile-domain-lead {
51 font-size: var(--text-note);
52 opacity: 0.8;
53 }
54 .profile-domain-add-result { margin-top: var(--gap-section); }
55
56 /* Personal feed row: URL input + Copy button. */
57 .profile-feed-row {
58 display: flex;
59 gap: var(--gap-peer);
60 align-items: center;
61 }
62 .profile-feed-input {
63 flex: 1;
64 font-size: var(--text-note);
65 font-family: var(--font-mono);
66 opacity: 0.8;
67 }
68 .profile-feed-lead { margin-bottom: var(--gap-section); }
69
70 .purchase-page .checkout-footer {
71 margin-top: var(--gap-page);
72 padding-top: var(--gap-pane);
73 border-top: 1px solid var(--border);
74 opacity: 0.6;
75 text-align: center;
76 font-size: var(--text-note);
77 }
78
79 .purchase-page .checkout-footer a { color: var(--content); }
80
81 @media (max-width: 599px) {
82 .purchase-page .container { padding: 0 var(--gap-section); }
83 .purchase-page .item-summary { flex-direction: column; }
84 .purchase-page .item-thumbnail { width: 100%; height: 160px; }
85 .purchase-page .checkout-box { padding: var(--gap-pane); }
86 .purchase-page h2 { font-size: var(--text-head); }
87 }
88
89 /* Feed page (src/quasi/feeds.rs). Compact tabular layout of items from
90 followed users / projects / tags.
91
92 The page is described rather than templated as of 2026-08-31, so the
93 selectors below name what quasi and makeover emit. It has no .container:
94 a described document is <body> > <main> > the screen's region, so the 900px
95 measure the container carried sits on <main> here. */
96 .feed-page main { max-width: 900px; margin: 0 auto; padding: var(--gap-page); }
97
98 .feed-page main h1 { font-size: var(--text-head); margin-bottom: var(--gap-section); }
99
100 /* The "Showing X-Y of N items" line, which the description states as a plain
101 text node above the table. */
102 .feed-page .pane > p.text {
103 font-size: var(--text-fine);
104 opacity: 0.6;
105 margin-bottom: var(--gap-section);
106 }
107
108 .feed-page .table-head {
109 /* respec-ok: the same five-column grid the rows carry, on the heading row
110 that has to line up with them. */
111 display: grid;
112 grid-template-columns: 50px 1fr 100px 70px 70px;
113 gap: var(--gap-peer);
114 padding: var(--gap-peer) var(--gap-section);
115 background: var(--surface-overlay);
116 font-size: var(--text-fine);
117 opacity: 0.7;
118 text-transform: uppercase;
119 letter-spacing: 0.03em;
120 }
121
122 .feed-page .table {
123 border: 1px solid var(--border);
124 }
125
126 .feed-page .table-row {
127 /* respec-ok: a five-column grid template. The generated `.table-row` sets a
128 display but has no vocabulary for column tracks, so the tracks and the
129 display that carries them are stated together here. */
130 display: grid;
131 grid-template-columns: 50px 1fr 100px 70px 70px;
132 gap: var(--gap-peer);
133 padding: var(--gap-peer) var(--gap-section);
134 align-items: center;
135 text-decoration: none;
136 color: var(--content);
137 font-size: var(--text-note);
138 border-bottom: 1px solid var(--border);
139 transition: background 0.1s ease;
140 }
141
142 .feed-page .table-row:last-child { border-bottom: none; }
143 .feed-page .table-row:hover { background: var(--surface-sunken); }
144
145 /* The two-line name cell: `Cell::part` puts the creator under the name in one
146 cell, and each part is emitted as its own `.cell-value`. */
147 .feed-page .col-Name {
148 display: flex;
149 flex-direction: column;
150 gap: var(--gap-bound);
151 min-width: 0;
152 }
153
154 .feed-page .table-row .col-Name .cell-value:first-child {
155 white-space: nowrap;
156 overflow: hidden;
157 text-overflow: ellipsis;
158 }
159
160 .feed-page .table-row .col-Name .cell-value:last-child {
161 font-size: var(--text-fine);
162 opacity: 0.5;
163 }
164
165 /* The feed's badges shout a little: caps and tracking. The sunken fill that
166 used to come with them went with the filled-badge form in B2. */
167 .feed-page .badge {
168 text-transform: uppercase;
169 letter-spacing: 0.03em;
170 }
171
172 /* The empty state and the numbered strip carry no page-specific rules any
173 more: `Node::empty` and `Rest` emit their own classes, styled once for every
174 described screen rather than again per page. */
175
176 @media (max-width: 599px) {
177 .feed-page main { padding: var(--gap-section); }
178 .feed-page .table-head,
179 .feed-page .table-row { grid-template-columns: 1fr 70px; }
180 /* Name and Date survive the narrow viewport, which is what the five-column
181 header dropped to before the conversion. */
182 .feed-page .col-Type,
183 .feed-page .col-Tag,
184 .feed-page .col-Price { display: none; }
185 }
186
187 /* (Stripe Connect disclaimer page rules defined in the canonical
188 STRIPE DISCLAIMER PAGE section near end of file.) */
189
190 /* The creators page moved to the description layer. Its headings, its ordered
191 list, its stat box, its four-column table and its call-to-action box are the
192 design system's now: the count is a `Figure`, the tiers are a `Node::Table`
193 with stated column widths, and the CTA is one or two `Act`s. `.wave-table`
194 went with it and had no other user. */
195
196 /* Tag tree browse page (templates/pages/tag_tree.html). */
197 .tag-tree-page .breadcrumbs {
198 font-size: var(--text-note);
199 margin-bottom: var(--gap-pane);
200 opacity: 0.7;
201 }
202 .tag-tree-page .breadcrumbs a:hover { opacity: 0.6; }
203 .tag-tree-page .breadcrumbs .sep { margin: 0 var(--gap-bound); opacity: 0.4; }
204
205 .tag-tree-page .tag-grid {
206 display: grid;
207 grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
208 gap: var(--gap-section);
209 }
210
211 .tag-tree-page .tag-card {
212 background: var(--surface-sunken);
213 padding: var(--gap-section);
214 text-decoration: none;
215 color: var(--content);
216 border: 1px solid var(--border);
217 transition: background 0.1s ease;
218 }
219
220 .tag-tree-page .tag-card:hover {
221 background: var(--surface-sunken);
222 text-decoration: none;
223 }
224
225 .tag-tree-page .tag-card-name {
226 font-family: var(--font-display);
227 font-weight: bold;
228 font-size: var(--text-body);
229 }
230
231 .tag-tree-page .tag-card-meta {
232 font-size: var(--text-fine);
233 opacity: 0.5;
234 margin-top: var(--gap-bound);
235 }
236
237 .tag-tree-page .empty-state {
238 opacity: 0.5;
239 font-size: var(--text-note);
240 padding: var(--gap-page) 0;
241 }
242
243 /* Confirm delete prompt (templates/pages/confirm_delete.html). Overrides
244 the global .warning-box to use --danger-bg (matches the delete-account
245 semantic). Also tokenized previously-broken fallbacks. */
246 .confirm-delete-page .warning-box {
247 background: color-mix(in oklch, var(--danger) 10%, var(--surface-page));
248 border: 1px solid var(--danger);
249 border-radius: var(--radius-panel);
250 padding: var(--gap-pane);
251 margin-bottom: var(--gap-pane);
252 }
253
254 .confirm-delete-page .warning-box p {
255 margin: 0;
256 color: var(--danger);
257 }
258
259 /* Project paywall page (templates/pages/project_paywall.html). */
260 .project-paywall-page .paywall-cover { margin-bottom: var(--gap-pane); }
261 .project-paywall-page .paywall-cover img {
262 width: 120px;
263 height: 120px;
264 border-radius: var(--radius-panel);
265 object-fit: cover;
266 }
267
268 .project-paywall-page .paywall-title {
269 font-family: var(--font-display);
270 font-size: var(--text-hero);
271 margin-bottom: var(--gap-peer);
272 }
273
274 .project-paywall-page .paywall-creator {
275 font-size: var(--text-body);
276 opacity: 0.7;
277 margin-bottom: var(--gap-pane);
278 }
279
280 .project-paywall-page .paywall-creator a { color: var(--content); }
281
282 .project-paywall-page .paywall-description {
283 font-size: var(--text-lead);
284 max-width: 800px;
285 margin: 0 auto var(--gap-page);
286 text-align: left;
287 }
288
289 .project-paywall-page .paywall-item-count {
290 font-size: var(--text-body);
291 opacity: 0.7;
292 margin-bottom: var(--gap-peer);
293 }
294
295 .project-paywall-page .paywall-tiers {
296 display: grid;
297 grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
298 gap: var(--gap-pane);
299 margin-top: var(--gap-pane);
300 text-align: left;
301 }
302
303 .project-paywall-page .paywall-tiers .tier-card {
304 background: var(--surface-overlay);
305 padding: var(--gap-page);
306 display: flex;
307 flex-direction: column;
308 }
309
310 .project-paywall-page .paywall-tiers .tier-card h3 {
311 font-family: var(--font-display);
312 font-weight: bold;
313 font-size: var(--text-subhead);
314 margin-bottom: var(--gap-peer);
315 }
316
317 .project-paywall-page .paywall-tiers .tier-price {
318 font-size: var(--text-head);
319 margin-bottom: var(--gap-section);
320 }
321
322 .project-paywall-page .paywall-tiers .tier-card form,
323 .project-paywall-page .paywall-tiers .tier-card .button { margin-top: auto; }
324
325 .project-paywall-page .paywall-tiers .tier-card button,
326 .project-paywall-page .paywall-tiers .tier-card .button { width: 100%; }
327
328 /* Collection detail page (templates/pages/collection.html). */
329 /* The collection page moved to the description layer. Its header, its owner
330 line, its per-item rows and its empty state are the design system's now: the
331 items are a `Node::Table` whose meta line became three droppable columns
332 rather than one string that wraps, and the empty state is `Node::empty`.
333 What is left is the measure, on <main>. */
334 .collection-page main { max-width: 700px; }
335
336 /* Project blog index page. Twelve rules stood here for markup the template
337 wrote by hand -- `.blog-header`, `.post-entry`, `.post-title` and the rest.
338 The page is a described screen (`crate::quasi::project_blog`) and its
339 heading, list and rows are makeover's, which is what the design system is
340 for. What is left is the one thing that is this page's rather than the
341 system's. */
342 .project-blog-page main { max-width: 800px; }
343
344 /* Canonical "page-level h1", left-aligned, smaller than the global centered
345 default. Used by dashboards, admin, health, import, delete-account, export,
346 receipt. Aliased via comma-grouped selectors so each page picks it up via
347 its body class without redefining. */
348 .dashboard-page h1,
349 .admin-page h1,
350 .health-page h1,
351 .import-page h1,
352 .delete-account-page h1,
353 .export-page h1,
354 .receipt-page h1 {
355 font-size: var(--text-title);
356 margin-bottom: var(--gap-peer);
357 text-align: left;
358 }
359 .delete-account-page h1 { color: var(--danger); }
360
361 /* Canonical subtitle under a page h1, muted, with bottom space. */
362 .health-page .subtitle,
363 .import-page .subtitle,
364 .delete-account-page .subtitle,
365 .export-page .subtitle {
366 opacity: 0.7;
367 margin-bottom: var(--gap-page);
368 text-align: left;
369 }
370 .health-page .subtitle { text-align: center; }
371
372 /* User Settings tab (templates/partials/tabs/user_settings.html).
373 Left-rail nav layout for the Settings dashboard tab. Selection uses the
374 canonical .is-selected modifier. */
375 .settings-layout { display: flex; gap: var(--gap-page); }
376 .settings-nav { flex-shrink: 0; min-width: 140px; }
377 .settings-nav a {
378 display: block;
379 padding: var(--gap-peer) var(--gap-section);
380 text-decoration: none;
381 color: var(--content);
382 opacity: 0.6;
383 font-family: var(--font-mono);
384 font-size: var(--text-note);
385 transition: opacity 0.15s ease;
386 }
387 .settings-nav a:hover { opacity: 1; }
388 .settings-nav a.is-selected { opacity: 1; background: var(--surface-sunken); }
389 .settings-body { flex: 1; min-width: 0; }
390 @media (max-width: 839px) {
391 .settings-layout { flex-direction: column; gap: var(--gap-section); }
392 .settings-nav { display: flex; flex-wrap: wrap; gap: 0; min-width: 0; }
393 .settings-nav a { padding: var(--gap-peer) var(--gap-group); font-size: var(--text-note); }
394 }.library-page .feed-table-header {
395 display: grid;
396 grid-template-columns: 50px 1fr 100px 70px 70px;
397 gap: var(--gap-peer);
398 padding: var(--gap-peer) var(--gap-section);
399 background: var(--surface-overlay);
400 font-size: var(--text-fine);
401 opacity: 0.7;
402 text-transform: uppercase;
403 letter-spacing: 0.03em;
404 }
405 .library-page .feed-col-right { text-align: right; }
406 .library-page .feed-results-table { border: 1px solid var(--border); border-top: none; }
407 .library-page .feed-table-row {
408 display: grid;
409 grid-template-columns: 50px 1fr 100px 70px 70px;
410 gap: var(--gap-peer);
411 padding: var(--gap-peer) var(--gap-section);
412 align-items: center;
413 text-decoration: none;
414 color: var(--content);
415 font-size: var(--text-note);
416 border-bottom: 1px solid var(--border);
417 transition: background 0.1s ease;
418 }
419 .library-page .feed-table-row:last-child { border-bottom: none; }
420 .library-page .feed-table-row:hover { background: var(--surface-sunken); }
421 .library-page .feed-item-name-cell {
422 display: flex;
423 flex-direction: column;
424 gap: var(--gap-bound);
425 min-width: 0;
426 }
427 .library-page .feed-item-name {
428 white-space: nowrap;
429 overflow: hidden;
430 text-overflow: ellipsis;
431 }
432 .library-page .feed-item-creator { font-size: var(--text-fine); opacity: 0.5; }
433 .library-page .feed-pagination {
434 display: flex;
435 gap: var(--gap-bound);
436 justify-content: center;
437 margin-top: var(--gap-section);
438 }
439 .library-page .feed-pagination a,
440 .library-page .feed-pagination span {
441 padding: var(--gap-peer) var(--gap-section);
442 font-size: var(--text-note);
443 text-decoration: none;
444 color: var(--content);
445 border: 1px solid var(--border);
446 }
447 .library-page .feed-pagination span.current {
448 background: var(--primary-dark);
449 color: var(--primary-light);
450 border-color: var(--primary-dark);
451 }
452 .library-page .feed-pagination a:hover { background: var(--surface-sunken); }
453 @media (max-width: 599px) {
454 .library-page .feed-table-header,
455 .library-page .feed-table-row {
456 grid-template-columns: 1fr 70px;
457 }
458 .library-page .feed-table-header span:nth-child(1),
459 .library-page .feed-table-row .badge:first-child,
460 .library-page .feed-table-header span:nth-child(3),
461 .library-page .feed-table-header span:nth-child(4),
462 .library-page .feed-table-row span:nth-child(3),
463 .library-page .feed-table-row span:nth-child(4) {
464 display: none;
465 }
466 }
467
468 /* User-level dashboard (templates/dashboards/dashboard-user.html).
469 Scoped under .dashboard-user-page to avoid colliding with .project-card
470 / .project-title / .project-meta on the public profile (user.html) and
471 the user_projects tab partial. */
472 .dashboard-user-page .stat-value { font-size: var(--text-title); margin-bottom: var(--gap-bound); }
473
474 .dashboard-user-page .project-card {
475 background: var(--surface-overlay);
476 padding: var(--gap-pane);
477 margin-bottom: var(--gap-section);
478 display: flex;
479 justify-content: space-between;
480 align-items: flex-start;
481 }
482
483 .dashboard-user-page .project-info { flex: 1; }
484
485 .dashboard-user-page .project-title {
486 font-family: var(--font-display);
487 font-weight: bold;
488 font-size: var(--text-subhead);
489 margin-bottom: var(--gap-bound);
490 }
491
492 .dashboard-user-page .project-meta {
493 font-size: var(--text-note);
494 opacity: 0.7;
495 margin-bottom: var(--gap-peer);
496 }
497
498 .dashboard-user-page .project-stats { font-size: var(--text-note); }
499 .dashboard-user-page .project-actions {
500 display: flex;
501 gap: var(--gap-peer);
502 }
503
504 .dashboard-user-page .project-actions button {
505 padding: var(--gap-peer) var(--gap-section);
506 font-size: var(--text-note);
507 }
508 @media (max-width: 839px) {
509 .dashboard-user-page .project-card { flex-direction: column; }
510 .dashboard-user-page .project-actions { margin-top: var(--gap-section); }
511 }
512
513 /* Project dashboard (templates/dashboards/dashboard-project.html). */
514 .dashboard-project-page .project-meta { font-size: var(--text-note); opacity: 0.7; }
515 .dashboard-project-page .stat-value { font-size: var(--text-title); margin-bottom: var(--gap-bound); }
516
517 .dashboard-project-page .content-header {
518 display: flex;
519 justify-content: space-between;
520 align-items: center;
521 margin-bottom: var(--gap-pane);
522 }
523
524 .dashboard-project-page .content-header h2 { font-size: var(--text-subhead); }
525
526 .dashboard-project-page .item-thumbnail {
527 width: 40px;
528 height: 40px;
529 background: var(--border);
530 display: inline-block;
531 vertical-align: middle;
532 margin-right: var(--gap-peer);
533 }
534
535 .dashboard-project-page .item-actions {
536 display: flex;
537 gap: var(--gap-peer);
538 }
539
540 .dashboard-project-page .item-actions button {
541 padding: var(--gap-peer) var(--gap-section);
542 font-size: var(--text-note);
543 }
544
545 .dashboard-project-page .data-section { margin-bottom: var(--gap-page); }
546
547 .dashboard-project-page .data-section h2 {
548 font-size: var(--text-subhead);
549 margin-bottom: var(--gap-section);
550 padding-bottom: var(--gap-peer);
551 border-bottom: 1px solid var(--border);
552 }
553
554 /* Item dashboard (templates/dashboards/dashboard-item.html). */
555 .dashboard-item-page .item-meta {
556 font-size: var(--text-note);
557 opacity: 0.7;
558 display: flex;
559 gap: var(--gap-section);
560 align-items: center;
561 }
562
563 .dashboard-item-page .stat-value { font-size: var(--text-head); }
564
565 .dashboard-item-page .section-header {
566 display: flex;
567 justify-content: space-between;
568 align-items: center;
569 margin-bottom: var(--gap-pane);
570 padding-bottom: var(--gap-section);
571 border-bottom: 1px solid var(--border);
572 }
573
574 .dashboard-item-page .section-header h2 { font-size: var(--text-subhead); }
575
576 @media (max-width: 839px) {
577 .dashboard-item-page .section-header {
578 flex-direction: column;
579 align-items: flex-start;
580 gap: var(--gap-section);
581 }
582 .dashboard-item-page .section-header .action-buttons { width: 100%; }
583 }
584
585 /* Changelog page (templates/pages/changelog.html). */
586 .changelog-page .container { max-width: 900px; margin: 0 auto; }
587 .changelog-page h1 { font-size: var(--text-display); margin-bottom: var(--gap-peer); }
588 .changelog-page .changelog-entry {
589 margin-bottom: var(--gap-page);
590 padding-bottom: var(--gap-page);
591 border-bottom: 1px solid var(--border);
592 }
593 .changelog-page .changelog-entry:last-child { border-bottom: none; }
594 .changelog-page .changelog-date {
595 font-family: var(--font-mono);
596 font-size: var(--text-note);
597 opacity: 0.6;
598 margin-bottom: var(--gap-peer);
599 }
600 .changelog-page .changelog-entry h2 { font-size: var(--text-subhead); margin-bottom: var(--gap-section); }
601 .changelog-page .changelog-entry ul {
602 padding-left: var(--gap-pane);
603 margin: var(--gap-peer) 0;
604 line-height: 1.7;
605 }
606 .changelog-page .changelog-entry li { margin-bottom: var(--gap-bound); }
607
608 /* Policy page (templates/pages/policy.html). */
609 /* The content policy moved to the description layer. Its headings, its section
610 spacing and its list indents are the design system's now; the prose itself
611 goes through docengine, the same renderer `/docs/*` uses. What is left is the
612 measure, on <main> rather than on a `.container`, as every converted document
613 does. */
614 .policy-page main { max-width: 900px; margin: 0 auto; }
615
616 /* Admin page extras (in addition to global .admin-page h1). */
617 .admin-page .metrics-grid {
618 display: grid;
619 grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
620 gap: var(--gap-section);
621 margin-bottom: var(--gap-page);
622 }
623
624 .admin-page .metric-card {
625 padding: var(--gap-section);
626 border: 1px solid var(--border);
627 border-radius: var(--radius-square);
628 }
629
630 .admin-page .metric-card .value {
631 font-size: var(--text-title);
632 font-family: var(--font-mono);
633 font-weight: 600;
634 }
635
636 .admin-page .metric-card .label {
637 font-size: var(--text-note);
638 color: var(--content-muted);
639 margin-top: var(--gap-bound);
640 }
641
642 .admin-page .metric-card.warn .value { color: var(--warning); }
643 .admin-page .metric-card.error .value { color: var(--danger); }
644
645 .admin-page .section-heading {
646 font-size: var(--text-subhead);
647 margin: var(--gap-pane) 0 var(--gap-section);
648 font-family: var(--font-mono);
649 }
650
651 /* Scan pipeline dashboard. See docs/scan-pipeline-audit.md § 5. */
652
653 .admin-scan-section {
654 margin-top: var(--gap-page);
655 }
656
657 .admin-section-header {
658 display: flex;
659 justify-content: space-between;
660 align-items: baseline;
661 margin-bottom: var(--gap-section);
662 gap: var(--gap-section);
663 }
664
665 /* Typeface comes from .subsection-title on the heading itself; this sets only
666 what the flex row needs. */
667 .admin-section-header h2 {
668 font-size: var(--text-lead);
669 margin: 0;
670 }
671
672 .layer-health-grid {
673 display: grid;
674 grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
675 gap: var(--gap-section);
676 }
677
678 .layer-health-card {
679 padding: var(--gap-section);
680 border: 1px solid var(--border);
681 border-radius: var(--radius-square);
682 border-left-width: 4px;
683 font-size: var(--text-note);
684 }
685
686 .layer-health-card .layer-name {
687 font-family: var(--font-mono);
688 font-weight: 600;
689 font-size: var(--text-body);
690 margin-bottom: var(--gap-peer);
691 }
692
693 .layer-health-card .layer-stat {
694 display: flex;
695 justify-content: space-between;
696 margin-bottom: 2px;
697 }
698
699 .layer-health-card .layer-stat .dimmed {
700 color: var(--content-muted);
701 }
702
703 .layer-health-card.layer-ok { border-left-color: var(--success); }
704 .layer-health-card.layer-degraded { border-left-color: var(--warning); }
705 .layer-health-card.layer-down { border-left-color: var(--danger); }
706
707 .layer-chips {
708 display: flex;
709 flex-wrap: wrap;
710 gap: 4px;
711 max-width: 360px;
712 }
713
714 .layer-chip {
715 display: inline-block;
716 font-family: var(--font-mono);
717 font-size: var(--text-fine);
718 padding: 1px 6px;
719 border-radius: var(--radius-control);
720 border: 1px solid transparent;
721 cursor: help;
722 line-height: 1.4;
723 }
724
725 .layer-chip-pass { background: color-mix(in oklch, var(--success) 12%, var(--surface-page)); border-color: var(--success); color: var(--success); }
726 .layer-chip-skip { background: var(--surface-page); border-color: var(--border); color: var(--content-muted); }
727 .layer-chip-fail { background: color-mix(in oklch, var(--danger) 10%, var(--surface-page)); border-color: var(--danger); color: var(--danger); font-weight: 600; }
728 .layer-chip-error { background: color-mix(in oklch, var(--warning) 14%, var(--surface-page)); border-color: var(--warning); color: var(--warning); font-weight: 600; }
729
730 .scan-history-grid table { font-size: var(--text-note); }
731
732 .scan-history-grid summary {
733 cursor: pointer;
734 font-family: var(--font-mono);
735 padding: var(--gap-peer) 0;
736 user-select: none;
737 }
738
739 .scan-row-meta {
740 font-size: var(--text-fine);
741 color: var(--content-muted);
742 margin-top: 2px;
743 }
744
745 .audit-filter-form {
746 display: flex;
747 flex-wrap: wrap;
748 align-items: flex-end;
749 gap: var(--gap-section);
750 padding: var(--gap-section) 0;
751 margin-bottom: var(--gap-section);
752 border-bottom: 1px solid var(--border);
753 }
754
755 .audit-filter-form label {
756 display: flex;
757 flex-direction: column;
758 gap: 2px;
759 }
760
761 .audit-filter-form input,
762 .audit-filter-form select {
763 font-size: var(--text-note);
764 }
765
766 .layer-chips-cell { vertical-align: top; }
767
768 .layer-detail-disclosure {
769 margin-top: var(--gap-peer);
770 }
771
772 .layer-detail-disclosure summary {
773 cursor: pointer;
774 user-select: none;
775 padding: 2px 0;
776 }
777
778 .layer-detail-list {
779 margin: var(--gap-peer) 0 0;
780 display: grid;
781 grid-template-columns: max-content 1fr;
782 gap: 2px var(--gap-section);
783 font-size: var(--text-fine);
784 }
785
786 .layer-detail-list dt {
787 font-family: var(--font-mono);
788 }
789
790 .layer-detail-list dd {
791 margin: 0;
792 color: var(--content-muted);
793 word-break: break-word;
794 }
795
796 .admin-page table {
797 width: 100%;
798 border-collapse: collapse;
799 font-size: var(--text-note);
800 }
801
802 .admin-page th,
803 .admin-page td {
804 text-align: left;
805 padding: var(--gap-peer) var(--gap-group);
806 border-bottom: 1px solid var(--border);
807 }
808
809 .admin-page th {
810 font-family: var(--font-mono);
811 font-size: var(--text-fine);
812 text-transform: uppercase;
813 color: var(--content-muted);
814 }
815
816 .admin-page td.mono { font-family: var(--font-mono); }
817
818 .admin-page .refresh-note {
819 font-size: var(--text-fine);
820 color: var(--content-muted);
821 margin-bottom: var(--gap-section);
822 font-family: var(--font-mono);
823 }
824
825 .admin-page .appeal-count {
826 font-size: var(--text-note);
827 opacity: 0.7;
828 margin-bottom: var(--gap-pane);
829 }
830
831 .admin-page .decide-form {
832 display: flex;
833 gap: var(--gap-peer);
834 align-items: flex-end;
835 flex-wrap: wrap;
836 }
837
838 .admin-page .decide-form textarea {
839 min-width: 200px;
840 font-size: var(--text-note);
841 }
842
843 .admin-page .suspend-form {
844 display: flex;
845 gap: var(--gap-peer);
846 align-items: flex-end;
847 }
848
849 .admin-page .suspend-form input[type="text"] {
850 min-width: 200px;
851 font-size: var(--text-note);
852 }
853
854 .admin-page .lottery-form {
855 background: var(--surface-overlay);
856 padding: var(--gap-pane);
857 margin: var(--gap-pane) 0;
858 display: flex;
859 gap: var(--gap-section);
860 align-items: flex-end;
861 }
862
863 .admin-page .lottery-form .form-group { margin-bottom: 0; }
864
865 .admin-page .lottery-form label {
866 font-size: var(--text-note);
867 display: block;
868 margin-bottom: var(--gap-bound);
869 }
870
871 .admin-page .lottery-form input[type="number"] { width: 80px; }
872
873 /* Page-top notice (charter primitive, replaces #restart-banner and
874 the inline sandbox banner in dashboard-project). Full-bleed across
875 the viewport, monospace, one short sentence + optional action.
876 Hero callouts on the landing page use `.alert` instead (multi-paragraph). */
877 .banner {
878 padding: var(--gap-section) var(--gap-pane);
879 font-family: var(--font-mono);
880 font-size: var(--text-note);
881 text-align: center;
882 color: var(--content);
883 }
884
885 .banner--info {
886 background: var(--highlight-faint);
887 border-bottom: 2px solid var(--focus-ring);
888 }
889
890 .banner--warning {
891 background: color-mix(in oklch, var(--warning) 14%, var(--surface-page));
892 border-bottom: 2px solid var(--warning);
893 }
894
895 /* A described `Node::Notice` carries its tone as an attribute rather than in
896 the class, which is what `quasi-webview` emits and what `makeover` keys every
897 other tone off. The two `banner--` modifiers above are this site's own
898 full-bleed notices and are untouched. */
899 .banner[data-tone="danger"] {
900 background: color-mix(in oklch, var(--danger) 14%, var(--surface-page));
901 border-bottom: 2px solid var(--danger);
902 }
903
904 .banner[data-tone="success"] {
905 background: color-mix(in oklch, var(--success) 14%, var(--surface-page));
906 border-bottom: 2px solid var(--success);
907 }
908
909 .banner[data-tone="info"] {
910 background: var(--highlight-faint);
911 border-bottom: 2px solid var(--focus-ring);
912 }
913
914 .banner a {
915 color: inherit;
916 text-decoration: underline;
917 }
918
919