@viraui/react 2026.8.0 → 2026.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- @layer viraui.preflight, viraui.components, viraui.overrides;@layer viraui.components{@property --vui-select-input-height{syntax:"<length>";inherits:true;initial-value:0}@property --vui-select-control-group-background{syntax:"<color>";inherits:true;initial-value:#0000}@property --vui-select-control-group-color{syntax:"<color>";inherits:true;initial-value:#0000}@property --vui-select-control-group-border-color{syntax:"<color>";inherits:true;initial-value:#0000}@property --vui-select-control-group-border-radius{syntax:"<length-percentage>";inherits:true;initial-value:0}@property --vui-select-trigger-padding-inline-start{syntax:"<length>";inherits:true;initial-value:0}@property --vui-select-trigger-padding-inline-end{syntax:"<length>";inherits:true;initial-value:0}@property --vui-select-list-border-radius{syntax:"<length-percentage>";inherits:true;initial-value:0}@property --vui-select-list-padding{syntax:"<length>";inherits:true;initial-value:0}@property --__select-list-appear-offset{syntax:"<length>";inherits:false;initial-value:8px}.viraui__select-module__Select_eXv4Y{--vui-select-input-height:var(--space-2xl);--vui-select-control-group-background:var(--base-1);--vui-select-control-group-color:var(--global-foreground);--vui-select-control-group-border-color:var(--global-contrast);--vui-select-control-group-border-radius:var(--radius-m);--vui-select-trigger-padding-inline-start:calc(var(--space-s) + var(--space-xs));--vui-select-trigger-padding-inline-end:var(--space-xs);--vui-field-label-padding-inline:calc((var(--vui-select-control-group-border-radius) + 0px) / 2);max-block-size:min-content;z-index:0;&:has([required]) .viraui__select-module__Label_-Y1fR{&:after{content:" *";color:var(--highlight-red)}&:dir(rtl){&:after{content:none}&:before{content:"* ";color:var(--highlight-red)}}}&[data-invalid]>.viraui__select-module__Trigger_-wBsg:not(:disabled):not([data-disabled]){--vui-select-control-group-border-color:var(--highlight-red);box-shadow:none;outline-color:oklab(from var(--highlight-red) l a b/.5)}}.viraui__select-module__Trigger_-wBsg{box-sizing:border-box;inline-size:100%;block-size:round(to-zero,var(--vui-select-input-height),2px);padding-inline:var(--vui-select-trigger-padding-inline-start) var(--vui-select-trigger-padding-inline-end);border:1px solid var(--vui-select-control-group-border-color);border-radius:var(--vui-select-control-group-border-radius);background:var(--vui-select-control-group-background);color:var(--vui-select-control-group-color);font:inherit;text-align:start;cursor:pointer;transition:background var(--duration-instant) var(--easing-standard);&:not([data-disabled],:disabled):hover{--vui-select-control-group-background:var(--base-2)}&[data-popup-open]{outline:none}&:disabled,&[data-disabled]{--vui-select-control-group-background:var(--global-disabled-background);--vui-select-control-group-border-color:#0000;--vui-select-control-group-color:var(--global-disabled-foreground);box-shadow:none;cursor:not-allowed}}.viraui__select-module__Icon_EOwki{font-size:var(--font-scale-body-s);pointer-events:none}.viraui__select-module__Description_OmwmV{padding-inline:calc((var(--vui-select-control-group-border-radius) + 0px) / 2)}.viraui__select-module__SelectPopup_UzGXL{--vui-select-list-border-radius:var(--radius-m);--vui-select-list-padding:var(--space-xs);box-sizing:border-box;min-inline-size:var(--anchor-width);overflow:visible;color:var(--global-foreground);outline:none;position:relative;transform-origin:var(--transform-origin);transition:opacity var(--duration-instant) var(--easing-entrance),scale var(--duration-instant) var(--easing-entrance),translate var(--duration-instant) var(--easing-entrance);&[data-ending-style],&[data-starting-style]{opacity:0;scale:.96}&[data-side=bottom][data-ending-style],&[data-side=bottom][data-starting-style]{translate:0 calc(var(--__select-list-appear-offset) * -1)}&[data-side=top][data-ending-style],&[data-side=top][data-starting-style]{translate:0 var(--__select-list-appear-offset)}&[data-side=inline-start][data-ending-style],&[data-side=inline-start][data-starting-style],&[data-side=left][data-ending-style],&[data-side=left][data-starting-style]{translate:var(--__select-list-appear-offset) 0}&[data-side=inline-end][data-ending-style],&[data-side=inline-end][data-starting-style],&[data-side=right][data-ending-style],&[data-side=right][data-starting-style]{translate:calc(var(--__select-list-appear-offset) * -1) 0}&[data-side=none]{transition:none;scale:1;translate:0;opacity:1}}.viraui__select-module__ScrollArrow_kHlEi{position:absolute;inset-inline:0;z-index:1;inline-size:100%;block-size:var(--space-l);cursor:default;background:var(--base-1);border:1px solid var(--global-contrast);@container root not style(--effect-vibrancy: initial){background:oklab(from var(--base-1) l a b/80%);backdrop-filter:brightness(var(--vibrancy-brightness)) blur(calc(var(--vibrancy-blur) * 1px))}}.viraui__select-module__ScrollButton_sHBOa{pointer-events:none}.viraui__select-module__ScrollArrowUp_DGXS-{inset-block-start:0;border-radius:var(--vui-select-list-border-radius) var(--vui-select-list-border-radius) 0 0}.viraui__select-module__ScrollArrowDown_vhJy0{inset-block-end:0;border-radius:0 0 var(--vui-select-list-border-radius) var(--vui-select-list-border-radius)}.viraui__select-module__List_jdUWx{box-sizing:border-box;inline-size:100%;max-block-size:var(--available-height);scroll-padding-block:var(--vui-select-list-padding);overscroll-behavior:contain;&:focus,&:focus-visible{outline:none}}.viraui__select-module__Indicator_YNUuz{min-inline-size:var(--space-m);min-block-size:var(--space-m);inline-size:fit-content;block-size:fit-content;color:var(--global-foreground);opacity:0;transition:opacity var(--duration-fast) var(--easing-standard),transform var(--duration-fast) var(--easing-standard);&[data-selected]{opacity:1}}}@layer viraui.overrides{.viraui__select-module__Value_uWHPX{overflow:hidden;display:block;text-overflow:ellipsis;&[data-placeholder]{color:var(--global-disabled-foreground)}}.viraui__select-module__Option_KgYqz{cursor:pointer;&:focus{outline:none}&:focus-visible{outline:none;box-shadow:none}&:not([data-disabled]):hover,&:not([data-disabled])[data-highlighted]{background:var(--global-contrast);@container root not style(--effect-vibrancy: initial){background:oklab(from var(--global-contrast) l a b/8%)}}&:not([data-disabled],:hover)[data-selected]{background:light-dark(oklab(from var(--global-contrast) l a b/8%),oklab(from var(--global-contrast) l a b/5%))}&[data-disabled]{color:var(--global-disabled-foreground);cursor:not-allowed}}}
1
+ @layer viraui.preflight, viraui.components, viraui.overrides;@layer viraui.components{@property --vui-select-input-height{syntax:"<length>";inherits:true;initial-value:0}@property --vui-select-control-group-background{syntax:"<color>";inherits:true;initial-value:#0000}@property --vui-select-control-group-color{syntax:"<color>";inherits:true;initial-value:#0000}@property --vui-select-control-group-border-color{syntax:"<color>";inherits:true;initial-value:#0000}@property --vui-select-control-group-border-radius{syntax:"<length-percentage>";inherits:true;initial-value:0}@property --vui-select-trigger-padding-inline-start{syntax:"<length>";inherits:true;initial-value:0}@property --vui-select-trigger-padding-inline-end{syntax:"<length>";inherits:true;initial-value:0}@property --vui-select-list-border-radius{syntax:"<length-percentage>";inherits:true;initial-value:0}@property --vui-select-list-padding{syntax:"<length>";inherits:true;initial-value:0}@property --__select-list-appear-offset{syntax:"<length>";inherits:false;initial-value:8px}.viraui__select-module__Select_eXv4Y{--vui-select-input-height:var(--space-2xl);--vui-select-control-group-background:var(--base-1);--vui-select-control-group-color:var(--global-foreground);--vui-select-control-group-border-color:var(--global-contrast);--vui-select-control-group-border-radius:var(--radius-m);--vui-select-trigger-padding-inline-start:calc(var(--space-s) + var(--space-xs));--vui-select-trigger-padding-inline-end:var(--space-xs);--vui-field-label-padding-inline:calc((var(--vui-select-control-group-border-radius) + 0px) / 2);max-block-size:min-content;z-index:0;&:has([required]) .viraui__select-module__Label_-Y1fR{&:after{content:" *";color:var(--highlight-red)}&:dir(rtl){&:after{content:none}&:before{content:"* ";color:var(--highlight-red)}}}&[data-invalid]>.viraui__select-module__Trigger_-wBsg:not(:disabled):not([data-disabled]){--vui-select-control-group-border-color:var(--highlight-red);box-shadow:none;outline-color:oklab(from var(--highlight-red) l a b/.5)}}.viraui__select-module__Trigger_-wBsg{box-sizing:border-box;inline-size:100%;block-size:round(to-zero,var(--vui-select-input-height),2px);padding-inline:var(--vui-select-trigger-padding-inline-start) var(--vui-select-trigger-padding-inline-end);border:1px solid var(--vui-select-control-group-border-color);border-radius:var(--vui-select-control-group-border-radius);background:var(--vui-select-control-group-background);color:var(--vui-select-control-group-color);font:inherit;text-align:start;cursor:pointer;transition:background var(--duration-instant) var(--easing-standard);&:not([data-disabled],:disabled):hover{--vui-select-control-group-background:var(--base-2)}&[data-popup-open]{outline:none}&:disabled,&[data-disabled]{--vui-select-control-group-background:var(--global-disabled-background);--vui-select-control-group-border-color:#0000;--vui-select-control-group-color:var(--global-disabled-foreground);box-shadow:none;cursor:not-allowed}}.viraui__select-module__Icon_EOwki{font-size:var(--font-scale-body-s);pointer-events:none}.viraui__select-module__Description_OmwmV{padding-inline:calc((var(--vui-select-control-group-border-radius) + 0px) / 2)}.viraui__select-module__SelectPopup_UzGXL{--vui-select-list-border-radius:var(--radius-m);--vui-select-list-padding:var(--space-xs);box-sizing:border-box;min-inline-size:var(--anchor-width);overflow:visible;color:var(--global-foreground);outline:none;position:relative;transform-origin:var(--transform-origin);transition:opacity var(--duration-instant) var(--easing-entrance),scale var(--duration-instant) var(--easing-entrance),translate var(--duration-instant) var(--easing-entrance);&[data-ending-style],&[data-starting-style]{opacity:0;scale:.96}&[data-side=bottom][data-ending-style],&[data-side=bottom][data-starting-style]{translate:0 calc(var(--__select-list-appear-offset) * -1)}&[data-side=top][data-ending-style],&[data-side=top][data-starting-style]{translate:0 var(--__select-list-appear-offset)}&[data-side=inline-start][data-ending-style],&[data-side=inline-start][data-starting-style],&[data-side=left][data-ending-style],&[data-side=left][data-starting-style]{translate:var(--__select-list-appear-offset) 0}&[data-side=inline-end][data-ending-style],&[data-side=inline-end][data-starting-style],&[data-side=right][data-ending-style],&[data-side=right][data-starting-style]{translate:calc(var(--__select-list-appear-offset) * -1) 0}&[data-side=none]{transition:none;scale:1;translate:0;opacity:1}}.viraui__select-module__ScrollArrow_kHlEi{position:absolute;inset-inline:0;z-index:1;inline-size:100%;block-size:var(--space-l);cursor:default;background:var(--base-1);border:1px solid var(--global-contrast);@container root not style(--effect-vibrancy: initial){background:oklab(from var(--base-1) l a b/80%);backdrop-filter:blur(calc(var(--vibrancy-blur) * 1px))}}.viraui__select-module__ScrollButton_sHBOa{pointer-events:none}.viraui__select-module__ScrollArrowUp_DGXS-{inset-block-start:0;border-radius:var(--vui-select-list-border-radius) var(--vui-select-list-border-radius) 0 0}.viraui__select-module__ScrollArrowDown_vhJy0{inset-block-end:0;border-radius:0 0 var(--vui-select-list-border-radius) var(--vui-select-list-border-radius)}.viraui__select-module__List_jdUWx{box-sizing:border-box;inline-size:100%;max-block-size:var(--available-height);scroll-padding-block:var(--vui-select-list-padding);overscroll-behavior:contain;&:focus,&:focus-visible{outline:none}}.viraui__select-module__Indicator_YNUuz{min-inline-size:var(--space-m);min-block-size:var(--space-m);inline-size:fit-content;block-size:fit-content;color:var(--global-foreground);opacity:0;transition:opacity var(--duration-fast) var(--easing-standard),transform var(--duration-fast) var(--easing-standard);&[data-selected]{opacity:1}}}@layer viraui.overrides{.viraui__select-module__Value_uWHPX{overflow:hidden;display:block;text-overflow:ellipsis;&[data-placeholder]{color:var(--global-disabled-foreground)}}.viraui__select-module__Option_KgYqz{cursor:pointer;&:focus{outline:none}&:focus-visible{outline:none;box-shadow:none}&:not([data-disabled]):hover,&:not([data-disabled])[data-highlighted]{background:var(--global-contrast);@container root not style(--effect-vibrancy: initial){background:oklab(from var(--global-contrast) l a b/8%)}}&:not([data-disabled],:hover)[data-selected]{background:light-dark(oklab(from var(--global-contrast) l a b/8%),oklab(from var(--global-contrast) l a b/5%))}&[data-disabled]{color:var(--global-disabled-foreground);cursor:not-allowed}}}
@@ -1 +1 @@
1
- @layer viraui.preflight, viraui.components, viraui.overrides;@layer viraui.components{@property --vui-stack-row-gap{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-column-gap{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-h-align{syntax:"*";inherits:false;initial-value:initial}@property --vui-stack-v-align{syntax:"*";inherits:false;initial-value:initial}@property --vui-stack-padding-inline-start{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-padding-inline-end{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-padding-block-start{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-padding-block-end{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-max-width{syntax:"*";inherits:false;initial-value:none}@property --vui-stack-min-width{syntax:"*";inherits:false;initial-value:none}.viraui__stack-module__Stack_NR-Ey{display:flex;gap:var(--vui-stack-row-gap) var(--vui-stack-column-gap);flex-direction:column;align-items:var(--vui-stack-h-align);justify-content:var(--vui-stack-v-align);max-inline-size:var(--vui-stack-max-width);min-inline-size:var(--vui-stack-min-width);&[data-stack-direction=column-reverse]{flex-direction:column-reverse}&[data-stack-direction=row-reverse],&[data-stack-direction=row]{align-items:var(--vui-stack-v-align);justify-content:var(--vui-stack-h-align)}&[data-stack-direction=row]{flex-direction:row}&[data-stack-direction=row-reverse]{flex-direction:row-reverse}&[data-stack-inline=true]{display:inline-flex;flex-grow:0}:where(&[data-stack-wrap=true]){flex-wrap:wrap}:where(&[data-stack-has-padding=true]){padding:var(--vui-stack-padding-block-start) var(--vui-stack-padding-inline-end) var(--vui-stack-padding-block-end) var(--vui-stack-padding-inline-start)}:where(&[data-stack-expand-children=true]>*){flex-grow:var(--vira-flex-grow,1)}&[data-stack-full-width=true]{inline-size:100%}&[data-stack-container=true]{container:stack/inline-size}}}
1
+ @layer viraui.preflight, viraui.components, viraui.overrides;@layer viraui.components{@property --vui-stack-row-gap{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-column-gap{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-h-align{syntax:"*";inherits:false;initial-value:initial}@property --vui-stack-v-align{syntax:"*";inherits:false;initial-value:initial}@property --vui-stack-padding-inline-start{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-padding-inline-end{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-padding-block-start{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-padding-block-end{syntax:"<length>";inherits:false;initial-value:0}@property --vui-stack-max-width{syntax:"*";inherits:false;initial-value:none}@property --vui-stack-min-width{syntax:"*";inherits:false;initial-value:none}.viraui__stack-module__Stack_NR-Ey{display:flex;gap:var(--vui-stack-row-gap) var(--vui-stack-column-gap);flex-direction:column;align-items:var(--vui-stack-h-align);justify-content:var(--vui-stack-v-align);max-inline-size:var(--vui-stack-max-width);min-inline-size:var(--vui-stack-min-width);&[data-stack-direction=column-reverse]{flex-direction:column-reverse}&[data-stack-direction=row-reverse],&[data-stack-direction=row]{align-items:var(--vui-stack-v-align);justify-content:var(--vui-stack-h-align)}&[data-stack-direction=row]{flex-direction:row}&[data-stack-direction=row-reverse]{flex-direction:row-reverse}&[data-stack-inline=true]{display:inline-flex;flex-grow:0}:where(&[data-stack-wrap=true]){flex-wrap:wrap}:where(&[data-stack-has-padding=true]){padding:var(--vui-stack-padding-block-start) var(--vui-stack-padding-inline-end) var(--vui-stack-padding-block-end) var(--vui-stack-padding-inline-start)}:where(&[data-stack-expand-children=true]>*){flex-grow:var(--vira-flex-grow,1)}&[data-stack-full-width=true]{inline-size:100%}&[data-stack-full-height=true]{block-size:100%}&[data-stack-container=true]{container:stack/inline-size}}}
@@ -47,8 +47,9 @@ export type StackProps = React.ComponentPropsWithoutRef<'div'> & {
47
47
  * Makes direct children grow along the flex main axis (`flex-grow`).
48
48
  *
49
49
  * Prefer for equal-width row actions instead of inventing width/flex CSS on each child.
50
- * Does not set the stack root's own inline size — use `fullWidth` when this stack must
51
- * fill its parent width (e.g. centered shell with `maxWidth`, or a full-bleed Button column).
50
+ * Cross-axis fill stays on `hAlign` / `vAlign="stretch"` (which prop is cross depends on
51
+ * `direction`). Does not size this root — use `fullWidth` / `fullHeight` when the Stack must
52
+ * fill its parent first so stretch has room.
52
53
  *
53
54
  * @defaultValue false
54
55
  */
@@ -59,11 +60,22 @@ export type StackProps = React.ComponentPropsWithoutRef<'div'> & {
59
60
  * Prefer this (with cross-axis stretch) so content-sized children like Button span a panel —
60
61
  * do not add `width: 100%` CSS on those children.
61
62
  * Use with `maxWidth` under a parent `hAlign="center"` for a fluid, capped, centered shell.
62
- * Orthogonal to `expandChildren` (self size vs children grow).
63
+ * Orthogonal to `expandChildren` (self size vs children grow). Pair with `fullHeight` when the
64
+ * root must fill both parent axes.
63
65
  *
64
66
  * @defaultValue false
65
67
  */
66
68
  fullWidth?: boolean;
69
+ /**
70
+ * Sets `block-size: 100%` on the stack root so it fills the parent's block size.
71
+ *
72
+ * Prefer this over `style`/`className` `height` / `block-size: 100%` on this Stack.
73
+ * Pair with `expandChildren` and cross-axis `hAlign`/`vAlign="stretch"` so children fill both
74
+ * axes without per-child size CSS. Orthogonal to `expandChildren` and `fullWidth`.
75
+ *
76
+ * @defaultValue false
77
+ */
78
+ fullHeight?: boolean;
67
79
  /**
68
80
  * Sets the gap between flex rows using the Vira space token scale.
69
81
  *
@@ -5,7 +5,7 @@ import { resolveAxisPadding } from "../../core/styles/resolve-axis-padding.js";
5
5
  import stack_module_default from "./stack.module.js";
6
6
  import { useRender } from "@base-ui/react/use-render";
7
7
  //#region src/components/stack/stack.tsx
8
- var Stack = ({ className, direction = "column", expandChildren = false, fullWidth = false, hAlign = "initial", hPadding, inline = false, maxWidth, minWidth, enableContainer, ref, render, rowGap, columnGap, style, vAlign = "initial", vPadding, wrap = false, ...otherProps }) => {
8
+ var Stack = ({ className, direction = "column", expandChildren = false, fullHeight = false, fullWidth = false, hAlign = "initial", hPadding, inline = false, maxWidth, minWidth, enableContainer, ref, render, rowGap, columnGap, style, vAlign = "initial", vPadding, wrap = false, ...otherProps }) => {
9
9
  const hasPadding = Boolean(hPadding || vPadding);
10
10
  const dynamicStyle = {
11
11
  "--vui-stack-row-gap": resolveThemeValue(rowGap, "space", 0),
@@ -30,6 +30,7 @@ var Stack = ({ className, direction = "column", expandChildren = false, fullWidt
30
30
  "data-stack-wrap": wrap ? "true" : "false",
31
31
  "data-stack-expand-children": expandChildren ? "true" : "false",
32
32
  "data-stack-full-width": fullWidth ? "true" : "false",
33
+ "data-stack-full-height": fullHeight ? "true" : "false",
33
34
  "data-stack-has-padding": hasPadding ? "true" : "false",
34
35
  className: clsx(stack_module_default.Stack, className),
35
36
  style: dynamicStyle
@@ -4,4 +4,4 @@
4
4
  )}&[data-surface-hover-color=primary]{--vui-surface-background-hover:light-dark(
5
5
  oklab(from var(--global-primary) l a b / 20%),
6
6
  oklab(from var(--global-primary) l a b / 10%)
7
- )}@container root not style(--effect-vibrancy: initial){&[data-vibrant]{background:oklab(from var(--global-background) l a b/80%)}&[data-vibrant][data-surface-has-color=true]{background:oklab(from var(--vui-surface-background) l a b/80%)}}&[data-surface-has-padding=true]{padding:var(--vui-surface-padding-block-start) var(--vui-surface-padding-inline-end) var(--vui-surface-padding-block-end) var(--vui-surface-padding-inline-start)}&[data-surface-border]{border-style:var(--vui-surface-border-style);border-color:var(--global-contrast);border-left-width:0;border-bottom-width:0;border-right-width:0;border-top-width:0}&[data-surface-border~=all]{border-width:1px}&[data-surface-border~=top]{border-top-width:1px}&[data-surface-border~=right]{border-right-width:1px}&[data-surface-border~=bottom]{border-bottom-width:1px}&[data-surface-border~=left]{border-left-width:1px}@media (hover:hover) and (pointer:fine){&[data-surface-has-hover-color=true]:hover{background:var(--vui-surface-background-hover)}}&[data-surface-container=true]{container:surface/inline-size}}}
7
+ )}@container root not style(--effect-vibrancy: initial){&[data-vibrant]{background:#0000}&[data-vibrant][data-surface-has-color=true]{background:oklab(from var(--vui-surface-background) l a b/80%)}}&[data-surface-has-padding=true]{padding:var(--vui-surface-padding-block-start) var(--vui-surface-padding-inline-end) var(--vui-surface-padding-block-end) var(--vui-surface-padding-inline-start)}&[data-surface-border]{border-style:var(--vui-surface-border-style);border-color:var(--global-contrast);border-left-width:0;border-bottom-width:0;border-right-width:0;border-top-width:0}&[data-surface-border~=all]{border-width:1px}&[data-surface-border~=top]{border-top-width:1px}&[data-surface-border~=right]{border-right-width:1px}&[data-surface-border~=bottom]{border-bottom-width:1px}&[data-surface-border~=left]{border-left-width:1px}@media (hover:hover) and (pointer:fine){&[data-surface-has-hover-color=true]:hover{background:var(--vui-surface-background-hover)}}&[data-surface-container=true]{container:surface/inline-size}}}
@@ -1,4 +1,4 @@
1
1
  @layer viraui.preflight, viraui.components, viraui.overrides;@layer viraui.preflight{@property --scrollbar-thumb{syntax:"<color>";initial-value:#0000;inherits:true}@property --scrollbar-track{syntax:"<color>";initial-value:#0000;inherits:true}@property --outline-offset{syntax:"<length>";initial-value:2px;inherits:true}@property --outline-color{syntax:"<color>";initial-value:currentcolor;inherits:true}@property --outline{syntax:"*";initial-value:2px solid currentcolor;inherits:true}@property --is-light-mode{syntax:"<color>";initial-value:#000;inherits:true}@property --vira-flex-grow{syntax:"<number>";initial-value:1;inherits:false}@property --vira-flex-shrink{syntax:"<number>";initial-value:1;inherits:false}@property --__corner-shape{syntax:"*";inherits:false}}@layer viraui.preflight{:root{--font-scale-body-m:1rem;--font-scale-body-s:min(1rem, max(0.875rem, round(down, calc(1rem / pow(var(--font-body-typescale), 1)), 1px)));--font-scale-body-xs:min(
2
2
  var(--font-scale-body-s),
3
3
  max(0.75rem, round(down, calc(1rem / pow(var(--font-body-typescale), 2)), 1px))
4
- );--font-scale-body-l:round(down, calc(1rem * pow(var(--font-body-typescale), 1)), 1px);--font-scale-body-xl:round(down, calc(1rem * pow(var(--font-body-typescale), 2)), 1px);--font-scale-body-2xl:round(down, calc(1rem * pow(var(--font-body-typescale), 3)), 1px);--font-scale-body-3xl:round(down, calc(1rem * pow(var(--font-body-typescale), 4)), 1px);--font-scale-body-4xl:round(down, calc(1rem * pow(var(--font-body-typescale), 5)), 1px);--font-scale-h6:round(down, calc(1rem * pow(var(--font-heading-typescale), 1)), 1px);--font-scale-h5:round(down, calc(1rem * pow(var(--font-heading-typescale), 2)), 1px);--font-scale-h4:round(down, calc(1rem * pow(var(--font-heading-typescale), 3)), 1px);--font-scale-h3:round(down, calc(1rem * pow(var(--font-heading-typescale), 4)), 1px);--font-scale-h2:round(down, calc(1rem * pow(var(--font-heading-typescale), 5)), 1px);--font-scale-h1:round(down, calc(1rem * pow(var(--font-heading-typescale), 6)), 1px);--font-scale-display:round(down, calc(1rem * pow(var(--font-heading-typescale), 8)), 1px)}}@layer viraui.preflight{html{--scrollbar-thumb:oklab(from var(--global-contrast) l a b / 0.3);--scrollbar-track:#0000;--outline-offset:2px;--outline-color:var(--global-outline);--outline:2px solid var(--outline-color);--is-light-mode:contrast-color(var(--global-background));font-size:var(--font-root-size);box-sizing:border-box;line-height:1.5;background-color:var(--global-background);color:var(--global-foreground);container:root/normal;scroll-behavior:smooth;@media (prefers-reduced-motion:reduce){scroll-behavior:auto}}*,:after,:before{margin:0;box-sizing:inherit;scrollbar-width:thin;scrollbar-color:var(--scrollbar-thumb) var(--scrollbar-track);@container root not style(--effect-corner-shape: initial){corner-shape:var(--__corner-shape,var(--corner-shape))}@media (prefers-reduced-motion:reduce){animation:none!important;transition:none!important}}::-webkit-scrollbar-track{background-color:var(--scrollbar-track)}:focus-visible{outline:var(--outline);outline-offset:var(--outline-offset)}body{color:var(--global-foreground);margin:0;font-size:var(--font-scale-body-m);font-optical-sizing:auto;font-family:var(--font-family-body),system-ui,sans-serif;font-variation-settings:"wght" 400;font-variant-numeric:tabular-nums;@container root not style(--effect-holofoil: initial){&:after{content:"";position:fixed;inset:0;z-index:999;background-color:#99ffd8;pointer-events:none;mix-blend-mode:multiply;contain:strict;isolation:isolate;opacity:25%;background-image:radial-gradient(at 79% 56%,#70ade6 0,#0000 50%),radial-gradient(at 61% 80%,#ee909e 0,#0000 50%),radial-gradient(at 0 63%,#fdbc68 0,#0000 50%),radial-gradient(at 6% 50%,#e5cb8a 0,#0000 50%),radial-gradient(at 23% 10%,#e5db8f 0,#0000 50%),radial-gradient(at 36% 91%,#a0eea8 0,#0000 50%),radial-gradient(at 2% 80%,#e3a47d 0,#0000 50%);@container root style(--is-light-mode: white){mix-blend-mode:color;opacity:15%}}}}::selection{background-color:var(--global-primary);color:contrast-color(var(--global-primary));text-shadow:none}img{display:block;inline-size:100%;max-inline-size:100%}svg{display:inline-flex;vertical-align:middle;&:not([fill]){fill:currentcolor}}ol ul,ul ol{font-size:medium}table{border-spacing:0;inline-size:100%;border-collapse:collapse}table[data-layout-fixed]{table-layout:fixed}table thead{box-shadow:inset 0 -3px 0 var(--base-2)}table[data-table-separators] tr+tr{border-top:1px solid var(--base-2)}table th{white-space:nowrap;font-variation-settings:"wght" 800}table :is(td,th){border:none;text-align:left;font-size:medium;padding:calc(var(--space-xs) + var(--space-2xs)) var(--space-s)}button,fieldset{padding:0;margin:0;border:0}button{appearance:none;background:none;font-size:inherit;font-family:inherit;display:inline-flex;cursor:pointer;color:inherit}}@layer viraui.preflight{@container root not style(--effect-shadows: initial){[data-elevation]{--shadow-direction:1;--shadow-opacity-factor:0.16;--extra-shadow:0 0 0 1px #0000;--shadow-color:oklch(0% 0 0);transition-property:box-shadow;transition-duration:var(--elevation-transition-duration,.16s);transition-timing-function:var(--elevation-transition-easing,ease)}[data-elevation]:where([data-elevation-direction=bottom],[data-elevation-direction=right]){--shadow-direction:1}[data-elevation]:where([data-elevation-direction=top],[data-elevation-direction=left]){--shadow-direction:-1}[data-elevation-hover="0"]:hover,[data-elevation="0"]{--y1:0px;--x1:0px;box-shadow:calc(var(--x1) * var(--shadow-direction)) calc(var(--y1) * var(--shadow-direction)) 0 oklch(from var(--shadow-color) l c h/var(--shadow-opacity-factor)),0 0 0 color-mix(in oklch,var(--shadow-color),#0000 calc(94% - var(--shadow-opacity-factor))),0 0 0 oklch(from var(--shadow-color) l c h/var(--shadow-opacity-factor)),var(--extra-shadow)}[data-elevation-hover="1"]:hover,[data-elevation-hover="2"]:hover,[data-elevation-hover="3"]:hover,[data-elevation-hover="4"]:hover,[data-elevation="1"],[data-elevation="2"],[data-elevation="3"],[data-elevation="4"]{box-shadow:calc(var(--x1) * var(--shadow-direction)) calc(var(--y1) * var(--shadow-direction)) var(--shadow-blur-1) oklab(from var(--shadow-color) l a b/.1),calc(var(--x2) * var(--shadow-direction)) calc(var(--y2) * var(--shadow-direction)) var(--shadow-blur-2) oklab(from var(--shadow-color) l a b/.08),calc(var(--x3) * var(--shadow-direction)) calc(var(--y3) * var(--shadow-direction)) var(--shadow-blur-3) oklab(from var(--shadow-color) l a b/.06),calc(var(--x4) * var(--shadow-direction)) calc(var(--y4) * var(--shadow-direction)) var(--shadow-blur-4) oklab(from var(--shadow-color) l a b/.04),calc(var(--x5) * var(--shadow-direction)) calc(var(--y5) * var(--shadow-direction)) var(--shadow-blur-5) oklab(from var(--shadow-color) l a b/.02),var(--extra-shadow)}[data-elevation-hover="1"]:hover,[data-elevation="1"]{--y1:0px;--y2:1px;--y3:1px;--y4:3px;--y5:4px;--x1:0px;--x2:0px;--x3:0px;--x4:0px;--x5:0px;--shadow-blur-1:0px;--shadow-blur-2:1px;--shadow-blur-3:1px;--shadow-blur-4:3px;--shadow-blur-5:4px}[data-elevation-hover="1"]:where([data-elevation-direction=left],[data-elevation-direction=right]):hover,[data-elevation="1"]:where([data-elevation-direction=left],[data-elevation-direction=right]){--y1:0px;--y2:0px;--y3:0px;--y4:0px;--y5:0px;--x1:0px;--x2:1px;--x3:1px;--x4:3px;--x5:4px}[data-elevation-hover="2"]:hover,[data-elevation="2"]{--y1:0px;--y2:1px;--y3:3px;--y4:5px;--y5:8px;--x1:0px;--x2:0px;--x3:0px;--x4:0px;--x5:0px;--shadow-blur-1:0px;--shadow-blur-2:1px;--shadow-blur-3:3px;--shadow-blur-4:5px;--shadow-blur-5:8px}[data-elevation-hover="2"]:where([data-elevation-direction=left],[data-elevation-direction=right]):hover,[data-elevation="2"]:where([data-elevation-direction=left],[data-elevation-direction=right]){--y1:0px;--y2:0px;--y3:0px;--y4:0px;--y5:0px;--x1:0px;--x2:1px;--x3:3px;--x4:5px;--x5:8px}[data-elevation-hover="3"]:hover,[data-elevation="3"]{--y1:1px;--y2:3px;--y3:6px;--y4:10px;--y5:16px;--x1:0px;--x2:0px;--x3:0px;--x4:0px;--x5:0px;--shadow-blur-1:1px;--shadow-blur-2:3px;--shadow-blur-3:6px;--shadow-blur-4:10px;--shadow-blur-5:16px}[data-elevation-hover="3"]:where([data-elevation-direction=left],[data-elevation-direction=right]):hover,[data-elevation="3"]:where([data-elevation-direction=left],[data-elevation-direction=right]){--y1:0px;--y2:0px;--y3:0px;--y4:0px;--y5:0px;--x1:1px;--x2:3px;--x3:6px;--x4:10px;--x5:16px}[data-elevation-hover="4"]:hover,[data-elevation="4"]{--y1:1px;--y2:5px;--y3:12px;--y4:20px;--y5:32px;--x1:0px;--x2:0px;--x3:0px;--x4:0px;--x5:0px;--shadow-blur-1:1px;--shadow-blur-2:5px;--shadow-blur-3:12px;--shadow-blur-4:20px;--shadow-blur-5:32px}[data-elevation-hover="4"]:where([data-elevation-direction=left],[data-elevation-direction=right]):hover,[data-elevation="4"]:where([data-elevation-direction=left],[data-elevation-direction=right]){--y1:0px;--y2:0px;--y3:0px;--y4:0px;--y5:0px;--x1:1px;--x2:5px;--x3:12px;--x4:20px;--x5:32px}}}@layer viraui.preflight{[data-grow=true]{--vira-flex-grow:1;flex-grow:1}[data-grow=false]{--vira-flex-grow:0;flex-grow:0}[data-shrink=true]{--vira-flex-shrink:1;flex-shrink:1}[data-shrink=false]{--vira-flex-shrink:0;flex-shrink:0}}@layer viraui.preflight{:where(p){line-height:1.5;min-block-size:.01vh;font-size:var(--font-scale-body-m)}small{font-size:.7em}b,strong{font-variation-settings:"wght" 700}:where(a:any-link):not([data-no-link-style]){text-decoration:none;color:var(--global-interactive-text);word-break:break-word;background:linear-gradient(currentcolor,currentcolor) no-repeat 0 100%;background-size:0 1px;transition:background-size var(--duration-fast) var(--easing-entrance);&:focus,&:hover{background-size:100% 1px}}del{padding:0 .4em;margin:0 .2em;background-color:oklab(from var(--highlight-red) l a b/12%);color:var(--highlight-red);box-shadow:0 0 0 1px oklab(from var(--highlight-red) l a b/50%);border-radius:var(--radius-s)}ins{background-color:oklab(from var(--highlight-green) l a b/15%);color:var(--highlight-green);box-shadow:0 0 0 1px oklab(from var(--highlight-green) l a b/50%)}ins,mark{padding:0 .4em;margin:0 .2em;text-decoration:none;border-radius:var(--radius-s)}mark{background-color:oklab(from var(--highlight-yellow) l a b/15%);color:var(--highlight-yellow);box-shadow:0 0 0 1px oklab(from var(--highlight-yellow) l a b/50%)}address{font-style:normal;line-height:inherit}dt{font-variation-settings:"wght" 600}dd{margin:0;padding:0}ul{font-size:medium;padding-left:1rem;& li::marker{font-size:inherit;text-align:right;font-variation-settings:"wght" 400;min-inline-size:var(--space-xl);color:oklab(from currentColor l a b/80%)}}ol{font-size:medium;& li::marker{font-size:inherit;font-variation-settings:"wght" 400;min-inline-size:var(--space-xl);font-variant-numeric:tabular-nums;white-space:nowrap;color:oklab(from currentColor l a b/80%)}}kbd{padding:.2em .4em;border-radius:var(--radius-s);font-variation-settings:"wght" 600;box-shadow:var(--global-contrast);background:var(--global-contrast)}abbr{text-decoration:underline dashed var(--global-primary)}label,legend{font-size:inherit}code{font-size:1em;font-family:var(--font-family-mono);&:not(:where(pre &)){background-color:var(--global-contrast);border-radius:var(--radius-s);box-shadow:var(--global-contrast);padding:.2em .4em}}pre code{box-shadow:none}s{text-decoration:line-through;color:var(--global-disabled-foreground);text-decoration-color:oklab(from var(--global-foreground) l a b/50%)}:root{color-scheme:light dark}[data-mode=dark]{--is-light-mode:#fff;color:var(--global-foreground);color-scheme:dark}[data-mode=light]{--is-light-mode:#000;color:var(--global-foreground);color-scheme:light}}@layer viraui.preflight{[data-mode=inverted]{color:var(--global-foreground);@container root style(--is-light-mode: black){color-scheme:dark}@container root style(--is-light-mode: white){color-scheme:light}}}@layer viraui.preflight{@container root not style(--effect-vibrancy: initial){[data-vibrant]{backdrop-filter:brightness(var(--vibrancy-brightness)) blur(calc(var(--vibrancy-blur) * 1px)) saturate(150%);@container root style(--is-light-mode: black){backdrop-filter:brightness(100%) blur(calc(var(--vibrancy-blur) * 1px)) saturate(150%)}}}}
4
+ );--font-scale-body-l:round(down, calc(1rem * pow(var(--font-body-typescale), 1)), 1px);--font-scale-body-xl:round(down, calc(1rem * pow(var(--font-body-typescale), 2)), 1px);--font-scale-body-2xl:round(down, calc(1rem * pow(var(--font-body-typescale), 3)), 1px);--font-scale-body-3xl:round(down, calc(1rem * pow(var(--font-body-typescale), 4)), 1px);--font-scale-body-4xl:round(down, calc(1rem * pow(var(--font-body-typescale), 5)), 1px);--font-scale-h6:round(down, calc(1rem * pow(var(--font-heading-typescale), 1)), 1px);--font-scale-h5:round(down, calc(1rem * pow(var(--font-heading-typescale), 2)), 1px);--font-scale-h4:round(down, calc(1rem * pow(var(--font-heading-typescale), 3)), 1px);--font-scale-h3:round(down, calc(1rem * pow(var(--font-heading-typescale), 4)), 1px);--font-scale-h2:round(down, calc(1rem * pow(var(--font-heading-typescale), 5)), 1px);--font-scale-h1:round(down, calc(1rem * pow(var(--font-heading-typescale), 6)), 1px);--font-scale-display:round(down, calc(1rem * pow(var(--font-heading-typescale), 8)), 1px)}}@layer viraui.preflight{html{--scrollbar-thumb:oklab(from var(--global-contrast) l a b / 0.3);--scrollbar-track:#0000;--outline-offset:2px;--outline-color:var(--global-outline);--outline:2px solid var(--outline-color);--is-light-mode:contrast-color(var(--global-background));font-size:var(--font-root-size);box-sizing:border-box;line-height:1.5;background-color:var(--global-background);color:var(--global-foreground);container:root/normal;scroll-behavior:smooth;@media (prefers-reduced-motion:reduce){scroll-behavior:auto}}*,:after,:before{margin:0;box-sizing:inherit;scrollbar-width:thin;scrollbar-color:var(--scrollbar-thumb) var(--scrollbar-track);@container root not style(--effect-corner-shape: initial){corner-shape:var(--__corner-shape,var(--corner-shape))}@media (prefers-reduced-motion:reduce){animation:none!important;transition:none!important}}::-webkit-scrollbar-track{background-color:var(--scrollbar-track)}:focus-visible{outline:var(--outline);outline-offset:var(--outline-offset)}body{color:var(--global-foreground);margin:0;font-size:var(--font-scale-body-m);font-optical-sizing:auto;font-family:var(--font-family-body),system-ui,sans-serif;font-variation-settings:"wght" 400;font-variant-numeric:tabular-nums;@container root not style(--effect-holofoil: initial){&:after{content:"";position:fixed;inset:0;z-index:999;background-color:#99ffd8;pointer-events:none;mix-blend-mode:multiply;contain:strict;isolation:isolate;opacity:25%;background-image:radial-gradient(at 79% 56%,#70ade6 0,#0000 50%),radial-gradient(at 61% 80%,#ee909e 0,#0000 50%),radial-gradient(at 0 63%,#fdbc68 0,#0000 50%),radial-gradient(at 6% 50%,#e5cb8a 0,#0000 50%),radial-gradient(at 23% 10%,#e5db8f 0,#0000 50%),radial-gradient(at 36% 91%,#a0eea8 0,#0000 50%),radial-gradient(at 2% 80%,#e3a47d 0,#0000 50%);@container root style(--is-light-mode: white){mix-blend-mode:color;opacity:15%}}}}::selection{background-color:var(--global-primary);color:contrast-color(var(--global-primary));text-shadow:none}img{display:block;inline-size:100%;max-inline-size:100%}svg{display:inline-flex;vertical-align:middle;&:not([fill]){fill:currentcolor}}ol ul,ul ol{font-size:medium}table{border-spacing:0;inline-size:100%;border-collapse:collapse}table[data-layout-fixed]{table-layout:fixed}table thead{box-shadow:inset 0 -3px 0 var(--base-2)}table[data-table-separators] tr+tr{border-top:1px solid var(--base-2)}table th{white-space:nowrap;font-variation-settings:"wght" 800}table :is(td,th){border:none;text-align:left;font-size:medium;padding:calc(var(--space-xs) + var(--space-2xs)) var(--space-s)}button,fieldset{padding:0;margin:0;border:0}button{appearance:none;background:none;font-size:inherit;font-family:inherit;display:inline-flex;cursor:pointer;color:inherit}}@layer viraui.preflight{@container root not style(--effect-shadows: initial){[data-elevation]{--shadow-direction:1;--shadow-opacity-factor:0.16;--extra-shadow:0 0 0 1px #0000;--shadow-color:oklch(0% 0 0);transition-property:box-shadow;transition-duration:var(--elevation-transition-duration,.16s);transition-timing-function:var(--elevation-transition-easing,ease)}[data-elevation]:where([data-elevation-direction=bottom],[data-elevation-direction=right]){--shadow-direction:1}[data-elevation]:where([data-elevation-direction=top],[data-elevation-direction=left]){--shadow-direction:-1}[data-elevation-hover="0"]:hover,[data-elevation="0"]{--y1:0px;--x1:0px;box-shadow:calc(var(--x1) * var(--shadow-direction)) calc(var(--y1) * var(--shadow-direction)) 0 oklch(from var(--shadow-color) l c h/var(--shadow-opacity-factor)),0 0 0 color-mix(in oklch,var(--shadow-color),#0000 calc(94% - var(--shadow-opacity-factor))),0 0 0 oklch(from var(--shadow-color) l c h/var(--shadow-opacity-factor)),var(--extra-shadow)}[data-elevation-hover="1"]:hover,[data-elevation-hover="2"]:hover,[data-elevation-hover="3"]:hover,[data-elevation-hover="4"]:hover,[data-elevation="1"],[data-elevation="2"],[data-elevation="3"],[data-elevation="4"]{box-shadow:calc(var(--x1) * var(--shadow-direction)) calc(var(--y1) * var(--shadow-direction)) var(--shadow-blur-1) oklab(from var(--shadow-color) l a b/.1),calc(var(--x2) * var(--shadow-direction)) calc(var(--y2) * var(--shadow-direction)) var(--shadow-blur-2) oklab(from var(--shadow-color) l a b/.08),calc(var(--x3) * var(--shadow-direction)) calc(var(--y3) * var(--shadow-direction)) var(--shadow-blur-3) oklab(from var(--shadow-color) l a b/.06),calc(var(--x4) * var(--shadow-direction)) calc(var(--y4) * var(--shadow-direction)) var(--shadow-blur-4) oklab(from var(--shadow-color) l a b/.04),calc(var(--x5) * var(--shadow-direction)) calc(var(--y5) * var(--shadow-direction)) var(--shadow-blur-5) oklab(from var(--shadow-color) l a b/.02),var(--extra-shadow)}[data-elevation-hover="1"]:hover,[data-elevation="1"]{--y1:0px;--y2:1px;--y3:1px;--y4:3px;--y5:4px;--x1:0px;--x2:0px;--x3:0px;--x4:0px;--x5:0px;--shadow-blur-1:0px;--shadow-blur-2:1px;--shadow-blur-3:1px;--shadow-blur-4:3px;--shadow-blur-5:4px}[data-elevation-hover="1"]:where([data-elevation-direction=left],[data-elevation-direction=right]):hover,[data-elevation="1"]:where([data-elevation-direction=left],[data-elevation-direction=right]){--y1:0px;--y2:0px;--y3:0px;--y4:0px;--y5:0px;--x1:0px;--x2:1px;--x3:1px;--x4:3px;--x5:4px}[data-elevation-hover="2"]:hover,[data-elevation="2"]{--y1:0px;--y2:1px;--y3:3px;--y4:5px;--y5:8px;--x1:0px;--x2:0px;--x3:0px;--x4:0px;--x5:0px;--shadow-blur-1:0px;--shadow-blur-2:1px;--shadow-blur-3:3px;--shadow-blur-4:5px;--shadow-blur-5:8px}[data-elevation-hover="2"]:where([data-elevation-direction=left],[data-elevation-direction=right]):hover,[data-elevation="2"]:where([data-elevation-direction=left],[data-elevation-direction=right]){--y1:0px;--y2:0px;--y3:0px;--y4:0px;--y5:0px;--x1:0px;--x2:1px;--x3:3px;--x4:5px;--x5:8px}[data-elevation-hover="3"]:hover,[data-elevation="3"]{--y1:1px;--y2:3px;--y3:6px;--y4:10px;--y5:16px;--x1:0px;--x2:0px;--x3:0px;--x4:0px;--x5:0px;--shadow-blur-1:1px;--shadow-blur-2:3px;--shadow-blur-3:6px;--shadow-blur-4:10px;--shadow-blur-5:16px}[data-elevation-hover="3"]:where([data-elevation-direction=left],[data-elevation-direction=right]):hover,[data-elevation="3"]:where([data-elevation-direction=left],[data-elevation-direction=right]){--y1:0px;--y2:0px;--y3:0px;--y4:0px;--y5:0px;--x1:1px;--x2:3px;--x3:6px;--x4:10px;--x5:16px}[data-elevation-hover="4"]:hover,[data-elevation="4"]{--y1:1px;--y2:5px;--y3:12px;--y4:20px;--y5:32px;--x1:0px;--x2:0px;--x3:0px;--x4:0px;--x5:0px;--shadow-blur-1:1px;--shadow-blur-2:5px;--shadow-blur-3:12px;--shadow-blur-4:20px;--shadow-blur-5:32px}[data-elevation-hover="4"]:where([data-elevation-direction=left],[data-elevation-direction=right]):hover,[data-elevation="4"]:where([data-elevation-direction=left],[data-elevation-direction=right]){--y1:0px;--y2:0px;--y3:0px;--y4:0px;--y5:0px;--x1:1px;--x2:5px;--x3:12px;--x4:20px;--x5:32px}}}@layer viraui.preflight{[data-grow=true]{--vira-flex-grow:1;flex-grow:1}[data-grow=false]{--vira-flex-grow:0;flex-grow:0}[data-shrink=true]{--vira-flex-shrink:1;flex-shrink:1}[data-shrink=false]{--vira-flex-shrink:0;flex-shrink:0}}@layer viraui.preflight{:where(p){line-height:1.5;min-block-size:.01vh;font-size:var(--font-scale-body-m)}small{font-size:.7em}b,strong{font-variation-settings:"wght" 700}:where(a:any-link):not([data-no-link-style]){text-decoration:none;color:var(--global-interactive-text);word-break:break-word;background:linear-gradient(currentcolor,currentcolor) no-repeat 0 100%;background-size:0 1px;transition:background-size var(--duration-fast) var(--easing-entrance);&:focus,&:hover{background-size:100% 1px}}del{padding:0 .4em;margin:0 .2em;background-color:oklab(from var(--highlight-red) l a b/12%);color:var(--highlight-red);box-shadow:0 0 0 1px oklab(from var(--highlight-red) l a b/50%);border-radius:var(--radius-s)}ins{background-color:oklab(from var(--highlight-green) l a b/15%);color:var(--highlight-green);box-shadow:0 0 0 1px oklab(from var(--highlight-green) l a b/50%)}ins,mark{padding:0 .4em;margin:0 .2em;text-decoration:none;border-radius:var(--radius-s)}mark{background-color:oklab(from var(--highlight-yellow) l a b/15%);color:var(--highlight-yellow);box-shadow:0 0 0 1px oklab(from var(--highlight-yellow) l a b/50%)}address{font-style:normal;line-height:inherit}dt{font-variation-settings:"wght" 600}dd{margin:0;padding:0}ul{font-size:medium;padding-left:1rem;& li::marker{font-size:inherit;text-align:right;font-variation-settings:"wght" 400;min-inline-size:var(--space-xl);color:oklab(from currentColor l a b/80%)}}ol{font-size:medium;& li::marker{font-size:inherit;font-variation-settings:"wght" 400;min-inline-size:var(--space-xl);font-variant-numeric:tabular-nums;white-space:nowrap;color:oklab(from currentColor l a b/80%)}}kbd{padding:.2em .4em;border-radius:var(--radius-s);font-variation-settings:"wght" 600;box-shadow:var(--global-contrast);background:var(--global-contrast)}abbr{text-decoration:underline dashed var(--global-primary)}label,legend{font-size:inherit}code{font-size:1em;font-family:var(--font-family-mono);&:not(:where(pre &)){background-color:var(--global-contrast);border-radius:var(--radius-s);box-shadow:var(--global-contrast);padding:.2em .4em}}pre code{box-shadow:none}s{text-decoration:line-through;color:var(--global-disabled-foreground);text-decoration-color:oklab(from var(--global-foreground) l a b/50%)}:root{color-scheme:light dark}[data-mode=dark]{--is-light-mode:#fff;color:var(--global-foreground);color-scheme:dark}[data-mode=light]{--is-light-mode:#000;color:var(--global-foreground);color-scheme:light}}@layer viraui.preflight{[data-mode=inverted]{color:var(--global-foreground);@container root style(--is-light-mode: black){color-scheme:dark}@container root style(--is-light-mode: white){color-scheme:light}}}@layer viraui.preflight{@container root not style(--effect-vibrancy: initial){[data-vibrant=true]{backdrop-filter:blur(calc(var(--vibrancy-blur) * 1px)) saturate(150%)}}}
@@ -44,7 +44,7 @@ Prefer opening via package export / that `dist/specs/` tree. The `version` attri
44
44
  Consumer agents build screens **with** ViraUI — public parts, compounds, and props from the units — not **around** it with immediate CSS overrides.
45
45
 
46
46
  1. Index → activity load → open `meta` / `props` / `usage` for every Vira surface you touch **before** JSX that invents classNames or a CSS module targeting those roots.
47
- 2. Prefer another Vira part or public prop over custom CSS (layout → `Stack`/`Grid`/`Masonry`/`Bleed`/`Surface`; fill → `fullWidth` / `expandChildren`; one-sided inset → `hPadding`/`vPadding` `[start, end]` tuples — not `paddingBlock*`/`paddingInline*` style; type → `Text`/`Title` props; chrome → `Surface` / `Elevator`).
47
+ 2. Prefer another Vira part or public prop over custom CSS (layout → `Stack`/`Grid`/`Masonry`/`Bleed`/`Surface`; fill → `fullWidth` / `fullHeight` / `expandChildren` + stretch align — open Stack `patterns.xml` / `usage` when children must fill both axes; never invent `width`/`height: 100%` CSS; one-sided inset → `hPadding`/`vPadding` `[start, end]` tuples — not `paddingBlock*`/`paddingInline*` style; type → `Text`/`Title` props; chrome → `Surface` / `Elevator` or Stack `render={&lt;Surface /&gt;}`).
48
48
  3. **Omit `render` when it restates the component’s default root.** Confirm the default in that surface’s `props`/`usage` (e.g. Stack → `div`). Do **not** write `render={<div />}` on Stack, or any other `render={<SameDefault />}` noop. Use `render` only to change the host (semantic tag, `Surface`, another component).
49
49
  4. Custom CSS defaults to **app chrome the system does not own** (page backdrop image, document scrollport, one-off marketing layout). It is **not** a license to reshape Vira control geometry, reinvent owned props, or “fix” controls that already look correct under theme + preflight — **unless the consumer expressly requests** that override / personalization. A future override layer will own formal customization hooks; until then, still open `props`/`usage` first and apply only the asked CSS.
50
50
  5. If `usage.xml` lists a **dont** against the CSS you are about to write and the consumer did **not** expressly override that guidance — stop. Do not ship it.
@@ -56,15 +56,15 @@
56
56
  <load>
57
57
  <step open="index.xml" note="category=pattern + stack/surface/grid/masonry/bleed" />
58
58
  <step open="patterns/compose-layout-first.xml" />
59
- <step open="patterns/stack-as-surface.xml" when="border/fill/radius on a flex cluster" />
60
- <step open="patterns/page-chrome.xml" when="page shell / semantic tags" />
61
- <step open="patterns/equal-width-actions.xml" when="full-bleed or equal action rows" />
62
59
  <step open="patterns/card-grid.xml" when="CSS grid tracks / card walls" />
63
60
  <step open="patterns/settings-panel.xml" when="settings / form panels" />
61
+ <step open="patterns/settings-row.xml" when="label + control settings rows" />
62
+ <step open="components/stack/patterns.xml" when="Stack-owned: Surface render, page chrome, equal-width actions, both-axes fill / height 100% temptation" />
64
63
  <step unit="usage" note="confirm stack/surface/grid (etc.) do/dont after pattern" />
65
- <step unit="props" note="verify spacing / render / fullWidth names" />
64
+ <step unit="props" note="verify spacing / render / fullWidth / fullHeight / expandChildren names" />
66
65
  </load>
67
66
  <forbid>Inventing display:flex / display:grid / CSS gap/padding/paddingBlock*/paddingInline*/border chrome when Stack, Grid, Masonry, Bleed, or Surface cover it — one-sided inset → hPadding/vPadding [start, end] tuples</forbid>
67
+ <forbid>Inventing width/height / inline-size/block-size:100% / w-full on Stack or children when fullWidth / fullHeight / expandChildren + hAlign/vAlign=&quot;stretch&quot; cover both-axis fill (open stack patterns + usage)</forbid>
68
68
  <forbid>Passing render={&lt;div /&gt;} (or any render that matches the component default root) — omit render; use it only for a different host</forbid>
69
69
  </activity>
70
70
  </activity_hints>
@@ -4,10 +4,10 @@
4
4
  <do>Edge scrim on glass / `data-vibrant` Surface heroes, sheets, or scroll regions where content should fade into blur</do>
5
5
  <do>Keep semantics and layout on Surface/Stack/Title/Text children underneath — ProgressiveBlur is decorative atmosphere only</do>
6
6
  <do>Use sparingly — stacked `backdrop-filter` is GPU/memory-heavy; prefer one focal overlay per view</do>
7
- <do>Rounded scroll shells: clip with Surface `overflow` + `radius`, mount ProgressiveBlur as a sibling overlay, set matching `border-radius` on the blur root (layers inherit)</do>
7
+ <do>Match a rounded Surface by setting `border-radius` on the ProgressiveBlur root — layers inherit it</do>
8
8
  <dont>Leaving the ProgressiveBlur root `position: static` so absolute layers escape the intended overlay box</dont>
9
9
  <dont>Driving layout size or scroll behavior from inside the overlay</dont>
10
10
  <dont>Scattering ProgressiveBlur across many cards or stacking full-viewport instances</dont>
11
11
  <dont>Using ProgressiveBlur as standalone loading or status feedback without a labeled parent region</dont>
12
- <dont>Nesting under an ancestor that pairs overflow clipping with border-radius (e.g. Surface `overflow="hidden"` + `radius`) — Chromium drops masked backdrop-filter</dont>
12
+ <dont>Nesting under an ancestor that pairs overflow clipping with border-radius (e.g. Surface `overflow="hidden"` + `radius`) — Chromium drops masked backdrop-filter; leave Surface overflow alone and scroll on an inner node</dont>
13
13
  </usage>
@@ -1,6 +1,71 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <patterns surface="stack">
3
3
  <!-- Sources: viraui-app/components — cleaned (no handlers, no app-only chrome, no CSS that reinvents Stack props). -->
4
+ <!-- Stack-owned recipes live HERE (local patterns unit). Core `specs/patterns/*` = true multi-surface screen recipes only. -->
5
+
6
+ <example title="Stack as Surface (one DOM node)">
7
+ <tsx><![CDATA[
8
+ {/* Preferred: layout + chrome share one root */}
9
+ <Stack
10
+ direction="row"
11
+ columnGap="s"
12
+ vAlign="center"
13
+ fullWidth
14
+ render={<Surface border="all" color={1} radius="m" hPadding="m" vPadding="s" />}
15
+ >
16
+ <Text size="sm" color="muted">
17
+ Status
18
+ </Text>
19
+ <Chip>Active</Chip>
20
+ </Stack>
21
+ ]]></tsx>
22
+ <notes>Gap/align/`fullWidth`/`expandChildren` on Stack; `border`/`color`/`radius`/padding on Surface in `render`. Nest Surface→Stack only when separate roots are required (Elevator, concentric Surfaces). Never invent border/radius CSS on Stack.</notes>
23
+ </example>
24
+
25
+ <example title="Equal-width action row">
26
+ <tsx><![CDATA[
27
+ {/* Full-bleed column CTAs */}
28
+ <Stack fullWidth rowGap="s">
29
+ <Button>Continue</Button>
30
+ <Button variant="secondary">Cancel</Button>
31
+ </Stack>
32
+
33
+ {/* Equal-width row actions — children grow on the main axis. Add fullWidth when this Stack must fill parent width */}
34
+ <Stack expandChildren direction="row" columnGap="s">
35
+ <Button>Continue</Button>
36
+ <Button variant="secondary">Cancel</Button>
37
+ </Stack>
38
+ ]]></tsx>
39
+ <notes>`fullWidth` sizes this Stack; `expandChildren` grows children on the main axis. Never invent `width: 100%` / `flex: 1` CSS on Button. Both-axes fill → examples below (not height CSS).</notes>
40
+ </example>
41
+
42
+ <example title="Page chrome (semantic hosts)">
43
+ <tsx><![CDATA[
44
+ <Stack rowGap="m" expandChildren>
45
+ <Stack
46
+ direction="row"
47
+ hAlign="space-between"
48
+ vAlign="center"
49
+ columnGap="m"
50
+ hPadding="m"
51
+ vPadding="m"
52
+ render={<header />}
53
+ >
54
+ <Title render={<h1 />}>Settings</Title>
55
+ <Button>Save</Button>
56
+ </Stack>
57
+ <Stack direction="row" columnGap="m" expandChildren render={<main />}>
58
+ <Stack rowGap="xs" hPadding="s" vPadding="s" render={<nav aria-label="Settings" />}>
59
+ {/* nav links */}
60
+ </Stack>
61
+ <Stack rowGap="l" expandChildren>
62
+ {/* content */}
63
+ </Stack>
64
+ </Stack>
65
+ </Stack>
66
+ ]]></tsx>
67
+ <notes>Semantic tags via `render` — Stack stays the layout engine. CSS may set `min-block-size` / scroll; never `display:flex`. Omit `render={&lt;div /&gt;}` (default host).</notes>
68
+ </example>
4
69
 
5
70
  <example title="App header (hub)">
6
71
  <tsx><![CDATA[
@@ -360,4 +425,37 @@
360
425
  ]]></tsx>
361
426
  <notes>From `editor/preview-grid/blocks/shipping-address`. `expandChildren` on row Stacks shares width across field pairs — do not invent per-field `flex`/`width` CSS.</notes>
362
427
  </example>
428
+
429
+ <example title="Row panels fill both axes">
430
+ <tsx><![CDATA[
431
+ {/* Parent must be sized (viewport shell, fullHeight ancestor, …). No height CSS on Stack/children. */}
432
+ <Stack direction="row" columnGap="s" expandChildren fullHeight vAlign="stretch">
433
+ <Stack rowGap="s" hPadding="m" vPadding="m">
434
+ {/* sidebar / panel A */}
435
+ </Stack>
436
+ <Stack rowGap="m" hPadding="m" vPadding="m" expandChildren>
437
+ {/* main / panel B */}
438
+ </Stack>
439
+ </Stack>
440
+ ]]></tsx>
441
+ <notes>Canonical horizontal both-axes fill (Stack-owned). Main = `expandChildren`; cross = `vAlign=&quot;stretch&quot;`; root block size = `fullHeight`. Never `style`/`className` height on Stack or children.</notes>
442
+ </example>
443
+
444
+ <example title="Column sections fill both axes">
445
+ <tsx><![CDATA[
446
+ {/* Parent must be sized. Children share height + fill width — props only. */}
447
+ <Stack rowGap="s" expandChildren fullWidth fullHeight hAlign="stretch">
448
+ <Stack direction="row" columnGap="m" vAlign="center" hPadding="m" vPadding="s">
449
+ {/* header strip */}
450
+ </Stack>
451
+ <Stack rowGap="m" hPadding="m" vPadding="m" expandChildren>
452
+ {/* grow body */}
453
+ </Stack>
454
+ <Stack direction="row" columnGap="s" hPadding="m" vPadding="s" data-grow="false">
455
+ {/* footer actions — opt out of main-axis grow */}
456
+ </Stack>
457
+ </Stack>
458
+ ]]></tsx>
459
+ <notes>Canonical vertical both-axes fill (Stack-owned). Main = `expandChildren`; cross = `hAlign=&quot;stretch&quot;`; root = `fullWidth` + `fullHeight`. Footer uses `data-grow=&quot;false&quot;` so only the body expands.</notes>
460
+ </example>
363
461
  </patterns>
@@ -8,12 +8,14 @@
8
8
  <item>Centered max-width shells: parent `hAlign=&quot;center&quot;` + child `fullWidth` + `maxWidth`</item>
9
9
  <item>Readable type columns: `maxWidth` in **`ch`** around Text/Title/Prose for ~10–12 words/line — width **tracks body `size`** (smaller → narrower; prefer `ch` over rem; never one fixed band for every size)</item>
10
10
  <item>Full-bleed or equal-width action clusters (Buttons, etc.): `fullWidth` and/or `expandChildren` instead of per-child width CSS</item>
11
+ <item>Children fill both axes in a sized parent — see this surface `patterns.xml`: row = `direction=&quot;row&quot;` + `expandChildren` + `fullHeight` + `vAlign=&quot;stretch&quot;`; column = `expandChildren` + `fullWidth` + `fullHeight` + `hAlign=&quot;stretch&quot;` — never invent `height`/`width` / `block-size`/`inline-size: 100%` CSS</item>
11
12
  </when_to_use>
12
13
  <when_not_to_use>
13
14
  <item>Cases where a single component already owns required flex chrome</item>
14
15
  <item>Expecting direct children to grow on the main axis without setting `expandChildren`</item>
15
16
  <item>Expecting this stack to fill parent inline size under non-stretch alignment without `fullWidth` (or an explicit `inlineSize`)</item>
16
- <item>Inventing `width: 100%` / `inline-size: 100%` / `w-full` / size-fill className on content-sized children (Button, Chip, …) when this Stack can own fill via `fullWidth` / `expandChildren` — or on fixed-size children (IconButton) where width CSS is useless</item>
17
+ <item>Expecting this stack to fill parent block size without `fullHeight` (or an explicit `blockSize`)</item>
18
+ <item>Inventing `width`/`height` / `inline-size`/`block-size: 100%` / `w-full` / size-fill className on this Stack or content-sized children when `fullWidth` / `fullHeight` / `expandChildren` + stretch align cover it (see `patterns.xml`) — or on fixed-size children (IconButton) where size CSS is useless</item>
17
19
  <item>Using `enableContainer` inside complex masonry-like layouts when you don&apos;t need container queries (inline-size containment can change nested layout)</item>
18
20
  </when_not_to_use>
19
21
  <prop name="columnGap" kind="react">
@@ -26,10 +28,13 @@
26
28
  <description>Renders children across rows or columns using the chosen flex direction.</description>
27
29
  </prop>
28
30
  <prop name="expandChildren" kind="react">
29
- <description>Makes direct children grow along the flex main axis (`flex-grow`). Default `false`. Use for equal-width row actions (Buttons, etc.) instead of inventing `width`/`flex` CSS on each child. Orthogonal to `fullWidth` (children grow vs this root&apos;s inline size). A child opts out with its own `data-grow=&quot;false&quot;`; ancestor `data-grow` does not inherit into nested stacks.</description>
31
+ <description>Makes direct children grow along the flex main axis (`flex-grow`). Default `false`. Use for equal-width row actions (Buttons, etc.) instead of inventing `width`/`flex` CSS on each child. Cross-axis fill stays on `hAlign` / `vAlign=&quot;stretch&quot;` (which prop is cross depends on `direction`). Orthogonal to `fullWidth` / `fullHeight` (children grow vs this root&apos;s size). A child opts out with its own `data-grow=&quot;false&quot;`; ancestor `data-grow` does not inherit into nested stacks.</description>
32
+ </prop>
33
+ <prop name="fullHeight" kind="react">
34
+ <description>Sets `block-size: 100%` on the stack root so it fills the parent&apos;s block size. Default `false`. Prefer this over `style`/`className` `height` / `block-size: 100%` on this Stack. Pair with `expandChildren` and cross-axis `hAlign`/`vAlign=&quot;stretch&quot;` so children fill both axes without per-child size CSS. Orthogonal to `expandChildren` and `fullWidth`.</description>
30
35
  </prop>
31
36
  <prop name="fullWidth" kind="react">
32
- <description>Sets `inline-size: 100%` on the stack root so it fills the parent&apos;s inline size. Default `false`. Prefer this (plus cross-axis stretch) so content-sized children like Button span a panel — do not add `width: 100%` CSS on those children. Use with `maxWidth` under a parent `hAlign=&quot;center&quot;` for a fluid capped centered shell. Does not grow children — use `expandChildren` for that.</description>
37
+ <description>Sets `inline-size: 100%` on the stack root so it fills the parent&apos;s inline size. Default `false`. Prefer this (plus cross-axis stretch) so content-sized children like Button span a panel — do not add `width: 100%` CSS on those children. Use with `maxWidth` under a parent `hAlign=&quot;center&quot;` for a fluid capped centered shell. Pair with `fullHeight` when the root must fill both parent axes. Does not grow children — use `expandChildren` for that.</description>
33
38
  </prop>
34
39
  <prop name="hAlign" kind="react">
35
40
  <description>Aligns content on the horizontal axis from the consumer point of view.</description>
@@ -2,8 +2,11 @@
2
2
  <usage surface="stack">
3
3
  <do>Default structural box instead of a bare wrapper `div` — Stack owns flex + token gap/padding/align/`fullWidth`/`render`</do>
4
4
  <do>Login/signup (or similar auth swap): host Tabs + Textfield(s) + Button (+ optional Fieldset) inside a Stack or `Stack render={&lt;Surface … /&gt;}` shell — props only, 0 custom CSS</do>
5
- <do>Flex + Surface chrome on one node via `render={&lt;Surface … /&gt;}` — prefer over a CSS border class or an extra wrapper (see package pattern `stack-as-surface`)</do>
6
- <do>Equal-width action or field clusters (Button, Chip, Textfield): `fullWidth` and/or `expandChildren` on this Stack — never per-child width CSS</do>
5
+ <do>Flex + Surface chrome on one node via `render={&lt;Surface … /&gt;}` — prefer over a CSS border class or an extra wrapper (see this surface `patterns.xml` — Stack as Surface)</do>
6
+ <do>Equal-width action or field clusters (Button, Chip, Textfield): `fullWidth` and/or `expandChildren` on this Stack — never per-child width CSS (see `patterns.xml`)</do>
7
+ <do>Children fill **both** axes inside a sized parent — this surface `patterns.xml` (never invent size-fill CSS):
8
+ row → `direction=&quot;row&quot;` + `expandChildren` + `fullHeight` + `vAlign=&quot;stretch&quot;` (share width + fill height);
9
+ column → `expandChildren` + `fullWidth` + `fullHeight` + `hAlign=&quot;stretch&quot;` (share height + fill width)</do>
7
10
  <do>Settings rows: Stack `direction=&quot;row&quot;` + Text (label/description column) + Switch or Checkbox — nest in Surface for panel chrome</do>
8
11
  <do>Centered capped shells: parent `hAlign=&quot;center&quot;` + child Stack `fullWidth` + `maxWidth`</do>
9
12
  <do>Readable type column: Stack `maxWidth` in **`ch`** around Text/Title/Prose sized for the dominant body `size` (~10–12 words/line; smaller → narrower) — prefer `ch` over rem; never one fixed ch for every size</do>
@@ -13,7 +16,7 @@
13
16
  <dont>Passing `render={&lt;div /&gt;}` (or any host that matches Stack&apos;s default root) — omit `render`; use it only for a different host (`header`, `Surface`, …)</dont>
14
17
  <dont>Assuming Stack expands direct children by default — pass `expandChildren` when children should grow on the flex main axis</dont>
15
18
  <dont>Using `expandChildren` to fill parent width under `hAlign=&quot;center&quot;` — that is `fullWidth` on the child Stack (self `inline-size`), not child flex-grow</dont>
16
- <dont>Inventing `width: 100%` / `inline-size: 100%` / `w-full` / `.fullWidth` / size-fill `className` on content-sized children when this Stack can own the fill — or when children are intentionally fixed-size (e.g. IconButton)</dont>
19
+ <dont>Inventing `width`/`height` / `inline-size`/`block-size: 100%` / `w-full` / size-fill `className` on this Stack or content-sized children when `fullWidth` / `fullHeight` / `expandChildren` + stretch align can own the fill — or when children are intentionally fixed-size (e.g. IconButton)</dont>
17
20
  <dont>Inventing CSS `gap` / `padding` / `paddingBlock*` / `paddingInline*` / side paddings (`style` or className) when public spacing props cover it — one-sided inset uses `hPadding`/`vPadding` `[start, end]` tuples (e.g. `vPadding={[0, &apos;l&apos;]}`), not `paddingBlockEnd: &apos;1rem&apos;`</dont>
18
21
  <dont>Putting `data-grow=&quot;false&quot;` on an ancestor to control nested `expandChildren` — set it on the child that should not grow</dont>
19
22
  <dont>Combining `fullWidth` with `inline` — prefer block flex when the root must fill parent inline size</dont>
@@ -2,7 +2,7 @@
2
2
  <usage surface="surface">
3
3
  <do>Group content with base-level background and contrast border — nest Stack for child gaps (Surface has no gap prop)</do>
4
4
  <do>Login/signup shell: Surface (or `Stack render={&lt;Surface … /&gt;}`) hosts Tabs + Textfield(s) + Button (+ optional Fieldset) — chrome + layout via props, 0 custom CSS</do>
5
- <do>Accept Stack as host via their `render={&lt;Surface … /&gt;}` so border/fill/radius share one DOM node — prefer over inventing chrome CSS (see package pattern `stack-as-surface`)</do>
5
+ <do>Accept Stack as host via their `render={&lt;Surface … /&gt;}` so border/fill/radius share one DOM node — prefer over inventing chrome CSS (see Stack `patterns.xml` — Stack as Surface)</do>
6
6
  <do>Settings / preferences panels: Surface card + Stack body + Switch/Checkbox rows (optionally padded inner Surfaces) + Button footer strip</do>
7
7
  <do>Frosted glass panels with `data-vibrant` — omit `color` for page-level shell or pass `color` for a tinted fill</do>
8
8
  <do>Compose with Elevator for animated elevation — Surface has no `elevation` prop</do>
@@ -138,9 +138,8 @@
138
138
  <attr name="data-vibrant">
139
139
  <presence>boolean attribute; value ignored</presence>
140
140
  <effect>
141
- When the active theme sets --effect-vibrancy, applies vibrancy backdrop-filter (brightness/blur/saturate). Surface with data-vibrant translucifies its fill via component CSS: it doesn't apply a background color to the element, that still need to be set by the consumer.
142
- Only the urface component applies the correct `color` prop based on the presence of the attribute. For custom styles you need to set the background color explicitly if you need one.
143
- In built-in themes, the applied backdrop-filter is different based on the active theme mode: light or dark.
141
+ When the active theme sets --effect-vibrancy, applies vibrancy backdrop-filter (blur/saturate). Surface with data-vibrant translucifies its fill via component CSS: it doesn't apply a background color to the element, that still need to be set by the consumer.
142
+ Only the Surface component applies the correct `color` prop based on the presence of the attribute. For custom styles you need to set the background color explicitly if you need one.
144
143
  </effect>
145
144
  <values>
146
145
  <value>(boolean presence)</value>
@@ -152,7 +151,6 @@
152
151
  <gotcha>Surface</gotcha>
153
152
  <gotcha>--effect-vibrancy</gotcha>
154
153
  <gotcha>--vibrancy-blur</gotcha>
155
- <gotcha>--vibrancy-brightness</gotcha>
156
154
  </attr>
157
155
  <attr name="data-layout-fixed">
158
156
  <presence>boolean attribute on table elements</presence>
@@ -45,9 +45,9 @@
45
45
  <agent>Theme-level gates. Runtime polarity/details: toggles.xml. Do not invent alternate effect hooks.</agent>
46
46
  </topic>
47
47
  <topic id="vibrancy" surface="theme">
48
- <pattern>--vibrancy-blur | --vibrancy-brightness</pattern>
49
- <summary>Vibrancy glass params; blur is a numeric amount consumed as pixels, brightness is a percent string.</summary>
50
- <agent>Theme params for data-vibrant hosts when --effect-vibrancy is on. Do not hand-roll backdrop-filter.</agent>
48
+ <pattern>--vibrancy-blur</pattern>
49
+ <summary>Vibrancy glass blur amount; numeric value consumed as pixels in data-vibrant backdrop-filter (with fixed saturate).</summary>
50
+ <agent>Theme param for data-vibrant hosts when --effect-vibrancy is on. Do not hand-roll backdrop-filter.</agent>
51
51
  </topic>
52
52
  <topic id="radius" surface="theme">
53
53
  <pattern>--radius-* | --corner-shape</pattern>
@@ -5,13 +5,13 @@
5
5
  <when>html registers polarity via contrast-color(var(--global-background)) so light backgrounds resolve to black and dark backgrounds to white; container name is root (see core.css).</when>
6
6
  <when>data-mode=&quot;light&quot; forces --is-light-mode: black and color-scheme: light; data-mode=&quot;dark&quot; forces white and color-scheme: dark.</when>
7
7
  <when>data-mode=&quot;inverted&quot; flips color-scheme against the root value: @container root style(--is-light-mode: black) → dark; style(--is-light-mode: white) → light.</when>
8
- <when>Component/preflight CSS branches on polarity with @container root style(--is-light-mode: black) or white — e.g. vibrancy brightness, holofoil mix-blend, Button/Chip secondary fills. Do not invent alternate light/dark hooks.</when>
8
+ <when>Component/preflight CSS branches on polarity with @container root style(--is-light-mode: black) or white — e.g. holofoil mix-blend, Button/Chip secondary fills. Do not invent alternate light/dark hooks.</when>
9
9
  </toggle>
10
10
  <toggle name="--effect-shadows">
11
11
  <when>Empty/unset enables data-elevation box-shadow stacks; set to initial to disable. Preflight gates with @container root not style(--effect-shadows: initial). Do not hand-roll box-shadow.</when>
12
12
  </toggle>
13
13
  <toggle name="--effect-vibrancy">
14
- <when>Empty/unset enables data-vibrant backdrop filters; set to initial to disable. Preflight gates with @container root not style(--effect-vibrancy: initial); vibrancy may further branch on --is-light-mode. Do not hand-roll backdrop-filter.</when>
14
+ <when>Empty/unset enables data-vibrant backdrop filters; set to initial to disable. Preflight gates with @container root not style(--effect-vibrancy: initial). Do not hand-roll backdrop-filter.</when>
15
15
  </toggle>
16
16
  <toggle name="--effect-corner-shape">
17
17
  <when>Empty/unset enables theme corner-shape on *; set to initial to disable. Preflight gates with @container root not style(--effect-corner-shape: initial) and applies var(--__corner-shape, var(--corner-shape)). Pair with --corner-shape token.</when>
@@ -1,5 +1,5 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
- <index package="@viraui/react" version="2026.8.0" generated="2026-10-14T16:23:26.846Z">
2
+ <index package="@viraui/react" version="2026.9.0" generated="2026-10-15T06:47:40.657Z">
3
3
  <categories>
4
4
  <category id="layout" />
5
5
  <category id="action" />
@@ -598,18 +598,6 @@
598
598
  <unit kind="pattern" href="patterns/compose-layout-first.xml" />
599
599
  </units>
600
600
  </entry>
601
- <entry id="equal-width-actions" category="pattern" title="Equal-width action row">
602
- <summary>Span or share space with Stack `fullWidth` and/or `expandChildren` (and control `fullWidth` when the surface owns it). Orthogonal: `fullWidth` sizes the Stack; `expandChildren` grows direct children …</summary>
603
- <units>
604
- <unit kind="pattern" href="patterns/equal-width-actions.xml" />
605
- </units>
606
- </entry>
607
- <entry id="page-chrome" category="pattern" title="Page chrome with Stack render">
608
- <summary>Own page/section flex with Stack. Pick semantic tags (`header`, `main`, `nav`, `section`, …) via `render={&amp;lt;tag /&amp;gt;}` — keep Stack as the layout engine. CSS modules may set min-block-size / scrol…</summary>
609
- <units>
610
- <unit kind="pattern" href="patterns/page-chrome.xml" />
611
- </units>
612
- </entry>
613
601
  <entry id="settings-panel" category="pattern" title="Settings panel (Surface + Stack)">
614
602
  <summary>Wrap a settings block in Surface for fill/border/radius/padding; nest Stack for child gaps and rows. Compose the settings-row pattern inside for label+control rows. Prefer props over CSS for spacing …</summary>
615
603
  <units>
@@ -622,10 +610,4 @@
622
610
  <unit kind="pattern" href="patterns/settings-row.xml" />
623
611
  </units>
624
612
  </entry>
625
- <entry id="stack-as-surface" category="pattern" title="Stack as Surface (avoid extra DOM)">
626
- <summary>When a flex cluster also needs Surface chrome (border, color, radius, padding), prefer `Stack render={&amp;lt;Surface … /&amp;gt;}` so layout + chrome share one root. Put gap/align/`fullWidth`/`expandChildre…</summary>
627
- <units>
628
- <unit kind="pattern" href="patterns/stack-as-surface.xml" />
629
- </units>
630
- </entry>
631
613
  </index>
@@ -10,7 +10,7 @@
10
10
  <ref id="bleed" units="meta,usage" />
11
11
  </uses>
12
12
  <do>Prefer Vira layout roots (`Stack`, `Grid`, `Masonry`, `Bleed`, `Surface`) and their public props for every consumer layout. Treat `Stack` as the default box: an enriched `div` (flex + gap/padding/align/`fullWidth`/`render`/…) — prefer it over bare wrapper `div`s even for simple nesting. Compose **with** these parts; default custom CSS = **app chrome** the system does not own. Prefer another Vira component (e.g. `Surface` for border/fill/radius) or `render` merge over a CSS class for chrome the library already owns. Do not open a CSS module to reshape a Vira control unless the consumer **expressly asked** for that override (still read `props`/`usage` first; a future override layer will formalize hooks).</do>
13
- <dont>Do not invent bare wrapper `div`s (or `display:flex` / `display:grid` / CSS `gap` / `padding` / `paddingBlock*` / `paddingInline*` / `width` / `inline-size` / border/radius chrome on raw tags or Vira control roots) when `Stack` or another layout primitive / `Surface` / a public `fullWidth` or `hPadding`/`vPadding` tuple covers it. Do not skip composition to reach for a one-off stylesheet — including size-fill classNames that would do nothing on fixed-size controls. Do not pass `render` that restates a component&apos;s default root (e.g. Stack `render={&lt;div /&gt;}`) — omit `render` unless the host changes.</dont>
13
+ <dont>Do not invent bare wrapper `div`s (or `display:flex` / `display:grid` / CSS `gap` / `padding` / `paddingBlock*` / `paddingInline*` / `width` / `height` / `inline-size` / `block-size: 100%` / border/radius chrome on raw tags or Vira control roots) when `Stack` or another layout primitive / `Surface` / a public `fullWidth`/`fullHeight`/`expandChildren` + stretch align (Stack `patterns.xml`) or `hPadding`/`vPadding` tuple covers it. Do not skip composition to reach for a one-off stylesheet — including size-fill classNames that would do nothing on fixed-size controls. Do not pass `render` that restates a component&apos;s default root (e.g. Stack `render={&lt;div /&gt;}`) — omit `render` unless the host changes.</dont>
14
14
  <tsx><![CDATA[
15
15
  {/* Flex row + panel chrome: one DOM node via Stack render={<Surface />} */}
16
16
  <Stack
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viraui/react",
3
- "version": "2026.8.0",
3
+ "version": "2026.9.0",
4
4
  "private": false,
5
5
  "files": [
6
6
  "dist"
@@ -28,7 +28,7 @@
28
28
  },
29
29
  "devDependencies": {
30
30
  "@base-ui/react": ">=1.8.0",
31
- "@viraui/foundation": "2026.8.0",
31
+ "@viraui/foundation": "2026.9.0",
32
32
  "@viraui/icons": "2026.1.0",
33
33
  "@viraui/postcss-config": "2026.0.0",
34
34
  "@viraui/tsconfig": "2026.0.0",
@@ -1,22 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <pattern id="equal-width-actions" title="Equal-width action row">
3
- <uses>
4
- <ref id="stack" units="meta,usage,props" />
5
- <ref id="button" units="meta,props" />
6
- </uses>
7
- <do>Span or share space with Stack `fullWidth` and/or `expandChildren` (and control `fullWidth` when the surface owns it). Orthogonal: `fullWidth` sizes the Stack; `expandChildren` grows direct children on the main axis.</do>
8
- <dont>Do not invent `width: 100%` / `w-full` / per-child `flex: 1` CSS on Button (or other content-sized controls) when Stack can own the fill.</dont>
9
- <tsx><![CDATA[
10
- {/* Full-bleed column CTAs */}
11
- <Stack fullWidth rowGap="s">
12
- <Button>Continue</Button>
13
- <Button variant="secondary">Cancel</Button>
14
- </Stack>
15
-
16
- {/* Equal-width row actions — children grow on the main axis. Add fullWidth when the Stack itself should fill its parent width */}
17
- <Stack expandChildren direction="row" columnGap="s">
18
- <Button>Continue</Button>
19
- <Button variant="secondary">Cancel</Button>
20
- </Stack>
21
- ]]></tsx>
22
- </pattern>
@@ -1,34 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <pattern id="page-chrome" title="Page chrome with Stack render">
3
- <uses>
4
- <ref id="stack" units="meta,usage,props" />
5
- <ref id="title" units="meta" />
6
- <ref id="button" units="meta" />
7
- </uses>
8
- <do>Own page/section flex with Stack. Pick semantic tags (`header`, `main`, `nav`, `section`, …) via `render={&lt;tag /&gt;}` — keep Stack as the layout engine. CSS modules may set min-block-size / scroll; never `display:flex`.</do>
9
- <dont>Do not use raw `header`/`main`/`nav` + `display:flex` / CSS gap for jobs Stack owns. Tag choice ≠ layout engine. Do not pass `render={&lt;div /&gt;}` — Stack already defaults to `div`; omit `render` unless the host changes.</dont>
10
- <tsx><![CDATA[
11
- <Stack rowGap="m" expandChildren>
12
- <Stack
13
- direction="row"
14
- hAlign="space-between"
15
- vAlign="center"
16
- columnGap="m"
17
- hPadding="m"
18
- vPadding="m"
19
- render={<header />}
20
- >
21
- <Title render={<h1 />}>Settings</Title>
22
- <Button>Save</Button>
23
- </Stack>
24
- <Stack direction="row" columnGap="m" expandChildren render={<main />}>
25
- <Stack rowGap="xs" hPadding="s" vPadding="s" render={<nav aria-label="Settings" />}>
26
- {/* nav links */}
27
- </Stack>
28
- <Stack rowGap="l" expandChildren>
29
- {/* content */}
30
- </Stack>
31
- </Stack>
32
- </Stack>
33
- ]]></tsx>
34
- </pattern>
@@ -1,37 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <pattern id="stack-as-surface" title="Stack as Surface (avoid extra DOM)">
3
- <uses>
4
- <ref id="stack" units="meta,usage,props" />
5
- <ref id="surface" units="meta,usage,props" />
6
- <ref id="text" units="meta" />
7
- <ref id="chip" units="meta" />
8
- </uses>
9
- <do>When a flex cluster also needs Surface chrome (border, color, radius, padding), prefer `Stack render={&lt;Surface … /&gt;}` so layout + chrome share one root. Put gap/align/`fullWidth`/`expandChildren` on Stack; put `border` / `color` / `radius` / padding on the Surface in `render`.</do>
10
- <dont>Do not add a CSS class for border/background/radius on a Stack when Surface owns that chrome. Do not wrap Stack in an extra Surface solely for those props when `render` merge is enough. Nest Surface→Stack only when you need separate roots (e.g. Elevator around Surface, concentric nested Surfaces, or chrome that must not sit on the flex host).</dont>
11
- <tsx><![CDATA[
12
- {/* Preferred: single node */}
13
- <Stack
14
- direction="row"
15
- columnGap="s"
16
- vAlign="center"
17
- fullWidth
18
- render={<Surface border="all" color={1} radius="m" hPadding="m" vPadding="s" />}
19
- >
20
- <Text size="sm" color="muted">
21
- Status
22
- </Text>
23
- <Chip>Active</Chip>
24
- </Stack>
25
-
26
- {/* OK when a separate Surface root is required (Elevator, nested radius="auto", …) */}
27
- {/*
28
- <Elevator elevation={1}>
29
- <Surface border="all" color={1} radius="m" hPadding="m" vPadding="s">
30
- <Stack direction="row" columnGap="s" vAlign="center" fullWidth>
31
- …
32
- </Stack>
33
- </Surface>
34
- </Elevator>
35
- */}
36
- ]]></tsx>
37
- </pattern>