@@ -205,6 +205,43 @@ describe('dark mode cascade structure', () => {
205205 } ) ;
206206} ) ;
207207
208+ describe ( 'popup close button' , ( ) => {
209+ it ( 'is a red square re-driven from palette variables' , ( ) => {
210+ // The template ships a bare × button; the red-square chrome must come
211+ // from main#app overrides (1,1,1) so both palettes stay compatible.
212+ const close = rules . get ( 'main#app .close-btn' ) ;
213+ expect ( close ) . toBeTruthy ( ) ;
214+ expect ( close ) . toMatch ( / b a c k g r o u n d : \s * v a r \( - - p o p u p - c l o s e - b g \) / ) ;
215+ expect ( close ) . toMatch ( / c o l o r : \s * v a r \( - - p o p u p - c l o s e - f g \) / ) ;
216+
217+ // SC 2.5.8: the pointer target is at least 24x24 CSS px.
218+ const width = Number ( close . match ( / w i d t h : \s * ( [ \d . ] + ) r e m / ) [ 1 ] ) ;
219+ const height = Number ( close . match ( / h e i g h t : \s * ( [ \d . ] + ) r e m / ) [ 1 ] ) ;
220+ expect ( width ) . toBeGreaterThanOrEqual ( 1.5 ) ;
221+ expect ( height ) . toBeGreaterThanOrEqual ( 1.5 ) ;
222+ } ) ;
223+
224+ it ( 'the focus ring floats off the red square onto the popup surface' , ( ) => {
225+ // A ring hugging the red fill cannot use --brand-accent (blue on red
226+ // is ~1:1); offset it so it contrasts with --card-bg instead.
227+ const focus = rules . get ( 'main#app .close-btn:focus-visible' ) ;
228+ expect ( focus ) . toMatch ( / o u t l i n e - c o l o r : \s * v a r \( - - b r a n d - a c c e n t \) / ) ;
229+ expect ( focus ) . toMatch ( / o u t l i n e - o f f s e t : \s * 2 p x / ) ;
230+ } ) ;
231+
232+ for ( const [ name , palette ] of [ [ 'light' , lightPalette ] , [ 'dark' , darkPalette ] ] ) {
233+ it ( `the white × keeps AA text contrast on the red square (${ name } )` , ( ) => {
234+ expect ( contrastOf ( palette , '--popup-close-bg' , '--popup-close-fg' ) )
235+ . toBeGreaterThanOrEqual ( 4.5 ) ;
236+ } ) ;
237+
238+ it ( `the red square is perceivable against the popup surface (${ name } )` , ( ) => {
239+ expect ( contrastOf ( palette , '--card-bg' , '--popup-close-bg' ) )
240+ . toBeGreaterThanOrEqual ( 3 ) ;
241+ } ) ;
242+ }
243+ } ) ;
244+
208245describe ( 'toggle styles' , ( ) => {
209246 it ( 'the toggle renders icon pills over appearance-none radios' , ( ) => {
210247 expect ( rules . get ( '.theme-toggle' ) ) . toMatch ( / d i s p l a y : \s * f l e x / ) ;
0 commit comments