@@ -179,7 +179,29 @@ const assertStaticDemoContract = () => {
179179 assert . match ( demoCss , / - - d e m o - c o n t a i n e r - b l o c k - s i z e / ) ;
180180 assert . match ( demoCss , / d a t a - d e m o - h e i g h t - t i e r = " s h o r t " / ) ;
181181 assert . match ( demoCss , / d a t a - d e m o - h e i g h t - t i e r = " s h a l l o w " / ) ;
182- assert . match ( demoCss , / 1 0 0 d v h / ) ;
182+ assert . equal (
183+ (
184+ demoCss . match (
185+ / m i n - b l o c k - s i z e : \s * 1 0 0 v h ; \s * m i n - b l o c k - s i z e : \s * 1 0 0 s v h ; \s * m i n - b l o c k - s i z e : \s * 1 0 0 d v h ; / g
186+ ) ?? [ ]
187+ ) . length ,
188+ 1 ,
189+ "The page minimum height must prefer dvh after its vh and svh fallbacks."
190+ ) ;
191+ assert . equal (
192+ (
193+ demoCss . match (
194+ / m a x - b l o c k - s i z e : \s * 1 0 0 v h ; \s * m a x - b l o c k - s i z e : \s * 1 0 0 s v h ; \s * m a x - b l o c k - s i z e : \s * 1 0 0 d v h ; / g
195+ ) ?? [ ]
196+ ) . length ,
197+ 1 ,
198+ "The mobile controls drawer must prefer dvh after its vh and svh fallbacks."
199+ ) ;
200+ assert . match (
201+ demoCss ,
202+ / m a x - b l o c k - s i z e : \s * c a l c \( 1 0 0 v h - 7 r e m \) ; \s * m a x - b l o c k - s i z e : \s * c a l c \( 1 0 0 s v h - 7 r e m \) ; \s * m a x - b l o c k - s i z e : \s * c a l c \( 1 0 0 d v h - 7 r e m \) ; / ,
203+ "The desktop controls must prefer dvh after their vh and svh fallbacks."
204+ ) ;
183205} ;
184206
185207const contentTypes = {
@@ -507,6 +529,21 @@ const verifyHeightBehavior = async (page, baseUrl) => {
507529 ) ;
508530 await page . waitForFunction ( ( ) => document . body . dataset . demoReady === "true" ) ;
509531
532+ const standaloneStickyPosition = await page . evaluate ( ( ) => {
533+ const fixture = document . createElement ( "header" ) ;
534+ fixture . className = "ly-header--sticky" ;
535+ fixture . style . setProperty ( "--ly-sticky-position" , "initial" ) ;
536+ document . body . append ( fixture ) ;
537+ const position = getComputedStyle ( fixture ) . position ;
538+ fixture . remove ( ) ;
539+ return position ;
540+ } ) ;
541+ assert . equal (
542+ standaloneStickyPosition ,
543+ "sticky" ,
544+ "A sticky header outside a token scope must retain its safe default."
545+ ) ;
546+
510547 const samples = [
511548 { height : 464 , shell : "auto" , position : "static" , tier : "shallow" } ,
512549 { height : 496 , shell : "100dvh" , position : "sticky" , tier : "short" } ,
@@ -567,6 +604,49 @@ const verifyHeightBehavior = async (page, baseUrl) => {
567604 }
568605} ;
569606
607+ const verifyDefaultFontHeightTiers = async ( baseUrl ) => {
608+ if ( browserName !== "chromium" ) return ;
609+
610+ /*
611+ Chromium can apply a real browser-default font preference at launch.
612+ This validates rem conversion without overriding the page's authored root size.
613+ */
614+ const fontBrowser = await chromium . launch ( {
615+ headless : true ,
616+ args : [ "--blink-settings=defaultFontSize=20" ]
617+ } ) ;
618+ const fontPage = await fontBrowser . newPage ( ) ;
619+
620+ try {
621+ await installExternalFixtures ( fontPage ) ;
622+
623+ for ( const sample of [
624+ { height : 550 , tier : "shallow" } ,
625+ { height : 800 , tier : "short" } ,
626+ { height : 920 , tier : "regular" }
627+ ] ) {
628+ await fontPage . setViewportSize ( { width : 1440 , height : sample . height } ) ;
629+ await fontPage . goto (
630+ `${ baseUrl } ?ecosystem=layout-only&wrapper=full&recipe=app-shell&container=73rem` ,
631+ { waitUntil : "domcontentloaded" }
632+ ) ;
633+ await fontPage . waitForFunction ( ( ) => document . body . dataset . demoReady === "true" ) ;
634+
635+ const result = await fontPage . evaluate ( ( ) => ( {
636+ fontSize : getComputedStyle ( document . documentElement ) . fontSize ,
637+ tier : document . querySelector ( ".demo-preview-root" ) . dataset . demoHeightTier
638+ } ) ) ;
639+ assert . deepEqual (
640+ result ,
641+ { fontSize : "20px" , tier : sample . tier } ,
642+ `The ${ sample . height } px viewport ignored the 20px browser default font size.`
643+ ) ;
644+ }
645+ } finally {
646+ await fontBrowser . close ( ) ;
647+ }
648+ } ;
649+
570650const verifyDeviceMatrix = async ( page , baseUrl ) => {
571651 await page . goto ( `${ baseUrl } ?ecosystem=layout-only&wrapper=full` , {
572652 waitUntil : "domcontentloaded"
@@ -801,6 +881,10 @@ const verifyPrimitiveOverflow = async (page, baseUrl) => {
801881
802882 if ( primitive === "scroll" ) {
803883 assert ( result . vertical > 2 && result . overflowY === "auto" , "Scroll must be vertically bounded." ) ;
884+ assert (
885+ ! [ "auto" , "scroll" , "visible" ] . includes ( result . overflowX ) ,
886+ `The bounded vertical scroll primitive exposed inline overflow as ${ result . overflowX } .`
887+ ) ;
804888 } else {
805889 assert (
806890 ! ( result . vertical > 2 && [ "auto" , "scroll" ] . includes ( result . overflowY ) ) ,
@@ -862,6 +946,7 @@ try {
862946 await verifyTopologyEdges ( page , server . baseUrl ) ;
863947 await verifyManualAndNearestContainer ( page , server . baseUrl ) ;
864948 await verifyHeightBehavior ( page , server . baseUrl ) ;
949+ await verifyDefaultFontHeightTiers ( server . baseUrl ) ;
865950 await verifyDeviceMatrix ( page , server . baseUrl ) ;
866951 await verifyPersonalityMatrix ( page , server . baseUrl ) ;
867952 await verifyMinimumWidth ( page , server . baseUrl ) ;
0 commit comments