Skip to main content

max / makenotwork

65.8 KB · 2630 lines History Blame Raw
1 /* ===========================================
2 PAYMENTS TAB (replaces inline styles in user_payments.html)
3 =========================================== */
4 /* Canonical "stack row", title-on-left + actions-on-right header bar.
5 One primitive; per-context modifiers handle gap, wrap, alignment, margins.
6 Aliases below cover existing per-tab class names (kept as JS hooks). */
7 .stack-row,
8 .content-header,
9 .user-media-header,
10 .transactions-header,
11 .analytics-range-bar,
12 .cart-multi-bar {
13 display: flex;
14 justify-content: space-between;
15 align-items: center;
16 flex-wrap: wrap;
17 gap: var(--gap-section);
18 }
19 .stack-row--tight { gap: var(--gap-section); flex-wrap: nowrap; }
20 .stack-row--top { align-items: flex-start; }
21 .stack-row--bordered,
22 .transactions-header {
23 margin-bottom: var(--gap-section);
24 padding-bottom: var(--gap-section);
25 border-bottom: 1px solid var(--border);
26 }
27 .content-header,
28 .user-media-header,
29 .analytics-range-bar { margin-bottom: var(--gap-section); }
30 .cart-multi-bar {
31 margin-bottom: var(--gap-pane);
32 padding: var(--gap-section);
33 background: var(--surface-sunken);
34 border: 1px solid var(--border);
35 }
36
37 /* Canonical list row (flex, gap, padding, bottom border). Aliases below cover
38 the per-tab variants. They exist as JS hooks but share the same look. */
39 .list-row,
40 .psection-row,
41 .section-mgmt-row,
42 .bundle-picker-row,
43 .checklist-row {
44 display: flex;
45 align-items: center;
46 gap: var(--gap-section);
47 padding: var(--gap-group) 0;
48 border-bottom: 1px solid var(--border);
49 }
50 .list-row:last-child,
51 .psection-row:last-child,
52 .section-mgmt-row:last-child,
53 .bundle-picker-row:last-child,
54 .checklist-row:last-child { border-bottom: none; }
55 .warn-glyph {
56 font-size: var(--text-subhead);
57 color: var(--warning);
58 }
59
60 .card-h {
61 margin: 0 0 var(--gap-section) 0;
62 font-size: var(--text-body);
63 }
64
65 .amount-big {
66 font-size: var(--text-subhead);
67 font-weight: bold;
68 }
69
70 .account-details {
71 margin-top: var(--gap-section);
72 padding-top: var(--gap-section);
73 border-top: 1px solid var(--border);
74 }
75 .account-details summary { cursor: pointer; }
76 .account-details-id {
77 font-size: var(--text-fine);
78 opacity: 0.5;
79 font-family: var(--font-mono);
80 margin-top: var(--gap-bound);
81 }
82
83 .stripe-actions {
84 display: flex;
85 gap: var(--gap-section);
86 flex-wrap: wrap;
87 }
88 .stripe-actions-disconnect { margin-left: auto; }
89
90 .fee-breakdown {
91 display: grid;
92 grid-template-columns: 1fr 1fr;
93 gap: var(--gap-peer);
94 font-size: var(--text-note);
95 }
96 .fee-row {
97 display: flex;
98 justify-content: space-between;
99 padding: var(--gap-peer) 0;
100 border-bottom: 1px solid var(--border);
101 }
102
103 .checkbox-row {
104 display: flex;
105 align-items: flex-start;
106 gap: var(--gap-peer);
107 cursor: pointer;
108 font-size: var(--text-note);
109 }
110 .check-inline {
111 width: auto;
112 margin-top: var(--gap-bound);
113 }
114
115 .stripe-connect-prompt { text-align: center; padding: var(--gap-pane); }
116 .stripe-logo { opacity: 0.8; }
117 .stripe-connect-btn {
118 background: var(--stripe);
119 padding: var(--gap-section) var(--gap-page);
120 }
121
122 .export-row {
123 display: flex;
124 justify-content: flex-end;
125 margin-bottom: var(--gap-section);
126 }
127
128 .splits-grid {
129 display: grid;
130 grid-template-columns: 1fr 1fr;
131 gap: var(--gap-section);
132 margin-bottom: var(--gap-section);
133 }
134
135 .tip-message {
136 max-width: 300px;
137 overflow: hidden;
138 text-overflow: ellipsis;
139 }
140
141 .transactions-title { font-size: var(--text-subhead); }
142
143 /* ===========================================
144 CREATOR TAB (replaces inline styles in user_creator.html)
145 =========================================== */
146 .creator-tab-section {
147 padding: var(--gap-page);
148 }
149 .creator-tab-section--centered { text-align: center; }
150 .creator-tab-section--no-top { padding-top: 0; }
151
152 .creator-h2 { font-size: var(--text-subhead); margin-bottom: var(--gap-section); }
153 .creator-h2--sm { font-size: var(--text-subhead); }
154
155 .creator-section-label {
156 margin-left: var(--gap-page);
157 margin-right: var(--gap-page);
158 }
159 .creator-form-section { padding: 0 var(--gap-page); }
160
161 .creator-plan-box {
162 background: var(--surface-overlay);
163 padding: var(--gap-section) var(--gap-pane);
164 }
165 .creator-plan-head {
166 display: flex;
167 align-items: center;
168 gap: var(--gap-section);
169 margin-bottom: var(--gap-peer);
170 flex-wrap: wrap;
171 }
172 .creator-plan-name {
173 font-family: var(--font-display);
174 font-weight: bold;
175 font-size: var(--text-lead);
176 }
177
178 /* Founder pricing, two states, and neither is a status tone: locked-for-life
179 is emphasis and pending-lock-in is an aside. They were a --content fill and
180 a --surface-sunken fill back when every badge was filled; as coloured text
181 the same distinction is full-strength ink against muted. */
182 .badge--founder-locked {
183 color: var(--content);
184 font-weight: bold;
185 }
186 .badge--founder-pending {
187 color: var(--content-muted);
188 }
189
190 .founder-callout {
191 background: var(--surface-overlay);
192 border-left: 3px solid var(--content);
193 padding: var(--gap-section);
194 }
195
196 .creator-tier-grid {
197 display: grid;
198 grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
199 gap: var(--gap-section);
200 }
201 .creator-tier-card {
202 background: var(--surface-overlay);
203 padding: var(--gap-section);
204 text-align: center;
205 }
206 .creator-tier-name {
207 font-family: var(--font-display);
208 font-weight: bold;
209 font-size: var(--text-body);
210 margin-bottom: var(--gap-bound);
211 }
212 .creator-tier-link {
213 color: inherit;
214 text-decoration: none;
215 border-bottom: 1px solid var(--border);
216 }
217 .creator-tier-sub {
218 font-size: var(--text-fine);
219 opacity: 0.7;
220 }
221 .creator-tier-storage { font-size: var(--text-fine); }
222 .creator-tier-buttons {
223 display: flex;
224 flex-direction: column;
225 gap: var(--gap-peer);
226 }
227 .creator-tier-btn {
228 font-size: var(--text-note);
229 width: 100%;
230 }
231
232 .strike-dim {
233 opacity: 0.5;
234 text-decoration: line-through;
235 }
236
237 .storage-box {
238 background: var(--surface-overlay);
239 padding: var(--gap-section) var(--gap-pane);
240 }
241 .storage-row {
242 display: flex;
243 justify-content: space-between;
244 margin-bottom: var(--gap-peer);
245 font-size: var(--text-note);
246 }
247 .storage-breakdown {
248 display: grid;
249 grid-template-columns: 1fr 1fr;
250 gap: var(--gap-bound) var(--gap-pane);
251 margin-top: var(--gap-section);
252 font-size: var(--text-note);
253 }
254
255 .broadcast-head {
256 display: flex;
257 justify-content: space-between;
258 align-items: flex-start;
259 }
260 .broadcast-desc { flex: 1; }
261 .broadcast-export { margin-left: var(--gap-section); }
262
263 .creator-divider {
264 margin: 0 var(--gap-page);
265 border-color: var(--border);
266 }
267
268 .creator-intro { line-height: 1.6; }
269 .creator-pitch-box {
270 background: var(--surface-overlay);
271 padding: var(--gap-pane);
272 }
273
274 .mono-sm {
275 font-family: var(--font-mono);
276 font-size: var(--text-note);
277 }
278
279 /* ===========================================
280 PROJECT CONTENT TAB (replaces inline styles in project_content.html)
281 =========================================== */
282
283 .empty-state--lg { padding: var(--gap-page) var(--gap-section); }
284
285 .content-filters {
286 display: flex;
287 gap: var(--gap-section);
288 margin-bottom: var(--gap-section);
289 align-items: center;
290 flex-wrap: wrap;
291 }
292 .content-filter-search {
293 flex: 1;
294 min-width: 180px;
295 padding: var(--gap-peer) var(--gap-group);
296 font-size: var(--text-note);
297 }
298 .content-filter-select {
299 padding: var(--gap-peer);
300 font-size: var(--text-note);
301 }
302
303 .bulk-action-bar {
304 padding: var(--gap-section);
305 margin-bottom: var(--gap-section);
306 background: var(--surface-raised);
307 border: 1px solid var(--border);
308 border-radius: var(--radius-square);
309 display: flex;
310 align-items: center;
311 gap: var(--gap-peer);
312 flex-wrap: wrap;
313 opacity: 0.4;
314 }
315 .bulk-action-bar--active { opacity: 1; }
316 .bulk-count { font-weight: bold; min-width: 5rem; }
317 .bulk-deselect { margin-left: auto; }
318 .danger-text { color: var(--danger); }
319
320 .bulk-form {
321 margin-bottom: var(--gap-section);
322 padding: var(--gap-section);
323 background: var(--surface-sunken);
324 border: 1px solid var(--border);
325 border-radius: var(--radius-square);
326 }
327 .bulk-form-row {
328 display: flex;
329 gap: var(--gap-section);
330 align-items: end;
331 }
332 .bulk-form-label {
333 font-size: var(--text-note);
334 display: block;
335 margin-bottom: var(--gap-bound);
336 }
337
338 /* Sortable table column header
339
340 The cursor and the caret are NOT here. `.table-heading[data-sortable]` and
341 `.table-heading[aria-sort="..."]::after` are generated into static/layout.css
342 by makeover-webview out of `Column::sortable` and `Column::sorted`. This file
343 carried two hand-written copies of the same fact -- `.sortable-th` here and
344 `.data-table th.sortable` up at the data-table block -- and a third channel in
345 tab-project-content.js, which wrote the glyph as text and toggled
346 `.sort-arrow--active`. Three vocabularies, one state, and the generated pair
347 matched nothing because no heading carried `.table-heading`.
348
349 The focus ring stays: it is this app's focus treatment, not a restatement of
350 the caret, and makeover emits no focus rule for a heading. */
351 .table-heading[data-sortable] {
352 user-select: none;
353 transition: background 0.2s ease;
354 }
355
356 .table-heading[data-sortable]:hover {
357 background: var(--border);
358 }
359
360 .table-heading[data-sortable]:focus-visible {
361 outline: 2px solid var(--focus-ring);
362 outline-offset: 2px;
363 }
364
365 /* Data-table column-width utilities (numeric width hints,
366 kept as classes to avoid inline `style="width: NN%"`) */
367 .col-3 { width: 3%; }
368 .col-5 { width: 5%; }
369 .col-8 { width: 8%; }
370 .col-10 { width: 10%; }
371 .col-12 { width: 12%; }
372 .col-15 { width: 15%; }
373 .col-20 { width: 20%; }
374 .col-32 { width: 32%; }
375 .col-45 { width: 45%; }
376
377 /* Pixel-width utilities for inputs and narrow fixed-width controls.
378 Use on form inputs that can't be sized by their parent column. */
379 .w-80 { width: 80px; }
380 .w-100 { width: 100px; }
381 .w-120 { width: 120px; }
382 .w-180 { width: 180px; }
383 .w-220 { width: 220px; }
384 .w-260 { width: 260px; }
385 .w-full { width: 100%; }
386 .maxw-320 { max-width: 320px; }
387
388 /* Canonical input shape modifiers. One base form-input look (defined globally
389 at line ~365 input[type], textarea, select) plus these size + feature variants.
390 Apply alongside the per-tab class which acts as a JS hook. */
391 .input--xs {
392 padding: var(--gap-bound) var(--gap-peer);
393 font-size: var(--text-note);
394 }
395 .input--sm {
396 padding: var(--gap-bound) var(--gap-peer);
397 font-size: var(--text-note);
398 }
399 .input--mono { font-family: var(--font-mono); }
400 .input--upper { text-transform: uppercase; }
401 .input--numeric { text-align: right; }
402
403 .order-arrow-btn {
404 padding: var(--gap-bound);
405 font-size: var(--text-fine);
406 line-height: 1;
407 }
408
409 .bundle-toggle {
410 background: none;
411 border: none;
412 cursor: pointer;
413 padding: 0 var(--gap-bound) 0 0;
414 font-size: var(--text-fine);
415 color: var(--content-muted);
416 }
417 .bundle-child-cell { padding-left: var(--gap-page); }
418 .bundle-child-title { opacity: 0.85; }
419 .bundle-child-arrow {
420 color: var(--content-muted);
421 margin-right: var(--gap-bound);
422 }
423
424 .item-actions {
425 display: flex;
426 gap: var(--gap-peer);
427 }
428
429 .badge--inline-tiny {
430 font-size: var(--text-fine);
431 margin-left: var(--gap-bound);
432 opacity: 0.7;
433 }
434
435 .deleted-items-details { margin-top: var(--gap-page); }
436 .deleted-items-summary {
437 cursor: pointer;
438 font-size: var(--text-body);
439 opacity: 0.7;
440 }
441
442 .section-divider {
443 margin: var(--gap-page) 0;
444 border: none;
445 border-top: 1px solid var(--border);
446 }
447
448 .inline-rename-input {
449 font-weight: bold;
450 width: 100%;
451 padding: var(--gap-bound) var(--gap-peer);
452 font-size: inherit;
453 }
454
455 /* ===========================================
456 ITEM DETAILS TAB (replaces inline styles in item_details.html)
457 =========================================== */
458
459 /* Compact button utility (small icon-side actions) */
460 .btn-compact { padding: var(--gap-peer) var(--gap-section); }
461
462 .ml-2 { margin-left: var(--gap-peer); }
463 .cursor-pointer { cursor: pointer; }
464 .inline { display: inline; }
465
466 .tag-search-wrap { position: relative; }
467 .tag-suggestions {
468 position: absolute;
469 z-index: var(--z-dropdown);
470 background: var(--surface-sunken);
471 border: 1px solid var(--border);
472 width: 100%;
473 max-height: 200px;
474 overflow-y: auto;
475 }
476
477 .advanced-details { margin-top: var(--gap-pane); }
478 .advanced-summary {
479 cursor: pointer;
480 font-size: var(--text-body);
481 opacity: 0.8;
482 }
483
484 /* Bundle table inside item-details */
485 .bundle-table {
486 width: 100%;
487 border-collapse: collapse;
488 }
489 .bundle-table-head {
490 text-align: left;
491 font-size: var(--text-fine);
492 opacity: 0.7;
493 text-transform: uppercase;
494 letter-spacing: 0.03em;
495 }
496 .bundle-row { border-bottom: 1px solid var(--border); }
497 .bundle-cell { padding: var(--gap-peer); }
498 .bundle-cell--first { padding-left: 0; }
499 .bundle-cell--actions { width: 60px; }
500 .bundle-cell--desc { font-size: var(--text-note); opacity: 0.8; }
501 .bundle-cell--file { font-size: var(--text-note); }
502
503 .bundle-remove-btn {
504 padding: var(--gap-bound) var(--gap-peer);
505 font-size: var(--text-fine);
506 }
507
508 .bundle-add-row {
509 margin-top: var(--gap-section);
510 display: flex;
511 gap: var(--gap-section);
512 align-items: center;
513 }
514
515 .bundle-existing-details { margin-top: var(--gap-section); }
516 .bundle-existing-summary {
517 cursor: pointer;
518 font-size: var(--text-note);
519 opacity: 0.7;
520 }
521 .bundle-existing-row {
522 margin-top: var(--gap-peer);
523 display: flex;
524 gap: var(--gap-peer);
525 align-items: center;
526 }
527 .bundle-existing-select {
528 flex: 1;
529 padding: var(--gap-peer);
530 }
531
532 .sections-intro {
533 font-size: var(--text-note);
534 opacity: 0.7;
535 margin: var(--gap-section) 0 var(--gap-section);
536 }
537
538 .section-mgmt-title {
539 flex: 1;
540 font-weight: bold;
541 }
542 .section-edit-btn,
543 .section-del-btn {
544 padding: var(--gap-bound) var(--gap-group);
545 font-size: var(--text-fine);
546 }
547
548 .section-add-details { margin-top: var(--gap-section); }
549 .section-add-summary {
550 cursor: pointer;
551 font-size: var(--text-body);
552 }
553
554 .section-edit-modal {
555 margin-top: var(--gap-section);
556 padding: var(--gap-section);
557 background: var(--surface-sunken);
558 }
559 .section-edit-actions {
560 display: flex;
561 gap: var(--gap-peer);
562 }
563
564 .publish-note {
565 margin: var(--gap-section) 0;
566 opacity: 0.7;
567 text-align: left;
568 }
569
570 /* ===========================================
571 CONTENT WIZARD STEP (replaces inline styles in wizards/steps/item/content.html)
572 =========================================== */
573
574 /* (Wizard upload-status + slim progress moved into canonical .upload-status*
575 / .progress-bar-container--slim primitives near top of file.) */
576
577 /* Bundle items picker, server-rendered rows and JS-appended rows share these. */
578 .bundle-picker-row-title { flex: 1; }
579 .bundle-picker-row-type { font-size: var(--text-fine); opacity: 0.6; }
580 .bundle-picker-row-unlisted {
581 font-size: var(--text-fine);
582 display: flex;
583 align-items: center;
584 gap: var(--gap-bound);
585 }
586
587 /* Batch upload queue table. */
588 .batch-queue-table {
589 width: 100%;
590 border-collapse: collapse;
591 }
592 .batch-queue-table thead tr {
593 border-bottom: 2px solid var(--border);
594 text-align: left;
595 }
596 .batch-queue-table th,
597 .batch-queue-table td {
598 padding: var(--gap-peer);
599 font-size: var(--text-note);
600 }
601 .batch-queue-table th:first-child,
602 .batch-queue-table td:first-child { padding-left: 0; }
603 .batch-queue-table th:last-child,
604 .batch-queue-table td:last-child { padding-right: 0; text-align: right; }
605 .batch-queue-table tbody tr { border-bottom: 1px solid var(--border); }
606
607 .batch-queue-name {
608 max-width: 150px;
609 overflow: hidden;
610 text-overflow: ellipsis;
611 white-space: nowrap;
612 }
613
614 /* ===========================================
615 ACCOUNT TAB (replaces inline styles in partials/tabs/user_account.html)
616 =========================================== */
617
618 /* Canonical solid-tint callout (one of these in the codebase).
619 Distinct from .alert (left-border) and .banner (full-bleed page notice).
620 Variants:
621 - .callout--danger (light bg, danger border, moderation, errors)
622 - .callout--warning (light bg, warning border, DNS, email-not-verified)
623 - .callout--solid-warning (full saturation warning bg, dark text, partial checkout) */
624 .callout {
625 padding: var(--gap-section);
626 margin-bottom: var(--gap-section);
627 font-size: var(--text-note);
628 border: 1px solid;
629 }
630 .callout--danger {
631 background: color-mix(in oklch, var(--danger) 10%, var(--surface-page));
632 border-color: var(--danger);
633 }
634 .callout--warning {
635 background: color-mix(in oklch, var(--warning) 14%, var(--surface-page));
636 border-color: var(--warning);
637 }
638 .callout--solid-warning {
639 background: var(--warning);
640 color: var(--primary-dark);
641 border-color: transparent;
642 padding: var(--gap-section);
643 }
644 .callout-title { text-transform: capitalize; }
645 .callout-meta {
646 opacity: 0.6;
647 margin-left: var(--gap-peer);
648 }
649 .callout-body { margin: var(--gap-peer) 0 0 0; }
650 .callout-hint {
651 font-size: var(--text-note);
652 margin-top: var(--gap-peer);
653 }
654
655 .account-mod-history { margin-top: var(--gap-section); }
656 .account-mod-history summary {
657 cursor: pointer;
658 font-size: var(--text-note);
659 opacity: 0.7;
660 }
661 .account-mod-history-list { margin-top: var(--gap-peer); }
662 .account-mod-history-item {
663 padding: var(--gap-peer) 0;
664 border-bottom: 1px solid var(--border);
665 font-size: var(--text-note);
666 }
667 .account-mod-history-reason {
668 margin: var(--gap-bound) 0 0 0;
669 opacity: 0.8;
670 }
671
672 .account-tip-card-title {
673 font-weight: bold;
674 margin-bottom: var(--gap-peer);
675 }
676 .account-tip-list {
677 display: flex;
678 flex-direction: column;
679 gap: var(--gap-bound);
680 opacity: 0.8;
681 }
682
683 /* Resend-verification button needs left spacing from preceding strong. */
684 .account-resend-btn { margin-left: var(--gap-peer); }
685
686 /* Cluster of small inline forms (manage-billing / cancel / resume). */
687 .inline-form { display: inline; }
688
689 /* Notification preferences, bare fieldset + monospace legend. */
690 .pref-fieldset {
691 border: none;
692 padding: 0;
693 margin: 0 0 var(--gap-section) 0;
694 }
695 .pref-fieldset--last { margin-bottom: var(--gap-peer); }
696 .pref-legend {
697 font-family: var(--font-mono);
698 font-size: var(--text-note);
699 font-weight: bold;
700 margin-bottom: var(--gap-peer);
701 }
702
703 /* The cannot-opt-out list, rendered from email::OperationalKind. Reads as
704 reference material rather than as more settings: no controls, and the
705 justification sits under its label rather than beside it. */
706 .operational-mail {
707 margin: var(--gap-peer) 0 0 0;
708 }
709 .operational-mail dt {
710 font-weight: bold;
711 font-size: var(--text-note);
712 margin-top: var(--gap-peer);
713 }
714 .operational-mail dd {
715 margin: 0;
716 opacity: 0.8;
717 font-size: var(--text-note);
718 }
719
720 /* ===========================================
721 PROJECT CODE TAB (replaces inline styles in partials/tabs/project_code.html)
722 =========================================== */
723
724 .proj-code-docs-link { margin-left: var(--gap-section); }
725
726 .proj-code-linked-list { margin-bottom: var(--gap-pane); }
727 .proj-code-linked-list > label { margin-bottom: var(--gap-peer); display: block; }
728
729 .proj-code-repo {
730 margin-bottom: var(--gap-section);
731 padding: var(--gap-section);
732 background: var(--surface-overlay);
733 }
734 .proj-code-repo-row {
735 display: flex;
736 align-items: center;
737 gap: var(--gap-section);
738 }
739 .proj-code-repo-link { flex: 1; }
740 .proj-code-repo .danger { padding: var(--gap-bound) var(--gap-section); font-size: var(--text-note); }
741
742 .proj-code-collab-block {
743 margin-top: var(--gap-peer);
744 padding-top: var(--gap-peer);
745 border-top: 1px solid var(--border);
746 }
747 .proj-code-collab-label { font-size: var(--text-note); margin-bottom: var(--gap-bound); display: block; }
748 .proj-code-collab-row {
749 display: flex;
750 align-items: center;
751 gap: var(--gap-peer);
752 margin-bottom: var(--gap-bound);
753 font-size: var(--text-note);
754 }
755 .proj-code-collab-name { flex: 1; }
756 .proj-code-collab-readonly { opacity: 0.5; }
757
758 .proj-code-add-collab-row {
759 display: flex;
760 gap: var(--gap-peer);
761 align-items: center;
762 }
763 .proj-code-add-collab-row .collab-username-input {
764 flex: 1;
765 font-size: var(--text-note);
766 padding: var(--gap-bound) var(--gap-peer);
767 }
768 .proj-code-add-collab-row .collab-add-btn { white-space: nowrap; }
769
770 .proj-code-link-row {
771 display: flex;
772 gap: var(--gap-peer);
773 align-items: center;
774 }
775 .proj-code-link-row #link-repo-select { flex: 1; }
776 .proj-code-link-row #link-repo-btn { white-space: nowrap; }
777
778 .proj-code-create-section {
779 margin-top: var(--gap-pane);
780 padding-top: var(--gap-section);
781 border-top: 1px solid var(--border);
782 }
783 .proj-code-create-section #create-repo-name { flex: 1; }
784 .proj-code-create-section #create-repo-btn { white-space: nowrap; }
785 .proj-code-create-status { margin-top: var(--gap-bound); }
786 .proj-code-create-status.is-error { color: var(--danger); }
787
788 .proj-code-disabled {
789 padding: var(--gap-page);
790 text-align: center;
791 opacity: 0.7;
792 }
793
794 /* ===========================================
795 ADMIN REPORT ENTRIES (replaces inline styles in partials/admin_report_entries.html)
796 =========================================== */
797
798 .admin-report-table {
799 width: 100%;
800 border-collapse: collapse;
801 font-size: var(--text-note);
802 }
803 .admin-report-table thead tr {
804 border-bottom: 2px solid var(--border);
805 text-align: left;
806 }
807 .admin-report-table tbody tr {
808 border-bottom: 1px solid var(--border);
809 }
810 .admin-report-table th,
811 .admin-report-table td {
812 padding: var(--gap-peer);
813 }
814 .admin-report-table td.admin-report-reason {
815 max-width: 200px;
816 overflow: hidden;
817 text-overflow: ellipsis;
818 white-space: nowrap;
819 }
820 .admin-report-table td.admin-report-date {
821 white-space: nowrap;
822 }
823
824 .admin-report-target-type {
825 opacity: 0.5;
826 font-size: var(--text-fine);
827 }
828
829 .admin-report-status-open {
830 color: var(--action);
831 font-weight: 600;
832 }
833 .admin-report-status-closed { opacity: 0.6; }
834
835 .admin-report-resolve-form {
836 display: inline-flex;
837 gap: var(--gap-bound);
838 align-items: center;
839 }
840 .admin-report-resolve-form input[type="text"] {
841 width: 120px;
842 padding: var(--gap-bound) var(--gap-peer);
843 font-size: var(--text-fine);
844 }
845 .admin-report-dismiss-form { display: inline; }
846
847 .admin-report-admin-notes {
848 font-size: var(--text-fine);
849 opacity: 0.6;
850 }
851
852 /* ===========================================
853 PROJECT PROMOTIONS TAB (replaces inline styles in partials/tabs/project_promotions.html)
854 =========================================== */
855
856 .proj-promo-form {
857 margin-bottom: var(--gap-page);
858 }
859
860 .proj-promo-grid {
861 display: grid;
862 grid-template-columns: 1fr 1fr;
863 gap: var(--gap-section) var(--gap-pane);
864 max-width: 500px;
865 }
866
867 .proj-promo-grid--bordered {
868 margin-top: var(--gap-section);
869 padding-top: var(--gap-section);
870 border-top: 1px solid var(--border);
871 }
872
873 .proj-promo-trial-fields {
874 display: none;
875 max-width: 500px;
876 margin-top: var(--gap-section);
877 }
878
879 .proj-promo-trial-fields.is-visible {
880 display: block;
881 }
882
883 .proj-promo-grid.is-hidden,
884 .proj-promo-trial-fields.is-hidden {
885 display: none;
886 }
887
888 .proj-promo-form .form-group {
889 margin-bottom: 0;
890 }
891
892 .proj-promo-form .form-group label {
893 font-size: var(--text-note);
894 }
895
896 .proj-promo-trial-group {
897 max-width: 240px;
898 }
899
900 .proj-promo-scope {
901 grid-column: 1 / -1;
902 }
903
904 .proj-promo-actions {
905 margin-top: var(--gap-section);
906 }
907
908 .proj-promo-hint {
909 margin-top: var(--gap-peer);
910 }
911
912 /* ===========================================
913 PROJECT SYNCKIT TAB (replaces inline styles in partials/tabs/project_synckit.html)
914 =========================================== */
915
916 .proj-synckit-intro { margin-bottom: var(--gap-section); }
917 .proj-synckit-intro-secondary { margin-bottom: var(--gap-pane); }
918 .proj-synckit-create { margin-bottom: var(--gap-pane); }
919 .proj-synckit-create-body {
920 padding: var(--gap-section); background: var(--surface-overlay); border: 1px solid var(--border);
921 }
922 .proj-synckit-create-form {
923 display: flex; flex-direction: row; gap: var(--gap-section); align-items: flex-end;
924 }
925 .proj-synckit-label {
926 display: block; font-size: var(--text-note); margin-bottom: var(--gap-bound);
927 }
928 .proj-synckit-code { font-size: var(--text-fine); }
929 .proj-synckit-code--wrap { font-size: var(--text-fine); word-break: break-all; }
930 .proj-synckit-code--selectable { font-size: var(--text-note); word-break: break-all; user-select: all; }
931 .proj-synckit-btn-tight {
932 margin-left: var(--gap-peer); padding: var(--gap-bound) var(--gap-peer); font-size: var(--text-fine);
933 }
934 .proj-synckit-btn-row {
935 padding: var(--gap-bound) var(--gap-peer); font-size: var(--text-fine);
936 }
937 .proj-synckit-btn-row + .proj-synckit-btn-row { margin-left: var(--gap-bound); }
938 .proj-synckit-hint-inline {
939 font-size: var(--text-fine); margin-left: var(--gap-bound);
940 }
941 .proj-synckit-hint-warn {
942 font-size: var(--text-fine); color: var(--danger);
943 }
944 .proj-synckit-status-active { color: var(--success); }
945 .proj-synckit-status-inactive { color: var(--danger); }
946 .proj-synckit-new-key {
947 padding: var(--gap-section); background: var(--surface-overlay);
948 border: 1px solid var(--border); margin-top: var(--gap-peer);
949 }
950 .proj-synckit-new-key-heading {
951 margin: 0 0 var(--gap-peer) 0; font-weight: 500; color: var(--danger);
952 }
953 .proj-synckit-create-status--error { color: var(--danger); margin-top: var(--gap-peer); }
954 .proj-synckit-create-status--reset { margin-top: var(--gap-peer); }
955
956 /* ===========================================
957 ITEM PAGE (replaces inline styles in pages/item.html)
958 =========================================== */
959
960 .item-page .breadcrumb {
961 display: flex;
962 justify-content: space-between;
963 align-items: center;
964 }
965
966 .item-page .breadcrumb-edit-link {
967 font-size: var(--text-note);
968 color: var(--content);
969 }
970
971 .item-page .video-player {
972 width: 100%;
973 max-height: 600px;
974 background: var(--primary-dark);
975 }
976
977 .item-page .item-cover-img {
978 width: 100%;
979 aspect-ratio: 1 / 1;
980 object-fit: cover;
981 display: block;
982 }
983
984
985 .item-page .bundle-notice-inline {
986 background: var(--surface-sunken);
987 padding: var(--gap-section);
988 }
989
990 .item-page .bundle-notice-title {
991 font-weight: bold;
992 margin-bottom: var(--gap-peer);
993 }
994
995 .item-page .bundle-notice-desc {
996 opacity: 0.8;
997 font-size: var(--text-note);
998 }
999
1000 .item-page .bundle-notice-entry {
1001 margin-top: var(--gap-section);
1002 }
1003
1004 .item-page .bundle-notice-entry a {
1005 font-weight: bold;
1006 }
1007
1008 .item-page .bundle-notice-price {
1009 opacity: 0.7;
1010 }
1011
1012 .item-page .bundle-notice-empty {
1013 margin-top: var(--gap-peer);
1014 opacity: 0.7;
1015 font-size: var(--text-note);
1016 }
1017
1018 .item-page .promo-details {
1019 margin-bottom: var(--gap-section);
1020 font-size: var(--text-note);
1021 }
1022
1023 .item-page .promo-summary {
1024 cursor: pointer;
1025 opacity: 0.7;
1026 }
1027
1028 .item-page .promo-form {
1029 display: flex;
1030 gap: var(--gap-peer);
1031 align-items: center;
1032 margin-top: var(--gap-peer);
1033 }
1034
1035 .item-page .promo-input {
1036 flex: 1;
1037 padding: var(--gap-peer) var(--gap-group);
1038 font-size: var(--text-note);
1039 }
1040
1041 .item-page .action-row {
1042 margin-top: var(--gap-section);
1043 }
1044
1045 .item-page .action-row-tight {
1046 margin-top: var(--gap-peer);
1047 }
1048
1049 .item-page .full-width-btn {
1050 width: 100%;
1051 font-size: var(--text-note);
1052 }
1053
1054 .item-page .license-preset-name {
1055 margin-bottom: var(--gap-section);
1056 }
1057
1058 .item-page .license-summary {
1059 cursor: pointer;
1060 opacity: 0.7;
1061 font-size: var(--text-note);
1062 }
1063
1064 .item-page .license-text {
1065 white-space: pre-wrap;
1066 font-family: var(--font-sans);
1067 font-size: var(--text-note);
1068 margin-top: var(--gap-section);
1069 padding: var(--gap-section);
1070 background: var(--surface-sunken);
1071 }
1072
1073 .item-page .license-download {
1074 margin-top: var(--gap-section);
1075 }
1076
1077 .item-page .license-download a {
1078 font-size: var(--text-note);
1079 color: var(--content);
1080 }
1081
1082 .item-page .bundle-list-entry {
1083 margin-top: var(--gap-peer);
1084 }
1085
1086 .item-page .footer-links {
1087 margin-top: var(--gap-peer);
1088 }
1089
1090 /* ===========================================
1091 JOIN COMPLETE STEP (replaces inline styles in wizards/steps/join/complete.html)
1092 =========================================== */
1093 .join-complete-intro { margin-bottom: var(--gap-pane); }
1094 .join-complete-choices {
1095 display: grid; grid-template-columns: 1fr 1fr;
1096 gap: var(--gap-section); max-width: 500px;
1097 }
1098 .join-complete-choice { text-decoration: none; color: inherit; display: block; }
1099 .join-complete-card {
1100 background: var(--surface-sunken); padding: var(--gap-section); text-align: center;
1101 border: 2px solid transparent; transition: border-color 0.15s;
1102 }
1103 .join-complete-choice:hover .join-complete-card,
1104 .join-complete-card--active { border-color: var(--content); }
1105 .join-complete-card-title {
1106 font-family: var(--font-display); font-weight: bold;
1107 font-size: var(--text-lead); margin-bottom: var(--gap-peer);
1108 }
1109 .join-complete-card-desc {
1110 font-size: var(--text-note); opacity: 0.7; margin: 0;
1111 }
1112 .join-complete-footnote {
1113 font-size: var(--text-note); opacity: 0.5;
1114 margin-top: var(--gap-section); text-align: center;
1115 }
1116
1117 /* ===========================================
1118 PROMO CODES LIST (replaces inline styles in partials/promo_codes_list.html)
1119 =========================================== */
1120 .promo-codes-row--expired { opacity: 0.5; }
1121 .promo-codes-row--pending { opacity: 0.7; }
1122 .promo-codes-schedule { font-size: var(--text-note); }
1123 .promo-codes-schedule-pending { color: var(--warning); }
1124 .promo-codes-schedule-expired { color: var(--danger); }
1125 .promo-codes-schedule-none { opacity: 0.5; }
1126 .promo-codes-actions { white-space: nowrap; }
1127 .promo-codes-edit-btn { font-size: var(--text-fine); }
1128 .promo-codes-edit-row { background: var(--surface-sunken); }
1129 .promo-codes-edit-cell { padding: var(--gap-section); }
1130 .promo-codes-edit-form {
1131 display: flex; gap: var(--gap-section); align-items: end; flex-wrap: wrap;
1132 }
1133 .promo-codes-edit-label {
1134 font-size: var(--text-fine); display: block; margin-bottom: var(--gap-bound);
1135 }
1136 .promo-codes-edit-save { font-size: var(--text-note); }
1137 .promo-codes-bulk-row { margin-top: var(--gap-section); }
1138 .promo-codes-bulk-btn { font-size: var(--text-note); opacity: 0.7; }
1139
1140 /* ===========================================
1141 USER MEDIA TAB (replaces inline styles in partials/tabs/user_media.html)
1142 =========================================== */
1143
1144 .user-media-intro {
1145 margin-bottom: var(--gap-section);
1146 }
1147
1148 .user-media-upload {
1149 border: 2px dashed var(--border);
1150 padding: var(--gap-pane);
1151 margin-bottom: var(--gap-pane);
1152 text-align: center;
1153 background: var(--surface-overlay);
1154 }
1155
1156 .user-media-upload--dragover {
1157 border-color: var(--action);
1158 }
1159
1160 .user-media-upload-row {
1161 margin-bottom: var(--gap-section);
1162 }
1163
1164 .user-media-upload-label {
1165 display: inline-block;
1166 font-size: var(--text-note);
1167 margin-right: var(--gap-section);
1168 }
1169
1170 .user-media-upload-folder-input {
1171 padding: var(--gap-bound);
1172 font-size: var(--text-note);
1173 width: 140px;
1174 margin-left: var(--gap-bound);
1175 }
1176
1177 .user-media-upload-progress {
1178 margin-top: var(--gap-section);
1179 }
1180
1181 .user-media-upload-status {
1182 font-size: var(--text-note);
1183 margin-bottom: var(--gap-bound);
1184 }
1185
1186 .user-media-upload-status--ok {
1187 color: var(--success);
1188 }
1189
1190 .user-media-upload-status--err {
1191 color: var(--danger);
1192 }
1193
1194 .user-media-folders {
1195 margin-bottom: var(--gap-section);
1196 display: flex;
1197 gap: var(--gap-peer);
1198 flex-wrap: wrap;
1199 align-items: center;
1200 }
1201
1202 .user-media-folders-label {
1203 font-size: var(--text-note);
1204 opacity: 0.7;
1205 }
1206
1207 .user-media-folders-btn {
1208 font-size: var(--text-fine);
1209 }
1210
1211 .user-media-grid {
1212 display: grid;
1213 grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
1214 gap: var(--gap-section);
1215 }
1216
1217 .user-media-card {
1218 background: var(--surface-overlay);
1219 border: 1px solid var(--border);
1220 padding: var(--gap-section);
1221 position: relative;
1222 }
1223
1224 .user-media-card-thumb {
1225 width: 100%;
1226 height: 120px;
1227 overflow: hidden;
1228 margin-bottom: var(--gap-peer);
1229 display: flex;
1230 align-items: center;
1231 justify-content: center;
1232 background: var(--surface-sunken);
1233 }
1234
1235 .user-media-card-thumb--video {
1236 font-size: var(--text-title);
1237 opacity: 0.4;
1238 }
1239
1240 .user-media-card-img {
1241 max-width: 100%;
1242 max-height: 120px;
1243 object-fit: contain;
1244 }
1245
1246 .user-media-card-name {
1247 font-size: var(--text-fine);
1248 word-break: break-all;
1249 margin-bottom: var(--gap-bound);
1250 }
1251
1252 .user-media-card-meta {
1253 font-size: var(--text-fine);
1254 opacity: 0.6;
1255 margin-bottom: var(--gap-peer);
1256 }
1257
1258 .user-media-card-actions {
1259 display: flex;
1260 gap: var(--gap-bound);
1261 }
1262
1263 .user-media-card-btn {
1264 font-size: var(--text-fine);
1265 padding: var(--gap-bound) var(--gap-peer);
1266 }
1267
1268 /* ===========================================
1269 ITEM VERSION UPLOAD (replaces inline styles in partials/item_version_upload.html)
1270 =========================================== */
1271
1272 .item-version-upload-grid {
1273 display: grid;
1274 grid-template-columns: 1fr 1fr;
1275 gap: var(--gap-section);
1276 }
1277
1278 /* Where one slot's own work has got to, in the three words `Progress` emits.
1279 Here rather than in makeover because the hook is a data attribute
1280 `quasi-webview` writes rather than a class makeover names, and this is its
1281 only consumer. A second host wanting it is the reason to move it. */
1282 .field-repeat-slot[data-repeat-progress="working"] {
1283 opacity: 0.75;
1284 }
1285
1286 .field-repeat-slot[data-repeat-progress="done"] {
1287 opacity: 0.55;
1288 }
1289
1290 .field-repeat-slot[data-repeat-progress="failed"] {
1291 border-left: 2px solid var(--danger);
1292 padding-left: var(--gap-peer);
1293 }
1294
1295 .item-version-upload-speed {
1296 font-size: var(--text-fine);
1297 opacity: 0.6;
1298 margin-top: var(--gap-bound);
1299 }
1300
1301 /* ===========================================
1302 INSERTION LIST (replaces inline styles in partials/insertion_list.html)
1303 =========================================== */
1304
1305 .insertion-list-heading {
1306 font-family: var(--font-mono);
1307 font-size: var(--text-body);
1308 margin-bottom: var(--gap-section);
1309 }
1310 .insertion-list-toolbar {
1311 margin-bottom: var(--gap-section);
1312 }
1313 .insertion-list-upload {
1314 font-family: var(--font-mono);
1315 }
1316 .insertion-list-table {
1317 width: 100%;
1318 font-family: var(--font-sans);
1319 }
1320 .insertion-list-table th {
1321 text-align: left;
1322 font-family: var(--font-mono);
1323 font-size: var(--text-note);
1324 }
1325 .insertion-list-table th.insertion-list-th-actions {
1326 text-align: right;
1327 }
1328 .insertion-list-table .insertion-list-actions {
1329 text-align: right;
1330 }
1331 .insertion-list-table .insertion-list-action-btn {
1332 font-family: var(--font-mono);
1333 }
1334
1335 /* ===========================================
1336 PROJECT MEMBERS TAB (replaces inline styles in partials/tabs/project_members.html)
1337 =========================================== */
1338
1339 .proj-members-summary {
1340 background: var(--surface-sunken);
1341 padding: var(--gap-section);
1342 margin-bottom: var(--gap-section);
1343 }
1344
1345 .proj-members-summary-row {
1346 display: flex;
1347 justify-content: space-between;
1348 align-items: center;
1349 }
1350
1351 .proj-members-stat {
1352 font-size: var(--text-head);
1353 font-weight: bold;
1354 }
1355
1356 .proj-members-add {
1357 margin-bottom: var(--gap-page);
1358 }
1359
1360 .proj-members-add-grid {
1361 display: grid;
1362 grid-template-columns: 1fr auto auto;
1363 gap: var(--gap-section);
1364 align-items: end;
1365 }
1366
1367 .proj-members-field-label {
1368 font-size: var(--text-note);
1369 display: block;
1370 margin-bottom: var(--gap-bound);
1371 }
1372
1373 .proj-members-add-result {
1374 margin-top: var(--gap-peer);
1375 }
1376
1377 .proj-members-name-link {
1378 color: inherit;
1379 }
1380
1381 .proj-members-split-cell {
1382 font-weight: bold;
1383 }
1384
1385 /* ===========================================
1386 PLACEMENT LIST (replaces inline styles in partials/placement_list.html)
1387 =========================================== */
1388
1389 .placement-list-heading {
1390 font-family: var(--font-mono);
1391 font-size: var(--text-body);
1392 margin-bottom: var(--gap-section);
1393 }
1394 .placement-list-table {
1395 width: 100%;
1396 font-family: var(--font-sans);
1397 margin-bottom: var(--gap-section);
1398 }
1399 .placement-list-table th {
1400 text-align: left;
1401 font-family: var(--font-mono);
1402 font-size: var(--text-note);
1403 }
1404 .placement-list-table th.placement-list-th-actions {
1405 text-align: right;
1406 }
1407 .placement-list-table .placement-list-actions {
1408 text-align: right;
1409 }
1410 .placement-list-table .placement-list-remove {
1411 font-family: var(--font-mono);
1412 }
1413 .placement-list-form {
1414 display: flex;
1415 gap: var(--gap-peer);
1416 align-items: flex-end;
1417 flex-wrap: wrap;
1418 }
1419 .placement-list-label {
1420 display: block;
1421 font-family: var(--font-mono);
1422 font-size: var(--text-fine);
1423 margin-bottom: var(--gap-bound);
1424 }
1425 .placement-list-add {
1426 font-family: var(--font-mono);
1427 }
1428
1429 /* ===========================================
1430 USER SYNCKIT TAB (replaces inline styles in partials/tabs/user_synckit.html)
1431 =========================================== */
1432
1433 .user-synckit-create { margin-bottom: var(--gap-pane); }
1434 .user-synckit-create-body {
1435 padding: var(--gap-section);
1436 background: var(--surface-overlay);
1437 border: 1px solid var(--border);
1438 }
1439 .user-synckit-create-form {
1440 display: flex;
1441 flex-direction: row;
1442 gap: var(--gap-section);
1443 align-items: flex-end;
1444 }
1445 .user-synckit-create-form label {
1446 display: block;
1447 font-size: var(--text-note);
1448 margin-bottom: var(--gap-bound);
1449 }
1450 .user-synckit-create-form input[type="text"],
1451 .user-synckit-create-form select {
1452 padding: var(--gap-peer);
1453 font-size: var(--text-note);
1454 }
1455 .user-synckit-create-form input[type="text"] { width: 220px; }
1456 .user-synckit-create-form select { width: 180px; }
1457
1458 .user-synckit-code { font-size: var(--text-fine); }
1459 .user-synckit-hint {
1460 font-size: var(--text-fine);
1461 margin-left: var(--gap-bound);
1462 }
1463
1464 .user-synckit-inline-btn {
1465 margin-left: var(--gap-peer);
1466 padding: var(--gap-bound) var(--gap-peer);
1467 font-size: var(--text-fine);
1468 }
1469 .user-synckit-row-btn {
1470 padding: var(--gap-bound) var(--gap-peer);
1471 font-size: var(--text-fine);
1472 }
1473 .user-synckit-row-btn + .user-synckit-row-btn {
1474 margin-left: var(--gap-bound);
1475 }
1476
1477 .user-synckit-status-active { color: var(--success); }
1478 .user-synckit-status-inactive { color: var(--danger); }
1479
1480 .user-synckit-edit-btn {
1481 padding: var(--gap-bound) var(--gap-peer);
1482 font-size: var(--text-fine);
1483 }
1484
1485 .user-synckit-create-error {
1486 color: var(--danger);
1487 margin-top: var(--gap-peer);
1488 }
1489
1490 /* ===========================================
1491 TOTP (replaces inline styles in partials/totp_setup.html and totp_status.html)
1492 =========================================== */
1493
1494 /* Section wrapper between TOTP subsections (QR + backup codes + confirm,
1495 or regenerate + disable). */
1496 .totp-section { margin-bottom: var(--gap-pane); }
1497
1498 /* Confirm-setup section is separated from the backup codes by a top border. */
1499 .totp-confirm {
1500 border-top: 1px solid var(--border);
1501 padding-top: var(--gap-section);
1502 }
1503
1504 /* QR code container, centered above the manual-entry details. */
1505 .totp-qr {
1506 text-align: center;
1507 margin-bottom: var(--gap-section);
1508 }
1509 .totp-qr img {
1510 max-width: 200px;
1511 image-rendering: pixelated;
1512 }
1513
1514 /* Collapsible "Manual entry key" group. */
1515 .totp-manual { margin-bottom: var(--gap-section); }
1516 .totp-manual summary {
1517 cursor: pointer;
1518 opacity: 0.7;
1519 font-size: var(--text-note);
1520 }
1521 .totp-manual-secret {
1522 display: block;
1523 margin-top: var(--gap-peer);
1524 word-break: break-all;
1525 font-size: var(--text-note);
1526 padding: var(--gap-peer);
1527 background: var(--surface-sunken);
1528 }
1529
1530 /* Backup codes grid (rendered list of one-time codes). */
1531 .backup-codes-grid {
1532 display: grid;
1533 grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr));
1534 gap: var(--gap-peer);
1535 }
1536 .backup-codes-grid code {
1537 padding: var(--gap-peer);
1538 background: var(--surface-sunken);
1539 text-align: center;
1540 font-size: var(--text-note);
1541 }
1542
1543 /* Status row for the "Enabled" badge above the management forms. */
1544 .totp-status-row {
1545 display: flex;
1546 align-items: center;
1547 gap: var(--gap-peer);
1548 margin-bottom: var(--gap-section);
1549 }
1550
1551 /* Container where regenerated backup codes are swapped in via HTMX. */
1552 .totp-regen-output { margin-top: var(--gap-section); }
1553
1554 /* ===========================================
1555 DASHBOARD-USER SHELL (replaces inline styles in dashboards/dashboard-user.html)
1556 =========================================== */
1557
1558 .sandbox-banner {
1559 background: var(--action);
1560 color: var(--primary-light);
1561 padding: var(--gap-section) var(--gap-pane);
1562 text-align: center;
1563 font-family: var(--font-mono);
1564 font-size: var(--text-note);
1565 }
1566
1567 .sandbox-banner-link {
1568 color: var(--primary-light);
1569 text-decoration: underline;
1570 margin-left: var(--gap-peer);
1571 }
1572 .account-status-actions {
1573 display: flex;
1574 gap: var(--gap-section);
1575 flex-wrap: wrap;
1576 margin-top: var(--gap-section);
1577 }
1578
1579 .suspension-wrap {
1580 margin-bottom: var(--gap-section);
1581 }
1582
1583 .password-warning-banner {
1584 margin-bottom: var(--gap-section);
1585 padding: var(--gap-section);
1586 background: color-mix(in oklch, var(--warning) 14%, var(--surface-page));
1587 border: 1px solid var(--warning);
1588 font-size: var(--text-body);
1589 }
1590
1591 .dash-user-header-links {
1592 margin-bottom: var(--gap-peer);
1593 display: flex;
1594 gap: var(--gap-pane);
1595 }
1596
1597 .dash-user-header-link {
1598 font-size: var(--text-note);
1599 opacity: 0.7;
1600 }
1601
1602 .checklist-recovery {
1603 padding: var(--gap-section) 0;
1604 text-align: right;
1605 }
1606
1607 .checklist-recovery-link {
1608 font-size: var(--text-note);
1609 opacity: 0.7;
1610 }
1611
1612
1613 /* ===========================================
1614 SUSPENSION BANNER (replaces inline styles in partials/suspension_banner.html)
1615 =========================================== */
1616
1617 .suspension-banner {
1618 background: color-mix(in oklch, var(--danger) 10%, var(--surface-page));
1619 border: 1px solid var(--danger);
1620 padding: var(--gap-pane);
1621 margin-bottom: var(--gap-pane);
1622 }
1623
1624 .suspension-banner-title {
1625 margin: 0 0 var(--gap-peer) 0;
1626 color: var(--danger);
1627 }
1628
1629 .suspension-banner-reason {
1630 font-size: var(--text-note);
1631 margin: 0 0 var(--gap-section) 0;
1632 }
1633
1634 .suspension-banner-denial {
1635 background: var(--surface-overlay);
1636 padding: var(--gap-section);
1637 margin-bottom: var(--gap-section);
1638 font-size: var(--text-note);
1639 }
1640
1641 .suspension-banner-denial-response {
1642 margin: var(--gap-bound) 0 0 0;
1643 }
1644
1645 .suspension-banner-denial-hint {
1646 margin: var(--gap-peer) 0 0 0;
1647 opacity: 0.7;
1648 }
1649
1650 .suspension-banner-pending {
1651 font-size: var(--text-note);
1652 opacity: 0.7;
1653 margin: 0;
1654 }
1655
1656 .suspension-banner-appeal {
1657 margin-top: var(--gap-peer);
1658 }
1659
1660 .suspension-banner-appeal-summary {
1661 cursor: pointer;
1662 font-size: var(--text-note);
1663 }
1664
1665 .suspension-banner-appeal-form {
1666 margin-top: var(--gap-section);
1667 }
1668
1669 .suspension-banner-appeal-text {
1670 width: 100%;
1671 margin-bottom: var(--gap-peer);
1672 font-size: var(--text-note);
1673 }
1674
1675 .suspension-banner-appeal-submit {
1676 font-size: var(--text-note);
1677 }
1678
1679 .suspension-banner-export {
1680 margin-top: var(--gap-section);
1681 }
1682
1683 .suspension-banner-export-link {
1684 font-size: var(--text-note);
1685 }
1686
1687 /* ===========================================
1688 REPORT MODAL (replaces inline styles in partials/report_modal.html)
1689 =========================================== */
1690
1691 .report-modal-content {
1692 background: var(--surface-page);
1693 padding: var(--gap-page);
1694 width: 90%;
1695 max-width: 480px;
1696 max-height: 90vh;
1697 overflow-y: auto;
1698 }
1699
1700 .report-modal-title {
1701 font-size: var(--text-subhead);
1702 margin: 0;
1703 }
1704
1705 .report-modal-fieldset {
1706 border: none;
1707 padding: 0;
1708 margin: 0 0 var(--gap-section) 0;
1709 }
1710
1711 .report-modal-legend {
1712 font-size: var(--text-note);
1713 font-weight: 600;
1714 margin-bottom: var(--gap-peer);
1715 }
1716
1717 .report-modal-option {
1718 display: block;
1719 margin-bottom: var(--gap-peer);
1720 cursor: pointer;
1721 }
1722
1723 .report-modal-details {
1724 margin-bottom: var(--gap-section);
1725 }
1726
1727 .report-modal-details-label {
1728 display: block;
1729 font-size: var(--text-note);
1730 margin-bottom: var(--gap-bound);
1731 }
1732
1733 .report-modal-textarea {
1734 width: 100%;
1735 font-size: var(--text-note);
1736 }
1737
1738 .report-modal-actions {
1739 display: flex;
1740 gap: var(--gap-peer);
1741 justify-content: flex-end;
1742 }
1743
1744 /* ===========================================
1745 LIBRARY COLLECTIONS TAB (partials/tabs/library_collections.html)
1746 =========================================== */
1747
1748 .badge.is-faded { opacity: 0.5; }
1749 .lib-coll-new { margin-top: var(--gap-pane); }
1750 .lib-coll-new-summary { cursor: pointer; font-weight: bold; }
1751 .lib-coll-new-form { margin-top: var(--gap-section); }
1752 .lib-coll-wishlist-heading {
1753 font-size: var(--text-lead);
1754 margin-top: var(--gap-page);
1755 margin-bottom: var(--gap-section);
1756 opacity: 0.8;
1757 }
1758 .lib-coll-wishlist-wrap {
1759 overflow-x: auto;
1760 -webkit-overflow-scrolling: touch;
1761 }
1762 .lib-coll-wishlist-table { min-width: 500px; }
1763 .lib-coll-row-actions { white-space: nowrap; }
1764 .lib-coll-row-actions .lib-coll-cart-btn { margin-right: var(--gap-bound); }
1765
1766 /* ===========================================
1767 USER ANALYTICS TAB (partials/tabs/user_analytics.html)
1768 =========================================== */
1769
1770 .analytics-export-link { margin-left: var(--gap-section); }
1771 .analytics-range-heading {
1772 font-size: var(--text-lead);
1773 margin: 0;
1774 }
1775 .analytics-section--comparison { margin-bottom: var(--gap-page); }
1776 .analytics-section--comparison h2 { margin-bottom: var(--gap-section); }
1777 .analytics-table-wrap {
1778 overflow-x: auto;
1779 -webkit-overflow-scrolling: touch;
1780 }
1781 .analytics-table { min-width: 500px; }
1782 .analytics-revenue-cell {
1783 display: flex;
1784 align-items: center;
1785 gap: var(--gap-peer);
1786 }
1787 .analytics-revenue-bar {
1788 width: var(--fill, 0%);
1789 height: 10px;
1790 min-width: 2px;
1791 max-width: 80px;
1792 background: var(--action);
1793 }
1794
1795 /* ===========================================
1796 ITEM EMBED TAB (templates/partials/tabs/item_embed.html)
1797 =========================================== */
1798 .embed-intro {
1799 opacity: 0.7;
1800 font-size: var(--text-note);
1801 margin-bottom: var(--gap-pane);
1802 }
1803 .embed-option {
1804 margin-bottom: var(--gap-pane);
1805 padding: var(--gap-section);
1806 border: 1px solid var(--border);
1807 border-radius: var(--radius-panel);
1808 }
1809 .embed-option h4 {
1810 margin-bottom: var(--gap-bound);
1811 font-size: var(--text-body);
1812 }
1813 .embed-option-desc {
1814 font-size: var(--text-note);
1815 opacity: 0.7;
1816 margin-bottom: var(--gap-peer);
1817 }
1818 .embed-preview {
1819 margin: var(--gap-section) 0;
1820 overflow: hidden;
1821 }
1822 .embed-iframe {
1823 border: none;
1824 border-radius: var(--radius-control);
1825 }
1826 .embed-layout-toggle {
1827 font-size: var(--text-note);
1828 margin-bottom: var(--gap-peer);
1829 display: flex;
1830 gap: var(--gap-section);
1831 }
1832 .embed-layout-toggle label {
1833 cursor: pointer;
1834 display: flex;
1835 align-items: center;
1836 gap: var(--gap-bound);
1837 }
1838 .embed-code-row {
1839 display: flex;
1840 align-items: center;
1841 gap: var(--gap-peer);
1842 }
1843 .embed-snippet {
1844 flex: 1;
1845 padding: var(--gap-peer) var(--gap-section);
1846 background: var(--surface-overlay);
1847 border-radius: var(--radius-control);
1848 font-size: var(--text-fine);
1849 overflow-x: auto;
1850 white-space: nowrap;
1851 font-family: var(--font-mono);
1852 border: 1px solid var(--border);
1853 }
1854 .copy-btn {
1855 padding: 6px 12px;
1856 font-size: var(--text-fine);
1857 background: var(--action);
1858 color: var(--primary-light);
1859 border: none;
1860 border-radius: var(--radius-control);
1861 cursor: pointer;
1862 white-space: nowrap;
1863 }
1864 .copy-btn:hover {
1865 opacity: 0.9;
1866 }
1867
1868 /* ===========================================
1869 ADMIN NAV (templates/partials/admin_nav.html)
1870 =========================================== */
1871 .admin-nav {
1872 display: flex;
1873 gap: var(--gap-peer);
1874 margin-bottom: var(--gap-pane);
1875 flex-wrap: wrap;
1876 font-family: var(--font-mono);
1877 font-size: var(--text-note);
1878 }
1879 .admin-nav a {
1880 padding: var(--gap-bound) var(--gap-section);
1881 text-decoration: none;
1882 }
1883
1884 /* Admin nav items and filter-bar toggles are .btn-primary / .btn-secondary,
1885 toggled by the templates to mark the current page or active filter. Colour
1886 and depth come from the button recipe; only the tighter admin metrics and
1887 the active weight are stated here. */
1888 .admin-nav a.btn-primary,
1889 .filter-bar button.btn-primary {
1890 font-weight: 700;
1891 }
1892 .admin-nav a.btn-secondary:hover,
1893 .filter-bar button.btn-secondary:hover {
1894 color: var(--content);
1895 }
1896
1897 /* ===========================================
1898 VIDEO PLAYER PAGE (templates/pages/video_player.html)
1899 =========================================== */
1900 .video-cover-img {
1901 width: 100%;
1902 display: block;
1903 background: var(--primary-dark);
1904 }
1905 .video-cover-placeholder {
1906 width: 100%;
1907 aspect-ratio: 16 / 9;
1908 background: var(--primary-dark);
1909 display: flex;
1910 align-items: center;
1911 justify-content: center;
1912 color: var(--content-muted);
1913 }
1914 .video-store-cta {
1915 margin: var(--gap-page) 0;
1916 padding: var(--gap-pane);
1917 background: var(--surface-sunken);
1918 text-align: center;
1919 }
1920 .video-cta-lead {
1921 font-size: var(--text-lead);
1922 margin-bottom: var(--gap-section);
1923 }
1924 .video-cta-price {
1925 font-size: var(--text-head);
1926 margin-bottom: var(--gap-section);
1927 }
1928 .video-cta-fineprint {
1929 font-size: var(--text-note);
1930 opacity: 0.7;
1931 margin-top: var(--gap-section);
1932 }
1933 .video-library-status {
1934 font-family: var(--font-mono);
1935 color: var(--content-muted);
1936 }
1937
1938 /* ===========================================
1939 LIBRARY LOCKED PAGE (templates/pages/library_locked.html)
1940 =========================================== */
1941 .library-locked-byline {
1942 opacity: 0.7;
1943 }
1944 .library-locked-cover {
1945 max-width: 320px;
1946 margin: var(--gap-section) 0;
1947 /* Reserve the space before the image loads (audit Run 17 Frontend). */
1948 aspect-ratio: 1 / 1;
1949 object-fit: cover;
1950 }
1951 .library-locked-purchase {
1952 margin-top: var(--gap-page);
1953 }
1954 .library-locked-lead {
1955 opacity: 0.85;
1956 }
1957 .library-locked-actions {
1958 margin-top: var(--gap-pane);
1959 display: flex;
1960 gap: var(--gap-section);
1961 flex-wrap: wrap;
1962 }
1963 .library-locked-bundles {
1964 margin-top: var(--gap-pane);
1965 }
1966 .library-locked-bundles-title {
1967 font-weight: bold;
1968 }
1969 .library-locked-bundle {
1970 margin-top: var(--gap-peer);
1971 }
1972 .library-locked-bundle-price {
1973 opacity: 0.7;
1974 }
1975
1976 /* ===========================================
1977 BLOG (replaces inline styles in project_blog.html
1978 and dashboard-blog-editor.html)
1979 =========================================== */
1980
1981 .blog-empty-state { padding: var(--gap-page) 0; }
1982 .blog-empty-hint {
1983 opacity: 0.7;
1984 font-size: var(--text-note);
1985 margin-top: var(--gap-peer);
1986 }
1987 .blog-post-title-link { font-weight: bold; }
1988 .blog-post-actions {
1989 display: flex;
1990 gap: var(--gap-peer);
1991 }
1992
1993 /* Blog editor dashboard (templates/dashboards/dashboard-blog-editor.html). */
1994 .blog-editor h1 {
1995 font-size: var(--text-title);
1996 margin-bottom: var(--gap-section);
1997 text-align: left;
1998 }
1999 .blog-editor .editor-form { max-width: 800px; }
2000 .blog-editor .editor-form .form-group { margin-bottom: var(--gap-section); }
2001 .blog-editor .editor-form textarea {
2002 font-family: var(--font-mono);
2003 font-size: var(--text-note);
2004 min-height: 400px;
2005 resize: vertical;
2006 }
2007 .blog-editor-slug-spinner { font-size: var(--text-note); }
2008 .blog-editor-actions {
2009 display: flex;
2010 gap: var(--gap-section);
2011 align-items: center;
2012 }
2013 .blog-editor-status { margin-top: var(--gap-peer); }
2014
2015 /* ===========================================
2016 AUDIO PLAYER (replaces inline styles in pages/audio_player.html)
2017 =========================================== */
2018
2019 .audio-store-cta {
2020 margin: var(--gap-page) 0;
2021 padding: var(--gap-pane);
2022 background: var(--surface-sunken);
2023 text-align: center;
2024 }
2025 .audio-store-cta .audio-access-msg {
2026 font-size: var(--text-lead);
2027 margin-bottom: var(--gap-section);
2028 }
2029 .audio-store-cta .audio-price {
2030 font-size: var(--text-head);
2031 margin-bottom: var(--gap-section);
2032 }
2033 .audio-store-cta .audio-fee-note {
2034 font-size: var(--text-note);
2035 opacity: 0.7;
2036 margin-top: var(--gap-section);
2037 }
2038 .audio-library-status {
2039 font-family: var(--font-mono);
2040 color: var(--content-muted);
2041 }
2042
2043 /* ===========================================
2044 SECTIONS WIZARD STEP (templates/wizards/steps/item/sections.html)
2045 Parallels .psection-row used by item_details + project-sections.js,
2046 but isolated so wizard markup can evolve independently.
2047 =========================================== */
2048
2049 .section-row {
2050 display: flex;
2051 align-items: center;
2052 gap: var(--gap-section);
2053 padding: var(--gap-group) 0;
2054 border-bottom: 1px solid var(--border);
2055 }
2056 .section-row-title { flex: 1; font-weight: bold; }
2057 .section-row-length { font-size: var(--text-fine); opacity: 0.6; }
2058 .section-row .section-delete-btn {
2059 padding: var(--gap-bound) var(--gap-group);
2060 font-size: var(--text-fine);
2061 }
2062
2063 .section-add-body { margin-top: var(--gap-section); }
2064
2065 .wizard-actions { margin-top: var(--gap-pane); }
2066
2067 /* ===========================================
2068 PROJECT SUBSCRIPTIONS TAB (templates/partials/tabs/project_subscriptions.html)
2069 =========================================== */
2070
2071 .subs-connect-info {
2072 margin-bottom: var(--gap-pane);
2073 padding: var(--gap-section);
2074 }
2075 .subs-new-tier { margin-bottom: var(--gap-page); }
2076
2077 .tier-row-desc {
2078 font-size: var(--text-note);
2079 opacity: 0.7;
2080 margin-top: var(--gap-bound);
2081 }
2082 .tier-action-btn {
2083 font-size: var(--text-note);
2084 padding: var(--gap-bound) var(--gap-group);
2085 }
2086
2087 .subs-members-bar {
2088 margin-top: var(--gap-page);
2089 display: flex;
2090 justify-content: space-between;
2091 align-items: center;
2092 }
2093
2094 /* ===========================================
2095 LIBRARY CONSUMPTION PAGES
2096 ===========================================
2097 Shared styles for the library-side consumption surfaces:
2098 text_reader.html, library_text.html (.article-page),
2099 library_downloads.html (.library-page),
2100 library_audio.html / library_video.html (.media-container + helpers).
2101 The .article-page and .library-page sections higher up in this file
2102 are activated by body classes set in the templates. */
2103
2104 /* Faded excerpt text on the public store-page text reader. */
2105 .article-page .article-body--excerpt { opacity: 0.85; }
2106
2107 /* Store-page call-to-action block (text_reader.html). */
2108 .article-page .store-cta {
2109 margin: var(--gap-page) 0;
2110 padding: var(--gap-pane);
2111 background: var(--surface-sunken);
2112 text-align: center;
2113 }
2114 .article-page .store-cta-lead {
2115 font-size: var(--text-lead);
2116 margin-bottom: var(--gap-section);
2117 }
2118 .article-page .store-cta-price {
2119 font-size: var(--text-head);
2120 margin-bottom: var(--gap-section);
2121 }
2122 .article-page .store-cta-note {
2123 font-size: var(--text-note);
2124 opacity: 0.7;
2125 margin-top: var(--gap-section);
2126 }
2127 .article-page .store-cta .library-status {
2128 font-family: var(--font-mono);
2129 color: var(--content-muted);
2130 }
2131
2132 /* Library back-link breadcrumb shared by the media library pages. */
2133 .media-container .library-back {
2134 font-size: var(--text-note);
2135 opacity: 0.7;
2136 margin: var(--gap-section) 0;
2137 }
2138 .media-container .library-back a { color: var(--content); }
2139
2140 /* Source-files download list under audio/video library pages.
2141 The .library-page version exists higher up; this block scopes the
2142 same look under .media-container for audio/video. */
2143 .media-container .library-downloads {
2144 background: var(--surface-overlay);
2145 padding: var(--gap-pane);
2146 margin-top: var(--gap-page);
2147 }
2148 .media-container .library-downloads h3 {
2149 font-size: var(--text-lead);
2150 margin-bottom: var(--gap-section);
2151 }
2152 .media-container .download-row {
2153 display: flex;
2154 align-items: center;
2155 gap: var(--gap-section);
2156 padding: var(--gap-peer) 0;
2157 border-bottom: 1px solid var(--border);
2158 }
2159 .media-container .download-row:last-child { border-bottom: none; }
2160 .media-container .download-version {
2161 min-width: 4em;
2162 font-family: var(--font-mono);
2163 font-size: var(--text-note);
2164 }
2165 .media-container .download-label { flex: 1; }
2166 .media-container .download-label--empty { flex: 1; opacity: 0.5; }
2167 .media-container .download-size {
2168 font-size: var(--text-note);
2169 opacity: 0.6;
2170 min-width: 5em;
2171 text-align: right;
2172 }
2173
2174 /* Compact download button used in both library_downloads.html and
2175 media library pages. */
2176 .btn-download-compact {
2177 padding: var(--gap-peer) var(--gap-section);
2178 font-size: var(--text-note);
2179 }
2180
2181 /* Faded "no label" placeholder on library_downloads.html download rows. */
2182 .library-page .download-label--empty { opacity: 0.5; }
2183
2184 /* Library-downloads description <details> summary + body. */
2185 .library-page .lib-summary {
2186 cursor: pointer;
2187 font-family: var(--font-display);
2188 font-size: var(--text-subhead);
2189 }
2190 .library-page .lib-summary-body { margin-top: var(--gap-section); }
2191
2192 /* License section on library_downloads.html. */
2193 .library-page .lib-license-name { margin-bottom: var(--gap-section); }
2194 .library-page .lib-license-download {
2195 font-size: var(--text-note);
2196 color: var(--content);
2197 }
2198
2199 /* Footer below the item-footer (was inline on library_downloads.html). */
2200 .library-page .item-footer-sub { margin-top: var(--gap-peer); }
2201
2202 /* library_text.html footer: a terse in-page footer for the library's own
2203 text view, unrelated to base.html's site-footer. */
2204 .article-page .lib-text-footer {
2205 text-align: center;
2206 padding: var(--gap-page);
2207 font-size: var(--text-note);
2208 opacity: 0.6;
2209 border-top: 1px solid var(--border);
2210 }
2211 .article-page .lib-text-footer a { color: var(--content); }
2212
2213 /* Media player play/pause icon initial state. The JS in media-player.js
2214 toggles via element.style.display directly, so we must NOT use
2215 !important here, element.style would still beat a normal-priority
2216 declaration, but !important in the stylesheet would defeat that. */
2217 .media-icon-hidden { display: none; }
2218
2219 /* Video element fills its .video-display parent. .video-display already
2220 provides a black background. */
2221 .video-display video { width: 100%; }
2222
2223 /* Cover image inside .cover-art on library_audio.html, the parent
2224 .cover-art already sets aspect ratio and centering; the inline
2225 width/aspect-ratio/object-fit was redundant with .cover-art img. */
2226
2227 /* ===========================================
2228 USER DASHBOARD TABS (support / sessions / buyer contacts)
2229 =========================================== */
2230
2231 /* Sessions tab (templates/partials/tabs/user_sessions.html). */
2232 .sessions-tab .sessions-table { width: 100%; }
2233 .sessions-tab .device-cell {
2234 max-width: 300px;
2235 overflow: hidden;
2236 text-overflow: ellipsis;
2237 white-space: nowrap;
2238 }
2239
2240 /* Buyer contacts tab (templates/partials/tabs/buyer_contacts.html). */
2241 .buyer-contacts .contacts-table { min-width: 500px; }
2242
2243 /* ===========================================
2244 LIBRARY TABS
2245 Shared classes for the library-dashboard tab partials:
2246 library_wishlists, library_contacts, library_purchases,
2247 library_subscriptions. Migrated from inline styles.
2248 =========================================== */
2249
2250 /* Tables in library tabs need a minimum width so columns stay readable
2251 while the outer container scrolls horizontally on narrow viewports. */
2252
2253 /* Empty-state hint paragraph (smaller, slightly faded). */
2254 .library-tab-empty-hint {
2255 font-size: var(--text-note);
2256 opacity: 0.7;
2257 margin-bottom: var(--gap-section);
2258 }
2259
2260 /* Compact row-action button (wishlist Add to Cart / Remove, etc.). */
2261
2262 .library-filter-wrap { margin-bottom: var(--gap-section); }
2263
2264 /* Purchases table "Open" action link + context menu trigger group. */
2265 .library-row-actions {
2266 display: flex;
2267 align-items: center;
2268 gap: var(--gap-peer);
2269 }
2270 .library-row-open {
2271 font-size: var(--text-fine);
2272 padding: var(--gap-bound) var(--gap-section);
2273 text-decoration: none;
2274 white-space: nowrap;
2275 }
2276
2277 /* Section sub-heading inside purchases tab (e.g. "Subscriptions"). */
2278 .library-tab-subheading {
2279 font-size: var(--text-lead);
2280 margin-top: var(--gap-page);
2281 margin-bottom: var(--gap-section);
2282 opacity: 0.8;
2283 }
2284
2285 /* Inline-block button styled as a link target on empty-state CTAs. */
2286 .library-tab-cta {
2287 display: inline-block;
2288 text-decoration: none;
2289 }
2290
2291 /* Context menu (dropdown) on each purchase row. */
2292 .context-menu-wrapper { position: relative; }
2293 .context-menu-btn {
2294 background: none;
2295 border: none;
2296 cursor: pointer;
2297 padding: var(--gap-peer);
2298 font-size: var(--text-subhead);
2299 line-height: 1;
2300 color: var(--content-muted);
2301 border-radius: var(--radius-control);
2302 }
2303 .context-menu-btn:hover {
2304 background: var(--surface-sunken);
2305 color: var(--content);
2306 }
2307 .context-menu {
2308 display: none;
2309 position: absolute;
2310 right: 0;
2311 top: 100%;
2312 background: var(--surface-overlay);
2313 border: 1px solid var(--border);
2314 box-shadow: var(--elevation-overlay);
2315 min-width: 160px;
2316 z-index: var(--z-context);
2317 }
2318 .context-menu.open { display: block; }
2319 .context-menu-item {
2320 display: block;
2321 width: 100%;
2322 padding: var(--gap-section);
2323 text-align: left;
2324 background: none;
2325 border: none;
2326 font-family: var(--font-sans);
2327 font-size: var(--text-note);
2328 color: var(--content);
2329 cursor: pointer;
2330 text-decoration: none;
2331 }
2332 .context-menu-item:hover { background: var(--surface-sunken); }
2333 .context-menu-item.danger { color: var(--danger); }
2334
2335 /* Inline license-key code chip shown beneath a purchase date. */
2336 .license-key-inline { margin-top: var(--gap-bound); }
2337 .key-code-small {
2338 font-size: var(--text-fine);
2339 padding: var(--gap-bound) var(--gap-peer);
2340 background: var(--surface-sunken);
2341 border-radius: var(--radius-control);
2342 cursor: pointer;
2343 user-select: all;
2344 }
2345 .key-code-small:hover { background: var(--border); }
2346
2347 /* Library row title link reads as plain text until hovered. */
2348 .library-title-link:hover { text-decoration: underline; }
2349 /* ===========================================
2350 ADMIN ENTRIES (replaces inline styles in partials/admin_user_entries.html,
2351 partials/admin_waitlist_entries.html,
2352 partials/admin_appeal_entries.html)
2353 =========================================== */
2354
2355 /* (`.badge-active` / `.badge-trusted` removed in wave 2 tier B2. They were a
2356 second, ad-hoc spelling of what data-tone="success" already says, and the
2357 admin entries take the tone now.) */
2358
2359 /* "Trust" toggle button sits next to a Trusted badge. */
2360 .admin-entries-trust-btn {
2361 margin-left: var(--gap-bound);
2362 }
2363
2364 /* Waitlist pitch cell, narrow body text. */
2365 .admin-entries-pitch {
2366 font-size: var(--text-note);
2367 max-width: 300px;
2368 }
2369 .admin-entries-pitch-empty {
2370 opacity: 0.5;
2371 font-style: italic;
2372 }
2373 .admin-entries-pitch-inviter {
2374 margin-top: var(--gap-bound);
2375 }
2376
2377 /* Appeal text columns. */
2378 .admin-entries-reason {
2379 font-size: var(--text-note);
2380 max-width: 200px;
2381 }
2382 .admin-entries-appeal {
2383 font-size: var(--text-note);
2384 max-width: 300px;
2385 }
2386
2387 /* Decide form textarea + stacked action buttons. */
2388 .admin-entries-decide-textarea {
2389 width: 200px;
2390 }
2391 .admin-entries-decide-actions {
2392 display: flex;
2393 flex-direction: column;
2394 gap: var(--gap-bound);
2395 }
2396
2397 /* Pagination row at the bottom of admin entry tables. */
2398 .admin-entries-pagination {
2399 display: flex;
2400 justify-content: center;
2401 align-items: center;
2402 gap: var(--gap-section);
2403 padding: var(--gap-section) 0;
2404 }
2405
2406 /* ===========================================
2407 ITEM TABS (item_settings, item_sales, item_overview partials)
2408 =========================================== */
2409
2410 /* Schedule form is hidden until "Schedule" button is clicked. JS toggles
2411 the `.hidden` utility class. */
2412 .item-settings-schedule-form {
2413 margin-top: var(--gap-section);
2414 }
2415
2416 .item-overview-embed {
2417 margin-top: var(--gap-pane);
2418 }
2419 .item-overview-embed > summary {
2420 cursor: pointer;
2421 font-weight: bold;
2422 font-size: var(--text-lead);
2423 }
2424
2425 /* ===========================================
2426 ITEM TEXT EDITOR (partials/item_text_editor.html)
2427 =========================================== */
2428
2429 .text-editor-actions {
2430 margin-top: var(--gap-section);
2431 }
2432
2433 /* ===========================================
2434 PROJECT ANALYTICS TAB (partials/tabs/project_analytics.html)
2435 =========================================== */
2436
2437 .tab-docs-extra {
2438 margin-left: var(--gap-section);
2439 }
2440
2441 .analytics-tab-header {
2442 display: flex;
2443 justify-content: space-between;
2444 align-items: center;
2445 margin-bottom: var(--gap-section);
2446 }
2447 .analytics-tab-header h2 {
2448 font-size: var(--text-lead);
2449 margin: 0;
2450 }
2451
2452 .analytics-empty-block {
2453 text-align: center;
2454 padding: var(--gap-page) var(--gap-section);
2455 opacity: 0.6;
2456 }
2457
2458 /* ===========================================
2459 RECEIPT PAGE INLINE FRAGMENTS (pages/receipt.html)
2460 =========================================== */
2461
2462 .receipt-page .receipt-brand {
2463 opacity: 0.6;
2464 font-size: var(--text-note);
2465 }
2466 .receipt-page .receipt-meta {
2467 text-align: right;
2468 }
2469 .receipt-page .receipt-meta-line {
2470 font-family: var(--font-mono);
2471 font-size: var(--text-note);
2472 opacity: 0.6;
2473 }
2474 .receipt-page .receipt-meta-sub {
2475 font-family: var(--font-mono);
2476 font-size: var(--text-fine);
2477 opacity: 0.4;
2478 margin-top: var(--gap-bound);
2479 }
2480 .receipt-page .print-btn {
2481 margin-top: var(--gap-section);
2482 font-size: var(--text-note);
2483 }
2484
2485 /* ===========================================
2486 IMPORT PAGE INLINE FRAGMENTS (dashboards/dashboard-import.html)
2487 =========================================== */
2488
2489 .import-page .import-preview-label,
2490 .import-page .import-mapping-label,
2491 .import-page .import-progress-label {
2492 font-family: var(--font-mono);
2493 font-size: var(--text-note);
2494 margin-bottom: var(--gap-peer);
2495 }
2496 .import-page .import-mapping-label {
2497 margin-bottom: var(--gap-section);
2498 }
2499 .import-page .import-progress-label {
2500 font-size: var(--text-note);
2501 }
2502 .import-page .import-start-btn {
2503 margin-top: var(--gap-section);
2504 }
2505 .import-page .import-history-heading {
2506 font-size: var(--text-subhead);
2507 margin-bottom: var(--gap-section);
2508 }
2509
2510 /* ===========================================
2511 SLUG STATUS PARTIAL (partials/slug_status.html)
2512 =========================================== */
2513
2514 .slug-status {
2515 font-size: var(--text-note);
2516 }
2517 .slug-status.available { color: var(--success); }
2518 .slug-status.taken { color: var(--danger); }
2519
2520 .slug-suggestions {
2521 font-size: var(--text-note);
2522 display: block;
2523 margin-top: var(--gap-bound);
2524 }
2525 .slug-suggestion-link {
2526 margin-right: var(--gap-peer);
2527 }
2528
2529 /* ===========================================
2530 STRIPE DISCLAIMER PAGE (pages/stripe_disclaimer.html)
2531 =========================================== */
2532
2533 .stripe-disclaimer-page .container {
2534 max-width: 700px;
2535 margin: var(--gap-pane) auto;
2536 padding: 0 var(--gap-page);
2537 }
2538 .stripe-disclaimer-page .stripe-disclaimer-title {
2539 text-align: center;
2540 }
2541 .stripe-disclaimer-page .tagline {
2542 font-size: var(--text-note);
2543 opacity: 0.7;
2544 margin-bottom: var(--gap-page);
2545 text-align: center;
2546 }
2547 .stripe-disclaimer-page h2 {
2548 font-size: var(--text-head);
2549 margin-bottom: var(--gap-pane);
2550 }
2551 .stripe-disclaimer-page .stripe-disclaimer-lead {
2552 margin-bottom: var(--gap-pane);
2553 opacity: 0.8;
2554 }
2555 .stripe-disclaimer-page .section { margin-bottom: var(--gap-page); }
2556 .stripe-disclaimer-page .section h3 {
2557 font-size: var(--text-lead);
2558 margin-bottom: var(--gap-section);
2559 font-family: var(--font-mono);
2560 }
2561 .stripe-disclaimer-page .section ul {
2562 margin: 0;
2563 padding-left: var(--gap-section);
2564 }
2565 .stripe-disclaimer-page .section li {
2566 margin-bottom: var(--gap-peer);
2567 line-height: 1.5;
2568 }
2569 .stripe-disclaimer-page .stripe-disclaimer-fee-lead {
2570 margin-bottom: var(--gap-section);
2571 }
2572 .stripe-disclaimer-page .fee-example {
2573 background: var(--surface-page);
2574 padding: var(--gap-section);
2575 margin: var(--gap-section) 0;
2576 font-family: var(--font-mono);
2577 font-size: var(--text-note);
2578 }
2579 .stripe-disclaimer-page .fee-row {
2580 display: flex;
2581 justify-content: space-between;
2582 padding: var(--gap-bound) 0;
2583 }
2584 .stripe-disclaimer-page .fee-row.highlight {
2585 font-weight: bold;
2586 border-top: 1px solid var(--border);
2587 margin-top: var(--gap-peer);
2588 padding-top: var(--gap-peer);
2589 }
2590 .stripe-disclaimer-page .fee-row .zero { color: var(--content); }
2591 .stripe-disclaimer-page .stripe-disclaimer-note {
2592 font-size: var(--text-note);
2593 opacity: 0.8;
2594 }
2595 .stripe-disclaimer-page .acceptance {
2596 background: var(--surface-page);
2597 padding: var(--gap-section);
2598 margin: var(--gap-pane) 0;
2599 }
2600 .stripe-disclaimer-page .checkbox-group {
2601 display: flex;
2602 align-items: flex-start;
2603 gap: var(--gap-section);
2604 }
2605 .stripe-disclaimer-page .checkbox-group input[type="checkbox"] {
2606 margin-top: var(--gap-bound);
2607 flex-shrink: 0;
2608 }
2609 .stripe-disclaimer-page .checkbox-group label {
2610 line-height: 1.5;
2611 cursor: pointer;
2612 }
2613 .stripe-disclaimer-page .button-row {
2614 display: flex;
2615 gap: var(--gap-section);
2616 margin-top: var(--gap-pane);
2617 }
2618 .stripe-disclaimer-page .button-row button { flex: 1; }
2619 .stripe-disclaimer-page button:disabled {
2620 opacity: 0.5;
2621 cursor: not-allowed;
2622 }
2623 .stripe-disclaimer-page .note {
2624 font-size: var(--text-note);
2625 opacity: 0.6;
2626 margin-top: var(--gap-section);
2627 text-align: center;
2628 }
2629
2630