Skip to main content

euv_ui/style/class/page/
fn.rs

1use super::*;
2
3class! {
4    // ═══════════════════════════════════════════════════════════════════════════
5    // Page Banner (unified header with emoji icon)
6    // ═══════════════════════════════════════════════════════════════════════════
7
8    pub(crate) c_page {
9        position: "relative";
10        text-align: "center";
11        box-sizing: "border-box";
12    }
13
14    pub(crate) c_page_glow {
15        position: "absolute";
16        top: "-50%";
17        left: "50%";
18        transform: "translateX(-50%)";
19        width: "400px";
20        max-width: "100%";
21        height: "400px";
22        pointer-events: "none";
23    }
24
25    pub(crate) c_page_content {
26        position: "relative";
27        z-index: "1";
28    }
29
30    pub(crate) c_page_icon {
31        font-size: "36px";
32        padding-bottom: var!(space-md);
33        @media ((max-width: 767px)) {
34            font-size: "40px";
35        }
36    }
37
38    pub(crate) c_page_title {
39        font-size: var!(font-4xl);
40        font-weight: "800";
41        letter-spacing: "-0.03em";
42        margin: "0px";
43        color: var!(foreground);
44        margin-bottom: var!(space-sm);
45        @media ((max-width: 767px)) {
46            font-size: var!(font-3xl);
47        }
48    }
49
50    pub(crate) c_page_subtitle {
51        font-size: var!(font-lg);
52        color: var!(muted-foreground);
53        margin: "0px auto";
54        margin-bottom: var!(space-sm);
55        max-width: "560px";
56        opacity: "1";
57        @media ((max-width: 767px)) {
58            font-size: var!(font-base);
59        }
60    }
61
62    // ═══════════════════════════════════════════════════════════════════════════
63    // Camera Page
64    // ═══════════════════════════════════════════════════════════════════════════
65
66    pub c_camera_video_container {
67        margin: format!("{} 0", var!(space-lg));
68    }
69
70    pub c_camera_video_active {
71        width: "100%";
72        background: "#000";
73        aspect-ratio: "16 / 9";
74        object-fit: "cover";
75        border: format!("2px solid {}", var!(accent));
76        box-sizing: "border-box";
77    }
78
79    pub c_camera_video_hidden {
80        width: "100%";
81        aspect-ratio: "16 / 9";
82        display: "none";
83    }
84
85    pub c_camera_video_placeholder {
86        width: "100%";
87        aspect-ratio: "16 / 9";
88        border: format!("2px dashed {}", var!(border));
89        display: "flex";
90        align-items: "center";
91        justify-content: "center";
92        box-sizing: "border-box";
93    }
94
95    pub c_camera_placeholder_content {
96        display: "flex";
97        flex-direction: "column";
98        align-items: "center";
99        gap: var!(space-md);
100    }
101
102    pub c_camera_placeholder_icon {
103        font-size: var!(font-4xl);
104        opacity: "1";
105    }
106
107    pub c_camera_placeholder_text {
108        font-size: var!(font-base);
109        color: "inherit";
110        opacity: "1";
111    }
112
113    pub c_camera_error_box {
114        margin: format!("{} 0px", var!(gap-component));
115        color: var!(foreground);
116        font-size: var!(font-base);
117        word-break: "break-all";
118        overflow-wrap: "break-word";
119        box-sizing: "border-box";
120    }
121
122    pub c_camera_scan_result_box {
123        margin-top: var!(gap-component);
124        box-sizing: "border-box";
125    }
126
127    pub c_camera_scan_result_label {
128        font-size: var!(font-sm);
129        font-weight: "600";
130        color: var!(foreground);
131        margin-bottom: var!(space-xs);
132    }
133
134    pub c_camera_scan_result_value {
135        font-size: var!(font-base);
136        color: "inherit";
137        word-break: "break-all";
138        overflow-wrap: "break-word";
139    }
140
141    // ═══════════════════════════════════════════════════════════════════════════
142    // Canvas Drawing Board
143    // ═══════════════════════════════════════════════════════════════════════════
144
145    pub c_canvas_preview_container {
146        margin: format!("{} 0", var!(space-lg));
147        overflow: "hidden";
148        border: format!("2px solid {}", var!(border));
149        background: "#ffffff";
150        aspect-ratio: "9 / 16";
151        display: "flex";
152        align-items: "center";
153        justify-content: "center";
154        box-sizing: "border-box";
155    }
156
157    pub c_canvas_placeholder {
158        color: var!(muted-foreground);
159        font-size: var!(font-sm);
160        text-align: "center";
161        padding: var!(space-lg);
162    }
163
164    pub c_canvas_preview_image {
165        width: "100%";
166        height: "100%";
167        object-fit: "cover";
168        display: "block";
169    }
170
171    pub c_canvas_container_fullscreen {
172        width: "100%";
173        height: "100%";
174        background: var!(background);
175        display: "flex";
176        flex-direction: "column";
177        position: "fixed";
178        top: "0";
179        left: "0";
180        z-index: "10002";
181        padding: format!("{} {} {} {}", var!(padding-shell-top), var!(space-lg), var!(padding-shell-bottom), var!(space-lg));
182        box-sizing: "border-box";
183    }
184
185    pub c_canvas_drawing_fullscreen_wrapper {
186        flex: "1";
187        display: "flex";
188        align-items: "center";
189        justify-content: "center";
190        overflow: "hidden";
191        padding: var!(space-xs);
192    }
193
194    pub c_canvas_drawing_fullscreen {
195        border: format!("2px solid {}", var!(border));
196        display: "block";
197        cursor: "crosshair";
198        touch-action: "none";
199    }
200
201    pub c_canvas_fullscreen_toolbar {
202        display: "flex";
203        flex-direction: "column";
204        align-items: "stretch";
205        width: "100%";
206        padding: format!("{} {}", var!(space-xs), "0px");
207        flex-shrink: "0";
208        gap: var!(space-xs);
209    }
210
211    pub c_canvas_fullscreen_toolbar_row_top {
212        display: "flex";
213        align-items: "center";
214        height: var!(mobile-header-height);
215        width: "100%";
216        gap: var!(space-sm);
217    }
218
219    pub c_canvas_fullscreen_toolbar_color_wrapper {
220        display: "flex";
221        align-items: "center";
222        justify-content: "center";
223        flex: "1";
224        min-width: "0";
225    }
226
227    pub c_canvas_color_input_fullscreen {
228        width: "100%";
229        height: "42px";
230        border: format!("1px solid {}", var!(border));
231        cursor: "pointer";
232        padding: format!("{}", var!(space-xs));
233    }
234
235    pub c_canvas_fullscreen_toolbar_row_bottom {
236        display: "flex";
237        align-items: "center";
238        width: "100%";
239    }
240
241    pub c_canvas_fullscreen_range_input {
242        flex: "1 1 0%";
243        min-width: "120px";
244        cursor: "pointer";
245        -webkit-appearance: "none";
246        appearance: "none";
247        border: "none";
248        outline: "none";
249        height: "24px";
250        ::-webkit-slider-runnable-track {
251            height: "6px";
252            background: format!("linear-gradient(to right, {} 0%, {} var(--value,50%), {} var(--value,50%), {} 100%)", var!(foreground), var!(foreground), var!(border), var!(border));
253            border-radius: "3px";
254            border: "none";
255        }
256        ::-webkit-slider-thumb {
257            width: "20px";
258            height: "20px";
259            background: var!(background);
260            border: format!("2px solid {}", var!(accent));
261            border-radius: "50%";
262            cursor: "pointer";
263            -webkit-appearance: "none";
264            margin-top: "-7px";
265        }
266        ::-moz-range-track {
267            height: "6px";
268            background: format!("linear-gradient(to right, {} 0%, {} var(--value,50%), {} var(--value,50%), {} 100%)", var!(foreground), var!(foreground), var!(border), var!(border));
269            border-radius: "3px";
270            border: "none";
271        }
272        ::-moz-range-thumb {
273            width: "20px";
274            height: "20px";
275            background: var!(background);
276            border: format!("2px solid {}", var!(accent));
277            border-radius: "50%";
278            cursor: "pointer";
279        }
280    }
281
282    pub c_canvas_fullscreen_toolbar_button {
283        flex: "0 0 auto";
284        overflow: "hidden";
285    }
286
287    // ═══════════════════════════════════════════════════════════════════════════
288    // Game Fullscreen (2D / 3D)
289    // ═══════════════════════════════════════════════════════════════════════════
290
291    // Fullscreen overlay container for the 2D and 3D game pages.
292    //
293    // Mirrors `c_canvas_container_fullscreen` so the safe-area caching
294    // pass in `UseEuvLayout::apply_cached_insets` can pick this selector
295    // up alongside the canvas one. Differs in that the game overlay holds
296    // the *same* `<canvas>` element that the inline page mounts (no
297    // canvas re-creation), so the running game loop, balls, cubes, FPS
298    // counter and other reactive state survive the fullscreen toggle
299    // without reset.
300    pub c_game_container_fullscreen {
301        width: "100%";
302        height: "100%";
303        background: var!(background);
304        display: "flex";
305        flex-direction: "column";
306        position: "fixed";
307        top: "0";
308        left: "0";
309        z-index: "10002";
310        padding: format!(
311        "{} {} {} {}",
312        var!(padding-shell-top),
313        var!(space-lg),
314        var!(padding-shell-bottom),
315        var!(space-lg)
316        );
317        box-sizing: "border-box";
318    }
319
320    // Toolbar wrapping the fullscreen exit button on game pages.
321    //
322    // Game pages only need an `Exit` button here (no color picker / line
323    // width control like the canvas drawing board), so the layout is a
324    // single horizontal row at the bottom of the overlay.
325    pub c_game_fullscreen_toolbar {
326        display: "flex";
327        align-items: "center";
328        justify-content: "flex-end";
329        width: "100%";
330        padding: format!("{} {} {} {}", var!(space-xs), var!(space-lg), var!(space-xs), var!(space-lg));
331        flex-shrink: "0";
332        gap: var!(space-sm);
333        box-sizing: "border-box";
334    }
335
336    // Wrapper that fills the fullscreen game container with the canvas.
337    //
338    // The game's `<canvas>` backing buffer is 600x400 (3:2). The canvas
339    // itself has `width: 100%; height: 100%` so it fills this wrapper
340    // exactly, and `object-fit: contain` on the canvas class makes the
341    // browser uniformly scale the backing buffer to fit while preserving
342    // its 3:2 aspect ratio. Without `object-fit: contain`, the canvas
343    // would be stretched to whatever shape the wrapper has, making balls
344    // render as horizontally-ovoid ellipses (e.g. on 1280x800 viewports
345    // → 1.6:1, slightly squashed vertically). The letterbox bars appear
346    // inside the canvas element rather than around an outer wrapper, so
347    // the canvas always fills the fullscreen container with the backing
348    // buffer uniformly scaled to its native aspect ratio.
349    pub c_game_fullscreen_canvas_letterbox {
350        position: "relative";
351        width: "100%";
352        max-width: "100%";
353        max-height: "100%";
354        height: "100%";
355        display: "flex";
356        align-items: "center";
357        justify-content: "center";
358    }
359
360    // ═══════════════════════════════════════════════════════════════════════════
361    // Custom Attrs Demo
362    // ═══════════════════════════════════════════════════════════════════════════
363
364    pub c_custom_attrs_demo {
365        // Use the theme foreground token (not `inherit`) so the text inside
366        // the dynamic demo block stays readable when the block itself
367        // applies a user-supplied background (e.g. `background-color: #000000`)
368        // that otherwise paints the inherited text the same colour.
369        color: var!(foreground);
370        box-sizing: "border-box";
371    }
372
373    pub c_demo_text {
374        color: var!(foreground);
375        margin-bottom: var!(gap-component);
376    }
377
378    pub c_demo_text_muted {
379        color: var!(foreground);
380        opacity: "1";
381        font-size: var!(font-base);
382        margin-bottom: "0px";
383    }
384
385    // ═══════════════════════════════════════════════════════════════════════════
386    // Conditional Rendering Demo
387    // ═══════════════════════════════════════════════════════════════════════════
388
389    pub c_toggle_content {
390        margin-top: var!(gap-component);
391        color: "inherit";
392    }
393
394    pub c_toggle_title {
395        margin-top: "0px";
396        color: var!(accent);
397        font-size: var!(font-md);
398    }
399
400    pub c_role_button_row {
401        display: "flex";
402        flex-wrap: "nowrap";
403        gap: var!(gap-element);
404        margin-bottom: var!(gap-component);
405    }
406
407    pub c_role_guest_text {
408        color: var!(foreground);
409        font-size: var!(font-base);
410    }
411
412    pub c_role_user_text {
413        color: var!(foreground);
414        font-size: var!(font-base);
415    }
416
417    pub c_role_admin_text {
418        color: var!(foreground);
419        font-size: var!(font-base);
420    }
421
422    // ═══════════════════════════════════════════════════════════════════════════
423    // 404 Not Found
424    // ═══════════════════════════════════════════════════════════════════════════
425
426    pub c_render_count_text {
427        font-size: var!(font-base);
428        color: "inherit";
429        margin-bottom: var!(gap-component);
430    }
431
432    // ═══════════════════════════════════════════════════════════════════════════
433    // Event Demo
434    // ═══════════════════════════════════════════════════════════════════════════
435
436    pub c_event_result {
437        font-size: var!(font-base);
438        color: "inherit";
439        margin-top: var!(gap-element);
440    }
441
442    pub c_event_highlight {
443        font-weight: "600";
444        color: var!(accent);
445    }
446
447    pub c_event_info_grid {
448        display: "grid";
449        grid-template-columns: "1fr 1fr";
450        gap: var!(gap-element);
451        margin-top: var!(gap-component);
452        @media ((max-width: 767px)) {
453            grid-template-columns: "1fr";
454            gap: var!(gap-element);
455        }
456    }
457
458    pub c_event_info_row {
459        display: "flex";
460        align-items: "center";
461        gap: var!(space-sm);
462        overflow: "hidden";
463    }
464
465    pub c_event_info_label {
466        font-size: var!(font-base);
467        font-weight: "600";
468        color: var!(foreground);
469        flex-shrink: "0";
470    }
471
472    pub c_event_info_value {
473        c_text_ellipsis();
474        font-size: var!(font-base);
475        font-weight: "600";
476        color: var!(accent);
477        font-family: "ui-monospace, monospace";
478        flex: "1";
479    }
480
481    pub c_event_mouse_area {
482        min-height: "120px";
483        padding: format!("{} 0px", var!(space-xl));
484        border: format!("2px dashed {}", var!(border));
485        cursor: "crosshair";
486        text-align: "center";
487        user-select: "none";
488        color: "inherit";
489    }
490
491    pub c_event_drag_zone {
492        min-height: "100px";
493        padding: format!("{} 0px", var!(space-xl));
494        border: format!("2px dashed {}", var!(border));
495        text-align: "center";
496        user-select: "none";
497        color: var!(foreground);
498    }
499
500    pub c_event_drag_zone_active {
501        min-height: "100px";
502        padding: format!("{} 0px", var!(space-xl));
503        border: format!("2px dashed {}", var!(border));
504        text-align: "center";
505        user-select: "none";
506        color: var!(foreground);
507    }
508
509    pub c_event_drag_item {
510        display: "inline-block";
511        padding: format!("{} {}", var!(space-sm), var!(space-xl));
512        background: var!(accent);
513        color: var!(text-on-accent);
514        font-size: var!(font-base);
515        font-weight: "500";
516        cursor: "grab";
517        margin: var!(space-sm);
518    }
519
520    pub c_event_drop_zone {
521        border: format!("2px dashed {}", var!(border));
522        padding: format!("{} {}", var!(space-4xl), var!(space-xl));
523        text-align: "center";
524        cursor: "pointer";
525    }
526
527    pub c_event_drop_zone_active {
528        border: format!("2px dashed {}", var!(accent));
529        padding: format!("{} {}", var!(space-4xl), var!(space-xl));
530        text-align: "center";
531        cursor: "pointer";
532        background: var!(accent-muted);
533    }
534
535    pub c_event_drop_icon {
536        font-size: var!(font-5xl);
537        display: "block";
538        padding-bottom: var!(space-md);
539    }
540
541    pub c_event_drop_text {
542        font-size: var!(font-lg);
543        font-weight: "500";
544        color: "inherit";
545        padding-bottom: var!(space-md);
546    }
547
548    pub c_event_drop_hint {
549        font-size: var!(font-base);
550        color: "inherit";
551        opacity: "1";
552        margin: "0px";
553    }
554
555    pub c_event_wheel_zone {
556        min-height: "120px";
557        padding: format!("{} 0px", var!(space-xl));
558        border: format!("2px dashed {}", var!(border));
559        text-align: "center";
560        overflow: "auto";
561        color: var!(foreground);
562    }
563
564    pub c_event_clipboard_area {
565        color: var!(foreground);
566    }
567
568    pub c_event_touch_zone {
569        min-height: "120px";
570        padding: format!("{} 0px", var!(space-xl));
571        border: format!("2px dashed {}", var!(accent));
572        text-align: "center";
573        touch-action: "none";
574        user-select: "none";
575        color: var!(accent);
576    }
577
578    pub c_event_form_area {
579        padding: format!("{} 0px", var!(space-lg));
580        color: var!(foreground);
581    }
582
583    pub c_event_media_area {
584        padding: format!("{} 0px", var!(space-lg));
585        color: var!(foreground);
586        max-width: "100%";
587        overflow: "hidden";
588    }
589
590    pub c_event_audio {
591        width: "100%";
592        max-width: "100%";
593    }
594
595    pub c_event_video_area {
596        color: var!(foreground);
597        width: "100%";
598        overflow: "hidden";
599    }
600
601    pub c_event_video {
602        width: "100%";
603        max-width: "100%";
604    }
605
606    pub c_event_image_area {
607        padding: format!("{} 0px", var!(space-lg));
608        color: "inherit";
609        width: "100%";
610        overflow: "hidden";
611        display: "flex";
612        flex-direction: "column";
613        align-items: "center";
614        gap: var!(space-md);
615    }
616
617    pub c_event_image {
618        width: "200px";
619        max-width: "100%";
620        object-fit: "contain";
621        display: "block";
622    }
623
624    pub c_event_url_text {
625        text-align: "center";
626        font-size: var!(font-sm);
627        color: "inherit";
628        opacity: "1";
629        font-family: "ui-monospace, monospace";
630        word-break: "break-all";
631        width: "100%";
632    }
633
634    // ═══════════════════════════════════════════════════════════════════════════
635    // Timer Demo
636    // ═══════════════════════════════════════════════════════════════════════════
637
638    pub c_timer_display {
639        text-align: "center";
640        padding: var!(space-xl);
641        margin: format!("{} 0px", var!(gap-component));
642        color: "inherit";
643    }
644
645    pub c_timer_value {
646        font-size: var!(font-base);
647        font-weight: "700";
648        color: var!(accent);
649        letter-spacing: "0.04em";
650        font-family: "ui-monospace, monospace";
651    }
652
653    pub c_timer_controls {
654        display: "flex";
655        flex-wrap: "wrap";
656        gap: var!(gap-element);
657    }
658
659    pub c_timer_done {
660        text-align: "center";
661        margin-top: var!(gap-component);
662        font-size: var!(font-lg);
663        font-weight: "600";
664        color: var!(foreground);
665    }
666
667    // ═══════════════════════════════════════════════════════════════════════════
668    // Browser API Demo
669    // ═══════════════════════════════════════════════════════════════════════════
670
671    pub c_browser_api_row {
672        display: "grid";
673        grid-template-columns: "1fr 1fr";
674        gap: var!(gap-component);
675        margin-bottom: var!(gap-component);
676        @media ((max-width: 767px)) {
677            grid-template-columns: "1fr";
678        }
679    }
680
681    pub c_browser_api_actions {
682        display: "flex";
683        flex-wrap: "wrap";
684        gap: var!(gap-element);
685        margin: format!("{} 0px", var!(gap-component));
686    }
687
688    pub c_browser_result_box {
689        margin-top: var!(gap-component);
690        font-size: var!(font-base);
691        word-break: "break-all";
692        color: "inherit";
693    }
694
695    pub c_browser_result_label {
696        font-weight: "600";
697        color: var!(accent);
698    }
699
700    pub c_browser_result_value {
701        color: "inherit";
702    }
703
704    pub c_browser_info_grid {
705        display: "grid";
706        gap: var!(gap-component);
707        margin-top: var!(gap-component);
708        @media ((max-width: 767px)) {
709            grid-template-columns: "1fr";
710        }
711    }
712
713    pub c_browser_info_item {
714        display: "flex";
715        flex-direction: "column";
716        gap: var!(space-xs);
717        color: "inherit";
718    }
719
720    pub c_browser_info_label {
721        font-size: var!(font-sm);
722        font-weight: "600";
723        color: "inherit";
724        opacity: "1";
725        text-transform: "uppercase";
726        letter-spacing: "0.05em";
727    }
728
729    pub c_browser_info_value {
730        font-size: var!(font-base);
731        color: "inherit";
732        word-break: "break-all";
733        font-family: "ui-monospace, monospace";
734    }
735
736    // ═══════════════════════════════════════════════════════════════════════════
737    // Keep-Alive Demo
738    // ═══════════════════════════════════════════════════════════════════════════
739
740    pub c_keep_alive_tab_bar {
741        display: "flex";
742        border-bottom: format!("1px dashed {}", var!(border));
743        margin-bottom: var!(gap-component);
744        gap: var!(gap-element);
745    }
746
747    pub c_keep_alive_tab_panel {
748        padding: format!("{} 0px", var!(gap-element));
749    }
750
751    pub c_keep_alive_panel_title {
752        margin-top: "0px";
753        color: var!(accent);
754        font-size: var!(font-md);
755        margin-bottom: var!(gap-element);
756    }
757
758    pub c_keep_alive_demo_text {
759        color: "inherit";
760        font-size: var!(font-base);
761        margin-bottom: var!(gap-component);
762    }
763
764    pub c_keep_alive_counter_display {
765        display: "flex";
766        justify-content: "center";
767        align-items: "center";
768        margin: format!("{} 0px", var!(space-xl));
769    }
770
771    pub c_keep_alive_counter_value {
772        font-size: var!(font-base);
773        font-weight: "700";
774        font-variant-numeric: "tabular-nums";
775        color: var!(accent);
776        text-align: "center";
777    }
778
779    pub c_keep_alive_counter_controls {
780        display: "flex";
781        flex-wrap: "wrap";
782        gap: format!("{}", var!(space-md));
783    }
784
785    pub c_keep_alive_form_group {
786        margin-bottom: var!(gap-component);
787    }
788
789    pub c_keep_alive_form_preview {
790        margin-top: var!(gap-component);
791        background: var!(accent-muted);
792    }
793
794    pub c_keep_alive_preview_label {
795        font-size: var!(font-base);
796        font-weight: "600";
797        color: var!(accent);
798        margin: format!("0px 0px {} 0px", var!(space-xs));
799    }
800
801    // ═══════════════════════════════════════════════════════════════════════════
802    // Binding Demo
803    // ═══════════════════════════════════════════════════════════════════════════
804
805    pub c_binding_child_box {
806        display: "flex";
807        flex-direction: "column";
808        gap: var!(gap-component);
809        margin-top: var!(gap-component);
810    }
811
812    pub c_binding_child_label {
813        font-size: var!(font-base);
814        font-weight: "600";
815        color: var!(accent);
816        text-transform: "uppercase";
817        letter-spacing: "0.05em";
818    }
819
820    pub c_binding_parent_box {
821        display: "flex";
822        flex-direction: "column";
823        gap: var!(gap-component);
824        margin-top: var!(gap-component);
825    }
826
827    pub c_binding_section_title {
828        margin-top: var!(gap-component);
829        margin-bottom: var!(gap-element);
830        color: var!(accent);
831        font-size: var!(font-md);
832        font-weight: "600";
833    }
834
835    pub c_binding_temp_converter {
836        display: "flex";
837        align-items: "flex-end";
838        gap: var!(gap-component);
839        flex-wrap: "wrap";
840        margin-top: var!(gap-component);
841    }
842
843    pub c_binding_temp_field {
844        flex: "1";
845        min-width: "120px";
846    }
847
848    pub c_binding_temp_arrow {
849        font-size: "20px";
850        font-weight: "700";
851        color: var!(accent);
852        padding-bottom: "10px";
853    }
854
855    pub c_binding_color_mixer {
856        margin-top: var!(gap-component);
857    }
858
859    pub c_binding_color_preview {
860        width: "100%";
861        height: "80px";
862        display: "flex";
863        align-items: "center";
864        justify-content: "center";
865        margin-bottom: var!(gap-component);
866    }
867
868    pub c_binding_color_hex {
869        font-family: "ui-monospace, monospace";
870        font-size: var!(font-xl);
871        font-weight: "700";
872        color: var!(text-on-accent);
873        letter-spacing: "0.02em";
874    }
875
876    pub c_binding_slider_row {
877        display: "flex";
878        align-items: "center";
879        gap: format!("{}", var!(space-md));
880        margin-bottom: var!(space-sm);
881    }
882
883    pub c_binding_slider_label {
884        font-size: var!(font-base);
885        font-weight: "700";
886        min-width: var!(font-sm);
887    }
888
889    pub c_binding_slider {
890        flex: "1";
891        height: "24px";
892        padding: "0px";
893        cursor: "pointer";
894        -webkit-appearance: "none";
895        appearance: "none";
896        border: "none";
897        outline: "none";
898        ::-webkit-slider-runnable-track {
899            height: "6px";
900            background: format!("linear-gradient(to right, {} 0%, {} var(--value,50%), {} var(--value,50%), {} 100%)", var!(foreground), var!(foreground), var!(border), var!(border));
901            border-radius: "3px";
902            border: "none";
903        }
904        ::-webkit-slider-thumb {
905            width: "20px";
906            height: "20px";
907            background: var!(background);
908            border: format!("2px solid {}", var!(accent));
909            border-radius: "50%";
910            cursor: "pointer";
911            -webkit-appearance: "none";
912            margin-top: "-7px";
913        }
914        : active::-webkit-slider-thumb {
915            transform: "scale(0.92)";
916        }
917        ::-moz-range-track {
918            height: "6px";
919            background: format!("linear-gradient(to right, {} 0%, {} var(--value,50%), {} var(--value,50%), {} 100%)", var!(foreground), var!(foreground), var!(border), var!(border));
920            border-radius: "3px";
921            border: "none";
922        }
923        ::-moz-range-thumb {
924            width: "20px";
925            height: "20px";
926            background: var!(background);
927            border: format!("2px solid {}", var!(accent));
928            border-radius: "50%";
929            cursor: "pointer";
930        }
931        : active::-moz-range-thumb {
932            transform: "scale(0.92)";
933        }
934    }
935
936    pub c_binding_slider_value {
937        font-size: var!(font-base);
938        font-weight: "500";
939        color: "inherit";
940        min-width: "32px";
941        text-align: "right";
942        font-family: "ui-monospace, monospace";
943    }
944
945    pub c_binding_typed_prop_value {
946        font-family: "ui-monospace, monospace";
947        font-size: var!(font-base);
948        font-weight: "600";
949        color: var!(accent);
950        padding: format!("1px {}", var!(space-sm));
951    }
952
953    pub c_binding_typed_prop_group {
954        display: "flex";
955        align-items: "center";
956        gap: var!(space-sm);
957    }
958
959    pub c_binding_typed_warning {
960        font-size: var!(font-base);
961        font-weight: "500";
962        color: var!(foreground);
963        margin-bottom: "0px";
964    }
965
966    pub c_binding_form_label {
967        display: "block";
968        color: "inherit";
969        font-weight: "500";
970        font-size: var!(font-base);
971    }
972
973    pub c_binding_demo_text {
974        color: "inherit";
975        margin: "0px"
976    }
977
978    pub c_binding_compact_button {
979        display: "inline-flex";
980        justify-content: "center";
981        align-items: "center";
982        height: "42px";
983        padding: format!("0px {}", var!(space-md));
984        background: var!(accent);
985        color: var!(text-on-accent);
986        border: format!("1px solid {}", var!(accent));
987        cursor: "pointer";
988        font-size: var!(font-sm);
989        font-weight: "600";
990        outline: "none";
991        white-space: "nowrap";
992        user-select: "none";
993        -webkit-user-select: "none";
994        box-sizing: "border-box";
995        :hover {
996            background: var!(accent);
997        }
998        :focus-visible {
999            outline: "none";
1000        }
1001        :active {
1002            background: var!(accent);
1003            color: var!(text-on-accent);
1004            border-color: var!(accent);
1005        }
1006    }
1007
1008    // ═══════════════════════════════════════════════════════════════════════════
1009    // Custom Attrs - Dynamic Style
1010    // ═══════════════════════════════════════════════════════════════════════════
1011
1012    pub c_attrs_dynamic_demo(prop_key: &str, prop_value: &str) {
1013        {
1014            prop_key
1015        }
1016        : prop_value;
1017        // No layout defaults: this class lives on a `<p>` whose own margin /
1018        // spacing is controlled by its parent's typography rules, and pinning
1019        // any colour here would shadow the user-supplied dynamic property.
1020        // Users are expected to set `color` / `background` / `font-*` /
1021        // etc. via the two CSS Property Key / Value inputs above; whatever
1022        // they type becomes the literal CSS rule applied to the paragraph.
1023    }
1024
1025    // ═══════════════════════════════════════════════════════════════════════════
1026    // Dynamic Component Demo
1027    // ═══════════════════════════════════════════════════════════════════════════
1028
1029    pub c_dynamic_component_tab_bar {
1030        display: "flex";
1031        flex-wrap: "wrap";
1032        gap: var!(gap-element);
1033        margin-bottom: var!(gap-component);
1034    }
1035
1036    pub c_dynamic_component_panel {
1037        display: "block";
1038        min-height: var!(min-height-sm);
1039        margin-top: var!(gap-component);
1040    }
1041
1042    // ═══════════════════════════════════════════════════════════════════════════
1043    // Sticky & CSS Effects Demo
1044    // ═══════════════════════════════════════════════════════════════════════════
1045
1046    // ═══════════════════════════════════════════════════════════════════════════
1047    // Home Page — Section
1048    // ═══════════════════════════════════════════════════════════════════════════
1049
1050    pub c_home {
1051        position: "relative";
1052        text-align: "center";
1053        margin-bottom: var!(space-xl);
1054        flex: "1";
1055        display: "flex";
1056        flex-direction: "column";
1057        justify-content: "center";
1058        @media ((max-width: 767px)) {
1059            margin-bottom: var!(space-lg);
1060            flex: "0 0 auto";
1061            justify-content: "flex-start";
1062        }
1063    }
1064
1065    pub c_home_content {
1066        position: "relative";
1067        z-index: "1";
1068    }
1069
1070    pub c_home_badge_row {
1071        display: "inline-flex";
1072        align-items: "center";
1073        // A base rule resets this to `flex`, so the row spans the full column
1074        // and `text-align: center` on the parent no longer centres it — a flex
1075        // child is placed by its own alignment. Without this the badges sit at
1076        // the left edge while the centred title below them does not.
1077        justify-content: "center";
1078        gap: var!(space-sm);
1079        margin-bottom: var!(space-md);
1080    }
1081
1082    pub c_home_badge {
1083        display: "inline-flex";
1084        justify-content: "center";
1085        align-items: "center";
1086        padding: format!("{} {}", var!(space-xs), var!(space-sm));
1087        color: var!(accent);
1088        font-size: var!(font-xs);
1089        font-weight: "600";
1090        letter-spacing: "0.05em";
1091        border: format!("1px solid {}", var!(accent));
1092    }
1093
1094    pub c_home_title {
1095        font-size: var!(font-5xl);
1096        font-weight: "800";
1097        letter-spacing: "-0.03em";
1098        margin: "0px";
1099        color: var!(foreground);
1100        margin-bottom: var!(space-xs);
1101        @media ((max-width: 767px)) {
1102            font-size: var!(font-4xl);
1103        }
1104    }
1105
1106    pub c_home_subtitle {
1107        font-size: var!(font-lg);
1108        color: var!(foreground);
1109        margin: "0px auto";
1110        max-width: "520px";
1111        margin-bottom: var!(space-lg);
1112        @media ((max-width: 767px)) {
1113            font-size: var!(font-base);
1114        }
1115    }
1116
1117    pub c_home_actions {
1118        display: "flex";
1119        gap: var!(space-md);
1120        justify-content: "center";
1121        flex-wrap: "wrap";
1122        // Below the breakpoint the actions become equal-width rows: the two
1123        // labels differ in length, so a content-sized wrap leaves the shorter
1124        // button visibly narrower and the row reads as misaligned.
1125        @media ((max-width: 767px)) {
1126            flex-wrap: "nowrap";
1127            align-items: "stretch";
1128        }
1129    }
1130
1131    pub c_home_btn_primary {
1132        display: "inline-flex";
1133        justify-content: "center";
1134        align-items: "center";
1135        gap: var!(space-sm);
1136        padding: format!("{} {}", var!(space-sm), var!(space-2xl));
1137        background: var!(accent);
1138        color: var!(text-on-accent);
1139        font-size: var!(font-base);
1140        font-weight: "600";
1141        text-decoration: "none";
1142        border: "1.5px solid transparent";
1143        cursor: "pointer";
1144        letter-spacing: "0.01em";
1145        vertical-align: "middle";
1146        min-height: var!(min-height-sm);
1147        @media ((max-width: 767px)) {
1148            flex: "1 1 0px";
1149            min-width: "0px";
1150        }
1151        :focus-visible {
1152            outline: "none";
1153        }
1154        :active {
1155            background: var!(accent);
1156            color: var!(text-on-accent);
1157            border-color: "1.5px solid transparent";
1158        }
1159    }
1160
1161    pub c_home_btn_secondary {
1162        display: "inline-flex";
1163        justify-content: "center";
1164        align-items: "center";
1165        gap: var!(space-sm);
1166        padding: format!("{} {}", var!(space-sm), var!(space-2xl));
1167        color: var!(accent);
1168        font-size: var!(font-base);
1169        font-weight: "600";
1170        text-decoration: "none";
1171        border: format!("1.5px solid {}", var!(accent));
1172        cursor: "pointer";
1173        letter-spacing: "0.01em";
1174        vertical-align: "middle";
1175        min-height: var!(min-height-sm);
1176        @media ((max-width: 767px)) {
1177            flex: "1 1 0px";
1178            min-width: "0px";
1179        }
1180        :focus-visible {
1181            outline: "none";
1182        }
1183        :active {
1184            background: "transparent";
1185            color: var!(accent);
1186            border-color: var!(accent);
1187        }
1188    }
1189
1190    // ═══════════════════════════════════════════════════════════════════════════
1191    // Home Page — Stats Row
1192    // ═══════════════════════════════════════════════════════════════════════════
1193
1194    pub c_home_stats {
1195        display: "grid";
1196        grid-template-columns: "repeat(4, 1fr)";
1197        gap: var!(space-md);
1198        margin-bottom: var!(space-xl);
1199        @media ((max-width: 767px)) {
1200            grid-template-columns: "repeat(2, 1fr)";
1201            gap: var!(space-sm);
1202        }
1203    }
1204
1205    pub c_home_stat_card {
1206        display: "flex";
1207        flex-direction: "column";
1208        align-items: "center";
1209        justify-content: "center";
1210        gap: var!(space-xs);
1211    }
1212
1213    pub c_home_stat_icon {
1214        font-size: var!(font-2xl);
1215    }
1216
1217    pub c_home_stat_value {
1218        font-size: var!(font-xl);
1219        font-weight: "800";
1220        color: var!(foreground);
1221        letter-spacing: "-0.01em";
1222    }
1223
1224    pub c_home_stat_label {
1225        font-size: var!(font-sm);
1226        color: var!(muted-foreground);
1227        font-weight: "500";
1228    }
1229
1230    // ═══════════════════════════════════════════════════════════════════════════
1231    // Home Page — Section & Feature Cards
1232    // ═══════════════════════════════════════════════════════════════════════════
1233
1234    pub c_home_section_title {
1235        font-size: var!(font-2xl);
1236        font-weight: "700";
1237        color: var!(foreground);
1238        margin: "0px";
1239        margin: format!("{} 0px", var!(gap-component));
1240        letter-spacing: "-0.02em";
1241    }
1242
1243    pub c_home_section_desc {
1244        font-size: var!(font-base);
1245        color: var!(foreground);
1246        margin: "0px";
1247        margin-bottom: var!(space-2xl);
1248    }
1249
1250    pub c_home_feature_grid {
1251        display: "grid";
1252        grid-template-columns: "repeat(2, 1fr)";
1253        gap: var!(space-md);
1254        @media ((max-width: 767px)) {
1255            grid-template-columns: "1fr";
1256        }
1257    }
1258
1259    pub c_feature_card {
1260        display: "flex";
1261        flex-direction: "column";
1262        gap: var!(space-sm);
1263        padding: "0px";
1264        overflow: "hidden";
1265    }
1266
1267    pub c_feature_header {
1268        display: "flex";
1269        align-items: "center";
1270        gap: var!(space-sm);
1271    }
1272
1273    pub c_feature_icon {
1274        font-size: var!(font-2xl);
1275        display: "flex";
1276        align-items: "center";
1277        justify-content: "center";
1278        line-height: "1";
1279        flex-shrink: "0";
1280    }
1281
1282    pub c_feature_name {
1283        font-size: var!(font-lg);
1284        font-weight: "600";
1285        color: var!(foreground);
1286        margin: "0px";
1287        overflow: "hidden";
1288        text-overflow: "ellipsis";
1289        white-space: "nowrap";
1290    }
1291
1292    pub c_feature_desc {
1293        font-size: var!(font-sm);
1294        color: var!(foreground);
1295        margin: "0px";
1296    }
1297
1298    // ═══════════════════════════════════════════════════════════════════════════
1299    // Home Page
1300    // ═══════════════════════════════════════════════════════════════════════════
1301
1302    pub(crate) c_text_ellipsis {
1303        overflow: "hidden";
1304        text-overflow: "ellipsis";
1305        white-space: "nowrap";
1306    }
1307
1308    pub c_info_row {
1309        display: "flex";
1310        align-items: "center";
1311        gap: var!(space-md);
1312        padding: format!("{} 0", var!(space-sm));
1313        overflow: "hidden";
1314    }
1315
1316    pub c_info_label {
1317        font-size: var!(font-sm);
1318        font-weight: "500";
1319        color: var!(muted-foreground);
1320        min-width: "72px";
1321        flex-shrink: "0";
1322        letter-spacing: "0.02em";
1323    }
1324
1325    pub c_info_value {
1326        c_text_ellipsis();
1327        font-size: var!(font-base);
1328        font-weight: "600";
1329        color: var!(foreground);
1330        font-family: "ui-monospace, monospace";
1331        flex: "1";
1332    }
1333
1334    pub c_info_link {
1335        c_text_ellipsis();
1336        font-size: var!(font-base);
1337        font-weight: "600";
1338        color: var!(accent);
1339        font-family: "ui-monospace, monospace";
1340        flex: "1";
1341        text-decoration: "none";
1342        transition: format!("opacity {} {}", var!(duration-fast), var!(ease-out));
1343        :hover {
1344            opacity: "1";
1345        }
1346    }
1347
1348    // ═══════════════════════════════════════════════════════════════════════════
1349    // Async / Loading States
1350    // ═══════════════════════════════════════════════════════════════════════════
1351
1352    pub(crate) c_loading_container {
1353        display: "flex";
1354        align-items: "center";
1355        justify-content: "center";
1356        gap: var!(gap-component);
1357        margin: format!("{} 0px", var!(gap-component));
1358        box-sizing: "border-box";
1359    }
1360
1361    pub c_spinner {
1362        width: "40px";
1363        height: "40px";
1364        border: format!("4px solid {}", var!(accent-muted));
1365        border-top: format!("4px solid {}", var!(accent));
1366        border-right: format!("4px solid {}", var!(accent));
1367        border-bottom: format!("4px solid {}", var!(accent));
1368        border-radius: "50%";
1369        flex-shrink: "0";
1370        animation: "euv-spin 0.8s linear infinite";
1371    }
1372
1373    pub(crate) c_loading_text_col {
1374        display: "flex";
1375        flex-direction: "column";
1376        gap: var!(space-xs);
1377    }
1378
1379    pub(crate) c_loading_title {
1380        color: var!(foreground);
1381        font-size: var!(font-md);
1382        font-weight: "500";
1383    }
1384
1385    pub(crate) c_loading_subtitle {
1386        color: var!(muted-foreground);
1387        font-size: var!(font-base);
1388    }
1389
1390    pub c_loading_overlay(background: &str) {
1391        position: "absolute";
1392        top: "0";
1393        left: "0";
1394        width: "100%";
1395        height: "100%";
1396        display: "flex";
1397        flex-direction: "column";
1398        align-items: "center";
1399        justify-content: "center";
1400        gap: var!(gap-component);
1401        background: background;
1402        z-index: "1";
1403        box-sizing: "border-box";
1404    }
1405
1406    pub c_error_container {
1407        display: "flex";
1408        align-items: "center";
1409        gap: var!(gap-element);
1410        margin-top: var!(gap-component);
1411        box-sizing: "border-box";
1412    }
1413
1414    pub c_error_icon {
1415        width: "20px";
1416        height: "20px";
1417        display: "flex";
1418        align-items: "center";
1419        justify-content: "center";
1420        flex-shrink: "0";
1421        color: var!(foreground);
1422        font-size: var!(font-sm);
1423        font-weight: "700";
1424    }
1425
1426    pub c_error_text {
1427        color: var!(foreground);
1428        font-size: var!(font-base);
1429    }
1430
1431    pub c_data_box {
1432        margin: format!("{} 0px", var!(gap-component));
1433        box-sizing: "border-box";
1434    }
1435
1436    pub c_data_pre {
1437        color: var!(foreground);
1438        font-size: var!(font-base);
1439        margin: "0px";
1440        white-space: "pre-wrap";
1441        word-break: "break-all";
1442        font-family: "ui-monospace, monospace";
1443    }
1444
1445    pub c_fetch_hint {
1446        color: "inherit";
1447        opacity: "1";
1448        font-size: var!(font-base);
1449        margin-bottom: var!(gap-component);
1450    }
1451
1452    // ═══════════════════════════════════════════════════════════════════════════
1453    // Log / Console Display
1454    // ═══════════════════════════════════════════════════════════════════════════
1455
1456    pub c_log_container {
1457        font-family: "ui-monospace, monospace";
1458        font-size: var!(font-base);
1459        margin-top: "0px";
1460        color: var!(foreground);
1461    }
1462
1463    pub c_log_item {
1464        padding: format!("{} 0px", var!(space-sm));
1465        font-size: var!(font-base);
1466        color: var!(foreground);
1467    }
1468}