Skip to main content

euv_ui/style/class/display/
fn.rs

1use super::*;
2
3#[cfg(not(feature = "custom-styles"))]
4class! {
5    pub c_card_title {
6        margin: format!("{} 0px", var!(gap-component));
7        color: var!(foreground);
8        font-size: var!(font-lg);
9        font-weight: "600";
10        padding-bottom: var!(gap-component);
11        border-bottom: format!("1px dashed {}", var!(border));
12        letter-spacing: "-0.01em";
13        @media ((max-width: 767px)) {
14            font-size: var!(font-md);
15        }
16    }
17
18    // ═══════════════════════════════════════════════════════════════════════════
19    // Buttons
20    // ═══════════════════════════════════════════════════════════════════════════
21
22    pub c_primary_button {
23        display: "flex";
24        justify-content: "center";
25        align-items: "center";
26        gap: var!(space-sm);
27        width: "100%";
28        height: "42px";
29        background: var!(accent);
30        color: var!(text-on-accent);
31        border: "1px solid transparent";
32        padding: format!("0px {}", var!(space-2xl));
33        cursor: "pointer";
34        font-size: var!(font-base);
35        font-weight: "500";
36        letter-spacing: "0.02em";
37        text-align: "center";
38        outline: "none";
39        box-sizing: "border-box";
40        white-space: "nowrap";
41        overflow: "hidden";
42        text-overflow: "ellipsis";
43        user-select: "none";
44        -webkit-user-select: "none";
45        :focus-visible {
46            outline: "none";
47        }
48        :disabled {
49            background: var!(muted-foreground);
50            cursor: "not-allowed";
51            opacity: "1";
52        }
53        :hover {
54            background: var!(accent);
55        }
56        :active {
57            background: var!(accent);
58            color: var!(text-on-accent);
59            border-color: "transparent";
60        }
61        @media ((max-width: 767px)) {
62            max-width: "100%";
63            padding: format!("{} {}", var!(space-lg), var!(space-xl));
64            font-size: var!(font-md);
65        }
66    }
67
68    // ═══════════════════════════════════════════════════════════════════════════
69    // Button Controls Container
70    // ═══════════════════════════════════════════════════════════════════════════
71
72    pub c_button_controls {
73        display: "flex";
74        flex-wrap: "wrap";
75        gap: var!(gap-element);
76        margin-top: var!(gap-component);
77        margin-bottom: var!(gap-component);
78    }
79
80    // ═══════════════════════════════════════════════════════════════════════════
81    // Euv Button Variants
82    // ═══════════════════════════════════════════════════════════════════════════
83
84    pub c_euv_button_primary_md {
85        display: "flex";
86        justify-content: "center";
87        align-items: "center";
88        gap: var!(space-sm);
89        flex: "1 1 120px";
90        height: "42px";
91        padding: format!("0px {}", var!(space-xl));
92        background: var!(accent);
93        color: var!(text-on-accent);
94        cursor: "pointer";
95        font-size: var!(font-base);
96        font-weight: "500";
97        outline: "none";
98        white-space: "nowrap";
99        user-select: "none";
100        -webkit-user-select: "none";
101        box-sizing: "border-box";
102        :disabled {
103            background: var!(muted-foreground);
104            cursor: "not-allowed";
105            opacity: "1";
106        }
107    }
108
109    // ═══════════════════════════════════════════════════════════════════════════
110    // Status Boxes
111    // ═══════════════════════════════════════════════════════════════════════════
112
113    pub c_error_box {
114        margin: format!("{} 0px", var!(gap-component));
115        background: var!(accent-muted);
116        color: var!(foreground);
117        font-size: var!(font-base);
118        box-sizing: "border-box";
119    }
120
121    pub c_success_box {
122        margin: format!("{} 0px", var!(gap-component));
123        background: var!(accent-muted);
124        color: var!(foreground);
125        font-size: var!(font-base);
126        box-sizing: "border-box";
127    }
128
129    // ═══════════════════════════════════════════════════════════════════════════
130    // Counter / Signals Demo
131    // ═══════════════════════════════════════════════════════════════════════════
132
133    pub c_counter_row {
134        display: "grid";
135        grid-template-columns: "1fr 1fr";
136        align-items: "center";
137        gap: var!(gap-component);
138        @media ((max-width: 767px)) {
139            grid-template-columns: "1fr";
140        }
141    }
142
143    pub c_counter_text {
144        font-size: var!(font-base);
145        color: "inherit";
146        margin-bottom: var!(gap-component);
147    }
148
149    pub c_counter_value {
150        font-weight: "700";
151        color: var!(accent);
152        font-size: var!(font-base);
153    }
154
155    pub c_counter_value_row {
156        margin-top: var!(space-sm);
157        word-break: "break-all";
158        overflow-wrap: "anywhere";
159        font-size: var!(font-base);
160        color: "inherit";
161        font-weight: "400";
162    }
163
164    pub c_badge_row {
165        display: "flex";
166        gap: var!(gap-inline);
167        flex-wrap: "wrap";
168        align-items: "center";
169    }
170
171    pub c_badge_hint {
172        margin-bottom: var!(gap-component);
173        color: "inherit";
174        opacity: "1";
175        font-size: var!(font-base);
176    }
177
178    // ═══════════════════════════════════════════════════════════════════════════
179    // Tabs
180    // ═══════════════════════════════════════════════════════════════════════════
181
182    pub c_tab_bar {
183        display: "flex";
184        border-bottom: format!("1px dashed {}", var!(border));
185        margin-bottom: var!(gap-component);
186        gap: var!(gap-element);
187        @media ((max-width: 767px)) {
188            flex-wrap: "wrap";
189        }
190    }
191
192    pub c_tab_item_active {
193        padding: format!("{} {}", var!(space-md), var!(space-xl));
194        cursor: "pointer";
195        border-bottom: format!("2px solid {}", var!(accent));
196        color: var!(text-on-accent);
197        background: var!(accent);
198        font-size: var!(font-base);
199        font-weight: "500";
200        // iOS WebKit: tap on a non-button element inside a scrollable
201        // container can be silently dropped because iOS interprets the
202        // touch as the start of a scroll gesture and never dispatches the
203        // synthetic `click`. `touch-action: manipulation` tells iOS this
204        // element only responds to taps and panning — no double-tap-zoom
205        // wait, no scroll-gesture disambiguation. `user-select: none`
206        // additionally suppresses the iOS text-selection bubble that
207        // would otherwise intercept the tap. See ui/src/style/css/fn.rs
208        // for the global reset and PR that documents the iOS repro.
209        touch-action: "manipulation";
210        user-select: "none";
211        -webkit-user-select: "none";
212    }
213
214    pub c_tab_item_inactive {
215        padding: format!("{} {}", var!(space-md), var!(space-xl));
216        cursor: "pointer";
217        border-bottom: "2px solid transparent";
218        color: "inherit";
219        font-size: var!(font-base);
220        font-weight: "500";
221        // iOS WebKit fix — see c_tab_item_active above for the rationale.
222        touch-action: "manipulation";
223        user-select: "none";
224        -webkit-user-select: "none";
225        :hover {
226            background: var!(accent-muted);
227            color: var!(accent);
228        }
229    }
230
231    pub c_tab_content {
232        padding: format!("{} 0px", var!(gap-element));
233    }
234
235    pub c_tab_text {
236        color: "inherit";
237        font-size: var!(font-base);
238        margin-bottom: var!(gap-element);
239    }
240
241    pub c_tab_text_muted {
242        color: "inherit";
243        opacity: "1";
244        font-size: var!(font-base);
245    }
246
247    pub c_tab_text_input {
248        color: "inherit";
249        font-size: var!(font-base);
250        margin-bottom: var!(gap-component);
251    }
252
253    // ═══════════════════════════════════════════════════════════════════════════
254    // List
255    // ═══════════════════════════════════════════════════════════════════════════
256
257    pub c_list_input {
258        width: "100%";
259        flex: "1";
260        height: "42px";
261        padding: format!("0px {}", var!(space-lg));
262        border: format!("1px solid {}", var!(border));
263        font-size: var!(font-base);
264        line-height: "normal";
265        box-sizing: "border-box";
266        outline: "none";
267        color: var!(foreground);
268        appearance: "none";
269        -webkit-appearance: "none";
270        -moz-appearance: "none";
271        vertical-align: "middle";
272        :hover {
273            border-color: var!(accent);
274            background: var!(accent-muted);
275        }
276        :focus {
277            outline: "none";
278            border-color: var!(accent);
279            background: var!(accent-muted);
280        }
281    }
282
283    pub c_list_input_error {
284        width: "100%";
285        flex: "1";
286        height: "42px";
287        padding: format!("0px {}", var!(space-lg));
288        border: format!("1px solid {}", var!(foreground));
289        font-size: var!(font-base);
290        line-height: "normal";
291        box-sizing: "border-box";
292        outline: "none";
293        color: var!(foreground);
294        appearance: "none";
295        -webkit-appearance: "none";
296        -moz-appearance: "none";
297        vertical-align: "middle";
298        :focus {
299            outline: "none";
300            border-color: var!(foreground);
301        }
302    }
303
304    pub c_list_error_text {
305        color: var!(foreground);
306        font-size: var!(font-base);
307        margin: format!("{} 0px", var!(gap-element));
308    }
309
310    pub c_inline_input_button_wrap {
311        flex-shrink: "0";
312    }
313
314    pub c_list_ul {
315        list-style: "none";
316        padding: "0px";
317        margin: "0px";
318        margin-top: var!(gap-component);
319    }
320
321    pub c_list_item {
322        display: "flex";
323        justify-content: "space-between";
324        align-items: "center";
325        gap: var!(gap-component);
326        min-height: var!(min-height-base);
327        margin: format!("{} 0px", var!(gap-element));
328    }
329
330    pub c_list_item_text {
331        flex: "1";
332        overflow: "hidden";
333        text-overflow: "ellipsis";
334        white-space: "nowrap";
335        font-size: var!(font-base);
336        color: "inherit";
337        min-width: "0";
338    }
339
340    pub c_list_item_button {
341        max-width: "120px";
342        flex-shrink: "0";
343    }
344
345    // ═══════════════════════════════════════════════════════════════════════════
346    // Animation Demo
347    // ═══════════════════════════════════════════════════════════════════════════
348
349    pub c_anim_fade_in {
350        margin-top: var!(gap-component);
351        animation: format!("euv-fade-in 0.5s {}", var!(ease-out));
352        font-size: var!(font-base);
353        color: "inherit";
354    }
355
356    pub c_anim_spin_container {
357        display: "flex";
358        justify-content: "center";
359        align-items: "center";
360        margin: format!("{} 0px", var!(space-lg));
361        min-height: "80px";
362    }
363
364    pub c_anim_spin {
365        font-size: var!(font-5xl);
366        animation: "euv-spin 1.5s linear infinite";
367        display: "inline-block";
368        @media ((max-width: 767px)) {
369            font-size: var!(font-4xl);
370        }
371    }
372
373    pub c_anim_spin_stopped {
374        font-size: var!(font-5xl);
375        display: "inline-block";
376        opacity: "1";
377        @media ((max-width: 767px)) {
378            font-size: var!(font-4xl);
379        }
380    }
381
382    pub c_anim_pulse_container {
383        display: "flex";
384        justify-content: "center";
385        align-items: "center";
386        margin: format!("{} 0px", var!(space-lg));
387        min-height: "80px";
388    }
389
390    pub c_anim_pulse {
391        font-size: var!(font-5xl);
392        animation: "euv-pulse 1.5s ease-in-out infinite";
393        display: "inline-block";
394        color: var!(foreground);
395        @media ((max-width: 767px)) {
396            font-size: var!(font-4xl);
397        }
398    }
399
400    pub c_anim_pulse_stopped {
401        font-size: var!(font-5xl);
402        display: "inline-block";
403        opacity: "1";
404        color: var!(foreground);
405        @media ((max-width: 767px)) {
406            font-size: var!(font-4xl);
407        }
408    }
409
410    pub c_progress_container {
411        width: "100%";
412        height: "12px";
413        margin: format!("{} 0px", var!(space-lg));
414        overflow: "hidden";
415    }
416
417    pub c_progress_bar_running {
418        height: "100%";
419        background: var!(accent);
420        animation: format!("euv-progress 1.6s {} forwards", var!(ease-in-out));
421    }
422
423    pub c_progress_bar_stopped {
424        height: "100%";
425        background: var!(accent);
426        width: "0%";
427    }
428
429    pub c_anim_scale_box {
430        margin: format!("{} 0px", var!(gap-component));
431        padding: var!(space-xl);
432        background: var!(accent);
433        cursor: "pointer";
434        transition: format!("transform {} {}", var!(duration-normal), var!(ease-out));
435    }
436
437    // ═══════════════════════════════════════════════════════════════════════════
438    // Unified Layout Primitives
439    // ═══════════════════════════════════════════════════════════════════════════
440
441    pub c_element_stack {
442        display: "flex";
443        flex-direction: "column";
444        gap: var!(gap-element);
445    }
446
447    pub c_switcher {
448        display: "flex";
449        gap: var!(gap-component);
450        flex-wrap: "wrap";
451        @media ((max-width: 767px)) {
452            flex-direction: "column";
453            gap: var!(gap-component-mobile);
454        }
455    }
456
457    pub c_switcher_col {
458        flex: "1";
459        min-width: "200px";
460        @media ((max-width: 767px)) {
461            min-width: "100%";
462        }
463    }
464
465    // ═══════════════════════════════════════════════════════════════════════════
466    // Unified Description / Hint Text
467    // ═══════════════════════════════════════════════════════════════════════════
468
469    pub c_hint {
470        color: "inherit";
471        opacity: "1";
472        font-size: var!(font-base);
473        margin-bottom: var!(gap-component);
474    }
475
476    // ═══════════════════════════════════════════════════════════════════════════
477    // euv_pagination
478    // ═══════════════════════════════════════════════════════════════════════════
479
480    pub c_euv_pagination {
481        // CSS grid with two equal columns gives us perfect 50/50 widths
482        // regardless of the link content length, which flex with `1 1
483        // auto` cannot (each link starts at its own content size). The
484        // mobile breakpoint stacks the grid to a single column so each
485        // link sizes to its content.
486        display: "grid";
487        grid-template-columns: "1fr 1fr";
488        gap: var!(gap-component);
489        // ~`space-2xl` (1.5rem) above the pagination — comfortable
490        // breathing room without a huge gap before prev/next. The original
491        // `space-4xl` (2.5rem) margin was doubled by a `padding-top` in the
492        // docs app override, leaving ~100px of empty space above the
493        // pagination boxes which made the page feel bottom-heavy.
494        margin-top: var!(space-2xl);
495        // `min-width: 0` lets prev/next text actually use ellipsis when the
496        // container is narrow — without it the grid track blows out the row.
497        min-width: "0px";
498        @media ((max-width: 767px)) {
499            grid-template-columns: "minmax(0, 1fr)";
500        }
501    }
502
503    pub c_euv_pagination_link {
504        // `min-width: 0` lets long labels ellipsize on the desktop row
505        // layout. `overflow: hidden` is required to actually apply ellipsis
506        // when content is wider than the link.
507        min-width: "0px";
508        border: format!("1px solid {}", var!(border));
509        padding: var!(space-lg);
510        cursor: "pointer";
511        display: "flex";
512        flex-direction: "column";
513        gap: var!(space-2xs);
514        overflow: "hidden";
515        :hover {
516            border-color: var!(accent);
517        }
518    }
519
520    pub c_euv_footer {
521        // Footer sits at the natural end of the article column. The user
522        // reaches it by scrolling to the bottom of the article — no sticky
523        // or fixed positioning. This matches the desktop behavior and
524        // Avoid any layout interference on mobile (where a sticky footer
525        // would overlap the last lines of content while scrolling).
526        // No top margin: the preceding tail block already carries the gap
527        // between the article and its pagination, so a margin here would
528        // stack with it and leave the rule stranded below an empty band.
529        // The dashed rule is this element's own `border-top`, so the
530        // padding below is the gap from the rule to the text and the
531        // padding above is the gap from the preceding content to the rule.
532        // Only one of them belongs to the band inside the rule, and it is
533        // the top one — that is the space between the divider and the text.
534        // `space-md` keeps the text close to the rule; the block is
535        // `display: flex` so the row is centred in the band the padding
536        // defines rather than riding its top edge.
537        padding: format!("{} 0px", var!(space-md));
538        border-top: format!("1px dashed {}", var!(border));
539        display: "flex";
540        // One row: the text and the notices sit side by side and never
541        // wrap. `align-items: center` keeps the badge on the text's
542        // midline, and `overflow: hidden` keeps a long row inside the
543        // column instead of pushing the page wider.
544        flex-wrap: "nowrap";
545        align-items: "center";
546        justify-content: "center";
547        gap: var!(space-md);
548        text-align: "center";
549        font-size: var!(font-sm);
550        color: var!(muted-foreground);
551        min-width: "0px";
552        overflow: "hidden";
553    }
554
555    // One item of the footer row.
556    //
557    // `inline-block` rather than a flex box: the text is inline content
558    // inside this box, so `text-overflow: ellipsis` can cut it with a
559    // dot when the row is too narrow. A flex box would put the text in
560    // an anonymous item that no selector can reach, and the text would
561    // be clipped without a hint that it was cut.
562    pub c_euv_footer_item {
563        display: "inline-block";
564        min-width: "0px";
565        max-width: "100%";
566        overflow: "hidden";
567        text-overflow: "ellipsis";
568        white-space: "nowrap";
569        vertical-align: "middle";
570    }
571
572    // A linked item of the footer row.
573    pub c_euv_footer_item_link {
574        c_euv_footer_item();
575        color: "inherit";
576        text-decoration: "none";
577        :hover {
578            color: var!(accent);
579        }
580    }
581
582    // The official badge that precedes a filing number.
583    //
584    // The height is the badge's own size (20px), so the picture is
585    // served at its native resolution instead of being scaled by the
586    // browser. The margin is the gap to the number: the link is an
587    // inline box, so the gap cannot come from a flex `gap`.
588    pub c_euv_footer_item_icon {
589        display: "inline-block";
590        height: var!(space-xl);
591        width: "auto";
592        vertical-align: "middle";
593        margin-right: var!(space-2xs);
594    }
595
596    pub c_euv_doc_layout {
597        display: "flex";
598        gap: var!(space-4xl);
599        width: "100%";
600        min-width: "0px";
601        max-width: "1080px";
602        margin: "0px auto";
603        // Fill the visible area of the scroll container (`c_app_main`,
604        // `overflow: auto` with a definite `height: 100%`) so the content
605        // column has room to push its tail to the bottom. A viewport unit
606        // would be wrong here: `100vh` measures the whole window including
607        // the app header, overshooting the visible area by the header
608        // height and pushing pagination/footer one header past the fold.
609        // Being a direct child of the scroll container, a percentage does
610        // resolve against its content box — put it one level deeper and
611        // the intermediate auto-height flex row makes `100%` degenerate to
612        // `auto`.
613        min-height: "100%";
614        // As a flex item of the scroll container's column, the default
615        // `flex-shrink: 1` lets this row be compressed to the `min-height`
616        // floor — 824px here — even though its content is 12780px tall. A
617        // sticky descendant can only travel inside its containing block, so
618        // the clamped row made `c_euv_doc_toc` unpin after roughly one
619        // viewport of scroll. Never shrink: the row must carry the article's
620        // full height so the sticky range spans the whole page.
621        flex-shrink: "0";
622    }
623
624    pub c_euv_doc_content {
625        // Two parallel children — the article body and the
626        // `c_euv_doc_tail` wrapper (pagination + footer). The flex column
627        // distributes them at the two ends:
628        //   - when the article is shorter than the column's intrinsic
629        //     height, `justify-content: space-between` pushes the tail to
630        //     the bottom edge;
631        //   - when the article is longer, the tail sits right after the
632        //     article in normal flow (because content height exceeds
633        //     min-height, there's no remaining space to distribute).
634        // The scroll container is `c_app_main` (`overflow: auto`), not the
635        // window, so a viewport unit measures the whole window including the
636        // app header. `100vh` therefore overshoots by the header height and
637        // pushes the tail one header past the fold on a short page. Height
638        // comes from `c_euv_doc_layout` (a direct child of the scroll
639        // container, where a percentage resolves); here `align-items:
640        // stretch` — the flex default — makes this column take that height
641        // so `space-between` has the full column to distribute across.
642        //   - article shorter than the column: `space-between` drops the
643        //     tail to the bottom edge of the visible area;
644        //   - article longer: the column grows with it and the tail follows
645        //     the body in normal flow, scrolling with the page.
646        flex: "1";
647        min-width: "0px";
648        max-width: var!(content-max-width);
649        display: "flex";
650        flex-direction: "column";
651        justify-content: "space-between";
652    }
653
654    pub c_euv_doc_body {
655        // Groups the page title and the rendered markdown into a single
656        // flex item. Without this the column would hold the `<h1>` and
657        // the `<article>` as two separate items, and
658        // `justify-content: space-between` would push them apart — a wide
659        // blank band between the title and the first paragraph on any
660        // page whose body is shorter than the column.
661        display: "flex";
662        flex-direction: "column";
663        // The body takes its natural height; only the tail is pushed to
664        // the far end. `flex-shrink: 0` keeps a long body from being
665        // compressed when the column is height-constrained.
666        flex: "0 0 auto";
667        min-width: "0px";
668    }
669
670    pub c_euv_doc_tail {
671        // Plain block wrapper that groups pagination + footer into one
672        // flex child. With `display: contents` the wrapper would be
673        // skipped and the two siblings would behave as direct children
674        // of `c_euv_doc_content` — breaking the two-parallel-containers
675        // contract that `justify-content: space-between` relies on.
676        display: "block";
677    }
678
679    pub c_euv_doc_toc {
680        width: "200px";
681        flex-shrink: "0";
682        // Pin the TOC column to the viewport while the main content scrolls.
683        // The sticky scroll container is `c_app_main` (the overflow:auto
684        // wrapper), so this offset is measured from that container's top edge.
685        // It tracks `padding-main-top` rather than a bare `0` so the pinned
686        // column keeps the same breathing room below the container edge as the
687        // article has below the same edge — the two columns stay on one
688        // vertical rhythm instead of the TOC riding flush against the top.
689        position: "sticky";
690        top: var!(padding-main-top);
691        @media ((max-width: 1100px)) {
692            display: "none";
693        }
694    }
695
696    // Makes the element's own box disappear while its children stay in the
697    // parent's layout flow, so a wrapper can carry a key or a conditional
698    // without contributing a box.
699    //
700    // The docs shell and page wrappers spelled this as an inline
701    // `style: "display: contents"`; the rule is the same either way, but a
702    // named class keeps the markup declarative and lets the browser cache it.
703    pub c_euv_display_contents {
704        display: "contents";
705    }
706
707    // ═══════════════════════════════════════════════════════════════════════
708    // Home Page Layout
709    // ═══════════════════════════════════════════════════════════════════════
710
711    pub c_home_layout {
712        // Mirrors `c_euv_doc_layout`: fill the visible area of the scroll
713        // container (`c_app_main`, `overflow: auto` with a definite
714        // `height: 100%`) so the column below has room to push its footer to
715        // the bottom. A viewport unit would overshoot by the app header.
716        //
717        // As a flex item of the scroll container's column it must never be
718        // shrunk below its content, or a tall home page collapses and the
719        // sticky-free column loses its height floor.
720        display: "flex";
721        flex-direction: "column";
722        width: "100%";
723        min-width: "0px";
724        min-height: "100%";
725        flex-shrink: "0";
726        margin: "0px auto";
727        max-width: var!(content-max-width);
728    }
729
730    pub c_home_content {
731        // Two parallel children — the content region (hero, stats, feature
732        // grid, blocks) and `c_home_tail` (the footer). `space-between`
733        // puts the footer at the far end of the column: on a short home page
734        // it drops to the bottom of the visible area, and on a tall one it
735        // follows the content in normal flow.
736        flex: "1";
737        min-width: "0px";
738        display: "flex";
739        flex-direction: "column";
740        justify-content: "space-between";
741    }
742
743    pub c_home_body {
744        // Groups hero + stats + grid + blocks into one flex item. Without
745        // this wrapper `space-between` would distribute the free space
746        // between the hero and the grid, tearing the title away from the
747        // content it introduces.
748        display: "flex";
749        flex-direction: "column";
750        flex-shrink: "0";
751    }
752
753    pub c_home_tail {
754        // Plain block wrapper around the footer so the column keeps exactly
755        // two children. A `display: contents` wrapper would be skipped and
756        // the footer would become a direct flex item, which is the case this
757        // structure exists to avoid.
758        display: "block";
759        flex-shrink: "0";
760    }
761
762    pub(crate) c_euv_tabs {
763        display: "flex";
764        flex-direction: "column";
765        width: "100%";
766    }
767
768    pub(crate) c_euv_tabs_bar {
769        display: "flex";
770        border-bottom: format!("1px dashed {}", var!(border));
771        margin-bottom: var!(gap-component);
772        gap: var!(gap-element);
773        @media ((max-width: 767px)) {
774            flex-wrap: "wrap";
775        }
776    }
777
778    pub(crate) c_euv_tab_item {
779        padding: format!("{} {}", var!(space-md), var!(space-xl));
780        cursor: "pointer";
781        font-size: var!(font-base);
782        font-weight: "500";
783        border-bottom: "2px solid transparent";
784        color: "inherit";
785        background: "transparent";
786        touch-action: "manipulation";
787        user-select: "none";
788        -webkit-user-select: "none";
789        white-space: "nowrap";
790        :hover {
791            background: var!(accent-muted);
792            color: var!(accent);
793        }
794    }
795
796    pub(crate) c_euv_tab_item_active {
797        padding: format!("{} {}", var!(space-md), var!(space-xl));
798        cursor: "pointer";
799        font-size: var!(font-base);
800        font-weight: "500";
801        border-bottom: format!("2px solid {}", var!(accent));
802        color: var!(text-on-accent);
803        background: var!(accent);
804        touch-action: "manipulation";
805        user-select: "none";
806        -webkit-user-select: "none";
807        white-space: "nowrap";
808    }
809
810    pub(crate) c_euv_tabs_panel {
811        padding: format!("{} 0px", var!(gap-element));
812    }
813
814    pub(crate) c_euv_collapse_item {
815        border-bottom: format!("1px dashed {}", var!(border));
816    }
817
818    pub(crate) c_euv_collapse_header {
819        display: "flex";
820        align-items: "center";
821        gap: var!(space-sm);
822        width: "100%";
823        min-height: var!(min-height-base);
824        padding: format!("{} 0px", var!(space-sm));
825        cursor: "pointer";
826        text-align: "left";
827        font-size: var!(font-base);
828        font-weight: "500";
829        color: var!(foreground);
830        background: "transparent";
831        border: "none";
832        outline: "none";
833        touch-action: "manipulation";
834        user-select: "none";
835        -webkit-user-select: "none";
836        :hover {
837            background: var!(accent-muted);
838            color: var!(accent);
839        }
840    }
841
842    pub(crate) c_euv_collapse_header_active {
843        display: "flex";
844        align-items: "center";
845        gap: var!(space-sm);
846        width: "100%";
847        min-height: var!(min-height-base);
848        padding: format!("{} 0px", var!(space-sm));
849        cursor: "pointer";
850        text-align: "left";
851        font-size: var!(font-base);
852        font-weight: "600";
853        color: var!(accent);
854        background: var!(accent-muted);
855        border: "none";
856        outline: "none";
857        touch-action: "manipulation";
858        user-select: "none";
859        -webkit-user-select: "none";
860    }
861
862    pub(crate) c_euv_collapse_body {
863        overflow: "hidden";
864        font-size: var!(font-base);
865        color: var!(foreground);
866        transition: format!("max-height {} {}, opacity {} {}", var!(duration-normal), var!(ease-out), var!(duration-normal), var!(ease-out));
867    }
868
869    pub(crate) c_euv_collapse_body_open {
870        overflow: "hidden";
871        max-height: "none";
872        opacity: "1";
873        padding-bottom: var!(space-md);
874        font-size: var!(font-base);
875        color: var!(foreground);
876        transition: format!("max-height {} {}, opacity {} {}", var!(duration-normal), var!(ease-out), var!(duration-normal), var!(ease-out));
877    }
878
879    pub(crate) c_euv_collapse_body_closed {
880        overflow: "hidden";
881        max-height: "0px";
882        opacity: "0";
883        font-size: var!(font-base);
884        color: var!(foreground);
885        transition: format!("max-height {} {}, opacity {} {}", var!(duration-normal), var!(ease-out), var!(duration-normal), var!(ease-out));
886    }
887
888    pub(crate) c_euv_breadcrumb {
889        display: "flex";
890        align-items: "center";
891        flex-wrap: "wrap";
892        gap: var!(space-xs);
893        font-size: var!(font-sm);
894    }
895
896    pub(crate) c_euv_breadcrumb_item {
897        font-size: var!(font-sm);
898        color: var!(muted-foreground);
899        cursor: "pointer";
900        text-decoration: "none";
901        touch-action: "manipulation";
902        user-select: "none";
903        -webkit-user-select: "none";
904        :hover {
905            background: var!(accent-muted);
906            color: var!(accent);
907        }
908    }
909
910    pub(crate) c_euv_breadcrumb_sep {
911        font-size: var!(font-sm);
912        color: var!(muted-foreground);
913        user-select: "none";
914        -webkit-user-select: "none";
915    }
916
917    pub(crate) c_euv_breadcrumb_current {
918        font-size: var!(font-sm);
919        font-weight: "600";
920        color: var!(foreground);
921        cursor: "default";
922    }
923
924    pub(crate) c_euv_divider {
925        display: "block";
926        width: "100%";
927    }
928
929    pub(crate) c_euv_divider_horizontal {
930        display: "block";
931        width: "100%";
932        height: "0px";
933        border: "none";
934        border-top: format!("1px solid {}", var!(border));
935        margin: format!("{} 0px", var!(space-lg));
936    }
937
938    pub(crate) c_euv_divider_vertical {
939        display: "block";
940        width: "0px";
941        height: "auto";
942        align-self: "center";
943        border: "none";
944        border-left: format!("1px solid {}", var!(border));
945        margin: format!("0px {}", var!(space-sm));
946    }
947
948    pub(crate) c_euv_divider_labeled {
949        display: "flex";
950        align-items: "center";
951        gap: var!(space-sm);
952        width: "100%";
953        margin: format!("{} 0px", var!(space-lg));
954    }
955
956    pub(crate) c_euv_divider_label_text {
957        font-size: var!(font-xs);
958        font-weight: "500";
959        color: var!(muted-foreground);
960        white-space: "nowrap";
961        user-select: "none";
962        -webkit-user-select: "none";
963    }
964
965    // ═══════════════════════════════════════════════════════════════════════════
966    // Card Component
967    // ═══════════════════════════════════════════════════════════════════════════
968
969    pub(crate) c_card {
970        color: var!(foreground);
971        box-sizing: "border-box";
972        // The card title carries a `gap-component` margin, and that margin
973        // collapses out of the card — the card has no padding and no border
974        // to stop it. The gap between two cards was therefore whatever the
975        // title's margin happened to be, not a value anybody chose. The
976        // block gap is the value the page template asks for, so it is named
977        // here instead of being left to a side effect.
978        margin-top: var!(page-block-gap);
979        @media ((max-width: 767px)) {
980            margin-top: var!(page-block-gap-mobile);
981        }
982    }
983
984    pub(crate) c_modal_close_button {
985        display: "flex";
986        justify-content: "center";
987        align-items: "center";
988        color: "inherit";
989        border: "none";
990        padding: format!("{} {}", var!(space-sm), var!(space-md));
991        cursor: "pointer";
992        font-size: "20px";
993        font-weight: "400";
994        vertical-align: "middle";
995        outline: "none";
996        opacity: "1";
997        flex-shrink: "0";
998        transition: format!("opacity {} {}", var!(duration-fast), var!(ease-out));
999        :hover {
1000            opacity: "1";
1001        }
1002        :active {
1003            opacity: "1";
1004        }
1005        :focus {
1006            outline: "none";
1007        }
1008    }
1009
1010    pub(crate) c_euv_button_outline_md {
1011        display: "flex";
1012        justify-content: "center";
1013        align-items: "center";
1014        gap: var!(space-sm);
1015        flex: "1 1 120px";
1016        height: "42px";
1017        padding: format!("0px {}", var!(space-xl));
1018        color: var!(foreground);
1019        border: format!("1px solid {}", var!(border));
1020        cursor: "pointer";
1021        font-size: var!(font-base);
1022        font-weight: "500";
1023        outline: "none";
1024        white-space: "nowrap";
1025        user-select: "none";
1026        -webkit-user-select: "none";
1027        box-sizing: "border-box";
1028        :focus-visible {
1029            outline: "none";
1030        }
1031        :disabled {
1032            background: var!(muted-foreground);
1033            cursor: "not-allowed";
1034            opacity: "1";
1035        }
1036    }
1037
1038    // ═══════════════════════════════════════════════════════════════════════════
1039    // Badges
1040    // ═══════════════════════════════════════════════════════════════════════════
1041
1042    pub(crate) c_badge {
1043        // The wrapping-atom recipe (§7): an inline flex box is atomic, so a
1044        // wrapped label left-aligns while the border stays at the parent
1045        // width — the right border reads as missing. The four `c_euv_tag_*`
1046        // variants already use this recipe; a badge is the same kind of
1047        // element and must not mix the two.
1048        display: "inline-block";
1049        vertical-align: "middle";
1050        text-align: "center";
1051        line-height: "1";
1052        box-sizing: "border-box";
1053        color: var!(text-on-accent);
1054        padding: format!("{} {}", var!(space-2xs), var!(space-sm));
1055        border: format!("1px solid {}", var!(accent));
1056        font-size: var!(font-xs);
1057        font-weight: "600";
1058        cursor: "pointer";
1059        background: var!(accent);
1060        :focus-visible {
1061            outline: "none";
1062        }
1063        @media ((max-width: 767px)) {
1064            padding: format!("{} {}", var!(space-2xs), var!(space-xs));
1065            font-size: var!(font-xs);
1066        }
1067    }
1068
1069    pub(crate) c_badge_outline {
1070        display: "inline-block";
1071        vertical-align: "middle";
1072        text-align: "center";
1073        line-height: "1";
1074        box-sizing: "border-box";
1075        color: var!(foreground);
1076        padding: format!("{} {}", var!(space-2xs), var!(space-sm));
1077        font-size: var!(font-xs);
1078        font-weight: "600";
1079        cursor: "pointer";
1080        border: format!("1.5px solid {}", var!(border));
1081        @media ((max-width: 767px)) {
1082            padding: format!("{} {}", var!(space-2xs), var!(space-xs));
1083            font-size: var!(font-xs);
1084        }
1085    }
1086
1087    pub(crate) c_euv_tag_solid_black {
1088        display: "inline-block";
1089        vertical-align: "middle";
1090        text-align: "center";
1091        line-height: "1";
1092        color: var!(text-on-accent);
1093        padding: format!("{} {}", var!(space-xs), var!(space-md));
1094        font-size: var!(font-sm);
1095        font-weight: "600";
1096        cursor: "pointer";
1097        background: var!(accent);
1098        border: format!("1px solid {}", var!(accent));
1099        box-sizing: "border-box";
1100    }
1101
1102    pub(crate) c_euv_tag_solid_white {
1103        display: "inline-block";
1104        vertical-align: "middle";
1105        text-align: "center";
1106        line-height: "1";
1107        color: var!(foreground);
1108        padding: format!("{} {}", var!(space-2xs), var!(space-sm));
1109        font-size: var!(font-xs);
1110        font-weight: "600";
1111        cursor: "pointer";
1112        border: format!("1.5px solid {}", var!(accent));
1113        box-sizing: "border-box";
1114    }
1115
1116    // ═══════════════════════════════════════════════════════════════════════════
1117    // Euv Tag Variants (semantic colour tags)
1118    // ═══════════════════════════════════════════════════════════════════════════
1119
1120    pub(crate) c_euv_tag_outline_black {
1121        display: "inline-block";
1122        vertical-align: "middle";
1123        text-align: "center";
1124        line-height: "1";
1125        color: var!(accent);
1126        padding: format!("{} {}", var!(space-2xs), var!(space-sm));
1127        font-size: var!(font-xs);
1128        font-weight: "600";
1129        cursor: "pointer";
1130        border: format!("1.5px solid {}", var!(accent));
1131        box-sizing: "border-box";
1132    }
1133
1134    pub(crate) c_euv_tag_outline_white {
1135        display: "inline-block";
1136        vertical-align: "middle";
1137        text-align: "center";
1138        line-height: "1";
1139        color: var!(foreground);
1140        padding: format!("{} {}", var!(space-xs), var!(space-md));
1141        font-size: var!(font-sm);
1142        font-weight: "600";
1143        cursor: "pointer";
1144        border: format!("1.5px solid {}", var!(border));
1145        box-sizing: "border-box";
1146    }
1147
1148    pub(crate) c_euv_pagination_label {
1149        font-size: var!(font-xs);
1150        color: var!(muted-foreground);
1151        text-transform: "uppercase";
1152        letter-spacing: "0.08em";
1153    }
1154
1155    pub(crate) c_euv_pagination_text {
1156        font-size: var!(font-base);
1157        font-weight: "600";
1158        color: var!(accent);
1159        // Ellipsize when the link is too narrow for the page title. The
1160        // outer `.c_euv_pagination_link` already sets `overflow: hidden`
1161        // and `min-width: 0`, so a single `text-overflow: ellipsis` here
1162        // is enough — without `white-space: nowrap` the text wraps to
1163        // multiple lines and the ellipsis never kicks in.
1164        white-space: "nowrap";
1165        overflow: "hidden";
1166        text-overflow: "ellipsis";
1167        min-width: "0px";
1168    }
1169
1170    pub(crate) c_euv_pagination_next {
1171        text-align: "right";
1172    }
1173
1174    pub(crate) c_euv_pagination_spacer {
1175        flex: "1";
1176    }
1177
1178    // ═══════════════════════════════════════════════════════════════════════════
1179    // euv_markdown / euv_footer
1180    // ═══════════════════════════════════════════════════════════════════════════
1181
1182    pub(crate) c_euv_markdown {
1183        width: "100%";
1184        min-width: "0px";
1185    }
1186
1187    // Scroll container for a markdown table.
1188    //
1189    // The table keeps `display: table` (so it fills the column and its
1190    // columns are sized by real table layout), which means the *wrapper*
1191    // is what can scroll: `overflow-x` on the table box itself is ignored.
1192    // `min-width: 0` is what lets the wrapper shrink inside the flex/grid
1193    // prose column instead of being floored by its table's intrinsic width,
1194    // so a wide table scrolls rather than pushing the whole article wide.
1195    pub(crate) c_euv_markdown_table_scroll {
1196        overflow-x: "auto";
1197        max-width: "100%";
1198        min-width: "0px";
1199    }
1200
1201    // ═══════════════════════════════════════════════════════════════════════════
1202    // euv_result / euv_doc_layout
1203    // ═══════════════════════════════════════════════════════════════════════════
1204
1205    pub(crate) c_euv_result {
1206        display: "flex";
1207        flex-direction: "column";
1208        align-items: "center";
1209        justify-content: "center";
1210        text-align: "center";
1211        gap: var!(space-md);
1212        padding: format!("{} {}", var!(space-4xl), var!(space-md));
1213        // Half the available height, not half the viewport: the result block
1214        // lives inside a scroll container, so a viewport unit would be taller
1215        // than the visible area on short pages and leave the buttons below
1216        // the fold.
1217        min-height: "50%";
1218    }
1219
1220    pub(crate) c_euv_result_code {
1221        font-size: var!(font-6xl);
1222        font-weight: "700";
1223        line-height: "1";
1224        letter-spacing: "-0.02em";
1225    }
1226
1227    pub(crate) c_euv_result_title {
1228        font-size: var!(font-2xl);
1229        font-weight: "600";
1230        margin: "0px";
1231    }
1232
1233    pub(crate) c_euv_result_description {
1234        color: var!(muted-foreground);
1235        margin: "0px";
1236    }
1237
1238    pub(crate) c_euv_result_actions {
1239        display: "flex";
1240        gap: var!(space-md);
1241        margin-top: var!(space-lg);
1242    }
1243
1244    // ═══════════════════════════════════════════════════════════════════════════
1245    // Empty
1246    // ═══════════════════════════════════════════════════════════════════════════
1247
1248    pub(crate) c_euv_empty {
1249        display: "flex";
1250        flex-direction: "column";
1251        align-items: "center";
1252        justify-content: "center";
1253        gap: var!(space-sm);
1254        width: "100%";
1255        padding: var!(space-3xl);
1256        box-sizing: "border-box";
1257        text-align: "center";
1258    }
1259
1260    pub(crate) c_euv_empty_icon {
1261        font-size: var!(font-3xl);
1262        line-height: "1";
1263        color: var!(muted-foreground);
1264    }
1265
1266    pub(crate) c_euv_empty_text {
1267        font-size: var!(font-lg);
1268        font-weight: "600";
1269        color: var!(foreground);
1270    }
1271
1272    pub(crate) c_euv_empty_desc {
1273        font-size: var!(font-sm);
1274        color: var!(muted-foreground);
1275        max-width: var!(text-measure);
1276    }
1277
1278    pub(crate) c_euv_empty_action {
1279        margin-top: var!(space-sm);
1280    }
1281
1282    // ═══════════════════════════════════════════════════════════════════════════
1283    // Typography
1284    // ═══════════════════════════════════════════════════════════════════════════
1285
1286    pub(crate) c_euv_text {
1287        margin: "0px";
1288        color: var!(foreground);
1289        font-size: var!(font-base);
1290        line-height: "1.6";
1291    }
1292
1293    pub(crate) c_euv_text_title {
1294        margin: "0px";
1295        color: var!(foreground);
1296        font-size: var!(font-xl);
1297        font-weight: "600";
1298        line-height: "1.4";
1299    }
1300
1301    pub(crate) c_euv_text_title_lg {
1302        margin: "0px";
1303        color: var!(foreground);
1304        font-size: var!(font-2xl);
1305        font-weight: "600";
1306        line-height: "1.35";
1307    }
1308
1309    pub(crate) c_euv_text_title_sm {
1310        margin: "0px";
1311        color: var!(foreground);
1312        font-size: var!(font-lg);
1313        font-weight: "600";
1314        line-height: "1.4";
1315    }
1316
1317    pub(crate) c_euv_text_paragraph {
1318        margin: "0px";
1319        color: var!(foreground);
1320        font-size: var!(font-base);
1321        line-height: "1.6";
1322    }
1323
1324    pub(crate) c_euv_text_secondary {
1325        margin: "0px";
1326        color: var!(muted-foreground);
1327        font-size: var!(font-sm);
1328        line-height: "1.6";
1329    }
1330
1331    pub(crate) c_euv_text_mono {
1332        margin: "0px";
1333        color: var!(foreground);
1334        font-size: var!(font-sm);
1335        font-family: "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace";
1336        line-height: "1.5";
1337    }
1338
1339    pub(crate) c_euv_text_deletion {
1340        margin: "0px";
1341        color: var!(muted-foreground);
1342        font-size: var!(font-base);
1343        text-decoration: "line-through";
1344        line-height: "1.6";
1345    }
1346
1347    pub(crate) c_euv_text_underline {
1348        margin: "0px";
1349        color: var!(foreground);
1350        font-size: var!(font-base);
1351        text-decoration: "underline";
1352        line-height: "1.6";
1353    }
1354
1355    // ═══════════════════════════════════════════════════════════════════════════
1356    // Link
1357    // ═══════════════════════════════════════════════════════════════════════════
1358
1359    pub(crate) c_euv_link {
1360        display: "inline";
1361        color: var!(foreground);
1362        font-size: var!(font-base);
1363        text-decoration: "underline";
1364        text-underline-offset: "2px";
1365        cursor: "pointer";
1366        touch-action: "manipulation";
1367        :hover {
1368            color: var!(muted-foreground);
1369        }
1370    }
1371
1372    pub(crate) c_euv_link_disabled {
1373        display: "inline";
1374        color: var!(muted-foreground);
1375        font-size: var!(font-base);
1376        text-decoration: "none";
1377        cursor: "not-allowed";
1378        opacity: "0.5";
1379    }
1380
1381    // ═══════════════════════════════════════════════════════════════════════════
1382    // Image
1383    // ═══════════════════════════════════════════════════════════════════════════
1384
1385    pub(crate) c_euv_image {
1386        display: "block";
1387        max-width: "100%";
1388        height: "auto";
1389        border: "none";
1390        background: "transparent";
1391    }
1392
1393    pub(crate) c_euv_image_placeholder {
1394        display: "flex";
1395        align-items: "center";
1396        justify-content: "center";
1397        width: "100%";
1398        min-height: var!(min-height-base);
1399        padding: var!(space-md);
1400        border: format!("1px dashed {}", var!(border));
1401        background: var!(background);
1402        color: var!(muted-foreground);
1403        font-size: var!(font-sm);
1404        text-align: "center";
1405        box-sizing: "border-box";
1406    }
1407
1408    pub(crate) c_euv_image_failed {
1409        display: "flex";
1410        align-items: "center";
1411        justify-content: "center";
1412        width: "100%";
1413        min-height: var!(min-height-base);
1414        padding: var!(space-md);
1415        border: format!("1px dashed {}", var!(border));
1416        background: var!(background);
1417        color: var!(muted-foreground);
1418        font-size: var!(font-sm);
1419        text-align: "center";
1420        box-sizing: "border-box";
1421    }
1422
1423    // ═══════════════════════════════════════════════════════════════════════════
1424    // Carousel
1425    // ═══════════════════════════════════════════════════════════════════════════
1426
1427    pub(crate) c_euv_carousel {
1428        position: "relative";
1429        display: "flex";
1430        flex-direction: "column";
1431        width: "100%";
1432        overflow: "hidden";
1433    }
1434
1435    pub(crate) c_euv_carousel_track {
1436        display: "flex";
1437        flex-direction: "row";
1438        width: "100%";
1439        transition: format!("transform {} {}", var!(duration-normal), var!(ease-out));
1440    }
1441
1442    pub(crate) c_euv_carousel_slide {
1443        flex: "0 0 100%";
1444        width: "100%";
1445        min-width: "100%";
1446        box-sizing: "border-box";
1447    }
1448
1449    pub(crate) c_euv_carousel_dots {
1450        display: "flex";
1451        align-items: "center";
1452        justify-content: "center";
1453        gap: var!(space-sm);
1454        padding-top: var!(space-sm);
1455    }
1456
1457    pub(crate) c_euv_carousel_dot {
1458        width: var!(space-sm);
1459        height: var!(space-sm);
1460        padding: "0px";
1461        border: format!("1px solid {}", var!(border));
1462        border-radius: "0px";
1463        background: var!(background);
1464        cursor: "pointer";
1465        touch-action: "manipulation";
1466        :hover {
1467            background: var!(accent-muted);
1468        }
1469    }
1470
1471    pub(crate) c_euv_carousel_dot_active {
1472        width: var!(space-sm);
1473        height: var!(space-sm);
1474        padding: "0px";
1475        border: format!("1px solid {}", var!(border));
1476        border-radius: "0px";
1477        background: var!(accent);
1478        cursor: "pointer";
1479        touch-action: "manipulation";
1480        :hover {
1481            background: var!(accent);
1482        }
1483    }
1484
1485    // ═══════════════════════════════════════════════════════════════════════════
1486    // Anchor
1487    // ═══════════════════════════════════════════════════════════════════════════
1488
1489    pub(crate) c_euv_anchor {
1490        display: "flex";
1491        flex-direction: "column";
1492        gap: var!(space-xs);
1493        width: "100%";
1494    }
1495
1496    pub(crate) c_euv_anchor_title {
1497        font-size: var!(font-sm);
1498        font-weight: "600";
1499        color: var!(foreground);
1500        margin-bottom: var!(space-xs);
1501    }
1502
1503    pub(crate) c_euv_anchor_link {
1504        display: "block";
1505        padding: format!("{} 0px", var!(space-2xs));
1506        color: var!(muted-foreground);
1507        font-size: var!(font-sm);
1508        text-decoration: "none";
1509        cursor: "pointer";
1510        touch-action: "manipulation";
1511        :hover {
1512            color: var!(foreground);
1513        }
1514    }
1515
1516    pub(crate) c_euv_anchor_link_active {
1517        display: "block";
1518        padding: format!("{} 0px", var!(space-2xs));
1519        color: var!(foreground);
1520        font-size: var!(font-sm);
1521        font-weight: "600";
1522        text-decoration: "none";
1523        cursor: "pointer";
1524        touch-action: "manipulation";
1525        :hover {
1526            color: var!(foreground);
1527        }
1528    }
1529
1530    // ═══════════════════════════════════════════════════════════════════════════
1531    // Watermark
1532    // ═══════════════════════════════════════════════════════════════════════════
1533
1534    pub(crate) c_euv_watermark {
1535        position: "relative";
1536        display: "block";
1537        width: "100%";
1538    }
1539
1540    pub(crate) c_euv_watermark_layer {
1541        position: "absolute";
1542        top: "0px";
1543        left: "0px";
1544        right: "0px";
1545        bottom: "0px";
1546        z-index: "1";
1547        display: "flex";
1548        align-items: "center";
1549        justify-content: "center";
1550        overflow: "hidden";
1551        pointer-events: "none";
1552    }
1553
1554    pub(crate) c_euv_watermark_text {
1555        color: var!(muted-foreground);
1556        font-size: var!(font-2xl);
1557        font-weight: "700";
1558        letter-spacing: "0.1em";
1559        opacity: "0.12";
1560        transform: "rotate(-22deg)";
1561        user-select: "none";
1562        -webkit-user-select: "none";
1563        white-space: "nowrap";
1564    }
1565
1566    // ═══════════════════════════════════════════════════════════════════════════
1567    // Back To Top
1568    // ═══════════════════════════════════════════════════════════════════════════
1569
1570
1571    pub(crate) c_euv_back_top_visible {
1572        position: "fixed";
1573        right: var!(space-xl);
1574        bottom: var!(space-xl);
1575        z-index: "900";
1576        display: "flex";
1577        align-items: "center";
1578        justify-content: "center";
1579        width: "40px";
1580        height: "40px";
1581        padding: "0px";
1582        border: format!("1px solid {}", var!(border));
1583        background: var!(background);
1584        color: var!(foreground);
1585        font-size: var!(font-sm);
1586        line-height: "1";
1587        cursor: "pointer";
1588        box-shadow: var!(shadow-sm);
1589        touch-action: "manipulation";
1590        :hover {
1591            background: var!(accent-muted);
1592            color: var!(accent);
1593        }
1594        @media ((max-width: 767px)) {
1595            right: var!(space-lg);
1596            bottom: var!(space-lg);
1597        }
1598    }
1599
1600    pub(crate) c_euv_back_top_hidden {
1601        position: "fixed";
1602        right: var!(space-xl);
1603        bottom: var!(space-xl);
1604        z-index: "900";
1605        display: "none";
1606        align-items: "center";
1607        justify-content: "center";
1608        width: "40px";
1609        height: "40px";
1610        padding: "0px";
1611        border: format!("1px solid {}", var!(border));
1612        background: var!(background);
1613        color: var!(foreground);
1614        font-size: var!(font-sm);
1615        line-height: "1";
1616        cursor: "pointer";
1617        box-shadow: var!(shadow-sm);
1618        touch-action: "manipulation";
1619        :hover {
1620            background: var!(accent-muted);
1621            color: var!(accent);
1622        }
1623        @media ((max-width: 767px)) {
1624            right: var!(space-lg);
1625            bottom: var!(space-lg);
1626        }
1627    }
1628
1629    // ═══════════════════════════════════════════════════════════════════════════
1630    // Splitter
1631    // ═══════════════════════════════════════════════════════════════════════════
1632
1633    pub(crate) c_euv_splitter {
1634        display: "flex";
1635        align-items: "stretch";
1636        width: "100%";
1637        height: "100%";
1638        min-height: "0px";
1639    }
1640
1641    pub(crate) c_euv_splitter_pane {
1642        flex: "1";
1643        min-width: "0px";
1644        min-height: "0px";
1645        overflow: "auto";
1646    }
1647
1648    pub(crate) c_euv_splitter_bar {
1649        flex: "0 0 6px";
1650        align-self: "stretch";
1651        background: var!(border);
1652        cursor: "col-resize";
1653        touch-action: "none";
1654        user-select: "none";
1655        -webkit-user-select: "none";
1656        :hover {
1657            background: var!(accent);
1658        }
1659    }
1660
1661    // ═══════════════════════════════════════════════════════════════════════════
1662    // Grid
1663    // ═══════════════════════════════════════════════════════════════════════════
1664
1665    pub(crate) c_euv_grid {
1666        display: "flex";
1667        flex-wrap: "wrap";
1668        width: "100%";
1669        box-sizing: "border-box";
1670    }
1671
1672    // A grid row that spaces its columns.
1673    //
1674    // The spacing is padding on the columns, not a `gap` on the row: a
1675    // column's width is a percentage of the row, so a gap would be
1676    // added on top of a row that already sums to a hundred percent and
1677    // push the last column onto a second line. The row pulls itself
1678    // out by half the gutter and the columns pad themselves back in, so
1679    // the columns still add up to the row's full width.
1680    pub(crate) c_euv_grid_gutter {
1681        display: "flex";
1682        flex-wrap: "wrap";
1683        width: "100%";
1684        box-sizing: "border-box";
1685        margin-left: {
1686            format!("calc({} / -2)", var!(gap-component))
1687        };
1688        margin-right: {
1689            format!("calc({} / -2)", var!(gap-component))
1690        };
1691    }
1692
1693    // A grid column. The width is a share of the row, and the caller
1694    // sets it inline, so a row's columns add up exactly whatever their
1695    // span.
1696    pub(crate) c_euv_grid_col {
1697        display: "block";
1698        flex: "0 0 auto";
1699        box-sizing: "border-box";
1700        min-width: "0px";
1701    }
1702
1703    // A grid column inside a spaced row. The column keeps its share of
1704    // the row and takes half the gutter as padding on each side, which
1705    // is what opens the space between two columns.
1706    pub(crate) c_euv_grid_gutter_col {
1707        display: "block";
1708        flex: "0 0 auto";
1709        box-sizing: "border-box";
1710        min-width: "0px";
1711        padding-left: {
1712            format!("calc({} / 2)", var!(gap-component))
1713        };
1714        padding-right: {
1715            format!("calc({} / 2)", var!(gap-component))
1716        };
1717    }
1718
1719    // A grid column that is pushed to the right by an offset. The
1720    // offset's size is set inline, like the column's own width.
1721    pub(crate) c_euv_grid_col_offset {
1722        display: "block";
1723        flex: "0 0 auto";
1724        box-sizing: "border-box";
1725        min-width: "0px";
1726    }
1727
1728    // A grid column inside a spaced row that is also pushed to the
1729    // right by an offset. It is the spaced column and the offset
1730    // column at once: the padding that opens the gutter and the offset
1731    // that pushes the column along the row.
1732    pub(crate) c_euv_grid_gutter_col_offset {
1733        display: "block";
1734        flex: "0 0 auto";
1735        box-sizing: "border-box";
1736        min-width: "0px";
1737        padding-left: {
1738            format!("calc({} / 2)", var!(gap-component))
1739        };
1740        padding-right: {
1741            format!("calc({} / 2)", var!(gap-component))
1742        };
1743    }
1744
1745    // ═══════════════════════════════════════════════════════════════════════════
1746    // Affix
1747    // ═══════════════════════════════════════════════════════════════════════════
1748
1749    pub(crate) c_euv_affix {
1750        position: "sticky";
1751        z-index: "10";
1752        width: "100%";
1753        box-sizing: "border-box";
1754    }
1755}
1756
1757#[cfg(feature = "custom-styles")]
1758class! {
1759    pub c_card_title {}
1760
1761    // ═══════════════════════════════════════════════════════════════════════════
1762    // Buttons
1763    // ═══════════════════════════════════════════════════════════════════════════
1764
1765    pub c_primary_button {}
1766
1767    // ═══════════════════════════════════════════════════════════════════════════
1768    // Button Controls Container
1769    // ═══════════════════════════════════════════════════════════════════════════
1770
1771    pub c_button_controls {}
1772
1773    // ═══════════════════════════════════════════════════════════════════════════
1774    // Euv Button Variants
1775    // ═══════════════════════════════════════════════════════════════════════════
1776
1777    pub c_euv_button_primary_md {}
1778
1779    // ═══════════════════════════════════════════════════════════════════════════
1780    // Status Boxes
1781    // ═══════════════════════════════════════════════════════════════════════════
1782
1783    pub c_error_box {}
1784
1785    pub c_success_box {}
1786
1787    // ═══════════════════════════════════════════════════════════════════════════
1788    // Counter / Signals Demo
1789    // ═══════════════════════════════════════════════════════════════════════════
1790
1791    pub c_counter_row {}
1792
1793    pub c_counter_text {}
1794
1795    pub c_counter_value {}
1796
1797    pub c_counter_value_row {}
1798
1799    pub c_badge_row {}
1800
1801    pub c_badge_hint {}
1802
1803    // ═══════════════════════════════════════════════════════════════════════════
1804    // Tabs
1805    // ═══════════════════════════════════════════════════════════════════════════
1806
1807    pub c_tab_bar {}
1808
1809    pub c_tab_item_active {}
1810
1811    pub c_tab_item_inactive {}
1812
1813    pub c_tab_content {}
1814
1815    pub c_tab_text {}
1816
1817    pub c_tab_text_muted {}
1818
1819    pub c_tab_text_input {}
1820
1821    // ═══════════════════════════════════════════════════════════════════════════
1822    // List
1823    // ═══════════════════════════════════════════════════════════════════════════
1824
1825    pub c_list_input {}
1826
1827    pub c_list_input_error {}
1828
1829    pub c_list_error_text {}
1830
1831    pub c_inline_input_button_wrap {}
1832
1833    pub c_list_ul {}
1834
1835    pub c_list_item {}
1836
1837    pub c_list_item_text {}
1838
1839    pub c_list_item_button {}
1840
1841    // ═══════════════════════════════════════════════════════════════════════════
1842    // Animation Demo
1843    // ═══════════════════════════════════════════════════════════════════════════
1844
1845    pub c_anim_fade_in {}
1846
1847    pub c_anim_spin_container {}
1848
1849    pub c_anim_spin {}
1850
1851    pub c_anim_spin_stopped {}
1852
1853    pub c_anim_pulse_container {}
1854
1855    pub c_anim_pulse {}
1856
1857    pub c_anim_pulse_stopped {}
1858
1859    pub c_progress_container {}
1860
1861    pub c_progress_bar_running {}
1862
1863    pub c_progress_bar_stopped {}
1864
1865    pub c_anim_scale_box {}
1866
1867    // ═══════════════════════════════════════════════════════════════════════════
1868    // Unified Layout Primitives
1869    // ═══════════════════════════════════════════════════════════════════════════
1870
1871    pub c_element_stack {}
1872
1873    pub c_switcher {}
1874
1875    pub c_switcher_col {}
1876
1877    // ═══════════════════════════════════════════════════════════════════════════
1878    // Unified Description / Hint Text
1879    // ═══════════════════════════════════════════════════════════════════════════
1880
1881    pub c_hint {}
1882
1883    // ═══════════════════════════════════════════════════════════════════════════
1884    // euv_pagination
1885    // ═══════════════════════════════════════════════════════════════════════════
1886
1887    pub c_euv_pagination {}
1888
1889    pub c_euv_pagination_link {}
1890
1891    pub c_euv_footer {}
1892
1893    // One item of the footer row.
1894    //
1895    // `inline-block` rather than a flex box: the text is inline content
1896    // inside this box, so `text-overflow: ellipsis` can cut it with a
1897    // dot when the row is too narrow. A flex box would put the text in
1898    // an anonymous item that no selector can reach, and the text would
1899    // be clipped without a hint that it was cut.
1900    pub c_euv_footer_item {}
1901
1902    // A linked item of the footer row.
1903    pub c_euv_footer_item_link {}
1904
1905    // The official badge that precedes a filing number.
1906    //
1907    // The height is the badge's own size (20px), so the picture is
1908    // served at its native resolution instead of being scaled by the
1909    // browser. The margin is the gap to the number: the link is an
1910    // inline box, so the gap cannot come from a flex `gap`.
1911    pub c_euv_footer_item_icon {}
1912
1913    pub c_euv_doc_layout {}
1914
1915    pub c_euv_doc_content {}
1916
1917    pub c_euv_doc_body {}
1918
1919    pub c_euv_doc_tail {}
1920
1921    pub c_euv_doc_toc {}
1922
1923    // Makes the element's own box disappear while its children stay in the
1924    // parent's layout flow, so a wrapper can carry a key or a conditional
1925    // without contributing a box.
1926    //
1927    // The docs shell and page wrappers spelled this as an inline
1928    // `style: "display: contents"`; the rule is the same either way, but a
1929    // named class keeps the markup declarative and lets the browser cache it.
1930    pub c_euv_display_contents {}
1931
1932    // ═══════════════════════════════════════════════════════════════════════
1933    // Home Page Layout
1934    // ═══════════════════════════════════════════════════════════════════════
1935
1936    pub c_home_layout {}
1937
1938    pub c_home_content {}
1939
1940    pub c_home_body {}
1941
1942    pub c_home_tail {}
1943
1944    pub(crate) c_euv_tabs {}
1945
1946    pub(crate) c_euv_tabs_bar {}
1947
1948    pub(crate) c_euv_tab_item {}
1949
1950    pub(crate) c_euv_tab_item_active {}
1951
1952    pub(crate) c_euv_tabs_panel {}
1953
1954    pub(crate) c_euv_collapse_item {}
1955
1956    pub(crate) c_euv_collapse_header {}
1957
1958    pub(crate) c_euv_collapse_header_active {}
1959
1960    pub(crate) c_euv_collapse_body {}
1961
1962    pub(crate) c_euv_collapse_body_open {}
1963
1964    pub(crate) c_euv_collapse_body_closed {}
1965
1966    pub(crate) c_euv_breadcrumb {}
1967
1968    pub(crate) c_euv_breadcrumb_item {}
1969
1970    pub(crate) c_euv_breadcrumb_sep {}
1971
1972    pub(crate) c_euv_breadcrumb_current {}
1973
1974    pub(crate) c_euv_divider {}
1975
1976    pub(crate) c_euv_divider_horizontal {}
1977
1978    pub(crate) c_euv_divider_vertical {}
1979
1980    pub(crate) c_euv_divider_labeled {}
1981
1982    pub(crate) c_euv_divider_label_text {}
1983
1984    // ═══════════════════════════════════════════════════════════════════════════
1985    // Card Component
1986    // ═══════════════════════════════════════════════════════════════════════════
1987
1988    pub(crate) c_card {}
1989
1990    pub(crate) c_modal_close_button {}
1991
1992    pub(crate) c_euv_button_outline_md {}
1993
1994    // ═══════════════════════════════════════════════════════════════════════════
1995    // Badges
1996    // ═══════════════════════════════════════════════════════════════════════════
1997
1998    pub(crate) c_badge {}
1999
2000    pub(crate) c_badge_outline {}
2001
2002    pub(crate) c_euv_tag_solid_black {}
2003
2004    pub(crate) c_euv_tag_solid_white {}
2005
2006    // ═══════════════════════════════════════════════════════════════════════════
2007    // Euv Tag Variants (semantic colour tags)
2008    // ═══════════════════════════════════════════════════════════════════════════
2009
2010    pub(crate) c_euv_tag_outline_black {}
2011
2012    pub(crate) c_euv_tag_outline_white {}
2013
2014    pub(crate) c_euv_pagination_label {}
2015
2016    pub(crate) c_euv_pagination_text {}
2017
2018    pub(crate) c_euv_pagination_next {}
2019
2020    pub(crate) c_euv_pagination_spacer {}
2021
2022    // ═══════════════════════════════════════════════════════════════════════════
2023    // euv_markdown / euv_footer
2024    // ═══════════════════════════════════════════════════════════════════════════
2025
2026    pub(crate) c_euv_markdown {}
2027
2028    // Scroll container for a markdown table.
2029    //
2030    // The table keeps `display: table` (so it fills the column and its
2031    // columns are sized by real table layout), which means the *wrapper*
2032    // is what can scroll: `overflow-x` on the table box itself is ignored.
2033    // `min-width: 0` is what lets the wrapper shrink inside the flex/grid
2034    // prose column instead of being floored by its table's intrinsic width,
2035    // so a wide table scrolls rather than pushing the whole article wide.
2036    pub(crate) c_euv_markdown_table_scroll {}
2037
2038    // ═══════════════════════════════════════════════════════════════════════════
2039    // euv_result / euv_doc_layout
2040    // ═══════════════════════════════════════════════════════════════════════════
2041
2042    pub(crate) c_euv_result {}
2043
2044    pub(crate) c_euv_result_code {}
2045
2046    pub(crate) c_euv_result_title {}
2047
2048    pub(crate) c_euv_result_description {}
2049
2050    pub(crate) c_euv_result_actions {}
2051
2052    // ═══════════════════════════════════════════════════════════════════════════
2053    // Empty
2054    // ═══════════════════════════════════════════════════════════════════════════
2055
2056    pub(crate) c_euv_empty {}
2057
2058    pub(crate) c_euv_empty_icon {}
2059
2060    pub(crate) c_euv_empty_text {}
2061
2062    pub(crate) c_euv_empty_desc {}
2063
2064    pub(crate) c_euv_empty_action {}
2065
2066    // ═══════════════════════════════════════════════════════════════════════════
2067    // Typography
2068    // ═══════════════════════════════════════════════════════════════════════════
2069
2070    pub(crate) c_euv_text {}
2071
2072    pub(crate) c_euv_text_title {}
2073
2074    pub(crate) c_euv_text_title_lg {}
2075
2076    pub(crate) c_euv_text_title_sm {}
2077
2078    pub(crate) c_euv_text_paragraph {}
2079
2080    pub(crate) c_euv_text_secondary {}
2081
2082    pub(crate) c_euv_text_mono {}
2083
2084    pub(crate) c_euv_text_deletion {}
2085
2086    pub(crate) c_euv_text_underline {}
2087
2088    // ═══════════════════════════════════════════════════════════════════════════
2089    // Link
2090    // ═══════════════════════════════════════════════════════════════════════════
2091
2092    pub(crate) c_euv_link {}
2093
2094    pub(crate) c_euv_link_disabled {}
2095
2096    // ═══════════════════════════════════════════════════════════════════════════
2097    // Image
2098    // ═══════════════════════════════════════════════════════════════════════════
2099
2100    pub(crate) c_euv_image {}
2101
2102    pub(crate) c_euv_image_placeholder {}
2103
2104    pub(crate) c_euv_image_failed {}
2105
2106    // ═══════════════════════════════════════════════════════════════════════════
2107    // Carousel
2108    // ═══════════════════════════════════════════════════════════════════════════
2109
2110    pub(crate) c_euv_carousel {}
2111
2112    pub(crate) c_euv_carousel_track {}
2113
2114    pub(crate) c_euv_carousel_slide {}
2115
2116    pub(crate) c_euv_carousel_dots {}
2117
2118    pub(crate) c_euv_carousel_dot {}
2119
2120    pub(crate) c_euv_carousel_dot_active {}
2121
2122    // ═══════════════════════════════════════════════════════════════════════════
2123    // Anchor
2124    // ═══════════════════════════════════════════════════════════════════════════
2125
2126    pub(crate) c_euv_anchor {}
2127
2128    pub(crate) c_euv_anchor_title {}
2129
2130    pub(crate) c_euv_anchor_link {}
2131
2132    pub(crate) c_euv_anchor_link_active {}
2133
2134    // ═══════════════════════════════════════════════════════════════════════════
2135    // Watermark
2136    // ═══════════════════════════════════════════════════════════════════════════
2137
2138    pub(crate) c_euv_watermark {}
2139
2140    pub(crate) c_euv_watermark_layer {}
2141
2142    pub(crate) c_euv_watermark_text {}
2143
2144    // ═══════════════════════════════════════════════════════════════════════════
2145    // Back To Top
2146    // ═══════════════════════════════════════════════════════════════════════════
2147
2148
2149    pub(crate) c_euv_back_top_visible {}
2150
2151    pub(crate) c_euv_back_top_hidden {}
2152
2153    // ═══════════════════════════════════════════════════════════════════════════
2154    // Splitter
2155    // ═══════════════════════════════════════════════════════════════════════════
2156
2157    pub(crate) c_euv_splitter {}
2158
2159    pub(crate) c_euv_splitter_pane {}
2160
2161    pub(crate) c_euv_splitter_bar {}
2162
2163    // ═══════════════════════════════════════════════════════════════════════════
2164    // Grid
2165    // ═══════════════════════════════════════════════════════════════════════════
2166
2167    pub(crate) c_euv_grid {}
2168
2169    // A grid row that spaces its columns.
2170    //
2171    // The spacing is padding on the columns, not a `gap` on the row: a
2172    // column's width is a percentage of the row, so a gap would be
2173    // added on top of a row that already sums to a hundred percent and
2174    // push the last column onto a second line. The row pulls itself
2175    // out by half the gutter and the columns pad themselves back in, so
2176    // the columns still add up to the row's full width.
2177    pub(crate) c_euv_grid_gutter {}
2178
2179    // A grid column. The width is a share of the row, and the caller
2180    // sets it inline, so a row's columns add up exactly whatever their
2181    // span.
2182    pub(crate) c_euv_grid_col {}
2183
2184    // A grid column inside a spaced row. The column keeps its share of
2185    // the row and takes half the gutter as padding on each side, which
2186    // is what opens the space between two columns.
2187    pub(crate) c_euv_grid_gutter_col {}
2188
2189    // A grid column that is pushed to the right by an offset. The
2190    // offset's size is set inline, like the column's own width.
2191    pub(crate) c_euv_grid_col_offset {}
2192
2193    // A grid column inside a spaced row that is also pushed to the
2194    // right by an offset. It is the spaced column and the offset
2195    // column at once: the padding that opens the gutter and the offset
2196    // that pushes the column along the row.
2197    pub(crate) c_euv_grid_gutter_col_offset {}
2198
2199    // ═══════════════════════════════════════════════════════════════════════════
2200    // Affix
2201    // ═══════════════════════════════════════════════════════════════════════════
2202
2203    pub(crate) c_euv_affix {}
2204}