From ddef6ac26c247fcc88dfb81e7ad02704597d620c Mon Sep 17 00:00:00 2001 From: Foscat Date: Wed, 29 Jul 2026 06:03:49 -0500 Subject: [PATCH 1/7] feat!: rebuild core as intrinsic responsive v3 --- dist/core.css | 3 +- dist/foundation.css | 168 +++ dist/integrations/ui-style-kit.css | 175 --- dist/layout-style-css.css | 1442 ++++++------------- dist/layout-style-css.min.css | 2 +- dist/legacy.css | 822 ----------- dist/personalities.css | 2 +- dist/personalities/bauhaus.css | 55 +- dist/personalities/bento.css | 56 +- dist/personalities/brutalism.css | 46 +- dist/personalities/cyberpunk.css | 44 +- dist/personalities/f-pattern.css | 61 +- dist/personalities/maximalist.css | 64 +- dist/personalities/minimal-saas.css | 40 +- dist/personalities/mondrian.css | 52 +- dist/personalities/neumorphism.css | 54 +- dist/personalities/retro-glass.css | 56 +- dist/personalities/retrofuturism.css | 44 +- dist/personalities/split-screen.css | 60 +- dist/personalities/synthwave.css | 54 +- dist/personalities/tactile.css | 47 +- dist/personalities/y2k.css | 46 +- dist/personalities/z-pattern.css | 62 +- dist/primitives.css | 89 +- dist/recipes.css | 260 ++-- dist/utilities.css | 114 +- dist/wrappers.css | 130 +- package-lock.json | 4 +- package.json | 36 +- scripts/build.mjs | 75 +- stylelint.config.mjs | 7 +- styles/core.css | 3 +- styles/foundation.css | 168 +++ styles/integrations/ui-style-kit.css | 175 --- styles/legacy.css | 173 --- styles/personalities.css | 2 +- styles/personalities/bauhaus.css | 55 +- styles/personalities/bento.css | 56 +- styles/personalities/brutalism.css | 46 +- styles/personalities/cyberpunk.css | 44 +- styles/personalities/f-pattern.css | 61 +- styles/personalities/maximalist.css | 64 +- styles/personalities/minimal-saas.css | 40 +- styles/personalities/mondrian.css | 52 +- styles/personalities/neumorphism.css | 54 +- styles/personalities/retro-glass.css | 56 +- styles/personalities/retrofuturism.css | 44 +- styles/personalities/split-screen.css | 60 +- styles/personalities/synthwave.css | 54 +- styles/personalities/tactile.css | 47 +- styles/personalities/y2k.css | 46 +- styles/personalities/z-pattern.css | 62 +- styles/primitives.css | 89 +- styles/recipes.css | 260 ++-- styles/utilities.css | 114 +- styles/wrappers.css | 130 +- test/layout-css-contract.test.mjs | 1816 +++--------------------- 57 files changed, 1784 insertions(+), 6157 deletions(-) create mode 100644 dist/foundation.css delete mode 100644 dist/integrations/ui-style-kit.css delete mode 100644 dist/legacy.css create mode 100644 styles/foundation.css delete mode 100644 styles/integrations/ui-style-kit.css delete mode 100644 styles/legacy.css diff --git a/dist/core.css b/dist/core.css index e24ab50..b215325 100644 --- a/dist/core.css +++ b/dist/core.css @@ -1,5 +1,6 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; +@import url("./foundation.css"); @import url("./wrappers.css"); @import url("./primitives.css"); @import url("./recipes.css"); diff --git a/dist/foundation.css b/dist/foundation.css new file mode 100644 index 0000000..d06c066 --- /dev/null +++ b/dist/foundation.css @@ -0,0 +1,168 @@ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; + +/* + Foundation owns only shared spatial tokens, containment, and defensive + sizing. Theme and interaction libraries remain responsible for paint. +*/ + +@layer ly.tokens { + :where(.ly-root) { + --ly-space-0: 0; + --ly-space-1: 0.25rem; + --ly-space-2: 0.5rem; + --ly-space-3: 0.75rem; + --ly-space-4: 1rem; + --ly-space-5: 1.5rem; + --ly-space-6: 2rem; + --ly-space-7: 3rem; + --ly-space-8: 4rem; + --ly-space-9: 6rem; + + --ly-wrapper-compact: 40rem; + --ly-wrapper-prose: 68ch; + --ly-wrapper-content: 72rem; + --ly-wrapper-wide: 112rem; + --ly-page-padding-inline: clamp(1rem, 4vw, 3rem); + --ly-safe-area-inline: max( + env(safe-area-inset-left, 0px), + env(safe-area-inset-right, 0px) + ); + --ly-safe-area-block-start: env(safe-area-inset-top, 0px); + --ly-safe-area-block-end: env(safe-area-inset-bottom, 0px); + --ly-wrapper-gutter: max(var(--ly-page-padding-inline), var(--ly-safe-area-inline)); + + --ly-profile-gap: var(--ly-space-5); + --ly-gap: var(--ly-profile-gap); + --ly-grid-gap: var(--ly-gap); + --ly-stack-gap: var(--ly-space-4); + --ly-cluster-gap: var(--ly-space-3); + --ly-section-padding-block: clamp(3rem, 7vh, 6rem); + --ly-header-height: 4.5rem; + --ly-sticky-position: sticky; + --ly-cover-min: 100dvh; + --ly-shell-min: 100dvh; + --ly-scroll-max: min(70dvh, 50rem); + + --ly-switcher-threshold: 42rem; + --ly-sidebar-size: 18rem; + --ly-sidebar-content-min: 50%; + --ly-grid-columns: 12; + --ly-grid-min: 16rem; + --ly-split-min: 20rem; + --ly-pane-min: 18rem; + --ly-pane-size: 22rem; + --ly-media-min: 18rem; + --ly-media-size: 14rem; + --ly-reel-item-min: 16rem; + --ly-reel-item-max: 28rem; + --ly-frame-ratio: 16 / 9; + + --ly-recipe-rail: 18rem; + --ly-recipe-aside: 22rem; + --ly-gallery-min: 12rem; + --ly-card-grid-min: 16rem; + + --ly-app-shell-medium-areas: + "header header" + "sidebar main" + "aside main" + "footer footer"; + --ly-app-shell-medium-columns: + minmax(min(100%, var(--ly-recipe-rail)), auto) + minmax(0, 1fr); + --ly-app-shell-wide-areas: + "sidebar header header" + "sidebar main aside" + "sidebar footer footer"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), auto) + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); + + --ly-dashboard-medium-areas: + "header header" + "nav nav" + "main aside" + "footer footer"; + --ly-dashboard-medium-columns: + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); + --ly-dashboard-wide-areas: + "nav header header" + "nav main aside" + "nav footer footer"; + --ly-dashboard-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), auto) + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); + + --ly-docs-wide-areas: + "header header" + "nav main" + "nav aside" + "footer footer"; + --ly-docs-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), auto) + minmax(0, 1fr); + --ly-list-detail-wide-areas: + "primary secondary" + "actions actions"; + --ly-list-detail-wide-columns: + minmax(min(100%, var(--ly-pane-size)), 0.7fr) + minmax(0, 1fr); + --ly-split-hero-wide-areas: + "content media" + "actions media"; + --ly-split-hero-wide-columns: + minmax(0, var(--ly-split-primary, 1fr)) + minmax(0, var(--ly-split-secondary, 1fr)); + + container-name: ly-scope; + container-type: inline-size; + min-inline-size: 0; + min-block-size: 0; + } +} + +@layer ly.reset { + :where(.ly-root), + :where(.ly-root *) { + box-sizing: border-box; + } + + :where(.ly-root) { + margin: 0; + } + + :where(.ly-root img), + :where(.ly-root svg), + :where(.ly-root video), + :where(.ly-root canvas), + :where(.ly-root iframe) { + max-inline-size: 100%; + } +} + +@layer ly.tokens { + @media (max-height: 44rem) { + :where(.ly-root) { + --ly-gap: min(var(--ly-profile-gap), var(--ly-space-4)); + --ly-grid-gap: var(--ly-gap); + --ly-stack-gap: min(var(--ly-space-4), 3dvh); + --ly-cluster-gap: min(var(--ly-space-3), 2dvh); + --ly-section-padding-block: clamp(1.5rem, 6dvh, 3rem); + --ly-header-height: 3.5rem; + --ly-scroll-max: min(62dvh, 34rem); + } + } + + @media (max-height: 30rem) { + :where(.ly-root) { + --ly-cover-min: auto; + --ly-shell-min: auto; + --ly-sticky-position: static; + --ly-section-padding-block: var(--ly-space-5); + --ly-scroll-max: max(12rem, calc(100dvh - 8rem)); + } + } +} diff --git a/dist/integrations/ui-style-kit.css b/dist/integrations/ui-style-kit.css deleted file mode 100644 index a2d4f2d..0000000 --- a/dist/integrations/ui-style-kit.css +++ /dev/null @@ -1,175 +0,0 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* - Compatibility bridge for ui-style-kit-css. - This bridge intentionally does not map color, type, border, or shadow tokens. - ui-style-kit-css owns those visuals; layout-style-css owns structure. -*/ - -@layer ly.integrations.ui_style_kit { - :where(.ly-root[data-ui][data-theme][data-mode], [data-ui][data-theme][data-mode] .ly-root) { - --ly-ui-style-kit-bridge: 1; - - /* - Normalize UI kit root background geometry without redefining its paint. - Patterned theme layers should fill the viewport once instead of tiling. - */ - min-block-size: 100svh; - background-attachment: fixed; - background-position: center; - background-repeat: no-repeat; - background-size: 100% 100%; - } - - :where(.ly-root[data-ui="minimal-saas"], [data-ui="minimal-saas"] .ly-root) { - --ly-ui-style-kit-bridge-style: minimal-saas; - } - - :where(.ly-root[data-ui="bento"], [data-ui="bento"] .ly-root) { - --ly-ui-style-kit-bridge-style: bento; - } - - :where(.ly-root[data-ui="maximalist"], [data-ui="maximalist"] .ly-root) { - --ly-ui-style-kit-bridge-style: maximalist; - } - - :where(.ly-root[data-ui="bauhaus"], [data-ui="bauhaus"] .ly-root) { - --ly-ui-style-kit-bridge-style: bauhaus; - } - - :where(.ly-root[data-ui="tactile"], [data-ui="tactile"] .ly-root) { - --ly-ui-style-kit-bridge-style: tactile; - } - - :where(.ly-root[data-ui="neumorphism"], [data-ui="neumorphism"] .ly-root) { - --ly-ui-style-kit-bridge-style: neumorphism; - } - - :where(.ly-root[data-ui="retrofuturism"], [data-ui="retrofuturism"] .ly-root) { - --ly-ui-style-kit-bridge-style: retrofuturism; - } - - :where(.ly-root[data-ui="brutalism"], [data-ui="brutalism"] .ly-root) { - --ly-ui-style-kit-bridge-style: brutalism; - } - - :where(.ly-root[data-ui="cyberpunk"], [data-ui="cyberpunk"] .ly-root) { - --ly-ui-style-kit-bridge-style: cyberpunk; - } - - :where(.ly-root[data-ui="y2k"], [data-ui="y2k"] .ly-root) { - --ly-ui-style-kit-bridge-style: y2k; - } - - :where(.ly-root[data-ui="retro-glass"], [data-ui="retro-glass"] .ly-root) { - --ly-ui-style-kit-bridge-style: retro-glass; - } - - :where(.saas-container, .bento-container, .max-container, .bau-container, .tactile-container, .neo-container, .retro-container, .brutal-container, .cyber-container, .y2k-container, .rg-container) { - /* UI Style Kit naming can opt into layout sizing without taking over visual paint. */ - container-name: ly-wrapper; - container-type: inline-size; - inline-size: min(100%, calc(var(--ly-wrapper-max) + (var(--ly-wrapper-gutter) * 2))); - margin-inline: auto; - padding-inline: var(--ly-wrapper-gutter); - } - - :where(.saas-section, .bento-section, .max-section, .bau-section, .tactile-section, .neo-section, .retro-section, .brutal-section, .cyber-section, .y2k-section, .rg-section) { - padding-block: var(--ly-section-padding-block); - } - - :where(.saas-stack, .bento-stack, .max-stack, .bau-stack, .tactile-stack, .neo-stack, .retro-stack, .brutal-stack, .cyber-stack, .y2k-stack, .rg-stack) { - display: flex; - flex-direction: column; - gap: var(--ly-stack-gap); - } - - :where(.saas-cluster, .bento-cluster, .max-cluster, .bau-cluster, .tactile-cluster, .neo-cluster, .retro-cluster, .brutal-cluster, .cyber-cluster, .y2k-cluster, .rg-cluster) { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: var(--ly-cluster-gap); - } - - :where(.saas-grid, .bento-grid, .max-grid, .bau-grid, .tactile-grid, .neo-grid, .retro-grid, .brutal-grid, .cyber-grid, .y2k-grid, .rg-grid) { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-grid-min)), 1fr)); - gap: var(--ly-grid-gap); - } - - :where(.saas-split, .bento-split, .max-split, .bau-split, .tactile-split, .neo-split, .retro-split, .brutal-split, .cyber-split, .y2k-split, .rg-split) { - display: grid; - grid-template-columns: 1fr; - gap: var(--ly-gap); - align-items: var(--ly-split-align, center); - } - - :where(.saas-split, .bento-split, .max-split, .bau-split, .tactile-split, .neo-split, .retro-split, .brutal-split, .cyber-split, .y2k-split, .rg-split) > * { - min-width: 0; - } - - :where(.saas-button-group, .bento-button-group, .max-button-group, .bau-button-group, .tactile-button-group, .neo-button-group, .retro-button-group, .brutal-button-group, .cyber-button-group, .y2k-button-group, .rg-button-group) { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: var(--ly-cluster-gap); - } - - :where(.saas-button-group, .bento-button-group, .max-button-group, .bau-button-group, .tactile-button-group, .neo-button-group, .retro-button-group, .brutal-button-group, .cyber-button-group, .y2k-button-group, .rg-button-group) > * { - flex: 0 1 auto; - min-width: min(100%, var(--ly-button-min, 8rem)); - } - - :where(.saas-card-grid, .bento-card-grid, .max-card-grid, .bau-card-grid, .tactile-card-grid, .neo-card-grid, .retro-card-grid, .brutal-card-grid, .cyber-card-grid, .y2k-card-grid, .rg-card-grid) { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-card-grid-min)), 1fr)); - gap: var(--ly-grid-gap); - } - - :where(.saas-card-grid, .bento-card-grid, .max-card-grid, .bau-card-grid, .tactile-card-grid, .neo-card-grid, .retro-card-grid, .brutal-card-grid, .cyber-card-grid, .y2k-card-grid, .rg-card-grid) > * { - min-width: 0; - } - - :where(.saas-card-sm, .bento-card-sm, .max-card-sm, .bau-card-sm, .tactile-card-sm, .neo-card-sm, .retro-card-sm, .brutal-card-sm, .cyber-card-sm, .y2k-card-sm, .rg-card-sm) { - min-block-size: var(--ly-card-size-sm); - } - - :where(.saas-card-md, .bento-card-md, .max-card-md, .bau-card-md, .tactile-card-md, .neo-card-md, .retro-card-md, .brutal-card-md, .cyber-card-md, .y2k-card-md, .rg-card-md) { - min-block-size: var(--ly-card-size-md); - } - - :where(.saas-card-lg, .bento-card-lg, .max-card-lg, .bau-card-lg, .tactile-card-lg, .neo-card-lg, .retro-card-lg, .brutal-card-lg, .cyber-card-lg, .y2k-card-lg, .rg-card-lg) { - min-block-size: var(--ly-card-size-lg); - } - - :where(.saas-gallery, .bento-gallery, .max-gallery, .bau-gallery, .tactile-gallery, .neo-gallery, .retro-gallery, .brutal-gallery, .cyber-gallery, .y2k-gallery, .rg-gallery) { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-gallery-min)), 1fr)); - gap: var(--ly-grid-gap); - } - - :where(.saas-gallery, .bento-gallery, .max-gallery, .bau-gallery, .tactile-gallery, .neo-gallery, .retro-gallery, .brutal-gallery, .cyber-gallery, .y2k-gallery, .rg-gallery) > * { - min-width: 0; - } - - :where(.saas-carousel, .bento-carousel, .max-carousel, .bau-carousel, .tactile-carousel, .neo-carousel, .retro-carousel, .brutal-carousel, .cyber-carousel, .y2k-carousel, .rg-carousel) { - display: grid; - grid-auto-flow: column; - grid-auto-columns: minmax(min(100%, var(--ly-carousel-item-min)), var(--ly-carousel-item-max)); - gap: var(--ly-grid-gap); - overflow-x: auto; - overscroll-behavior-inline: contain; - scroll-snap-type: x proximity; - } - - :where(.saas-carousel, .bento-carousel, .max-carousel, .bau-carousel, .tactile-carousel, .neo-carousel, .retro-carousel, .brutal-carousel, .cyber-carousel, .y2k-carousel, .rg-carousel) > * { - min-width: 0; - scroll-snap-align: start; - } - - @container (min-width: 48rem) { - :where(.saas-split, .bento-split, .max-split, .bau-split, .tactile-split, .neo-split, .retro-split, .brutal-split, .cyber-split, .y2k-split, .rg-split) { - grid-template-columns: minmax(0, var(--ly-split-primary, 1fr)) minmax(0, var(--ly-split-secondary, 1fr)); - } - } -} diff --git a/dist/layout-style-css.css b/dist/layout-style-css.css index f3e14ad..0460629 100644 --- a/dist/layout-style-css.css +++ b/dist/layout-style-css.css @@ -1,11 +1,11 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; -/* layout-style-css bundle. Generated from focused styles/ modules by scripts/build.mjs. */ +/* layout-style-css v3 bundle. Generated from focused styles/ modules. */ -/* wrappers.css */ +/* foundation.css */ /* - Shared structural tokens and wrapper geometry. Theme, type, borders, shadows, - and interactive states remain outside Layout Style's ownership boundary. + Foundation owns only shared spatial tokens, containment, and defensive + sizing. Theme and interaction libraries remain responsible for paint. */ @layer ly.tokens { @@ -25,57 +25,105 @@ --ly-wrapper-prose: 68ch; --ly-wrapper-content: 72rem; --ly-wrapper-wide: 112rem; - --ly-wrapper-max: var(--ly-wrapper-content); --ly-page-padding-inline: clamp(1rem, 4vw, 3rem); --ly-safe-area-inline: max( env(safe-area-inset-left, 0px), env(safe-area-inset-right, 0px) ); + --ly-safe-area-block-start: env(safe-area-inset-top, 0px); + --ly-safe-area-block-end: env(safe-area-inset-bottom, 0px); --ly-wrapper-gutter: max(var(--ly-page-padding-inline), var(--ly-safe-area-inline)); - --ly-section-padding-block: clamp(3rem, 7vw, 6rem); - --ly-gap: var(--ly-space-5); + --ly-profile-gap: var(--ly-space-5); + --ly-gap: var(--ly-profile-gap); --ly-grid-gap: var(--ly-gap); --ly-stack-gap: var(--ly-space-4); --ly-cluster-gap: var(--ly-space-3); - --ly-cover-min: 100svh; + --ly-section-padding-block: clamp(3rem, 7vh, 6rem); + --ly-header-height: 4.5rem; + --ly-sticky-position: sticky; + --ly-cover-min: 100dvh; + --ly-shell-min: 100dvh; + --ly-scroll-max: min(70dvh, 50rem); + --ly-switcher-threshold: 42rem; --ly-sidebar-size: 18rem; --ly-sidebar-content-min: 50%; --ly-grid-columns: 12; --ly-grid-min: 16rem; + --ly-split-min: 20rem; + --ly-pane-min: 18rem; --ly-pane-size: 22rem; + --ly-media-min: 18rem; --ly-media-size: 14rem; --ly-reel-item-min: 16rem; --ly-reel-item-max: 28rem; - --ly-scroll-max: 70svh; --ly-frame-ratio: 16 / 9; --ly-recipe-rail: 18rem; --ly-recipe-aside: 22rem; - --ly-card-grid-min: 16rem; --ly-gallery-min: 12rem; - --ly-card-size-sm: 10rem; - --ly-card-size-md: 14rem; - --ly-card-size-lg: 18rem; - --ly-header-height: 4.5rem; - --ly-z-header: 20; - - /* V1 token aliases remain available so legacy selectors can preserve sizing. */ - --ly-container-sm: var(--ly-wrapper-compact); - --ly-container-md: 56rem; - --ly-container-lg: var(--ly-wrapper-content); - --ly-container-xl: 88rem; - --ly-container-wide: var(--ly-wrapper-wide); - --ly-container-max: var(--ly-container-lg); - --ly-content-readable: var(--ly-wrapper-prose); - --ly-carousel-item-min: var(--ly-reel-item-min); - --ly-carousel-item-max: var(--ly-reel-item-max); - --ly-sidebar-min: 14rem; - --ly-sidebar-width: var(--ly-recipe-rail); - --ly-sidebar-max: var(--ly-recipe-aside); - --ly-pane-fixed: var(--ly-pane-size); - --ly-z-sidebar: 10; + --ly-card-grid-min: 16rem; + + --ly-app-shell-medium-areas: + "header header" + "sidebar main" + "aside main" + "footer footer"; + --ly-app-shell-medium-columns: + minmax(min(100%, var(--ly-recipe-rail)), auto) + minmax(0, 1fr); + --ly-app-shell-wide-areas: + "sidebar header header" + "sidebar main aside" + "sidebar footer footer"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), auto) + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); + + --ly-dashboard-medium-areas: + "header header" + "nav nav" + "main aside" + "footer footer"; + --ly-dashboard-medium-columns: + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); + --ly-dashboard-wide-areas: + "nav header header" + "nav main aside" + "nav footer footer"; + --ly-dashboard-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), auto) + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); + + --ly-docs-wide-areas: + "header header" + "nav main" + "nav aside" + "footer footer"; + --ly-docs-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), auto) + minmax(0, 1fr); + --ly-list-detail-wide-areas: + "primary secondary" + "actions actions"; + --ly-list-detail-wide-columns: + minmax(min(100%, var(--ly-pane-size)), 0.7fr) + minmax(0, 1fr); + --ly-split-hero-wide-areas: + "content media" + "actions media"; + --ly-split-hero-wide-columns: + minmax(0, var(--ly-split-primary, 1fr)) + minmax(0, var(--ly-split-secondary, 1fr)); + + container-name: ly-scope; + container-type: inline-size; + min-inline-size: 0; + min-block-size: 0; } } @@ -86,45 +134,77 @@ } :where(.ly-root) { - min-inline-size: 0; margin: 0; } :where(.ly-root img), :where(.ly-root svg), :where(.ly-root video), - :where(.ly-root canvas) { + :where(.ly-root canvas), + :where(.ly-root iframe) { max-inline-size: 100%; } } +@layer ly.tokens { + @media (max-height: 44rem) { + :where(.ly-root) { + --ly-gap: min(var(--ly-profile-gap), var(--ly-space-4)); + --ly-grid-gap: var(--ly-gap); + --ly-stack-gap: min(var(--ly-space-4), 3dvh); + --ly-cluster-gap: min(var(--ly-space-3), 2dvh); + --ly-section-padding-block: clamp(1.5rem, 6dvh, 3rem); + --ly-header-height: 3.5rem; + --ly-scroll-max: min(62dvh, 34rem); + } + } + + @media (max-height: 30rem) { + :where(.ly-root) { + --ly-cover-min: auto; + --ly-shell-min: auto; + --ly-sticky-position: static; + --ly-section-padding-block: var(--ly-space-5); + --ly-scroll-max: max(12rem, calc(100dvh - 8rem)); + } + } +} + +/* wrappers.css */ +/* Wrappers provide fluid measures and become the nearest responsive scope. */ + @layer ly.wrappers { .ly-wrapper { - /* Personalities provide only the plain-wrapper default; explicit variants stay authoritative. */ --ly-wrapper-max: var(--ly-personality-wrapper-max, var(--ly-wrapper-content)); + --ly-wrapper-fluid-gutter: clamp(1rem, 3vw, 3rem); + --ly-wrapper-fluid-gutter: clamp(1rem, 3cqi, 3rem); + --ly-wrapper-local-gutter: max( + var(--ly-wrapper-fluid-gutter), + var(--ly-safe-area-inline) + ); - /* Symmetric safe-area compensation keeps logical gutters stable in either direction. */ - container-name: ly-wrapper; + container-name: ly-scope; container-type: inline-size; - inline-size: min(100%, calc(var(--ly-wrapper-max) + (var(--ly-wrapper-gutter) * 2))); + inline-size: min(100%, calc(var(--ly-wrapper-max) + (var(--ly-wrapper-local-gutter) * 2))); + max-inline-size: 100%; margin-inline: auto; - padding-inline: var(--ly-wrapper-gutter); + padding-inline: var(--ly-wrapper-local-gutter); } .ly-wrapper--compact { - --ly-wrapper-max: 40rem; + --ly-wrapper-max: var(--ly-wrapper-compact); } .ly-wrapper--prose { - --ly-wrapper-max: 68ch; + --ly-wrapper-max: var(--ly-wrapper-prose); } .ly-wrapper--content { - --ly-wrapper-max: 72rem; + --ly-wrapper-max: var(--ly-wrapper-content); } .ly-wrapper--wide { - --ly-wrapper-max: 112rem; + --ly-wrapper-max: var(--ly-wrapper-wide); } .ly-wrapper--full { @@ -132,18 +212,19 @@ } .ly-wrapper--breakout { + --ly-wrapper-max: 100%; --ly-breakout-content-size: min( var(--ly-wrapper-content), - calc(100% - (var(--ly-wrapper-gutter) * 2)) + calc(100% - (var(--ly-wrapper-local-gutter) * 2)) ); --ly-breakout-feature-size: min( var(--ly-wrapper-wide), - calc(100% - (var(--ly-wrapper-gutter) * 2)) + calc(100% - (var(--ly-wrapper-local-gutter) * 2)) ); display: grid; grid-template-columns: - [full-start] minmax(min(100%, var(--ly-wrapper-gutter)), 1fr) + [full-start] minmax(min(100%, var(--ly-wrapper-local-gutter)), 1fr) [feature-start] minmax( 0, calc((var(--ly-breakout-feature-size) - var(--ly-breakout-content-size)) / 2) @@ -153,7 +234,7 @@ 0, calc((var(--ly-breakout-feature-size) - var(--ly-breakout-content-size)) / 2) ) - [feature-end] minmax(min(100%, var(--ly-wrapper-gutter)), 1fr) [full-end]; + [feature-end] minmax(min(100%, var(--ly-wrapper-local-gutter)), 1fr) [full-end]; inline-size: 100%; padding-inline: 0; } @@ -161,6 +242,7 @@ .ly-wrapper--breakout > * { grid-column: content; min-inline-size: 0; + max-inline-size: 100%; } .ly-wrapper--breakout > :where(.ly-lane--content, [data-ly-lane="content"]) { @@ -177,11 +259,14 @@ } /* primitives.css */ -/* Reusable composition primitives own flow and sizing only. */ +/* Composition primitives use intrinsic sizing so their content chooses reflow points. */ @layer ly.primitives { .ly-page { - min-block-size: 100svh; + min-block-size: 100vh; + min-block-size: 100dvh; + padding-block-start: var(--ly-safe-area-block-start); + padding-block-end: var(--ly-safe-area-block-end); } .ly-header, @@ -198,9 +283,9 @@ } .ly-header--sticky { - position: sticky; + position: var(--ly-sticky-position); inset-block-start: 0; - z-index: var(--ly-z-header); + z-index: var(--ly-z-header, 20); } .ly-section { @@ -240,6 +325,7 @@ .ly-cover { display: flex; flex-direction: column; + min-block-size: 100vh; min-block-size: var(--ly-cover-min); padding-block: var(--ly-cover-padding, var(--ly-space-5)); } @@ -269,6 +355,7 @@ .ly-sidebar > :where(.ly-sidebar__side, [data-ly-sidebar="side"]) { flex-basis: var(--ly-sidebar-size); flex-grow: 1; + min-inline-size: min(100%, var(--ly-sidebar-size)); } .ly-sidebar > :where(.ly-sidebar__content, [data-ly-sidebar="content"]) { @@ -279,55 +366,44 @@ .ly-grid { display: grid; - grid-template-columns: repeat(var(--ly-grid-columns), minmax(0, 1fr)); - gap: var(--ly-grid-gap); - } - - .ly-grid--auto { grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-grid-min)), 1fr)); + gap: var(--ly-grid-gap); } - .ly-grid > *, - .ly-split > *, - .ly-panes > *, - .ly-media > * { - min-inline-size: 0; + .ly-grid--fixed { + grid-template-columns: repeat(var(--ly-grid-columns), minmax(0, 1fr)); } .ly-split { display: grid; - grid-template-columns: minmax(0, 1fr); + grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-split-min)), 1fr)); gap: var(--ly-gap); align-items: var(--ly-split-align, center); } .ly-panes { display: grid; - grid-template-columns: minmax(0, 1fr); + grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-pane-min)), 1fr)); gap: var(--ly-gap); } .ly-media { display: grid; - grid-template-areas: - "media" - "content" - "actions"; - grid-template-columns: minmax(0, 1fr); + grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-media-min)), 1fr)); gap: var(--ly-gap); align-items: var(--ly-media-align, start); } - .ly-media > :where(.ly-media__asset, [data-ly-media="asset"]) { - grid-area: media; - } - - .ly-media > :where(.ly-media__content, [data-ly-media="content"]) { - grid-area: content; + .ly-media > :where(.ly-media__actions, [data-ly-media="actions"]) { + min-inline-size: min(100%, var(--ly-media-size)); } - .ly-media > :where(.ly-media__actions, [data-ly-media="actions"]) { - grid-area: actions; + .ly-grid > *, + .ly-split > *, + .ly-panes > *, + .ly-media > * { + min-inline-size: 0; + min-block-size: 0; } .ly-reel { @@ -336,7 +412,6 @@ grid-auto-columns: minmax(min(100%, var(--ly-reel-item-min)), var(--ly-reel-item-max)); gap: var(--ly-grid-gap); overflow-x: auto; - overflow-inline: auto; overscroll-behavior-inline: contain; scroll-snap-type: inline proximity; } @@ -360,72 +435,48 @@ .ly-scroll { min-block-size: 0; max-block-size: var(--ly-scroll-max); - overflow: auto; - overscroll-behavior: contain; - } - - /* Unsupported container-query browsers retain this safe DOM-order stack. */ -} - -@layer ly.primitives { - @container (min-width: 48rem) { - .ly-split { - grid-template-columns: minmax(0, var(--ly-split-primary, 1fr)) minmax(0, var(--ly-split-secondary, 1fr)); - } - - .ly-panes--2 { - grid-template-columns: minmax(0, 1fr) minmax(min(100%, var(--ly-pane-size)), 0.7fr); - } - - .ly-media { - grid-template-areas: - "media content" - "media actions"; - grid-template-columns: minmax(min(100%, var(--ly-media-size)), auto) minmax(0, 1fr); - } - } - - @container (min-width: 64rem) { - .ly-panes--3 { - grid-template-columns: - minmax(min(100%, var(--ly-pane-rail, 14rem)), 0.35fr) - minmax(0, 1fr) - minmax(min(100%, var(--ly-pane-rail, 14rem)), 0.35fr); - } + overflow-y: auto; + overscroll-behavior-block: contain; } } /* recipes.css */ /* - Built-in recipes follow semantic mobile DOM order. Wider arrangements use - named areas so visual placement never changes keyboard or reading order. + Recipes preserve the narrow-screen DOM order. Automatic topology queries + consume inherited profile tokens and can be disabled per recipe. */ @layer ly.recipes { - :where(.ly-app-shell, [data-ly-recipe="app-shell"]), - :where(.ly-dashboard, [data-ly-recipe="dashboard"]), - :where(.ly-docs, [data-ly-recipe="docs"]), - :where(.ly-list-detail, [data-ly-recipe="list-detail"]), - :where(.ly-split-hero, [data-ly-recipe="split-hero"]), - :where(.ly-gallery, [data-ly-recipe="gallery"]), - :where(.ly-card-grid, [data-ly-recipe="card-grid"]) { - container-name: ly-recipe; + :where( + [data-ly-recipe="app-shell"], + [data-ly-recipe="dashboard"], + [data-ly-recipe="docs"], + [data-ly-recipe="list-detail"], + [data-ly-recipe="split-hero"], + [data-ly-recipe="gallery"], + [data-ly-recipe="card-grid"] + ) { + container-name: ly-scope; container-type: inline-size; min-inline-size: 0; + min-block-size: 0; } - :where(.ly-app-shell, [data-ly-recipe="app-shell"]), - :where(.ly-dashboard, [data-ly-recipe="dashboard"]), - :where(.ly-docs, [data-ly-recipe="docs"]), - :where(.ly-list-detail, [data-ly-recipe="list-detail"]), - :where(.ly-split-hero, [data-ly-recipe="split-hero"]) { + :where( + [data-ly-recipe="app-shell"], + [data-ly-recipe="dashboard"], + [data-ly-recipe="docs"], + [data-ly-recipe="list-detail"], + [data-ly-recipe="split-hero"] + ) { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--ly-gap); } - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - min-block-size: 100svh; + [data-ly-recipe="app-shell"] { + min-block-size: 100vh; + min-block-size: var(--ly-shell-min); grid-template-areas: "header" "sidebar" @@ -435,7 +486,8 @@ grid-template-rows: auto auto minmax(0, 1fr) auto auto; } - :where(.ly-dashboard, [data-ly-recipe="dashboard"]) { + [data-ly-recipe="dashboard"], + [data-ly-recipe="docs"] { grid-template-areas: "header" "nav" @@ -444,23 +496,14 @@ "footer"; } - :where(.ly-docs, [data-ly-recipe="docs"]) { - grid-template-areas: - "header" - "nav" - "main" - "aside" - "footer"; - } - - :where(.ly-list-detail, [data-ly-recipe="list-detail"]) { + [data-ly-recipe="list-detail"] { grid-template-areas: "primary" "secondary" "actions"; } - :where(.ly-split-hero, [data-ly-recipe="split-hero"]) { + [data-ly-recipe="split-hero"] { grid-template-areas: "content" "media" @@ -468,279 +511,156 @@ align-items: var(--ly-split-hero-align, center); } - :where(.ly-gallery, [data-ly-recipe="gallery"]), - :where(.ly-card-grid, [data-ly-recipe="card-grid"]) { + [data-ly-recipe="gallery"], + [data-ly-recipe="card-grid"] { display: grid; gap: var(--ly-grid-gap); } - :where(.ly-gallery, [data-ly-recipe="gallery"]) { + [data-ly-recipe="gallery"] { grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-gallery-min)), 1fr)); } - :where(.ly-card-grid, [data-ly-recipe="card-grid"]) { + [data-ly-recipe="card-grid"] { grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-card-grid-min)), 1fr)); } - :where(.ly-gallery, [data-ly-recipe="gallery"]) > *, - :where(.ly-card-grid, [data-ly-recipe="card-grid"]) > * { + :where( + [data-ly-recipe="app-shell"], + [data-ly-recipe="dashboard"], + [data-ly-recipe="docs"], + [data-ly-recipe="list-detail"], + [data-ly-recipe="split-hero"], + [data-ly-recipe="gallery"], + [data-ly-recipe="card-grid"] + ) > * { min-inline-size: 0; + min-block-size: 0; } - :where(.ly-area--header, [data-ly-area="header"]) { + [data-ly-area="header"] { grid-area: header; - min-inline-size: 0; } - :where(.ly-area--nav, [data-ly-area="nav"]) { + [data-ly-area="nav"] { grid-area: nav; - min-inline-size: 0; } - :where(.ly-area--main, [data-ly-area="main"]) { + [data-ly-area="sidebar"] { + grid-area: sidebar; + } + + [data-ly-area="main"] { grid-area: main; - min-inline-size: 0; } - :where(.ly-area--aside, [data-ly-area="aside"]) { + [data-ly-area="aside"] { grid-area: aside; - min-inline-size: 0; } - :where(.ly-area--footer, [data-ly-area="footer"]) { + [data-ly-area="footer"] { grid-area: footer; - min-inline-size: 0; } - :where(.ly-area--content, [data-ly-area="content"]) { + [data-ly-area="content"] { grid-area: content; - min-inline-size: 0; } - :where(.ly-area--media, [data-ly-area="media"]) { + [data-ly-area="media"] { grid-area: media; - min-inline-size: 0; } - :where(.ly-area--actions, [data-ly-area="actions"]) { + [data-ly-area="actions"] { grid-area: actions; - min-inline-size: 0; } - :where(.ly-area--primary, [data-ly-area="primary"]) { + [data-ly-area="primary"] { grid-area: primary; - min-inline-size: 0; } - :where(.ly-area--secondary, [data-ly-area="secondary"]) { + [data-ly-area="secondary"] { grid-area: secondary; - min-inline-size: 0; - } - - .ly-app-header { - grid-area: header; - min-inline-size: 0; - } - - .ly-app-sidebar { - grid-area: sidebar; - min-inline-size: 0; } - .ly-app-main { - grid-area: main; - min-inline-size: 0; - } - - .ly-app-aside { - grid-area: aside; - min-inline-size: 0; - } - - .ly-app-footer { - grid-area: footer; - min-inline-size: 0; - } - - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) - > :where(.ly-area--nav, [data-ly-area="nav"]) { - grid-area: sidebar; - } - - /* - A recipe responds to its nearest ancestor container and then becomes the - containment scope for nested compositions. Standalone roots keep the safe - mobile template when no ancestor container is present. - */ - @container (min-width: 48rem) { - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header" - "sidebar main" - "aside main" - "footer footer"; - grid-template-columns: minmax(min(100%, var(--ly-recipe-rail)), auto) minmax(0, 1fr); - } - - :where(.ly-dashboard, [data-ly-recipe="dashboard"]) { - grid-template-areas: - "header header" - "nav nav" - "main aside" - "footer footer"; - grid-template-columns: minmax(0, 1fr) minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); - } - - :where(.ly-docs, [data-ly-recipe="docs"]) { - grid-template-areas: - "header header" - "nav main" - "nav aside" - "footer footer"; - grid-template-columns: minmax(min(100%, var(--ly-recipe-rail)), auto) minmax(0, 1fr); - } - - :where(.ly-list-detail, [data-ly-recipe="list-detail"]) { - grid-template-areas: - "primary secondary" - "actions actions"; - grid-template-columns: minmax(min(100%, var(--ly-pane-size)), 0.7fr) minmax(0, 1fr); - } - - :where(.ly-split-hero, [data-ly-recipe="split-hero"]) { - grid-template-areas: - "content media" - "actions media"; - grid-template-columns: minmax(0, var(--ly-split-primary, 1fr)) minmax(0, var(--ly-split-secondary, 1fr)); - } - - :where(.ly-gallery, [data-ly-recipe="gallery"]) { - --ly-gallery-min: 14rem; - } - - :where(.ly-card-grid, [data-ly-recipe="card-grid"]) { - --ly-card-grid-min: 18rem; + @container ly-scope (min-width: 42rem) { + [data-ly-recipe="split-hero"]:not([data-ly-responsive="manual"]) { + grid-template-areas: var(--ly-split-hero-wide-areas); + grid-template-columns: var(--ly-split-hero-wide-columns); } } - @container (min-width: 64rem) { - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header header" - "sidebar main aside" - "sidebar footer footer"; - grid-template-columns: - minmax(min(100%, var(--ly-recipe-rail)), auto) - minmax(0, 1fr) - minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); - } - - :where(.ly-dashboard, [data-ly-recipe="dashboard"]) { - grid-template-areas: - "nav header header" - "nav main aside" - "nav footer footer"; - grid-template-columns: - minmax(min(100%, var(--ly-recipe-rail)), auto) - minmax(0, 1fr) - minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); + @container ly-scope (min-width: 44rem) { + [data-ly-recipe="list-detail"]:not([data-ly-responsive="manual"]) { + grid-template-areas: var(--ly-list-detail-wide-areas); + grid-template-columns: var(--ly-list-detail-wide-columns); } + } - :where(.ly-docs, [data-ly-recipe="docs"]) { - grid-template-areas: - "nav header" - "nav main" - "nav aside" - "nav footer"; - grid-template-columns: minmax(min(100%, var(--ly-recipe-rail)), auto) minmax(0, 1fr); + @container ly-scope (min-width: 48rem) { + [data-ly-recipe="docs"]:not([data-ly-responsive="manual"]) { + grid-template-areas: var(--ly-docs-wide-areas); + grid-template-columns: var(--ly-docs-wide-columns); } + } - :where(.ly-list-detail, [data-ly-recipe="list-detail"]) { - grid-template-columns: minmax(min(100%, var(--ly-pane-size)), 0.45fr) minmax(0, 1fr); + @container ly-scope (min-width: 52rem) { + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]) { + grid-template-areas: var(--ly-app-shell-medium-areas); + grid-template-columns: var(--ly-app-shell-medium-columns); } - :where(.ly-split-hero, [data-ly-recipe="split-hero"]) { - grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); + [data-ly-recipe="dashboard"]:not([data-ly-responsive="manual"]) { + grid-template-areas: var(--ly-dashboard-medium-areas); + grid-template-columns: var(--ly-dashboard-medium-columns); } + } - :where(.ly-gallery, [data-ly-recipe="gallery"]) { - --ly-gallery-min: 16rem; + @container ly-scope (min-width: 72rem) { + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]) { + grid-template-areas: var(--ly-app-shell-wide-areas); + grid-template-columns: var(--ly-app-shell-wide-columns); } - :where(.ly-card-grid, [data-ly-recipe="card-grid"]) { - --ly-card-grid-min: 20rem; + [data-ly-recipe="dashboard"]:not([data-ly-responsive="manual"]) { + grid-template-areas: var(--ly-dashboard-wide-areas); + grid-template-columns: var(--ly-dashboard-wide-columns); } } } /* utilities.css */ +/* Optional structural utilities expose direct token overrides without breakpoint tiers. */ + @layer ly.utilities { .ly-cols-1 { --ly-grid-columns: 1; } .ly-cols-2 { --ly-grid-columns: 2; } .ly-cols-3 { --ly-grid-columns: 3; } .ly-cols-4 { --ly-grid-columns: 4; } - .ly-cols-5 { --ly-grid-columns: 5; } .ly-cols-6 { --ly-grid-columns: 6; } - .ly-cols-7 { --ly-grid-columns: 7; } - .ly-cols-8 { --ly-grid-columns: 8; } - .ly-cols-9 { --ly-grid-columns: 9; } - .ly-cols-10 { --ly-grid-columns: 10; } - .ly-cols-11 { --ly-grid-columns: 11; } .ly-cols-12 { --ly-grid-columns: 12; } - .ly-cols-16 { --ly-grid-columns: 16; } .ly-span-1 { grid-column: span 1; } .ly-span-2 { grid-column: span 2; } .ly-span-3 { grid-column: span 3; } .ly-span-4 { grid-column: span 4; } - .ly-span-5 { grid-column: span 5; } - .ly-span-6 { grid-column: span 6; } - .ly-span-7 { grid-column: span 7; } - .ly-span-8 { grid-column: span 8; } - .ly-span-9 { grid-column: span 9; } - .ly-span-10 { grid-column: span 10; } - .ly-span-11 { grid-column: span 11; } - .ly-span-12 { grid-column: span 12; } - .ly-span-13 { grid-column: span 13; } - .ly-span-14 { grid-column: span 14; } - .ly-span-15 { grid-column: span 15; } - .ly-span-16 { grid-column: span 16; } .ly-span-full { grid-column: 1 / -1; } - .ly-gap-0 { --ly-gap: var(--ly-space-0); --ly-grid-gap: var(--ly-space-0); --ly-stack-gap: var(--ly-space-0); --ly-cluster-gap: var(--ly-space-0); } - .ly-gap-1 { --ly-gap: var(--ly-space-1); --ly-grid-gap: var(--ly-space-1); --ly-stack-gap: var(--ly-space-1); --ly-cluster-gap: var(--ly-space-1); } - .ly-gap-2 { --ly-gap: var(--ly-space-2); --ly-grid-gap: var(--ly-space-2); --ly-stack-gap: var(--ly-space-2); --ly-cluster-gap: var(--ly-space-2); } - .ly-gap-3 { --ly-gap: var(--ly-space-3); --ly-grid-gap: var(--ly-space-3); --ly-stack-gap: var(--ly-space-3); --ly-cluster-gap: var(--ly-space-3); } - .ly-gap-4 { --ly-gap: var(--ly-space-4); --ly-grid-gap: var(--ly-space-4); --ly-stack-gap: var(--ly-space-4); --ly-cluster-gap: var(--ly-space-4); } - .ly-gap-5 { --ly-gap: var(--ly-space-5); --ly-grid-gap: var(--ly-space-5); --ly-stack-gap: var(--ly-space-5); --ly-cluster-gap: var(--ly-space-5); } - .ly-gap-6 { --ly-gap: var(--ly-space-6); --ly-grid-gap: var(--ly-space-6); --ly-stack-gap: var(--ly-space-6); --ly-cluster-gap: var(--ly-space-6); } - .ly-gap-7 { --ly-gap: var(--ly-space-7); --ly-grid-gap: var(--ly-space-7); --ly-stack-gap: var(--ly-space-7); --ly-cluster-gap: var(--ly-space-7); } - .ly-gap-8 { --ly-gap: var(--ly-space-8); --ly-grid-gap: var(--ly-space-8); --ly-stack-gap: var(--ly-space-8); --ly-cluster-gap: var(--ly-space-8); } - .ly-gap-9 { --ly-gap: var(--ly-space-9); --ly-grid-gap: var(--ly-space-9); --ly-stack-gap: var(--ly-space-9); --ly-cluster-gap: var(--ly-space-9); } + .ly-gap-0 { --ly-gap: var(--ly-space-0); --ly-grid-gap: var(--ly-space-0); } + .ly-gap-2 { --ly-gap: var(--ly-space-2); --ly-grid-gap: var(--ly-space-2); } + .ly-gap-4 { --ly-gap: var(--ly-space-4); --ly-grid-gap: var(--ly-space-4); } + .ly-gap-6 { --ly-gap: var(--ly-space-6); --ly-grid-gap: var(--ly-space-6); } + .ly-gap-8 { --ly-gap: var(--ly-space-8); --ly-grid-gap: var(--ly-space-8); } .ly-pad-0 { padding: var(--ly-space-0); } - .ly-pad-1 { padding: var(--ly-space-1); } .ly-pad-2 { padding: var(--ly-space-2); } - .ly-pad-3 { padding: var(--ly-space-3); } .ly-pad-4 { padding: var(--ly-space-4); } - .ly-pad-5 { padding: var(--ly-space-5); } .ly-pad-6 { padding: var(--ly-space-6); } - .ly-pad-7 { padding: var(--ly-space-7); } .ly-pad-8 { padding: var(--ly-space-8); } - .ly-pad-9 { padding: var(--ly-space-9); } - - .ly-px-4 { padding-inline: var(--ly-space-4); } - .ly-px-6 { padding-inline: var(--ly-space-6); } - .ly-px-8 { padding-inline: var(--ly-space-8); } - .ly-py-4 { padding-block: var(--ly-space-4); } - .ly-py-6 { padding-block: var(--ly-space-6); } - .ly-py-8 { padding-block: var(--ly-space-8); } .ly-mx-auto { margin-inline: auto; } .ly-w-full { inline-size: 100%; } .ly-h-full { block-size: 100%; } - .ly-min-h-screen { min-block-size: 100svh; } - .ly-bleed { inline-size: 100vw; margin-inline: calc(50% - 50vw); } + .ly-min-h-screen { min-block-size: 100vh; min-block-size: 100dvh; } .ly-overflow-auto { overflow: auto; } .ly-overflow-hidden { overflow: hidden; } @@ -754,16 +674,12 @@ .ly-justify-between { justify-content: space-between; } .ly-frame-1x1 { --ly-frame-ratio: 1 / 1; } - .ly-frame-2x1 { --ly-frame-ratio: 2 / 1; } .ly-frame-3x2 { --ly-frame-ratio: 3 / 2; } .ly-frame-4x3 { --ly-frame-ratio: 4 / 3; } .ly-frame-16x9 { --ly-frame-ratio: 16 / 9; } .ly-frame-21x9 { --ly-frame-ratio: 21 / 9; } - .ly-hidden { display: none !important; } - - .ly-show-md-up, - .ly-show-lg-up { + .ly-hidden { display: none !important; } @@ -778,774 +694,332 @@ clip-path: inset(50%) !important; white-space: nowrap !important; } - - /* Explicit escape hatches require consumers to verify focus and reading order. */ - .ly-order-first { order: -1; } - .ly-order-normal { order: 0; } - .ly-order-last { order: 999; } - .ly-order-1 { order: 1; } - .ly-order-2 { order: 2; } - .ly-order-3 { order: 3; } - .ly-order-4 { order: 4; } - .ly-order-5 { order: 5; } - .ly-order-6 { order: 6; } - - @container (min-width: 48rem) { - .ly-md-cols-1 { --ly-grid-columns: 1; } - .ly-md-cols-2 { --ly-grid-columns: 2; } - .ly-md-cols-3 { --ly-grid-columns: 3; } - .ly-md-cols-4 { --ly-grid-columns: 4; } - .ly-md-cols-6 { --ly-grid-columns: 6; } - .ly-md-cols-8 { --ly-grid-columns: 8; } - .ly-md-cols-12 { --ly-grid-columns: 12; } - .ly-md-cols-16 { --ly-grid-columns: 16; } - .ly-show-md-up { display: revert !important; } - - .ly-md-order-first { order: -1; } - .ly-md-order-normal { order: 0; } - .ly-md-order-last { order: 999; } - .ly-md-order-1 { order: 1; } - .ly-md-order-2 { order: 2; } - .ly-md-order-3 { order: 3; } - .ly-md-order-4 { order: 4; } - .ly-md-order-5 { order: 5; } - .ly-md-order-6 { order: 6; } - } - - @container (min-width: 64rem) { - .ly-lg-cols-1 { --ly-grid-columns: 1; } - .ly-lg-cols-2 { --ly-grid-columns: 2; } - .ly-lg-cols-3 { --ly-grid-columns: 3; } - .ly-lg-cols-4 { --ly-grid-columns: 4; } - .ly-lg-cols-6 { --ly-grid-columns: 6; } - .ly-lg-cols-8 { --ly-grid-columns: 8; } - .ly-lg-cols-12 { --ly-grid-columns: 12; } - .ly-lg-cols-16 { --ly-grid-columns: 16; } - .ly-show-lg-up { display: revert !important; } - - .ly-lg-order-first { order: -1; } - .ly-lg-order-normal { order: 0; } - .ly-lg-order-last { order: 999; } - .ly-lg-order-1 { order: 1; } - .ly-lg-order-2 { order: 2; } - .ly-lg-order-3 { order: 3; } - .ly-lg-order-4 { order: 4; } - .ly-lg-order-5 { order: 5; } - .ly-lg-order-6 { order: 6; } - } } /* personalities/minimal-saas.css */ -/* Layout style: minimal-saas. A measured left rail keeps work areas predictable. */ - -@layer ly.personalities.minimal_saas { +@layer ly.personalities.minimal-saas { :where(.ly-root[data-ly-layout="minimal-saas"]) { + --ly-personality-wrapper-max: 88rem; + --ly-profile-gap: var(--ly-space-5); + --ly-grid-min: 16rem; --ly-recipe-rail: 15rem; --ly-recipe-aside: 16rem; - --ly-grid-columns: 4; - --ly-grid-min: 16rem; - --ly-personality-wrapper-max: 88rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="minimal-saas"]) .ly-grid > :nth-child(4n + 1) { - grid-column: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="minimal-saas"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header header" - "sidebar main aside" - "sidebar footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 15rem), 0.24fr) - minmax(0, 1fr) - minmax(min(100%, 16rem), 0.28fr); - } + --ly-split-primary: 1.05fr; + --ly-split-secondary: 0.95fr; } } /* personalities/bento.css */ -/* Layout style: bento. A full-width shell and staggered spans form modular tiles. */ - @layer ly.personalities.bento { :where(.ly-root[data-ly-layout="bento"]) { - --ly-grid-columns: 6; - --ly-grid-min: 12rem; - --ly-card-grid-min: 13rem; --ly-personality-wrapper-max: 112rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="bento"]) .ly-grid > :nth-child(6n + 1) { - grid-column: span 2; - grid-row: span 2; - } - - :where(.ly-root[data-ly-layout="bento"]) - :where(.ly-card-grid, [data-ly-recipe="card-grid"]) - > :nth-child(6n + 1) { - grid-column: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="bento"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header header" - "sidebar main main" - "aside main main" - "footer footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto auto; - grid-template-columns: - minmax(min(100%, 14rem), 0.3fr) - minmax(0, 1fr) - minmax(0, 1fr); - } + --ly-profile-gap: var(--ly-space-4); + --ly-grid-min: 12rem; + --ly-card-grid-min: 14rem; + --ly-gallery-min: 11rem; + --ly-recipe-rail: 14rem; + --ly-recipe-aside: 18rem; + --ly-app-shell-wide-areas: + "header header header" + "sidebar main main" + "aside main main" + "footer footer footer"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.3fr) + minmax(0, 1fr) + minmax(0, 1fr); } } /* personalities/maximalist.css */ -/* Layout style: maximalist. A full-bleed four-track mosaic favors dramatic spans. */ - @layer ly.personalities.maximalist { :where(.ly-root[data-ly-layout="maximalist"]) { - --ly-grid-columns: 12; - --ly-grid-min: 10rem; --ly-personality-wrapper-max: 100%; - --ly-card-grid-min: 12rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="maximalist"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 18rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 56rem) { - :where(.ly-root[data-ly-layout="maximalist"]) .ly-grid > :nth-child(7n + 1) { - grid-column: span 3; - grid-row: span 2; - } - - :where(.ly-root[data-ly-layout="maximalist"]) - :where(.ly-gallery, [data-ly-recipe="gallery"]) - > :nth-child(5n + 1) { - grid-column: span 2; - grid-row: span 2; - } - } - - /* The four-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="maximalist"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header header header" - "main main sidebar aside" - "main main footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(0, 1.4fr) - minmax(0, 0.6fr) - minmax(min(100%, 15rem), 0.32fr) - minmax(min(100%, 18rem), 0.38fr); - } + --ly-profile-gap: var(--ly-space-7); + --ly-grid-min: 10rem; + --ly-card-grid-min: 13rem; + --ly-gallery-min: 10rem; + --ly-recipe-rail: 15rem; + --ly-recipe-aside: 18rem; + --ly-app-shell-wide-areas: + "header header header header" + "main main sidebar aside" + "main main footer footer"; + --ly-app-shell-wide-columns: + minmax(0, 1.4fr) + minmax(0, 0.6fr) + minmax(min(100%, var(--ly-recipe-rail)), 0.32fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.38fr); } } /* personalities/bauhaus.css */ -/* Layout style: bauhaus. A left rail anchors an intentionally asymmetric grid. */ - @layer ly.personalities.bauhaus { :where(.ly-root[data-ly-layout="bauhaus"]) { + --ly-personality-wrapper-max: 96rem; + --ly-profile-gap: var(--ly-space-6); + --ly-grid-min: 13rem; --ly-recipe-rail: 14rem; --ly-recipe-aside: 18rem; - --ly-grid-columns: 6; - --ly-grid-min: 13rem; - --ly-personality-wrapper-max: 96rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - /* Cap the fallback rail until the wider personality template is eligible. */ - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="bauhaus"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 14rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 52rem) { - :where(.ly-root[data-ly-layout="bauhaus"]) .ly-grid > :nth-child(3n + 1) { - grid-column: span 2; - grid-row: span 2; - } - } - - /* The four-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="bauhaus"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header header aside" - "sidebar main main aside" - "sidebar footer footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 14rem), 0.24fr) - minmax(0, 0.7fr) - minmax(0, 1.3fr) - minmax(min(100%, 18rem), 0.3fr); - } + --ly-app-shell-wide-areas: + "header header header header" + "sidebar main main aside" + "sidebar footer footer aside"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.24fr) + minmax(0, 0.7fr) + minmax(0, 1.3fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.3fr); } } /* personalities/tactile.css */ -/* Layout style: tactile. A compact left rail leaves a broad, steady work lane. */ - @layer ly.personalities.tactile { :where(.ly-root[data-ly-layout="tactile"]) { + --ly-personality-wrapper-max: 82rem; + --ly-profile-gap: var(--ly-space-4); + --ly-grid-min: 15rem; --ly-recipe-rail: 17rem; --ly-recipe-aside: 20rem; - --ly-grid-columns: 5; - --ly-grid-min: 15rem; - --ly-personality-wrapper-max: 82rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="tactile"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header" - "sidebar main" - "sidebar aside" - "sidebar footer"; - grid-template-rows: auto minmax(0, 1fr) auto auto; - grid-template-columns: minmax(min(100%, 17rem), 0.28fr) minmax(0, 1fr); - } - - :where(.ly-root[data-ly-layout="tactile"]) .ly-grid > :nth-child(5n + 2) { - grid-column: span 2; - } - - :where(.ly-root[data-ly-layout="tactile"]) - :where(.ly-list-detail, [data-ly-recipe="list-detail"]) { - grid-template-columns: minmax(min(100%, 20rem), 0.42fr) minmax(0, 0.58fr); - } + --ly-app-shell-wide-areas: + "header header" + "sidebar main" + "aside main" + "footer footer"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.28fr) + minmax(0, 1fr); + --ly-list-detail-wide-columns: + minmax(min(100%, var(--ly-pane-size)), 0.5fr) + minmax(0, 0.9fr); } } /* personalities/neumorphism.css */ -/* Layout style: neumorphism. A calm right rail preserves a compact workspace. */ - @layer ly.personalities.neumorphism { :where(.ly-root[data-ly-layout="neumorphism"]) { + --ly-personality-wrapper-max: 84rem; + --ly-profile-gap: var(--ly-space-6); + --ly-grid-min: 17rem; --ly-recipe-rail: 17rem; --ly-recipe-aside: 19rem; - --ly-grid-columns: 4; - --ly-grid-min: 17rem; - --ly-personality-wrapper-max: 84rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="neumorphism"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 17rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 52rem) { - :where(.ly-root[data-ly-layout="neumorphism"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header sidebar" - "main sidebar" - "aside sidebar" - "footer sidebar"; - grid-template-rows: auto minmax(0, 1fr) auto auto; - grid-template-columns: minmax(0, 1fr) minmax(min(100%, 17rem), 0.3fr); - } - - :where(.ly-root[data-ly-layout="neumorphism"]) .ly-grid > :nth-child(4n + 1) { - grid-column: span 2; - } - - :where(.ly-root[data-ly-layout="neumorphism"]) - :where(.ly-list-detail, [data-ly-recipe="list-detail"]) { - grid-template-columns: minmax(0, 0.58fr) minmax(min(100%, 19rem), 0.42fr); - } + --ly-app-shell-wide-areas: + "header sidebar" + "main sidebar" + "aside sidebar" + "footer sidebar"; + --ly-app-shell-wide-columns: + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-rail)), 0.3fr); + --ly-list-detail-wide-columns: + minmax(0, 1.1fr) + minmax(min(100%, var(--ly-pane-size)), 0.7fr); } } /* personalities/retrofuturism.css */ -/* Layout style: retrofuturism. Twin rails frame a focused central work zone. */ - @layer ly.personalities.retrofuturism { :where(.ly-root[data-ly-layout="retrofuturism"]) { + --ly-personality-wrapper-max: 106rem; + --ly-profile-gap: var(--ly-space-5); + --ly-grid-min: 14rem; --ly-recipe-rail: 14rem; --ly-recipe-aside: 17rem; - --ly-grid-columns: 6; - --ly-grid-min: 14rem; - --ly-personality-wrapper-max: 106rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="retrofuturism"]) .ly-grid > :nth-child(6n + 1) { - grid-column: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="retrofuturism"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header aside" - "sidebar main aside" - "sidebar footer aside"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 14rem), 0.24fr) - minmax(0, 1fr) - minmax(min(100%, 17rem), 0.3fr); - } + --ly-app-shell-wide-areas: + "sidebar header aside" + "sidebar main aside" + "sidebar footer aside"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.24fr) + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.3fr); } } /* personalities/brutalism.css */ -/* Layout style: brutalism. A blunt right rail counters a broad primary plane. */ - @layer ly.personalities.brutalism { :where(.ly-root[data-ly-layout="brutalism"]) { - --ly-recipe-rail: 18rem; - --ly-recipe-aside: 16rem; - --ly-grid-columns: 6; - --ly-grid-min: 14rem; --ly-personality-wrapper-max: 100rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="brutalism"]) .ly-grid > :nth-child(3n) { - grid-column: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="brutalism"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header sidebar" - "main aside sidebar" - "footer footer sidebar"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(0, 1.3fr) - minmax(min(100%, 16rem), 0.7fr) - minmax(min(100%, 18rem), 0.34fr); - } + --ly-profile-gap: var(--ly-space-3); + --ly-grid-min: 14rem; + --ly-recipe-rail: 16rem; + --ly-recipe-aside: 18rem; + --ly-app-shell-wide-areas: + "header header sidebar" + "main aside sidebar" + "footer footer sidebar"; + --ly-app-shell-wide-columns: + minmax(0, 1.3fr) + minmax(0, 0.7fr) + minmax(min(100%, var(--ly-recipe-rail)), 0.34fr); } } /* personalities/cyberpunk.css */ -/* Layout style: cyberpunk. A narrow command rail fronts a dense three-lane shell. */ - @layer ly.personalities.cyberpunk { :where(.ly-root[data-ly-layout="cyberpunk"]) { + --ly-personality-wrapper-max: 112rem; + --ly-profile-gap: var(--ly-space-4); + --ly-grid-min: 12rem; --ly-recipe-rail: 13rem; --ly-recipe-aside: 19rem; - --ly-grid-columns: 8; - --ly-grid-min: 12rem; - --ly-personality-wrapper-max: 112rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 44rem) { - :where(.ly-root[data-ly-layout="cyberpunk"]) .ly-grid > :nth-child(4n + 2) { - grid-column: span 3; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="cyberpunk"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header aside" - "sidebar main aside" - "sidebar footer aside"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 13rem), 0.2fr) - minmax(0, 1fr) - minmax(min(100%, 19rem), 0.32fr); - } + --ly-app-shell-wide-areas: + "sidebar header header" + "sidebar main aside" + "sidebar footer footer"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.2fr) + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.32fr); } } /* personalities/y2k.css */ -/* Layout style: y2k. A tall right rail frames a reversed supporting workspace. */ - @layer ly.personalities.y2k { :where(.ly-root[data-ly-layout="y2k"]) { - --ly-recipe-rail: 16rem; - --ly-recipe-aside: 18rem; - --ly-grid-columns: 5; - --ly-grid-min: 13rem; --ly-personality-wrapper-max: 90rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="y2k"]) .ly-grid > :nth-child(5n + 1) { - grid-column: span 3; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="y2k"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header sidebar" - "aside main sidebar" - "footer footer sidebar"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 18rem), 0.34fr) - minmax(0, 1fr) - minmax(min(100%, 16rem), 0.28fr); - } + --ly-profile-gap: var(--ly-space-6); + --ly-grid-min: 13rem; + --ly-recipe-rail: 18rem; + --ly-recipe-aside: 16rem; + --ly-app-shell-wide-areas: + "header header sidebar" + "aside main sidebar" + "footer footer sidebar"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-aside)), 0.34fr) + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-rail)), 0.28fr); } } /* personalities/retro-glass.css */ -/* Layout style: retro-glass. A stepped right rail floats beside a wide stage. */ - -@layer ly.personalities.retro_glass { +@layer ly.personalities.retro-glass { :where(.ly-root[data-ly-layout="retro-glass"]) { - --ly-recipe-rail: 18rem; - --ly-recipe-aside: 20rem; - --ly-grid-columns: 8; - --ly-grid-min: 15rem; --ly-personality-wrapper-max: 104rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="retro-glass"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 18rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 56rem) { - :where(.ly-root[data-ly-layout="retro-glass"]) .ly-grid > :nth-child(4n) { - grid-column: span 2; - grid-row: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="retro-glass"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header sidebar" - "main main sidebar" - "aside footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(0, 1.25fr) - minmax(0, 0.75fr) - minmax(min(100%, 18rem), 0.32fr); - } + --ly-profile-gap: var(--ly-space-5); + --ly-grid-min: 15rem; + --ly-recipe-rail: 18rem; + --ly-recipe-aside: 18rem; + --ly-app-shell-wide-areas: + "header header sidebar" + "main main sidebar" + "aside footer footer"; + --ly-app-shell-wide-columns: + minmax(0, 1.25fr) + minmax(0, 0.75fr) + minmax(min(100%, var(--ly-recipe-rail)), 0.32fr); } } /* personalities/f-pattern.css */ -/* Layout style: f-pattern. A left rail supports a wide first-reading column. */ - -@layer ly.personalities.f_pattern { +@layer ly.personalities.f-pattern { :where(.ly-root[data-ly-layout="f-pattern"]) { + --ly-personality-wrapper-max: 92rem; + --ly-profile-gap: var(--ly-space-4); + --ly-grid-min: 14rem; --ly-recipe-rail: 16rem; --ly-recipe-aside: 18rem; - --ly-grid-columns: 6; - --ly-grid-min: 14rem; - --ly-personality-wrapper-max: 92rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="f-pattern"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 16rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 56rem) { - :where(.ly-root[data-ly-layout="f-pattern"]) .ly-grid > :nth-child(3n + 1) { - grid-column: span 2; - } - - :where(.ly-root[data-ly-layout="f-pattern"]) - :where(.ly-split-hero, [data-ly-recipe="split-hero"]) { - grid-template-columns: minmax(0, 1.35fr) minmax(0, 0.65fr); - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="f-pattern"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header header" - "sidebar main aside" - "sidebar footer aside"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 16rem), 0.26fr) - minmax(0, 1.35fr) - minmax(min(100%, 18rem), 0.65fr); - } + --ly-app-shell-wide-areas: + "sidebar header header" + "sidebar main aside" + "sidebar footer footer"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.26fr) + minmax(0, 1.35fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.65fr); + --ly-split-hero-wide-columns: + minmax(0, 1.8fr) + minmax(0, 0.8fr); } } /* personalities/z-pattern.css */ -/* Layout style: z-pattern. A right rail closes a diagonal reading progression. */ - -@layer ly.personalities.z_pattern { +@layer ly.personalities.z-pattern { :where(.ly-root[data-ly-layout="z-pattern"]) { + --ly-personality-wrapper-max: 108rem; + --ly-profile-gap: var(--ly-space-5); + --ly-grid-min: 14rem; --ly-recipe-rail: 17rem; --ly-recipe-aside: 19rem; - --ly-grid-columns: 8; - --ly-grid-min: 14rem; - --ly-personality-wrapper-max: 108rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="z-pattern"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 17rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 60rem) { - :where(.ly-root[data-ly-layout="z-pattern"]) .ly-grid > :nth-child(4n + 2) { - grid-column: span 2; - align-self: end; - } - - :where(.ly-root[data-ly-layout="z-pattern"]) - :where(.ly-split-hero, [data-ly-recipe="split-hero"]) { - grid-template-columns: minmax(0, 1.5fr) minmax(0, 0.5fr); - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="z-pattern"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header sidebar" - "main aside sidebar" - "footer aside sidebar"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(0, 1.45fr) - minmax(min(100%, 19rem), 0.55fr) - minmax(min(100%, 17rem), 0.3fr); - } + --ly-app-shell-wide-areas: + "header header sidebar" + "main aside sidebar" + "footer aside sidebar"; + --ly-app-shell-wide-columns: + minmax(0, 1.45fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.55fr) + minmax(min(100%, var(--ly-recipe-rail)), 0.3fr); + --ly-split-hero-wide-columns: + minmax(0, 1.5fr) + minmax(0, 0.5fr); } } /* personalities/split-screen.css */ -/* Layout style: split-screen. Equal tracks keep two primary experiences in balance. */ - -@layer ly.personalities.split_screen { +@layer ly.personalities.split-screen { :where(.ly-root[data-ly-layout="split-screen"]) { - --ly-grid-columns: 2; - --ly-grid-min: 20rem; --ly-personality-wrapper-max: 100%; - --ly-split-primary: 1fr; - --ly-split-secondary: 1fr; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="split-screen"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header" - "main sidebar" - "aside sidebar" - "footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto auto; - grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); - } - - :where(.ly-root[data-ly-layout="split-screen"]) - :where( - .ly-split, - .ly-split-hero, - [data-ly-recipe="split-hero"], - .ly-list-detail, - [data-ly-recipe="list-detail"] - ) { - grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); - } + --ly-profile-gap: var(--ly-space-4); + --ly-grid-min: 20rem; + /* + Fixed preferred halves leave a shrink-safe center track in recipes that + retain the shared three-column dashboard topology. + */ + --ly-recipe-rail: 24rem; + --ly-recipe-aside: 24rem; + --ly-app-shell-wide-areas: + "header header" + "main sidebar" + "aside sidebar" + "footer footer"; + --ly-app-shell-wide-columns: + minmax(0, 1fr) + minmax(0, 1fr); + --ly-split-hero-wide-columns: + minmax(0, 1fr) + minmax(0, 1fr); + --ly-list-detail-wide-columns: + minmax(0, 1fr) + minmax(0, 1fr); } } /* personalities/mondrian.css */ -/* Layout style: mondrian. Unequal zones and spanning blocks create a strict mosaic. */ - @layer ly.personalities.mondrian { :where(.ly-root[data-ly-layout="mondrian"]) { + --ly-personality-wrapper-max: 112rem; + --ly-profile-gap: var(--ly-space-3); + --ly-grid-min: 11rem; --ly-recipe-rail: 13rem; --ly-recipe-aside: 18rem; - --ly-grid-columns: 10; - --ly-grid-min: 11rem; - --ly-personality-wrapper-max: 112rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="mondrian"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 13rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 52rem) { - :where(.ly-root[data-ly-layout="mondrian"]) .ly-grid > :nth-child(5n + 1) { - grid-column: span 2; - grid-row: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="mondrian"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header header" - "sidebar main aside" - "footer footer aside"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 13rem), 0.22fr) - minmax(0, 1.45fr) - minmax(min(100%, 18rem), 0.55fr); - } + --ly-app-shell-wide-areas: + "sidebar header header" + "sidebar main aside" + "footer footer aside"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.22fr) + minmax(0, 1.45fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.55fr); } } /* personalities/synthwave.css */ -/* Layout style: synthwave. A cinematic center stage sits between support zones. */ - @layer ly.personalities.synthwave { :where(.ly-root[data-ly-layout="synthwave"]) { + --ly-personality-wrapper-max: 112rem; + --ly-profile-gap: var(--ly-space-6); + --ly-grid-min: 14rem; --ly-recipe-rail: 16rem; --ly-recipe-aside: 20rem; - --ly-grid-columns: 12; - --ly-grid-min: 14rem; - --ly-reel-item-max: 34rem; - --ly-personality-wrapper-max: 112rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="synthwave"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 16rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="synthwave"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header header" - "sidebar main aside" - "footer footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 16rem), 0.28fr) - minmax(0, 1fr) - minmax(min(100%, 20rem), 0.34fr); - } - - :where(.ly-root[data-ly-layout="synthwave"]) .ly-grid > :nth-child(4n + 1) { - grid-column: span 3; - } - - :where(.ly-root[data-ly-layout="synthwave"]) .ly-reel { - grid-auto-columns: minmax(min(100%, 20rem), var(--ly-reel-item-max)); - } + --ly-app-shell-wide-areas: + "header header header" + "sidebar main aside" + "footer footer footer"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.28fr) + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.34fr); + --ly-reel-item-min: 20rem; } } diff --git a/dist/layout-style-css.min.css b/dist/layout-style-css.min.css index 71f1665..e350028 100644 --- a/dist/layout-style-css.min.css +++ b/dist/layout-style-css.min.css @@ -1 +1 @@ -@layer ly.reset,ly.tokens,ly.wrappers,ly.primitives,ly.recipes,ly.utilities,ly.personalities,ly.integrations,ly.legacy;@layer ly.tokens{:where(.ly-root){--ly-space-0:0;--ly-space-1:0.25rem;--ly-space-2:0.5rem;--ly-space-3:0.75rem;--ly-space-4:1rem;--ly-space-5:1.5rem;--ly-space-6:2rem;--ly-space-7:3rem;--ly-space-8:4rem;--ly-space-9:6rem;--ly-wrapper-compact:40rem;--ly-wrapper-prose:68ch;--ly-wrapper-content:72rem;--ly-wrapper-wide:112rem;--ly-wrapper-max:var(--ly-wrapper-content);--ly-page-padding-inline:clamp(1rem,4vw,3rem);--ly-safe-area-inline:max( env(safe-area-inset-left,0px),env(safe-area-inset-right,0px) );--ly-wrapper-gutter:max(var(--ly-page-padding-inline),var(--ly-safe-area-inline));--ly-section-padding-block:clamp(3rem,7vw,6rem);--ly-gap:var(--ly-space-5);--ly-grid-gap:var(--ly-gap);--ly-stack-gap:var(--ly-space-4);--ly-cluster-gap:var(--ly-space-3);--ly-cover-min:100svh;--ly-switcher-threshold:42rem;--ly-sidebar-size:18rem;--ly-sidebar-content-min:50%;--ly-grid-columns:12;--ly-grid-min:16rem;--ly-pane-size:22rem;--ly-media-size:14rem;--ly-reel-item-min:16rem;--ly-reel-item-max:28rem;--ly-scroll-max:70svh;--ly-frame-ratio:16 / 9;--ly-recipe-rail:18rem;--ly-recipe-aside:22rem;--ly-card-grid-min:16rem;--ly-gallery-min:12rem;--ly-card-size-sm:10rem;--ly-card-size-md:14rem;--ly-card-size-lg:18rem;--ly-header-height:4.5rem;--ly-z-header:20;--ly-container-sm:var(--ly-wrapper-compact);--ly-container-md:56rem;--ly-container-lg:var(--ly-wrapper-content);--ly-container-xl:88rem;--ly-container-wide:var(--ly-wrapper-wide);--ly-container-max:var(--ly-container-lg);--ly-content-readable:var(--ly-wrapper-prose);--ly-carousel-item-min:var(--ly-reel-item-min);--ly-carousel-item-max:var(--ly-reel-item-max);--ly-sidebar-min:14rem;--ly-sidebar-width:var(--ly-recipe-rail);--ly-sidebar-max:var(--ly-recipe-aside);--ly-pane-fixed:var(--ly-pane-size);--ly-z-sidebar:10}}@layer ly.reset{:where(.ly-root),:where(.ly-root *){box-sizing:border-box}:where(.ly-root){min-inline-size:0;margin:0}:where(.ly-root img),:where(.ly-root svg),:where(.ly-root video),:where(.ly-root canvas){max-inline-size:100%}}@layer ly.wrappers{.ly-wrapper{--ly-wrapper-max:var(--ly-personality-wrapper-max,var(--ly-wrapper-content));container-name:ly-wrapper;container-type:inline-size;inline-size:min(100%,calc(var(--ly-wrapper-max) + (var(--ly-wrapper-gutter) * 2)));margin-inline:auto;padding-inline:var(--ly-wrapper-gutter)}.ly-wrapper--compact{--ly-wrapper-max:40rem}.ly-wrapper--prose{--ly-wrapper-max:68ch}.ly-wrapper--content{--ly-wrapper-max:72rem}.ly-wrapper--wide{--ly-wrapper-max:112rem}.ly-wrapper--full{--ly-wrapper-max:100%}.ly-wrapper--breakout{--ly-breakout-content-size:min( var(--ly-wrapper-content),calc(100% - (var(--ly-wrapper-gutter) * 2)) );--ly-breakout-feature-size:min( var(--ly-wrapper-wide),calc(100% - (var(--ly-wrapper-gutter) * 2)) );display:grid;grid-template-columns:[full-start] minmax(min(100%,var(--ly-wrapper-gutter)),1fr) [feature-start] minmax( 0,calc((var(--ly-breakout-feature-size) - var(--ly-breakout-content-size)) / 2) ) [content-start] minmax(0,var(--ly-breakout-content-size)) [content-end] minmax( 0,calc((var(--ly-breakout-feature-size) - var(--ly-breakout-content-size)) / 2) ) [feature-end] minmax(min(100%,var(--ly-wrapper-gutter)),1fr) [full-end];inline-size:100%;padding-inline:0}.ly-wrapper--breakout>*{grid-column:content;min-inline-size:0}.ly-wrapper--breakout>:where(.ly-lane--content,[data-ly-lane="content"]){grid-column:content}.ly-wrapper--breakout>:where(.ly-lane--feature,[data-ly-lane="feature"]){grid-column:feature}.ly-wrapper--breakout>:where(.ly-lane--full,[data-ly-lane="full"]){grid-column:full}}@layer ly.primitives{.ly-page{min-block-size:100svh}.ly-header,.ly-footer,.ly-main,.ly-section,.ly-surface{min-inline-size:0;min-block-size:0}.ly-header{min-block-size:var(--ly-header-height)}.ly-header--sticky{position:sticky;inset-block-start:0;z-index:var(--ly-z-header)}.ly-section{padding-block:var(--ly-section-padding-block)}.ly-section--compact{--ly-section-padding-block:var(--ly-space-7)}.ly-section--flush{--ly-section-padding-block:0}.ly-readable{max-inline-size:var(--ly-wrapper-prose)}.ly-stack{display:flex;flex-direction:column;gap:var(--ly-stack-gap)}.ly-cluster{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ly-cluster-gap)}.ly-center{inline-size:min(100%,var(--ly-center-max,var(--ly-wrapper-content)));margin-inline:auto}.ly-cover{display:flex;flex-direction:column;min-block-size:var(--ly-cover-min);padding-block:var(--ly-cover-padding,var(--ly-space-5))}.ly-cover>:where(.ly-cover__center,[data-ly-cover-center]){margin-block:auto}.ly-switcher{display:flex;flex-wrap:wrap;gap:var(--ly-gap)}.ly-switcher>*{flex-basis:calc((var(--ly-switcher-threshold) - 100%) * 999);flex-grow:1;min-inline-size:0}.ly-sidebar{display:flex;flex-wrap:wrap;gap:var(--ly-gap)}.ly-sidebar>:where(.ly-sidebar__side,[data-ly-sidebar="side"]){flex-basis:var(--ly-sidebar-size);flex-grow:1}.ly-sidebar>:where(.ly-sidebar__content,[data-ly-sidebar="content"]){flex-basis:0;flex-grow:999;min-inline-size:min(100%,var(--ly-sidebar-content-min))}.ly-grid{display:grid;grid-template-columns:repeat(var(--ly-grid-columns),minmax(0,1fr));gap:var(--ly-grid-gap)}.ly-grid--auto{grid-template-columns:repeat(auto-fit,minmax(min(100%,var(--ly-grid-min)),1fr))}.ly-grid>*,.ly-split>*,.ly-panes>*,.ly-media>*{min-inline-size:0}.ly-split{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--ly-gap);align-items:var(--ly-split-align,center)}.ly-panes{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--ly-gap)}.ly-media{display:grid;grid-template-areas:"media" "content" "actions";grid-template-columns:minmax(0,1fr);gap:var(--ly-gap);align-items:var(--ly-media-align,start)}.ly-media>:where(.ly-media__asset,[data-ly-media="asset"]){grid-area:media}.ly-media>:where(.ly-media__content,[data-ly-media="content"]){grid-area:content}.ly-media>:where(.ly-media__actions,[data-ly-media="actions"]){grid-area:actions}.ly-reel{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(min(100%,var(--ly-reel-item-min)),var(--ly-reel-item-max));gap:var(--ly-grid-gap);overflow-x:auto;overflow-inline:auto;overscroll-behavior-inline:contain;scroll-snap-type:inline proximity}.ly-reel>*{min-inline-size:0;scroll-snap-align:start}.ly-frame{aspect-ratio:var(--ly-frame-ratio);overflow:hidden}.ly-frame>*{inline-size:100%;block-size:100%;object-fit:cover}.ly-scroll{min-block-size:0;max-block-size:var(--ly-scroll-max);overflow:auto;overscroll-behavior:contain}}@layer ly.primitives{@container (min-width:48rem){.ly-split{grid-template-columns:minmax(0,var(--ly-split-primary,1fr)) minmax(0,var(--ly-split-secondary,1fr))}.ly-panes--2{grid-template-columns:minmax(0,1fr) minmax(min(100%,var(--ly-pane-size)),0.7fr)}.ly-media{grid-template-areas:"media content" "media actions";grid-template-columns:minmax(min(100%,var(--ly-media-size)),auto) minmax(0,1fr)}}@container (min-width:64rem){.ly-panes--3{grid-template-columns:minmax(min(100%,var(--ly-pane-rail,14rem)),0.35fr) minmax(0,1fr) minmax(min(100%,var(--ly-pane-rail,14rem)),0.35fr)}}}@layer ly.recipes{:where(.ly-app-shell,[data-ly-recipe="app-shell"]),:where(.ly-dashboard,[data-ly-recipe="dashboard"]),:where(.ly-docs,[data-ly-recipe="docs"]),:where(.ly-list-detail,[data-ly-recipe="list-detail"]),:where(.ly-split-hero,[data-ly-recipe="split-hero"]),:where(.ly-gallery,[data-ly-recipe="gallery"]),:where(.ly-card-grid,[data-ly-recipe="card-grid"]){container-name:ly-recipe;container-type:inline-size;min-inline-size:0}:where(.ly-app-shell,[data-ly-recipe="app-shell"]),:where(.ly-dashboard,[data-ly-recipe="dashboard"]),:where(.ly-docs,[data-ly-recipe="docs"]),:where(.ly-list-detail,[data-ly-recipe="list-detail"]),:where(.ly-split-hero,[data-ly-recipe="split-hero"]){display:grid;grid-template-columns:minmax(0,1fr);gap:var(--ly-gap)}:where(.ly-app-shell,[data-ly-recipe="app-shell"]){min-block-size:100svh;grid-template-areas:"header" "sidebar" "main" "aside" "footer";grid-template-rows:auto auto minmax(0,1fr) auto auto}:where(.ly-dashboard,[data-ly-recipe="dashboard"]){grid-template-areas:"header" "nav" "main" "aside" "footer"}:where(.ly-docs,[data-ly-recipe="docs"]){grid-template-areas:"header" "nav" "main" "aside" "footer"}:where(.ly-list-detail,[data-ly-recipe="list-detail"]){grid-template-areas:"primary" "secondary" "actions"}:where(.ly-split-hero,[data-ly-recipe="split-hero"]){grid-template-areas:"content" "media" "actions";align-items:var(--ly-split-hero-align,center)}:where(.ly-gallery,[data-ly-recipe="gallery"]),:where(.ly-card-grid,[data-ly-recipe="card-grid"]){display:grid;gap:var(--ly-grid-gap)}:where(.ly-gallery,[data-ly-recipe="gallery"]){grid-template-columns:repeat(auto-fit,minmax(min(100%,var(--ly-gallery-min)),1fr))}:where(.ly-card-grid,[data-ly-recipe="card-grid"]){grid-template-columns:repeat(auto-fit,minmax(min(100%,var(--ly-card-grid-min)),1fr))}:where(.ly-gallery,[data-ly-recipe="gallery"])>*,:where(.ly-card-grid,[data-ly-recipe="card-grid"])>*{min-inline-size:0}:where(.ly-area--header,[data-ly-area="header"]){grid-area:header;min-inline-size:0}:where(.ly-area--nav,[data-ly-area="nav"]){grid-area:nav;min-inline-size:0}:where(.ly-area--main,[data-ly-area="main"]){grid-area:main;min-inline-size:0}:where(.ly-area--aside,[data-ly-area="aside"]){grid-area:aside;min-inline-size:0}:where(.ly-area--footer,[data-ly-area="footer"]){grid-area:footer;min-inline-size:0}:where(.ly-area--content,[data-ly-area="content"]){grid-area:content;min-inline-size:0}:where(.ly-area--media,[data-ly-area="media"]){grid-area:media;min-inline-size:0}:where(.ly-area--actions,[data-ly-area="actions"]){grid-area:actions;min-inline-size:0}:where(.ly-area--primary,[data-ly-area="primary"]){grid-area:primary;min-inline-size:0}:where(.ly-area--secondary,[data-ly-area="secondary"]){grid-area:secondary;min-inline-size:0}.ly-app-header{grid-area:header;min-inline-size:0}.ly-app-sidebar{grid-area:sidebar;min-inline-size:0}.ly-app-main{grid-area:main;min-inline-size:0}.ly-app-aside{grid-area:aside;min-inline-size:0}.ly-app-footer{grid-area:footer;min-inline-size:0}:where(.ly-app-shell,[data-ly-recipe="app-shell"])>:where(.ly-area--nav,[data-ly-area="nav"]){grid-area:sidebar}@container (min-width:48rem){:where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-areas:"header header" "sidebar main" "aside main" "footer footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(0,1fr)}:where(.ly-dashboard,[data-ly-recipe="dashboard"]){grid-template-areas:"header header" "nav nav" "main aside" "footer footer";grid-template-columns:minmax(0,1fr) minmax(min(100%,var(--ly-recipe-aside)),0.35fr)}:where(.ly-docs,[data-ly-recipe="docs"]){grid-template-areas:"header header" "nav main" "nav aside" "footer footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(0,1fr)}:where(.ly-list-detail,[data-ly-recipe="list-detail"]){grid-template-areas:"primary secondary" "actions actions";grid-template-columns:minmax(min(100%,var(--ly-pane-size)),0.7fr) minmax(0,1fr)}:where(.ly-split-hero,[data-ly-recipe="split-hero"]){grid-template-areas:"content media" "actions media";grid-template-columns:minmax(0,var(--ly-split-primary,1fr)) minmax(0,var(--ly-split-secondary,1fr))}:where(.ly-gallery,[data-ly-recipe="gallery"]){--ly-gallery-min:14rem}:where(.ly-card-grid,[data-ly-recipe="card-grid"]){--ly-card-grid-min:18rem}}@container (min-width:64rem){:where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-areas:"sidebar header header" "sidebar main aside" "sidebar footer footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(0,1fr) minmax(min(100%,var(--ly-recipe-aside)),0.35fr)}:where(.ly-dashboard,[data-ly-recipe="dashboard"]){grid-template-areas:"nav header header" "nav main aside" "nav footer footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(0,1fr) minmax(min(100%,var(--ly-recipe-aside)),0.35fr)}:where(.ly-docs,[data-ly-recipe="docs"]){grid-template-areas:"nav header" "nav main" "nav aside" "nav footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(0,1fr)}:where(.ly-list-detail,[data-ly-recipe="list-detail"]){grid-template-columns:minmax(min(100%,var(--ly-pane-size)),0.45fr) minmax(0,1fr)}:where(.ly-split-hero,[data-ly-recipe="split-hero"]){grid-template-columns:minmax(0,0.9fr) minmax(0,1.1fr)}:where(.ly-gallery,[data-ly-recipe="gallery"]){--ly-gallery-min:16rem}:where(.ly-card-grid,[data-ly-recipe="card-grid"]){--ly-card-grid-min:20rem}}}@layer ly.utilities{.ly-cols-1{--ly-grid-columns:1}.ly-cols-2{--ly-grid-columns:2}.ly-cols-3{--ly-grid-columns:3}.ly-cols-4{--ly-grid-columns:4}.ly-cols-5{--ly-grid-columns:5}.ly-cols-6{--ly-grid-columns:6}.ly-cols-7{--ly-grid-columns:7}.ly-cols-8{--ly-grid-columns:8}.ly-cols-9{--ly-grid-columns:9}.ly-cols-10{--ly-grid-columns:10}.ly-cols-11{--ly-grid-columns:11}.ly-cols-12{--ly-grid-columns:12}.ly-cols-16{--ly-grid-columns:16}.ly-span-1{grid-column:span 1}.ly-span-2{grid-column:span 2}.ly-span-3{grid-column:span 3}.ly-span-4{grid-column:span 4}.ly-span-5{grid-column:span 5}.ly-span-6{grid-column:span 6}.ly-span-7{grid-column:span 7}.ly-span-8{grid-column:span 8}.ly-span-9{grid-column:span 9}.ly-span-10{grid-column:span 10}.ly-span-11{grid-column:span 11}.ly-span-12{grid-column:span 12}.ly-span-13{grid-column:span 13}.ly-span-14{grid-column:span 14}.ly-span-15{grid-column:span 15}.ly-span-16{grid-column:span 16}.ly-span-full{grid-column:1 / -1}.ly-gap-0{--ly-gap:var(--ly-space-0);--ly-grid-gap:var(--ly-space-0);--ly-stack-gap:var(--ly-space-0);--ly-cluster-gap:var(--ly-space-0)}.ly-gap-1{--ly-gap:var(--ly-space-1);--ly-grid-gap:var(--ly-space-1);--ly-stack-gap:var(--ly-space-1);--ly-cluster-gap:var(--ly-space-1)}.ly-gap-2{--ly-gap:var(--ly-space-2);--ly-grid-gap:var(--ly-space-2);--ly-stack-gap:var(--ly-space-2);--ly-cluster-gap:var(--ly-space-2)}.ly-gap-3{--ly-gap:var(--ly-space-3);--ly-grid-gap:var(--ly-space-3);--ly-stack-gap:var(--ly-space-3);--ly-cluster-gap:var(--ly-space-3)}.ly-gap-4{--ly-gap:var(--ly-space-4);--ly-grid-gap:var(--ly-space-4);--ly-stack-gap:var(--ly-space-4);--ly-cluster-gap:var(--ly-space-4)}.ly-gap-5{--ly-gap:var(--ly-space-5);--ly-grid-gap:var(--ly-space-5);--ly-stack-gap:var(--ly-space-5);--ly-cluster-gap:var(--ly-space-5)}.ly-gap-6{--ly-gap:var(--ly-space-6);--ly-grid-gap:var(--ly-space-6);--ly-stack-gap:var(--ly-space-6);--ly-cluster-gap:var(--ly-space-6)}.ly-gap-7{--ly-gap:var(--ly-space-7);--ly-grid-gap:var(--ly-space-7);--ly-stack-gap:var(--ly-space-7);--ly-cluster-gap:var(--ly-space-7)}.ly-gap-8{--ly-gap:var(--ly-space-8);--ly-grid-gap:var(--ly-space-8);--ly-stack-gap:var(--ly-space-8);--ly-cluster-gap:var(--ly-space-8)}.ly-gap-9{--ly-gap:var(--ly-space-9);--ly-grid-gap:var(--ly-space-9);--ly-stack-gap:var(--ly-space-9);--ly-cluster-gap:var(--ly-space-9)}.ly-pad-0{padding:var(--ly-space-0)}.ly-pad-1{padding:var(--ly-space-1)}.ly-pad-2{padding:var(--ly-space-2)}.ly-pad-3{padding:var(--ly-space-3)}.ly-pad-4{padding:var(--ly-space-4)}.ly-pad-5{padding:var(--ly-space-5)}.ly-pad-6{padding:var(--ly-space-6)}.ly-pad-7{padding:var(--ly-space-7)}.ly-pad-8{padding:var(--ly-space-8)}.ly-pad-9{padding:var(--ly-space-9)}.ly-px-4{padding-inline:var(--ly-space-4)}.ly-px-6{padding-inline:var(--ly-space-6)}.ly-px-8{padding-inline:var(--ly-space-8)}.ly-py-4{padding-block:var(--ly-space-4)}.ly-py-6{padding-block:var(--ly-space-6)}.ly-py-8{padding-block:var(--ly-space-8)}.ly-mx-auto{margin-inline:auto}.ly-w-full{inline-size:100%}.ly-h-full{block-size:100%}.ly-min-h-screen{min-block-size:100svh}.ly-bleed{inline-size:100vw;margin-inline:calc(50% - 50vw)}.ly-overflow-auto{overflow:auto}.ly-overflow-hidden{overflow:hidden}.ly-items-start{align-items:flex-start}.ly-items-center{align-items:center}.ly-items-end{align-items:flex-end}.ly-items-stretch{align-items:stretch}.ly-justify-start{justify-content:flex-start}.ly-justify-center{justify-content:center}.ly-justify-end{justify-content:flex-end}.ly-justify-between{justify-content:space-between}.ly-frame-1x1{--ly-frame-ratio:1 / 1}.ly-frame-2x1{--ly-frame-ratio:2 / 1}.ly-frame-3x2{--ly-frame-ratio:3 / 2}.ly-frame-4x3{--ly-frame-ratio:4 / 3}.ly-frame-16x9{--ly-frame-ratio:16 / 9}.ly-frame-21x9{--ly-frame-ratio:21 / 9}.ly-hidden{display:none !important}.ly-show-md-up,.ly-show-lg-up{display:none !important}.ly-visually-hidden{position:absolute !important;inline-size:1px !important;block-size:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0,0,0,0) !important;clip-path:inset(50%) !important;white-space:nowrap !important}.ly-order-first{order:-1}.ly-order-normal{order:0}.ly-order-last{order:999}.ly-order-1{order:1}.ly-order-2{order:2}.ly-order-3{order:3}.ly-order-4{order:4}.ly-order-5{order:5}.ly-order-6{order:6}@container (min-width:48rem){.ly-md-cols-1{--ly-grid-columns:1}.ly-md-cols-2{--ly-grid-columns:2}.ly-md-cols-3{--ly-grid-columns:3}.ly-md-cols-4{--ly-grid-columns:4}.ly-md-cols-6{--ly-grid-columns:6}.ly-md-cols-8{--ly-grid-columns:8}.ly-md-cols-12{--ly-grid-columns:12}.ly-md-cols-16{--ly-grid-columns:16}.ly-show-md-up{display:revert !important}.ly-md-order-first{order:-1}.ly-md-order-normal{order:0}.ly-md-order-last{order:999}.ly-md-order-1{order:1}.ly-md-order-2{order:2}.ly-md-order-3{order:3}.ly-md-order-4{order:4}.ly-md-order-5{order:5}.ly-md-order-6{order:6}}@container (min-width:64rem){.ly-lg-cols-1{--ly-grid-columns:1}.ly-lg-cols-2{--ly-grid-columns:2}.ly-lg-cols-3{--ly-grid-columns:3}.ly-lg-cols-4{--ly-grid-columns:4}.ly-lg-cols-6{--ly-grid-columns:6}.ly-lg-cols-8{--ly-grid-columns:8}.ly-lg-cols-12{--ly-grid-columns:12}.ly-lg-cols-16{--ly-grid-columns:16}.ly-show-lg-up{display:revert !important}.ly-lg-order-first{order:-1}.ly-lg-order-normal{order:0}.ly-lg-order-last{order:999}.ly-lg-order-1{order:1}.ly-lg-order-2{order:2}.ly-lg-order-3{order:3}.ly-lg-order-4{order:4}.ly-lg-order-5{order:5}.ly-lg-order-6{order:6}}}@layer ly.personalities.minimal_saas{:where(.ly-root[data-ly-layout="minimal-saas"]){--ly-recipe-rail:15rem;--ly-recipe-aside:16rem;--ly-grid-columns:4;--ly-grid-min:16rem;--ly-personality-wrapper-max:88rem;container-name:ly-personality;container-type:inline-size;min-inline-size:0}@container (min-width:48rem){:where(.ly-root[data-ly-layout="minimal-saas"]) .ly-grid>:nth-child(4n + 1){grid-column:span 2}}@container (min-width:64rem){:where(.ly-root[data-ly-layout="minimal-saas"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-areas:"sidebar header header" "sidebar main aside" "sidebar footer footer";grid-template-rows:auto minmax(0,1fr) auto;grid-template-columns:minmax(min(100%,15rem),0.24fr) minmax(0,1fr) minmax(min(100%,16rem),0.28fr)}}}@layer ly.personalities.bento{:where(.ly-root[data-ly-layout="bento"]){--ly-grid-columns:6;--ly-grid-min:12rem;--ly-card-grid-min:13rem;--ly-personality-wrapper-max:112rem;container-name:ly-personality;container-type:inline-size;min-inline-size:0}@container (min-width:48rem){:where(.ly-root[data-ly-layout="bento"]) .ly-grid>:nth-child(6n + 1){grid-column:span 2;grid-row:span 2}:where(.ly-root[data-ly-layout="bento"]):where(.ly-card-grid,[data-ly-recipe="card-grid"])>:nth-child(6n + 1){grid-column:span 2}}@container (min-width:64rem){:where(.ly-root[data-ly-layout="bento"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-areas:"header header header" "sidebar main main" "aside main main" "footer footer footer";grid-template-rows:auto minmax(0,1fr) auto auto;grid-template-columns:minmax(min(100%,14rem),0.3fr) minmax(0,1fr) minmax(0,1fr)}}}@layer ly.personalities.maximalist{:where(.ly-root[data-ly-layout="maximalist"]){--ly-grid-columns:12;--ly-grid-min:10rem;--ly-personality-wrapper-max:100%;--ly-card-grid-min:12rem;container-name:ly-personality;container-type:inline-size;min-inline-size:0}@container (min-width:48rem){:where(.ly-root[data-ly-layout="maximalist"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-columns:minmax(min(100%,18rem),0.3fr) minmax(0,1fr)}}@container (min-width:56rem){:where(.ly-root[data-ly-layout="maximalist"]) .ly-grid>:nth-child(7n + 1){grid-column:span 3;grid-row:span 2}:where(.ly-root[data-ly-layout="maximalist"]):where(.ly-gallery,[data-ly-recipe="gallery"])>:nth-child(5n + 1){grid-column:span 2;grid-row:span 2}}@container (min-width:64rem){:where(.ly-root[data-ly-layout="maximalist"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-areas:"header header header header" "main main sidebar aside" "main main footer footer";grid-template-rows:auto minmax(0,1fr) auto;grid-template-columns:minmax(0,1.4fr) minmax(0,0.6fr) minmax(min(100%,15rem),0.32fr) minmax(min(100%,18rem),0.38fr)}}}@layer ly.personalities.bauhaus{:where(.ly-root[data-ly-layout="bauhaus"]){--ly-recipe-rail:14rem;--ly-recipe-aside:18rem;--ly-grid-columns:6;--ly-grid-min:13rem;--ly-personality-wrapper-max:96rem;container-name:ly-personality;container-type:inline-size;min-inline-size:0}@container (min-width:48rem){:where(.ly-root[data-ly-layout="bauhaus"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-columns:minmax(min(100%,14rem),0.3fr) minmax(0,1fr)}}@container (min-width:52rem){:where(.ly-root[data-ly-layout="bauhaus"]) .ly-grid>:nth-child(3n + 1){grid-column:span 2;grid-row:span 2}}@container (min-width:64rem){:where(.ly-root[data-ly-layout="bauhaus"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-areas:"sidebar header header aside" "sidebar main main aside" "sidebar footer footer footer";grid-template-rows:auto minmax(0,1fr) auto;grid-template-columns:minmax(min(100%,14rem),0.24fr) minmax(0,0.7fr) minmax(0,1.3fr) minmax(min(100%,18rem),0.3fr)}}}@layer ly.personalities.tactile{:where(.ly-root[data-ly-layout="tactile"]){--ly-recipe-rail:17rem;--ly-recipe-aside:20rem;--ly-grid-columns:5;--ly-grid-min:15rem;--ly-personality-wrapper-max:82rem;container-name:ly-personality;container-type:inline-size;min-inline-size:0}@container (min-width:48rem){:where(.ly-root[data-ly-layout="tactile"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-areas:"sidebar header" "sidebar main" "sidebar aside" "sidebar footer";grid-template-rows:auto minmax(0,1fr) auto auto;grid-template-columns:minmax(min(100%,17rem),0.28fr) minmax(0,1fr)}:where(.ly-root[data-ly-layout="tactile"]) .ly-grid>:nth-child(5n + 2){grid-column:span 2}:where(.ly-root[data-ly-layout="tactile"]):where(.ly-list-detail,[data-ly-recipe="list-detail"]){grid-template-columns:minmax(min(100%,20rem),0.42fr) minmax(0,0.58fr)}}}@layer ly.personalities.neumorphism{:where(.ly-root[data-ly-layout="neumorphism"]){--ly-recipe-rail:17rem;--ly-recipe-aside:19rem;--ly-grid-columns:4;--ly-grid-min:17rem;--ly-personality-wrapper-max:84rem;container-name:ly-personality;container-type:inline-size;min-inline-size:0}@container (min-width:48rem){:where(.ly-root[data-ly-layout="neumorphism"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-columns:minmax(min(100%,17rem),0.3fr) minmax(0,1fr)}}@container (min-width:52rem){:where(.ly-root[data-ly-layout="neumorphism"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-areas:"header sidebar" "main sidebar" "aside sidebar" "footer sidebar";grid-template-rows:auto minmax(0,1fr) auto auto;grid-template-columns:minmax(0,1fr) minmax(min(100%,17rem),0.3fr)}:where(.ly-root[data-ly-layout="neumorphism"]) .ly-grid>:nth-child(4n + 1){grid-column:span 2}:where(.ly-root[data-ly-layout="neumorphism"]):where(.ly-list-detail,[data-ly-recipe="list-detail"]){grid-template-columns:minmax(0,0.58fr) minmax(min(100%,19rem),0.42fr)}}}@layer ly.personalities.retrofuturism{:where(.ly-root[data-ly-layout="retrofuturism"]){--ly-recipe-rail:14rem;--ly-recipe-aside:17rem;--ly-grid-columns:6;--ly-grid-min:14rem;--ly-personality-wrapper-max:106rem;container-name:ly-personality;container-type:inline-size;min-inline-size:0}@container (min-width:48rem){:where(.ly-root[data-ly-layout="retrofuturism"]) .ly-grid>:nth-child(6n + 1){grid-column:span 2}}@container (min-width:64rem){:where(.ly-root[data-ly-layout="retrofuturism"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-areas:"sidebar header aside" "sidebar main aside" "sidebar footer aside";grid-template-rows:auto minmax(0,1fr) auto;grid-template-columns:minmax(min(100%,14rem),0.24fr) minmax(0,1fr) minmax(min(100%,17rem),0.3fr)}}}@layer ly.personalities.brutalism{:where(.ly-root[data-ly-layout="brutalism"]){--ly-recipe-rail:18rem;--ly-recipe-aside:16rem;--ly-grid-columns:6;--ly-grid-min:14rem;--ly-personality-wrapper-max:100rem;container-name:ly-personality;container-type:inline-size;min-inline-size:0}@container (min-width:48rem){:where(.ly-root[data-ly-layout="brutalism"]) .ly-grid>:nth-child(3n){grid-column:span 2}}@container (min-width:64rem){:where(.ly-root[data-ly-layout="brutalism"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-areas:"header header sidebar" "main aside sidebar" "footer footer sidebar";grid-template-rows:auto minmax(0,1fr) auto;grid-template-columns:minmax(0,1.3fr) minmax(min(100%,16rem),0.7fr) minmax(min(100%,18rem),0.34fr)}}}@layer ly.personalities.cyberpunk{:where(.ly-root[data-ly-layout="cyberpunk"]){--ly-recipe-rail:13rem;--ly-recipe-aside:19rem;--ly-grid-columns:8;--ly-grid-min:12rem;--ly-personality-wrapper-max:112rem;container-name:ly-personality;container-type:inline-size;min-inline-size:0}@container (min-width:44rem){:where(.ly-root[data-ly-layout="cyberpunk"]) .ly-grid>:nth-child(4n + 2){grid-column:span 3}}@container (min-width:64rem){:where(.ly-root[data-ly-layout="cyberpunk"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-areas:"sidebar header aside" "sidebar main aside" "sidebar footer aside";grid-template-rows:auto minmax(0,1fr) auto;grid-template-columns:minmax(min(100%,13rem),0.2fr) minmax(0,1fr) minmax(min(100%,19rem),0.32fr)}}}@layer ly.personalities.y2k{:where(.ly-root[data-ly-layout="y2k"]){--ly-recipe-rail:16rem;--ly-recipe-aside:18rem;--ly-grid-columns:5;--ly-grid-min:13rem;--ly-personality-wrapper-max:90rem;container-name:ly-personality;container-type:inline-size;min-inline-size:0}@container (min-width:48rem){:where(.ly-root[data-ly-layout="y2k"]) .ly-grid>:nth-child(5n + 1){grid-column:span 3}}@container (min-width:64rem){:where(.ly-root[data-ly-layout="y2k"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-areas:"header header sidebar" "aside main sidebar" "footer footer sidebar";grid-template-rows:auto minmax(0,1fr) auto;grid-template-columns:minmax(min(100%,18rem),0.34fr) minmax(0,1fr) minmax(min(100%,16rem),0.28fr)}}}@layer ly.personalities.retro_glass{:where(.ly-root[data-ly-layout="retro-glass"]){--ly-recipe-rail:18rem;--ly-recipe-aside:20rem;--ly-grid-columns:8;--ly-grid-min:15rem;--ly-personality-wrapper-max:104rem;container-name:ly-personality;container-type:inline-size;min-inline-size:0}@container (min-width:48rem){:where(.ly-root[data-ly-layout="retro-glass"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-columns:minmax(min(100%,18rem),0.3fr) minmax(0,1fr)}}@container (min-width:56rem){:where(.ly-root[data-ly-layout="retro-glass"]) .ly-grid>:nth-child(4n){grid-column:span 2;grid-row:span 2}}@container (min-width:64rem){:where(.ly-root[data-ly-layout="retro-glass"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-areas:"header header sidebar" "main main sidebar" "aside footer footer";grid-template-rows:auto minmax(0,1fr) auto;grid-template-columns:minmax(0,1.25fr) minmax(0,0.75fr) minmax(min(100%,18rem),0.32fr)}}}@layer ly.personalities.f_pattern{:where(.ly-root[data-ly-layout="f-pattern"]){--ly-recipe-rail:16rem;--ly-recipe-aside:18rem;--ly-grid-columns:6;--ly-grid-min:14rem;--ly-personality-wrapper-max:92rem;container-name:ly-personality;container-type:inline-size;min-inline-size:0}@container (min-width:48rem){:where(.ly-root[data-ly-layout="f-pattern"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-columns:minmax(min(100%,16rem),0.3fr) minmax(0,1fr)}}@container (min-width:56rem){:where(.ly-root[data-ly-layout="f-pattern"]) .ly-grid>:nth-child(3n + 1){grid-column:span 2}:where(.ly-root[data-ly-layout="f-pattern"]):where(.ly-split-hero,[data-ly-recipe="split-hero"]){grid-template-columns:minmax(0,1.35fr) minmax(0,0.65fr)}}@container (min-width:64rem){:where(.ly-root[data-ly-layout="f-pattern"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-areas:"sidebar header header" "sidebar main aside" "sidebar footer aside";grid-template-rows:auto minmax(0,1fr) auto;grid-template-columns:minmax(min(100%,16rem),0.26fr) minmax(0,1.35fr) minmax(min(100%,18rem),0.65fr)}}}@layer ly.personalities.z_pattern{:where(.ly-root[data-ly-layout="z-pattern"]){--ly-recipe-rail:17rem;--ly-recipe-aside:19rem;--ly-grid-columns:8;--ly-grid-min:14rem;--ly-personality-wrapper-max:108rem;container-name:ly-personality;container-type:inline-size;min-inline-size:0}@container (min-width:48rem){:where(.ly-root[data-ly-layout="z-pattern"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-columns:minmax(min(100%,17rem),0.3fr) minmax(0,1fr)}}@container (min-width:60rem){:where(.ly-root[data-ly-layout="z-pattern"]) .ly-grid>:nth-child(4n + 2){grid-column:span 2;align-self:end}:where(.ly-root[data-ly-layout="z-pattern"]):where(.ly-split-hero,[data-ly-recipe="split-hero"]){grid-template-columns:minmax(0,1.5fr) minmax(0,0.5fr)}}@container (min-width:64rem){:where(.ly-root[data-ly-layout="z-pattern"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-areas:"header header sidebar" "main aside sidebar" "footer aside sidebar";grid-template-rows:auto minmax(0,1fr) auto;grid-template-columns:minmax(0,1.45fr) minmax(min(100%,19rem),0.55fr) minmax(min(100%,17rem),0.3fr)}}}@layer ly.personalities.split_screen{:where(.ly-root[data-ly-layout="split-screen"]){--ly-grid-columns:2;--ly-grid-min:20rem;--ly-personality-wrapper-max:100%;--ly-split-primary:1fr;--ly-split-secondary:1fr;container-name:ly-personality;container-type:inline-size;min-inline-size:0}@container (min-width:48rem){:where(.ly-root[data-ly-layout="split-screen"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-areas:"header header" "main sidebar" "aside sidebar" "footer footer";grid-template-rows:auto minmax(0,1fr) auto auto;grid-template-columns:minmax(0,1fr) minmax(0,1fr)}:where(.ly-root[data-ly-layout="split-screen"]):where( .ly-split,.ly-split-hero,[data-ly-recipe="split-hero"],.ly-list-detail,[data-ly-recipe="list-detail"] ){grid-template-columns:minmax(0,1fr) minmax(0,1fr)}}}@layer ly.personalities.mondrian{:where(.ly-root[data-ly-layout="mondrian"]){--ly-recipe-rail:13rem;--ly-recipe-aside:18rem;--ly-grid-columns:10;--ly-grid-min:11rem;--ly-personality-wrapper-max:112rem;container-name:ly-personality;container-type:inline-size;min-inline-size:0}@container (min-width:48rem){:where(.ly-root[data-ly-layout="mondrian"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-columns:minmax(min(100%,13rem),0.3fr) minmax(0,1fr)}}@container (min-width:52rem){:where(.ly-root[data-ly-layout="mondrian"]) .ly-grid>:nth-child(5n + 1){grid-column:span 2;grid-row:span 2}}@container (min-width:64rem){:where(.ly-root[data-ly-layout="mondrian"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-areas:"sidebar header header" "sidebar main aside" "footer footer aside";grid-template-rows:auto minmax(0,1fr) auto;grid-template-columns:minmax(min(100%,13rem),0.22fr) minmax(0,1.45fr) minmax(min(100%,18rem),0.55fr)}}}@layer ly.personalities.synthwave{:where(.ly-root[data-ly-layout="synthwave"]){--ly-recipe-rail:16rem;--ly-recipe-aside:20rem;--ly-grid-columns:12;--ly-grid-min:14rem;--ly-reel-item-max:34rem;--ly-personality-wrapper-max:112rem;container-name:ly-personality;container-type:inline-size;min-inline-size:0}@container (min-width:48rem){:where(.ly-root[data-ly-layout="synthwave"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-columns:minmax(min(100%,16rem),0.3fr) minmax(0,1fr)}}@container (min-width:64rem){:where(.ly-root[data-ly-layout="synthwave"]):where(.ly-app-shell,[data-ly-recipe="app-shell"]){grid-template-areas:"header header header" "sidebar main aside" "footer footer footer";grid-template-rows:auto minmax(0,1fr) auto;grid-template-columns:minmax(min(100%,16rem),0.28fr) minmax(0,1fr) minmax(min(100%,20rem),0.34fr)}:where(.ly-root[data-ly-layout="synthwave"]) .ly-grid>:nth-child(4n + 1){grid-column:span 3}:where(.ly-root[data-ly-layout="synthwave"]) .ly-reel{grid-auto-columns:minmax(min(100%,20rem),var(--ly-reel-item-max))}}} +@layer ly.reset,ly.tokens,ly.wrappers,ly.primitives,ly.recipes,ly.utilities,ly.personalities;@layer ly.tokens{:where(.ly-root){--ly-space-0:0;--ly-space-1:0.25rem;--ly-space-2:0.5rem;--ly-space-3:0.75rem;--ly-space-4:1rem;--ly-space-5:1.5rem;--ly-space-6:2rem;--ly-space-7:3rem;--ly-space-8:4rem;--ly-space-9:6rem;--ly-wrapper-compact:40rem;--ly-wrapper-prose:68ch;--ly-wrapper-content:72rem;--ly-wrapper-wide:112rem;--ly-page-padding-inline:clamp(1rem,4vw,3rem);--ly-safe-area-inline:max( env(safe-area-inset-left,0px),env(safe-area-inset-right,0px) );--ly-safe-area-block-start:env(safe-area-inset-top,0px);--ly-safe-area-block-end:env(safe-area-inset-bottom,0px);--ly-wrapper-gutter:max(var(--ly-page-padding-inline),var(--ly-safe-area-inline));--ly-profile-gap:var(--ly-space-5);--ly-gap:var(--ly-profile-gap);--ly-grid-gap:var(--ly-gap);--ly-stack-gap:var(--ly-space-4);--ly-cluster-gap:var(--ly-space-3);--ly-section-padding-block:clamp(3rem,7vh,6rem);--ly-header-height:4.5rem;--ly-sticky-position:sticky;--ly-cover-min:100dvh;--ly-shell-min:100dvh;--ly-scroll-max:min(70dvh,50rem);--ly-switcher-threshold:42rem;--ly-sidebar-size:18rem;--ly-sidebar-content-min:50%;--ly-grid-columns:12;--ly-grid-min:16rem;--ly-split-min:20rem;--ly-pane-min:18rem;--ly-pane-size:22rem;--ly-media-min:18rem;--ly-media-size:14rem;--ly-reel-item-min:16rem;--ly-reel-item-max:28rem;--ly-frame-ratio:16 / 9;--ly-recipe-rail:18rem;--ly-recipe-aside:22rem;--ly-gallery-min:12rem;--ly-card-grid-min:16rem;--ly-app-shell-medium-areas:"header header" "sidebar main" "aside main" "footer footer";--ly-app-shell-medium-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(0,1fr);--ly-app-shell-wide-areas:"sidebar header header" "sidebar main aside" "sidebar footer footer";--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(0,1fr) minmax(min(100%,var(--ly-recipe-aside)),0.35fr);--ly-dashboard-medium-areas:"header header" "nav nav" "main aside" "footer footer";--ly-dashboard-medium-columns:minmax(0,1fr) minmax(min(100%,var(--ly-recipe-aside)),0.35fr);--ly-dashboard-wide-areas:"nav header header" "nav main aside" "nav footer footer";--ly-dashboard-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(0,1fr) minmax(min(100%,var(--ly-recipe-aside)),0.35fr);--ly-docs-wide-areas:"header header" "nav main" "nav aside" "footer footer";--ly-docs-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(0,1fr);--ly-list-detail-wide-areas:"primary secondary" "actions actions";--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-size)),0.7fr) minmax(0,1fr);--ly-split-hero-wide-areas:"content media" "actions media";--ly-split-hero-wide-columns:minmax(0,var(--ly-split-primary,1fr)) minmax(0,var(--ly-split-secondary,1fr));container-name:ly-scope;container-type:inline-size;min-inline-size:0;min-block-size:0}}@layer ly.reset{:where(.ly-root),:where(.ly-root *){box-sizing:border-box}:where(.ly-root){margin:0}:where(.ly-root img),:where(.ly-root svg),:where(.ly-root video),:where(.ly-root canvas),:where(.ly-root iframe){max-inline-size:100%}}@layer ly.tokens{@media (max-height:44rem){:where(.ly-root){--ly-gap:min(var(--ly-profile-gap),var(--ly-space-4));--ly-grid-gap:var(--ly-gap);--ly-stack-gap:min(var(--ly-space-4),3dvh);--ly-cluster-gap:min(var(--ly-space-3),2dvh);--ly-section-padding-block:clamp(1.5rem,6dvh,3rem);--ly-header-height:3.5rem;--ly-scroll-max:min(62dvh,34rem)}}@media (max-height:30rem){:where(.ly-root){--ly-cover-min:auto;--ly-shell-min:auto;--ly-sticky-position:static;--ly-section-padding-block:var(--ly-space-5);--ly-scroll-max:max(12rem,calc(100dvh - 8rem))}}}@layer ly.wrappers{.ly-wrapper{--ly-wrapper-max:var(--ly-personality-wrapper-max,var(--ly-wrapper-content));--ly-wrapper-fluid-gutter:clamp(1rem,3vw,3rem);--ly-wrapper-fluid-gutter:clamp(1rem,3cqi,3rem);--ly-wrapper-local-gutter:max( var(--ly-wrapper-fluid-gutter),var(--ly-safe-area-inline) );container-name:ly-scope;container-type:inline-size;inline-size:min(100%,calc(var(--ly-wrapper-max) + (var(--ly-wrapper-local-gutter) * 2)));max-inline-size:100%;margin-inline:auto;padding-inline:var(--ly-wrapper-local-gutter)}.ly-wrapper--compact{--ly-wrapper-max:var(--ly-wrapper-compact)}.ly-wrapper--prose{--ly-wrapper-max:var(--ly-wrapper-prose)}.ly-wrapper--content{--ly-wrapper-max:var(--ly-wrapper-content)}.ly-wrapper--wide{--ly-wrapper-max:var(--ly-wrapper-wide)}.ly-wrapper--full{--ly-wrapper-max:100%}.ly-wrapper--breakout{--ly-wrapper-max:100%;--ly-breakout-content-size:min( var(--ly-wrapper-content),calc(100% - (var(--ly-wrapper-local-gutter) * 2)) );--ly-breakout-feature-size:min( var(--ly-wrapper-wide),calc(100% - (var(--ly-wrapper-local-gutter) * 2)) );display:grid;grid-template-columns:[full-start] minmax(min(100%,var(--ly-wrapper-local-gutter)),1fr) [feature-start] minmax( 0,calc((var(--ly-breakout-feature-size) - var(--ly-breakout-content-size)) / 2) ) [content-start] minmax(0,var(--ly-breakout-content-size)) [content-end] minmax( 0,calc((var(--ly-breakout-feature-size) - var(--ly-breakout-content-size)) / 2) ) [feature-end] minmax(min(100%,var(--ly-wrapper-local-gutter)),1fr) [full-end];inline-size:100%;padding-inline:0}.ly-wrapper--breakout>*{grid-column:content;min-inline-size:0;max-inline-size:100%}.ly-wrapper--breakout>:where(.ly-lane--content,[data-ly-lane="content"]){grid-column:content}.ly-wrapper--breakout>:where(.ly-lane--feature,[data-ly-lane="feature"]){grid-column:feature}.ly-wrapper--breakout>:where(.ly-lane--full,[data-ly-lane="full"]){grid-column:full}}@layer ly.primitives{.ly-page{min-block-size:100vh;min-block-size:100dvh;padding-block-start:var(--ly-safe-area-block-start);padding-block-end:var(--ly-safe-area-block-end)}.ly-header,.ly-footer,.ly-main,.ly-section,.ly-surface{min-inline-size:0;min-block-size:0}.ly-header{min-block-size:var(--ly-header-height)}.ly-header--sticky{position:var(--ly-sticky-position);inset-block-start:0;z-index:var(--ly-z-header,20)}.ly-section{padding-block:var(--ly-section-padding-block)}.ly-section--compact{--ly-section-padding-block:var(--ly-space-7)}.ly-section--flush{--ly-section-padding-block:0}.ly-readable{max-inline-size:var(--ly-wrapper-prose)}.ly-stack{display:flex;flex-direction:column;gap:var(--ly-stack-gap)}.ly-cluster{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ly-cluster-gap)}.ly-center{inline-size:min(100%,var(--ly-center-max,var(--ly-wrapper-content)));margin-inline:auto}.ly-cover{display:flex;flex-direction:column;min-block-size:100vh;min-block-size:var(--ly-cover-min);padding-block:var(--ly-cover-padding,var(--ly-space-5))}.ly-cover>:where(.ly-cover__center,[data-ly-cover-center]){margin-block:auto}.ly-switcher{display:flex;flex-wrap:wrap;gap:var(--ly-gap)}.ly-switcher>*{flex-basis:calc((var(--ly-switcher-threshold) - 100%) * 999);flex-grow:1;min-inline-size:0}.ly-sidebar{display:flex;flex-wrap:wrap;gap:var(--ly-gap)}.ly-sidebar>:where(.ly-sidebar__side,[data-ly-sidebar="side"]){flex-basis:var(--ly-sidebar-size);flex-grow:1;min-inline-size:min(100%,var(--ly-sidebar-size))}.ly-sidebar>:where(.ly-sidebar__content,[data-ly-sidebar="content"]){flex-basis:0;flex-grow:999;min-inline-size:min(100%,var(--ly-sidebar-content-min))}.ly-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,var(--ly-grid-min)),1fr));gap:var(--ly-grid-gap)}.ly-grid--fixed{grid-template-columns:repeat(var(--ly-grid-columns),minmax(0,1fr))}.ly-split{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,var(--ly-split-min)),1fr));gap:var(--ly-gap);align-items:var(--ly-split-align,center)}.ly-panes{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,var(--ly-pane-min)),1fr));gap:var(--ly-gap)}.ly-media{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,var(--ly-media-min)),1fr));gap:var(--ly-gap);align-items:var(--ly-media-align,start)}.ly-media>:where(.ly-media__actions,[data-ly-media="actions"]){min-inline-size:min(100%,var(--ly-media-size))}.ly-grid>*,.ly-split>*,.ly-panes>*,.ly-media>*{min-inline-size:0;min-block-size:0}.ly-reel{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(min(100%,var(--ly-reel-item-min)),var(--ly-reel-item-max));gap:var(--ly-grid-gap);overflow-x:auto;overscroll-behavior-inline:contain;scroll-snap-type:inline proximity}.ly-reel>*{min-inline-size:0;scroll-snap-align:start}.ly-frame{aspect-ratio:var(--ly-frame-ratio);overflow:hidden}.ly-frame>*{inline-size:100%;block-size:100%;object-fit:cover}.ly-scroll{min-block-size:0;max-block-size:var(--ly-scroll-max);overflow-y:auto;overscroll-behavior-block:contain}}@layer ly.recipes{:where( [data-ly-recipe="app-shell"],[data-ly-recipe="dashboard"],[data-ly-recipe="docs"],[data-ly-recipe="list-detail"],[data-ly-recipe="split-hero"],[data-ly-recipe="gallery"],[data-ly-recipe="card-grid"] ){container-name:ly-scope;container-type:inline-size;min-inline-size:0;min-block-size:0}:where( [data-ly-recipe="app-shell"],[data-ly-recipe="dashboard"],[data-ly-recipe="docs"],[data-ly-recipe="list-detail"],[data-ly-recipe="split-hero"] ){display:grid;grid-template-columns:minmax(0,1fr);gap:var(--ly-gap)}[data-ly-recipe="app-shell"]{min-block-size:100vh;min-block-size:var(--ly-shell-min);grid-template-areas:"header" "sidebar" "main" "aside" "footer";grid-template-rows:auto auto minmax(0,1fr) auto auto}[data-ly-recipe="dashboard"],[data-ly-recipe="docs"]{grid-template-areas:"header" "nav" "main" "aside" "footer"}[data-ly-recipe="list-detail"]{grid-template-areas:"primary" "secondary" "actions"}[data-ly-recipe="split-hero"]{grid-template-areas:"content" "media" "actions";align-items:var(--ly-split-hero-align,center)}[data-ly-recipe="gallery"],[data-ly-recipe="card-grid"]{display:grid;gap:var(--ly-grid-gap)}[data-ly-recipe="gallery"]{grid-template-columns:repeat(auto-fit,minmax(min(100%,var(--ly-gallery-min)),1fr))}[data-ly-recipe="card-grid"]{grid-template-columns:repeat(auto-fit,minmax(min(100%,var(--ly-card-grid-min)),1fr))}:where( [data-ly-recipe="app-shell"],[data-ly-recipe="dashboard"],[data-ly-recipe="docs"],[data-ly-recipe="list-detail"],[data-ly-recipe="split-hero"],[data-ly-recipe="gallery"],[data-ly-recipe="card-grid"] )>*{min-inline-size:0;min-block-size:0}[data-ly-area="header"]{grid-area:header}[data-ly-area="nav"]{grid-area:nav}[data-ly-area="sidebar"]{grid-area:sidebar}[data-ly-area="main"]{grid-area:main}[data-ly-area="aside"]{grid-area:aside}[data-ly-area="footer"]{grid-area:footer}[data-ly-area="content"]{grid-area:content}[data-ly-area="media"]{grid-area:media}[data-ly-area="actions"]{grid-area:actions}[data-ly-area="primary"]{grid-area:primary}[data-ly-area="secondary"]{grid-area:secondary}@container ly-scope (min-width:42rem){[data-ly-recipe="split-hero"]:not([data-ly-responsive="manual"]){grid-template-areas:var(--ly-split-hero-wide-areas);grid-template-columns:var(--ly-split-hero-wide-columns)}}@container ly-scope (min-width:44rem){[data-ly-recipe="list-detail"]:not([data-ly-responsive="manual"]){grid-template-areas:var(--ly-list-detail-wide-areas);grid-template-columns:var(--ly-list-detail-wide-columns)}}@container ly-scope (min-width:48rem){[data-ly-recipe="docs"]:not([data-ly-responsive="manual"]){grid-template-areas:var(--ly-docs-wide-areas);grid-template-columns:var(--ly-docs-wide-columns)}}@container ly-scope (min-width:52rem){[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]){grid-template-areas:var(--ly-app-shell-medium-areas);grid-template-columns:var(--ly-app-shell-medium-columns)}[data-ly-recipe="dashboard"]:not([data-ly-responsive="manual"]){grid-template-areas:var(--ly-dashboard-medium-areas);grid-template-columns:var(--ly-dashboard-medium-columns)}}@container ly-scope (min-width:72rem){[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]){grid-template-areas:var(--ly-app-shell-wide-areas);grid-template-columns:var(--ly-app-shell-wide-columns)}[data-ly-recipe="dashboard"]:not([data-ly-responsive="manual"]){grid-template-areas:var(--ly-dashboard-wide-areas);grid-template-columns:var(--ly-dashboard-wide-columns)}}}@layer ly.utilities{.ly-cols-1{--ly-grid-columns:1}.ly-cols-2{--ly-grid-columns:2}.ly-cols-3{--ly-grid-columns:3}.ly-cols-4{--ly-grid-columns:4}.ly-cols-6{--ly-grid-columns:6}.ly-cols-12{--ly-grid-columns:12}.ly-span-1{grid-column:span 1}.ly-span-2{grid-column:span 2}.ly-span-3{grid-column:span 3}.ly-span-4{grid-column:span 4}.ly-span-full{grid-column:1 / -1}.ly-gap-0{--ly-gap:var(--ly-space-0);--ly-grid-gap:var(--ly-space-0)}.ly-gap-2{--ly-gap:var(--ly-space-2);--ly-grid-gap:var(--ly-space-2)}.ly-gap-4{--ly-gap:var(--ly-space-4);--ly-grid-gap:var(--ly-space-4)}.ly-gap-6{--ly-gap:var(--ly-space-6);--ly-grid-gap:var(--ly-space-6)}.ly-gap-8{--ly-gap:var(--ly-space-8);--ly-grid-gap:var(--ly-space-8)}.ly-pad-0{padding:var(--ly-space-0)}.ly-pad-2{padding:var(--ly-space-2)}.ly-pad-4{padding:var(--ly-space-4)}.ly-pad-6{padding:var(--ly-space-6)}.ly-pad-8{padding:var(--ly-space-8)}.ly-mx-auto{margin-inline:auto}.ly-w-full{inline-size:100%}.ly-h-full{block-size:100%}.ly-min-h-screen{min-block-size:100vh;min-block-size:100dvh}.ly-overflow-auto{overflow:auto}.ly-overflow-hidden{overflow:hidden}.ly-items-start{align-items:flex-start}.ly-items-center{align-items:center}.ly-items-end{align-items:flex-end}.ly-items-stretch{align-items:stretch}.ly-justify-start{justify-content:flex-start}.ly-justify-center{justify-content:center}.ly-justify-end{justify-content:flex-end}.ly-justify-between{justify-content:space-between}.ly-frame-1x1{--ly-frame-ratio:1 / 1}.ly-frame-3x2{--ly-frame-ratio:3 / 2}.ly-frame-4x3{--ly-frame-ratio:4 / 3}.ly-frame-16x9{--ly-frame-ratio:16 / 9}.ly-frame-21x9{--ly-frame-ratio:21 / 9}.ly-hidden{display:none !important}.ly-visually-hidden{position:absolute !important;inline-size:1px !important;block-size:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0,0,0,0) !important;clip-path:inset(50%) !important;white-space:nowrap !important}}@layer ly.personalities.minimal-saas{:where(.ly-root[data-ly-layout="minimal-saas"]){--ly-personality-wrapper-max:88rem;--ly-profile-gap:var(--ly-space-5);--ly-grid-min:16rem;--ly-recipe-rail:15rem;--ly-recipe-aside:16rem;--ly-split-primary:1.05fr;--ly-split-secondary:0.95fr}}@layer ly.personalities.bento{:where(.ly-root[data-ly-layout="bento"]){--ly-personality-wrapper-max:112rem;--ly-profile-gap:var(--ly-space-4);--ly-grid-min:12rem;--ly-card-grid-min:14rem;--ly-gallery-min:11rem;--ly-recipe-rail:14rem;--ly-recipe-aside:18rem;--ly-app-shell-wide-areas:"header header header" "sidebar main main" "aside main main" "footer footer footer";--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.3fr) minmax(0,1fr) minmax(0,1fr)}}@layer ly.personalities.maximalist{:where(.ly-root[data-ly-layout="maximalist"]){--ly-personality-wrapper-max:100%;--ly-profile-gap:var(--ly-space-7);--ly-grid-min:10rem;--ly-card-grid-min:13rem;--ly-gallery-min:10rem;--ly-recipe-rail:15rem;--ly-recipe-aside:18rem;--ly-app-shell-wide-areas:"header header header header" "main main sidebar aside" "main main footer footer";--ly-app-shell-wide-columns:minmax(0,1.4fr) minmax(0,0.6fr) minmax(min(100%,var(--ly-recipe-rail)),0.32fr) minmax(min(100%,var(--ly-recipe-aside)),0.38fr)}}@layer ly.personalities.bauhaus{:where(.ly-root[data-ly-layout="bauhaus"]){--ly-personality-wrapper-max:96rem;--ly-profile-gap:var(--ly-space-6);--ly-grid-min:13rem;--ly-recipe-rail:14rem;--ly-recipe-aside:18rem;--ly-app-shell-wide-areas:"header header header header" "sidebar main main aside" "sidebar footer footer aside";--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.24fr) minmax(0,0.7fr) minmax(0,1.3fr) minmax(min(100%,var(--ly-recipe-aside)),0.3fr)}}@layer ly.personalities.tactile{:where(.ly-root[data-ly-layout="tactile"]){--ly-personality-wrapper-max:82rem;--ly-profile-gap:var(--ly-space-4);--ly-grid-min:15rem;--ly-recipe-rail:17rem;--ly-recipe-aside:20rem;--ly-app-shell-wide-areas:"header header" "sidebar main" "aside main" "footer footer";--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.28fr) minmax(0,1fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-size)),0.5fr) minmax(0,0.9fr)}}@layer ly.personalities.neumorphism{:where(.ly-root[data-ly-layout="neumorphism"]){--ly-personality-wrapper-max:84rem;--ly-profile-gap:var(--ly-space-6);--ly-grid-min:17rem;--ly-recipe-rail:17rem;--ly-recipe-aside:19rem;--ly-app-shell-wide-areas:"header sidebar" "main sidebar" "aside sidebar" "footer sidebar";--ly-app-shell-wide-columns:minmax(0,1fr) minmax(min(100%,var(--ly-recipe-rail)),0.3fr);--ly-list-detail-wide-columns:minmax(0,1.1fr) minmax(min(100%,var(--ly-pane-size)),0.7fr)}}@layer ly.personalities.retrofuturism{:where(.ly-root[data-ly-layout="retrofuturism"]){--ly-personality-wrapper-max:106rem;--ly-profile-gap:var(--ly-space-5);--ly-grid-min:14rem;--ly-recipe-rail:14rem;--ly-recipe-aside:17rem;--ly-app-shell-wide-areas:"sidebar header aside" "sidebar main aside" "sidebar footer aside";--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.24fr) minmax(0,1fr) minmax(min(100%,var(--ly-recipe-aside)),0.3fr)}}@layer ly.personalities.brutalism{:where(.ly-root[data-ly-layout="brutalism"]){--ly-personality-wrapper-max:100rem;--ly-profile-gap:var(--ly-space-3);--ly-grid-min:14rem;--ly-recipe-rail:16rem;--ly-recipe-aside:18rem;--ly-app-shell-wide-areas:"header header sidebar" "main aside sidebar" "footer footer sidebar";--ly-app-shell-wide-columns:minmax(0,1.3fr) minmax(0,0.7fr) minmax(min(100%,var(--ly-recipe-rail)),0.34fr)}}@layer ly.personalities.cyberpunk{:where(.ly-root[data-ly-layout="cyberpunk"]){--ly-personality-wrapper-max:112rem;--ly-profile-gap:var(--ly-space-4);--ly-grid-min:12rem;--ly-recipe-rail:13rem;--ly-recipe-aside:19rem;--ly-app-shell-wide-areas:"sidebar header header" "sidebar main aside" "sidebar footer footer";--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.2fr) minmax(0,1fr) minmax(min(100%,var(--ly-recipe-aside)),0.32fr)}}@layer ly.personalities.y2k{:where(.ly-root[data-ly-layout="y2k"]){--ly-personality-wrapper-max:90rem;--ly-profile-gap:var(--ly-space-6);--ly-grid-min:13rem;--ly-recipe-rail:18rem;--ly-recipe-aside:16rem;--ly-app-shell-wide-areas:"header header sidebar" "aside main sidebar" "footer footer sidebar";--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-aside)),0.34fr) minmax(0,1fr) minmax(min(100%,var(--ly-recipe-rail)),0.28fr)}}@layer ly.personalities.retro-glass{:where(.ly-root[data-ly-layout="retro-glass"]){--ly-personality-wrapper-max:104rem;--ly-profile-gap:var(--ly-space-5);--ly-grid-min:15rem;--ly-recipe-rail:18rem;--ly-recipe-aside:18rem;--ly-app-shell-wide-areas:"header header sidebar" "main main sidebar" "aside footer footer";--ly-app-shell-wide-columns:minmax(0,1.25fr) minmax(0,0.75fr) minmax(min(100%,var(--ly-recipe-rail)),0.32fr)}}@layer ly.personalities.f-pattern{:where(.ly-root[data-ly-layout="f-pattern"]){--ly-personality-wrapper-max:92rem;--ly-profile-gap:var(--ly-space-4);--ly-grid-min:14rem;--ly-recipe-rail:16rem;--ly-recipe-aside:18rem;--ly-app-shell-wide-areas:"sidebar header header" "sidebar main aside" "sidebar footer footer";--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.26fr) minmax(0,1.35fr) minmax(min(100%,var(--ly-recipe-aside)),0.65fr);--ly-split-hero-wide-columns:minmax(0,1.8fr) minmax(0,0.8fr)}}@layer ly.personalities.z-pattern{:where(.ly-root[data-ly-layout="z-pattern"]){--ly-personality-wrapper-max:108rem;--ly-profile-gap:var(--ly-space-5);--ly-grid-min:14rem;--ly-recipe-rail:17rem;--ly-recipe-aside:19rem;--ly-app-shell-wide-areas:"header header sidebar" "main aside sidebar" "footer aside sidebar";--ly-app-shell-wide-columns:minmax(0,1.45fr) minmax(min(100%,var(--ly-recipe-aside)),0.55fr) minmax(min(100%,var(--ly-recipe-rail)),0.3fr);--ly-split-hero-wide-columns:minmax(0,1.5fr) minmax(0,0.5fr)}}@layer ly.personalities.split-screen{:where(.ly-root[data-ly-layout="split-screen"]){--ly-personality-wrapper-max:100%;--ly-profile-gap:var(--ly-space-4);--ly-grid-min:20rem;--ly-recipe-rail:24rem;--ly-recipe-aside:24rem;--ly-app-shell-wide-areas:"header header" "main sidebar" "aside sidebar" "footer footer";--ly-app-shell-wide-columns:minmax(0,1fr) minmax(0,1fr);--ly-split-hero-wide-columns:minmax(0,1fr) minmax(0,1fr);--ly-list-detail-wide-columns:minmax(0,1fr) minmax(0,1fr)}}@layer ly.personalities.mondrian{:where(.ly-root[data-ly-layout="mondrian"]){--ly-personality-wrapper-max:112rem;--ly-profile-gap:var(--ly-space-3);--ly-grid-min:11rem;--ly-recipe-rail:13rem;--ly-recipe-aside:18rem;--ly-app-shell-wide-areas:"sidebar header header" "sidebar main aside" "footer footer aside";--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.22fr) minmax(0,1.45fr) minmax(min(100%,var(--ly-recipe-aside)),0.55fr)}}@layer ly.personalities.synthwave{:where(.ly-root[data-ly-layout="synthwave"]){--ly-personality-wrapper-max:112rem;--ly-profile-gap:var(--ly-space-6);--ly-grid-min:14rem;--ly-recipe-rail:16rem;--ly-recipe-aside:20rem;--ly-app-shell-wide-areas:"header header header" "sidebar main aside" "footer footer footer";--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.28fr) minmax(0,1fr) minmax(min(100%,var(--ly-recipe-aside)),0.34fr);--ly-reel-item-min:20rem}} diff --git a/dist/legacy.css b/dist/legacy.css deleted file mode 100644 index 4dadc0b..0000000 --- a/dist/legacy.css +++ /dev/null @@ -1,822 +0,0 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -@import url("./layout-style-css.css"); - -@layer ly.legacy { - /* Preserve v1 wrapper measures while applications migrate to semantic v2 names. */ - .ly-container { - container-name: ly-wrapper; - container-type: inline-size; - width: min(100% - (var(--ly-page-padding-inline) * 2), var(--ly-container-max)); - margin-inline: auto; - } - - .ly-container--sm, - .ly-wrapper--sm { - --ly-container-max: var(--ly-container-sm); - --ly-wrapper-max: 40rem; - } - - .ly-container--md, - .ly-wrapper--md { - --ly-container-max: var(--ly-container-md); - --ly-wrapper-max: 56rem; - } - - .ly-container--lg, - .ly-wrapper--lg { - --ly-container-max: var(--ly-container-lg); - --ly-wrapper-max: 72rem; - } - - .ly-container--xl, - .ly-wrapper--xl { - --ly-container-max: var(--ly-container-xl); - --ly-wrapper-max: 88rem; - } - - .ly-container--wide { - --ly-container-max: var(--ly-container-wide); - } - - .ly-container--fluid { - width: 100%; - max-width: none; - padding-inline: var(--ly-wrapper-gutter); - } - - .ly-wrapper--fluid { - --ly-wrapper-max: 100%; - } - - .ly-wrapper--readable { - --ly-wrapper-max: 68ch; - } - - .ly-row { - display: flex; - flex-wrap: wrap; - /* Outer compensation preserves exact percentage tracks while columns own gutters. */ - margin-inline: calc(var(--ly-gutter, var(--ly-gap)) * -0.5); - } - - .ly-col { - flex: 1 1 0; - min-inline-size: 0; - padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); - } - - .ly-col-1 { flex: 0 0 auto; width: 8.333333%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - .ly-col-2 { flex: 0 0 auto; width: 16.666667%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - .ly-col-3 { flex: 0 0 auto; width: 25%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - .ly-col-4 { flex: 0 0 auto; width: 33.333333%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - .ly-col-5 { flex: 0 0 auto; width: 41.666667%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - .ly-col-6 { flex: 0 0 auto; width: 50%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - .ly-col-7 { flex: 0 0 auto; width: 58.333333%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - .ly-col-8 { flex: 0 0 auto; width: 66.666667%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - .ly-col-9 { flex: 0 0 auto; width: 75%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - .ly-col-10 { flex: 0 0 auto; width: 83.333333%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - .ly-col-11 { flex: 0 0 auto; width: 91.666667%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - .ly-col-12 { flex: 0 0 auto; width: 100%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - - .ly-carousel { - display: grid; - grid-auto-flow: column; - grid-auto-columns: minmax(min(100%, var(--ly-reel-item-min)), var(--ly-reel-item-max)); - gap: var(--ly-grid-gap); - overflow-x: auto; - overflow-inline: auto; - overscroll-behavior-inline: contain; - scroll-snap-type: inline proximity; - } - - .ly-carousel > * { - min-inline-size: 0; - scroll-snap-align: start; - } - - .ly-button-group { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: var(--ly-cluster-gap); - } - - .ly-button-group > * { - flex: 0 1 auto; - min-inline-size: min(100%, var(--ly-button-min, 8rem)); - } - - .ly-sidebar-layout { - display: grid; - grid-template-columns: minmax(0, 1fr); - gap: var(--ly-gap); - } - - .ly-sidebar-layout > * { - min-inline-size: 0; - } - - .ly-content { - min-inline-size: 0; - } - - .ly-divider { - /* V2 preserves separator geometry here; themes remain responsible for visible paint. */ - min-block-size: 1px; - margin-block: var(--ly-space-5); - } - - .ly-card-sm { min-block-size: var(--ly-card-size-sm); } - .ly-card-md { min-block-size: var(--ly-card-size-md); } - .ly-card-lg { min-block-size: var(--ly-card-size-lg); } - - .ly-scroll-area { - min-block-size: 0; - max-block-size: var(--ly-scroll-max); - overflow: auto; - overscroll-behavior: contain; - } - - .ly-app-header { grid-area: header; min-inline-size: 0; } - .ly-app-sidebar { grid-area: sidebar; min-inline-size: 0; } - .ly-app-main { grid-area: main; min-inline-size: 0; } - .ly-app-aside { grid-area: aside; min-inline-size: 0; } - .ly-app-footer { grid-area: footer; min-inline-size: 0; } - - /* The build expands canonical personality rules into functional v1 aliases here. */ - /* V1 personality aliases for minimal-saas; generated from the canonical v2 source. */ -:where(.ly-root[data-layout="minimal-saas"], .ly-root[layout-style="minimal-saas"], .ly-root.ly-layout-minimal-saas, .ly-root.ly-style-minimal-saas) { - --ly-recipe-rail: 15rem; - --ly-recipe-aside: 16rem; - --ly-grid-columns: 4; - --ly-grid-min: 16rem; - --ly-personality-wrapper-max: 88rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-layout="minimal-saas"], .ly-root[layout-style="minimal-saas"], .ly-root.ly-layout-minimal-saas, .ly-root.ly-style-minimal-saas) .ly-grid > :nth-child(4n + 1) { - grid-column: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-layout="minimal-saas"], .ly-root[layout-style="minimal-saas"], .ly-root.ly-layout-minimal-saas, .ly-root.ly-style-minimal-saas) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header header" - "sidebar main aside" - "sidebar footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 15rem), 0.24fr) - minmax(0, 1fr) - minmax(min(100%, 16rem), 0.28fr); - } - } - -/* V1 personality aliases for bento; generated from the canonical v2 source. */ -:where(.ly-root[data-layout="bento"], .ly-root[layout-style="bento"], .ly-root.ly-layout-bento, .ly-root.ly-style-bento) { - --ly-grid-columns: 6; - --ly-grid-min: 12rem; - --ly-card-grid-min: 13rem; - --ly-personality-wrapper-max: 112rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-layout="bento"], .ly-root[layout-style="bento"], .ly-root.ly-layout-bento, .ly-root.ly-style-bento) .ly-grid > :nth-child(6n + 1) { - grid-column: span 2; - grid-row: span 2; - } - - :where(.ly-root[data-layout="bento"], .ly-root[layout-style="bento"], .ly-root.ly-layout-bento, .ly-root.ly-style-bento) - :where(.ly-card-grid, [data-ly-recipe="card-grid"]) - > :nth-child(6n + 1) { - grid-column: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-layout="bento"], .ly-root[layout-style="bento"], .ly-root.ly-layout-bento, .ly-root.ly-style-bento) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header header" - "sidebar main main" - "aside main main" - "footer footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto auto; - grid-template-columns: - minmax(min(100%, 14rem), 0.3fr) - minmax(0, 1fr) - minmax(0, 1fr); - } - } - -/* V1 personality aliases for maximalist; generated from the canonical v2 source. */ -:where(.ly-root[data-layout="maximalist"], .ly-root[layout-style="maximalist"], .ly-root.ly-layout-maximalist, .ly-root.ly-style-maximalist) { - --ly-grid-columns: 12; - --ly-grid-min: 10rem; - --ly-personality-wrapper-max: 100%; - --ly-card-grid-min: 12rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-layout="maximalist"], .ly-root[layout-style="maximalist"], .ly-root.ly-layout-maximalist, .ly-root.ly-style-maximalist) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 18rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 56rem) { - :where(.ly-root[data-layout="maximalist"], .ly-root[layout-style="maximalist"], .ly-root.ly-layout-maximalist, .ly-root.ly-style-maximalist) .ly-grid > :nth-child(7n + 1) { - grid-column: span 3; - grid-row: span 2; - } - - :where(.ly-root[data-layout="maximalist"], .ly-root[layout-style="maximalist"], .ly-root.ly-layout-maximalist, .ly-root.ly-style-maximalist) - :where(.ly-gallery, [data-ly-recipe="gallery"]) - > :nth-child(5n + 1) { - grid-column: span 2; - grid-row: span 2; - } - } - - /* The four-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-layout="maximalist"], .ly-root[layout-style="maximalist"], .ly-root.ly-layout-maximalist, .ly-root.ly-style-maximalist) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header header header" - "main main sidebar aside" - "main main footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(0, 1.4fr) - minmax(0, 0.6fr) - minmax(min(100%, 15rem), 0.32fr) - minmax(min(100%, 18rem), 0.38fr); - } - } - -/* V1 personality aliases for bauhaus; generated from the canonical v2 source. */ -:where(.ly-root[data-layout="bauhaus"], .ly-root[layout-style="bauhaus"], .ly-root.ly-layout-bauhaus, .ly-root.ly-style-bauhaus) { - --ly-recipe-rail: 14rem; - --ly-recipe-aside: 18rem; - --ly-grid-columns: 6; - --ly-grid-min: 13rem; - --ly-personality-wrapper-max: 96rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - /* Cap the fallback rail until the wider personality template is eligible. */ - @container (min-width: 48rem) { - :where(.ly-root[data-layout="bauhaus"], .ly-root[layout-style="bauhaus"], .ly-root.ly-layout-bauhaus, .ly-root.ly-style-bauhaus) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 14rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 52rem) { - :where(.ly-root[data-layout="bauhaus"], .ly-root[layout-style="bauhaus"], .ly-root.ly-layout-bauhaus, .ly-root.ly-style-bauhaus) .ly-grid > :nth-child(3n + 1) { - grid-column: span 2; - grid-row: span 2; - } - } - - /* The four-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-layout="bauhaus"], .ly-root[layout-style="bauhaus"], .ly-root.ly-layout-bauhaus, .ly-root.ly-style-bauhaus) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header header aside" - "sidebar main main aside" - "sidebar footer footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 14rem), 0.24fr) - minmax(0, 0.7fr) - minmax(0, 1.3fr) - minmax(min(100%, 18rem), 0.3fr); - } - } - -/* V1 personality aliases for tactile; generated from the canonical v2 source. */ -:where(.ly-root[data-layout="tactile"], .ly-root[layout-style="tactile"], .ly-root.ly-layout-tactile, .ly-root.ly-style-tactile) { - --ly-recipe-rail: 17rem; - --ly-recipe-aside: 20rem; - --ly-grid-columns: 5; - --ly-grid-min: 15rem; - --ly-personality-wrapper-max: 82rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-layout="tactile"], .ly-root[layout-style="tactile"], .ly-root.ly-layout-tactile, .ly-root.ly-style-tactile) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header" - "sidebar main" - "sidebar aside" - "sidebar footer"; - grid-template-rows: auto minmax(0, 1fr) auto auto; - grid-template-columns: minmax(min(100%, 17rem), 0.28fr) minmax(0, 1fr); - } - - :where(.ly-root[data-layout="tactile"], .ly-root[layout-style="tactile"], .ly-root.ly-layout-tactile, .ly-root.ly-style-tactile) .ly-grid > :nth-child(5n + 2) { - grid-column: span 2; - } - - :where(.ly-root[data-layout="tactile"], .ly-root[layout-style="tactile"], .ly-root.ly-layout-tactile, .ly-root.ly-style-tactile) - :where(.ly-list-detail, [data-ly-recipe="list-detail"]) { - grid-template-columns: minmax(min(100%, 20rem), 0.42fr) minmax(0, 0.58fr); - } - } - -/* V1 personality aliases for neumorphism; generated from the canonical v2 source. */ -:where(.ly-root[data-layout="neumorphism"], .ly-root[layout-style="neumorphism"], .ly-root.ly-layout-neumorphism, .ly-root.ly-style-neumorphism) { - --ly-recipe-rail: 17rem; - --ly-recipe-aside: 19rem; - --ly-grid-columns: 4; - --ly-grid-min: 17rem; - --ly-personality-wrapper-max: 84rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-layout="neumorphism"], .ly-root[layout-style="neumorphism"], .ly-root.ly-layout-neumorphism, .ly-root.ly-style-neumorphism) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 17rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 52rem) { - :where(.ly-root[data-layout="neumorphism"], .ly-root[layout-style="neumorphism"], .ly-root.ly-layout-neumorphism, .ly-root.ly-style-neumorphism) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header sidebar" - "main sidebar" - "aside sidebar" - "footer sidebar"; - grid-template-rows: auto minmax(0, 1fr) auto auto; - grid-template-columns: minmax(0, 1fr) minmax(min(100%, 17rem), 0.3fr); - } - - :where(.ly-root[data-layout="neumorphism"], .ly-root[layout-style="neumorphism"], .ly-root.ly-layout-neumorphism, .ly-root.ly-style-neumorphism) .ly-grid > :nth-child(4n + 1) { - grid-column: span 2; - } - - :where(.ly-root[data-layout="neumorphism"], .ly-root[layout-style="neumorphism"], .ly-root.ly-layout-neumorphism, .ly-root.ly-style-neumorphism) - :where(.ly-list-detail, [data-ly-recipe="list-detail"]) { - grid-template-columns: minmax(0, 0.58fr) minmax(min(100%, 19rem), 0.42fr); - } - } - -/* V1 personality aliases for retrofuturism; generated from the canonical v2 source. */ -:where(.ly-root[data-layout="retrofuturism"], .ly-root[layout-style="retrofuturism"], .ly-root.ly-layout-retrofuturism, .ly-root.ly-style-retrofuturism) { - --ly-recipe-rail: 14rem; - --ly-recipe-aside: 17rem; - --ly-grid-columns: 6; - --ly-grid-min: 14rem; - --ly-personality-wrapper-max: 106rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-layout="retrofuturism"], .ly-root[layout-style="retrofuturism"], .ly-root.ly-layout-retrofuturism, .ly-root.ly-style-retrofuturism) .ly-grid > :nth-child(6n + 1) { - grid-column: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-layout="retrofuturism"], .ly-root[layout-style="retrofuturism"], .ly-root.ly-layout-retrofuturism, .ly-root.ly-style-retrofuturism) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header aside" - "sidebar main aside" - "sidebar footer aside"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 14rem), 0.24fr) - minmax(0, 1fr) - minmax(min(100%, 17rem), 0.3fr); - } - } - -/* V1 personality aliases for brutalism; generated from the canonical v2 source. */ -:where(.ly-root[data-layout="brutalism"], .ly-root[layout-style="brutalism"], .ly-root.ly-layout-brutalism, .ly-root.ly-style-brutalism) { - --ly-recipe-rail: 18rem; - --ly-recipe-aside: 16rem; - --ly-grid-columns: 6; - --ly-grid-min: 14rem; - --ly-personality-wrapper-max: 100rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-layout="brutalism"], .ly-root[layout-style="brutalism"], .ly-root.ly-layout-brutalism, .ly-root.ly-style-brutalism) .ly-grid > :nth-child(3n) { - grid-column: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-layout="brutalism"], .ly-root[layout-style="brutalism"], .ly-root.ly-layout-brutalism, .ly-root.ly-style-brutalism) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header sidebar" - "main aside sidebar" - "footer footer sidebar"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(0, 1.3fr) - minmax(min(100%, 16rem), 0.7fr) - minmax(min(100%, 18rem), 0.34fr); - } - } - -/* V1 personality aliases for cyberpunk; generated from the canonical v2 source. */ -:where(.ly-root[data-layout="cyberpunk"], .ly-root[layout-style="cyberpunk"], .ly-root.ly-layout-cyberpunk, .ly-root.ly-style-cyberpunk) { - --ly-recipe-rail: 13rem; - --ly-recipe-aside: 19rem; - --ly-grid-columns: 8; - --ly-grid-min: 12rem; - --ly-personality-wrapper-max: 112rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 44rem) { - :where(.ly-root[data-layout="cyberpunk"], .ly-root[layout-style="cyberpunk"], .ly-root.ly-layout-cyberpunk, .ly-root.ly-style-cyberpunk) .ly-grid > :nth-child(4n + 2) { - grid-column: span 3; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-layout="cyberpunk"], .ly-root[layout-style="cyberpunk"], .ly-root.ly-layout-cyberpunk, .ly-root.ly-style-cyberpunk) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header aside" - "sidebar main aside" - "sidebar footer aside"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 13rem), 0.2fr) - minmax(0, 1fr) - minmax(min(100%, 19rem), 0.32fr); - } - } - -/* V1 personality aliases for y2k; generated from the canonical v2 source. */ -:where(.ly-root[data-layout="y2k"], .ly-root[layout-style="y2k"], .ly-root.ly-layout-y2k, .ly-root.ly-style-y2k) { - --ly-recipe-rail: 16rem; - --ly-recipe-aside: 18rem; - --ly-grid-columns: 5; - --ly-grid-min: 13rem; - --ly-personality-wrapper-max: 90rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-layout="y2k"], .ly-root[layout-style="y2k"], .ly-root.ly-layout-y2k, .ly-root.ly-style-y2k) .ly-grid > :nth-child(5n + 1) { - grid-column: span 3; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-layout="y2k"], .ly-root[layout-style="y2k"], .ly-root.ly-layout-y2k, .ly-root.ly-style-y2k) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header sidebar" - "aside main sidebar" - "footer footer sidebar"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 18rem), 0.34fr) - minmax(0, 1fr) - minmax(min(100%, 16rem), 0.28fr); - } - } - -/* V1 personality aliases for retro-glass; generated from the canonical v2 source. */ -:where(.ly-root[data-layout="retro-glass"], .ly-root[layout-style="retro-glass"], .ly-root.ly-layout-retro-glass, .ly-root.ly-style-retro-glass) { - --ly-recipe-rail: 18rem; - --ly-recipe-aside: 20rem; - --ly-grid-columns: 8; - --ly-grid-min: 15rem; - --ly-personality-wrapper-max: 104rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-layout="retro-glass"], .ly-root[layout-style="retro-glass"], .ly-root.ly-layout-retro-glass, .ly-root.ly-style-retro-glass) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 18rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 56rem) { - :where(.ly-root[data-layout="retro-glass"], .ly-root[layout-style="retro-glass"], .ly-root.ly-layout-retro-glass, .ly-root.ly-style-retro-glass) .ly-grid > :nth-child(4n) { - grid-column: span 2; - grid-row: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-layout="retro-glass"], .ly-root[layout-style="retro-glass"], .ly-root.ly-layout-retro-glass, .ly-root.ly-style-retro-glass) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header sidebar" - "main main sidebar" - "aside footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(0, 1.25fr) - minmax(0, 0.75fr) - minmax(min(100%, 18rem), 0.32fr); - } - } - -/* V1 personality aliases for f-pattern; generated from the canonical v2 source. */ -:where(.ly-root[data-layout="f-pattern"], .ly-root[layout-style="f-pattern"], .ly-root.ly-layout-f-pattern, .ly-root.ly-style-f-pattern) { - --ly-recipe-rail: 16rem; - --ly-recipe-aside: 18rem; - --ly-grid-columns: 6; - --ly-grid-min: 14rem; - --ly-personality-wrapper-max: 92rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-layout="f-pattern"], .ly-root[layout-style="f-pattern"], .ly-root.ly-layout-f-pattern, .ly-root.ly-style-f-pattern) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 16rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 56rem) { - :where(.ly-root[data-layout="f-pattern"], .ly-root[layout-style="f-pattern"], .ly-root.ly-layout-f-pattern, .ly-root.ly-style-f-pattern) .ly-grid > :nth-child(3n + 1) { - grid-column: span 2; - } - - :where(.ly-root[data-layout="f-pattern"], .ly-root[layout-style="f-pattern"], .ly-root.ly-layout-f-pattern, .ly-root.ly-style-f-pattern) - :where(.ly-split-hero, [data-ly-recipe="split-hero"]) { - grid-template-columns: minmax(0, 1.35fr) minmax(0, 0.65fr); - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-layout="f-pattern"], .ly-root[layout-style="f-pattern"], .ly-root.ly-layout-f-pattern, .ly-root.ly-style-f-pattern) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header header" - "sidebar main aside" - "sidebar footer aside"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 16rem), 0.26fr) - minmax(0, 1.35fr) - minmax(min(100%, 18rem), 0.65fr); - } - } - -/* V1 personality aliases for z-pattern; generated from the canonical v2 source. */ -:where(.ly-root[data-layout="z-pattern"], .ly-root[layout-style="z-pattern"], .ly-root.ly-layout-z-pattern, .ly-root.ly-style-z-pattern) { - --ly-recipe-rail: 17rem; - --ly-recipe-aside: 19rem; - --ly-grid-columns: 8; - --ly-grid-min: 14rem; - --ly-personality-wrapper-max: 108rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-layout="z-pattern"], .ly-root[layout-style="z-pattern"], .ly-root.ly-layout-z-pattern, .ly-root.ly-style-z-pattern) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 17rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 60rem) { - :where(.ly-root[data-layout="z-pattern"], .ly-root[layout-style="z-pattern"], .ly-root.ly-layout-z-pattern, .ly-root.ly-style-z-pattern) .ly-grid > :nth-child(4n + 2) { - grid-column: span 2; - align-self: end; - } - - :where(.ly-root[data-layout="z-pattern"], .ly-root[layout-style="z-pattern"], .ly-root.ly-layout-z-pattern, .ly-root.ly-style-z-pattern) - :where(.ly-split-hero, [data-ly-recipe="split-hero"]) { - grid-template-columns: minmax(0, 1.5fr) minmax(0, 0.5fr); - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-layout="z-pattern"], .ly-root[layout-style="z-pattern"], .ly-root.ly-layout-z-pattern, .ly-root.ly-style-z-pattern) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header sidebar" - "main aside sidebar" - "footer aside sidebar"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(0, 1.45fr) - minmax(min(100%, 19rem), 0.55fr) - minmax(min(100%, 17rem), 0.3fr); - } - } - -/* V1 personality aliases for split-screen; generated from the canonical v2 source. */ -:where(.ly-root[data-layout="split-screen"], .ly-root[layout-style="split-screen"], .ly-root.ly-layout-split-screen, .ly-root.ly-style-split-screen) { - --ly-grid-columns: 2; - --ly-grid-min: 20rem; - --ly-personality-wrapper-max: 100%; - --ly-split-primary: 1fr; - --ly-split-secondary: 1fr; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-layout="split-screen"], .ly-root[layout-style="split-screen"], .ly-root.ly-layout-split-screen, .ly-root.ly-style-split-screen) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header" - "main sidebar" - "aside sidebar" - "footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto auto; - grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); - } - - :where(.ly-root[data-layout="split-screen"], .ly-root[layout-style="split-screen"], .ly-root.ly-layout-split-screen, .ly-root.ly-style-split-screen) - :where( - .ly-split, - .ly-split-hero, - [data-ly-recipe="split-hero"], - .ly-list-detail, - [data-ly-recipe="list-detail"] - ) { - grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); - } - } - -/* V1 personality aliases for mondrian; generated from the canonical v2 source. */ -:where(.ly-root[data-layout="mondrian"], .ly-root[layout-style="mondrian"], .ly-root.ly-layout-mondrian, .ly-root.ly-style-mondrian) { - --ly-recipe-rail: 13rem; - --ly-recipe-aside: 18rem; - --ly-grid-columns: 10; - --ly-grid-min: 11rem; - --ly-personality-wrapper-max: 112rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-layout="mondrian"], .ly-root[layout-style="mondrian"], .ly-root.ly-layout-mondrian, .ly-root.ly-style-mondrian) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 13rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 52rem) { - :where(.ly-root[data-layout="mondrian"], .ly-root[layout-style="mondrian"], .ly-root.ly-layout-mondrian, .ly-root.ly-style-mondrian) .ly-grid > :nth-child(5n + 1) { - grid-column: span 2; - grid-row: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-layout="mondrian"], .ly-root[layout-style="mondrian"], .ly-root.ly-layout-mondrian, .ly-root.ly-style-mondrian) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header header" - "sidebar main aside" - "footer footer aside"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 13rem), 0.22fr) - minmax(0, 1.45fr) - minmax(min(100%, 18rem), 0.55fr); - } - } - -/* V1 personality aliases for synthwave; generated from the canonical v2 source. */ -:where(.ly-root[data-layout="synthwave"], .ly-root[layout-style="synthwave"], .ly-root.ly-layout-synthwave, .ly-root.ly-style-synthwave) { - --ly-recipe-rail: 16rem; - --ly-recipe-aside: 20rem; - --ly-grid-columns: 12; - --ly-grid-min: 14rem; - --ly-reel-item-max: 34rem; - --ly-personality-wrapper-max: 112rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-layout="synthwave"], .ly-root[layout-style="synthwave"], .ly-root.ly-layout-synthwave, .ly-root.ly-style-synthwave) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 16rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 64rem) { - :where(.ly-root[data-layout="synthwave"], .ly-root[layout-style="synthwave"], .ly-root.ly-layout-synthwave, .ly-root.ly-style-synthwave) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header header" - "sidebar main aside" - "footer footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 16rem), 0.28fr) - minmax(0, 1fr) - minmax(min(100%, 20rem), 0.34fr); - } - - :where(.ly-root[data-layout="synthwave"], .ly-root[layout-style="synthwave"], .ly-root.ly-layout-synthwave, .ly-root.ly-style-synthwave) .ly-grid > :nth-child(4n + 1) { - grid-column: span 3; - } - - :where(.ly-root[data-layout="synthwave"], .ly-root[layout-style="synthwave"], .ly-root.ly-layout-synthwave, .ly-root.ly-style-synthwave) .ly-reel { - grid-auto-columns: minmax(min(100%, 20rem), var(--ly-reel-item-max)); - } - } - - @container (min-width: 48rem) { - .ly-sidebar-layout { - grid-template-columns: minmax(min(100%, var(--ly-sidebar-min)), var(--ly-sidebar-max)) minmax(0, 1fr); - align-items: start; - } - - .ly-sidebar-layout--right { - grid-template-columns: minmax(0, 1fr) minmax(min(100%, var(--ly-sidebar-min)), var(--ly-sidebar-max)); - } - - .ly-panes--two { - grid-template-columns: minmax(0, 1fr) minmax(min(100%, var(--ly-pane-size)), 0.7fr); - } - } - - @container (min-width: 64rem) { - .ly-panes--three { - grid-template-columns: - minmax(min(100%, var(--ly-pane-rail, 14rem)), 0.35fr) - minmax(0, 1fr) - minmax(min(100%, var(--ly-pane-rail, 14rem)), 0.35fr); - } - } -} diff --git a/dist/personalities.css b/dist/personalities.css index 29016df..b98c221 100644 --- a/dist/personalities.css +++ b/dist/personalities.css @@ -1,4 +1,4 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @import url("./personalities/minimal-saas.css"); @import url("./personalities/bento.css"); diff --git a/dist/personalities/bauhaus.css b/dist/personalities/bauhaus.css index c08ebb2..52ce8c2 100644 --- a/dist/personalities/bauhaus.css +++ b/dist/personalities/bauhaus.css @@ -1,49 +1,20 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* Layout style: bauhaus. A left rail anchors an intentionally asymmetric grid. */ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @layer ly.personalities.bauhaus { :where(.ly-root[data-ly-layout="bauhaus"]) { + --ly-personality-wrapper-max: 96rem; + --ly-profile-gap: var(--ly-space-6); + --ly-grid-min: 13rem; --ly-recipe-rail: 14rem; --ly-recipe-aside: 18rem; - --ly-grid-columns: 6; - --ly-grid-min: 13rem; - --ly-personality-wrapper-max: 96rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - /* Cap the fallback rail until the wider personality template is eligible. */ - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="bauhaus"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 14rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 52rem) { - :where(.ly-root[data-ly-layout="bauhaus"]) .ly-grid > :nth-child(3n + 1) { - grid-column: span 2; - grid-row: span 2; - } - } - - /* The four-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="bauhaus"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header header aside" - "sidebar main main aside" - "sidebar footer footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 14rem), 0.24fr) - minmax(0, 0.7fr) - minmax(0, 1.3fr) - minmax(min(100%, 18rem), 0.3fr); - } + --ly-app-shell-wide-areas: + "header header header header" + "sidebar main main aside" + "sidebar footer footer aside"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.24fr) + minmax(0, 0.7fr) + minmax(0, 1.3fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.3fr); } } diff --git a/dist/personalities/bento.css b/dist/personalities/bento.css index 29121d6..33d50f1 100644 --- a/dist/personalities/bento.css +++ b/dist/personalities/bento.css @@ -1,46 +1,22 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* Layout style: bento. A full-width shell and staggered spans form modular tiles. */ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @layer ly.personalities.bento { :where(.ly-root[data-ly-layout="bento"]) { - --ly-grid-columns: 6; - --ly-grid-min: 12rem; - --ly-card-grid-min: 13rem; --ly-personality-wrapper-max: 112rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="bento"]) .ly-grid > :nth-child(6n + 1) { - grid-column: span 2; - grid-row: span 2; - } - - :where(.ly-root[data-ly-layout="bento"]) - :where(.ly-card-grid, [data-ly-recipe="card-grid"]) - > :nth-child(6n + 1) { - grid-column: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="bento"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header header" - "sidebar main main" - "aside main main" - "footer footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto auto; - grid-template-columns: - minmax(min(100%, 14rem), 0.3fr) - minmax(0, 1fr) - minmax(0, 1fr); - } + --ly-profile-gap: var(--ly-space-4); + --ly-grid-min: 12rem; + --ly-card-grid-min: 14rem; + --ly-gallery-min: 11rem; + --ly-recipe-rail: 14rem; + --ly-recipe-aside: 18rem; + --ly-app-shell-wide-areas: + "header header header" + "sidebar main main" + "aside main main" + "footer footer footer"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.3fr) + minmax(0, 1fr) + minmax(0, 1fr); } } diff --git a/dist/personalities/brutalism.css b/dist/personalities/brutalism.css index f88a9e1..8815608 100644 --- a/dist/personalities/brutalism.css +++ b/dist/personalities/brutalism.css @@ -1,39 +1,19 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* Layout style: brutalism. A blunt right rail counters a broad primary plane. */ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @layer ly.personalities.brutalism { :where(.ly-root[data-ly-layout="brutalism"]) { - --ly-recipe-rail: 18rem; - --ly-recipe-aside: 16rem; - --ly-grid-columns: 6; - --ly-grid-min: 14rem; --ly-personality-wrapper-max: 100rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="brutalism"]) .ly-grid > :nth-child(3n) { - grid-column: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="brutalism"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header sidebar" - "main aside sidebar" - "footer footer sidebar"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(0, 1.3fr) - minmax(min(100%, 16rem), 0.7fr) - minmax(min(100%, 18rem), 0.34fr); - } + --ly-profile-gap: var(--ly-space-3); + --ly-grid-min: 14rem; + --ly-recipe-rail: 16rem; + --ly-recipe-aside: 18rem; + --ly-app-shell-wide-areas: + "header header sidebar" + "main aside sidebar" + "footer footer sidebar"; + --ly-app-shell-wide-columns: + minmax(0, 1.3fr) + minmax(0, 0.7fr) + minmax(min(100%, var(--ly-recipe-rail)), 0.34fr); } } diff --git a/dist/personalities/cyberpunk.css b/dist/personalities/cyberpunk.css index 3b715eb..dca349f 100644 --- a/dist/personalities/cyberpunk.css +++ b/dist/personalities/cyberpunk.css @@ -1,39 +1,19 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* Layout style: cyberpunk. A narrow command rail fronts a dense three-lane shell. */ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @layer ly.personalities.cyberpunk { :where(.ly-root[data-ly-layout="cyberpunk"]) { + --ly-personality-wrapper-max: 112rem; + --ly-profile-gap: var(--ly-space-4); + --ly-grid-min: 12rem; --ly-recipe-rail: 13rem; --ly-recipe-aside: 19rem; - --ly-grid-columns: 8; - --ly-grid-min: 12rem; - --ly-personality-wrapper-max: 112rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 44rem) { - :where(.ly-root[data-ly-layout="cyberpunk"]) .ly-grid > :nth-child(4n + 2) { - grid-column: span 3; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="cyberpunk"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header aside" - "sidebar main aside" - "sidebar footer aside"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 13rem), 0.2fr) - minmax(0, 1fr) - minmax(min(100%, 19rem), 0.32fr); - } + --ly-app-shell-wide-areas: + "sidebar header header" + "sidebar main aside" + "sidebar footer footer"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.2fr) + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.32fr); } } diff --git a/dist/personalities/f-pattern.css b/dist/personalities/f-pattern.css index de31747..904e0b7 100644 --- a/dist/personalities/f-pattern.css +++ b/dist/personalities/f-pattern.css @@ -1,51 +1,22 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; -/* Layout style: f-pattern. A left rail supports a wide first-reading column. */ - -@layer ly.personalities.f_pattern { +@layer ly.personalities.f-pattern { :where(.ly-root[data-ly-layout="f-pattern"]) { + --ly-personality-wrapper-max: 92rem; + --ly-profile-gap: var(--ly-space-4); + --ly-grid-min: 14rem; --ly-recipe-rail: 16rem; --ly-recipe-aside: 18rem; - --ly-grid-columns: 6; - --ly-grid-min: 14rem; - --ly-personality-wrapper-max: 92rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="f-pattern"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 16rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 56rem) { - :where(.ly-root[data-ly-layout="f-pattern"]) .ly-grid > :nth-child(3n + 1) { - grid-column: span 2; - } - - :where(.ly-root[data-ly-layout="f-pattern"]) - :where(.ly-split-hero, [data-ly-recipe="split-hero"]) { - grid-template-columns: minmax(0, 1.35fr) minmax(0, 0.65fr); - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="f-pattern"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header header" - "sidebar main aside" - "sidebar footer aside"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 16rem), 0.26fr) - minmax(0, 1.35fr) - minmax(min(100%, 18rem), 0.65fr); - } + --ly-app-shell-wide-areas: + "sidebar header header" + "sidebar main aside" + "sidebar footer footer"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.26fr) + minmax(0, 1.35fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.65fr); + --ly-split-hero-wide-columns: + minmax(0, 1.8fr) + minmax(0, 0.8fr); } } diff --git a/dist/personalities/maximalist.css b/dist/personalities/maximalist.css index a0be822..79fc40d 100644 --- a/dist/personalities/maximalist.css +++ b/dist/personalities/maximalist.css @@ -1,54 +1,22 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* Layout style: maximalist. A full-bleed four-track mosaic favors dramatic spans. */ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @layer ly.personalities.maximalist { :where(.ly-root[data-ly-layout="maximalist"]) { - --ly-grid-columns: 12; - --ly-grid-min: 10rem; --ly-personality-wrapper-max: 100%; - --ly-card-grid-min: 12rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="maximalist"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 18rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 56rem) { - :where(.ly-root[data-ly-layout="maximalist"]) .ly-grid > :nth-child(7n + 1) { - grid-column: span 3; - grid-row: span 2; - } - - :where(.ly-root[data-ly-layout="maximalist"]) - :where(.ly-gallery, [data-ly-recipe="gallery"]) - > :nth-child(5n + 1) { - grid-column: span 2; - grid-row: span 2; - } - } - - /* The four-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="maximalist"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header header header" - "main main sidebar aside" - "main main footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(0, 1.4fr) - minmax(0, 0.6fr) - minmax(min(100%, 15rem), 0.32fr) - minmax(min(100%, 18rem), 0.38fr); - } + --ly-profile-gap: var(--ly-space-7); + --ly-grid-min: 10rem; + --ly-card-grid-min: 13rem; + --ly-gallery-min: 10rem; + --ly-recipe-rail: 15rem; + --ly-recipe-aside: 18rem; + --ly-app-shell-wide-areas: + "header header header header" + "main main sidebar aside" + "main main footer footer"; + --ly-app-shell-wide-columns: + minmax(0, 1.4fr) + minmax(0, 0.6fr) + minmax(min(100%, var(--ly-recipe-rail)), 0.32fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.38fr); } } diff --git a/dist/personalities/minimal-saas.css b/dist/personalities/minimal-saas.css index 828f82e..9b2bb14 100644 --- a/dist/personalities/minimal-saas.css +++ b/dist/personalities/minimal-saas.css @@ -1,39 +1,13 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; -/* Layout style: minimal-saas. A measured left rail keeps work areas predictable. */ - -@layer ly.personalities.minimal_saas { +@layer ly.personalities.minimal-saas { :where(.ly-root[data-ly-layout="minimal-saas"]) { + --ly-personality-wrapper-max: 88rem; + --ly-profile-gap: var(--ly-space-5); + --ly-grid-min: 16rem; --ly-recipe-rail: 15rem; --ly-recipe-aside: 16rem; - --ly-grid-columns: 4; - --ly-grid-min: 16rem; - --ly-personality-wrapper-max: 88rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="minimal-saas"]) .ly-grid > :nth-child(4n + 1) { - grid-column: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="minimal-saas"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header header" - "sidebar main aside" - "sidebar footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 15rem), 0.24fr) - minmax(0, 1fr) - minmax(min(100%, 16rem), 0.28fr); - } + --ly-split-primary: 1.05fr; + --ly-split-secondary: 0.95fr; } } diff --git a/dist/personalities/mondrian.css b/dist/personalities/mondrian.css index 9e5c662..0b1fc66 100644 --- a/dist/personalities/mondrian.css +++ b/dist/personalities/mondrian.css @@ -1,47 +1,19 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* Layout style: mondrian. Unequal zones and spanning blocks create a strict mosaic. */ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @layer ly.personalities.mondrian { :where(.ly-root[data-ly-layout="mondrian"]) { + --ly-personality-wrapper-max: 112rem; + --ly-profile-gap: var(--ly-space-3); + --ly-grid-min: 11rem; --ly-recipe-rail: 13rem; --ly-recipe-aside: 18rem; - --ly-grid-columns: 10; - --ly-grid-min: 11rem; - --ly-personality-wrapper-max: 112rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="mondrian"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 13rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 52rem) { - :where(.ly-root[data-ly-layout="mondrian"]) .ly-grid > :nth-child(5n + 1) { - grid-column: span 2; - grid-row: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="mondrian"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header header" - "sidebar main aside" - "footer footer aside"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 13rem), 0.22fr) - minmax(0, 1.45fr) - minmax(min(100%, 18rem), 0.55fr); - } + --ly-app-shell-wide-areas: + "sidebar header header" + "sidebar main aside" + "footer footer aside"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.22fr) + minmax(0, 1.45fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.55fr); } } diff --git a/dist/personalities/neumorphism.css b/dist/personalities/neumorphism.css index 556c31d..be83073 100644 --- a/dist/personalities/neumorphism.css +++ b/dist/personalities/neumorphism.css @@ -1,46 +1,22 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* Layout style: neumorphism. A calm right rail preserves a compact workspace. */ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @layer ly.personalities.neumorphism { :where(.ly-root[data-ly-layout="neumorphism"]) { + --ly-personality-wrapper-max: 84rem; + --ly-profile-gap: var(--ly-space-6); + --ly-grid-min: 17rem; --ly-recipe-rail: 17rem; --ly-recipe-aside: 19rem; - --ly-grid-columns: 4; - --ly-grid-min: 17rem; - --ly-personality-wrapper-max: 84rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="neumorphism"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 17rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 52rem) { - :where(.ly-root[data-ly-layout="neumorphism"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header sidebar" - "main sidebar" - "aside sidebar" - "footer sidebar"; - grid-template-rows: auto minmax(0, 1fr) auto auto; - grid-template-columns: minmax(0, 1fr) minmax(min(100%, 17rem), 0.3fr); - } - - :where(.ly-root[data-ly-layout="neumorphism"]) .ly-grid > :nth-child(4n + 1) { - grid-column: span 2; - } - - :where(.ly-root[data-ly-layout="neumorphism"]) - :where(.ly-list-detail, [data-ly-recipe="list-detail"]) { - grid-template-columns: minmax(0, 0.58fr) minmax(min(100%, 19rem), 0.42fr); - } + --ly-app-shell-wide-areas: + "header sidebar" + "main sidebar" + "aside sidebar" + "footer sidebar"; + --ly-app-shell-wide-columns: + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-rail)), 0.3fr); + --ly-list-detail-wide-columns: + minmax(0, 1.1fr) + minmax(min(100%, var(--ly-pane-size)), 0.7fr); } } diff --git a/dist/personalities/retro-glass.css b/dist/personalities/retro-glass.css index 326d683..f0c959d 100644 --- a/dist/personalities/retro-glass.css +++ b/dist/personalities/retro-glass.css @@ -1,47 +1,19 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; -/* Layout style: retro-glass. A stepped right rail floats beside a wide stage. */ - -@layer ly.personalities.retro_glass { +@layer ly.personalities.retro-glass { :where(.ly-root[data-ly-layout="retro-glass"]) { - --ly-recipe-rail: 18rem; - --ly-recipe-aside: 20rem; - --ly-grid-columns: 8; - --ly-grid-min: 15rem; --ly-personality-wrapper-max: 104rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="retro-glass"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 18rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 56rem) { - :where(.ly-root[data-ly-layout="retro-glass"]) .ly-grid > :nth-child(4n) { - grid-column: span 2; - grid-row: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="retro-glass"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header sidebar" - "main main sidebar" - "aside footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(0, 1.25fr) - minmax(0, 0.75fr) - minmax(min(100%, 18rem), 0.32fr); - } + --ly-profile-gap: var(--ly-space-5); + --ly-grid-min: 15rem; + --ly-recipe-rail: 18rem; + --ly-recipe-aside: 18rem; + --ly-app-shell-wide-areas: + "header header sidebar" + "main main sidebar" + "aside footer footer"; + --ly-app-shell-wide-columns: + minmax(0, 1.25fr) + minmax(0, 0.75fr) + minmax(min(100%, var(--ly-recipe-rail)), 0.32fr); } } diff --git a/dist/personalities/retrofuturism.css b/dist/personalities/retrofuturism.css index 886ef09..106d878 100644 --- a/dist/personalities/retrofuturism.css +++ b/dist/personalities/retrofuturism.css @@ -1,39 +1,19 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* Layout style: retrofuturism. Twin rails frame a focused central work zone. */ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @layer ly.personalities.retrofuturism { :where(.ly-root[data-ly-layout="retrofuturism"]) { + --ly-personality-wrapper-max: 106rem; + --ly-profile-gap: var(--ly-space-5); + --ly-grid-min: 14rem; --ly-recipe-rail: 14rem; --ly-recipe-aside: 17rem; - --ly-grid-columns: 6; - --ly-grid-min: 14rem; - --ly-personality-wrapper-max: 106rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="retrofuturism"]) .ly-grid > :nth-child(6n + 1) { - grid-column: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="retrofuturism"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header aside" - "sidebar main aside" - "sidebar footer aside"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 14rem), 0.24fr) - minmax(0, 1fr) - minmax(min(100%, 17rem), 0.3fr); - } + --ly-app-shell-wide-areas: + "sidebar header aside" + "sidebar main aside" + "sidebar footer aside"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.24fr) + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.3fr); } } diff --git a/dist/personalities/split-screen.css b/dist/personalities/split-screen.css index 8ba8e06..4c95a76 100644 --- a/dist/personalities/split-screen.css +++ b/dist/personalities/split-screen.css @@ -1,41 +1,29 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; -/* Layout style: split-screen. Equal tracks keep two primary experiences in balance. */ - -@layer ly.personalities.split_screen { +@layer ly.personalities.split-screen { :where(.ly-root[data-ly-layout="split-screen"]) { - --ly-grid-columns: 2; - --ly-grid-min: 20rem; --ly-personality-wrapper-max: 100%; - --ly-split-primary: 1fr; - --ly-split-secondary: 1fr; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="split-screen"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header" - "main sidebar" - "aside sidebar" - "footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto auto; - grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); - } - - :where(.ly-root[data-ly-layout="split-screen"]) - :where( - .ly-split, - .ly-split-hero, - [data-ly-recipe="split-hero"], - .ly-list-detail, - [data-ly-recipe="list-detail"] - ) { - grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); - } + --ly-profile-gap: var(--ly-space-4); + --ly-grid-min: 20rem; + /* + Fixed preferred halves leave a shrink-safe center track in recipes that + retain the shared three-column dashboard topology. + */ + --ly-recipe-rail: 24rem; + --ly-recipe-aside: 24rem; + --ly-app-shell-wide-areas: + "header header" + "main sidebar" + "aside sidebar" + "footer footer"; + --ly-app-shell-wide-columns: + minmax(0, 1fr) + minmax(0, 1fr); + --ly-split-hero-wide-columns: + minmax(0, 1fr) + minmax(0, 1fr); + --ly-list-detail-wide-columns: + minmax(0, 1fr) + minmax(0, 1fr); } } diff --git a/dist/personalities/synthwave.css b/dist/personalities/synthwave.css index 063f77d..71f400a 100644 --- a/dist/personalities/synthwave.css +++ b/dist/personalities/synthwave.css @@ -1,48 +1,20 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* Layout style: synthwave. A cinematic center stage sits between support zones. */ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @layer ly.personalities.synthwave { :where(.ly-root[data-ly-layout="synthwave"]) { + --ly-personality-wrapper-max: 112rem; + --ly-profile-gap: var(--ly-space-6); + --ly-grid-min: 14rem; --ly-recipe-rail: 16rem; --ly-recipe-aside: 20rem; - --ly-grid-columns: 12; - --ly-grid-min: 14rem; - --ly-reel-item-max: 34rem; - --ly-personality-wrapper-max: 112rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="synthwave"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 16rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="synthwave"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header header" - "sidebar main aside" - "footer footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 16rem), 0.28fr) - minmax(0, 1fr) - minmax(min(100%, 20rem), 0.34fr); - } - - :where(.ly-root[data-ly-layout="synthwave"]) .ly-grid > :nth-child(4n + 1) { - grid-column: span 3; - } - - :where(.ly-root[data-ly-layout="synthwave"]) .ly-reel { - grid-auto-columns: minmax(min(100%, 20rem), var(--ly-reel-item-max)); - } + --ly-app-shell-wide-areas: + "header header header" + "sidebar main aside" + "footer footer footer"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.28fr) + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.34fr); + --ly-reel-item-min: 20rem; } } diff --git a/dist/personalities/tactile.css b/dist/personalities/tactile.css index a5f8120..e3ee930 100644 --- a/dist/personalities/tactile.css +++ b/dist/personalities/tactile.css @@ -1,39 +1,22 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* Layout style: tactile. A compact left rail leaves a broad, steady work lane. */ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @layer ly.personalities.tactile { :where(.ly-root[data-ly-layout="tactile"]) { + --ly-personality-wrapper-max: 82rem; + --ly-profile-gap: var(--ly-space-4); + --ly-grid-min: 15rem; --ly-recipe-rail: 17rem; --ly-recipe-aside: 20rem; - --ly-grid-columns: 5; - --ly-grid-min: 15rem; - --ly-personality-wrapper-max: 82rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="tactile"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header" - "sidebar main" - "sidebar aside" - "sidebar footer"; - grid-template-rows: auto minmax(0, 1fr) auto auto; - grid-template-columns: minmax(min(100%, 17rem), 0.28fr) minmax(0, 1fr); - } - - :where(.ly-root[data-ly-layout="tactile"]) .ly-grid > :nth-child(5n + 2) { - grid-column: span 2; - } - - :where(.ly-root[data-ly-layout="tactile"]) - :where(.ly-list-detail, [data-ly-recipe="list-detail"]) { - grid-template-columns: minmax(min(100%, 20rem), 0.42fr) minmax(0, 0.58fr); - } + --ly-app-shell-wide-areas: + "header header" + "sidebar main" + "aside main" + "footer footer"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.28fr) + minmax(0, 1fr); + --ly-list-detail-wide-columns: + minmax(min(100%, var(--ly-pane-size)), 0.5fr) + minmax(0, 0.9fr); } } diff --git a/dist/personalities/y2k.css b/dist/personalities/y2k.css index b696f4a..fbaa789 100644 --- a/dist/personalities/y2k.css +++ b/dist/personalities/y2k.css @@ -1,39 +1,19 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* Layout style: y2k. A tall right rail frames a reversed supporting workspace. */ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @layer ly.personalities.y2k { :where(.ly-root[data-ly-layout="y2k"]) { - --ly-recipe-rail: 16rem; - --ly-recipe-aside: 18rem; - --ly-grid-columns: 5; - --ly-grid-min: 13rem; --ly-personality-wrapper-max: 90rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="y2k"]) .ly-grid > :nth-child(5n + 1) { - grid-column: span 3; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="y2k"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header sidebar" - "aside main sidebar" - "footer footer sidebar"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 18rem), 0.34fr) - minmax(0, 1fr) - minmax(min(100%, 16rem), 0.28fr); - } + --ly-profile-gap: var(--ly-space-6); + --ly-grid-min: 13rem; + --ly-recipe-rail: 18rem; + --ly-recipe-aside: 16rem; + --ly-app-shell-wide-areas: + "header header sidebar" + "aside main sidebar" + "footer footer sidebar"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-aside)), 0.34fr) + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-rail)), 0.28fr); } } diff --git a/dist/personalities/z-pattern.css b/dist/personalities/z-pattern.css index 1960a48..8d6c46e 100644 --- a/dist/personalities/z-pattern.css +++ b/dist/personalities/z-pattern.css @@ -1,52 +1,22 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; -/* Layout style: z-pattern. A right rail closes a diagonal reading progression. */ - -@layer ly.personalities.z_pattern { +@layer ly.personalities.z-pattern { :where(.ly-root[data-ly-layout="z-pattern"]) { + --ly-personality-wrapper-max: 108rem; + --ly-profile-gap: var(--ly-space-5); + --ly-grid-min: 14rem; --ly-recipe-rail: 17rem; --ly-recipe-aside: 19rem; - --ly-grid-columns: 8; - --ly-grid-min: 14rem; - --ly-personality-wrapper-max: 108rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="z-pattern"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 17rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 60rem) { - :where(.ly-root[data-ly-layout="z-pattern"]) .ly-grid > :nth-child(4n + 2) { - grid-column: span 2; - align-self: end; - } - - :where(.ly-root[data-ly-layout="z-pattern"]) - :where(.ly-split-hero, [data-ly-recipe="split-hero"]) { - grid-template-columns: minmax(0, 1.5fr) minmax(0, 0.5fr); - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="z-pattern"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header sidebar" - "main aside sidebar" - "footer aside sidebar"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(0, 1.45fr) - minmax(min(100%, 19rem), 0.55fr) - minmax(min(100%, 17rem), 0.3fr); - } + --ly-app-shell-wide-areas: + "header header sidebar" + "main aside sidebar" + "footer aside sidebar"; + --ly-app-shell-wide-columns: + minmax(0, 1.45fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.55fr) + minmax(min(100%, var(--ly-recipe-rail)), 0.3fr); + --ly-split-hero-wide-columns: + minmax(0, 1.5fr) + minmax(0, 0.5fr); } } diff --git a/dist/primitives.css b/dist/primitives.css index b282bf4..1e957d1 100644 --- a/dist/primitives.css +++ b/dist/primitives.css @@ -1,10 +1,13 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; -/* Reusable composition primitives own flow and sizing only. */ +/* Composition primitives use intrinsic sizing so their content chooses reflow points. */ @layer ly.primitives { .ly-page { - min-block-size: 100svh; + min-block-size: 100vh; + min-block-size: 100dvh; + padding-block-start: var(--ly-safe-area-block-start); + padding-block-end: var(--ly-safe-area-block-end); } .ly-header, @@ -21,9 +24,9 @@ } .ly-header--sticky { - position: sticky; + position: var(--ly-sticky-position); inset-block-start: 0; - z-index: var(--ly-z-header); + z-index: var(--ly-z-header, 20); } .ly-section { @@ -63,6 +66,7 @@ .ly-cover { display: flex; flex-direction: column; + min-block-size: 100vh; min-block-size: var(--ly-cover-min); padding-block: var(--ly-cover-padding, var(--ly-space-5)); } @@ -92,6 +96,7 @@ .ly-sidebar > :where(.ly-sidebar__side, [data-ly-sidebar="side"]) { flex-basis: var(--ly-sidebar-size); flex-grow: 1; + min-inline-size: min(100%, var(--ly-sidebar-size)); } .ly-sidebar > :where(.ly-sidebar__content, [data-ly-sidebar="content"]) { @@ -102,55 +107,44 @@ .ly-grid { display: grid; - grid-template-columns: repeat(var(--ly-grid-columns), minmax(0, 1fr)); - gap: var(--ly-grid-gap); - } - - .ly-grid--auto { grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-grid-min)), 1fr)); + gap: var(--ly-grid-gap); } - .ly-grid > *, - .ly-split > *, - .ly-panes > *, - .ly-media > * { - min-inline-size: 0; + .ly-grid--fixed { + grid-template-columns: repeat(var(--ly-grid-columns), minmax(0, 1fr)); } .ly-split { display: grid; - grid-template-columns: minmax(0, 1fr); + grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-split-min)), 1fr)); gap: var(--ly-gap); align-items: var(--ly-split-align, center); } .ly-panes { display: grid; - grid-template-columns: minmax(0, 1fr); + grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-pane-min)), 1fr)); gap: var(--ly-gap); } .ly-media { display: grid; - grid-template-areas: - "media" - "content" - "actions"; - grid-template-columns: minmax(0, 1fr); + grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-media-min)), 1fr)); gap: var(--ly-gap); align-items: var(--ly-media-align, start); } - .ly-media > :where(.ly-media__asset, [data-ly-media="asset"]) { - grid-area: media; - } - - .ly-media > :where(.ly-media__content, [data-ly-media="content"]) { - grid-area: content; + .ly-media > :where(.ly-media__actions, [data-ly-media="actions"]) { + min-inline-size: min(100%, var(--ly-media-size)); } - .ly-media > :where(.ly-media__actions, [data-ly-media="actions"]) { - grid-area: actions; + .ly-grid > *, + .ly-split > *, + .ly-panes > *, + .ly-media > * { + min-inline-size: 0; + min-block-size: 0; } .ly-reel { @@ -159,7 +153,6 @@ grid-auto-columns: minmax(min(100%, var(--ly-reel-item-min)), var(--ly-reel-item-max)); gap: var(--ly-grid-gap); overflow-x: auto; - overflow-inline: auto; overscroll-behavior-inline: contain; scroll-snap-type: inline proximity; } @@ -183,37 +176,7 @@ .ly-scroll { min-block-size: 0; max-block-size: var(--ly-scroll-max); - overflow: auto; - overscroll-behavior: contain; - } - - /* Unsupported container-query browsers retain this safe DOM-order stack. */ -} - -@layer ly.primitives { - @container (min-width: 48rem) { - .ly-split { - grid-template-columns: minmax(0, var(--ly-split-primary, 1fr)) minmax(0, var(--ly-split-secondary, 1fr)); - } - - .ly-panes--2 { - grid-template-columns: minmax(0, 1fr) minmax(min(100%, var(--ly-pane-size)), 0.7fr); - } - - .ly-media { - grid-template-areas: - "media content" - "media actions"; - grid-template-columns: minmax(min(100%, var(--ly-media-size)), auto) minmax(0, 1fr); - } - } - - @container (min-width: 64rem) { - .ly-panes--3 { - grid-template-columns: - minmax(min(100%, var(--ly-pane-rail, 14rem)), 0.35fr) - minmax(0, 1fr) - minmax(min(100%, var(--ly-pane-rail, 14rem)), 0.35fr); - } + overflow-y: auto; + overscroll-behavior-block: contain; } } diff --git a/dist/recipes.css b/dist/recipes.css index 08eef6c..a504943 100644 --- a/dist/recipes.css +++ b/dist/recipes.css @@ -1,35 +1,41 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; /* - Built-in recipes follow semantic mobile DOM order. Wider arrangements use - named areas so visual placement never changes keyboard or reading order. + Recipes preserve the narrow-screen DOM order. Automatic topology queries + consume inherited profile tokens and can be disabled per recipe. */ @layer ly.recipes { - :where(.ly-app-shell, [data-ly-recipe="app-shell"]), - :where(.ly-dashboard, [data-ly-recipe="dashboard"]), - :where(.ly-docs, [data-ly-recipe="docs"]), - :where(.ly-list-detail, [data-ly-recipe="list-detail"]), - :where(.ly-split-hero, [data-ly-recipe="split-hero"]), - :where(.ly-gallery, [data-ly-recipe="gallery"]), - :where(.ly-card-grid, [data-ly-recipe="card-grid"]) { - container-name: ly-recipe; + :where( + [data-ly-recipe="app-shell"], + [data-ly-recipe="dashboard"], + [data-ly-recipe="docs"], + [data-ly-recipe="list-detail"], + [data-ly-recipe="split-hero"], + [data-ly-recipe="gallery"], + [data-ly-recipe="card-grid"] + ) { + container-name: ly-scope; container-type: inline-size; min-inline-size: 0; + min-block-size: 0; } - :where(.ly-app-shell, [data-ly-recipe="app-shell"]), - :where(.ly-dashboard, [data-ly-recipe="dashboard"]), - :where(.ly-docs, [data-ly-recipe="docs"]), - :where(.ly-list-detail, [data-ly-recipe="list-detail"]), - :where(.ly-split-hero, [data-ly-recipe="split-hero"]) { + :where( + [data-ly-recipe="app-shell"], + [data-ly-recipe="dashboard"], + [data-ly-recipe="docs"], + [data-ly-recipe="list-detail"], + [data-ly-recipe="split-hero"] + ) { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--ly-gap); } - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - min-block-size: 100svh; + [data-ly-recipe="app-shell"] { + min-block-size: 100vh; + min-block-size: var(--ly-shell-min); grid-template-areas: "header" "sidebar" @@ -39,7 +45,8 @@ grid-template-rows: auto auto minmax(0, 1fr) auto auto; } - :where(.ly-dashboard, [data-ly-recipe="dashboard"]) { + [data-ly-recipe="dashboard"], + [data-ly-recipe="docs"] { grid-template-areas: "header" "nav" @@ -48,23 +55,14 @@ "footer"; } - :where(.ly-docs, [data-ly-recipe="docs"]) { - grid-template-areas: - "header" - "nav" - "main" - "aside" - "footer"; - } - - :where(.ly-list-detail, [data-ly-recipe="list-detail"]) { + [data-ly-recipe="list-detail"] { grid-template-areas: "primary" "secondary" "actions"; } - :where(.ly-split-hero, [data-ly-recipe="split-hero"]) { + [data-ly-recipe="split-hero"] { grid-template-areas: "content" "media" @@ -72,207 +70,119 @@ align-items: var(--ly-split-hero-align, center); } - :where(.ly-gallery, [data-ly-recipe="gallery"]), - :where(.ly-card-grid, [data-ly-recipe="card-grid"]) { + [data-ly-recipe="gallery"], + [data-ly-recipe="card-grid"] { display: grid; gap: var(--ly-grid-gap); } - :where(.ly-gallery, [data-ly-recipe="gallery"]) { + [data-ly-recipe="gallery"] { grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-gallery-min)), 1fr)); } - :where(.ly-card-grid, [data-ly-recipe="card-grid"]) { + [data-ly-recipe="card-grid"] { grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-card-grid-min)), 1fr)); } - :where(.ly-gallery, [data-ly-recipe="gallery"]) > *, - :where(.ly-card-grid, [data-ly-recipe="card-grid"]) > * { + :where( + [data-ly-recipe="app-shell"], + [data-ly-recipe="dashboard"], + [data-ly-recipe="docs"], + [data-ly-recipe="list-detail"], + [data-ly-recipe="split-hero"], + [data-ly-recipe="gallery"], + [data-ly-recipe="card-grid"] + ) > * { min-inline-size: 0; + min-block-size: 0; } - :where(.ly-area--header, [data-ly-area="header"]) { + [data-ly-area="header"] { grid-area: header; - min-inline-size: 0; } - :where(.ly-area--nav, [data-ly-area="nav"]) { + [data-ly-area="nav"] { grid-area: nav; - min-inline-size: 0; } - :where(.ly-area--main, [data-ly-area="main"]) { + [data-ly-area="sidebar"] { + grid-area: sidebar; + } + + [data-ly-area="main"] { grid-area: main; - min-inline-size: 0; } - :where(.ly-area--aside, [data-ly-area="aside"]) { + [data-ly-area="aside"] { grid-area: aside; - min-inline-size: 0; } - :where(.ly-area--footer, [data-ly-area="footer"]) { + [data-ly-area="footer"] { grid-area: footer; - min-inline-size: 0; } - :where(.ly-area--content, [data-ly-area="content"]) { + [data-ly-area="content"] { grid-area: content; - min-inline-size: 0; } - :where(.ly-area--media, [data-ly-area="media"]) { + [data-ly-area="media"] { grid-area: media; - min-inline-size: 0; } - :where(.ly-area--actions, [data-ly-area="actions"]) { + [data-ly-area="actions"] { grid-area: actions; - min-inline-size: 0; } - :where(.ly-area--primary, [data-ly-area="primary"]) { + [data-ly-area="primary"] { grid-area: primary; - min-inline-size: 0; } - :where(.ly-area--secondary, [data-ly-area="secondary"]) { + [data-ly-area="secondary"] { grid-area: secondary; - min-inline-size: 0; } - .ly-app-header { - grid-area: header; - min-inline-size: 0; - } - - .ly-app-sidebar { - grid-area: sidebar; - min-inline-size: 0; - } - - .ly-app-main { - grid-area: main; - min-inline-size: 0; - } - - .ly-app-aside { - grid-area: aside; - min-inline-size: 0; - } - - .ly-app-footer { - grid-area: footer; - min-inline-size: 0; - } - - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) - > :where(.ly-area--nav, [data-ly-area="nav"]) { - grid-area: sidebar; - } - - /* - A recipe responds to its nearest ancestor container and then becomes the - containment scope for nested compositions. Standalone roots keep the safe - mobile template when no ancestor container is present. - */ - @container (min-width: 48rem) { - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header" - "sidebar main" - "aside main" - "footer footer"; - grid-template-columns: minmax(min(100%, var(--ly-recipe-rail)), auto) minmax(0, 1fr); - } - - :where(.ly-dashboard, [data-ly-recipe="dashboard"]) { - grid-template-areas: - "header header" - "nav nav" - "main aside" - "footer footer"; - grid-template-columns: minmax(0, 1fr) minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); - } - - :where(.ly-docs, [data-ly-recipe="docs"]) { - grid-template-areas: - "header header" - "nav main" - "nav aside" - "footer footer"; - grid-template-columns: minmax(min(100%, var(--ly-recipe-rail)), auto) minmax(0, 1fr); - } - - :where(.ly-list-detail, [data-ly-recipe="list-detail"]) { - grid-template-areas: - "primary secondary" - "actions actions"; - grid-template-columns: minmax(min(100%, var(--ly-pane-size)), 0.7fr) minmax(0, 1fr); - } - - :where(.ly-split-hero, [data-ly-recipe="split-hero"]) { - grid-template-areas: - "content media" - "actions media"; - grid-template-columns: minmax(0, var(--ly-split-primary, 1fr)) minmax(0, var(--ly-split-secondary, 1fr)); - } - - :where(.ly-gallery, [data-ly-recipe="gallery"]) { - --ly-gallery-min: 14rem; - } - - :where(.ly-card-grid, [data-ly-recipe="card-grid"]) { - --ly-card-grid-min: 18rem; + @container ly-scope (min-width: 42rem) { + [data-ly-recipe="split-hero"]:not([data-ly-responsive="manual"]) { + grid-template-areas: var(--ly-split-hero-wide-areas); + grid-template-columns: var(--ly-split-hero-wide-columns); } } - @container (min-width: 64rem) { - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header header" - "sidebar main aside" - "sidebar footer footer"; - grid-template-columns: - minmax(min(100%, var(--ly-recipe-rail)), auto) - minmax(0, 1fr) - minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); - } - - :where(.ly-dashboard, [data-ly-recipe="dashboard"]) { - grid-template-areas: - "nav header header" - "nav main aside" - "nav footer footer"; - grid-template-columns: - minmax(min(100%, var(--ly-recipe-rail)), auto) - minmax(0, 1fr) - minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); + @container ly-scope (min-width: 44rem) { + [data-ly-recipe="list-detail"]:not([data-ly-responsive="manual"]) { + grid-template-areas: var(--ly-list-detail-wide-areas); + grid-template-columns: var(--ly-list-detail-wide-columns); } + } - :where(.ly-docs, [data-ly-recipe="docs"]) { - grid-template-areas: - "nav header" - "nav main" - "nav aside" - "nav footer"; - grid-template-columns: minmax(min(100%, var(--ly-recipe-rail)), auto) minmax(0, 1fr); + @container ly-scope (min-width: 48rem) { + [data-ly-recipe="docs"]:not([data-ly-responsive="manual"]) { + grid-template-areas: var(--ly-docs-wide-areas); + grid-template-columns: var(--ly-docs-wide-columns); } + } - :where(.ly-list-detail, [data-ly-recipe="list-detail"]) { - grid-template-columns: minmax(min(100%, var(--ly-pane-size)), 0.45fr) minmax(0, 1fr); + @container ly-scope (min-width: 52rem) { + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]) { + grid-template-areas: var(--ly-app-shell-medium-areas); + grid-template-columns: var(--ly-app-shell-medium-columns); } - :where(.ly-split-hero, [data-ly-recipe="split-hero"]) { - grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); + [data-ly-recipe="dashboard"]:not([data-ly-responsive="manual"]) { + grid-template-areas: var(--ly-dashboard-medium-areas); + grid-template-columns: var(--ly-dashboard-medium-columns); } + } - :where(.ly-gallery, [data-ly-recipe="gallery"]) { - --ly-gallery-min: 16rem; + @container ly-scope (min-width: 72rem) { + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]) { + grid-template-areas: var(--ly-app-shell-wide-areas); + grid-template-columns: var(--ly-app-shell-wide-columns); } - :where(.ly-card-grid, [data-ly-recipe="card-grid"]) { - --ly-card-grid-min: 20rem; + [data-ly-recipe="dashboard"]:not([data-ly-responsive="manual"]) { + grid-template-areas: var(--ly-dashboard-wide-areas); + grid-template-columns: var(--ly-dashboard-wide-columns); } } } diff --git a/dist/utilities.css b/dist/utilities.css index 0497d4e..06a99e4 100644 --- a/dist/utilities.css +++ b/dist/utilities.css @@ -1,72 +1,37 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; + +/* Optional structural utilities expose direct token overrides without breakpoint tiers. */ @layer ly.utilities { .ly-cols-1 { --ly-grid-columns: 1; } .ly-cols-2 { --ly-grid-columns: 2; } .ly-cols-3 { --ly-grid-columns: 3; } .ly-cols-4 { --ly-grid-columns: 4; } - .ly-cols-5 { --ly-grid-columns: 5; } .ly-cols-6 { --ly-grid-columns: 6; } - .ly-cols-7 { --ly-grid-columns: 7; } - .ly-cols-8 { --ly-grid-columns: 8; } - .ly-cols-9 { --ly-grid-columns: 9; } - .ly-cols-10 { --ly-grid-columns: 10; } - .ly-cols-11 { --ly-grid-columns: 11; } .ly-cols-12 { --ly-grid-columns: 12; } - .ly-cols-16 { --ly-grid-columns: 16; } .ly-span-1 { grid-column: span 1; } .ly-span-2 { grid-column: span 2; } .ly-span-3 { grid-column: span 3; } .ly-span-4 { grid-column: span 4; } - .ly-span-5 { grid-column: span 5; } - .ly-span-6 { grid-column: span 6; } - .ly-span-7 { grid-column: span 7; } - .ly-span-8 { grid-column: span 8; } - .ly-span-9 { grid-column: span 9; } - .ly-span-10 { grid-column: span 10; } - .ly-span-11 { grid-column: span 11; } - .ly-span-12 { grid-column: span 12; } - .ly-span-13 { grid-column: span 13; } - .ly-span-14 { grid-column: span 14; } - .ly-span-15 { grid-column: span 15; } - .ly-span-16 { grid-column: span 16; } .ly-span-full { grid-column: 1 / -1; } - .ly-gap-0 { --ly-gap: var(--ly-space-0); --ly-grid-gap: var(--ly-space-0); --ly-stack-gap: var(--ly-space-0); --ly-cluster-gap: var(--ly-space-0); } - .ly-gap-1 { --ly-gap: var(--ly-space-1); --ly-grid-gap: var(--ly-space-1); --ly-stack-gap: var(--ly-space-1); --ly-cluster-gap: var(--ly-space-1); } - .ly-gap-2 { --ly-gap: var(--ly-space-2); --ly-grid-gap: var(--ly-space-2); --ly-stack-gap: var(--ly-space-2); --ly-cluster-gap: var(--ly-space-2); } - .ly-gap-3 { --ly-gap: var(--ly-space-3); --ly-grid-gap: var(--ly-space-3); --ly-stack-gap: var(--ly-space-3); --ly-cluster-gap: var(--ly-space-3); } - .ly-gap-4 { --ly-gap: var(--ly-space-4); --ly-grid-gap: var(--ly-space-4); --ly-stack-gap: var(--ly-space-4); --ly-cluster-gap: var(--ly-space-4); } - .ly-gap-5 { --ly-gap: var(--ly-space-5); --ly-grid-gap: var(--ly-space-5); --ly-stack-gap: var(--ly-space-5); --ly-cluster-gap: var(--ly-space-5); } - .ly-gap-6 { --ly-gap: var(--ly-space-6); --ly-grid-gap: var(--ly-space-6); --ly-stack-gap: var(--ly-space-6); --ly-cluster-gap: var(--ly-space-6); } - .ly-gap-7 { --ly-gap: var(--ly-space-7); --ly-grid-gap: var(--ly-space-7); --ly-stack-gap: var(--ly-space-7); --ly-cluster-gap: var(--ly-space-7); } - .ly-gap-8 { --ly-gap: var(--ly-space-8); --ly-grid-gap: var(--ly-space-8); --ly-stack-gap: var(--ly-space-8); --ly-cluster-gap: var(--ly-space-8); } - .ly-gap-9 { --ly-gap: var(--ly-space-9); --ly-grid-gap: var(--ly-space-9); --ly-stack-gap: var(--ly-space-9); --ly-cluster-gap: var(--ly-space-9); } + .ly-gap-0 { --ly-gap: var(--ly-space-0); --ly-grid-gap: var(--ly-space-0); } + .ly-gap-2 { --ly-gap: var(--ly-space-2); --ly-grid-gap: var(--ly-space-2); } + .ly-gap-4 { --ly-gap: var(--ly-space-4); --ly-grid-gap: var(--ly-space-4); } + .ly-gap-6 { --ly-gap: var(--ly-space-6); --ly-grid-gap: var(--ly-space-6); } + .ly-gap-8 { --ly-gap: var(--ly-space-8); --ly-grid-gap: var(--ly-space-8); } .ly-pad-0 { padding: var(--ly-space-0); } - .ly-pad-1 { padding: var(--ly-space-1); } .ly-pad-2 { padding: var(--ly-space-2); } - .ly-pad-3 { padding: var(--ly-space-3); } .ly-pad-4 { padding: var(--ly-space-4); } - .ly-pad-5 { padding: var(--ly-space-5); } .ly-pad-6 { padding: var(--ly-space-6); } - .ly-pad-7 { padding: var(--ly-space-7); } .ly-pad-8 { padding: var(--ly-space-8); } - .ly-pad-9 { padding: var(--ly-space-9); } - - .ly-px-4 { padding-inline: var(--ly-space-4); } - .ly-px-6 { padding-inline: var(--ly-space-6); } - .ly-px-8 { padding-inline: var(--ly-space-8); } - .ly-py-4 { padding-block: var(--ly-space-4); } - .ly-py-6 { padding-block: var(--ly-space-6); } - .ly-py-8 { padding-block: var(--ly-space-8); } .ly-mx-auto { margin-inline: auto; } .ly-w-full { inline-size: 100%; } .ly-h-full { block-size: 100%; } - .ly-min-h-screen { min-block-size: 100svh; } - .ly-bleed { inline-size: 100vw; margin-inline: calc(50% - 50vw); } + .ly-min-h-screen { min-block-size: 100vh; min-block-size: 100dvh; } .ly-overflow-auto { overflow: auto; } .ly-overflow-hidden { overflow: hidden; } @@ -80,16 +45,12 @@ .ly-justify-between { justify-content: space-between; } .ly-frame-1x1 { --ly-frame-ratio: 1 / 1; } - .ly-frame-2x1 { --ly-frame-ratio: 2 / 1; } .ly-frame-3x2 { --ly-frame-ratio: 3 / 2; } .ly-frame-4x3 { --ly-frame-ratio: 4 / 3; } .ly-frame-16x9 { --ly-frame-ratio: 16 / 9; } .ly-frame-21x9 { --ly-frame-ratio: 21 / 9; } - .ly-hidden { display: none !important; } - - .ly-show-md-up, - .ly-show-lg-up { + .ly-hidden { display: none !important; } @@ -104,59 +65,4 @@ clip-path: inset(50%) !important; white-space: nowrap !important; } - - /* Explicit escape hatches require consumers to verify focus and reading order. */ - .ly-order-first { order: -1; } - .ly-order-normal { order: 0; } - .ly-order-last { order: 999; } - .ly-order-1 { order: 1; } - .ly-order-2 { order: 2; } - .ly-order-3 { order: 3; } - .ly-order-4 { order: 4; } - .ly-order-5 { order: 5; } - .ly-order-6 { order: 6; } - - @container (min-width: 48rem) { - .ly-md-cols-1 { --ly-grid-columns: 1; } - .ly-md-cols-2 { --ly-grid-columns: 2; } - .ly-md-cols-3 { --ly-grid-columns: 3; } - .ly-md-cols-4 { --ly-grid-columns: 4; } - .ly-md-cols-6 { --ly-grid-columns: 6; } - .ly-md-cols-8 { --ly-grid-columns: 8; } - .ly-md-cols-12 { --ly-grid-columns: 12; } - .ly-md-cols-16 { --ly-grid-columns: 16; } - .ly-show-md-up { display: revert !important; } - - .ly-md-order-first { order: -1; } - .ly-md-order-normal { order: 0; } - .ly-md-order-last { order: 999; } - .ly-md-order-1 { order: 1; } - .ly-md-order-2 { order: 2; } - .ly-md-order-3 { order: 3; } - .ly-md-order-4 { order: 4; } - .ly-md-order-5 { order: 5; } - .ly-md-order-6 { order: 6; } - } - - @container (min-width: 64rem) { - .ly-lg-cols-1 { --ly-grid-columns: 1; } - .ly-lg-cols-2 { --ly-grid-columns: 2; } - .ly-lg-cols-3 { --ly-grid-columns: 3; } - .ly-lg-cols-4 { --ly-grid-columns: 4; } - .ly-lg-cols-6 { --ly-grid-columns: 6; } - .ly-lg-cols-8 { --ly-grid-columns: 8; } - .ly-lg-cols-12 { --ly-grid-columns: 12; } - .ly-lg-cols-16 { --ly-grid-columns: 16; } - .ly-show-lg-up { display: revert !important; } - - .ly-lg-order-first { order: -1; } - .ly-lg-order-normal { order: 0; } - .ly-lg-order-last { order: 999; } - .ly-lg-order-1 { order: 1; } - .ly-lg-order-2 { order: 2; } - .ly-lg-order-3 { order: 3; } - .ly-lg-order-4 { order: 4; } - .ly-lg-order-5 { order: 5; } - .ly-lg-order-6 { order: 6; } - } } diff --git a/dist/wrappers.css b/dist/wrappers.css index 3a4947f..a554e09 100644 --- a/dist/wrappers.css +++ b/dist/wrappers.css @@ -1,127 +1,39 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; -/* - Shared structural tokens and wrapper geometry. Theme, type, borders, shadows, - and interactive states remain outside Layout Style's ownership boundary. -*/ - -@layer ly.tokens { - :where(.ly-root) { - --ly-space-0: 0; - --ly-space-1: 0.25rem; - --ly-space-2: 0.5rem; - --ly-space-3: 0.75rem; - --ly-space-4: 1rem; - --ly-space-5: 1.5rem; - --ly-space-6: 2rem; - --ly-space-7: 3rem; - --ly-space-8: 4rem; - --ly-space-9: 6rem; - - --ly-wrapper-compact: 40rem; - --ly-wrapper-prose: 68ch; - --ly-wrapper-content: 72rem; - --ly-wrapper-wide: 112rem; - --ly-wrapper-max: var(--ly-wrapper-content); - --ly-page-padding-inline: clamp(1rem, 4vw, 3rem); - --ly-safe-area-inline: max( - env(safe-area-inset-left, 0px), - env(safe-area-inset-right, 0px) - ); - --ly-wrapper-gutter: max(var(--ly-page-padding-inline), var(--ly-safe-area-inline)); - - --ly-section-padding-block: clamp(3rem, 7vw, 6rem); - --ly-gap: var(--ly-space-5); - --ly-grid-gap: var(--ly-gap); - --ly-stack-gap: var(--ly-space-4); - --ly-cluster-gap: var(--ly-space-3); - --ly-cover-min: 100svh; - --ly-switcher-threshold: 42rem; - --ly-sidebar-size: 18rem; - --ly-sidebar-content-min: 50%; - --ly-grid-columns: 12; - --ly-grid-min: 16rem; - --ly-pane-size: 22rem; - --ly-media-size: 14rem; - --ly-reel-item-min: 16rem; - --ly-reel-item-max: 28rem; - --ly-scroll-max: 70svh; - --ly-frame-ratio: 16 / 9; - - --ly-recipe-rail: 18rem; - --ly-recipe-aside: 22rem; - --ly-card-grid-min: 16rem; - --ly-gallery-min: 12rem; - --ly-card-size-sm: 10rem; - --ly-card-size-md: 14rem; - --ly-card-size-lg: 18rem; - --ly-header-height: 4.5rem; - --ly-z-header: 20; - - /* V1 token aliases remain available so legacy selectors can preserve sizing. */ - --ly-container-sm: var(--ly-wrapper-compact); - --ly-container-md: 56rem; - --ly-container-lg: var(--ly-wrapper-content); - --ly-container-xl: 88rem; - --ly-container-wide: var(--ly-wrapper-wide); - --ly-container-max: var(--ly-container-lg); - --ly-content-readable: var(--ly-wrapper-prose); - --ly-carousel-item-min: var(--ly-reel-item-min); - --ly-carousel-item-max: var(--ly-reel-item-max); - --ly-sidebar-min: 14rem; - --ly-sidebar-width: var(--ly-recipe-rail); - --ly-sidebar-max: var(--ly-recipe-aside); - --ly-pane-fixed: var(--ly-pane-size); - --ly-z-sidebar: 10; - } -} - -@layer ly.reset { - :where(.ly-root), - :where(.ly-root *) { - box-sizing: border-box; - } - - :where(.ly-root) { - min-inline-size: 0; - margin: 0; - } - - :where(.ly-root img), - :where(.ly-root svg), - :where(.ly-root video), - :where(.ly-root canvas) { - max-inline-size: 100%; - } -} +/* Wrappers provide fluid measures and become the nearest responsive scope. */ @layer ly.wrappers { .ly-wrapper { - /* Personalities provide only the plain-wrapper default; explicit variants stay authoritative. */ --ly-wrapper-max: var(--ly-personality-wrapper-max, var(--ly-wrapper-content)); + --ly-wrapper-fluid-gutter: clamp(1rem, 3vw, 3rem); + --ly-wrapper-fluid-gutter: clamp(1rem, 3cqi, 3rem); + --ly-wrapper-local-gutter: max( + var(--ly-wrapper-fluid-gutter), + var(--ly-safe-area-inline) + ); - /* Symmetric safe-area compensation keeps logical gutters stable in either direction. */ - container-name: ly-wrapper; + container-name: ly-scope; container-type: inline-size; - inline-size: min(100%, calc(var(--ly-wrapper-max) + (var(--ly-wrapper-gutter) * 2))); + inline-size: min(100%, calc(var(--ly-wrapper-max) + (var(--ly-wrapper-local-gutter) * 2))); + max-inline-size: 100%; margin-inline: auto; - padding-inline: var(--ly-wrapper-gutter); + padding-inline: var(--ly-wrapper-local-gutter); } .ly-wrapper--compact { - --ly-wrapper-max: 40rem; + --ly-wrapper-max: var(--ly-wrapper-compact); } .ly-wrapper--prose { - --ly-wrapper-max: 68ch; + --ly-wrapper-max: var(--ly-wrapper-prose); } .ly-wrapper--content { - --ly-wrapper-max: 72rem; + --ly-wrapper-max: var(--ly-wrapper-content); } .ly-wrapper--wide { - --ly-wrapper-max: 112rem; + --ly-wrapper-max: var(--ly-wrapper-wide); } .ly-wrapper--full { @@ -129,18 +41,19 @@ } .ly-wrapper--breakout { + --ly-wrapper-max: 100%; --ly-breakout-content-size: min( var(--ly-wrapper-content), - calc(100% - (var(--ly-wrapper-gutter) * 2)) + calc(100% - (var(--ly-wrapper-local-gutter) * 2)) ); --ly-breakout-feature-size: min( var(--ly-wrapper-wide), - calc(100% - (var(--ly-wrapper-gutter) * 2)) + calc(100% - (var(--ly-wrapper-local-gutter) * 2)) ); display: grid; grid-template-columns: - [full-start] minmax(min(100%, var(--ly-wrapper-gutter)), 1fr) + [full-start] minmax(min(100%, var(--ly-wrapper-local-gutter)), 1fr) [feature-start] minmax( 0, calc((var(--ly-breakout-feature-size) - var(--ly-breakout-content-size)) / 2) @@ -150,7 +63,7 @@ 0, calc((var(--ly-breakout-feature-size) - var(--ly-breakout-content-size)) / 2) ) - [feature-end] minmax(min(100%, var(--ly-wrapper-gutter)), 1fr) [full-end]; + [feature-end] minmax(min(100%, var(--ly-wrapper-local-gutter)), 1fr) [full-end]; inline-size: 100%; padding-inline: 0; } @@ -158,6 +71,7 @@ .ly-wrapper--breakout > * { grid-column: content; min-inline-size: 0; + max-inline-size: 100%; } .ly-wrapper--breakout > :where(.ly-lane--content, [data-ly-lane="content"]) { diff --git a/package-lock.json b/package-lock.json index aec3fb9..fe1cf7e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "layout-style-css", - "version": "2.1.1", + "version": "3.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "layout-style-css", - "version": "2.1.1", + "version": "3.0.0", "license": "MIT", "devDependencies": { "@playwright/test": "1.61.1", diff --git a/package.json b/package.json index cdfe2d2..ef69f25 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "layout-style-css", - "version": "2.1.1", + "version": "3.0.0", "description": "Dependency-free structural CSS for responsive wrappers, composition primitives, recipes, utilities, and layout personalities.", "type": "module", "license": "MIT", @@ -60,39 +60,27 @@ }, "exports": { ".": "./dist/layout-style-css.css", - "./css": "./dist/layout-style-css.css", - "./css.css": "./dist/layout-style-css.css", - "./min": "./dist/layout-style-css.min.css", "./min.css": "./dist/layout-style-css.min.css", "./core.css": "./dist/core.css", + "./foundation.css": "./dist/foundation.css", "./wrappers.css": "./dist/wrappers.css", "./primitives.css": "./dist/primitives.css", "./recipes.css": "./dist/recipes.css", "./utilities.css": "./dist/utilities.css", "./personalities.css": "./dist/personalities.css", "./personalities/*.css": "./dist/personalities/*.css", - "./integrations/ui-style-kit.css": "./dist/integrations/ui-style-kit.css", - "./legacy.css": "./dist/legacy.css", "./package.json": "./package.json" }, "files": [ - "dist", - "styles", - "docs/wiki", - "demo/index.html", - "demo/demo.css", - "demo/demo.js", - "demo/assets/apple-touch-icon.svg", - "demo/assets/favicon.svg", - "demo/assets/social-card.png", - "demo/browserconfig.xml", - "demo/robots.txt", - "demo/site.webmanifest", - "demo/sitemap.xml", - "README.md", - "CHANGELOG.md", - "CONTRIBUTING.md", - "SECURITY.md", - "LICENSE" + "dist/layout-style-css.css", + "dist/layout-style-css.min.css", + "dist/core.css", + "dist/foundation.css", + "dist/wrappers.css", + "dist/primitives.css", + "dist/recipes.css", + "dist/utilities.css", + "dist/personalities.css", + "dist/personalities/*.css" ] } diff --git a/scripts/build.mjs b/scripts/build.mjs index 2966862..479cfa6 100644 --- a/scripts/build.mjs +++ b/scripts/build.mjs @@ -6,10 +6,15 @@ const root = fileURLToPath(new URL("..", import.meta.url)); const sourceDir = join(root, "styles"); const distDir = join(root, "dist"); const cascadeLayerPrelude = - "@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy;"; -const legacyAliasMarker = "/* @generated-personality-aliases */"; - -const coreModuleFiles = ["wrappers.css", "primitives.css", "recipes.css", "utilities.css"]; + "@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities;"; + +const coreModuleFiles = [ + "foundation.css", + "wrappers.css", + "primitives.css", + "recipes.css", + "utilities.css" +]; const personalityNames = [ "minimal-saas", "bento", @@ -33,9 +38,7 @@ const authoredEntryFiles = [ "core.css", ...coreModuleFiles, "personalities.css", - ...personalityFiles, - "integrations/ui-style-kit.css", - "legacy.css" + ...personalityFiles ]; const flattenedSourceFiles = [...coreModuleFiles, ...personalityFiles]; @@ -68,60 +71,6 @@ async function readSource(file) { return readFile(join(sourceDir, file), "utf8"); } -function extractPersonalityLayerBody(css, file) { - const layerStart = css.indexOf("@layer ly.personalities."); - - if (layerStart === -1) { - throw new Error(`${file} must define a personality cascade layer.`); - } - - const bodyStart = css.indexOf("{", layerStart); - let depth = 1; - - for (let index = bodyStart + 1; index < css.length; index += 1) { - if (css[index] === "{") { - depth += 1; - } else if (css[index] === "}") { - depth -= 1; - } - - if (depth === 0) { - return css.slice(bodyStart + 1, index).trim(); - } - } - - throw new Error(`${file} has an incomplete personality cascade layer.`); -} - -async function generateLegacyCss() { - const source = await readSource("legacy.css"); - - if (!source.includes(legacyAliasMarker)) { - throw new Error("styles/legacy.css must contain the personality alias build marker."); - } - - const aliases = []; - - for (const name of personalityNames) { - const file = `personalities/${name}.css`; - const css = await readSource(file); - const canonicalRoot = `:where(.ly-root[data-ly-layout="${name}"])`; - const legacyRoot = `:where(.ly-root[data-layout="${name}"], .ly-root[layout-style="${name}"], .ly-root.ly-layout-${name}, .ly-root.ly-style-${name})`; - const body = extractPersonalityLayerBody(css, file); - - if (!body.includes(canonicalRoot)) { - throw new Error(`${file} must use the canonical ${canonicalRoot} selector.`); - } - - aliases.push( - `/* V1 personality aliases for ${name}; generated from the canonical v2 source. */\n${body.replaceAll(canonicalRoot, legacyRoot)}` - ); - } - - /* Generated aliases prevent the compatibility bundle from drifting from v2 geometry. */ - return source.replace(legacyAliasMarker, aliases.join("\n\n")); -} - async function writeDist(file, css) { const destination = join(distDir, file); assertInsideRoot(destination); @@ -136,12 +85,12 @@ await rm(distDir, { recursive: true, force: true }); await mkdir(distDir, { recursive: true }); for (const file of authoredEntryFiles) { - await writeDist(file, file === "legacy.css" ? await generateLegacyCss() : await readSource(file)); + await writeDist(file, await readSource(file)); } const flattenedParts = [ cascadeLayerPrelude, - "/* layout-style-css bundle. Generated from focused styles/ modules by scripts/build.mjs. */" + "/* layout-style-css v3 bundle. Generated from focused styles/ modules. */" ]; for (const file of flattenedSourceFiles) { diff --git a/stylelint.config.mjs b/stylelint.config.mjs index b25ec6b..c666c8b 100644 --- a/stylelint.config.mjs +++ b/stylelint.config.mjs @@ -3,7 +3,12 @@ export default { "block-no-empty": true, "color-no-invalid-hex": true, "comment-no-empty": true, - "declaration-block-no-duplicate-properties": true, + "declaration-block-no-duplicate-properties": [ + true, + { + ignore: ["consecutive-duplicates-with-different-values"] + } + ], "declaration-block-no-shorthand-property-overrides": true, "font-family-no-duplicate-names": true, "function-calc-no-unspaced-operator": true, diff --git a/styles/core.css b/styles/core.css index e24ab50..b215325 100644 --- a/styles/core.css +++ b/styles/core.css @@ -1,5 +1,6 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; +@import url("./foundation.css"); @import url("./wrappers.css"); @import url("./primitives.css"); @import url("./recipes.css"); diff --git a/styles/foundation.css b/styles/foundation.css new file mode 100644 index 0000000..d06c066 --- /dev/null +++ b/styles/foundation.css @@ -0,0 +1,168 @@ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; + +/* + Foundation owns only shared spatial tokens, containment, and defensive + sizing. Theme and interaction libraries remain responsible for paint. +*/ + +@layer ly.tokens { + :where(.ly-root) { + --ly-space-0: 0; + --ly-space-1: 0.25rem; + --ly-space-2: 0.5rem; + --ly-space-3: 0.75rem; + --ly-space-4: 1rem; + --ly-space-5: 1.5rem; + --ly-space-6: 2rem; + --ly-space-7: 3rem; + --ly-space-8: 4rem; + --ly-space-9: 6rem; + + --ly-wrapper-compact: 40rem; + --ly-wrapper-prose: 68ch; + --ly-wrapper-content: 72rem; + --ly-wrapper-wide: 112rem; + --ly-page-padding-inline: clamp(1rem, 4vw, 3rem); + --ly-safe-area-inline: max( + env(safe-area-inset-left, 0px), + env(safe-area-inset-right, 0px) + ); + --ly-safe-area-block-start: env(safe-area-inset-top, 0px); + --ly-safe-area-block-end: env(safe-area-inset-bottom, 0px); + --ly-wrapper-gutter: max(var(--ly-page-padding-inline), var(--ly-safe-area-inline)); + + --ly-profile-gap: var(--ly-space-5); + --ly-gap: var(--ly-profile-gap); + --ly-grid-gap: var(--ly-gap); + --ly-stack-gap: var(--ly-space-4); + --ly-cluster-gap: var(--ly-space-3); + --ly-section-padding-block: clamp(3rem, 7vh, 6rem); + --ly-header-height: 4.5rem; + --ly-sticky-position: sticky; + --ly-cover-min: 100dvh; + --ly-shell-min: 100dvh; + --ly-scroll-max: min(70dvh, 50rem); + + --ly-switcher-threshold: 42rem; + --ly-sidebar-size: 18rem; + --ly-sidebar-content-min: 50%; + --ly-grid-columns: 12; + --ly-grid-min: 16rem; + --ly-split-min: 20rem; + --ly-pane-min: 18rem; + --ly-pane-size: 22rem; + --ly-media-min: 18rem; + --ly-media-size: 14rem; + --ly-reel-item-min: 16rem; + --ly-reel-item-max: 28rem; + --ly-frame-ratio: 16 / 9; + + --ly-recipe-rail: 18rem; + --ly-recipe-aside: 22rem; + --ly-gallery-min: 12rem; + --ly-card-grid-min: 16rem; + + --ly-app-shell-medium-areas: + "header header" + "sidebar main" + "aside main" + "footer footer"; + --ly-app-shell-medium-columns: + minmax(min(100%, var(--ly-recipe-rail)), auto) + minmax(0, 1fr); + --ly-app-shell-wide-areas: + "sidebar header header" + "sidebar main aside" + "sidebar footer footer"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), auto) + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); + + --ly-dashboard-medium-areas: + "header header" + "nav nav" + "main aside" + "footer footer"; + --ly-dashboard-medium-columns: + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); + --ly-dashboard-wide-areas: + "nav header header" + "nav main aside" + "nav footer footer"; + --ly-dashboard-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), auto) + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); + + --ly-docs-wide-areas: + "header header" + "nav main" + "nav aside" + "footer footer"; + --ly-docs-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), auto) + minmax(0, 1fr); + --ly-list-detail-wide-areas: + "primary secondary" + "actions actions"; + --ly-list-detail-wide-columns: + minmax(min(100%, var(--ly-pane-size)), 0.7fr) + minmax(0, 1fr); + --ly-split-hero-wide-areas: + "content media" + "actions media"; + --ly-split-hero-wide-columns: + minmax(0, var(--ly-split-primary, 1fr)) + minmax(0, var(--ly-split-secondary, 1fr)); + + container-name: ly-scope; + container-type: inline-size; + min-inline-size: 0; + min-block-size: 0; + } +} + +@layer ly.reset { + :where(.ly-root), + :where(.ly-root *) { + box-sizing: border-box; + } + + :where(.ly-root) { + margin: 0; + } + + :where(.ly-root img), + :where(.ly-root svg), + :where(.ly-root video), + :where(.ly-root canvas), + :where(.ly-root iframe) { + max-inline-size: 100%; + } +} + +@layer ly.tokens { + @media (max-height: 44rem) { + :where(.ly-root) { + --ly-gap: min(var(--ly-profile-gap), var(--ly-space-4)); + --ly-grid-gap: var(--ly-gap); + --ly-stack-gap: min(var(--ly-space-4), 3dvh); + --ly-cluster-gap: min(var(--ly-space-3), 2dvh); + --ly-section-padding-block: clamp(1.5rem, 6dvh, 3rem); + --ly-header-height: 3.5rem; + --ly-scroll-max: min(62dvh, 34rem); + } + } + + @media (max-height: 30rem) { + :where(.ly-root) { + --ly-cover-min: auto; + --ly-shell-min: auto; + --ly-sticky-position: static; + --ly-section-padding-block: var(--ly-space-5); + --ly-scroll-max: max(12rem, calc(100dvh - 8rem)); + } + } +} diff --git a/styles/integrations/ui-style-kit.css b/styles/integrations/ui-style-kit.css deleted file mode 100644 index a2d4f2d..0000000 --- a/styles/integrations/ui-style-kit.css +++ /dev/null @@ -1,175 +0,0 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* - Compatibility bridge for ui-style-kit-css. - This bridge intentionally does not map color, type, border, or shadow tokens. - ui-style-kit-css owns those visuals; layout-style-css owns structure. -*/ - -@layer ly.integrations.ui_style_kit { - :where(.ly-root[data-ui][data-theme][data-mode], [data-ui][data-theme][data-mode] .ly-root) { - --ly-ui-style-kit-bridge: 1; - - /* - Normalize UI kit root background geometry without redefining its paint. - Patterned theme layers should fill the viewport once instead of tiling. - */ - min-block-size: 100svh; - background-attachment: fixed; - background-position: center; - background-repeat: no-repeat; - background-size: 100% 100%; - } - - :where(.ly-root[data-ui="minimal-saas"], [data-ui="minimal-saas"] .ly-root) { - --ly-ui-style-kit-bridge-style: minimal-saas; - } - - :where(.ly-root[data-ui="bento"], [data-ui="bento"] .ly-root) { - --ly-ui-style-kit-bridge-style: bento; - } - - :where(.ly-root[data-ui="maximalist"], [data-ui="maximalist"] .ly-root) { - --ly-ui-style-kit-bridge-style: maximalist; - } - - :where(.ly-root[data-ui="bauhaus"], [data-ui="bauhaus"] .ly-root) { - --ly-ui-style-kit-bridge-style: bauhaus; - } - - :where(.ly-root[data-ui="tactile"], [data-ui="tactile"] .ly-root) { - --ly-ui-style-kit-bridge-style: tactile; - } - - :where(.ly-root[data-ui="neumorphism"], [data-ui="neumorphism"] .ly-root) { - --ly-ui-style-kit-bridge-style: neumorphism; - } - - :where(.ly-root[data-ui="retrofuturism"], [data-ui="retrofuturism"] .ly-root) { - --ly-ui-style-kit-bridge-style: retrofuturism; - } - - :where(.ly-root[data-ui="brutalism"], [data-ui="brutalism"] .ly-root) { - --ly-ui-style-kit-bridge-style: brutalism; - } - - :where(.ly-root[data-ui="cyberpunk"], [data-ui="cyberpunk"] .ly-root) { - --ly-ui-style-kit-bridge-style: cyberpunk; - } - - :where(.ly-root[data-ui="y2k"], [data-ui="y2k"] .ly-root) { - --ly-ui-style-kit-bridge-style: y2k; - } - - :where(.ly-root[data-ui="retro-glass"], [data-ui="retro-glass"] .ly-root) { - --ly-ui-style-kit-bridge-style: retro-glass; - } - - :where(.saas-container, .bento-container, .max-container, .bau-container, .tactile-container, .neo-container, .retro-container, .brutal-container, .cyber-container, .y2k-container, .rg-container) { - /* UI Style Kit naming can opt into layout sizing without taking over visual paint. */ - container-name: ly-wrapper; - container-type: inline-size; - inline-size: min(100%, calc(var(--ly-wrapper-max) + (var(--ly-wrapper-gutter) * 2))); - margin-inline: auto; - padding-inline: var(--ly-wrapper-gutter); - } - - :where(.saas-section, .bento-section, .max-section, .bau-section, .tactile-section, .neo-section, .retro-section, .brutal-section, .cyber-section, .y2k-section, .rg-section) { - padding-block: var(--ly-section-padding-block); - } - - :where(.saas-stack, .bento-stack, .max-stack, .bau-stack, .tactile-stack, .neo-stack, .retro-stack, .brutal-stack, .cyber-stack, .y2k-stack, .rg-stack) { - display: flex; - flex-direction: column; - gap: var(--ly-stack-gap); - } - - :where(.saas-cluster, .bento-cluster, .max-cluster, .bau-cluster, .tactile-cluster, .neo-cluster, .retro-cluster, .brutal-cluster, .cyber-cluster, .y2k-cluster, .rg-cluster) { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: var(--ly-cluster-gap); - } - - :where(.saas-grid, .bento-grid, .max-grid, .bau-grid, .tactile-grid, .neo-grid, .retro-grid, .brutal-grid, .cyber-grid, .y2k-grid, .rg-grid) { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-grid-min)), 1fr)); - gap: var(--ly-grid-gap); - } - - :where(.saas-split, .bento-split, .max-split, .bau-split, .tactile-split, .neo-split, .retro-split, .brutal-split, .cyber-split, .y2k-split, .rg-split) { - display: grid; - grid-template-columns: 1fr; - gap: var(--ly-gap); - align-items: var(--ly-split-align, center); - } - - :where(.saas-split, .bento-split, .max-split, .bau-split, .tactile-split, .neo-split, .retro-split, .brutal-split, .cyber-split, .y2k-split, .rg-split) > * { - min-width: 0; - } - - :where(.saas-button-group, .bento-button-group, .max-button-group, .bau-button-group, .tactile-button-group, .neo-button-group, .retro-button-group, .brutal-button-group, .cyber-button-group, .y2k-button-group, .rg-button-group) { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: var(--ly-cluster-gap); - } - - :where(.saas-button-group, .bento-button-group, .max-button-group, .bau-button-group, .tactile-button-group, .neo-button-group, .retro-button-group, .brutal-button-group, .cyber-button-group, .y2k-button-group, .rg-button-group) > * { - flex: 0 1 auto; - min-width: min(100%, var(--ly-button-min, 8rem)); - } - - :where(.saas-card-grid, .bento-card-grid, .max-card-grid, .bau-card-grid, .tactile-card-grid, .neo-card-grid, .retro-card-grid, .brutal-card-grid, .cyber-card-grid, .y2k-card-grid, .rg-card-grid) { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-card-grid-min)), 1fr)); - gap: var(--ly-grid-gap); - } - - :where(.saas-card-grid, .bento-card-grid, .max-card-grid, .bau-card-grid, .tactile-card-grid, .neo-card-grid, .retro-card-grid, .brutal-card-grid, .cyber-card-grid, .y2k-card-grid, .rg-card-grid) > * { - min-width: 0; - } - - :where(.saas-card-sm, .bento-card-sm, .max-card-sm, .bau-card-sm, .tactile-card-sm, .neo-card-sm, .retro-card-sm, .brutal-card-sm, .cyber-card-sm, .y2k-card-sm, .rg-card-sm) { - min-block-size: var(--ly-card-size-sm); - } - - :where(.saas-card-md, .bento-card-md, .max-card-md, .bau-card-md, .tactile-card-md, .neo-card-md, .retro-card-md, .brutal-card-md, .cyber-card-md, .y2k-card-md, .rg-card-md) { - min-block-size: var(--ly-card-size-md); - } - - :where(.saas-card-lg, .bento-card-lg, .max-card-lg, .bau-card-lg, .tactile-card-lg, .neo-card-lg, .retro-card-lg, .brutal-card-lg, .cyber-card-lg, .y2k-card-lg, .rg-card-lg) { - min-block-size: var(--ly-card-size-lg); - } - - :where(.saas-gallery, .bento-gallery, .max-gallery, .bau-gallery, .tactile-gallery, .neo-gallery, .retro-gallery, .brutal-gallery, .cyber-gallery, .y2k-gallery, .rg-gallery) { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-gallery-min)), 1fr)); - gap: var(--ly-grid-gap); - } - - :where(.saas-gallery, .bento-gallery, .max-gallery, .bau-gallery, .tactile-gallery, .neo-gallery, .retro-gallery, .brutal-gallery, .cyber-gallery, .y2k-gallery, .rg-gallery) > * { - min-width: 0; - } - - :where(.saas-carousel, .bento-carousel, .max-carousel, .bau-carousel, .tactile-carousel, .neo-carousel, .retro-carousel, .brutal-carousel, .cyber-carousel, .y2k-carousel, .rg-carousel) { - display: grid; - grid-auto-flow: column; - grid-auto-columns: minmax(min(100%, var(--ly-carousel-item-min)), var(--ly-carousel-item-max)); - gap: var(--ly-grid-gap); - overflow-x: auto; - overscroll-behavior-inline: contain; - scroll-snap-type: x proximity; - } - - :where(.saas-carousel, .bento-carousel, .max-carousel, .bau-carousel, .tactile-carousel, .neo-carousel, .retro-carousel, .brutal-carousel, .cyber-carousel, .y2k-carousel, .rg-carousel) > * { - min-width: 0; - scroll-snap-align: start; - } - - @container (min-width: 48rem) { - :where(.saas-split, .bento-split, .max-split, .bau-split, .tactile-split, .neo-split, .retro-split, .brutal-split, .cyber-split, .y2k-split, .rg-split) { - grid-template-columns: minmax(0, var(--ly-split-primary, 1fr)) minmax(0, var(--ly-split-secondary, 1fr)); - } - } -} diff --git a/styles/legacy.css b/styles/legacy.css deleted file mode 100644 index d8bcb98..0000000 --- a/styles/legacy.css +++ /dev/null @@ -1,173 +0,0 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -@import url("./layout-style-css.css"); - -@layer ly.legacy { - /* Preserve v1 wrapper measures while applications migrate to semantic v2 names. */ - .ly-container { - container-name: ly-wrapper; - container-type: inline-size; - width: min(100% - (var(--ly-page-padding-inline) * 2), var(--ly-container-max)); - margin-inline: auto; - } - - .ly-container--sm, - .ly-wrapper--sm { - --ly-container-max: var(--ly-container-sm); - --ly-wrapper-max: 40rem; - } - - .ly-container--md, - .ly-wrapper--md { - --ly-container-max: var(--ly-container-md); - --ly-wrapper-max: 56rem; - } - - .ly-container--lg, - .ly-wrapper--lg { - --ly-container-max: var(--ly-container-lg); - --ly-wrapper-max: 72rem; - } - - .ly-container--xl, - .ly-wrapper--xl { - --ly-container-max: var(--ly-container-xl); - --ly-wrapper-max: 88rem; - } - - .ly-container--wide { - --ly-container-max: var(--ly-container-wide); - } - - .ly-container--fluid { - width: 100%; - max-width: none; - padding-inline: var(--ly-wrapper-gutter); - } - - .ly-wrapper--fluid { - --ly-wrapper-max: 100%; - } - - .ly-wrapper--readable { - --ly-wrapper-max: 68ch; - } - - .ly-row { - display: flex; - flex-wrap: wrap; - /* Outer compensation preserves exact percentage tracks while columns own gutters. */ - margin-inline: calc(var(--ly-gutter, var(--ly-gap)) * -0.5); - } - - .ly-col { - flex: 1 1 0; - min-inline-size: 0; - padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); - } - - .ly-col-1 { flex: 0 0 auto; width: 8.333333%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - .ly-col-2 { flex: 0 0 auto; width: 16.666667%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - .ly-col-3 { flex: 0 0 auto; width: 25%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - .ly-col-4 { flex: 0 0 auto; width: 33.333333%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - .ly-col-5 { flex: 0 0 auto; width: 41.666667%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - .ly-col-6 { flex: 0 0 auto; width: 50%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - .ly-col-7 { flex: 0 0 auto; width: 58.333333%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - .ly-col-8 { flex: 0 0 auto; width: 66.666667%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - .ly-col-9 { flex: 0 0 auto; width: 75%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - .ly-col-10 { flex: 0 0 auto; width: 83.333333%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - .ly-col-11 { flex: 0 0 auto; width: 91.666667%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - .ly-col-12 { flex: 0 0 auto; width: 100%; padding-inline: calc(var(--ly-gutter, var(--ly-gap)) * 0.5); } - - .ly-carousel { - display: grid; - grid-auto-flow: column; - grid-auto-columns: minmax(min(100%, var(--ly-reel-item-min)), var(--ly-reel-item-max)); - gap: var(--ly-grid-gap); - overflow-x: auto; - overflow-inline: auto; - overscroll-behavior-inline: contain; - scroll-snap-type: inline proximity; - } - - .ly-carousel > * { - min-inline-size: 0; - scroll-snap-align: start; - } - - .ly-button-group { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: var(--ly-cluster-gap); - } - - .ly-button-group > * { - flex: 0 1 auto; - min-inline-size: min(100%, var(--ly-button-min, 8rem)); - } - - .ly-sidebar-layout { - display: grid; - grid-template-columns: minmax(0, 1fr); - gap: var(--ly-gap); - } - - .ly-sidebar-layout > * { - min-inline-size: 0; - } - - .ly-content { - min-inline-size: 0; - } - - .ly-divider { - /* V2 preserves separator geometry here; themes remain responsible for visible paint. */ - min-block-size: 1px; - margin-block: var(--ly-space-5); - } - - .ly-card-sm { min-block-size: var(--ly-card-size-sm); } - .ly-card-md { min-block-size: var(--ly-card-size-md); } - .ly-card-lg { min-block-size: var(--ly-card-size-lg); } - - .ly-scroll-area { - min-block-size: 0; - max-block-size: var(--ly-scroll-max); - overflow: auto; - overscroll-behavior: contain; - } - - .ly-app-header { grid-area: header; min-inline-size: 0; } - .ly-app-sidebar { grid-area: sidebar; min-inline-size: 0; } - .ly-app-main { grid-area: main; min-inline-size: 0; } - .ly-app-aside { grid-area: aside; min-inline-size: 0; } - .ly-app-footer { grid-area: footer; min-inline-size: 0; } - - /* The build expands canonical personality rules into functional v1 aliases here. */ - /* @generated-personality-aliases */ - - @container (min-width: 48rem) { - .ly-sidebar-layout { - grid-template-columns: minmax(min(100%, var(--ly-sidebar-min)), var(--ly-sidebar-max)) minmax(0, 1fr); - align-items: start; - } - - .ly-sidebar-layout--right { - grid-template-columns: minmax(0, 1fr) minmax(min(100%, var(--ly-sidebar-min)), var(--ly-sidebar-max)); - } - - .ly-panes--two { - grid-template-columns: minmax(0, 1fr) minmax(min(100%, var(--ly-pane-size)), 0.7fr); - } - } - - @container (min-width: 64rem) { - .ly-panes--three { - grid-template-columns: - minmax(min(100%, var(--ly-pane-rail, 14rem)), 0.35fr) - minmax(0, 1fr) - minmax(min(100%, var(--ly-pane-rail, 14rem)), 0.35fr); - } - } -} diff --git a/styles/personalities.css b/styles/personalities.css index 29016df..b98c221 100644 --- a/styles/personalities.css +++ b/styles/personalities.css @@ -1,4 +1,4 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @import url("./personalities/minimal-saas.css"); @import url("./personalities/bento.css"); diff --git a/styles/personalities/bauhaus.css b/styles/personalities/bauhaus.css index c08ebb2..52ce8c2 100644 --- a/styles/personalities/bauhaus.css +++ b/styles/personalities/bauhaus.css @@ -1,49 +1,20 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* Layout style: bauhaus. A left rail anchors an intentionally asymmetric grid. */ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @layer ly.personalities.bauhaus { :where(.ly-root[data-ly-layout="bauhaus"]) { + --ly-personality-wrapper-max: 96rem; + --ly-profile-gap: var(--ly-space-6); + --ly-grid-min: 13rem; --ly-recipe-rail: 14rem; --ly-recipe-aside: 18rem; - --ly-grid-columns: 6; - --ly-grid-min: 13rem; - --ly-personality-wrapper-max: 96rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - /* Cap the fallback rail until the wider personality template is eligible. */ - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="bauhaus"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 14rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 52rem) { - :where(.ly-root[data-ly-layout="bauhaus"]) .ly-grid > :nth-child(3n + 1) { - grid-column: span 2; - grid-row: span 2; - } - } - - /* The four-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="bauhaus"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header header aside" - "sidebar main main aside" - "sidebar footer footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 14rem), 0.24fr) - minmax(0, 0.7fr) - minmax(0, 1.3fr) - minmax(min(100%, 18rem), 0.3fr); - } + --ly-app-shell-wide-areas: + "header header header header" + "sidebar main main aside" + "sidebar footer footer aside"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.24fr) + minmax(0, 0.7fr) + minmax(0, 1.3fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.3fr); } } diff --git a/styles/personalities/bento.css b/styles/personalities/bento.css index 29121d6..33d50f1 100644 --- a/styles/personalities/bento.css +++ b/styles/personalities/bento.css @@ -1,46 +1,22 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* Layout style: bento. A full-width shell and staggered spans form modular tiles. */ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @layer ly.personalities.bento { :where(.ly-root[data-ly-layout="bento"]) { - --ly-grid-columns: 6; - --ly-grid-min: 12rem; - --ly-card-grid-min: 13rem; --ly-personality-wrapper-max: 112rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="bento"]) .ly-grid > :nth-child(6n + 1) { - grid-column: span 2; - grid-row: span 2; - } - - :where(.ly-root[data-ly-layout="bento"]) - :where(.ly-card-grid, [data-ly-recipe="card-grid"]) - > :nth-child(6n + 1) { - grid-column: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="bento"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header header" - "sidebar main main" - "aside main main" - "footer footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto auto; - grid-template-columns: - minmax(min(100%, 14rem), 0.3fr) - minmax(0, 1fr) - minmax(0, 1fr); - } + --ly-profile-gap: var(--ly-space-4); + --ly-grid-min: 12rem; + --ly-card-grid-min: 14rem; + --ly-gallery-min: 11rem; + --ly-recipe-rail: 14rem; + --ly-recipe-aside: 18rem; + --ly-app-shell-wide-areas: + "header header header" + "sidebar main main" + "aside main main" + "footer footer footer"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.3fr) + minmax(0, 1fr) + minmax(0, 1fr); } } diff --git a/styles/personalities/brutalism.css b/styles/personalities/brutalism.css index f88a9e1..8815608 100644 --- a/styles/personalities/brutalism.css +++ b/styles/personalities/brutalism.css @@ -1,39 +1,19 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* Layout style: brutalism. A blunt right rail counters a broad primary plane. */ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @layer ly.personalities.brutalism { :where(.ly-root[data-ly-layout="brutalism"]) { - --ly-recipe-rail: 18rem; - --ly-recipe-aside: 16rem; - --ly-grid-columns: 6; - --ly-grid-min: 14rem; --ly-personality-wrapper-max: 100rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="brutalism"]) .ly-grid > :nth-child(3n) { - grid-column: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="brutalism"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header sidebar" - "main aside sidebar" - "footer footer sidebar"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(0, 1.3fr) - minmax(min(100%, 16rem), 0.7fr) - minmax(min(100%, 18rem), 0.34fr); - } + --ly-profile-gap: var(--ly-space-3); + --ly-grid-min: 14rem; + --ly-recipe-rail: 16rem; + --ly-recipe-aside: 18rem; + --ly-app-shell-wide-areas: + "header header sidebar" + "main aside sidebar" + "footer footer sidebar"; + --ly-app-shell-wide-columns: + minmax(0, 1.3fr) + minmax(0, 0.7fr) + minmax(min(100%, var(--ly-recipe-rail)), 0.34fr); } } diff --git a/styles/personalities/cyberpunk.css b/styles/personalities/cyberpunk.css index 3b715eb..dca349f 100644 --- a/styles/personalities/cyberpunk.css +++ b/styles/personalities/cyberpunk.css @@ -1,39 +1,19 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* Layout style: cyberpunk. A narrow command rail fronts a dense three-lane shell. */ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @layer ly.personalities.cyberpunk { :where(.ly-root[data-ly-layout="cyberpunk"]) { + --ly-personality-wrapper-max: 112rem; + --ly-profile-gap: var(--ly-space-4); + --ly-grid-min: 12rem; --ly-recipe-rail: 13rem; --ly-recipe-aside: 19rem; - --ly-grid-columns: 8; - --ly-grid-min: 12rem; - --ly-personality-wrapper-max: 112rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 44rem) { - :where(.ly-root[data-ly-layout="cyberpunk"]) .ly-grid > :nth-child(4n + 2) { - grid-column: span 3; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="cyberpunk"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header aside" - "sidebar main aside" - "sidebar footer aside"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 13rem), 0.2fr) - minmax(0, 1fr) - minmax(min(100%, 19rem), 0.32fr); - } + --ly-app-shell-wide-areas: + "sidebar header header" + "sidebar main aside" + "sidebar footer footer"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.2fr) + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.32fr); } } diff --git a/styles/personalities/f-pattern.css b/styles/personalities/f-pattern.css index de31747..904e0b7 100644 --- a/styles/personalities/f-pattern.css +++ b/styles/personalities/f-pattern.css @@ -1,51 +1,22 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; -/* Layout style: f-pattern. A left rail supports a wide first-reading column. */ - -@layer ly.personalities.f_pattern { +@layer ly.personalities.f-pattern { :where(.ly-root[data-ly-layout="f-pattern"]) { + --ly-personality-wrapper-max: 92rem; + --ly-profile-gap: var(--ly-space-4); + --ly-grid-min: 14rem; --ly-recipe-rail: 16rem; --ly-recipe-aside: 18rem; - --ly-grid-columns: 6; - --ly-grid-min: 14rem; - --ly-personality-wrapper-max: 92rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="f-pattern"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 16rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 56rem) { - :where(.ly-root[data-ly-layout="f-pattern"]) .ly-grid > :nth-child(3n + 1) { - grid-column: span 2; - } - - :where(.ly-root[data-ly-layout="f-pattern"]) - :where(.ly-split-hero, [data-ly-recipe="split-hero"]) { - grid-template-columns: minmax(0, 1.35fr) minmax(0, 0.65fr); - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="f-pattern"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header header" - "sidebar main aside" - "sidebar footer aside"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 16rem), 0.26fr) - minmax(0, 1.35fr) - minmax(min(100%, 18rem), 0.65fr); - } + --ly-app-shell-wide-areas: + "sidebar header header" + "sidebar main aside" + "sidebar footer footer"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.26fr) + minmax(0, 1.35fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.65fr); + --ly-split-hero-wide-columns: + minmax(0, 1.8fr) + minmax(0, 0.8fr); } } diff --git a/styles/personalities/maximalist.css b/styles/personalities/maximalist.css index a0be822..79fc40d 100644 --- a/styles/personalities/maximalist.css +++ b/styles/personalities/maximalist.css @@ -1,54 +1,22 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* Layout style: maximalist. A full-bleed four-track mosaic favors dramatic spans. */ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @layer ly.personalities.maximalist { :where(.ly-root[data-ly-layout="maximalist"]) { - --ly-grid-columns: 12; - --ly-grid-min: 10rem; --ly-personality-wrapper-max: 100%; - --ly-card-grid-min: 12rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="maximalist"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 18rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 56rem) { - :where(.ly-root[data-ly-layout="maximalist"]) .ly-grid > :nth-child(7n + 1) { - grid-column: span 3; - grid-row: span 2; - } - - :where(.ly-root[data-ly-layout="maximalist"]) - :where(.ly-gallery, [data-ly-recipe="gallery"]) - > :nth-child(5n + 1) { - grid-column: span 2; - grid-row: span 2; - } - } - - /* The four-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="maximalist"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header header header" - "main main sidebar aside" - "main main footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(0, 1.4fr) - minmax(0, 0.6fr) - minmax(min(100%, 15rem), 0.32fr) - minmax(min(100%, 18rem), 0.38fr); - } + --ly-profile-gap: var(--ly-space-7); + --ly-grid-min: 10rem; + --ly-card-grid-min: 13rem; + --ly-gallery-min: 10rem; + --ly-recipe-rail: 15rem; + --ly-recipe-aside: 18rem; + --ly-app-shell-wide-areas: + "header header header header" + "main main sidebar aside" + "main main footer footer"; + --ly-app-shell-wide-columns: + minmax(0, 1.4fr) + minmax(0, 0.6fr) + minmax(min(100%, var(--ly-recipe-rail)), 0.32fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.38fr); } } diff --git a/styles/personalities/minimal-saas.css b/styles/personalities/minimal-saas.css index 828f82e..9b2bb14 100644 --- a/styles/personalities/minimal-saas.css +++ b/styles/personalities/minimal-saas.css @@ -1,39 +1,13 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; -/* Layout style: minimal-saas. A measured left rail keeps work areas predictable. */ - -@layer ly.personalities.minimal_saas { +@layer ly.personalities.minimal-saas { :where(.ly-root[data-ly-layout="minimal-saas"]) { + --ly-personality-wrapper-max: 88rem; + --ly-profile-gap: var(--ly-space-5); + --ly-grid-min: 16rem; --ly-recipe-rail: 15rem; --ly-recipe-aside: 16rem; - --ly-grid-columns: 4; - --ly-grid-min: 16rem; - --ly-personality-wrapper-max: 88rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="minimal-saas"]) .ly-grid > :nth-child(4n + 1) { - grid-column: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="minimal-saas"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header header" - "sidebar main aside" - "sidebar footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 15rem), 0.24fr) - minmax(0, 1fr) - minmax(min(100%, 16rem), 0.28fr); - } + --ly-split-primary: 1.05fr; + --ly-split-secondary: 0.95fr; } } diff --git a/styles/personalities/mondrian.css b/styles/personalities/mondrian.css index 9e5c662..0b1fc66 100644 --- a/styles/personalities/mondrian.css +++ b/styles/personalities/mondrian.css @@ -1,47 +1,19 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* Layout style: mondrian. Unequal zones and spanning blocks create a strict mosaic. */ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @layer ly.personalities.mondrian { :where(.ly-root[data-ly-layout="mondrian"]) { + --ly-personality-wrapper-max: 112rem; + --ly-profile-gap: var(--ly-space-3); + --ly-grid-min: 11rem; --ly-recipe-rail: 13rem; --ly-recipe-aside: 18rem; - --ly-grid-columns: 10; - --ly-grid-min: 11rem; - --ly-personality-wrapper-max: 112rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="mondrian"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 13rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 52rem) { - :where(.ly-root[data-ly-layout="mondrian"]) .ly-grid > :nth-child(5n + 1) { - grid-column: span 2; - grid-row: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="mondrian"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header header" - "sidebar main aside" - "footer footer aside"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 13rem), 0.22fr) - minmax(0, 1.45fr) - minmax(min(100%, 18rem), 0.55fr); - } + --ly-app-shell-wide-areas: + "sidebar header header" + "sidebar main aside" + "footer footer aside"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.22fr) + minmax(0, 1.45fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.55fr); } } diff --git a/styles/personalities/neumorphism.css b/styles/personalities/neumorphism.css index 556c31d..be83073 100644 --- a/styles/personalities/neumorphism.css +++ b/styles/personalities/neumorphism.css @@ -1,46 +1,22 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* Layout style: neumorphism. A calm right rail preserves a compact workspace. */ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @layer ly.personalities.neumorphism { :where(.ly-root[data-ly-layout="neumorphism"]) { + --ly-personality-wrapper-max: 84rem; + --ly-profile-gap: var(--ly-space-6); + --ly-grid-min: 17rem; --ly-recipe-rail: 17rem; --ly-recipe-aside: 19rem; - --ly-grid-columns: 4; - --ly-grid-min: 17rem; - --ly-personality-wrapper-max: 84rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="neumorphism"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 17rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 52rem) { - :where(.ly-root[data-ly-layout="neumorphism"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header sidebar" - "main sidebar" - "aside sidebar" - "footer sidebar"; - grid-template-rows: auto minmax(0, 1fr) auto auto; - grid-template-columns: minmax(0, 1fr) minmax(min(100%, 17rem), 0.3fr); - } - - :where(.ly-root[data-ly-layout="neumorphism"]) .ly-grid > :nth-child(4n + 1) { - grid-column: span 2; - } - - :where(.ly-root[data-ly-layout="neumorphism"]) - :where(.ly-list-detail, [data-ly-recipe="list-detail"]) { - grid-template-columns: minmax(0, 0.58fr) minmax(min(100%, 19rem), 0.42fr); - } + --ly-app-shell-wide-areas: + "header sidebar" + "main sidebar" + "aside sidebar" + "footer sidebar"; + --ly-app-shell-wide-columns: + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-rail)), 0.3fr); + --ly-list-detail-wide-columns: + minmax(0, 1.1fr) + minmax(min(100%, var(--ly-pane-size)), 0.7fr); } } diff --git a/styles/personalities/retro-glass.css b/styles/personalities/retro-glass.css index 326d683..f0c959d 100644 --- a/styles/personalities/retro-glass.css +++ b/styles/personalities/retro-glass.css @@ -1,47 +1,19 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; -/* Layout style: retro-glass. A stepped right rail floats beside a wide stage. */ - -@layer ly.personalities.retro_glass { +@layer ly.personalities.retro-glass { :where(.ly-root[data-ly-layout="retro-glass"]) { - --ly-recipe-rail: 18rem; - --ly-recipe-aside: 20rem; - --ly-grid-columns: 8; - --ly-grid-min: 15rem; --ly-personality-wrapper-max: 104rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="retro-glass"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 18rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 56rem) { - :where(.ly-root[data-ly-layout="retro-glass"]) .ly-grid > :nth-child(4n) { - grid-column: span 2; - grid-row: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="retro-glass"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header sidebar" - "main main sidebar" - "aside footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(0, 1.25fr) - minmax(0, 0.75fr) - minmax(min(100%, 18rem), 0.32fr); - } + --ly-profile-gap: var(--ly-space-5); + --ly-grid-min: 15rem; + --ly-recipe-rail: 18rem; + --ly-recipe-aside: 18rem; + --ly-app-shell-wide-areas: + "header header sidebar" + "main main sidebar" + "aside footer footer"; + --ly-app-shell-wide-columns: + minmax(0, 1.25fr) + minmax(0, 0.75fr) + minmax(min(100%, var(--ly-recipe-rail)), 0.32fr); } } diff --git a/styles/personalities/retrofuturism.css b/styles/personalities/retrofuturism.css index 886ef09..106d878 100644 --- a/styles/personalities/retrofuturism.css +++ b/styles/personalities/retrofuturism.css @@ -1,39 +1,19 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* Layout style: retrofuturism. Twin rails frame a focused central work zone. */ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @layer ly.personalities.retrofuturism { :where(.ly-root[data-ly-layout="retrofuturism"]) { + --ly-personality-wrapper-max: 106rem; + --ly-profile-gap: var(--ly-space-5); + --ly-grid-min: 14rem; --ly-recipe-rail: 14rem; --ly-recipe-aside: 17rem; - --ly-grid-columns: 6; - --ly-grid-min: 14rem; - --ly-personality-wrapper-max: 106rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="retrofuturism"]) .ly-grid > :nth-child(6n + 1) { - grid-column: span 2; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="retrofuturism"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header aside" - "sidebar main aside" - "sidebar footer aside"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 14rem), 0.24fr) - minmax(0, 1fr) - minmax(min(100%, 17rem), 0.3fr); - } + --ly-app-shell-wide-areas: + "sidebar header aside" + "sidebar main aside" + "sidebar footer aside"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.24fr) + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.3fr); } } diff --git a/styles/personalities/split-screen.css b/styles/personalities/split-screen.css index 8ba8e06..4c95a76 100644 --- a/styles/personalities/split-screen.css +++ b/styles/personalities/split-screen.css @@ -1,41 +1,29 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; -/* Layout style: split-screen. Equal tracks keep two primary experiences in balance. */ - -@layer ly.personalities.split_screen { +@layer ly.personalities.split-screen { :where(.ly-root[data-ly-layout="split-screen"]) { - --ly-grid-columns: 2; - --ly-grid-min: 20rem; --ly-personality-wrapper-max: 100%; - --ly-split-primary: 1fr; - --ly-split-secondary: 1fr; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="split-screen"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header" - "main sidebar" - "aside sidebar" - "footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto auto; - grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); - } - - :where(.ly-root[data-ly-layout="split-screen"]) - :where( - .ly-split, - .ly-split-hero, - [data-ly-recipe="split-hero"], - .ly-list-detail, - [data-ly-recipe="list-detail"] - ) { - grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); - } + --ly-profile-gap: var(--ly-space-4); + --ly-grid-min: 20rem; + /* + Fixed preferred halves leave a shrink-safe center track in recipes that + retain the shared three-column dashboard topology. + */ + --ly-recipe-rail: 24rem; + --ly-recipe-aside: 24rem; + --ly-app-shell-wide-areas: + "header header" + "main sidebar" + "aside sidebar" + "footer footer"; + --ly-app-shell-wide-columns: + minmax(0, 1fr) + minmax(0, 1fr); + --ly-split-hero-wide-columns: + minmax(0, 1fr) + minmax(0, 1fr); + --ly-list-detail-wide-columns: + minmax(0, 1fr) + minmax(0, 1fr); } } diff --git a/styles/personalities/synthwave.css b/styles/personalities/synthwave.css index 063f77d..71f400a 100644 --- a/styles/personalities/synthwave.css +++ b/styles/personalities/synthwave.css @@ -1,48 +1,20 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* Layout style: synthwave. A cinematic center stage sits between support zones. */ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @layer ly.personalities.synthwave { :where(.ly-root[data-ly-layout="synthwave"]) { + --ly-personality-wrapper-max: 112rem; + --ly-profile-gap: var(--ly-space-6); + --ly-grid-min: 14rem; --ly-recipe-rail: 16rem; --ly-recipe-aside: 20rem; - --ly-grid-columns: 12; - --ly-grid-min: 14rem; - --ly-reel-item-max: 34rem; - --ly-personality-wrapper-max: 112rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="synthwave"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 16rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="synthwave"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header header" - "sidebar main aside" - "footer footer footer"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 16rem), 0.28fr) - minmax(0, 1fr) - minmax(min(100%, 20rem), 0.34fr); - } - - :where(.ly-root[data-ly-layout="synthwave"]) .ly-grid > :nth-child(4n + 1) { - grid-column: span 3; - } - - :where(.ly-root[data-ly-layout="synthwave"]) .ly-reel { - grid-auto-columns: minmax(min(100%, 20rem), var(--ly-reel-item-max)); - } + --ly-app-shell-wide-areas: + "header header header" + "sidebar main aside" + "footer footer footer"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.28fr) + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.34fr); + --ly-reel-item-min: 20rem; } } diff --git a/styles/personalities/tactile.css b/styles/personalities/tactile.css index a5f8120..e3ee930 100644 --- a/styles/personalities/tactile.css +++ b/styles/personalities/tactile.css @@ -1,39 +1,22 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* Layout style: tactile. A compact left rail leaves a broad, steady work lane. */ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @layer ly.personalities.tactile { :where(.ly-root[data-ly-layout="tactile"]) { + --ly-personality-wrapper-max: 82rem; + --ly-profile-gap: var(--ly-space-4); + --ly-grid-min: 15rem; --ly-recipe-rail: 17rem; --ly-recipe-aside: 20rem; - --ly-grid-columns: 5; - --ly-grid-min: 15rem; - --ly-personality-wrapper-max: 82rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="tactile"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header" - "sidebar main" - "sidebar aside" - "sidebar footer"; - grid-template-rows: auto minmax(0, 1fr) auto auto; - grid-template-columns: minmax(min(100%, 17rem), 0.28fr) minmax(0, 1fr); - } - - :where(.ly-root[data-ly-layout="tactile"]) .ly-grid > :nth-child(5n + 2) { - grid-column: span 2; - } - - :where(.ly-root[data-ly-layout="tactile"]) - :where(.ly-list-detail, [data-ly-recipe="list-detail"]) { - grid-template-columns: minmax(min(100%, 20rem), 0.42fr) minmax(0, 0.58fr); - } + --ly-app-shell-wide-areas: + "header header" + "sidebar main" + "aside main" + "footer footer"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-rail)), 0.28fr) + minmax(0, 1fr); + --ly-list-detail-wide-columns: + minmax(min(100%, var(--ly-pane-size)), 0.5fr) + minmax(0, 0.9fr); } } diff --git a/styles/personalities/y2k.css b/styles/personalities/y2k.css index b696f4a..fbaa789 100644 --- a/styles/personalities/y2k.css +++ b/styles/personalities/y2k.css @@ -1,39 +1,19 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; - -/* Layout style: y2k. A tall right rail frames a reversed supporting workspace. */ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; @layer ly.personalities.y2k { :where(.ly-root[data-ly-layout="y2k"]) { - --ly-recipe-rail: 16rem; - --ly-recipe-aside: 18rem; - --ly-grid-columns: 5; - --ly-grid-min: 13rem; --ly-personality-wrapper-max: 90rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="y2k"]) .ly-grid > :nth-child(5n + 1) { - grid-column: span 3; - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="y2k"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header sidebar" - "aside main sidebar" - "footer footer sidebar"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(min(100%, 18rem), 0.34fr) - minmax(0, 1fr) - minmax(min(100%, 16rem), 0.28fr); - } + --ly-profile-gap: var(--ly-space-6); + --ly-grid-min: 13rem; + --ly-recipe-rail: 18rem; + --ly-recipe-aside: 16rem; + --ly-app-shell-wide-areas: + "header header sidebar" + "aside main sidebar" + "footer footer sidebar"; + --ly-app-shell-wide-columns: + minmax(min(100%, var(--ly-recipe-aside)), 0.34fr) + minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-rail)), 0.28fr); } } diff --git a/styles/personalities/z-pattern.css b/styles/personalities/z-pattern.css index 1960a48..8d6c46e 100644 --- a/styles/personalities/z-pattern.css +++ b/styles/personalities/z-pattern.css @@ -1,52 +1,22 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; -/* Layout style: z-pattern. A right rail closes a diagonal reading progression. */ - -@layer ly.personalities.z_pattern { +@layer ly.personalities.z-pattern { :where(.ly-root[data-ly-layout="z-pattern"]) { + --ly-personality-wrapper-max: 108rem; + --ly-profile-gap: var(--ly-space-5); + --ly-grid-min: 14rem; --ly-recipe-rail: 17rem; --ly-recipe-aside: 19rem; - --ly-grid-columns: 8; - --ly-grid-min: 14rem; - --ly-personality-wrapper-max: 108rem; - - container-name: ly-personality; - container-type: inline-size; - min-inline-size: 0; - } - - @container (min-width: 48rem) { - :where(.ly-root[data-ly-layout="z-pattern"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-columns: minmax(min(100%, 17rem), 0.3fr) minmax(0, 1fr); - } - } - - @container (min-width: 60rem) { - :where(.ly-root[data-ly-layout="z-pattern"]) .ly-grid > :nth-child(4n + 2) { - grid-column: span 2; - align-self: end; - } - - :where(.ly-root[data-ly-layout="z-pattern"]) - :where(.ly-split-hero, [data-ly-recipe="split-hero"]) { - grid-template-columns: minmax(0, 1.5fr) minmax(0, 0.5fr); - } - } - - /* The three-track shell waits for a locally feasible allocation. */ - @container (min-width: 64rem) { - :where(.ly-root[data-ly-layout="z-pattern"]) - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header sidebar" - "main aside sidebar" - "footer aside sidebar"; - grid-template-rows: auto minmax(0, 1fr) auto; - grid-template-columns: - minmax(0, 1.45fr) - minmax(min(100%, 19rem), 0.55fr) - minmax(min(100%, 17rem), 0.3fr); - } + --ly-app-shell-wide-areas: + "header header sidebar" + "main aside sidebar" + "footer aside sidebar"; + --ly-app-shell-wide-columns: + minmax(0, 1.45fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.55fr) + minmax(min(100%, var(--ly-recipe-rail)), 0.3fr); + --ly-split-hero-wide-columns: + minmax(0, 1.5fr) + minmax(0, 0.5fr); } } diff --git a/styles/primitives.css b/styles/primitives.css index b282bf4..1e957d1 100644 --- a/styles/primitives.css +++ b/styles/primitives.css @@ -1,10 +1,13 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; -/* Reusable composition primitives own flow and sizing only. */ +/* Composition primitives use intrinsic sizing so their content chooses reflow points. */ @layer ly.primitives { .ly-page { - min-block-size: 100svh; + min-block-size: 100vh; + min-block-size: 100dvh; + padding-block-start: var(--ly-safe-area-block-start); + padding-block-end: var(--ly-safe-area-block-end); } .ly-header, @@ -21,9 +24,9 @@ } .ly-header--sticky { - position: sticky; + position: var(--ly-sticky-position); inset-block-start: 0; - z-index: var(--ly-z-header); + z-index: var(--ly-z-header, 20); } .ly-section { @@ -63,6 +66,7 @@ .ly-cover { display: flex; flex-direction: column; + min-block-size: 100vh; min-block-size: var(--ly-cover-min); padding-block: var(--ly-cover-padding, var(--ly-space-5)); } @@ -92,6 +96,7 @@ .ly-sidebar > :where(.ly-sidebar__side, [data-ly-sidebar="side"]) { flex-basis: var(--ly-sidebar-size); flex-grow: 1; + min-inline-size: min(100%, var(--ly-sidebar-size)); } .ly-sidebar > :where(.ly-sidebar__content, [data-ly-sidebar="content"]) { @@ -102,55 +107,44 @@ .ly-grid { display: grid; - grid-template-columns: repeat(var(--ly-grid-columns), minmax(0, 1fr)); - gap: var(--ly-grid-gap); - } - - .ly-grid--auto { grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-grid-min)), 1fr)); + gap: var(--ly-grid-gap); } - .ly-grid > *, - .ly-split > *, - .ly-panes > *, - .ly-media > * { - min-inline-size: 0; + .ly-grid--fixed { + grid-template-columns: repeat(var(--ly-grid-columns), minmax(0, 1fr)); } .ly-split { display: grid; - grid-template-columns: minmax(0, 1fr); + grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-split-min)), 1fr)); gap: var(--ly-gap); align-items: var(--ly-split-align, center); } .ly-panes { display: grid; - grid-template-columns: minmax(0, 1fr); + grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-pane-min)), 1fr)); gap: var(--ly-gap); } .ly-media { display: grid; - grid-template-areas: - "media" - "content" - "actions"; - grid-template-columns: minmax(0, 1fr); + grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-media-min)), 1fr)); gap: var(--ly-gap); align-items: var(--ly-media-align, start); } - .ly-media > :where(.ly-media__asset, [data-ly-media="asset"]) { - grid-area: media; - } - - .ly-media > :where(.ly-media__content, [data-ly-media="content"]) { - grid-area: content; + .ly-media > :where(.ly-media__actions, [data-ly-media="actions"]) { + min-inline-size: min(100%, var(--ly-media-size)); } - .ly-media > :where(.ly-media__actions, [data-ly-media="actions"]) { - grid-area: actions; + .ly-grid > *, + .ly-split > *, + .ly-panes > *, + .ly-media > * { + min-inline-size: 0; + min-block-size: 0; } .ly-reel { @@ -159,7 +153,6 @@ grid-auto-columns: minmax(min(100%, var(--ly-reel-item-min)), var(--ly-reel-item-max)); gap: var(--ly-grid-gap); overflow-x: auto; - overflow-inline: auto; overscroll-behavior-inline: contain; scroll-snap-type: inline proximity; } @@ -183,37 +176,7 @@ .ly-scroll { min-block-size: 0; max-block-size: var(--ly-scroll-max); - overflow: auto; - overscroll-behavior: contain; - } - - /* Unsupported container-query browsers retain this safe DOM-order stack. */ -} - -@layer ly.primitives { - @container (min-width: 48rem) { - .ly-split { - grid-template-columns: minmax(0, var(--ly-split-primary, 1fr)) minmax(0, var(--ly-split-secondary, 1fr)); - } - - .ly-panes--2 { - grid-template-columns: minmax(0, 1fr) minmax(min(100%, var(--ly-pane-size)), 0.7fr); - } - - .ly-media { - grid-template-areas: - "media content" - "media actions"; - grid-template-columns: minmax(min(100%, var(--ly-media-size)), auto) minmax(0, 1fr); - } - } - - @container (min-width: 64rem) { - .ly-panes--3 { - grid-template-columns: - minmax(min(100%, var(--ly-pane-rail, 14rem)), 0.35fr) - minmax(0, 1fr) - minmax(min(100%, var(--ly-pane-rail, 14rem)), 0.35fr); - } + overflow-y: auto; + overscroll-behavior-block: contain; } } diff --git a/styles/recipes.css b/styles/recipes.css index 08eef6c..a504943 100644 --- a/styles/recipes.css +++ b/styles/recipes.css @@ -1,35 +1,41 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; /* - Built-in recipes follow semantic mobile DOM order. Wider arrangements use - named areas so visual placement never changes keyboard or reading order. + Recipes preserve the narrow-screen DOM order. Automatic topology queries + consume inherited profile tokens and can be disabled per recipe. */ @layer ly.recipes { - :where(.ly-app-shell, [data-ly-recipe="app-shell"]), - :where(.ly-dashboard, [data-ly-recipe="dashboard"]), - :where(.ly-docs, [data-ly-recipe="docs"]), - :where(.ly-list-detail, [data-ly-recipe="list-detail"]), - :where(.ly-split-hero, [data-ly-recipe="split-hero"]), - :where(.ly-gallery, [data-ly-recipe="gallery"]), - :where(.ly-card-grid, [data-ly-recipe="card-grid"]) { - container-name: ly-recipe; + :where( + [data-ly-recipe="app-shell"], + [data-ly-recipe="dashboard"], + [data-ly-recipe="docs"], + [data-ly-recipe="list-detail"], + [data-ly-recipe="split-hero"], + [data-ly-recipe="gallery"], + [data-ly-recipe="card-grid"] + ) { + container-name: ly-scope; container-type: inline-size; min-inline-size: 0; + min-block-size: 0; } - :where(.ly-app-shell, [data-ly-recipe="app-shell"]), - :where(.ly-dashboard, [data-ly-recipe="dashboard"]), - :where(.ly-docs, [data-ly-recipe="docs"]), - :where(.ly-list-detail, [data-ly-recipe="list-detail"]), - :where(.ly-split-hero, [data-ly-recipe="split-hero"]) { + :where( + [data-ly-recipe="app-shell"], + [data-ly-recipe="dashboard"], + [data-ly-recipe="docs"], + [data-ly-recipe="list-detail"], + [data-ly-recipe="split-hero"] + ) { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--ly-gap); } - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - min-block-size: 100svh; + [data-ly-recipe="app-shell"] { + min-block-size: 100vh; + min-block-size: var(--ly-shell-min); grid-template-areas: "header" "sidebar" @@ -39,7 +45,8 @@ grid-template-rows: auto auto minmax(0, 1fr) auto auto; } - :where(.ly-dashboard, [data-ly-recipe="dashboard"]) { + [data-ly-recipe="dashboard"], + [data-ly-recipe="docs"] { grid-template-areas: "header" "nav" @@ -48,23 +55,14 @@ "footer"; } - :where(.ly-docs, [data-ly-recipe="docs"]) { - grid-template-areas: - "header" - "nav" - "main" - "aside" - "footer"; - } - - :where(.ly-list-detail, [data-ly-recipe="list-detail"]) { + [data-ly-recipe="list-detail"] { grid-template-areas: "primary" "secondary" "actions"; } - :where(.ly-split-hero, [data-ly-recipe="split-hero"]) { + [data-ly-recipe="split-hero"] { grid-template-areas: "content" "media" @@ -72,207 +70,119 @@ align-items: var(--ly-split-hero-align, center); } - :where(.ly-gallery, [data-ly-recipe="gallery"]), - :where(.ly-card-grid, [data-ly-recipe="card-grid"]) { + [data-ly-recipe="gallery"], + [data-ly-recipe="card-grid"] { display: grid; gap: var(--ly-grid-gap); } - :where(.ly-gallery, [data-ly-recipe="gallery"]) { + [data-ly-recipe="gallery"] { grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-gallery-min)), 1fr)); } - :where(.ly-card-grid, [data-ly-recipe="card-grid"]) { + [data-ly-recipe="card-grid"] { grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-card-grid-min)), 1fr)); } - :where(.ly-gallery, [data-ly-recipe="gallery"]) > *, - :where(.ly-card-grid, [data-ly-recipe="card-grid"]) > * { + :where( + [data-ly-recipe="app-shell"], + [data-ly-recipe="dashboard"], + [data-ly-recipe="docs"], + [data-ly-recipe="list-detail"], + [data-ly-recipe="split-hero"], + [data-ly-recipe="gallery"], + [data-ly-recipe="card-grid"] + ) > * { min-inline-size: 0; + min-block-size: 0; } - :where(.ly-area--header, [data-ly-area="header"]) { + [data-ly-area="header"] { grid-area: header; - min-inline-size: 0; } - :where(.ly-area--nav, [data-ly-area="nav"]) { + [data-ly-area="nav"] { grid-area: nav; - min-inline-size: 0; } - :where(.ly-area--main, [data-ly-area="main"]) { + [data-ly-area="sidebar"] { + grid-area: sidebar; + } + + [data-ly-area="main"] { grid-area: main; - min-inline-size: 0; } - :where(.ly-area--aside, [data-ly-area="aside"]) { + [data-ly-area="aside"] { grid-area: aside; - min-inline-size: 0; } - :where(.ly-area--footer, [data-ly-area="footer"]) { + [data-ly-area="footer"] { grid-area: footer; - min-inline-size: 0; } - :where(.ly-area--content, [data-ly-area="content"]) { + [data-ly-area="content"] { grid-area: content; - min-inline-size: 0; } - :where(.ly-area--media, [data-ly-area="media"]) { + [data-ly-area="media"] { grid-area: media; - min-inline-size: 0; } - :where(.ly-area--actions, [data-ly-area="actions"]) { + [data-ly-area="actions"] { grid-area: actions; - min-inline-size: 0; } - :where(.ly-area--primary, [data-ly-area="primary"]) { + [data-ly-area="primary"] { grid-area: primary; - min-inline-size: 0; } - :where(.ly-area--secondary, [data-ly-area="secondary"]) { + [data-ly-area="secondary"] { grid-area: secondary; - min-inline-size: 0; } - .ly-app-header { - grid-area: header; - min-inline-size: 0; - } - - .ly-app-sidebar { - grid-area: sidebar; - min-inline-size: 0; - } - - .ly-app-main { - grid-area: main; - min-inline-size: 0; - } - - .ly-app-aside { - grid-area: aside; - min-inline-size: 0; - } - - .ly-app-footer { - grid-area: footer; - min-inline-size: 0; - } - - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) - > :where(.ly-area--nav, [data-ly-area="nav"]) { - grid-area: sidebar; - } - - /* - A recipe responds to its nearest ancestor container and then becomes the - containment scope for nested compositions. Standalone roots keep the safe - mobile template when no ancestor container is present. - */ - @container (min-width: 48rem) { - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "header header" - "sidebar main" - "aside main" - "footer footer"; - grid-template-columns: minmax(min(100%, var(--ly-recipe-rail)), auto) minmax(0, 1fr); - } - - :where(.ly-dashboard, [data-ly-recipe="dashboard"]) { - grid-template-areas: - "header header" - "nav nav" - "main aside" - "footer footer"; - grid-template-columns: minmax(0, 1fr) minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); - } - - :where(.ly-docs, [data-ly-recipe="docs"]) { - grid-template-areas: - "header header" - "nav main" - "nav aside" - "footer footer"; - grid-template-columns: minmax(min(100%, var(--ly-recipe-rail)), auto) minmax(0, 1fr); - } - - :where(.ly-list-detail, [data-ly-recipe="list-detail"]) { - grid-template-areas: - "primary secondary" - "actions actions"; - grid-template-columns: minmax(min(100%, var(--ly-pane-size)), 0.7fr) minmax(0, 1fr); - } - - :where(.ly-split-hero, [data-ly-recipe="split-hero"]) { - grid-template-areas: - "content media" - "actions media"; - grid-template-columns: minmax(0, var(--ly-split-primary, 1fr)) minmax(0, var(--ly-split-secondary, 1fr)); - } - - :where(.ly-gallery, [data-ly-recipe="gallery"]) { - --ly-gallery-min: 14rem; - } - - :where(.ly-card-grid, [data-ly-recipe="card-grid"]) { - --ly-card-grid-min: 18rem; + @container ly-scope (min-width: 42rem) { + [data-ly-recipe="split-hero"]:not([data-ly-responsive="manual"]) { + grid-template-areas: var(--ly-split-hero-wide-areas); + grid-template-columns: var(--ly-split-hero-wide-columns); } } - @container (min-width: 64rem) { - :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { - grid-template-areas: - "sidebar header header" - "sidebar main aside" - "sidebar footer footer"; - grid-template-columns: - minmax(min(100%, var(--ly-recipe-rail)), auto) - minmax(0, 1fr) - minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); - } - - :where(.ly-dashboard, [data-ly-recipe="dashboard"]) { - grid-template-areas: - "nav header header" - "nav main aside" - "nav footer footer"; - grid-template-columns: - minmax(min(100%, var(--ly-recipe-rail)), auto) - minmax(0, 1fr) - minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); + @container ly-scope (min-width: 44rem) { + [data-ly-recipe="list-detail"]:not([data-ly-responsive="manual"]) { + grid-template-areas: var(--ly-list-detail-wide-areas); + grid-template-columns: var(--ly-list-detail-wide-columns); } + } - :where(.ly-docs, [data-ly-recipe="docs"]) { - grid-template-areas: - "nav header" - "nav main" - "nav aside" - "nav footer"; - grid-template-columns: minmax(min(100%, var(--ly-recipe-rail)), auto) minmax(0, 1fr); + @container ly-scope (min-width: 48rem) { + [data-ly-recipe="docs"]:not([data-ly-responsive="manual"]) { + grid-template-areas: var(--ly-docs-wide-areas); + grid-template-columns: var(--ly-docs-wide-columns); } + } - :where(.ly-list-detail, [data-ly-recipe="list-detail"]) { - grid-template-columns: minmax(min(100%, var(--ly-pane-size)), 0.45fr) minmax(0, 1fr); + @container ly-scope (min-width: 52rem) { + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]) { + grid-template-areas: var(--ly-app-shell-medium-areas); + grid-template-columns: var(--ly-app-shell-medium-columns); } - :where(.ly-split-hero, [data-ly-recipe="split-hero"]) { - grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); + [data-ly-recipe="dashboard"]:not([data-ly-responsive="manual"]) { + grid-template-areas: var(--ly-dashboard-medium-areas); + grid-template-columns: var(--ly-dashboard-medium-columns); } + } - :where(.ly-gallery, [data-ly-recipe="gallery"]) { - --ly-gallery-min: 16rem; + @container ly-scope (min-width: 72rem) { + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]) { + grid-template-areas: var(--ly-app-shell-wide-areas); + grid-template-columns: var(--ly-app-shell-wide-columns); } - :where(.ly-card-grid, [data-ly-recipe="card-grid"]) { - --ly-card-grid-min: 20rem; + [data-ly-recipe="dashboard"]:not([data-ly-responsive="manual"]) { + grid-template-areas: var(--ly-dashboard-wide-areas); + grid-template-columns: var(--ly-dashboard-wide-columns); } } } diff --git a/styles/utilities.css b/styles/utilities.css index 0497d4e..06a99e4 100644 --- a/styles/utilities.css +++ b/styles/utilities.css @@ -1,72 +1,37 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; + +/* Optional structural utilities expose direct token overrides without breakpoint tiers. */ @layer ly.utilities { .ly-cols-1 { --ly-grid-columns: 1; } .ly-cols-2 { --ly-grid-columns: 2; } .ly-cols-3 { --ly-grid-columns: 3; } .ly-cols-4 { --ly-grid-columns: 4; } - .ly-cols-5 { --ly-grid-columns: 5; } .ly-cols-6 { --ly-grid-columns: 6; } - .ly-cols-7 { --ly-grid-columns: 7; } - .ly-cols-8 { --ly-grid-columns: 8; } - .ly-cols-9 { --ly-grid-columns: 9; } - .ly-cols-10 { --ly-grid-columns: 10; } - .ly-cols-11 { --ly-grid-columns: 11; } .ly-cols-12 { --ly-grid-columns: 12; } - .ly-cols-16 { --ly-grid-columns: 16; } .ly-span-1 { grid-column: span 1; } .ly-span-2 { grid-column: span 2; } .ly-span-3 { grid-column: span 3; } .ly-span-4 { grid-column: span 4; } - .ly-span-5 { grid-column: span 5; } - .ly-span-6 { grid-column: span 6; } - .ly-span-7 { grid-column: span 7; } - .ly-span-8 { grid-column: span 8; } - .ly-span-9 { grid-column: span 9; } - .ly-span-10 { grid-column: span 10; } - .ly-span-11 { grid-column: span 11; } - .ly-span-12 { grid-column: span 12; } - .ly-span-13 { grid-column: span 13; } - .ly-span-14 { grid-column: span 14; } - .ly-span-15 { grid-column: span 15; } - .ly-span-16 { grid-column: span 16; } .ly-span-full { grid-column: 1 / -1; } - .ly-gap-0 { --ly-gap: var(--ly-space-0); --ly-grid-gap: var(--ly-space-0); --ly-stack-gap: var(--ly-space-0); --ly-cluster-gap: var(--ly-space-0); } - .ly-gap-1 { --ly-gap: var(--ly-space-1); --ly-grid-gap: var(--ly-space-1); --ly-stack-gap: var(--ly-space-1); --ly-cluster-gap: var(--ly-space-1); } - .ly-gap-2 { --ly-gap: var(--ly-space-2); --ly-grid-gap: var(--ly-space-2); --ly-stack-gap: var(--ly-space-2); --ly-cluster-gap: var(--ly-space-2); } - .ly-gap-3 { --ly-gap: var(--ly-space-3); --ly-grid-gap: var(--ly-space-3); --ly-stack-gap: var(--ly-space-3); --ly-cluster-gap: var(--ly-space-3); } - .ly-gap-4 { --ly-gap: var(--ly-space-4); --ly-grid-gap: var(--ly-space-4); --ly-stack-gap: var(--ly-space-4); --ly-cluster-gap: var(--ly-space-4); } - .ly-gap-5 { --ly-gap: var(--ly-space-5); --ly-grid-gap: var(--ly-space-5); --ly-stack-gap: var(--ly-space-5); --ly-cluster-gap: var(--ly-space-5); } - .ly-gap-6 { --ly-gap: var(--ly-space-6); --ly-grid-gap: var(--ly-space-6); --ly-stack-gap: var(--ly-space-6); --ly-cluster-gap: var(--ly-space-6); } - .ly-gap-7 { --ly-gap: var(--ly-space-7); --ly-grid-gap: var(--ly-space-7); --ly-stack-gap: var(--ly-space-7); --ly-cluster-gap: var(--ly-space-7); } - .ly-gap-8 { --ly-gap: var(--ly-space-8); --ly-grid-gap: var(--ly-space-8); --ly-stack-gap: var(--ly-space-8); --ly-cluster-gap: var(--ly-space-8); } - .ly-gap-9 { --ly-gap: var(--ly-space-9); --ly-grid-gap: var(--ly-space-9); --ly-stack-gap: var(--ly-space-9); --ly-cluster-gap: var(--ly-space-9); } + .ly-gap-0 { --ly-gap: var(--ly-space-0); --ly-grid-gap: var(--ly-space-0); } + .ly-gap-2 { --ly-gap: var(--ly-space-2); --ly-grid-gap: var(--ly-space-2); } + .ly-gap-4 { --ly-gap: var(--ly-space-4); --ly-grid-gap: var(--ly-space-4); } + .ly-gap-6 { --ly-gap: var(--ly-space-6); --ly-grid-gap: var(--ly-space-6); } + .ly-gap-8 { --ly-gap: var(--ly-space-8); --ly-grid-gap: var(--ly-space-8); } .ly-pad-0 { padding: var(--ly-space-0); } - .ly-pad-1 { padding: var(--ly-space-1); } .ly-pad-2 { padding: var(--ly-space-2); } - .ly-pad-3 { padding: var(--ly-space-3); } .ly-pad-4 { padding: var(--ly-space-4); } - .ly-pad-5 { padding: var(--ly-space-5); } .ly-pad-6 { padding: var(--ly-space-6); } - .ly-pad-7 { padding: var(--ly-space-7); } .ly-pad-8 { padding: var(--ly-space-8); } - .ly-pad-9 { padding: var(--ly-space-9); } - - .ly-px-4 { padding-inline: var(--ly-space-4); } - .ly-px-6 { padding-inline: var(--ly-space-6); } - .ly-px-8 { padding-inline: var(--ly-space-8); } - .ly-py-4 { padding-block: var(--ly-space-4); } - .ly-py-6 { padding-block: var(--ly-space-6); } - .ly-py-8 { padding-block: var(--ly-space-8); } .ly-mx-auto { margin-inline: auto; } .ly-w-full { inline-size: 100%; } .ly-h-full { block-size: 100%; } - .ly-min-h-screen { min-block-size: 100svh; } - .ly-bleed { inline-size: 100vw; margin-inline: calc(50% - 50vw); } + .ly-min-h-screen { min-block-size: 100vh; min-block-size: 100dvh; } .ly-overflow-auto { overflow: auto; } .ly-overflow-hidden { overflow: hidden; } @@ -80,16 +45,12 @@ .ly-justify-between { justify-content: space-between; } .ly-frame-1x1 { --ly-frame-ratio: 1 / 1; } - .ly-frame-2x1 { --ly-frame-ratio: 2 / 1; } .ly-frame-3x2 { --ly-frame-ratio: 3 / 2; } .ly-frame-4x3 { --ly-frame-ratio: 4 / 3; } .ly-frame-16x9 { --ly-frame-ratio: 16 / 9; } .ly-frame-21x9 { --ly-frame-ratio: 21 / 9; } - .ly-hidden { display: none !important; } - - .ly-show-md-up, - .ly-show-lg-up { + .ly-hidden { display: none !important; } @@ -104,59 +65,4 @@ clip-path: inset(50%) !important; white-space: nowrap !important; } - - /* Explicit escape hatches require consumers to verify focus and reading order. */ - .ly-order-first { order: -1; } - .ly-order-normal { order: 0; } - .ly-order-last { order: 999; } - .ly-order-1 { order: 1; } - .ly-order-2 { order: 2; } - .ly-order-3 { order: 3; } - .ly-order-4 { order: 4; } - .ly-order-5 { order: 5; } - .ly-order-6 { order: 6; } - - @container (min-width: 48rem) { - .ly-md-cols-1 { --ly-grid-columns: 1; } - .ly-md-cols-2 { --ly-grid-columns: 2; } - .ly-md-cols-3 { --ly-grid-columns: 3; } - .ly-md-cols-4 { --ly-grid-columns: 4; } - .ly-md-cols-6 { --ly-grid-columns: 6; } - .ly-md-cols-8 { --ly-grid-columns: 8; } - .ly-md-cols-12 { --ly-grid-columns: 12; } - .ly-md-cols-16 { --ly-grid-columns: 16; } - .ly-show-md-up { display: revert !important; } - - .ly-md-order-first { order: -1; } - .ly-md-order-normal { order: 0; } - .ly-md-order-last { order: 999; } - .ly-md-order-1 { order: 1; } - .ly-md-order-2 { order: 2; } - .ly-md-order-3 { order: 3; } - .ly-md-order-4 { order: 4; } - .ly-md-order-5 { order: 5; } - .ly-md-order-6 { order: 6; } - } - - @container (min-width: 64rem) { - .ly-lg-cols-1 { --ly-grid-columns: 1; } - .ly-lg-cols-2 { --ly-grid-columns: 2; } - .ly-lg-cols-3 { --ly-grid-columns: 3; } - .ly-lg-cols-4 { --ly-grid-columns: 4; } - .ly-lg-cols-6 { --ly-grid-columns: 6; } - .ly-lg-cols-8 { --ly-grid-columns: 8; } - .ly-lg-cols-12 { --ly-grid-columns: 12; } - .ly-lg-cols-16 { --ly-grid-columns: 16; } - .ly-show-lg-up { display: revert !important; } - - .ly-lg-order-first { order: -1; } - .ly-lg-order-normal { order: 0; } - .ly-lg-order-last { order: 999; } - .ly-lg-order-1 { order: 1; } - .ly-lg-order-2 { order: 2; } - .ly-lg-order-3 { order: 3; } - .ly-lg-order-4 { order: 4; } - .ly-lg-order-5 { order: 5; } - .ly-lg-order-6 { order: 6; } - } } diff --git a/styles/wrappers.css b/styles/wrappers.css index 3a4947f..a554e09 100644 --- a/styles/wrappers.css +++ b/styles/wrappers.css @@ -1,127 +1,39 @@ -@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy; +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities; -/* - Shared structural tokens and wrapper geometry. Theme, type, borders, shadows, - and interactive states remain outside Layout Style's ownership boundary. -*/ - -@layer ly.tokens { - :where(.ly-root) { - --ly-space-0: 0; - --ly-space-1: 0.25rem; - --ly-space-2: 0.5rem; - --ly-space-3: 0.75rem; - --ly-space-4: 1rem; - --ly-space-5: 1.5rem; - --ly-space-6: 2rem; - --ly-space-7: 3rem; - --ly-space-8: 4rem; - --ly-space-9: 6rem; - - --ly-wrapper-compact: 40rem; - --ly-wrapper-prose: 68ch; - --ly-wrapper-content: 72rem; - --ly-wrapper-wide: 112rem; - --ly-wrapper-max: var(--ly-wrapper-content); - --ly-page-padding-inline: clamp(1rem, 4vw, 3rem); - --ly-safe-area-inline: max( - env(safe-area-inset-left, 0px), - env(safe-area-inset-right, 0px) - ); - --ly-wrapper-gutter: max(var(--ly-page-padding-inline), var(--ly-safe-area-inline)); - - --ly-section-padding-block: clamp(3rem, 7vw, 6rem); - --ly-gap: var(--ly-space-5); - --ly-grid-gap: var(--ly-gap); - --ly-stack-gap: var(--ly-space-4); - --ly-cluster-gap: var(--ly-space-3); - --ly-cover-min: 100svh; - --ly-switcher-threshold: 42rem; - --ly-sidebar-size: 18rem; - --ly-sidebar-content-min: 50%; - --ly-grid-columns: 12; - --ly-grid-min: 16rem; - --ly-pane-size: 22rem; - --ly-media-size: 14rem; - --ly-reel-item-min: 16rem; - --ly-reel-item-max: 28rem; - --ly-scroll-max: 70svh; - --ly-frame-ratio: 16 / 9; - - --ly-recipe-rail: 18rem; - --ly-recipe-aside: 22rem; - --ly-card-grid-min: 16rem; - --ly-gallery-min: 12rem; - --ly-card-size-sm: 10rem; - --ly-card-size-md: 14rem; - --ly-card-size-lg: 18rem; - --ly-header-height: 4.5rem; - --ly-z-header: 20; - - /* V1 token aliases remain available so legacy selectors can preserve sizing. */ - --ly-container-sm: var(--ly-wrapper-compact); - --ly-container-md: 56rem; - --ly-container-lg: var(--ly-wrapper-content); - --ly-container-xl: 88rem; - --ly-container-wide: var(--ly-wrapper-wide); - --ly-container-max: var(--ly-container-lg); - --ly-content-readable: var(--ly-wrapper-prose); - --ly-carousel-item-min: var(--ly-reel-item-min); - --ly-carousel-item-max: var(--ly-reel-item-max); - --ly-sidebar-min: 14rem; - --ly-sidebar-width: var(--ly-recipe-rail); - --ly-sidebar-max: var(--ly-recipe-aside); - --ly-pane-fixed: var(--ly-pane-size); - --ly-z-sidebar: 10; - } -} - -@layer ly.reset { - :where(.ly-root), - :where(.ly-root *) { - box-sizing: border-box; - } - - :where(.ly-root) { - min-inline-size: 0; - margin: 0; - } - - :where(.ly-root img), - :where(.ly-root svg), - :where(.ly-root video), - :where(.ly-root canvas) { - max-inline-size: 100%; - } -} +/* Wrappers provide fluid measures and become the nearest responsive scope. */ @layer ly.wrappers { .ly-wrapper { - /* Personalities provide only the plain-wrapper default; explicit variants stay authoritative. */ --ly-wrapper-max: var(--ly-personality-wrapper-max, var(--ly-wrapper-content)); + --ly-wrapper-fluid-gutter: clamp(1rem, 3vw, 3rem); + --ly-wrapper-fluid-gutter: clamp(1rem, 3cqi, 3rem); + --ly-wrapper-local-gutter: max( + var(--ly-wrapper-fluid-gutter), + var(--ly-safe-area-inline) + ); - /* Symmetric safe-area compensation keeps logical gutters stable in either direction. */ - container-name: ly-wrapper; + container-name: ly-scope; container-type: inline-size; - inline-size: min(100%, calc(var(--ly-wrapper-max) + (var(--ly-wrapper-gutter) * 2))); + inline-size: min(100%, calc(var(--ly-wrapper-max) + (var(--ly-wrapper-local-gutter) * 2))); + max-inline-size: 100%; margin-inline: auto; - padding-inline: var(--ly-wrapper-gutter); + padding-inline: var(--ly-wrapper-local-gutter); } .ly-wrapper--compact { - --ly-wrapper-max: 40rem; + --ly-wrapper-max: var(--ly-wrapper-compact); } .ly-wrapper--prose { - --ly-wrapper-max: 68ch; + --ly-wrapper-max: var(--ly-wrapper-prose); } .ly-wrapper--content { - --ly-wrapper-max: 72rem; + --ly-wrapper-max: var(--ly-wrapper-content); } .ly-wrapper--wide { - --ly-wrapper-max: 112rem; + --ly-wrapper-max: var(--ly-wrapper-wide); } .ly-wrapper--full { @@ -129,18 +41,19 @@ } .ly-wrapper--breakout { + --ly-wrapper-max: 100%; --ly-breakout-content-size: min( var(--ly-wrapper-content), - calc(100% - (var(--ly-wrapper-gutter) * 2)) + calc(100% - (var(--ly-wrapper-local-gutter) * 2)) ); --ly-breakout-feature-size: min( var(--ly-wrapper-wide), - calc(100% - (var(--ly-wrapper-gutter) * 2)) + calc(100% - (var(--ly-wrapper-local-gutter) * 2)) ); display: grid; grid-template-columns: - [full-start] minmax(min(100%, var(--ly-wrapper-gutter)), 1fr) + [full-start] minmax(min(100%, var(--ly-wrapper-local-gutter)), 1fr) [feature-start] minmax( 0, calc((var(--ly-breakout-feature-size) - var(--ly-breakout-content-size)) / 2) @@ -150,7 +63,7 @@ 0, calc((var(--ly-breakout-feature-size) - var(--ly-breakout-content-size)) / 2) ) - [feature-end] minmax(min(100%, var(--ly-wrapper-gutter)), 1fr) [full-end]; + [feature-end] minmax(min(100%, var(--ly-wrapper-local-gutter)), 1fr) [full-end]; inline-size: 100%; padding-inline: 0; } @@ -158,6 +71,7 @@ .ly-wrapper--breakout > * { grid-column: content; min-inline-size: 0; + max-inline-size: 100%; } .ly-wrapper--breakout > :where(.ly-lane--content, [data-ly-lane="content"]) { diff --git a/test/layout-css-contract.test.mjs b/test/layout-css-contract.test.mjs index c46a389..29846fc 100644 --- a/test/layout-css-contract.test.mjs +++ b/test/layout-css-contract.test.mjs @@ -1,19 +1,23 @@ +import assert from "node:assert/strict"; import { existsSync, readFileSync } from "node:fs"; -import { dirname, join } from "node:path"; -import { spawnSync } from "node:child_process"; +import { join } from "node:path"; import { fileURLToPath } from "node:url"; -import assert from "node:assert/strict"; const root = fileURLToPath(new URL("..", import.meta.url)); -const dist = join(root, "dist"); const styles = join(root, "styles"); -const npmPublishWorkflowPath = join(root, ".github", "workflows", "npm-publish.yml"); -const v1BaseApiSnapshot = JSON.parse( - readFileSync(join(root, "test", "fixtures", "v1-base-public-api.json"), "utf8") -); +const dist = join(root, "dist"); +const packageJson = JSON.parse(readFileSync(join(root, "package.json"), "utf8")); -const cascadeLayerPrelude = - "@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.integrations, ly.legacy;"; +const layerPrelude = + "@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities;"; +const focusedFiles = [ + "foundation.css", + "wrappers.css", + "primitives.css", + "recipes.css", + "utilities.css", + "personalities.css" +]; const personalityNames = [ "minimal-saas", "bento", @@ -32,1680 +36,282 @@ const personalityNames = [ "mondrian", "synthwave" ]; -const focusedEntryFiles = [ - "core.css", - "wrappers.css", - "primitives.css", - "recipes.css", - "utilities.css", - "personalities.css", - ...personalityNames.map((name) => `personalities/${name}.css`), - "integrations/ui-style-kit.css", - "legacy.css" -]; -const requiredFiles = [ - ...focusedEntryFiles, - "layout-style-css.css", - "layout-style-css.min.css" +const recipeNames = [ + "app-shell", + "dashboard", + "docs", + "list-detail", + "split-hero", + "gallery", + "card-grid" ]; -const requiredSourceFiles = [...focusedEntryFiles]; -const obsoleteDistFiles = [ - "layout-base.css", - "layout-ui-style-kit-bridge.css", - "layout-style-minimal-saas.css", - "layout-style-bento.css", - "layout-style-maximalist.css", - "layout-style-bauhaus.css", - "layout-style-tactile.css", - "layout-style-neumorphism.css", - "layout-style-retrofuturism.css", - "layout-style-brutalism.css", - "layout-style-cyberpunk.css", - "layout-style-y2k.css", - "layout-style-retro-glass.css", - "layout-style-f-pattern.css", - "layout-style-z-pattern.css", - "layout-style-split-screen.css", - "layout-style-mondrian.css", - "layout-style-synthwave.css", - "layout-all.css", - "layout-all-with-ui-kit.css", - "layout-all-with-ui-kit-and-interactive-surface.css" +const recipeAreas = [ + "header", + "nav", + "sidebar", + "main", + "aside", + "footer", + "content", + "media", + "actions", + "primary", + "secondary" ]; -const expectedV2Exports = { +const expectedExports = { ".": "./dist/layout-style-css.css", - "./css": "./dist/layout-style-css.css", - "./css.css": "./dist/layout-style-css.css", - "./min": "./dist/layout-style-css.min.css", "./min.css": "./dist/layout-style-css.min.css", "./core.css": "./dist/core.css", + "./foundation.css": "./dist/foundation.css", "./wrappers.css": "./dist/wrappers.css", "./primitives.css": "./dist/primitives.css", "./recipes.css": "./dist/recipes.css", "./utilities.css": "./dist/utilities.css", "./personalities.css": "./dist/personalities.css", "./personalities/*.css": "./dist/personalities/*.css", - "./integrations/ui-style-kit.css": "./dist/integrations/ui-style-kit.css", - "./legacy.css": "./dist/legacy.css", "./package.json": "./package.json" }; - -const requiredDemoAssets = [ - "demo/index.html", - "demo/demo.css", - "demo/demo.js", - "demo/assets/favicon.svg", - "demo/assets/apple-touch-icon.svg", - "demo/assets/social-card.png", - "demo/browserconfig.xml", - "demo/robots.txt", - "demo/sitemap.xml", - "demo/site.webmanifest" -]; - -const requiredDocumentationFiles = [ - "CHANGELOG.md", - "CONTRIBUTING.md", - "SECURITY.md", - "docs/wiki/Home.md", - "docs/wiki/_Sidebar.md", - "docs/wiki/Getting-Started.md", - "docs/wiki/Installation-And-CDN.md", - "docs/wiki/Layout-Primitives.md", - "docs/wiki/Layout-Recipes.md", - "docs/wiki/Layout-Styles.md", - "docs/wiki/Migrating-To-2.0.md", - "docs/wiki/UI-Style-Kit-Compatibility.md", - "docs/wiki/Demo-And-GitHub-Pages.md", - "docs/wiki/Release-And-Publishing.md", - "docs/wiki/Security-And-Support.md", - "docs/wiki/Contributing.md" -]; - -const requiredDataUiSelectors = [ - '[data-ui="minimal-saas"]', - '[data-ui="bento"]', - '[data-ui="maximalist"]', - '[data-ui="bauhaus"]', - '[data-ui="tactile"]', - '[data-ui="neumorphism"]', - '[data-ui="retrofuturism"]', - '[data-ui="brutalism"]', - '[data-ui="cyberpunk"]', - '[data-ui="y2k"]', - '[data-ui="retro-glass"]' +const expectedPublishedFiles = [ + "dist/layout-style-css.css", + "dist/layout-style-css.min.css", + "dist/core.css", + "dist/foundation.css", + "dist/wrappers.css", + "dist/primitives.css", + "dist/recipes.css", + "dist/utilities.css", + "dist/personalities.css", + "dist/personalities/*.css" ]; -const uiStylePrefixes = [ - "saas", - "bento", - "max", - "bau", - "tactile", - "neo", - "retro", - "brutal", - "cyber", - "y2k", - "rg" -]; - -const requiredUiStructuralAliasSuffixes = [ - "container", - "section", - "stack", - "cluster", - "grid", - "split" -]; - -const requiredUiRecipeAliasSuffixes = [ - "button-group", - "card-grid", - "card-sm", - "card-md", - "card-lg", - "gallery", - "carousel" -]; - -const personalityContracts = { - "minimal-saas": { - family: "left-rail", - measure: "88rem", - threshold: "48rem", - areas: '"sidebar header header" "sidebar main aside" "sidebar footer footer"', - rhythm: ".ly-grid > :nth-child(4n + 1)" - }, - bauhaus: { - family: "left-rail", - measure: "96rem", - threshold: "52rem", - areas: '"sidebar header header aside" "sidebar main main aside" "sidebar footer footer footer"', - rhythm: ".ly-grid > :nth-child(3n + 1)" - }, - tactile: { - family: "left-rail", - measure: "82rem", - threshold: "48rem", - areas: '"sidebar header" "sidebar main" "sidebar aside" "sidebar footer"', - rhythm: ".ly-grid > :nth-child(5n + 2)" - }, - cyberpunk: { - family: "left-rail", - measure: "112rem", - threshold: "44rem", - areas: '"sidebar header aside" "sidebar main aside" "sidebar footer aside"', - rhythm: ".ly-grid > :nth-child(4n + 2)" - }, - "f-pattern": { - family: "left-rail", - measure: "92rem", - threshold: "56rem", - areas: '"sidebar header header" "sidebar main aside" "sidebar footer aside"', - rhythm: ".ly-grid > :nth-child(3n + 1)" - }, - brutalism: { - family: "right-rail", - measure: "100rem", - threshold: "48rem", - areas: '"header header sidebar" "main aside sidebar" "footer footer sidebar"', - rhythm: ".ly-grid > :nth-child(3n)" - }, - neumorphism: { - family: "right-rail", - measure: "84rem", - threshold: "52rem", - areas: '"header sidebar" "main sidebar" "aside sidebar" "footer sidebar"', - rhythm: ".ly-grid > :nth-child(4n + 1)" - }, - y2k: { - family: "right-rail", - measure: "90rem", - threshold: "48rem", - areas: '"header header sidebar" "aside main sidebar" "footer footer sidebar"', - rhythm: ".ly-grid > :nth-child(5n + 1)" - }, - "retro-glass": { - family: "right-rail", - measure: "104rem", - threshold: "56rem", - areas: '"header header sidebar" "main main sidebar" "aside footer footer"', - rhythm: ".ly-grid > :nth-child(4n)" - }, - "z-pattern": { - family: "right-rail", - measure: "108rem", - threshold: "60rem", - areas: '"header header sidebar" "main aside sidebar" "footer aside sidebar"', - rhythm: ".ly-grid > :nth-child(4n + 2)" - }, - retrofuturism: { - family: "three-zone", - measure: "106rem", - threshold: "48rem", - areas: '"sidebar header aside" "sidebar main aside" "sidebar footer aside"', - rhythm: ".ly-grid > :nth-child(6n + 1)" - }, - mondrian: { - family: "three-zone", - measure: "112rem", - threshold: "52rem", - areas: '"sidebar header header" "sidebar main aside" "footer footer aside"', - rhythm: ".ly-grid > :nth-child(5n + 1)" - }, - synthwave: { - family: "three-zone", - measure: "112rem", - threshold: "64rem", - areas: '"header header header" "sidebar main aside" "footer footer footer"', - rhythm: ".ly-grid > :nth-child(4n + 1)" - }, - bento: { - family: "mosaic", - measure: "112rem", - threshold: "48rem", - areas: '"header header header" "sidebar main main" "aside main main" "footer footer footer"', - rhythm: ".ly-grid > :nth-child(6n + 1)" - }, - maximalist: { - family: "mosaic", - measure: "100%", - threshold: "56rem", - areas: '"header header header header" "main main sidebar aside" "main main footer footer"', - rhythm: ".ly-grid > :nth-child(7n + 1)" - }, - "split-screen": { - family: "equal-split", - measure: "100%", - threshold: "48rem", - areas: '"header header" "main sidebar" "aside sidebar" "footer footer"', - rhythm: "grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);" - } -}; - -const safeTwoTrackPersonalityShellThresholds = new Map([ - ["tactile", "48rem"], - ["neumorphism", "52rem"], - ["split-screen", "48rem"] -]); - -const task2WrapperVariants = [ - [".ly-wrapper--compact", "--ly-wrapper-max: 40rem;"], - [".ly-wrapper--prose", "--ly-wrapper-max: 68ch;"], - [".ly-wrapper--content", "--ly-wrapper-max: 72rem;"], - [".ly-wrapper--wide", "--ly-wrapper-max: 112rem;"], - [".ly-wrapper--full", "--ly-wrapper-max: 100%;"], - [".ly-wrapper--breakout", "display: grid;"] -]; - -const task2CompositionPrimitives = [ - ".ly-stack", - ".ly-cluster", - ".ly-center", - ".ly-cover", - ".ly-switcher", - ".ly-sidebar", - ".ly-grid", - ".ly-split", - ".ly-panes", - ".ly-media", - ".ly-reel", - ".ly-frame", - ".ly-scroll" -]; - -const task2RecipeRoots = [ - ".ly-app-shell", - ".ly-dashboard", - ".ly-docs", - ".ly-list-detail", - ".ly-split-hero", - ".ly-gallery", - ".ly-card-grid" -]; - -const recipeRootContracts = [ - ["app-shell", ".ly-app-shell"], - ["dashboard", ".ly-dashboard"], - ["docs", ".ly-docs"], - ["list-detail", ".ly-list-detail"], - ["split-hero", ".ly-split-hero"], - ["gallery", ".ly-gallery"], - ["card-grid", ".ly-card-grid"] -]; - -const task2AreaNames = [ - "header", - "nav", - "main", - "aside", - "footer", - "content", - "media", - "actions", - "primary", - "secondary" -]; - -const visualPropertiesOwnedByUiKit = new Set([ - "background", - "background-color", - "background-image", - "border", - "border-block", - "border-block-end", - "border-block-start", - "border-bottom", - "border-color", - "border-inline", - "border-inline-end", - "border-inline-start", - "border-left", - "border-right", - "border-style", - "border-top", - "border-width", - "box-shadow", - "color", - "filter", - "font", - "font-family", - "font-size", - "font-style", - "font-weight", - "line-height", - "opacity", - "text-shadow" -]); - -const visualLayoutTokensOwnedByUiKit = /--ly-(?:color|font|shadow|surface-border)\b/; - -function findOwnedVisualDeclarations(css) { - const matches = []; - const declaration = /(?:^|[;{}\n\r])\s*([a-z-]+)\s*:/g; - let match = declaration.exec(css); - - while (match) { - if (visualPropertiesOwnedByUiKit.has(match[1])) { - matches.push(match[1]); - } - - match = declaration.exec(css); - } - - return matches; +function read(path) { + return readFileSync(path, "utf8").replace(/\r\n/g, "\n"); } -function findUnguardedGridTrackFloors(css, file) { - const matches = []; - const declaration = /grid-template-columns:\s*([^;]+);/g; - let match = declaration.exec(css); - - while (match) { - const value = match[1].trim(); - const unguardedFloor = /minmax\((?!\s*(?:0\s*,|min\(\s*100%))/; - - if (unguardedFloor.test(value)) { - matches.push(`${file}: ${value}`); - } - - match = declaration.exec(css); - } - - return matches; +function readStyle(file) { + return read(join(styles, file)); } -function normalizeCssWhitespace(css) { - return css.replace(/\s+/g, " ").trim(); +function declarationProperties(css) { + return [...css.matchAll(/(?:^|[;{])\s*([a-z-]+)\s*:/gim)].map((match) => match[1]); } -function extractContainerBodies(css, condition) { - const bodies = []; - const marker = `@container ${condition}`; - let searchIndex = 0; - - while (searchIndex < css.length) { - const atRuleStart = css.indexOf(marker, searchIndex); - - if (atRuleStart === -1) { - break; - } - - const bodyStart = css.indexOf("{", atRuleStart + marker.length); - assert.notEqual(bodyStart, -1, `Incomplete container query ${marker}`); - - let depth = 1; - let bodyEnd = bodyStart + 1; - - while (bodyEnd < css.length && depth > 0) { - if (css[bodyEnd] === "{") { - depth += 1; - } else if (css[bodyEnd] === "}") { - depth -= 1; - } - - bodyEnd += 1; - } - - assert.equal(depth, 0, `Unbalanced container query ${marker}`); - bodies.push(css.slice(bodyStart + 1, bodyEnd - 1)); - searchIndex = bodyEnd; - } - - return bodies; -} - -function extractStyleRuleSelectors(css) { - const selectors = []; - let buffer = ""; - const withoutComments = css.replace(/\/\*[\s\S]*?\*\//g, ""); - - for (const character of withoutComments) { - if (character === "{") { - const prelude = buffer.trim(); - const isAtRule = prelude.startsWith("@"); - - if (prelude && !isAtRule) { - selectors.push(prelude); - } - - buffer = ""; - } else if (character === "}") { - buffer = ""; - } else if (character === ";") { - buffer = ""; - } else { - buffer += character; - } - } - - return selectors; -} - -function hasRectangularNamedAreas(template) { - const rows = [...template.matchAll(/"([^"]+)"/g)].map((match) => match[1].trim().split(/\s+/)); - - if (rows.length === 0 || rows.some((row) => row.length !== rows[0].length)) { - return false; - } - - const names = new Set(rows.flat().filter((name) => name !== ".")); - - for (const name of names) { - const cells = []; - - for (const [rowIndex, row] of rows.entries()) { - for (const [columnIndex, cell] of row.entries()) { - if (cell === name) { - cells.push([rowIndex, columnIndex]); - } - } - } - - const rowIndexes = cells.map(([rowIndex]) => rowIndex); - const columnIndexes = cells.map(([, columnIndex]) => columnIndex); - const rowStart = Math.min(...rowIndexes); - const rowEnd = Math.max(...rowIndexes); - const columnStart = Math.min(...columnIndexes); - const columnEnd = Math.max(...columnIndexes); - - for (let rowIndex = rowStart; rowIndex <= rowEnd; rowIndex += 1) { - for (let columnIndex = columnStart; columnIndex <= columnEnd; columnIndex += 1) { - if (rows[rowIndex][columnIndex] !== name) { - return false; - } - } - } - } - - return true; -} - -function hasExpectedFamilyShape(family, template) { - const rows = [...template.matchAll(/"([^"]+)"/g)].map((match) => match[1].trim().split(/\s+/)); - - if (family === "left-rail") { - return rows[0][0] === "sidebar" && rows.filter((row) => row[0] === "sidebar").length >= 2; - } - if (family === "right-rail") { - return ( - rows[0].at(-1) === "sidebar" && rows.filter((row) => row.at(-1) === "sidebar").length >= 2 - ); - } - if (family === "three-zone") { - return rows.some((row) => row[0] === "sidebar" && row.at(-1) === "aside"); - } - if (family === "mosaic") { - return ( - rows[0].every((area) => area === "header") && - rows.some((row) => row.includes("main") && new Set(row).size < row.length) - ); - } - - return ( - family === "equal-split" && - rows.some((row) => row.length === 2 && row[0] === "main" && row[1] === "sidebar") - ); -} - -function expectedPersonalityRows(template) { - const rowCount = [...template.matchAll(/"[^"]+"/g)].length; - - if (rowCount === 3) { - return "auto minmax(0, 1fr) auto"; - } - if (rowCount === 4) { - return "auto minmax(0, 1fr) auto auto"; - } - - throw new Error(`Unsupported personality row count: ${rowCount}`); -} - -function extractRuleBody(css, selector) { - const ruleStart = css.indexOf(`${selector} {`); - assert.notEqual(ruleStart, -1, `Missing rule ${selector}`); - const declarationStart = css.indexOf("{", ruleStart); - const ruleEnd = css.indexOf("}", declarationStart); - assert.notEqual(ruleEnd, -1, `Incomplete rule ${selector}`); - - return css.slice(declarationStart + 1, ruleEnd); -} - -function runNpmPackDryRun() { - const command = "npm pack --dry-run --json --ignore-scripts"; - const result = spawnSync(command, { - cwd: root, - encoding: "utf8", - shell: true - }); - - assert.equal(result.status, 0, result.stderr || result.stdout); - - const parsed = JSON.parse(result.stdout); - assert.equal(parsed.length, 1, "npm pack dry-run should describe one package"); - - return parsed[0].files.map((file) => file.path).sort(); -} - -function extractFencedBlocks(markdown, language) { - const blocks = []; - const normalizedMarkdown = markdown.replace(/\r\n/g, "\n"); - const pattern = new RegExp(`\`\`\`${language}\\n([\\s\\S]*?)\\n\`\`\``, "g"); - let match = pattern.exec(normalizedMarkdown); - - while (match) { - blocks.push(match[1]); - match = pattern.exec(normalizedMarkdown); - } - - return blocks; -} - -function extractPackageImports(markdown) { - const imports = []; - const importPattern = /import\s+["']([^"']+)["'];?/g; - - for (const block of extractFencedBlocks(markdown, "js")) { - importPattern.lastIndex = 0; - let match = importPattern.exec(block); - - while (match) { - imports.push(match[1]); - match = importPattern.exec(block); - } - } - - return imports; -} - -function extractMarkdownLinks(markdown) { - const links = []; - const linkPattern = /\[[^\]]+\]\(([^)]+)\)/g; - let match = linkPattern.exec(markdown); - - while (match) { - links.push(match[1]); - match = linkPattern.exec(markdown); - } - - return links; -} - -function isLocalMarkdownLink(link) { - return ( - !link.startsWith("http://") && - !link.startsWith("https://") && - !link.startsWith("#") && - link.endsWith(".md") - ); -} - -const packageJson = JSON.parse(readFileSync(join(root, "package.json"), "utf8")); -const packageLock = JSON.parse(readFileSync(join(root, "package-lock.json"), "utf8")); -const lockRoot = packageLock.packages[""]; -const uiKitFixtureSpec = "2.1.0"; -const uiKitFixtureTarball = - "https://registry.npmjs.org/ui-style-kit-css/-/ui-style-kit-css-2.1.0.tgz"; -const uiKitFixturePackage = JSON.parse( - readFileSync(join(root, "node_modules", "ui-style-kit-css", "package.json"), "utf8") +assert.equal(packageJson.version, "3.0.0", "The v3 branch must expose version 3.0.0"); +assert.equal(packageJson.engines?.node, ">=20", "Development must retain the Node 20 floor"); +assert.deepEqual(packageJson.exports, expectedExports, "Package exports must match the clean v3 API"); +assert.deepEqual( + packageJson.files, + expectedPublishedFiles, + "The npm tarball must contain only the public v3 CSS surface" ); -const v2ContractFailures = []; - -if (packageJson.version !== "2.1.1") { - v2ContractFailures.push(`package version is ${packageJson.version}, expected 2.1.1`); -} -if (packageJson.engines?.node !== ">=20") { - v2ContractFailures.push(`Node engine is ${packageJson.engines?.node ?? "missing"}, expected >=20`); -} -if (packageJson.dependencies !== undefined || packageJson.peerDependencies !== undefined) { - v2ContractFailures.push("runtime and peer dependencies must be absent"); -} -if (packageJson.devDependencies?.["interactive-surface-css"] !== "1.5.0") { - v2ContractFailures.push("interactive-surface-css dev fixture must be exactly 1.5.0"); -} -if (JSON.stringify(packageJson.exports) !== JSON.stringify(expectedV2Exports)) { - v2ContractFailures.push("package exports do not match the focused v2 contract"); -} -for (const file of requiredFiles) { - if (!existsSync(join(dist, file))) { - v2ContractFailures.push(`missing dist/${file}`); - } -} -for (const file of requiredSourceFiles) { - if (!existsSync(join(styles, file))) { - v2ContractFailures.push(`missing styles/${file}`); - } -} -for (const file of obsoleteDistFiles) { - if (existsSync(join(dist, file))) { - v2ContractFailures.push(`obsolete dist/${file} is still generated`); - } -} -assert.deepEqual(v2ContractFailures, [], "V2 package/build contract is incomplete"); +assert.equal(packageJson.dependencies, undefined, "Runtime dependencies are not allowed"); +assert.equal(packageJson.peerDependencies, undefined, "Peer dependencies are not allowed"); -for (const file of requiredSourceFiles) { +for (const file of focusedFiles) { const sourcePath = join(styles, file); const distPath = join(dist, file); - const sourceCss = readFileSync(sourcePath, "utf8"); - const distCss = readFileSync(distPath, "utf8"); - assert(existsSync(sourcePath), `Missing source CSS ${file}`); - if (file === "legacy.css") { - const marker = "/* @generated-personality-aliases */"; - const [beforeAliases, afterAliases] = sourceCss.split(marker); - - assert(sourceCss.includes(marker), "styles/legacy.css must own the generated alias marker"); - assert( - distCss.startsWith(beforeAliases) && distCss.endsWith(afterAliases), - "legacy.css must preserve authored source around its generated personality aliases" - ); - } else { - assert.equal(distCss, sourceCss, `${file} must be generated from styles/${file}`); - } - assert( - sourceCss.startsWith(cascadeLayerPrelude), - `${file} must begin with the shared cascade-layer prelude` - ); - assert.deepEqual( - findUnguardedGridTrackFloors(sourceCss, file), - [], - `${file} grid tracks must guard fixed floors with min(100%, ...)` - ); + assert(existsSync(sourcePath), `Missing authored v3 module: styles/${file}`); + assert(existsSync(distPath), `Missing generated v3 module: dist/${file}`); + assert(read(sourcePath).startsWith(layerPrelude), `${file} must begin with the v3 layer prelude`); + assert.equal(read(distPath), read(sourcePath), `${file} generated output drifted from authored CSS`); } -const wrappers = readFileSync(join(dist, "wrappers.css"), "utf8").replace(/\r\n/g, "\n"); -const primitives = readFileSync(join(dist, "primitives.css"), "utf8").replace(/\r\n/g, "\n"); -const recipes = readFileSync(join(dist, "recipes.css"), "utf8").replace(/\r\n/g, "\n"); -const utilities = readFileSync(join(dist, "utilities.css"), "utf8").replace(/\r\n/g, "\n"); - -assert(wrappers.includes(".ly-wrapper {"), "wrappers.css must own the semantic .ly-wrapper API"); -assert( - wrappers.includes("container-type: inline-size;") && wrappers.includes("container-name: ly-wrapper;"), - ".ly-wrapper must establish a named inline-size container" -); -assert( - wrappers.includes("inline-size:") && - wrappers.includes("margin-inline: auto;") && - wrappers.includes("padding-inline:") && - wrappers.includes("env(safe-area-inset-left, 0px)") && - wrappers.includes("env(safe-area-inset-right, 0px)"), - "All wrappers must use logical sizing with fluid, safe-area-aware inline gutters" -); -assert( - wrappers.includes( - "--ly-wrapper-max: var(--ly-personality-wrapper-max, var(--ly-wrapper-content));" - ), - "The plain wrapper must consume the inherited personality default without overriding semantic variants" -); -for (const [selector, declaration] of task2WrapperVariants) { - assert(wrappers.includes(selector), `wrappers.css missing ${selector}`); - assert(wrappers.includes(declaration), `${selector} must preserve ${declaration}`); -} -for (const lane of ["content", "feature", "full"]) { +for (const name of personalityNames) { + const file = `personalities/${name}.css`; + const css = readStyle(file); + const generatedCss = read(join(dist, file)); + const tokenDeclarations = [...css.matchAll(/--ly-[a-z0-9-]+\s*:\s*([^;]+);/g)]; + + assert(existsSync(join(dist, file)), `Missing generated personality: ${file}`); + assert(css.startsWith(layerPrelude), `${file} must begin with the v3 layer prelude`); + assert(css.includes(`[data-ly-layout="${name}"]`), `${file} must expose its canonical layout hook`); assert( - wrappers.includes(`[data-ly-lane="${lane}"]`) && wrappers.includes(`grid-column: ${lane};`), - `Breakout wrapper must expose the ${lane} lane` + tokenDeclarations.length >= 2, + `${file} must remain distinct through at least two spatial tokens` ); + assert(!/@container|@media/.test(css), `${file} must not define an independent breakpoint engine`); + assert.equal(generatedCss, css, `${file} generated output drifted from its authored profile`); } -const primitiveMobileFallback = primitives.slice(0, primitives.indexOf("@container")); -for (const selector of task2CompositionPrimitives) { - assert(primitives.includes(selector), `primitives.css missing composition primitive ${selector}`); - assert( - primitiveMobileFallback.includes(selector), - `${selector} must have a mobile-first fallback before container enhancements` - ); -} -assert( - primitives.includes("@container (min-width: 48rem)") && - primitives.includes("@container (min-width: 64rem)"), - "Composition primitives must enhance at 48rem and 64rem container thresholds" -); -assert( - primitives.includes("overflow-inline: auto;") && primitives.includes("max-block-size:"), - "Reel and bounded-scroll primitives must constrain overflow structurally" +const personalitySignatures = personalityNames.map((name) => { + const css = readStyle(`personalities/${name}.css`); + return [...css.matchAll(/(--ly-[a-z0-9-]+)\s*:\s*([^;]+);/g)] + .map(([, property, value]) => `${property}:${value.replace(/\s+/g, " ").trim()}`) + .sort() + .join("|"); +}); +assert.equal( + new Set(personalitySignatures).size, + personalityNames.length, + "Every personality must expose a unique spatial signature" ); -const recipeMobileFallback = recipes.slice(0, recipes.indexOf("@container")); -for (const selector of task2RecipeRoots) { - assert(recipes.includes(selector), `recipes.css missing recipe root ${selector}`); - assert( - recipeMobileFallback.includes(selector), - `${selector} must define its DOM-order mobile fallback before container enhancements` - ); -} -const recipeStyleRuleSelectors = extractStyleRuleSelectors(recipes); -for (const [recipe, classSelector] of recipeRootContracts) { - const dataSelector = `[data-ly-recipe="${recipe}"]`; - const selectorsUsingClass = recipeStyleRuleSelectors.filter((selector) => - selector.includes(classSelector) - ); - - assert( - recipeMobileFallback.includes(dataSelector), - `${dataSelector} must define an independent mobile-first recipe fallback` - ); - assert(selectorsUsingClass.length > 0, `${classSelector} must own at least one recipe rule`); - - for (const selector of selectorsUsingClass) { - assert( - selector.includes(dataSelector), - `${classSelector} rule must include its independent ${dataSelector} alternative: ${selector}` - ); - } -} -assert( - recipes.includes("container-type: inline-size;") && recipes.includes("container-name: ly-recipe;"), - "Recipe roots must establish named inline-size containers" -); +assert(!existsSync(join(styles, "legacy.css")), "v3 must remove the authored legacy bundle"); +assert(!existsSync(join(dist, "legacy.css")), "v3 must remove the generated legacy bundle"); assert( - recipes.includes("@container (min-width: 48rem)") && recipes.includes("@container (min-width: 64rem)"), - "Recipes must enhance at 48rem and 64rem container thresholds" + !existsSync(join(styles, "integrations", "ui-style-kit.css")), + "v3 must remove the deprecated structural integration bridge" ); -assert(recipes.includes("grid-template-areas:"), "Recipes must use named grid areas"); assert( - extractContainerBodies(recipes, "(min-width: 64rem)").some((body) => - normalizeCssWhitespace(body).includes( - normalizeCssWhitespace( - `:where(.ly-docs, [data-ly-recipe="docs"]) { - grid-template-areas: - "nav header" - "nav main" - "nav aside" - "nav footer";` - ) - ) - ), - "Docs must use its distinct two-column navigation-and-content shell at 64rem" + !existsSync(join(dist, "integrations", "ui-style-kit.css")), + "v3 must not generate the deprecated structural integration bridge" ); -assert( - !/(?:^|[;{}\n\r])\s*order\s*:/.test(recipes), - "Built-in recipes must preserve DOM order and never declare CSS order" -); -for (const area of task2AreaNames) { - assert( - recipes.includes(`.ly-area--${area}`) && recipes.includes(`[data-ly-area="${area}"]`), - `recipes.css missing class and data hooks for the ${area} area` - ); -} -for (const hook of ["header", "sidebar", "main"]) { - assert( - recipes.includes(`.ly-app-${hook}`) && recipes.includes(`grid-area: ${hook};`), - `App shell must preserve its semantic .ly-app-${hook} area hook` - ); -} - -for (const prefix of ["", "md-", "lg-"]) { - for (const value of ["first", "normal", "last", "1", "2", "3", "4", "5", "6"]) { - assert( - utilities.includes(`.ly-${prefix}order-${value}`), - `utilities.css missing explicit escape hatch .ly-${prefix}order-${value}` - ); - } -} -assert( - utilities.includes("@container (min-width: 48rem)") && - utilities.includes("@container (min-width: 64rem)"), - "Responsive order utilities must follow container size rather than the viewport" -); - -for (const [file, css] of [ - ["wrappers.css", wrappers], - ["primitives.css", primitives], - ["recipes.css", recipes], - ["utilities.css", utilities] -]) { - assert.deepEqual( - findOwnedVisualDeclarations(css), - [], - `${file} must keep the v2 core structural-only` - ); -} - -for (const asset of requiredDemoAssets) { - assert(existsSync(join(root, asset)), `Missing demo asset ${asset}`); -} - -for (const file of requiredDocumentationFiles) { - assert(existsSync(join(root, file)), `Missing professional documentation file ${file}`); -} -assert(existsSync(join(root, "demo", "index.html")), "Demo must live at demo/index.html"); +const foundation = readStyle("foundation.css"); +const wrappers = readStyle("wrappers.css"); +const primitives = readStyle("primitives.css"); +const recipes = readStyle("recipes.css"); +const utilities = readStyle("utilities.css"); +const core = readStyle("core.css"); +const aggregatePersonalities = readStyle("personalities.css"); +const authoredCss = [ + foundation, + wrappers, + primitives, + recipes, + utilities, + aggregatePersonalities, + ...personalityNames.map((name) => readStyle(`personalities/${name}.css`)) +].join("\n"); -assert.deepEqual( - findOwnedVisualDeclarations(primitives), - [], - "primitives.css must leave visual properties to ui-style-kit-css" -); -assert( - !visualLayoutTokensOwnedByUiKit.test(primitives), - "primitives.css must not define visual layout tokens" -); assert( - primitives.includes("grid-template-columns: minmax(0, 1fr);"), - "Composition primitives must define mobile-safe single-column fallbacks" + foundation.includes("container-name: ly-scope;") && + foundation.includes("container-type: inline-size;"), + ".ly-root must establish the zero-configuration ly-scope container" ); -assert(primitives.includes(".ly-split > *"), "Split children must allow shrinkage"); -assert(primitives.includes(".ly-panes > *"), "Pane children must allow shrinkage"); assert( - wrappers.includes(":where(.ly-root),\n :where(.ly-root *) {\n box-sizing: border-box;"), - "Wrapper reset must keep padded wrappers inside their assigned inline size" -); - -assert.deepEqual( - Object.keys(personalityContracts).sort(), - personalityNames.toSorted(), - "Personality contracts must enumerate the exact sixteen public data-ly-layout values" + foundation.includes("@media (max-height: 44rem)") && + foundation.includes("@media (max-height: 30rem)"), + "Foundation must expose short and shallow viewport tiers" ); -const personalityFamilyCounts = Object.values(personalityContracts).reduce((counts, { family }) => { - counts[family] = (counts[family] ?? 0) + 1; - return counts; -}, {}); -assert.deepEqual( - personalityFamilyCounts, - { "left-rail": 5, "right-rail": 5, "three-zone": 3, mosaic: 2, "equal-split": 1 }, - "Personality contracts must preserve the five public spatial families" -); - -for (const [name, contract] of Object.entries(personalityContracts)) { - const path = join(dist, "personalities", `${name}.css`); - const css = readFileSync(path, "utf8"); - const normalizedCss = normalizeCssWhitespace(css); - const canonicalRoot = `.ly-root[data-ly-layout="${name}"]`; - - assert( - hasRectangularNamedAreas(contract.areas), - `${name} must define valid rectangular CSS grid named areas` - ); - assert( - hasExpectedFamilyShape(contract.family, contract.areas), - `${name} must preserve the ${contract.family} family geometry` - ); - assert(css.includes(canonicalRoot), `${path} missing its canonical ${canonicalRoot} hook`); - assert(!css.includes("[data-layout="), `${path} must not ship the v1 data-layout hook`); - assert(!css.includes("[layout-style="), `${path} must not ship the v1 layout-style hook`); - assert(!css.includes(".ly-layout-"), `${path} must not ship v1 ly-layout-* classes`); - assert(!css.includes(".ly-style-"), `${path} must not ship v1 ly-style-* classes`); - assert(!css.includes("[data-ui="), `${path} must not couple layout personalities to data-ui`); - assert(!css.includes("@media"), `${path} must respond to containers instead of the viewport`); - assert( - css.includes("container-name: ly-personality;") && css.includes("container-type: inline-size;"), - `${path} must establish the personality containment scope` - ); - assert( - !css.includes("@container ly-personality"), - `${path} personality enhancements must query the nearest inline-size container` - ); - assert( - normalizedCss.includes(normalizeCssWhitespace(`@container (min-width: ${contract.threshold})`)), - `${path} must preserve its authored ${contract.threshold} enhancement rhythm` - ); - assert( - normalizedCss.includes( - normalizeCssWhitespace(`--ly-personality-wrapper-max: ${contract.measure};`) - ), - `${path} must own its inherited ${contract.measure} default wrapper measure signature` - ); - assert( - !extractStyleRuleSelectors(css).some((selector) => selector.includes(".ly-wrapper")), - `${path} must not override explicit semantic wrapper variants from a later cascade layer` - ); - for (const selector of extractStyleRuleSelectors(css)) { - for (const [recipe, classSelector] of recipeRootContracts) { - if (!selector.includes(classSelector)) { - continue; - } +assert(!foundation.includes("(orientation:"), "v3 must respond to space rather than orientation labels"); - assert( - selector.includes(`[data-ly-recipe="${recipe}"]`), - `${path} has a class-only ${recipe} personality selector: ${selector}` - ); - } - } - assert( - normalizedCss.includes(normalizeCssWhitespace(`grid-template-areas: ${contract.areas};`)), - `${path} must implement its ${contract.family} named-area signature` - ); - const shellThreshold = safeTwoTrackPersonalityShellThresholds.get(name) ?? "64rem"; - assert( - extractContainerBodies(css, `(min-width: ${shellThreshold})`).some((body) => - normalizeCssWhitespace(body).includes( - normalizeCssWhitespace(`grid-template-areas: ${contract.areas};`) - ) - ), - `${path} must activate its app-shell signature at the safe ${shellThreshold} local threshold` - ); - assert( - normalizedCss.includes( - normalizeCssWhitespace(`grid-template-rows: ${expectedPersonalityRows(contract.areas)};`) - ), - `${path} must explicitly match its named-area row count` - ); - assert( - normalizedCss.includes(normalizeCssWhitespace(contract.rhythm)), - `${path} must implement a second spatial signature through grid/span rhythm` - ); - assert.deepEqual( - findOwnedVisualDeclarations(css), - [], - `${path} must leave visual properties to ui-style-kit-css` - ); - assert( - !/(?:^|[;{}\n\r])\s*(?:animation|backdrop-filter|border-radius|cursor|outline|text-decoration|transition)\s*:/.test( - css - ), - `${path} must not own decorative or interactive presentation` - ); - assert(!visualLayoutTokensOwnedByUiKit.test(css), `${path} must not define visual tokens`); - assert(!/(?:^|[;{}\n\r])\s*order\s*:/.test(css), `${path} must preserve DOM and focus order`); - assert(!css.includes("position: fixed"), `${path} must keep shell regions in normal flow`); -} - -const bridge = readFileSync(join(dist, "integrations", "ui-style-kit.css"), "utf8"); -assert(!bridge.includes("@import"), "UI Style Kit integration must contain mappings only"); -for (const dataUi of requiredDataUiSelectors) { - assert(bridge.includes(dataUi), `Bridge missing ${dataUi}`); +for (const variant of ["compact", "prose", "content", "wide", "full", "breakout"]) { + assert(wrappers.includes(`.ly-wrapper--${variant}`), `Missing wrapper variant: ${variant}`); } -for (const prefix of uiStylePrefixes) { - for (const suffix of requiredUiStructuralAliasSuffixes) { - assert(bridge.includes(`.${prefix}-${suffix}`), `Bridge missing .${prefix}-${suffix} structural alias`); - } - - for (const suffix of requiredUiRecipeAliasSuffixes) { - assert(bridge.includes(`.${prefix}-${suffix}`), `Bridge missing .${prefix}-${suffix} recipe alias`); - } -} -assert.deepEqual( - findOwnedVisualDeclarations(bridge), - [], - "Bridge must not declare visual properties" +assert( + wrappers.includes("container-name: ly-scope;") && + wrappers.includes("container-type: inline-size;"), + "Every wrapper must establish the shared responsive scope" ); assert( - !visualLayoutTokensOwnedByUiKit.test(bridge), - "Bridge must not map ui-style-kit-css visual tokens into layout-owned visual tokens" + wrappers.includes("clamp(1rem, 3vw, 3rem)") && + wrappers.includes("clamp(1rem, 3cqi, 3rem)"), + "Wrapper gutters must provide a viewport fallback before container-relative enhancement" ); - -const core = readFileSync(join(dist, "core.css"), "utf8"); -for (const file of ["wrappers.css", "primitives.css", "recipes.css", "utilities.css"]) { - assert(core.includes(`@import url("./${file}");`), `core.css must import ${file}`); -} - -const personalities = readFileSync(join(dist, "personalities.css"), "utf8"); -for (const name of personalityNames) { - assert( - personalities.includes(`@import url("./personalities/${name}.css");`), - `personalities.css must import personalities/${name}.css` - ); -} - -const legacy = readFileSync(join(dist, "legacy.css"), "utf8"); -assert.equal((legacy.match(/@import\b/g) ?? []).length, 1, "legacy.css must use one import"); assert( - legacy.includes('@import url("./layout-style-css.css");'), - "legacy.css must import the default v2 bundle" + /\.ly-wrapper--breakout\s*\{[^}]*--ly-wrapper-max:\s*100%/s.test(wrappers), + "Breakout wrappers must use the available containing block before computing lane measures" ); -const legacyLayer = legacy.match(/@layer ly\.legacy\s*\{([\s\S]*)\}\s*$/)?.[1] ?? ""; -const legacyWrapperContracts = [ - [ - ".ly-container {", - [ - "width: min(100% - (var(--ly-page-padding-inline) * 2), var(--ly-container-max));", - "margin-inline: auto;" - ] - ], - [ - ".ly-container--sm,", - ["--ly-container-max: var(--ly-container-sm);", "--ly-wrapper-max: 40rem;"] - ], - [ - ".ly-container--md,", - ["--ly-container-max: var(--ly-container-md);", "--ly-wrapper-max: 56rem;"] - ], - [ - ".ly-container--lg,", - ["--ly-container-max: var(--ly-container-lg);", "--ly-wrapper-max: 72rem;"] - ], - [ - ".ly-container--xl,", - ["--ly-container-max: var(--ly-container-xl);", "--ly-wrapper-max: 88rem;"] - ], - [".ly-container--wide {", ["--ly-container-max: var(--ly-container-wide);"]], - [ - ".ly-container--fluid {", - ["width: 100%;", "max-width: none;", "padding-inline: var(--ly-wrapper-gutter);"] - ] -]; - -assert(legacyLayer, "legacy.css must define concrete rules inside @layer ly.legacy"); -for (const [selector, declarations] of legacyWrapperContracts) { - const ruleStart = legacyLayer.indexOf(selector); - const ruleEnd = legacyLayer.indexOf("}", ruleStart); - - assert.notEqual(ruleStart, -1, `Legacy wrapper compatibility missing ${selector}`); - assert.notEqual(ruleEnd, -1, `Legacy wrapper compatibility rule is incomplete: ${selector}`); - - const rule = legacyLayer.slice(ruleStart, ruleEnd); - for (const declaration of declarations) { - assert(rule.includes(declaration), `${selector} must preserve ${declaration}`); - } +for (const lane of ["content", "feature", "full"]) { + assert(wrappers.includes(`[data-ly-lane="${lane}"]`), `Breakout wrapper missing ${lane} lane`); } -const requiredLegacyAliases = [ - ".ly-wrapper--sm", - ".ly-wrapper--md", - ".ly-wrapper--lg", - ".ly-wrapper--xl", - ".ly-wrapper--fluid", - ".ly-wrapper--readable", - ".ly-row", - ".ly-col", - ".ly-col-1", - ".ly-col-12", - ".ly-carousel", - ".ly-sidebar-layout", - ".ly-button-group", - ".ly-card-sm", - ".ly-card-md", - ".ly-card-lg", - ".ly-panes--two", - ".ly-panes--three", - '[data-layout="minimal-saas"]', - '[layout-style="minimal-saas"]', - ".ly-layout-minimal-saas", - ".ly-style-minimal-saas" -]; - -for (const selector of requiredLegacyAliases) { - assert(legacyLayer.includes(selector), `legacy.css missing v1 alias ${selector}`); -} -for (const name of personalityNames) { - for (const selector of [ - `[data-layout="${name}"]`, - `[layout-style="${name}"]`, - `.ly-layout-${name}`, - `.ly-style-${name}` - ]) { - assert(legacyLayer.includes(selector), `legacy.css missing old root hook ${selector}`); - } +for (const primitive of [ + "stack", + "cluster", + "center", + "cover", + "switcher", + "sidebar", + "grid", + "split", + "panes", + "media", + "reel", + "frame", + "scroll" +]) { + assert(primitives.includes(`.ly-${primitive}`), `Missing composition primitive: ${primitive}`); } -const normalizedLegacy = normalizeCssWhitespace(legacyLayer); -for (const [name, contract] of Object.entries(personalityContracts)) { - const legacyRoot = `:where(.ly-root[data-layout="${name}"], .ly-root[layout-style="${name}"], .ly-root.ly-layout-${name}, .ly-root.ly-style-${name})`; +assert(primitives.includes("100dvh"), "Viewport-bound primitives must use dynamic viewport units"); +assert(!primitives.includes("@container"), "Intrinsic primitives must not depend on fixed width tiers"); +for (const recipe of recipeNames) { assert( - normalizedLegacy.includes( - normalizeCssWhitespace( - `${legacyRoot} :where(.ly-app-shell, [data-ly-recipe="app-shell"]) { grid-template-areas: ${contract.areas}; grid-template-rows: ${expectedPersonalityRows(contract.areas)};` - ) - ), - `legacy.css must give ${name} root hooks the same named-area and row-track behavior as data-ly-layout` - ); - assert( - extractRuleBody(legacyLayer, legacyRoot).includes( - `--ly-personality-wrapper-max: ${contract.measure};` - ), - `legacy.css must give ${name} root hooks the same inherited wrapper default as data-ly-layout` + recipes.includes(`[data-ly-recipe="${recipe}"]`), + `Missing canonical recipe attribute: ${recipe}` ); } -assert( - !legacy.includes("@generated-personality-aliases"), - "dist/legacy.css must replace its build-time personality alias marker" -); -for (let column = 1; column <= 12; column += 1) { - assert(legacyLayer.includes(`.ly-col-${column}`), `legacy.css missing .ly-col-${column}`); +for (const area of recipeAreas) { + assert(recipes.includes(`[data-ly-area="${area}"]`), `Missing canonical recipe area: ${area}`); } -const legacyHalfGutter = "calc(var(--ly-gutter, var(--ly-gap)) * 0.5)"; -const legacyRowRule = extractRuleBody(legacyLayer, ".ly-row"); -assert( - legacyRowRule.includes(`margin-inline: calc(var(--ly-gutter, var(--ly-gap)) * -0.5);`) && - !legacyRowRule.includes("gap:"), - "Legacy rows must compensate column padding without adding width between percentage columns" -); -assert( - extractRuleBody(legacyLayer, ".ly-col").includes(`padding-inline: ${legacyHalfGutter};`), - "Legacy flexible columns must retain half-gutter padding" -); -const legacyColumnWidths = [ - "8.333333%", - "16.666667%", - "25%", - "33.333333%", - "41.666667%", - "50%", - "58.333333%", - "66.666667%", - "75%", - "83.333333%", - "91.666667%", - "100%" -]; -for (const [index, width] of legacyColumnWidths.entries()) { - const selector = `.ly-col-${index + 1}`; - const rule = extractRuleBody(legacyLayer, selector); - assert( - rule.includes("flex: 0 0 auto;") && - rule.includes(`width: ${width};`) && - rule.includes(`padding-inline: ${legacyHalfGutter};`), - `${selector} must preserve its v1 border-box percentage and half-gutter geometry` - ); -} -assert( - legacyLayer.includes(".ly-app-sidebar { grid-area: sidebar;"), - "Legacy app-sidebar alias must preserve the v1 named sidebar area" -); -assert( - extractRuleBody(legacyLayer, ".ly-content").includes("min-inline-size: 0;"), - "Legacy compatibility must preserve the v1 content shrink-safety contract" -); -const legacyDivider = extractRuleBody(legacyLayer, ".ly-divider"); -assert( - legacyDivider.includes("min-block-size: 1px;") && - legacyDivider.includes("margin-block: var(--ly-space-5);") && - findOwnedVisualDeclarations(`.ly-divider { ${legacyDivider} }`).length === 0, - "Legacy divider compatibility must preserve structural geometry without reclaiming paint" -); assert( - !legacyLayer.includes(".ly-surface--raised"), - "Legacy compatibility must not restore the paint-owned v1 raised-surface selector" + !/\.ly-(?:app-shell|dashboard|docs|list-detail|split-hero|gallery|card-grid)\b/.test(recipes), + "v3 recipes must not expose duplicate class aliases" ); assert( - !/@import[^;]*(?:ui-style-kit-css|interactive-surface-css)/.test(legacy), - "legacy.css must not restore removed companion imports" + recipes.includes(':not([data-ly-responsive="manual"])'), + "Automatic topology rules must exclude manual recipes" ); - -for (const file of requiredFiles) { - const css = readFileSync(join(dist, file), "utf8"); - assert( - !/@import[^;]*(?:ui-style-kit-css|interactive-surface-css)/.test(css), - `${file} must not import companion packages` - ); -} - -const flattened = readFileSync(join(dist, "layout-style-css.css"), "utf8"); -const migrationGuide = readFileSync(join(root, "docs", "wiki", "Migrating-To-2.0.md"), "utf8"); -const documentedV1Removals = new Set([".ly-surface--raised"]); - -assert.equal( - v1BaseApiSnapshot.source, - "styles/layout-base.css from the final 1.x source line", - "The v1 migration audit must identify its frozen public-source baseline" -); -for (const selector of v1BaseApiSnapshot.selectors) { - if (documentedV1Removals.has(selector)) { - assert( - migrationGuide.includes(selector) && migrationGuide.includes("Removed"), - `${selector} must retain an explicit documented removal disposition` - ); - } else { - assert( - flattened.includes(selector) || legacy.includes(selector), - `${selector} from the v1 base API needs a v2 or legacy compatibility disposition` - ); - } +for (const threshold of ["42rem", "44rem", "48rem", "52rem", "72rem"]) { + assert(recipes.includes(`@container ly-scope (min-width: ${threshold})`), `Missing ${threshold} recipe tier`); } assert( - flattened.includes("layout-style-css bundle"), - "Flattened bundle must include a generated bundle header" -); -assert( - flattened.includes("Shared structural tokens and wrapper geometry") && - flattened.includes("Reusable composition primitives") && - flattened.includes("Layout style: retro-glass.") && - flattened.includes("Layout style: synthwave."), - "Flattened bundle must include core and every layout personality" -); -assert( - !flattened.includes("Compatibility bridge for ui-style-kit-css"), - "Default bundle must not include the optional UI Style Kit integration" -); -assert( - !flattened.includes("@import"), - "Flattened layout-style-css.css must not depend on CSS @import" -); -for (const oldHook of ["[data-layout=", "[layout-style=", ".ly-layout-", ".ly-style-"]) { - assert(!flattened.includes(oldHook), `Default bundle must not include the v1 personality hook ${oldHook}`); -} -assert.deepEqual( - findOwnedVisualDeclarations(flattened), - [], - "Flattened bundle must leave visual properties to ui-style-kit-css" + recipes.includes("container-name: ly-scope;") && recipes.includes("container-type: inline-size;"), + "Recipe roots must scope nested responsive compositions" ); -const minified = readFileSync(join(dist, "layout-style-css.min.css"), "utf8"); -assert(minified.length > 0, "Minified bundle must not be empty"); -assert(minified.length < flattened.length, "Minified bundle must be smaller than full bundle"); -assert(!minified.includes("\n\n"), "Minified bundle should not preserve expanded whitespace"); -assert(!minified.includes("@import"), "Minified bundle must be layout-only and flattened"); +assert(!/\bly-(?:md|lg)-/.test(utilities), "Fixed responsive utility families must be removed"); +assert(!/\bly-order-/.test(utilities), "Visual order utilities must be removed"); +assert(!utilities.includes(".ly-bleed"), "The scrollbar-unsafe viewport bleed utility must be removed"); +assert(!utilities.includes("100vw"), "Utilities must not use scrollbar-unsafe viewport widths"); +assert(!/(?:^|[;{}\n\r])\s*order\s*:/.test(authoredCss), "Layout source must never set visual order"); -assert.equal(packageJson.name, "layout-style-css"); -assert.equal(packageJson.version, "2.1.1"); -assert.equal(packageJson.license, "MIT"); -assert.equal(packageJson.private, undefined); -assert.match(packageJson.description, /dependency-free/i); -assert.equal(packageJson.homepage, "https://github.com/Foscat/layout-style-css#readme"); -assert.equal(packageJson.repository.type, "git"); -assert.equal(packageJson.repository.url, "git+https://github.com/Foscat/layout-style-css.git"); -assert.equal(packageJson.bugs.url, "https://github.com/Foscat/layout-style-css/issues"); -assert.equal(packageJson.engines.node, ">=20"); -assert.equal(packageJson.style, "dist/layout-style-css.min.css"); -assert.equal(packageJson.unpkg, "dist/layout-style-css.min.css"); -assert.equal(packageJson.jsdelivr, "dist/layout-style-css.min.css"); -assert.equal(packageJson.dependencies, undefined); -assert.equal(packageJson.peerDependencies, undefined); -assert.equal(packageJson.peerDependenciesMeta, undefined); -assert.equal(packageJson.devDependencies["ui-style-kit-css"], uiKitFixtureSpec); -assert.equal(packageJson.devDependencies["interactive-surface-css"], "1.5.0"); -assert(packageJson.devDependencies.stylelint, "Stylelint must be installed for CSS linting"); -assert(packageJson.devDependencies["@playwright/test"], "Playwright must be installed for demo smoke checks"); -assert.equal(packageLock.version, "2.1.1"); -assert.equal(lockRoot.version, "2.1.1"); -assert.equal(lockRoot.engines.node, ">=20"); -assert.equal(lockRoot.dependencies, undefined); -assert.equal(lockRoot.peerDependencies, undefined); -assert.equal(lockRoot.peerDependenciesMeta, undefined); -assert.equal(lockRoot.devDependencies["ui-style-kit-css"], uiKitFixtureSpec); -assert.equal(lockRoot.devDependencies["interactive-surface-css"], "1.5.0"); -assert.equal(uiKitFixturePackage.version, "2.1.0", "UI Style Kit fixture must be the released 2.1.0 line"); -assert.equal( - packageLock.packages["node_modules/ui-style-kit-css"].resolved, - uiKitFixtureTarball, - "Lockfile must resolve the released UI Style Kit fixture from the npm registry" -); -assert.equal( - packageLock.packages["node_modules/interactive-surface-css"].version, - "1.5.0", - "Lockfile must resolve the exact Interactive Surface fixture" -); -assert.deepEqual(packageJson.files, [ - "dist", - "styles", - "docs/wiki", - "demo/index.html", - "demo/demo.css", - "demo/demo.js", - "demo/assets/apple-touch-icon.svg", - "demo/assets/favicon.svg", - "demo/assets/social-card.png", - "demo/browserconfig.xml", - "demo/robots.txt", - "demo/site.webmanifest", - "demo/sitemap.xml", - "README.md", - "CHANGELOG.md", - "CONTRIBUTING.md", - "SECURITY.md", - "LICENSE" +const forbiddenPaintProperties = new Set([ + "animation", + "background", + "background-color", + "border", + "border-color", + "border-radius", + "box-shadow", + "color", + "font", + "font-family", + "font-size", + "font-weight", + "opacity", + "outline", + "text-decoration", + "text-shadow", + "transition" ]); -assert.equal(packageJson.scripts.build, "node scripts/build.mjs"); -assert.equal(packageJson.scripts.lint, "stylelint \"styles/**/*.css\" \"demo/**/*.css\""); -assert.equal(packageJson.scripts["check:demo-js"], "node --check demo/demo.js"); -assert.equal( - packageJson.scripts["test:demo:quick"], - "node test/demo-smoke.test.mjs --quick --browser=chromium" -); -assert.equal( - packageJson.scripts["test:static"], - "node test/layout-css-contract.test.mjs && node test/release-docs-contract.test.mjs" -); -for (const browser of ["chromium", "firefox", "webkit"]) { - assert.equal( - packageJson.scripts[`test:demo:${browser}`], - `node test/demo-smoke.test.mjs --browser=${browser}` - ); -} -assert.equal( - packageJson.scripts.test, - "npm run test:static && npm run test:demo:quick && npm run test:pages" -); -assert.equal(packageJson.scripts["pages:build"], "node scripts/build-pages.mjs"); -assert.equal( - packageJson.scripts.check, - "npm run build && npm run lint && npm run check:demo-js && npm test && npm run pack:dry-run" -); -assert.equal(packageJson.scripts["pack:dry-run"], "npm pack --dry-run --ignore-scripts"); -assert.equal( - packageJson.scripts["publish:dry-run"], - "npm publish --dry-run --access public --ignore-scripts" -); -assert.equal( - packageJson.scripts["release:verify"], - "npm run check:full && npm audit --audit-level=moderate && npm run publish:dry-run" -); -assert.equal(packageJson.scripts.prepack, "npm run build && npm run test:static"); -assert.equal(packageJson.scripts.prepublishOnly, "npm run release:verify"); -assert.equal(packageJson.publishConfig.access, "public"); -assert.deepEqual(packageJson.exports, expectedV2Exports); -for (const name of personalityNames) { - assert.equal( - packageJson.exports[`./${name}.css`], - undefined, - `Root personality alias ./${name}.css must be removed` - ); -} - -const demo = readFileSync(join(root, "demo", "index.html"), "utf8"); -const demoScript = readFileSync(join(root, "demo", "demo.js"), "utf8"); -const demoInlineCss = demo.match(/