@@ -61,49 +61,88 @@ dialog[s-modal]:not([open]) {
6161 color : var (--s-text-primary );
6262}
6363
64- /* Open state animation */
64+ /* Open state animation - using @starting-style for cleaner entry animations */
6565dialog [s-modal ][open ] {
66- animation : s-modal-scale-in var ( --s-duration-200 ) var ( --s-ease-out ) ;
67- }
68-
69- /* Focus visible state for keyboard navigation */
70- dialog [ s-modal ] : focus-visible {
71- outline : 2 px solid var (--s-focus-ring );
72- outline-offset : 2 px ;
66+ opacity : 1 ;
67+ transform : scale ( 1 ) translateY ( 0 );
68+ transition :
69+ opacity var ( --s-duration-200 ) var ( --s-ease-out ) ,
70+ transform var ( --s-duration-200 ) var ( --s-ease-out ) ,
71+ overlay var (--s-duration-200 ) var ( --s-ease-out ) allow-discrete ,
72+ display var ( --s-duration-200 ) var ( --s-ease-out ) allow-discrete ;
7373}
7474
75- @keyframes s-modal-scale-in {
76- from {
75+ /* Entry animation initial state - CSS @starting-style */
76+ @starting-style {
77+ dialog [s-modal ][open ] {
7778 opacity : 0 ;
7879 transform : scale (0.95 ) translateY (-10px );
7980 }
80- to {
81- opacity : 1 ;
82- transform : scale (1 ) translateY (0 );
81+ }
82+
83+ /* Fallback for browsers without @starting-style (using transition-behavior as proxy test) */
84+ @supports not (transition-behavior : allow-discrete) {
85+ dialog [s-modal ][open ] {
86+ animation : s-modal-scale-in var (--s-duration-200 ) var (--s-ease-out );
87+ }
88+
89+ @keyframes s-modal-scale-in {
90+ from {
91+ opacity : 0 ;
92+ transform : scale (0.95 ) translateY (-10px );
93+ }
94+ to {
95+ opacity : 1 ;
96+ transform : scale (1 ) translateY (0 );
97+ }
8398 }
8499}
85100
101+ /* Focus visible state for keyboard navigation */
102+ dialog [s-modal ]: focus-visible {
103+ outline : 2px solid var (--s-focus-ring );
104+ outline-offset : 2px ;
105+ }
106+
86107/* =============================================================================
87108 BACKDROP STYLING
88109 ============================================================================= */
89110
90111dialog [s-modal ]::backdrop {
91112 background : oklch (0 0 0 / 0.5 );
92113 backdrop-filter : blur (4px );
93- animation : s-modal-backdrop-in var (--s-duration-200 ) var (--s-ease-out );
114+ opacity : 1 ;
115+ transition :
116+ opacity var (--s-duration-200 ) var (--s-ease-out ),
117+ overlay var (--s-duration-200 ) var (--s-ease-out ) allow-discrete,
118+ display var (--s-duration-200 ) var (--s-ease-out ) allow-discrete;
94119
95120 /* RCS: adaptive backdrop - tinted with brand hue */
96121 @supports (color : oklch (from red l c h)) {
97122 background : oklch (from var (--s-primary-500 ) 0.1 0.02 h / 0.5 );
98123 }
99124}
100125
101- @keyframes s-modal-backdrop-in {
102- from {
126+ /* Backdrop entry animation */
127+ @starting-style {
128+ dialog [s-modal ]::backdrop {
103129 opacity : 0 ;
104130 }
105- to {
106- opacity : 1 ;
131+ }
132+
133+ /* Fallback for browsers without @starting-style (using transition-behavior as proxy test) */
134+ @supports not (transition-behavior : allow-discrete) {
135+ dialog [s-modal ]::backdrop {
136+ animation : s-modal-backdrop-in var (--s-duration-200 ) var (--s-ease-out );
137+ }
138+
139+ @keyframes s-modal-backdrop-in {
140+ from {
141+ opacity : 0 ;
142+ }
143+ to {
144+ opacity : 1 ;
145+ }
107146 }
108147}
109148
@@ -262,6 +301,18 @@ dialog[s-modal][s-position="right"] {
262301 ACCESSIBILITY & HIGH CONTRAST
263302 ============================================================================= */
264303
304+ /* Respect reduced motion preferences */
305+ @media (prefers-reduced-motion : reduce) {
306+ dialog [s-modal ][open ] {
307+ transition : none;
308+ transform : none;
309+ }
310+
311+ dialog [s-modal ]::backdrop {
312+ transition : none;
313+ }
314+ }
315+
265316/* High contrast mode support */
266317@media (forced-colors : active) {
267318 dialog [s-modal ] {
0 commit comments