Skip to main content

euv_ui/style/class/page/
fn.rs

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