Skip to main content

euv_ui/style/class/display/
fn.rs

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