From 73f4a6fd06762f51c2a15cfa766f6149239a7761 Mon Sep 17 00:00:00 2001 From: Foscat Date: Thu, 3 Sep 2026 09:06:55 -0500 Subject: [PATCH 01/11] docs: specify layout style 3.2 expansion --- .../2026-09-03-layout-style-css-3-2-design.md | 832 ++++++++++++++++++ 1 file changed, 832 insertions(+) create mode 100644 docs/superpowers/specs/2026-09-03-layout-style-css-3-2-design.md diff --git a/docs/superpowers/specs/2026-09-03-layout-style-css-3-2-design.md b/docs/superpowers/specs/2026-09-03-layout-style-css-3-2-design.md new file mode 100644 index 0000000..85e0b80 --- /dev/null +++ b/docs/superpowers/specs/2026-09-03-layout-style-css-3-2-design.md @@ -0,0 +1,832 @@ +# Layout Style CSS 3.2.0 Expansion Design + +## Status + +Approved architecture: additive `layout-style-css@3.2.0` release on top of v3.1.0. No v4 rewrite. + +This design consolidates the September 2026 layout-personality review against the current Layout Style CSS v3.1 engine and the published `ui-style-kit-css@2.3.0` preset inventory and the in-progress `ui-style-kit-css@2.4.0` correctness work. + +## Goal + +Expand Layout Style CSS from 16 to 20 meaningful spatial personalities, correct personalities whose current geometry conflicts with their intended design language, add the smallest shared structural capabilities repeatedly required by the reviewed real-world UI references, and fix the v3 content-resilience defects that permit unusably narrow tracks or silently clipped legitimate overflow. + +## Design Principle + +Layout Style CSS owns spatial behavior, not visual paint. + +A layout personality may control: + +- preferred measure +- gaps and density defaults +- intrinsic item minimums +- rail and aside proportions +- split ratios +- frame ratios +- recipe topology tokens +- responsive composition behavior + +It must not own: + +- color +- typography +- border appearance +- shadows +- decorative textures +- visual component states +- interaction animation + +UI Style Kit owns paint. Interactive Surface CSS owns interaction feedback. + +## Release Classification + +`3.2.0` is an additive minor release. + +The release must not: + +- remove or rename `.ly-root` or `.ly-wrapper` +- remove or rename any existing wrapper +- remove or rename any existing primitive +- remove or rename any existing recipe +- remove or rename any existing `data-ly-area` value +- remove any existing package export +- add runtime dependencies +- add framework-specific runtime behavior +- add personality-local `@container`, viewport, or orientation breakpoint systems +- reorder DOM content to produce visual layouts + +Personality geometry changes listed in this specification are intentional minor-version behavior changes and must be documented in `Migrating-To-3.2.md`. + +## Compatibility Baseline + +- Base release: `layout-style-css@3.1.0` +- Node development floor: `>=20` +- Runtime dependencies: zero +- Companion range for UI Style Kit: keep `>=2.1.0 <3.0.0` +- Companion range for Interactive Surface CSS: keep `>=1.5.0 <2.0.0` +- Development may use published `ui-style-kit-css@2.3.0` for layout-only work; final all-three-library verification targets `ui-style-kit-css@2.4.0` after the registry confirms that version is published +- Existing container thresholds remain valid: `42rem`, `44rem`, `48rem`, `52rem`, `72rem` +- Existing viewport-height thresholds remain valid: `44rem`, `30rem` + +Do not invent a new threshold solely for v3.2. New composition behavior must reuse the existing threshold vocabulary. + +--- + +# 1. Shared Engine Additions + +## 1.1 Mosaic Composition + +### Purpose + +Add a generic heterogeneous-grid composition used by Bento, Bauhaus, Brutalism, Y2K, Retro Glass, Technical Blueprint, and other dense workspaces. + +The primitive must be visually neutral and must not use dense auto-placement because visual reordering would conflict with semantic reading order. + +### Public API + +```html +
+
...
+
...
+
...
+
...
+
+``` + +Public additions: + +```text +.ly-mosaic +.ly-span-6 +.ly-row-span-2 +.ly-row-span-3 +``` + +Existing utilities remain public and unchanged in meaning outside Mosaic: + +```text +.ly-span-1 +.ly-span-2 +.ly-span-3 +.ly-span-4 +.ly-span-full +``` + +Do not add a second `data-ly-span` API. + +### Tokens + +Add: + +```css +--ly-mosaic-medium-columns: 6; +--ly-mosaic-wide-columns: 12; +``` + +Both tokens are public geometry tokens and must be runtime-consumed. + +### Automatic responsive behavior + +Mosaic uses the nearest `ly-scope` container. + +Base allocation below `42rem`: + +- one explicit column +- all column-span utilities on direct Mosaic children collapse to full width +- row-span utilities on direct Mosaic children collapse to normal row flow +- DOM order is the rendered order + +At `42rem` and above: + +- use `repeat(var(--ly-mosaic-medium-columns), minmax(0, 1fr))` +- `.ly-span-1/2/3/4/6` use their explicit column span +- `.ly-span-full` remains `1 / -1` +- `.ly-row-span-2/3` become active + +At `72rem` and above: + +- use `repeat(var(--ly-mosaic-wide-columns), minmax(0, 1fr))` +- the same span utilities remain active + +`data-ly-responsive="manual"` on `.ly-mosaic` disables the automatic 42rem/72rem column topology. Application CSS then owns the track definition. + +Additive manifest metadata: + +```json +{ + "thresholds": { + "compositions": { + "mosaic": { + "medium": "42rem", + "wide": "72rem" + } + } + } +} +``` + +The primitive is the explicit exception to the v3 rule that composition primitives are entirely intrinsic. The exception is justified because intentional spans require a known track count. No other primitive gains a breakpoint engine in 3.2. + +## 1.2 Action Bar Composition + +### Purpose + +Standardize workflow action regions repeatedly present in Maximalist, Tactile, Neumorphism, Retrofuturism, Cyberpunk, and other task interfaces. + +### Public API + +```html +
+
+ +
+
+ +
+
+``` + +Optional modifier: + +```text +.ly-action-bar--sticky +``` + +### Structural behavior + +`.ly-action-bar`: + +- uses Flexbox +- wraps intrinsically +- aligns the end action group to logical inline-end when space permits +- retains DOM order when wrapping +- uses `--ly-cluster-gap` +- applies bottom safe-area compensation +- does not style buttons + +`[data-ly-actions="start"]` and `[data-ly-actions="end"]`: + +- are wrapping action clusters +- use logical alignment +- remain shrink-safe + +`.ly-action-bar--sticky`: + +- uses the existing `--ly-sticky-position` token so short-height behavior can disable stickiness +- sticks to logical block-end +- uses existing structural z-index semantics rather than introducing decorative layering + +Do not turn Action Bar into a generic application dock. Media players, desktop launchers, and arbitrary toolbars remain normal Cluster/Grid/Reel compositions. + +## 1.3 Area-Aware App Shell + +### Problem + +The existing App Shell assumes the five canonical areas are all structurally present: + +```text +header +sidebar +main +aside +footer +``` + +When a side area is absent, an authored named-area template can still reserve a useless column. The reviewed UI references include legitimate shells with no sidebar, no aside, dual rails, global headers/footers, and personality-specific spans. + +### Contract + +Keep the existing five area names. Do not add aliases. + +When both `sidebar` and `aside` are present, the existing personality-owned medium/wide topology tokens remain authoritative. + +When one or both side regions are missing and automatic responsiveness is enabled, use shared reduced topologies that do not reserve empty side tracks. + +At medium/wide widths, support these cases: + +```text +header + sidebar + main + aside + footer +header + sidebar + main + footer +header + main + aside + footer +header + main + footer +``` + +Recommended reduced topology rules: + +### Sidebar present, aside absent + +Medium: + +```text +header header +sidebar main +footer footer +``` + +Wide: + +```text +sidebar header +sidebar main +sidebar footer +``` + +### Sidebar absent, aside present + +Medium and wide: + +```text +header header +main aside +footer footer +``` + +### Sidebar absent, aside absent + +```text +header +main +footer +``` + +Missing header/footer rows may remain zero-height named rows when absent; the required no-empty-track guarantee applies to side columns that consume usable inline space. + +Implementation should use feature-detected `:has()` presence selectors in the shared recipe engine. Browsers without `:has()` keep the existing stacked/current fallback rather than receiving broken geometry. + +`data-ly-responsive="manual"` must disable both existing topology enhancement and new area-aware enhancement. + +No personality may implement its own presence-detection selectors. + +## 1.4 Content Resilience Correctness Patch + +### Root cause + +The v3.1 layout engine is intentionally shrink-safe, but it currently has no meaningful usable-width floor for flexible recipe content. Recipe children receive `min-inline-size: 0`, primary flexible tracks commonly use `minmax(0, 1fr)`, and rendered regression coverage only rejects regions that collapse to exactly zero width. A region that is only a few pixels or roughly one character wide therefore satisfies the existing contract. + +This becomes visibly severe when paired with UI Style Kit's current shared text-containment layer, which applies `overflow-wrap: anywhere` and `min-inline-size: 0` broadly. Layout Style CSS must not depend on companion text min-content behavior to keep a primary work region usable. + +The base `.ly-scroll` primitive also currently clips inline overflow while only scrolling in the block axis. That silently hides legitimate wide content such as tables, code, diagrams, forms, and technical workspaces. + +### Public token + +Add one public geometry token: + +```css +--ly-recipe-main-min: 20rem; +``` + +The token is a guarded minimum for primary application/content tracks in automatic recipe topologies. It is not a minimum width for every arbitrary child element and must not be applied globally to all layout primitives. + +### Guarded recipe tracks + +Keep `min-inline-size: 0` on recipe children for shrink safety, but move usability protection to the track definitions. + +Automatic recipe topology must use guarded floors as follows: + +- App Shell `main`: `--ly-recipe-main-min` +- Dashboard `main`: `--ly-recipe-main-min` +- Docs `main`: `--ly-recipe-main-min` +- area-aware reduced App Shell `main`: `--ly-recipe-main-min` +- List Detail `primary` and `secondary`: existing `--ly-pane-min` +- Split Hero `content` and `media`: existing `--ly-split-min` + +The intended flexible-track form is: + +```css +minmax(min(100%, var(--ly-recipe-main-min)), 1fr) +``` + +with the equivalent existing pane/split token substituted where appropriate. Personality-owned column templates must use the same guarded main/content floor rather than introducing unguarded `minmax(0, 1fr)` application tracks. + +The existing `42rem`, `44rem`, `48rem`, `52rem`, and `72rem` topology thresholds remain unchanged. The default `20rem` floor fits within those approved threshold budgets alongside the largest approved rail/aside combinations in this specification. + +Explicit fixed-column utilities remain explicit expert controls. `.ly-grid--fixed` is not converted into an automatically reflowing grid in 3.2. Documentation must distinguish it from the guarded recipe and intrinsic-grid paths. + +### Scroll behavior + +Change base Scroll from inline clipping plus block scrolling to genuine two-axis overflow access: + +```css +.ly-scroll { + min-block-size: 0; + overflow: auto; + overscroll-behavior-block: contain; +} +``` + +`ly-scroll--bounded` and `ly-scroll--viewport` continue to control only `max-block-size`. They must not disable horizontal access. + +Intentional clipping remains limited to explicit contracts such as `.ly-frame`, `.ly-overflow-hidden`, and consumer-owned paint/media clipping. Layout Style CSS must not hide arbitrary recipe or section overflow merely to satisfy a no-document-overflow test. + +### Required rendered behavior + +Automatic multi-column recipes must prefer reflow/stacked topology over an unusably narrow primary content track. At an active automatic topology, the relevant content track must meet its public floor within a one-pixel rendering tolerance. + +The rendered test fixture must include: + +- multi-word labels +- ordinary paragraph copy +- an intentionally long unbroken token/URL +- a wide table or code/diagram surrogate inside `.ly-scroll` +- nested layout scopes +- layout-only and all-three-library ecosystem modes + +The test must prove: + +1. App Shell, Dashboard, and Docs primary content never collapse below `--ly-recipe-main-min` while their multi-column topology is active. +2. List Detail and Split Hero tracks respect their existing pane/split minimums while enhanced. +3. No regression test considers `width > 0` sufficient evidence of usability. +4. A constrained `.ly-scroll` can be programmatically scrolled both horizontally and vertically when its child is larger on both axes. +5. Required content is not clipped by Layout Style CSS. +6. Document-level horizontal overflow remains absent except where the application explicitly chooses document scrolling; designated scroll containers own their overflow instead. + +### Companion-library boundary + +The Layout Style CSS patch does not modify UI Style Kit source. Before final v3.2 ecosystem verification, the in-progress UI Style Kit 2.4.0 release must separately correct its broad `overflow-wrap: anywhere` policy and audit preset-specific `overflow: hidden` on general page/surface containers. Layout Style CSS must remain robust even when paired with older compatible UI Style Kit versions that still carry aggressive text wrapping. + +--- + +# 2. Final Personality Inventory + +The public `data-ly-layout` inventory becomes exactly 20 values: + +1. `minimal-saas` +2. `bento` +3. `maximalist` +4. `bauhaus` +5. `tactile` +6. `neumorphism` +7. `retrofuturism` +8. `brutalism` +9. `cyberpunk` +10. `y2k` +11. `retro-glass` +12. `f-pattern` +13. `z-pattern` +14. `split-screen` +15. `mondrian` +16. `synthwave` +17. `technical-blueprint` +18. `data-terminal` +19. `industrial-hmi` +20. `editorial` + +Do not add layouts named `clay`, `neo-noir`, `art-deco`, `organic-modern`, `industrial-utility`, `editorial-luxe`, or `paper-editorial`. Those UI presets are covered through pairing guidance. + +--- + +# 3. Personality Geometry Targets + +All values below are release targets. Exact rendered pixel behavior must be verified before final commit; changing a target requires updating this spec rather than silently tuning implementation. + +| Layout | Preferred wrapper | Profile gap | Grid min | Rail | Aside | Other required behavior | +| --- | --- | --- | --- | --- | --- | --- | +| Minimal SaaS | `88rem` | `--ly-space-5` (1.5rem) | `16rem` | `15rem` | `16rem` | Keep split `1.05fr / 0.95fr`; conservative shared topology | +| Bento | `112rem` | `--ly-space-4` (1rem) | `12rem` | `14rem` | `18rem` | Keep card `14rem`, gallery `11rem`; remove old four-track shell; canonical Mosaic consumer | +| Maximalist | `100%` | `--ly-space-3` (0.75rem) | `10rem` | `15rem` | `18rem` | Keep card `13rem`, gallery `10rem`; remove old four-track shell | +| Bauhaus | `96rem` | `--ly-space-2` (0.5rem) | `13rem` | `14rem` | `18rem` | Remove old four-track shell; set split bias `0.7fr / 1.3fr`; canonical Mosaic consumer | +| Tactile | `96rem` | `--ly-space-4` (1rem) | `15rem` | `17rem` | `20rem` | Preserve List Detail bias `0.5fr / 0.9fr`; remove left sidebar/aside stacking topology | +| Neumorphism | `84rem` | `--ly-space-6` (2rem) | `17rem` | `17rem` | `22rem` | Remove persistent-right-sidebar topology; preserve List Detail `1.1fr / 0.7fr` | +| Retrofuturism | `106rem` | `--ly-space-5` (1.5rem) | `14rem` | `14rem` | `17rem` | Preserve current dual-rail wide topology | +| Brutalism | `100%` | `--ly-space-1` (0.25rem) | `14rem` | `16rem` | `18rem` | Remove persistent-right-sidebar topology; canonical Mosaic consumer | +| Cyberpunk | `112rem` | `--ly-space-4` (1rem) | `12rem` | `13rem` | `19rem` | Preserve current wide topology | +| Y2K | `100%` | `--ly-space-2` (0.5rem) | `13rem` | `18rem` | `16rem` | Wide shell uses global header/footer with persistent dual rails; Mosaic consumer | +| Retro Glass | `100%` | `--ly-space-2` (0.5rem) | `15rem` | `16rem` | `17rem` | Wide shell uses global header/footer with dual-rail desktop workbench; Mosaic consumer | +| F-pattern | `92rem` | `--ly-space-4` (1rem) | `14rem` | `16rem` | `18rem` | Preserve Split Hero `1.8fr / 0.8fr` | +| Z-pattern | `108rem` | `--ly-space-5` (1.5rem) | `14rem` | `17rem` | `19rem` | Preserve Split Hero `1.5fr / 0.5fr` and current directional weighting | +| Split Screen | `100%` | `--ly-space-4` (1rem) | `20rem` | `24rem` | `24rem` | Preserve equal-half App Shell, Split Hero, and List Detail behavior | +| Mondrian | `112rem` | `--ly-space-3` (0.75rem) | `11rem` | `13rem` | `18rem` | Preserve asymmetric wide composition | +| Synthwave | `112rem` | `--ly-space-6` (2rem) | `14rem` | `16rem` | `20rem` | Preserve three-zone wide shell and `20rem` Reel item minimum | +| Technical Blueprint | `100%` | `--ly-space-1` (0.25rem) | `10rem` | `11rem` | `26rem` | Split bias `2.2fr / 0.8fr`; technical-canvas-dominant; Mosaic consumer | +| Data Terminal | `100%` | `--ly-space-1` (0.25rem) | `10rem` | `12rem` | `18rem` | Band-dense command/data composition; card/gallery mins `10rem`; no new Band primitive in 3.2 | +| Industrial HMI | `100%` | `--ly-space-2` (0.5rem) | `11rem` | `7rem` | `32rem` | Narrow persistent nav + dominant process canvas + large controls rail | +| Editorial | `108rem` | `--ly-space-6` (2rem) | `16rem` | `10rem` | `18rem` | Split bias `1.65fr / 0.75fr`; default Frame ratio `4 / 5`; publication-first composition | + +### Wide topology requirements that differ from shared defaults + +Y2K and Retro Glass must use: + +```text +header header header +sidebar main aside +footer footer footer +``` + +Retrofuturism, Cyberpunk, Split Screen, Mondrian, Synthwave, and any other existing personality not explicitly reworked retain their approved current topology unless a rendered contract proves a regression. + +Industrial HMI uses the standard persistent-left-rail wide topology with a substantially wider aside. + +Technical Blueprint, Data Terminal, Editorial, Neumorphism, Brutalism, and other references that omit a side area rely on the shared area-aware App Shell rather than inventing empty placeholder regions. + +--- + +# 4. UI Style Kit 2.3 Pairing Metadata + +## 4.1 Metadata extension + +Add one additive array to every personality pairing record: + +```json +"compatibleVisualPresets": [] +``` + +Semantics: + +- `recommendedVisualPresets`: primary verified visual pairing(s) +- `compatibleVisualPresets`: additional UI Style Kit presets whose spatial needs are already covered by this layout and therefore do not justify a duplicate layout personality + +Generated `personalities.json` and the demo fallback must preserve the new field. + +## 4.2 Pairing requirements + +| Layout | Compatibility | Recommended UI presets | Compatible UI presets | +| --- | --- | --- | --- | +| minimal-saas | native | `minimal-saas` | `organic-modern` | +| bento | native | `bento` | none | +| maximalist | native | `maximalist` | none | +| bauhaus | native | `bauhaus` | `art-deco` | +| tactile | native | `tactile` | `clay` | +| neumorphism | native | `neumorphism` | none | +| retrofuturism | native | `retrofuturism` | none | +| brutalism | native | `brutalism` | none | +| cyberpunk | native | `cyberpunk` | none | +| y2k | native | `y2k` | none | +| retro-glass | native | `retro-glass` | none | +| f-pattern | any | none | none | +| z-pattern | any | none | none | +| split-screen | any | none | none | +| mondrian | any | none | none | +| synthwave | recommended | `cyberpunk`, `retrofuturism` | none | +| technical-blueprint | native | `technical-blueprint` | none | +| data-terminal | native | `data-terminal` | `neo-noir` | +| industrial-hmi | recommended | `industrial-utility` | none | +| editorial | recommended | `editorial-luxe`, `paper-editorial` | none | + +This mapping covers every preset published by `ui-style-kit-css@2.3.0` and carried into the in-progress 2.4.0 line without creating redundant layout IDs. + +The Layout Style CSS demo must display pairing guidance but must not force the UI selector to follow the selected layout. Layout, density, UI preset, theme, and mode remain independently selectable. + +--- + +# 5. Demo Requirements + +The existing Interactive Layout Lab remains the verification surface. + +Required v3.2 updates: + +1. Version all layout assets and metadata as `3.2.0`. +2. Use published `ui-style-kit-css@2.3.0` during independent layout development; switch the final ecosystem fixture to `ui-style-kit-css@2.4.0` after registry publication is confirmed. +3. Update the packaged UI manifest fallback to the 20-preset UI Style Kit 2.3 inventory. +4. Populate all 20 layout personalities from generated layout metadata. +5. Display recommended and compatible UI pairing guidance for the selected personality. +6. Keep layout, UI, theme, mode, density, wrapper, and recipe controls independent. +7. Add visible fixture examples for Mosaic and Action Bar without making them public recipes. +8. Keep the current device presets and threshold-adjacent preview widths. +9. Add 42rem and 72rem Mosaic topology readout/verification where needed. +10. Preserve layout-only, layout-plus-UI, and all-three ecosystem modes. + +The demo must remain an engineering workbench, not the canonical visual-design document for each personality. + +--- + +# 6. Canonical Documentation + +Create `docs/wiki/Layout-Personality-Reference.md`. + +For each of the 20 personalities, document: + +- purpose +- canonical spatial model +- preferred wrapper +- default profile gap +- rail/aside behavior +- important recipe biases +- recommended/compatible UI Style Kit pairings +- wide/medium/narrow responsive intent +- whether Mosaic is a canonical composition +- whether Action Bar is commonly useful + +Document the following general reference principles: + +- Minimal SaaS: content-first, conservative whitespace +- Bento: heterogeneous modular tiles +- Maximalist: maximal content/visual density, not maximal whitespace +- Bauhaus: low-gap geometric asymmetry +- Tactile: broad task workspace with physical grouping +- Neumorphism: bounded two-region configuration/readiness composition +- Retrofuturism: dual-rail workstation +- Brutalism: near-zero-gap operational control grid +- Cyberpunk: broad operational shell with compact nav and substantial settings rail +- Y2K: dense portal with persistent dual rails +- Retro Glass: desktop workbench with global chrome and dual rails +- F-pattern: strong top-left and primary-content reading priority +- Z-pattern: deliberate diagonal attention path +- Split Screen: equal-priority dual workspaces +- Mondrian: asymmetric modular blocks +- Synthwave: neon workstation geometry independent of paint +- Technical Blueprint: engineering sheet/canvas workspace +- Data Terminal: horizontal telemetry and command bands +- Industrial HMI: supervisory process canvas with instrument rail +- Editorial: publication composition with narrow readable text and dominant media + +Update maintained docs: + +- `README.md` +- `CHANGELOG.md` +- `docs/wiki/Home.md` +- `docs/wiki/Getting-Started.md` +- `docs/wiki/Layout-Primitives.md` +- `docs/wiki/Layout-Recipes.md` +- `docs/wiki/Layout-Styles.md` +- `docs/wiki/UI-Style-Kit-Compatibility.md` +- `docs/wiki/Demo-And-GitHub-Pages.md` +- `docs/wiki/Release-And-Publishing.md` +- `docs/wiki/_Sidebar.md` +- new `docs/wiki/Migrating-To-3.2.md` + +--- + +# 7. Manifest and Generated Metadata + +Update `manifest.json` additively: + +- version `3.2.0` +- primitives include `mosaic` and `action-bar` +- personalities contain exactly 20 IDs in the approved order +- personalityPairings implement the table in Section 4 +- thresholds retain current recipe metadata and add `thresholds.compositions.mosaic` +- geometry tokens add `--ly-mosaic-medium-columns`, `--ly-mosaic-wide-columns`, and `--ly-recipe-main-min` +- companions retain their current semver ranges + +`personalities.json` remains generated from `manifest.json`. + +`scripts/build.mjs` must preserve `compatibleVisualPresets` when generating metadata and the browser fallback. + +All four new authored personality files must generate matching `dist/personalities/*.css` outputs and be included in aggregate `personalities.css` generation. + +--- + +# 8. Test Strategy + +## 8.1 Static contracts + +Extend current source/package contracts to prove: + +- version synchronization at 3.2.0 +- exactly 20 personalities +- all personality files have unique spatial signatures +- no personality defines its own breakpoint engine +- Mosaic and Action Bar are public primitives +- new Mosaic tokens are declared and runtime-consumed +- `.ly-span-6`, `.ly-row-span-2`, `.ly-row-span-3` exist +- all existing span utilities remain available +- `compatibleVisualPresets` survives manifest -> generated metadata -> demo fallback generation +- all UI Style Kit 2.3/2.4 preset IDs are covered by recommended or compatible layout metadata +- package exports remain unchanged +- package file surface gains only the new maintained documentation and generated personality modules required by 3.2 + +Update the current assertion that `primitives.css` contains no `@container`: only Mosaic may own the shared 42rem/72rem composition queries. Other primitives remain query-free. + +## 8.2 Rendered Mosaic contracts + +Test at representative nearest-container widths: + +- `32rem`: one column; all direct span children full width; row spans inactive +- `43rem`: six explicit tracks; column and row spans active +- `71rem`: six explicit tracks +- `73rem`: twelve explicit tracks + +Verify: + +- no horizontal overflow +- DOM order equals reading/focus order +- `data-ly-responsive="manual"` disables automatic Mosaic topology +- nested Mosaic uses its nearest `ly-scope` +- `.ly-span-full` stays full width at every tier + +## 8.3 Rendered Action Bar contracts + +Verify: + +- start/end groups share one row when space permits +- end group aligns to logical inline-end +- narrow width wraps without reordering DOM/focus order +- sticky modifier sticks at regular heights +- existing shallow-height token disables sticky behavior +- bottom safe-area padding is honored + +## 8.4 Area-aware App Shell contracts + +At 53rem and 73rem, render all four side-area combinations: + +1. sidebar + aside +2. sidebar only +3. aside only +4. neither + +For each: + +- no empty side column is reserved +- main remains shrink-safe +- header/footer placement matches the reduced contract +- manual responsiveness stays stacked/application-owned + +Repeat key cases using personalities with custom all-area topology: + +- Retrofuturism +- Cyberpunk +- Y2K +- Retro Glass +- Split Screen + +## 8.5 Personality rendered matrix + +Every personality receives at least one browser-computed signature test covering its defining spatial traits, not only source-token text. + +Required explicit regression checks: + +- Bento removes the old four-track shell and works as a canonical Mosaic consumer +- Maximalist gap is materially smaller than v3.1 +- Bauhaus gap is <= 0.5rem at normal density +- Tactile default wrapper resolves to 96rem +- Neumorphism no longer places a persistent sidebar on the right +- Brutalism wrapper is full width and gap <= 0.25rem +- Y2K uses dual rails with global header/footer at wide allocation +- Retro Glass uses dual rails with global header/footer at wide allocation +- Retrofuturism and Cyberpunk retain their approved current wide topologies +- Split Screen remains equal-half +- Technical Blueprint exposes a dominant primary/canvas ratio +- Data Terminal remains full-width and high-density +- Industrial HMI has a narrow rail and substantially wider aside +- Editorial uses asymmetric split geometry and 4:5 default Frame ratio + +## 8.6 Content resilience regression contracts + +Add focused static and rendered coverage for the correctness patch: + +Static contracts must prove: + +- `--ly-recipe-main-min: 20rem` is declared and runtime-consumed +- shared App Shell, Dashboard, Docs, and area-aware main tracks use the guarded recipe floor +- List Detail wide tracks use `--ly-pane-min` guards on both content tracks +- Split Hero wide tracks use `--ly-split-min` guards on both content tracks +- personality-owned automatic content columns do not reintroduce unguarded primary `minmax(0, 1fr)` tracks +- `.ly-scroll` uses two-axis `overflow: auto` +- `.ly-frame` and `.ly-overflow-hidden` retain their explicit clipping semantics + +Rendered contracts must replace the current `regionWidths.every(width => width > 0)` acceptance with area-aware minimum assertions. Use computed root font size and public token values so tests verify behavior rather than hard-coding pixel copies. + +At the relevant enhanced topology, assert: + +- `main >= --ly-recipe-main-min` for App Shell, Dashboard, and Docs +- both List Detail content tracks meet `--ly-pane-min` +- both Split Hero tracks meet `--ly-split-min` +- representative multi-word labels do not render in character-by-character columns caused by Layout geometry + +For `.ly-scroll`, render content wider and taller than the scroll container, then set both `scrollLeft` and `scrollTop`; both values must advance above zero. The fixture must retain access to the overflowing content rather than merely reporting a larger `scrollWidth`/`scrollHeight`. + +Run the content-resilience fixture in `layout-only` and `all-three` ecosystem modes. The all-three mode is specifically intended to prove that Layout geometry remains usable even when a compatible UI Style Kit version applies aggressive text wrapping. + +## 8.7 Browser matrix + +Focused development checks use Chromium. + +Final release gate runs: + +- Chromium +- Firefox +- WebKit + +Representative allocations include: + +- phone portrait: 360 x 800 +- phone landscape: 800 x 360 +- tablet portrait: 768 x 1024 +- tablet landscape: 1024 x 768 +- desktop: 1440 x 900 +- wide desktop: 1920 x 1080 +- short-height cases around 44rem and 30rem +- Mosaic widths immediately below/above 42rem and 72rem + +--- + +# 9. Accessibility Requirements + +- Mobile/narrow DOM order is authoritative. +- Mosaic must never use `grid-auto-flow: dense`. +- No new `order` utilities are introduced. +- Area-aware App Shell changes only visual placement. +- Action Bar wrapping must preserve focus order. +- Sticky Action Bar must not make actions unreachable at short viewport heights. +- All generated demo fixtures must remain keyboard reachable. +- No layout personality may hide required content solely to satisfy its desktop composition. + +--- + +# 10. Release and Migration + +Create `docs/wiki/Migrating-To-3.2.md` with: + +- new Mosaic API and responsive behavior +- new Action Bar API +- area-aware App Shell behavior +- four new personality IDs +- geometry changes to Maximalist, Bauhaus, Tactile, Neumorphism, Brutalism, Y2K, and Retro Glass +- note that existing selectors and exports are retained +- UI Style Kit 2.4 pairing and content-resilience guidance +- guarded automatic content-track floors and the new `--ly-recipe-main-min` token +- `.ly-scroll` now exposes legitimate inline overflow with a scrollbar instead of clipping it + +Release flow: + +1. Start the implementation branch from protected `main` at the verified v3.1.0 release. +2. Implement with focused TDD slices. +3. Do not publish or tag from a partial implementation. +4. Confirm `ui-style-kit-css@2.4.0` exists in the npm registry before final all-three-library ecosystem/demo verification; until then, run layout-only and published-2.3 compatibility checks without treating them as the final ecosystem gate. +5. Run the full repository check chain and three-browser rendered matrix. +6. Run dependency audit, pack dry-run, publish dry-run, and existing release preflight. +7. Verify exact staged scope and `git diff --check`. +8. Merge through normal PR policy. +9. Tag immutable `v3.2.0` from merged `main`. +10. Publish through the protected npm workflow with provenance. +11. Verify npm version, dist-tag, tarball contents, provenance, GitHub Pages artifact, and live demo identity after publication. + +--- + +# 11. Non-Goals for 3.2 + +Do not add: + +- a v4 Wrapper/Measure/Scope decomposition +- a generic Band primitive +- a generic application Dock primitive +- a priority/reordering API +- framework components +- JavaScript layout runtime +- draggable Split Screen behavior +- personality-specific breakpoint values +- new visual styling +- layout IDs for every UI Style Kit preset + +If future evidence requires those capabilities, they belong in a later release rather than expanding 3.2 beyond the reviewed requirements. + +--- + +# 12. Acceptance Criteria + +The release is complete when all of the following are true: + +1. `manifest.json` publishes exactly 20 approved personalities. +2. All 20 personality modules build and have unique spatial signatures. +3. Mosaic supports automatic 1/6/12-track topology with responsive span collapse and no overflow. +4. Action Bar supports start/end grouping, intrinsic wrapping, optional sticky behavior, safe areas, and preserved DOM order. +5. App Shell does not reserve an empty sidebar/aside column when that area is absent in supported browsers. +6. The eight materially changed existing personalities (Bento, Maximalist, Bauhaus, Tactile, Neumorphism, Brutalism, Y2K, and Retro Glass) match the geometry targets in this spec. +7. Retrofuturism, Cyberpunk, F-pattern, Z-pattern, Split Screen, Mondrian, and Synthwave retain their approved spatial behavior unless explicitly changed here. +8. Technical Blueprint, Data Terminal, Industrial HMI, and Editorial are public, documented, tested personalities. +9. Every UI Style Kit 2.4 preset is covered by recommended or compatible pairing metadata, and the final all-three-library content-resilience fixture uses the published 2.4.0 package. +10. Layout/UI/theme/mode/density remain independently selectable. +11. Automatic App Shell, Dashboard, and Docs primary tracks never collapse below the public `--ly-recipe-main-min` floor while enhanced; List Detail and Split Hero honor their pane/split floors. +12. The rendered regression suite rejects functionally unusable narrow regions instead of accepting any width greater than zero. +13. `.ly-scroll` preserves access to legitimate horizontal and vertical overflow, with rendered tests proving both axes can be scrolled. +14. All static, rendered, package, documentation, Pages, and release-preflight tests pass. +15. No runtime dependency or breaking package export change is introduced. From 44751c7b74905983b88148d4ee0d2eb08f631f26 Mon Sep 17 00:00:00 2001 From: Foscat Date: Thu, 3 Sep 2026 09:11:45 -0500 Subject: [PATCH 02/11] fix: preserve usable layout content and overflow --- dist/foundation.css | 19 +-- dist/layout-style-css.css | 76 ++++++------ dist/layout-style-css.min.css | 2 +- dist/personalities/bauhaus.css | 2 +- dist/personalities/bento.css | 2 +- dist/personalities/brutalism.css | 2 +- dist/personalities/cyberpunk.css | 2 +- dist/personalities/f-pattern.css | 6 +- dist/personalities/maximalist.css | 2 +- dist/personalities/mondrian.css | 2 +- dist/personalities/neumorphism.css | 6 +- dist/personalities/retro-glass.css | 2 +- dist/personalities/retrofuturism.css | 2 +- dist/personalities/split-screen.css | 10 +- dist/personalities/synthwave.css | 2 +- dist/personalities/tactile.css | 6 +- dist/personalities/y2k.css | 2 +- dist/personalities/z-pattern.css | 6 +- dist/primitives.css | 3 +- manifest.json | 3 +- styles/foundation.css | 19 +-- styles/personalities/bauhaus.css | 2 +- styles/personalities/bento.css | 2 +- styles/personalities/brutalism.css | 2 +- styles/personalities/cyberpunk.css | 2 +- styles/personalities/f-pattern.css | 6 +- styles/personalities/maximalist.css | 2 +- styles/personalities/mondrian.css | 2 +- styles/personalities/neumorphism.css | 6 +- styles/personalities/retro-glass.css | 2 +- styles/personalities/retrofuturism.css | 2 +- styles/personalities/split-screen.css | 10 +- styles/personalities/synthwave.css | 2 +- styles/personalities/tactile.css | 6 +- styles/personalities/y2k.css | 2 +- styles/personalities/z-pattern.css | 6 +- styles/primitives.css | 3 +- test/demo-smoke.test.mjs | 159 ++++++++++++++++++++++++- test/layout-css-contract.test.mjs | 64 +++++++++- test/manifest-contract.test.mjs | 3 +- 40 files changed, 336 insertions(+), 123 deletions(-) diff --git a/dist/foundation.css b/dist/foundation.css index 88468e9..d3216b2 100644 --- a/dist/foundation.css +++ b/dist/foundation.css @@ -62,6 +62,7 @@ --ly-split-primary: 1fr; --ly-split-secondary: 1fr; + --ly-recipe-main-min: 20rem; --ly-recipe-rail: 18rem; --ly-recipe-aside: 22rem; --ly-gallery-min: 12rem; @@ -76,7 +77,7 @@ --ly-app-shell-medium-rows: auto auto minmax(0, 1fr) auto; --ly-app-shell-medium-columns: minmax(min(100%, var(--ly-recipe-rail)), auto) - minmax(0, 1fr); + minmax(min(100%, var(--ly-recipe-main-min)), 1fr); --ly-app-shell-wide-areas: "sidebar header header" "sidebar main aside" @@ -84,7 +85,7 @@ --ly-app-shell-wide-rows: auto minmax(0, 1fr) auto; --ly-app-shell-wide-columns: minmax(min(100%, var(--ly-recipe-rail)), auto) - minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); --ly-dashboard-medium-areas: @@ -93,7 +94,7 @@ "main aside" "footer footer"; --ly-dashboard-medium-columns: - minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); --ly-dashboard-wide-areas: "nav header header" @@ -101,7 +102,7 @@ "nav footer footer"; --ly-dashboard-wide-columns: minmax(min(100%, var(--ly-recipe-rail)), auto) - minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); --ly-docs-wide-areas: @@ -111,19 +112,19 @@ "footer footer"; --ly-docs-wide-columns: minmax(min(100%, var(--ly-recipe-rail)), auto) - minmax(0, 1fr); + minmax(min(100%, var(--ly-recipe-main-min)), 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); + minmax(min(100%, max(var(--ly-pane-min), var(--ly-pane-size))), 0.7fr) + minmax(min(100%, var(--ly-pane-min)), 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)); + minmax(min(100%, var(--ly-split-min)), var(--ly-split-primary, 1fr)) + minmax(min(100%, var(--ly-split-min)), var(--ly-split-secondary, 1fr)); container-name: ly-scope; container-type: inline-size; diff --git a/dist/layout-style-css.css b/dist/layout-style-css.css index 6709c75..f405626 100644 --- a/dist/layout-style-css.css +++ b/dist/layout-style-css.css @@ -65,6 +65,7 @@ --ly-split-primary: 1fr; --ly-split-secondary: 1fr; + --ly-recipe-main-min: 20rem; --ly-recipe-rail: 18rem; --ly-recipe-aside: 22rem; --ly-gallery-min: 12rem; @@ -79,7 +80,7 @@ --ly-app-shell-medium-rows: auto auto minmax(0, 1fr) auto; --ly-app-shell-medium-columns: minmax(min(100%, var(--ly-recipe-rail)), auto) - minmax(0, 1fr); + minmax(min(100%, var(--ly-recipe-main-min)), 1fr); --ly-app-shell-wide-areas: "sidebar header header" "sidebar main aside" @@ -87,7 +88,7 @@ --ly-app-shell-wide-rows: auto minmax(0, 1fr) auto; --ly-app-shell-wide-columns: minmax(min(100%, var(--ly-recipe-rail)), auto) - minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); --ly-dashboard-medium-areas: @@ -96,7 +97,7 @@ "main aside" "footer footer"; --ly-dashboard-medium-columns: - minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); --ly-dashboard-wide-areas: "nav header header" @@ -104,7 +105,7 @@ "nav footer footer"; --ly-dashboard-wide-columns: minmax(min(100%, var(--ly-recipe-rail)), auto) - minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); --ly-docs-wide-areas: @@ -114,19 +115,19 @@ "footer footer"; --ly-docs-wide-columns: minmax(min(100%, var(--ly-recipe-rail)), auto) - minmax(0, 1fr); + minmax(min(100%, var(--ly-recipe-main-min)), 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); + minmax(min(100%, max(var(--ly-pane-min), var(--ly-pane-size))), 0.7fr) + minmax(min(100%, var(--ly-pane-min)), 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)); + minmax(min(100%, var(--ly-split-min)), var(--ly-split-primary, 1fr)) + minmax(min(100%, var(--ly-split-min)), var(--ly-split-secondary, 1fr)); container-name: ly-scope; container-type: inline-size; @@ -618,8 +619,7 @@ .ly-scroll { min-block-size: 0; - overflow-x: clip; - overflow-y: auto; + overflow: auto; overscroll-behavior-block: contain; } @@ -933,7 +933,7 @@ --ly-app-shell-wide-rows: auto auto minmax(0, 1fr) auto; --ly-app-shell-wide-columns: minmax(min(100%, var(--ly-recipe-rail)), 0.3fr) - minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) minmax(0, 1fr); } } @@ -953,7 +953,7 @@ "main main sidebar aside" "main main footer footer"; --ly-app-shell-wide-columns: - minmax(0, 1.4fr) + minmax(min(100%, var(--ly-recipe-main-min)), 1.4fr) minmax(0, 0.6fr) minmax(min(100%, var(--ly-recipe-rail)), 0.32fr) minmax(min(100%, var(--ly-recipe-aside)), 0.38fr); @@ -974,7 +974,7 @@ "sidebar footer footer aside"; --ly-app-shell-wide-columns: minmax(min(100%, var(--ly-recipe-rail)), 0.24fr) - minmax(0, 0.7fr) + minmax(min(100%, var(--ly-recipe-main-min)), 0.7fr) minmax(0, 1.3fr) minmax(min(100%, var(--ly-recipe-aside)), 0.3fr); } @@ -996,10 +996,10 @@ --ly-app-shell-wide-rows: auto auto minmax(0, 1fr) auto; --ly-app-shell-wide-columns: minmax(min(100%, var(--ly-recipe-rail)), 0.28fr) - minmax(0, 1fr); + minmax(min(100%, var(--ly-recipe-main-min)), 1fr); --ly-list-detail-wide-columns: - minmax(min(100%, var(--ly-pane-size)), 0.5fr) - minmax(0, 0.9fr); + minmax(min(100%, var(--ly-pane-min)), 0.5fr) + minmax(min(100%, var(--ly-pane-min)), 0.9fr); } } @@ -1018,11 +1018,11 @@ "footer sidebar"; --ly-app-shell-wide-rows: auto minmax(0, 1fr) auto auto; --ly-app-shell-wide-columns: - minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-main-min)), 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); + minmax(min(100%, var(--ly-pane-min)), 1.1fr) + minmax(min(100%, var(--ly-pane-min)), 0.7fr); } } @@ -1040,7 +1040,7 @@ "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-main-min)), 1fr) minmax(min(100%, var(--ly-recipe-aside)), 0.3fr); } } @@ -1058,7 +1058,7 @@ "main aside sidebar" "footer footer sidebar"; --ly-app-shell-wide-columns: - minmax(0, 1.3fr) + minmax(min(100%, var(--ly-recipe-main-min)), 1.3fr) minmax(0, 0.7fr) minmax(min(100%, var(--ly-recipe-rail)), 0.34fr); } @@ -1078,7 +1078,7 @@ "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-main-min)), 1fr) minmax(min(100%, var(--ly-recipe-aside)), 0.32fr); } } @@ -1097,7 +1097,7 @@ "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-main-min)), 1fr) minmax(min(100%, var(--ly-recipe-rail)), 0.28fr); } } @@ -1115,7 +1115,7 @@ "main main sidebar" "aside footer footer"; --ly-app-shell-wide-columns: - minmax(0, 1.25fr) + minmax(min(100%, var(--ly-recipe-main-min)), 1.25fr) minmax(0, 0.75fr) minmax(min(100%, var(--ly-recipe-rail)), 0.32fr); } @@ -1135,11 +1135,11 @@ "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-main-min)), 1.35fr) minmax(min(100%, var(--ly-recipe-aside)), 0.65fr); --ly-split-hero-wide-columns: - minmax(0, 1.8fr) - minmax(0, 0.8fr); + minmax(min(100%, var(--ly-split-min)), 1.8fr) + minmax(min(100%, var(--ly-split-min)), 0.8fr); } } @@ -1156,12 +1156,12 @@ "main aside sidebar" "footer aside sidebar"; --ly-app-shell-wide-columns: - minmax(0, 1.45fr) + minmax(min(100%, var(--ly-recipe-main-min)), 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); + minmax(min(100%, var(--ly-split-min)), 1.5fr) + minmax(min(100%, var(--ly-split-min)), 0.5fr); } } @@ -1184,14 +1184,14 @@ "footer footer"; --ly-app-shell-wide-rows: auto minmax(0, 1fr) auto auto; --ly-app-shell-wide-columns: - minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) minmax(0, 1fr); --ly-split-hero-wide-columns: - minmax(0, 1fr) - minmax(0, 1fr); + minmax(min(100%, var(--ly-split-min)), 1fr) + minmax(min(100%, var(--ly-split-min)), 1fr); --ly-list-detail-wide-columns: - minmax(0, 1fr) - minmax(0, 1fr); + minmax(min(100%, var(--ly-pane-min)), 1fr) + minmax(min(100%, var(--ly-pane-min)), 1fr); } } @@ -1209,7 +1209,7 @@ "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-main-min)), 1.45fr) minmax(min(100%, var(--ly-recipe-aside)), 0.55fr); } } @@ -1228,7 +1228,7 @@ "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-main-min)), 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 4f09f14..08cb454 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.context;@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-workspace:96rem;--ly-wrapper-wide:112rem;--ly-page-padding-inline:clamp(1rem,3vw,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:var(--ly-page-padding-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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem);--ly-header-height:4.5rem;--ly-sticky-position:sticky;--ly-cover-min:100vh;--ly-shell-min:100vh;--ly-scroll-max:50rem;--ly-scroll-viewport-max:min(70vh,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-split-primary:1fr;--ly-split-secondary:1fr;--ly-recipe-rail:18rem;--ly-recipe-aside:22rem;--ly-gallery-min:12rem;--ly-card-grid-min:16rem;--ly-app-shell-base-rows:auto auto minmax(0,1fr) auto auto;--ly-app-shell-medium-areas:"header header" "sidebar main" "aside main" "footer footer";--ly-app-shell-medium-rows:auto auto minmax(0,1fr) auto;--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-rows:auto minmax(0,1fr) auto;--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}@supports (width:1cqi){:where(.ly-root){--ly-page-padding-inline:clamp(1rem,3cqi,3rem)}}@supports (height:100dvh){:where(.ly-root){--ly-cover-min:100dvh;--ly-shell-min:100dvh;--ly-scroll-viewport-max:min(70dvh,50rem)}}}@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),3vh);--ly-cluster-gap:min(var(--ly-space-3),2vh);--ly-section-padding-block:clamp(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem);--ly-header-height:3.5rem;--ly-scroll-viewport-max:min(62vh,34rem)}@supports (height:100dvh){:where(.ly-root){--ly-stack-gap:min(var(--ly-space-4),3dvh);--ly-cluster-gap:min(var(--ly-space-3),2dvh);--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem);--ly-scroll-viewport-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-4);--ly-section-padding-block-compact:var(--ly-space-2);--ly-scroll-viewport-max:max(12rem,calc(100vh - 8rem))}@supports (height:100dvh){:where(.ly-root){--ly-scroll-viewport-max:max(12rem,calc(100dvh - 8rem))}}}}@layer ly.context{:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(1rem,2.5vh,2rem);--ly-section-padding-block-compact:clamp(0.5rem,1.5vh,1rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:max(var(--ly-profile-gap),var(--ly-space-6));--ly-grid-gap:var(--ly-gap);--ly-stack-gap:var(--ly-space-5);--ly-cluster-gap:var(--ly-space-4);--ly-section-padding-block:clamp(3rem,7vh,6rem);--ly-section-padding-block-compact:clamp(1.5rem,3.5vh,3rem)}@media (max-height:44rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(0.75rem,2vh,1.25rem);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-gap:min(var(--ly-profile-gap),var(--ly-space-4));--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(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:var(--ly-space-5);--ly-grid-gap:var(--ly-space-5);--ly-stack-gap:var(--ly-space-4);--ly-cluster-gap:var(--ly-space-3);--ly-section-padding-block:clamp(1.5rem,6vh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3vh,1.25rem)}@supports (height:100dvh){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--ly-section-padding-block:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-section-padding-block:clamp(1.5rem,6dvh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3dvh,1.25rem)}}}@media (max-height:30rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-1);--ly-section-padding-block:var(--ly-space-3);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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-2);--ly-section-padding-block:var(--ly-space-4);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--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-3);--ly-section-padding-block:var(--ly-space-5);--ly-section-padding-block-compact:var(--ly-space-3)}}}@layer ly.wrappers{.ly-wrapper{--ly-wrapper-max:var(--ly-personality-wrapper-max,var(--ly-wrapper-content));--ly-wrapper-fluid-gutter:var(--ly-wrapper-gutter);--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--workspace{--ly-wrapper-max:var(--ly-wrapper-workspace)}.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,sticky);inset-block-start:0;z-index:var(--ly-z-header,20)}.ly-section{padding-block:var(--ly-section-padding-block)}.ly-section--compact{padding-block:var(--ly-section-padding-block-compact)}.ly-section--flush{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;overflow-x:clip;overflow-y:auto;overscroll-behavior-block:contain}.ly-scroll--bounded{max-block-size:var(--ly-scroll-max)}.ly-scroll--viewport{max-block-size:var(--ly-scroll-viewport-max)}}@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:var(--ly-app-shell-base-rows)}[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="gallery"],[data-ly-recipe="card-grid"] )[data-ly-responsive="manual"]{grid-template-columns:minmax(0,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);grid-template-rows:var(--ly-app-shell-medium-rows)}[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);grid-template-rows:var(--ly-app-shell-wide-rows)}[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{gap:var(--ly-space-0)}.ly-gap-1{gap:var(--ly-space-1)}.ly-gap-2{gap:var(--ly-space-2)}.ly-gap-3{gap:var(--ly-space-3)}.ly-gap-4{gap:var(--ly-space-4)}.ly-gap-5{gap:var(--ly-space-5)}.ly-gap-6{gap:var(--ly-space-6)}.ly-gap-7{gap:var(--ly-space-7)}.ly-gap-8{gap:var(--ly-space-8)}.ly-gap-9{gap:var(--ly-space-9)}.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-rows:auto auto minmax(0,1fr) auto;--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-rows:auto auto minmax(0,1fr) auto;--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-rows:auto minmax(0,1fr) auto auto;--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-rows:auto minmax(0,1fr) auto auto;--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}} +@layer ly.reset,ly.tokens,ly.wrappers,ly.primitives,ly.recipes,ly.utilities,ly.personalities,ly.context;@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-workspace:96rem;--ly-wrapper-wide:112rem;--ly-page-padding-inline:clamp(1rem,3vw,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:var(--ly-page-padding-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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem);--ly-header-height:4.5rem;--ly-sticky-position:sticky;--ly-cover-min:100vh;--ly-shell-min:100vh;--ly-scroll-max:50rem;--ly-scroll-viewport-max:min(70vh,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-split-primary:1fr;--ly-split-secondary:1fr;--ly-recipe-main-min:20rem;--ly-recipe-rail:18rem;--ly-recipe-aside:22rem;--ly-gallery-min:12rem;--ly-card-grid-min:16rem;--ly-app-shell-base-rows:auto auto minmax(0,1fr) auto auto;--ly-app-shell-medium-areas:"header header" "sidebar main" "aside main" "footer footer";--ly-app-shell-medium-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-medium-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),1fr);--ly-app-shell-wide-areas:"sidebar header header" "sidebar main aside" "sidebar footer footer";--ly-app-shell-wide-rows:auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1fr);--ly-list-detail-wide-areas:"primary secondary" "actions actions";--ly-list-detail-wide-columns:minmax(min(100%,max(var(--ly-pane-min),var(--ly-pane-size))),0.7fr) minmax(min(100%,var(--ly-pane-min)),1fr);--ly-split-hero-wide-areas:"content media" "actions media";--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),var(--ly-split-primary,1fr)) minmax(min(100%,var(--ly-split-min)),var(--ly-split-secondary,1fr));container-name:ly-scope;container-type:inline-size;min-inline-size:0;min-block-size:0}@supports (width:1cqi){:where(.ly-root){--ly-page-padding-inline:clamp(1rem,3cqi,3rem)}}@supports (height:100dvh){:where(.ly-root){--ly-cover-min:100dvh;--ly-shell-min:100dvh;--ly-scroll-viewport-max:min(70dvh,50rem)}}}@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),3vh);--ly-cluster-gap:min(var(--ly-space-3),2vh);--ly-section-padding-block:clamp(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem);--ly-header-height:3.5rem;--ly-scroll-viewport-max:min(62vh,34rem)}@supports (height:100dvh){:where(.ly-root){--ly-stack-gap:min(var(--ly-space-4),3dvh);--ly-cluster-gap:min(var(--ly-space-3),2dvh);--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem);--ly-scroll-viewport-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-4);--ly-section-padding-block-compact:var(--ly-space-2);--ly-scroll-viewport-max:max(12rem,calc(100vh - 8rem))}@supports (height:100dvh){:where(.ly-root){--ly-scroll-viewport-max:max(12rem,calc(100dvh - 8rem))}}}}@layer ly.context{:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(1rem,2.5vh,2rem);--ly-section-padding-block-compact:clamp(0.5rem,1.5vh,1rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:max(var(--ly-profile-gap),var(--ly-space-6));--ly-grid-gap:var(--ly-gap);--ly-stack-gap:var(--ly-space-5);--ly-cluster-gap:var(--ly-space-4);--ly-section-padding-block:clamp(3rem,7vh,6rem);--ly-section-padding-block-compact:clamp(1.5rem,3.5vh,3rem)}@media (max-height:44rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(0.75rem,2vh,1.25rem);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-gap:min(var(--ly-profile-gap),var(--ly-space-4));--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(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:var(--ly-space-5);--ly-grid-gap:var(--ly-space-5);--ly-stack-gap:var(--ly-space-4);--ly-cluster-gap:var(--ly-space-3);--ly-section-padding-block:clamp(1.5rem,6vh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3vh,1.25rem)}@supports (height:100dvh){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--ly-section-padding-block:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-section-padding-block:clamp(1.5rem,6dvh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3dvh,1.25rem)}}}@media (max-height:30rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-1);--ly-section-padding-block:var(--ly-space-3);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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-2);--ly-section-padding-block:var(--ly-space-4);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--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-3);--ly-section-padding-block:var(--ly-space-5);--ly-section-padding-block-compact:var(--ly-space-3)}}}@layer ly.wrappers{.ly-wrapper{--ly-wrapper-max:var(--ly-personality-wrapper-max,var(--ly-wrapper-content));--ly-wrapper-fluid-gutter:var(--ly-wrapper-gutter);--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--workspace{--ly-wrapper-max:var(--ly-wrapper-workspace)}.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,sticky);inset-block-start:0;z-index:var(--ly-z-header,20)}.ly-section{padding-block:var(--ly-section-padding-block)}.ly-section--compact{padding-block:var(--ly-section-padding-block-compact)}.ly-section--flush{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;overflow:auto;overscroll-behavior-block:contain}.ly-scroll--bounded{max-block-size:var(--ly-scroll-max)}.ly-scroll--viewport{max-block-size:var(--ly-scroll-viewport-max)}}@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:var(--ly-app-shell-base-rows)}[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="gallery"],[data-ly-recipe="card-grid"] )[data-ly-responsive="manual"]{grid-template-columns:minmax(0,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);grid-template-rows:var(--ly-app-shell-medium-rows)}[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);grid-template-rows:var(--ly-app-shell-wide-rows)}[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{gap:var(--ly-space-0)}.ly-gap-1{gap:var(--ly-space-1)}.ly-gap-2{gap:var(--ly-space-2)}.ly-gap-3{gap:var(--ly-space-3)}.ly-gap-4{gap:var(--ly-space-4)}.ly-gap-5{gap:var(--ly-space-5)}.ly-gap-6{gap:var(--ly-space-6)}.ly-gap-7{gap:var(--ly-space-7)}.ly-gap-8{gap:var(--ly-space-8)}.ly-gap-9{gap:var(--ly-space-9)}.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-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.3fr) minmax(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.28fr) minmax(min(100%,var(--ly-recipe-main-min)),1fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),0.5fr) minmax(min(100%,var(--ly-pane-min)),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-rows:auto minmax(0,1fr) auto auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-rail)),0.3fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),1.1fr) minmax(min(100%,var(--ly-pane-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1.35fr) minmax(min(100%,var(--ly-recipe-aside)),0.65fr);--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),1.8fr) minmax(min(100%,var(--ly-split-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-split-min)),1.5fr) minmax(min(100%,var(--ly-split-min)),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-rows:auto minmax(0,1fr) auto auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(0,1fr);--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),1fr) minmax(min(100%,var(--ly-split-min)),1fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),1fr) minmax(min(100%,var(--ly-pane-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.34fr);--ly-reel-item-min:20rem}} diff --git a/dist/personalities/bauhaus.css b/dist/personalities/bauhaus.css index 09bb47b..886e579 100644 --- a/dist/personalities/bauhaus.css +++ b/dist/personalities/bauhaus.css @@ -13,7 +13,7 @@ "sidebar footer footer aside"; --ly-app-shell-wide-columns: minmax(min(100%, var(--ly-recipe-rail)), 0.24fr) - minmax(0, 0.7fr) + minmax(min(100%, var(--ly-recipe-main-min)), 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 295fb81..d799469 100644 --- a/dist/personalities/bento.css +++ b/dist/personalities/bento.css @@ -17,7 +17,7 @@ --ly-app-shell-wide-rows: auto auto minmax(0, 1fr) auto; --ly-app-shell-wide-columns: minmax(min(100%, var(--ly-recipe-rail)), 0.3fr) - minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) minmax(0, 1fr); } } diff --git a/dist/personalities/brutalism.css b/dist/personalities/brutalism.css index 91dfd16..79dc216 100644 --- a/dist/personalities/brutalism.css +++ b/dist/personalities/brutalism.css @@ -12,7 +12,7 @@ "main aside sidebar" "footer footer sidebar"; --ly-app-shell-wide-columns: - minmax(0, 1.3fr) + minmax(min(100%, var(--ly-recipe-main-min)), 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 cecd1cb..119c8e9 100644 --- a/dist/personalities/cyberpunk.css +++ b/dist/personalities/cyberpunk.css @@ -13,7 +13,7 @@ "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-main-min)), 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 5d0ef16..bef8a16 100644 --- a/dist/personalities/f-pattern.css +++ b/dist/personalities/f-pattern.css @@ -13,10 +13,10 @@ "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-main-min)), 1.35fr) minmax(min(100%, var(--ly-recipe-aside)), 0.65fr); --ly-split-hero-wide-columns: - minmax(0, 1.8fr) - minmax(0, 0.8fr); + minmax(min(100%, var(--ly-split-min)), 1.8fr) + minmax(min(100%, var(--ly-split-min)), 0.8fr); } } diff --git a/dist/personalities/maximalist.css b/dist/personalities/maximalist.css index 82cdf0c..cae11df 100644 --- a/dist/personalities/maximalist.css +++ b/dist/personalities/maximalist.css @@ -14,7 +14,7 @@ "main main sidebar aside" "main main footer footer"; --ly-app-shell-wide-columns: - minmax(0, 1.4fr) + minmax(min(100%, var(--ly-recipe-main-min)), 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/mondrian.css b/dist/personalities/mondrian.css index 2e67153..0bbac6a 100644 --- a/dist/personalities/mondrian.css +++ b/dist/personalities/mondrian.css @@ -13,7 +13,7 @@ "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-main-min)), 1.45fr) minmax(min(100%, var(--ly-recipe-aside)), 0.55fr); } } diff --git a/dist/personalities/neumorphism.css b/dist/personalities/neumorphism.css index f52a353..f39f925 100644 --- a/dist/personalities/neumorphism.css +++ b/dist/personalities/neumorphism.css @@ -14,10 +14,10 @@ "footer sidebar"; --ly-app-shell-wide-rows: auto minmax(0, 1fr) auto auto; --ly-app-shell-wide-columns: - minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-main-min)), 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); + minmax(min(100%, var(--ly-pane-min)), 1.1fr) + minmax(min(100%, var(--ly-pane-min)), 0.7fr); } } diff --git a/dist/personalities/retro-glass.css b/dist/personalities/retro-glass.css index 66c5031..672a10e 100644 --- a/dist/personalities/retro-glass.css +++ b/dist/personalities/retro-glass.css @@ -12,7 +12,7 @@ "main main sidebar" "aside footer footer"; --ly-app-shell-wide-columns: - minmax(0, 1.25fr) + minmax(min(100%, var(--ly-recipe-main-min)), 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 1ce1190..ca2c152 100644 --- a/dist/personalities/retrofuturism.css +++ b/dist/personalities/retrofuturism.css @@ -13,7 +13,7 @@ "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-main-min)), 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 5b04b0e..9238e2a 100644 --- a/dist/personalities/split-screen.css +++ b/dist/personalities/split-screen.css @@ -18,13 +18,13 @@ "footer footer"; --ly-app-shell-wide-rows: auto minmax(0, 1fr) auto auto; --ly-app-shell-wide-columns: - minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) minmax(0, 1fr); --ly-split-hero-wide-columns: - minmax(0, 1fr) - minmax(0, 1fr); + minmax(min(100%, var(--ly-split-min)), 1fr) + minmax(min(100%, var(--ly-split-min)), 1fr); --ly-list-detail-wide-columns: - minmax(0, 1fr) - minmax(0, 1fr); + minmax(min(100%, var(--ly-pane-min)), 1fr) + minmax(min(100%, var(--ly-pane-min)), 1fr); } } diff --git a/dist/personalities/synthwave.css b/dist/personalities/synthwave.css index 7c2a4e0..028f17c 100644 --- a/dist/personalities/synthwave.css +++ b/dist/personalities/synthwave.css @@ -13,7 +13,7 @@ "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-main-min)), 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 e94d742..db5ce59 100644 --- a/dist/personalities/tactile.css +++ b/dist/personalities/tactile.css @@ -15,9 +15,9 @@ --ly-app-shell-wide-rows: auto auto minmax(0, 1fr) auto; --ly-app-shell-wide-columns: minmax(min(100%, var(--ly-recipe-rail)), 0.28fr) - minmax(0, 1fr); + minmax(min(100%, var(--ly-recipe-main-min)), 1fr); --ly-list-detail-wide-columns: - minmax(min(100%, var(--ly-pane-size)), 0.5fr) - minmax(0, 0.9fr); + minmax(min(100%, var(--ly-pane-min)), 0.5fr) + minmax(min(100%, var(--ly-pane-min)), 0.9fr); } } diff --git a/dist/personalities/y2k.css b/dist/personalities/y2k.css index 7e35ff2..1327693 100644 --- a/dist/personalities/y2k.css +++ b/dist/personalities/y2k.css @@ -13,7 +13,7 @@ "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-main-min)), 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 34ac8f8..701910a 100644 --- a/dist/personalities/z-pattern.css +++ b/dist/personalities/z-pattern.css @@ -12,11 +12,11 @@ "main aside sidebar" "footer aside sidebar"; --ly-app-shell-wide-columns: - minmax(0, 1.45fr) + minmax(min(100%, var(--ly-recipe-main-min)), 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); + minmax(min(100%, var(--ly-split-min)), 1.5fr) + minmax(min(100%, var(--ly-split-min)), 0.5fr); } } diff --git a/dist/primitives.css b/dist/primitives.css index 1af7140..d5b86c2 100644 --- a/dist/primitives.css +++ b/dist/primitives.css @@ -175,8 +175,7 @@ .ly-scroll { min-block-size: 0; - overflow-x: clip; - overflow-y: auto; + overflow: auto; overscroll-behavior-block: contain; } diff --git a/manifest.json b/manifest.json index 02549b2..c6ba13f 100644 --- a/manifest.json +++ b/manifest.json @@ -91,7 +91,8 @@ "--ly-sidebar-content-min", "--ly-grid-columns", "--ly-grid-min", "--ly-split-min", "--ly-pane-min", "--ly-pane-size", "--ly-media-min", "--ly-media-size", "--ly-reel-item-min", "--ly-reel-item-max", "--ly-frame-ratio", "--ly-split-primary", "--ly-split-secondary", - "--ly-recipe-rail", "--ly-recipe-aside", "--ly-gallery-min", "--ly-card-grid-min", + "--ly-recipe-main-min", "--ly-recipe-rail", "--ly-recipe-aside", "--ly-gallery-min", + "--ly-card-grid-min", "--ly-app-shell-medium-areas", "--ly-app-shell-medium-columns", "--ly-app-shell-wide-areas", "--ly-app-shell-wide-columns", "--ly-dashboard-medium-areas", "--ly-dashboard-medium-columns", "--ly-dashboard-wide-areas", "--ly-dashboard-wide-columns", "--ly-docs-wide-areas", diff --git a/styles/foundation.css b/styles/foundation.css index 88468e9..d3216b2 100644 --- a/styles/foundation.css +++ b/styles/foundation.css @@ -62,6 +62,7 @@ --ly-split-primary: 1fr; --ly-split-secondary: 1fr; + --ly-recipe-main-min: 20rem; --ly-recipe-rail: 18rem; --ly-recipe-aside: 22rem; --ly-gallery-min: 12rem; @@ -76,7 +77,7 @@ --ly-app-shell-medium-rows: auto auto minmax(0, 1fr) auto; --ly-app-shell-medium-columns: minmax(min(100%, var(--ly-recipe-rail)), auto) - minmax(0, 1fr); + minmax(min(100%, var(--ly-recipe-main-min)), 1fr); --ly-app-shell-wide-areas: "sidebar header header" "sidebar main aside" @@ -84,7 +85,7 @@ --ly-app-shell-wide-rows: auto minmax(0, 1fr) auto; --ly-app-shell-wide-columns: minmax(min(100%, var(--ly-recipe-rail)), auto) - minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); --ly-dashboard-medium-areas: @@ -93,7 +94,7 @@ "main aside" "footer footer"; --ly-dashboard-medium-columns: - minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); --ly-dashboard-wide-areas: "nav header header" @@ -101,7 +102,7 @@ "nav footer footer"; --ly-dashboard-wide-columns: minmax(min(100%, var(--ly-recipe-rail)), auto) - minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); --ly-docs-wide-areas: @@ -111,19 +112,19 @@ "footer footer"; --ly-docs-wide-columns: minmax(min(100%, var(--ly-recipe-rail)), auto) - minmax(0, 1fr); + minmax(min(100%, var(--ly-recipe-main-min)), 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); + minmax(min(100%, max(var(--ly-pane-min), var(--ly-pane-size))), 0.7fr) + minmax(min(100%, var(--ly-pane-min)), 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)); + minmax(min(100%, var(--ly-split-min)), var(--ly-split-primary, 1fr)) + minmax(min(100%, var(--ly-split-min)), var(--ly-split-secondary, 1fr)); container-name: ly-scope; container-type: inline-size; diff --git a/styles/personalities/bauhaus.css b/styles/personalities/bauhaus.css index 09bb47b..886e579 100644 --- a/styles/personalities/bauhaus.css +++ b/styles/personalities/bauhaus.css @@ -13,7 +13,7 @@ "sidebar footer footer aside"; --ly-app-shell-wide-columns: minmax(min(100%, var(--ly-recipe-rail)), 0.24fr) - minmax(0, 0.7fr) + minmax(min(100%, var(--ly-recipe-main-min)), 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 295fb81..d799469 100644 --- a/styles/personalities/bento.css +++ b/styles/personalities/bento.css @@ -17,7 +17,7 @@ --ly-app-shell-wide-rows: auto auto minmax(0, 1fr) auto; --ly-app-shell-wide-columns: minmax(min(100%, var(--ly-recipe-rail)), 0.3fr) - minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) minmax(0, 1fr); } } diff --git a/styles/personalities/brutalism.css b/styles/personalities/brutalism.css index 91dfd16..79dc216 100644 --- a/styles/personalities/brutalism.css +++ b/styles/personalities/brutalism.css @@ -12,7 +12,7 @@ "main aside sidebar" "footer footer sidebar"; --ly-app-shell-wide-columns: - minmax(0, 1.3fr) + minmax(min(100%, var(--ly-recipe-main-min)), 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 cecd1cb..119c8e9 100644 --- a/styles/personalities/cyberpunk.css +++ b/styles/personalities/cyberpunk.css @@ -13,7 +13,7 @@ "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-main-min)), 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 5d0ef16..bef8a16 100644 --- a/styles/personalities/f-pattern.css +++ b/styles/personalities/f-pattern.css @@ -13,10 +13,10 @@ "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-main-min)), 1.35fr) minmax(min(100%, var(--ly-recipe-aside)), 0.65fr); --ly-split-hero-wide-columns: - minmax(0, 1.8fr) - minmax(0, 0.8fr); + minmax(min(100%, var(--ly-split-min)), 1.8fr) + minmax(min(100%, var(--ly-split-min)), 0.8fr); } } diff --git a/styles/personalities/maximalist.css b/styles/personalities/maximalist.css index 82cdf0c..cae11df 100644 --- a/styles/personalities/maximalist.css +++ b/styles/personalities/maximalist.css @@ -14,7 +14,7 @@ "main main sidebar aside" "main main footer footer"; --ly-app-shell-wide-columns: - minmax(0, 1.4fr) + minmax(min(100%, var(--ly-recipe-main-min)), 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/mondrian.css b/styles/personalities/mondrian.css index 2e67153..0bbac6a 100644 --- a/styles/personalities/mondrian.css +++ b/styles/personalities/mondrian.css @@ -13,7 +13,7 @@ "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-main-min)), 1.45fr) minmax(min(100%, var(--ly-recipe-aside)), 0.55fr); } } diff --git a/styles/personalities/neumorphism.css b/styles/personalities/neumorphism.css index f52a353..f39f925 100644 --- a/styles/personalities/neumorphism.css +++ b/styles/personalities/neumorphism.css @@ -14,10 +14,10 @@ "footer sidebar"; --ly-app-shell-wide-rows: auto minmax(0, 1fr) auto auto; --ly-app-shell-wide-columns: - minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-main-min)), 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); + minmax(min(100%, var(--ly-pane-min)), 1.1fr) + minmax(min(100%, var(--ly-pane-min)), 0.7fr); } } diff --git a/styles/personalities/retro-glass.css b/styles/personalities/retro-glass.css index 66c5031..672a10e 100644 --- a/styles/personalities/retro-glass.css +++ b/styles/personalities/retro-glass.css @@ -12,7 +12,7 @@ "main main sidebar" "aside footer footer"; --ly-app-shell-wide-columns: - minmax(0, 1.25fr) + minmax(min(100%, var(--ly-recipe-main-min)), 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 1ce1190..ca2c152 100644 --- a/styles/personalities/retrofuturism.css +++ b/styles/personalities/retrofuturism.css @@ -13,7 +13,7 @@ "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-main-min)), 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 5b04b0e..9238e2a 100644 --- a/styles/personalities/split-screen.css +++ b/styles/personalities/split-screen.css @@ -18,13 +18,13 @@ "footer footer"; --ly-app-shell-wide-rows: auto minmax(0, 1fr) auto auto; --ly-app-shell-wide-columns: - minmax(0, 1fr) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) minmax(0, 1fr); --ly-split-hero-wide-columns: - minmax(0, 1fr) - minmax(0, 1fr); + minmax(min(100%, var(--ly-split-min)), 1fr) + minmax(min(100%, var(--ly-split-min)), 1fr); --ly-list-detail-wide-columns: - minmax(0, 1fr) - minmax(0, 1fr); + minmax(min(100%, var(--ly-pane-min)), 1fr) + minmax(min(100%, var(--ly-pane-min)), 1fr); } } diff --git a/styles/personalities/synthwave.css b/styles/personalities/synthwave.css index 7c2a4e0..028f17c 100644 --- a/styles/personalities/synthwave.css +++ b/styles/personalities/synthwave.css @@ -13,7 +13,7 @@ "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-main-min)), 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 e94d742..db5ce59 100644 --- a/styles/personalities/tactile.css +++ b/styles/personalities/tactile.css @@ -15,9 +15,9 @@ --ly-app-shell-wide-rows: auto auto minmax(0, 1fr) auto; --ly-app-shell-wide-columns: minmax(min(100%, var(--ly-recipe-rail)), 0.28fr) - minmax(0, 1fr); + minmax(min(100%, var(--ly-recipe-main-min)), 1fr); --ly-list-detail-wide-columns: - minmax(min(100%, var(--ly-pane-size)), 0.5fr) - minmax(0, 0.9fr); + minmax(min(100%, var(--ly-pane-min)), 0.5fr) + minmax(min(100%, var(--ly-pane-min)), 0.9fr); } } diff --git a/styles/personalities/y2k.css b/styles/personalities/y2k.css index 7e35ff2..1327693 100644 --- a/styles/personalities/y2k.css +++ b/styles/personalities/y2k.css @@ -13,7 +13,7 @@ "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-main-min)), 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 34ac8f8..701910a 100644 --- a/styles/personalities/z-pattern.css +++ b/styles/personalities/z-pattern.css @@ -12,11 +12,11 @@ "main aside sidebar" "footer aside sidebar"; --ly-app-shell-wide-columns: - minmax(0, 1.45fr) + minmax(min(100%, var(--ly-recipe-main-min)), 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); + minmax(min(100%, var(--ly-split-min)), 1.5fr) + minmax(min(100%, var(--ly-split-min)), 0.5fr); } } diff --git a/styles/primitives.css b/styles/primitives.css index 1af7140..d5b86c2 100644 --- a/styles/primitives.css +++ b/styles/primitives.css @@ -175,8 +175,7 @@ .ly-scroll { min-block-size: 0; - overflow-x: clip; - overflow-y: auto; + overflow: auto; overscroll-behavior-block: contain; } diff --git a/test/demo-smoke.test.mjs b/test/demo-smoke.test.mjs index 5be6219..9d51812 100644 --- a/test/demo-smoke.test.mjs +++ b/test/demo-smoke.test.mjs @@ -391,6 +391,146 @@ const assertNoHorizontalFailures = (snapshot, label) => { assert.deepEqual(snapshot.clippedRegions, [], `${label}: required region content was clipped.`); }; +/** + * Verifies usable automatic recipe floors and accessible two-axis Scroll + * behavior in both the standalone and complete ecosystem modes. + * + * @param {import("@playwright/test").Page} page Active browser page. + * @param {string} baseUrl Demo server URL. + * @returns {Promise} + */ +const verifyContentResilience = async (page, baseUrl) => { + await page.setViewportSize({ width: 1440, height: 900 }); + + for (const ecosystem of ["layout-only", "all-three"]) { + await page.goto(`${baseUrl}?ecosystem=${ecosystem}&wrapper=full`, { + waitUntil: "domcontentloaded" + }); + await page.waitForFunction(() => document.body.dataset.demoReady === "true"); + await setCustomAllocation(page, "73rem"); + + const result = await page.evaluate(() => { + const wrapper = document.querySelector("#previewWrapper"); + wrapper.style.setProperty("--ly-shell-min", "auto"); + const recipeAreas = { + "app-shell": ["header", "sidebar", "main", "aside", "footer"], + dashboard: ["header", "nav", "main", "aside", "footer"], + docs: ["header", "nav", "main", "aside", "footer"], + "list-detail": ["primary", "secondary", "actions"], + "split-hero": ["content", "media", "actions"] + }; + const measurements = {}; + let scrollMetrics; + + /** + * Converts a public rem-valued geometry token to rendered pixels. + * + * @param {CSSStyleDeclaration} style Computed layout-root styles. + * @param {string} property Public custom-property name. + * @returns {number} Token value in CSS pixels. + */ + const tokenPixels = (style, property) => + Number.parseFloat(style.getPropertyValue(property)) * + Number.parseFloat(getComputedStyle(document.documentElement).fontSize); + + for (const [recipeName, areas] of Object.entries(recipeAreas)) { + const recipe = document.createElement("section"); + recipe.dataset.lyRecipe = recipeName; + + for (const areaName of areas) { + const region = document.createElement("article"); + region.dataset.lyArea = areaName; + const label = document.createElement("strong"); + label.textContent = `${areaName} operational workspace`; + const copy = document.createElement("p"); + copy.textContent = + "Ordinary multi-word content must retain a practical reading and interaction width."; + region.append(label, copy); + recipe.append(region); + } + + wrapper.replaceChildren(recipe); + const rootStyle = getComputedStyle(wrapper); + const areaWidths = Object.fromEntries( + areas.map((areaName) => [ + areaName, + recipe.querySelector(`[data-ly-area="${areaName}"]`).getBoundingClientRect().width + ]) + ); + measurements[recipeName] = { + areaWidths, + mainFloor: tokenPixels(rootStyle, "--ly-recipe-main-min"), + paneFloor: tokenPixels(rootStyle, "--ly-pane-min"), + splitFloor: tokenPixels(rootStyle, "--ly-split-min") + }; + + if (recipeName === "app-shell") { + const scroll = document.createElement("div"); + scroll.className = "ly-scroll"; + scroll.style.inlineSize = "18rem"; + scroll.style.blockSize = "8rem"; + const oversizedContent = document.createElement("div"); + oversizedContent.style.inlineSize = "64rem"; + oversizedContent.style.blockSize = "24rem"; + oversizedContent.textContent = + "https://example.test/a-legitimate-wide-technical-resource-that-must-remain-accessible"; + scroll.append(oversizedContent); + recipe.querySelector('[data-ly-area="main"]').append(scroll); + scroll.scrollLeft = 80; + scroll.scrollTop = 80; + scrollMetrics = { + horizontalOverflow: scroll.scrollWidth - scroll.clientWidth, + verticalOverflow: scroll.scrollHeight - scroll.clientHeight, + scrollLeft: scroll.scrollLeft, + scrollTop: scroll.scrollTop, + overflowX: getComputedStyle(scroll).overflowX, + overflowY: getComputedStyle(scroll).overflowY + }; + } + } + + return { measurements, scrollMetrics }; + }); + + for (const recipeName of ["app-shell", "dashboard", "docs"]) { + const measurement = result.measurements[recipeName]; + assert( + measurement.areaWidths.main + 1 >= measurement.mainFloor, + `${ecosystem} ${recipeName} main width ${measurement.areaWidths.main}px did not meet ${measurement.mainFloor}px.` + ); + } + for (const areaName of ["primary", "secondary"]) { + const measurement = result.measurements["list-detail"]; + assert( + measurement.areaWidths[areaName] + 1 >= measurement.paneFloor, + `${ecosystem} List Detail ${areaName} did not meet its pane floor.` + ); + } + for (const areaName of ["content", "media"]) { + const measurement = result.measurements["split-hero"]; + assert( + measurement.areaWidths[areaName] + 1 >= measurement.splitFloor, + `${ecosystem} Split Hero ${areaName} did not meet its split floor.` + ); + } + assert( + result.scrollMetrics.horizontalOverflow > 0, + `${ecosystem} Scroll lacked inline overflow.` + ); + assert( + result.scrollMetrics.verticalOverflow > 0, + `${ecosystem} Scroll lacked block overflow.` + ); + assert(result.scrollMetrics.scrollLeft > 0, `${ecosystem} Scroll could not move inline.`); + assert( + result.scrollMetrics.scrollTop > 0, + `${ecosystem} Scroll could not move in block flow.` + ); + assert.equal(result.scrollMetrics.overflowX, "auto"); + assert.equal(result.scrollMetrics.overflowY, "auto"); + } +}; + const installExternalFixtures = async (page) => { await page.route("https://unpkg.com/**", async (route) => { const url = route.request().url(); @@ -1404,6 +1544,9 @@ const verifyPrimitiveOverflow = async (page, baseUrl) => { primitiveName === "scroll" ? `Bounded vertical item ${index + 1}` : `Shrink-safe item ${index + 1}`; + if (primitiveName === "scroll" && index === 0) { + item.style.inlineSize = "120rem"; + } if (primitiveName === "sidebar") { item.dataset.lySidebar = index === 0 ? "side" : "content"; } @@ -1414,12 +1557,18 @@ const verifyPrimitiveOverflow = async (page, baseUrl) => { } wrapper.replaceChildren(fixture); + if (primitiveName === "scroll") { + fixture.scrollLeft = 80; + fixture.scrollTop = 80; + } const style = getComputedStyle(fixture); return { documentOverflow: document.documentElement.scrollWidth - document.documentElement.clientWidth, horizontal: fixture.scrollWidth - fixture.clientWidth, vertical: fixture.scrollHeight - fixture.clientHeight, + scrollLeft: fixture.scrollLeft, + scrollTop: fixture.scrollTop, overflowX: style.overflowX, overflowY: style.overflowY }; @@ -1428,16 +1577,17 @@ const verifyPrimitiveOverflow = async (page, baseUrl) => { assert(result.documentOverflow <= 2, `${primitive} overflowed the ${width}px document.`); if (primitive === "reel") { assert(result.horizontal > 2 && result.overflowX === "auto", "Reel must scroll internally."); + } else if (primitive === "scroll") { + assert(result.horizontal > 2, "Scroll must retain legitimate inline overflow."); } else { assert(result.horizontal <= 2, `${primitive} introduced horizontal scrolling.`); } if (primitive === "scroll") { assert(result.vertical > 2 && result.overflowY === "auto", "Scroll must be vertically bounded."); - assert( - !["auto", "scroll", "visible"].includes(result.overflowX), - `The bounded vertical scroll primitive exposed inline overflow as ${result.overflowX}.` - ); + assert.equal(result.overflowX, "auto", "Scroll must expose inline overflow."); + assert(result.scrollLeft > 0, "Scroll must permit inline movement."); + assert(result.scrollTop > 0, "Scroll must permit block movement."); } else { assert( !(result.vertical > 2 && ["auto", "scroll"].includes(result.overflowY)), @@ -1512,6 +1662,7 @@ try { await verifyWorkspaceMeasure(page, server.baseUrl); await verifyBreakoutGeometry(page, server.baseUrl); await verifyProfileAndUtilityIsolation(page, server.baseUrl); + await verifyContentResilience(page, server.baseUrl); await verifyPrimitiveOverflow(page, server.baseUrl); await verifyCodeBlockContrast(page, server.baseUrl); await verifyInteractions(page, server.baseUrl); diff --git a/test/layout-css-contract.test.mjs b/test/layout-css-contract.test.mjs index 01c6553..40404a0 100644 --- a/test/layout-css-contract.test.mjs +++ b/test/layout-css-contract.test.mjs @@ -333,9 +333,13 @@ assert( "Bounded and viewport-relative Scroll need separate public maxima." ); assert( - /\.ly-scroll\s*\{[^}]*overflow-y:\s*auto/s.test(primitives) && + /\.ly-scroll\s*\{[^}]*overflow:\s*auto/s.test(primitives) && !/\.ly-scroll\s*\{[^}]*max-block-size:/s.test(primitives), - "Base Scroll must not impose a height cap." + "Base Scroll must expose legitimate overflow on both axes without imposing a height cap." +); +assert( + !/\.ly-scroll\s*\{[^}]*overflow-x:\s*clip/s.test(primitives), + "Base Scroll must not silently clip inline overflow." ); assert( /\.ly-scroll--bounded\s*\{[^}]*max-block-size:\s*var\(--ly-scroll-max\)/s.test( @@ -351,6 +355,62 @@ assert( /--ly-split-secondary:\s*1fr/.test(foundation), "Every nested layout root must reset optional personality split ratios" ); +assert( + /--ly-recipe-main-min:\s*20rem/.test(foundation), + "Automatic application recipes need a public 20rem usable main-track floor." +); +for (const property of [ + "--ly-app-shell-medium-columns", + "--ly-app-shell-wide-columns", + "--ly-dashboard-medium-columns", + "--ly-dashboard-wide-columns", + "--ly-docs-wide-columns" +]) { + assert( + new RegExp( + `${property}:\\s*[\\s\\S]*?minmax\\(min\\(100%,\\s*var\\(--ly-recipe-main-min\\)\\)` + ).test(foundation), + `${property} must guard primary content with --ly-recipe-main-min.` + ); +} +assert( + /--ly-list-detail-wide-columns:\s*[\s\S]*?var\(--ly-pane-min\)[\s\S]*?var\(--ly-pane-min\)/.test( + foundation + ), + "List Detail must guard both content tracks with --ly-pane-min." +); +assert( + /--ly-split-hero-wide-columns:\s*[\s\S]*?var\(--ly-split-min\)[\s\S]*?var\(--ly-split-min\)/.test( + foundation + ), + "Split Hero must guard both content tracks with --ly-split-min." +); +for (const name of personalityNames) { + const css = readStyle(`personalities/${name}.css`); + const appShellColumns = css.match(/--ly-app-shell-wide-columns:\s*([^;]+);/s)?.[1]; + const listDetailColumns = css.match(/--ly-list-detail-wide-columns:\s*([^;]+);/s)?.[1]; + const splitHeroColumns = css.match(/--ly-split-hero-wide-columns:\s*([^;]+);/s)?.[1]; + if (appShellColumns) { + assert( + appShellColumns.includes("var(--ly-recipe-main-min)"), + `${name} App Shell must guard its primary application track.` + ); + } + if (listDetailColumns) { + assert.equal( + (listDetailColumns.match(/var\(--ly-pane-min\)/g) ?? []).length, + 2, + `${name} List Detail must guard both pane tracks.` + ); + } + if (splitHeroColumns) { + assert.equal( + (splitHeroColumns.match(/var\(--ly-split-min\)/g) ?? []).length, + 2, + `${name} Split Hero must guard both content tracks.` + ); + } +} for (const recipe of recipeNames) { assert( diff --git a/test/manifest-contract.test.mjs b/test/manifest-contract.test.mjs index 8976a5c..4ee0c6a 100644 --- a/test/manifest-contract.test.mjs +++ b/test/manifest-contract.test.mjs @@ -61,7 +61,8 @@ const geometryTokens = [ "--ly-sidebar-content-min", "--ly-grid-columns", "--ly-grid-min", "--ly-split-min", "--ly-pane-min", "--ly-pane-size", "--ly-media-min", "--ly-media-size", "--ly-reel-item-min", "--ly-reel-item-max", "--ly-frame-ratio", "--ly-split-primary", "--ly-split-secondary", - "--ly-recipe-rail", "--ly-recipe-aside", "--ly-gallery-min", "--ly-card-grid-min", + "--ly-recipe-main-min", "--ly-recipe-rail", "--ly-recipe-aside", "--ly-gallery-min", + "--ly-card-grid-min", "--ly-app-shell-medium-areas", "--ly-app-shell-medium-columns", "--ly-app-shell-wide-areas", "--ly-app-shell-wide-columns", "--ly-dashboard-medium-areas", "--ly-dashboard-medium-columns", "--ly-dashboard-wide-areas", "--ly-dashboard-wide-columns", "--ly-docs-wide-areas", From 97dd07048665357d69187832bc3e2f44c20afed4 Mon Sep 17 00:00:00 2001 From: Foscat Date: Thu, 3 Sep 2026 09:15:37 -0500 Subject: [PATCH 03/11] feat: add responsive mosaic composition --- dist/foundation.css | 2 + dist/layout-style-css.css | 90 +++++++++++++++++++++++ dist/layout-style-css.min.css | 2 +- dist/primitives.css | 85 ++++++++++++++++++++++ dist/utilities.css | 3 + manifest.json | 8 ++- styles/foundation.css | 2 + styles/primitives.css | 85 ++++++++++++++++++++++ styles/utilities.css | 3 + test/demo-smoke.test.mjs | 116 ++++++++++++++++++++++++++++++ test/layout-css-contract.test.mjs | 14 +++- test/manifest-contract.test.mjs | 9 ++- 12 files changed, 413 insertions(+), 6 deletions(-) diff --git a/dist/foundation.css b/dist/foundation.css index d3216b2..3a11d69 100644 --- a/dist/foundation.css +++ b/dist/foundation.css @@ -51,6 +51,8 @@ --ly-sidebar-content-min: 50%; --ly-grid-columns: 12; --ly-grid-min: 16rem; + --ly-mosaic-medium-columns: 6; + --ly-mosaic-wide-columns: 12; --ly-split-min: 20rem; --ly-pane-min: 18rem; --ly-pane-size: 22rem; diff --git a/dist/layout-style-css.css b/dist/layout-style-css.css index f405626..8355376 100644 --- a/dist/layout-style-css.css +++ b/dist/layout-style-css.css @@ -54,6 +54,8 @@ --ly-sidebar-content-min: 50%; --ly-grid-columns: 12; --ly-grid-min: 16rem; + --ly-mosaic-medium-columns: 6; + --ly-mosaic-wide-columns: 12; --ly-split-min: 20rem; --ly-pane-min: 18rem; --ly-pane-size: 22rem; @@ -559,6 +561,17 @@ grid-template-columns: repeat(var(--ly-grid-columns), minmax(0, 1fr)); } + .ly-mosaic { + display: grid; + grid-template-columns: minmax(0, 1fr); + gap: var(--ly-grid-gap); + } + + .ly-mosaic > * { + min-inline-size: 0; + min-block-size: 0; + } + .ly-split { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-split-min)), 1fr)); @@ -632,6 +645,80 @@ } } +/* + Mosaic span behavior lives in the final structural context layer so it can + deliberately override the general-purpose span utilities at automatic tiers. +*/ +@layer ly.context { + .ly-mosaic:not([data-ly-responsive="manual"]) > :where( + .ly-span-1, + .ly-span-2, + .ly-span-3, + .ly-span-4, + .ly-span-6, + .ly-span-full + ) { + grid-column: 1 / -1; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > :where( + .ly-row-span-2, + .ly-row-span-3 + ) { + grid-row: auto; + } + + @container ly-scope (min-width: 42rem) { + .ly-mosaic:not([data-ly-responsive="manual"]) { + grid-template-columns: repeat( + var(--ly-mosaic-medium-columns), + minmax(0, 1fr) + ); + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-span-1 { + grid-column: span 1; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-span-2 { + grid-column: span 2; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-span-3 { + grid-column: span 3; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-span-4 { + grid-column: span 4; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-span-6 { + grid-column: span 6; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-span-full { + grid-column: 1 / -1; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-row-span-2 { + grid-row: span 2; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-row-span-3 { + grid-row: span 3; + } + } + + @container ly-scope (min-width: 72rem) { + .ly-mosaic:not([data-ly-responsive="manual"]) { + grid-template-columns: repeat( + var(--ly-mosaic-wide-columns), + minmax(0, 1fr) + ); + } + } +} + /* recipes.css */ /* Recipes preserve the narrow-screen DOM order. Automatic topology queries @@ -844,7 +931,10 @@ .ly-span-2 { grid-column: span 2; } .ly-span-3 { grid-column: span 3; } .ly-span-4 { grid-column: span 4; } + .ly-span-6 { grid-column: span 6; } .ly-span-full { grid-column: 1 / -1; } + .ly-row-span-2 { grid-row: span 2; } + .ly-row-span-3 { grid-row: span 3; } .ly-gap-0 { gap: var(--ly-space-0); } .ly-gap-1 { gap: var(--ly-space-1); } diff --git a/dist/layout-style-css.min.css b/dist/layout-style-css.min.css index 08cb454..2629ad6 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.context;@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-workspace:96rem;--ly-wrapper-wide:112rem;--ly-page-padding-inline:clamp(1rem,3vw,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:var(--ly-page-padding-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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem);--ly-header-height:4.5rem;--ly-sticky-position:sticky;--ly-cover-min:100vh;--ly-shell-min:100vh;--ly-scroll-max:50rem;--ly-scroll-viewport-max:min(70vh,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-split-primary:1fr;--ly-split-secondary:1fr;--ly-recipe-main-min:20rem;--ly-recipe-rail:18rem;--ly-recipe-aside:22rem;--ly-gallery-min:12rem;--ly-card-grid-min:16rem;--ly-app-shell-base-rows:auto auto minmax(0,1fr) auto auto;--ly-app-shell-medium-areas:"header header" "sidebar main" "aside main" "footer footer";--ly-app-shell-medium-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-medium-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),1fr);--ly-app-shell-wide-areas:"sidebar header header" "sidebar main aside" "sidebar footer footer";--ly-app-shell-wide-rows:auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1fr);--ly-list-detail-wide-areas:"primary secondary" "actions actions";--ly-list-detail-wide-columns:minmax(min(100%,max(var(--ly-pane-min),var(--ly-pane-size))),0.7fr) minmax(min(100%,var(--ly-pane-min)),1fr);--ly-split-hero-wide-areas:"content media" "actions media";--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),var(--ly-split-primary,1fr)) minmax(min(100%,var(--ly-split-min)),var(--ly-split-secondary,1fr));container-name:ly-scope;container-type:inline-size;min-inline-size:0;min-block-size:0}@supports (width:1cqi){:where(.ly-root){--ly-page-padding-inline:clamp(1rem,3cqi,3rem)}}@supports (height:100dvh){:where(.ly-root){--ly-cover-min:100dvh;--ly-shell-min:100dvh;--ly-scroll-viewport-max:min(70dvh,50rem)}}}@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),3vh);--ly-cluster-gap:min(var(--ly-space-3),2vh);--ly-section-padding-block:clamp(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem);--ly-header-height:3.5rem;--ly-scroll-viewport-max:min(62vh,34rem)}@supports (height:100dvh){:where(.ly-root){--ly-stack-gap:min(var(--ly-space-4),3dvh);--ly-cluster-gap:min(var(--ly-space-3),2dvh);--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem);--ly-scroll-viewport-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-4);--ly-section-padding-block-compact:var(--ly-space-2);--ly-scroll-viewport-max:max(12rem,calc(100vh - 8rem))}@supports (height:100dvh){:where(.ly-root){--ly-scroll-viewport-max:max(12rem,calc(100dvh - 8rem))}}}}@layer ly.context{:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(1rem,2.5vh,2rem);--ly-section-padding-block-compact:clamp(0.5rem,1.5vh,1rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:max(var(--ly-profile-gap),var(--ly-space-6));--ly-grid-gap:var(--ly-gap);--ly-stack-gap:var(--ly-space-5);--ly-cluster-gap:var(--ly-space-4);--ly-section-padding-block:clamp(3rem,7vh,6rem);--ly-section-padding-block-compact:clamp(1.5rem,3.5vh,3rem)}@media (max-height:44rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(0.75rem,2vh,1.25rem);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-gap:min(var(--ly-profile-gap),var(--ly-space-4));--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(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:var(--ly-space-5);--ly-grid-gap:var(--ly-space-5);--ly-stack-gap:var(--ly-space-4);--ly-cluster-gap:var(--ly-space-3);--ly-section-padding-block:clamp(1.5rem,6vh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3vh,1.25rem)}@supports (height:100dvh){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--ly-section-padding-block:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-section-padding-block:clamp(1.5rem,6dvh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3dvh,1.25rem)}}}@media (max-height:30rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-1);--ly-section-padding-block:var(--ly-space-3);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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-2);--ly-section-padding-block:var(--ly-space-4);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--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-3);--ly-section-padding-block:var(--ly-space-5);--ly-section-padding-block-compact:var(--ly-space-3)}}}@layer ly.wrappers{.ly-wrapper{--ly-wrapper-max:var(--ly-personality-wrapper-max,var(--ly-wrapper-content));--ly-wrapper-fluid-gutter:var(--ly-wrapper-gutter);--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--workspace{--ly-wrapper-max:var(--ly-wrapper-workspace)}.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,sticky);inset-block-start:0;z-index:var(--ly-z-header,20)}.ly-section{padding-block:var(--ly-section-padding-block)}.ly-section--compact{padding-block:var(--ly-section-padding-block-compact)}.ly-section--flush{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;overflow:auto;overscroll-behavior-block:contain}.ly-scroll--bounded{max-block-size:var(--ly-scroll-max)}.ly-scroll--viewport{max-block-size:var(--ly-scroll-viewport-max)}}@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:var(--ly-app-shell-base-rows)}[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="gallery"],[data-ly-recipe="card-grid"] )[data-ly-responsive="manual"]{grid-template-columns:minmax(0,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);grid-template-rows:var(--ly-app-shell-medium-rows)}[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);grid-template-rows:var(--ly-app-shell-wide-rows)}[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{gap:var(--ly-space-0)}.ly-gap-1{gap:var(--ly-space-1)}.ly-gap-2{gap:var(--ly-space-2)}.ly-gap-3{gap:var(--ly-space-3)}.ly-gap-4{gap:var(--ly-space-4)}.ly-gap-5{gap:var(--ly-space-5)}.ly-gap-6{gap:var(--ly-space-6)}.ly-gap-7{gap:var(--ly-space-7)}.ly-gap-8{gap:var(--ly-space-8)}.ly-gap-9{gap:var(--ly-space-9)}.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-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.3fr) minmax(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.28fr) minmax(min(100%,var(--ly-recipe-main-min)),1fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),0.5fr) minmax(min(100%,var(--ly-pane-min)),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-rows:auto minmax(0,1fr) auto auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-rail)),0.3fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),1.1fr) minmax(min(100%,var(--ly-pane-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1.35fr) minmax(min(100%,var(--ly-recipe-aside)),0.65fr);--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),1.8fr) minmax(min(100%,var(--ly-split-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-split-min)),1.5fr) minmax(min(100%,var(--ly-split-min)),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-rows:auto minmax(0,1fr) auto auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(0,1fr);--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),1fr) minmax(min(100%,var(--ly-split-min)),1fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),1fr) minmax(min(100%,var(--ly-pane-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.34fr);--ly-reel-item-min:20rem}} +@layer ly.reset,ly.tokens,ly.wrappers,ly.primitives,ly.recipes,ly.utilities,ly.personalities,ly.context;@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-workspace:96rem;--ly-wrapper-wide:112rem;--ly-page-padding-inline:clamp(1rem,3vw,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:var(--ly-page-padding-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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem);--ly-header-height:4.5rem;--ly-sticky-position:sticky;--ly-cover-min:100vh;--ly-shell-min:100vh;--ly-scroll-max:50rem;--ly-scroll-viewport-max:min(70vh,50rem);--ly-switcher-threshold:42rem;--ly-sidebar-size:18rem;--ly-sidebar-content-min:50%;--ly-grid-columns:12;--ly-grid-min:16rem;--ly-mosaic-medium-columns:6;--ly-mosaic-wide-columns:12;--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-split-primary:1fr;--ly-split-secondary:1fr;--ly-recipe-main-min:20rem;--ly-recipe-rail:18rem;--ly-recipe-aside:22rem;--ly-gallery-min:12rem;--ly-card-grid-min:16rem;--ly-app-shell-base-rows:auto auto minmax(0,1fr) auto auto;--ly-app-shell-medium-areas:"header header" "sidebar main" "aside main" "footer footer";--ly-app-shell-medium-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-medium-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),1fr);--ly-app-shell-wide-areas:"sidebar header header" "sidebar main aside" "sidebar footer footer";--ly-app-shell-wide-rows:auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1fr);--ly-list-detail-wide-areas:"primary secondary" "actions actions";--ly-list-detail-wide-columns:minmax(min(100%,max(var(--ly-pane-min),var(--ly-pane-size))),0.7fr) minmax(min(100%,var(--ly-pane-min)),1fr);--ly-split-hero-wide-areas:"content media" "actions media";--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),var(--ly-split-primary,1fr)) minmax(min(100%,var(--ly-split-min)),var(--ly-split-secondary,1fr));container-name:ly-scope;container-type:inline-size;min-inline-size:0;min-block-size:0}@supports (width:1cqi){:where(.ly-root){--ly-page-padding-inline:clamp(1rem,3cqi,3rem)}}@supports (height:100dvh){:where(.ly-root){--ly-cover-min:100dvh;--ly-shell-min:100dvh;--ly-scroll-viewport-max:min(70dvh,50rem)}}}@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),3vh);--ly-cluster-gap:min(var(--ly-space-3),2vh);--ly-section-padding-block:clamp(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem);--ly-header-height:3.5rem;--ly-scroll-viewport-max:min(62vh,34rem)}@supports (height:100dvh){:where(.ly-root){--ly-stack-gap:min(var(--ly-space-4),3dvh);--ly-cluster-gap:min(var(--ly-space-3),2dvh);--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem);--ly-scroll-viewport-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-4);--ly-section-padding-block-compact:var(--ly-space-2);--ly-scroll-viewport-max:max(12rem,calc(100vh - 8rem))}@supports (height:100dvh){:where(.ly-root){--ly-scroll-viewport-max:max(12rem,calc(100dvh - 8rem))}}}}@layer ly.context{:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(1rem,2.5vh,2rem);--ly-section-padding-block-compact:clamp(0.5rem,1.5vh,1rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:max(var(--ly-profile-gap),var(--ly-space-6));--ly-grid-gap:var(--ly-gap);--ly-stack-gap:var(--ly-space-5);--ly-cluster-gap:var(--ly-space-4);--ly-section-padding-block:clamp(3rem,7vh,6rem);--ly-section-padding-block-compact:clamp(1.5rem,3.5vh,3rem)}@media (max-height:44rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(0.75rem,2vh,1.25rem);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-gap:min(var(--ly-profile-gap),var(--ly-space-4));--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(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:var(--ly-space-5);--ly-grid-gap:var(--ly-space-5);--ly-stack-gap:var(--ly-space-4);--ly-cluster-gap:var(--ly-space-3);--ly-section-padding-block:clamp(1.5rem,6vh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3vh,1.25rem)}@supports (height:100dvh){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--ly-section-padding-block:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-section-padding-block:clamp(1.5rem,6dvh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3dvh,1.25rem)}}}@media (max-height:30rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-1);--ly-section-padding-block:var(--ly-space-3);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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-2);--ly-section-padding-block:var(--ly-space-4);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--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-3);--ly-section-padding-block:var(--ly-space-5);--ly-section-padding-block-compact:var(--ly-space-3)}}}@layer ly.wrappers{.ly-wrapper{--ly-wrapper-max:var(--ly-personality-wrapper-max,var(--ly-wrapper-content));--ly-wrapper-fluid-gutter:var(--ly-wrapper-gutter);--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--workspace{--ly-wrapper-max:var(--ly-wrapper-workspace)}.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,sticky);inset-block-start:0;z-index:var(--ly-z-header,20)}.ly-section{padding-block:var(--ly-section-padding-block)}.ly-section--compact{padding-block:var(--ly-section-padding-block-compact)}.ly-section--flush{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-mosaic{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--ly-grid-gap)}.ly-mosaic>*{min-inline-size:0;min-block-size:0}.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;overflow:auto;overscroll-behavior-block:contain}.ly-scroll--bounded{max-block-size:var(--ly-scroll-max)}.ly-scroll--viewport{max-block-size:var(--ly-scroll-viewport-max)}}@layer ly.context{.ly-mosaic:not([data-ly-responsive="manual"])>:where( .ly-span-1,.ly-span-2,.ly-span-3,.ly-span-4,.ly-span-6,.ly-span-full ){grid-column:1 / -1}.ly-mosaic:not([data-ly-responsive="manual"])>:where( .ly-row-span-2,.ly-row-span-3 ){grid-row:auto}@container ly-scope (min-width:42rem){.ly-mosaic:not([data-ly-responsive="manual"]){grid-template-columns:repeat( var(--ly-mosaic-medium-columns),minmax(0,1fr) )}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-1{grid-column:span 1}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-2{grid-column:span 2}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-3{grid-column:span 3}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-4{grid-column:span 4}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-6{grid-column:span 6}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-full{grid-column:1 / -1}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-row-span-2{grid-row:span 2}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-row-span-3{grid-row:span 3}}@container ly-scope (min-width:72rem){.ly-mosaic:not([data-ly-responsive="manual"]){grid-template-columns:repeat( var(--ly-mosaic-wide-columns),minmax(0,1fr) )}}}@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:var(--ly-app-shell-base-rows)}[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="gallery"],[data-ly-recipe="card-grid"] )[data-ly-responsive="manual"]{grid-template-columns:minmax(0,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);grid-template-rows:var(--ly-app-shell-medium-rows)}[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);grid-template-rows:var(--ly-app-shell-wide-rows)}[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-6{grid-column:span 6}.ly-span-full{grid-column:1 / -1}.ly-row-span-2{grid-row:span 2}.ly-row-span-3{grid-row:span 3}.ly-gap-0{gap:var(--ly-space-0)}.ly-gap-1{gap:var(--ly-space-1)}.ly-gap-2{gap:var(--ly-space-2)}.ly-gap-3{gap:var(--ly-space-3)}.ly-gap-4{gap:var(--ly-space-4)}.ly-gap-5{gap:var(--ly-space-5)}.ly-gap-6{gap:var(--ly-space-6)}.ly-gap-7{gap:var(--ly-space-7)}.ly-gap-8{gap:var(--ly-space-8)}.ly-gap-9{gap:var(--ly-space-9)}.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-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.3fr) minmax(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.28fr) minmax(min(100%,var(--ly-recipe-main-min)),1fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),0.5fr) minmax(min(100%,var(--ly-pane-min)),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-rows:auto minmax(0,1fr) auto auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-rail)),0.3fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),1.1fr) minmax(min(100%,var(--ly-pane-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1.35fr) minmax(min(100%,var(--ly-recipe-aside)),0.65fr);--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),1.8fr) minmax(min(100%,var(--ly-split-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-split-min)),1.5fr) minmax(min(100%,var(--ly-split-min)),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-rows:auto minmax(0,1fr) auto auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(0,1fr);--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),1fr) minmax(min(100%,var(--ly-split-min)),1fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),1fr) minmax(min(100%,var(--ly-pane-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.34fr);--ly-reel-item-min:20rem}} diff --git a/dist/primitives.css b/dist/primitives.css index d5b86c2..ae4ae38 100644 --- a/dist/primitives.css +++ b/dist/primitives.css @@ -115,6 +115,17 @@ grid-template-columns: repeat(var(--ly-grid-columns), minmax(0, 1fr)); } + .ly-mosaic { + display: grid; + grid-template-columns: minmax(0, 1fr); + gap: var(--ly-grid-gap); + } + + .ly-mosaic > * { + min-inline-size: 0; + min-block-size: 0; + } + .ly-split { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-split-min)), 1fr)); @@ -187,3 +198,77 @@ max-block-size: var(--ly-scroll-viewport-max); } } + +/* + Mosaic span behavior lives in the final structural context layer so it can + deliberately override the general-purpose span utilities at automatic tiers. +*/ +@layer ly.context { + .ly-mosaic:not([data-ly-responsive="manual"]) > :where( + .ly-span-1, + .ly-span-2, + .ly-span-3, + .ly-span-4, + .ly-span-6, + .ly-span-full + ) { + grid-column: 1 / -1; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > :where( + .ly-row-span-2, + .ly-row-span-3 + ) { + grid-row: auto; + } + + @container ly-scope (min-width: 42rem) { + .ly-mosaic:not([data-ly-responsive="manual"]) { + grid-template-columns: repeat( + var(--ly-mosaic-medium-columns), + minmax(0, 1fr) + ); + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-span-1 { + grid-column: span 1; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-span-2 { + grid-column: span 2; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-span-3 { + grid-column: span 3; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-span-4 { + grid-column: span 4; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-span-6 { + grid-column: span 6; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-span-full { + grid-column: 1 / -1; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-row-span-2 { + grid-row: span 2; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-row-span-3 { + grid-row: span 3; + } + } + + @container ly-scope (min-width: 72rem) { + .ly-mosaic:not([data-ly-responsive="manual"]) { + grid-template-columns: repeat( + var(--ly-mosaic-wide-columns), + minmax(0, 1fr) + ); + } + } +} diff --git a/dist/utilities.css b/dist/utilities.css index 959dae5..75409e1 100644 --- a/dist/utilities.css +++ b/dist/utilities.css @@ -14,7 +14,10 @@ .ly-span-2 { grid-column: span 2; } .ly-span-3 { grid-column: span 3; } .ly-span-4 { grid-column: span 4; } + .ly-span-6 { grid-column: span 6; } .ly-span-full { grid-column: 1 / -1; } + .ly-row-span-2 { grid-row: span 2; } + .ly-row-span-3 { grid-row: span 3; } .ly-gap-0 { gap: var(--ly-space-0); } .ly-gap-1 { gap: var(--ly-space-1); } diff --git a/manifest.json b/manifest.json index c6ba13f..58ed597 100644 --- a/manifest.json +++ b/manifest.json @@ -24,7 +24,7 @@ "deprecated": [] }, "wrappers": ["compact", "prose", "content", "workspace", "wide", "full", "breakout"], - "primitives": ["page", "header", "footer", "main", "section", "surface", "readable", "stack", "cluster", "center", "cover", "switcher", "sidebar", "grid", "split", "panes", "media", "reel", "frame", "scroll"], + "primitives": ["page", "header", "footer", "main", "section", "surface", "readable", "stack", "cluster", "center", "cover", "switcher", "sidebar", "grid", "mosaic", "split", "panes", "media", "reel", "frame", "scroll"], "recipes": ["app-shell", "dashboard", "docs", "list-detail", "split-hero", "gallery", "card-grid"], "areas": ["header", "nav", "sidebar", "main", "aside", "footer", "content", "media", "actions", "primary", "secondary"], "personalities": ["minimal-saas", "bento", "maximalist", "bauhaus", "tactile", "neumorphism", "retrofuturism", "brutalism", "cyberpunk", "y2k", "retro-glass", "f-pattern", "z-pattern", "split-screen", "mondrian", "synthwave"], @@ -73,6 +73,9 @@ "docs": { "wide": "48rem" }, "appShell": { "medium": "52rem", "wide": "72rem" }, "dashboard": { "medium": "52rem", "wide": "72rem" } + }, + "compositions": { + "mosaic": { "medium": "42rem", "wide": "72rem" } } }, "tokens": { @@ -88,7 +91,8 @@ "--ly-sticky-position", "--ly-cover-min", "--ly-shell-min", "--ly-scroll-max", "--ly-scroll-viewport-max", "--ly-switcher-threshold", "--ly-sidebar-size", - "--ly-sidebar-content-min", "--ly-grid-columns", "--ly-grid-min", "--ly-split-min", + "--ly-sidebar-content-min", "--ly-grid-columns", "--ly-grid-min", "--ly-mosaic-medium-columns", + "--ly-mosaic-wide-columns", "--ly-split-min", "--ly-pane-min", "--ly-pane-size", "--ly-media-min", "--ly-media-size", "--ly-reel-item-min", "--ly-reel-item-max", "--ly-frame-ratio", "--ly-split-primary", "--ly-split-secondary", "--ly-recipe-main-min", "--ly-recipe-rail", "--ly-recipe-aside", "--ly-gallery-min", diff --git a/styles/foundation.css b/styles/foundation.css index d3216b2..3a11d69 100644 --- a/styles/foundation.css +++ b/styles/foundation.css @@ -51,6 +51,8 @@ --ly-sidebar-content-min: 50%; --ly-grid-columns: 12; --ly-grid-min: 16rem; + --ly-mosaic-medium-columns: 6; + --ly-mosaic-wide-columns: 12; --ly-split-min: 20rem; --ly-pane-min: 18rem; --ly-pane-size: 22rem; diff --git a/styles/primitives.css b/styles/primitives.css index d5b86c2..ae4ae38 100644 --- a/styles/primitives.css +++ b/styles/primitives.css @@ -115,6 +115,17 @@ grid-template-columns: repeat(var(--ly-grid-columns), minmax(0, 1fr)); } + .ly-mosaic { + display: grid; + grid-template-columns: minmax(0, 1fr); + gap: var(--ly-grid-gap); + } + + .ly-mosaic > * { + min-inline-size: 0; + min-block-size: 0; + } + .ly-split { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-split-min)), 1fr)); @@ -187,3 +198,77 @@ max-block-size: var(--ly-scroll-viewport-max); } } + +/* + Mosaic span behavior lives in the final structural context layer so it can + deliberately override the general-purpose span utilities at automatic tiers. +*/ +@layer ly.context { + .ly-mosaic:not([data-ly-responsive="manual"]) > :where( + .ly-span-1, + .ly-span-2, + .ly-span-3, + .ly-span-4, + .ly-span-6, + .ly-span-full + ) { + grid-column: 1 / -1; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > :where( + .ly-row-span-2, + .ly-row-span-3 + ) { + grid-row: auto; + } + + @container ly-scope (min-width: 42rem) { + .ly-mosaic:not([data-ly-responsive="manual"]) { + grid-template-columns: repeat( + var(--ly-mosaic-medium-columns), + minmax(0, 1fr) + ); + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-span-1 { + grid-column: span 1; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-span-2 { + grid-column: span 2; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-span-3 { + grid-column: span 3; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-span-4 { + grid-column: span 4; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-span-6 { + grid-column: span 6; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-span-full { + grid-column: 1 / -1; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-row-span-2 { + grid-row: span 2; + } + + .ly-mosaic:not([data-ly-responsive="manual"]) > .ly-row-span-3 { + grid-row: span 3; + } + } + + @container ly-scope (min-width: 72rem) { + .ly-mosaic:not([data-ly-responsive="manual"]) { + grid-template-columns: repeat( + var(--ly-mosaic-wide-columns), + minmax(0, 1fr) + ); + } + } +} diff --git a/styles/utilities.css b/styles/utilities.css index 959dae5..75409e1 100644 --- a/styles/utilities.css +++ b/styles/utilities.css @@ -14,7 +14,10 @@ .ly-span-2 { grid-column: span 2; } .ly-span-3 { grid-column: span 3; } .ly-span-4 { grid-column: span 4; } + .ly-span-6 { grid-column: span 6; } .ly-span-full { grid-column: 1 / -1; } + .ly-row-span-2 { grid-row: span 2; } + .ly-row-span-3 { grid-row: span 3; } .ly-gap-0 { gap: var(--ly-space-0); } .ly-gap-1 { gap: var(--ly-space-1); } diff --git a/test/demo-smoke.test.mjs b/test/demo-smoke.test.mjs index 9d51812..579a291 100644 --- a/test/demo-smoke.test.mjs +++ b/test/demo-smoke.test.mjs @@ -531,6 +531,121 @@ const verifyContentResilience = async (page, baseUrl) => { } }; +/** + * Verifies Mosaic track tiers, span collapse, manual ownership, DOM order, and + * nearest-container behavior across every threshold-adjacent allocation. + * + * @param {import("@playwright/test").Page} page Active browser page. + * @param {string} baseUrl Demo server URL. + * @returns {Promise} + */ +const verifyMosaicComposition = async (page, baseUrl) => { + await page.setViewportSize({ width: 1920, height: 1080 }); + await page.goto(`${baseUrl}?ecosystem=layout-only&wrapper=full`, { + waitUntil: "domcontentloaded" + }); + await page.waitForFunction(() => document.body.dataset.demoReady === "true"); + + await setCustomAllocation(page, "80rem"); + for (const scenario of [ + { width: "32rem", tracks: 1, spansActive: false }, + { width: "43rem", tracks: 6, spansActive: true }, + { width: "71rem", tracks: 6, spansActive: true }, + { width: "73rem", tracks: 12, spansActive: true } + ]) { + const snapshot = await page.evaluate((scopeWidth) => { + const wrapper = document.querySelector("#previewWrapper"); + wrapper.style.setProperty("--ly-wrapper-local-gutter", "0px"); + wrapper.style.inlineSize = scopeWidth; + const mosaic = document.createElement("section"); + mosaic.className = "ly-mosaic"; + const definitions = [ + ["ly-span-2", "two"], + ["ly-span-4 ly-row-span-2", "four"], + ["ly-span-6 ly-row-span-3", "six"], + ["ly-span-full", "full"] + ]; + + for (const [className, label] of definitions) { + const item = document.createElement("article"); + item.className = className; + const action = document.createElement("button"); + action.type = "button"; + action.dataset.mosaicFocus = label; + action.textContent = label; + item.append(action); + mosaic.append(item); + } + + wrapper.replaceChildren(mosaic); + const items = [...mosaic.children]; + const style = getComputedStyle(mosaic); + return { + scopeWidth: wrapper.getBoundingClientRect().width, + tracks: style.gridTemplateColumns.split(/\s+/).filter(Boolean).length, + overflow: mosaic.scrollWidth - mosaic.clientWidth, + mosaicWidth: mosaic.getBoundingClientRect().width, + fullWidth: items.at(-1).getBoundingClientRect().width, + spanTwo: getComputedStyle(items[0]).gridColumn, + rowTwo: getComputedStyle(items[1]).gridRow, + rowThree: getComputedStyle(items[2]).gridRow, + domOrder: items.map((item) => item.querySelector("button").dataset.mosaicFocus), + focusOrder: [...mosaic.querySelectorAll("button")].map( + (button) => button.dataset.mosaicFocus + ) + }; + }, scenario.width); + + assert.equal( + snapshot.tracks, + scenario.tracks, + `${scenario.width} Mosaic track count drifted at ${snapshot.scopeWidth}px.` + ); + assert(snapshot.overflow <= 2, `${scenario.width} Mosaic overflowed by ${snapshot.overflow}px.`); + assert( + Math.abs(snapshot.fullWidth - snapshot.mosaicWidth) <= 2, + `${scenario.width} full-span item did not cover the Mosaic.` + ); + assert.deepEqual(snapshot.focusOrder, snapshot.domOrder, "Mosaic focus order drifted from DOM order."); + if (scenario.spansActive) { + assert.match(snapshot.spanTwo, /span 2/); + assert.match(snapshot.rowTwo, /span 2/); + assert.match(snapshot.rowThree, /span 3/); + } else { + assert.match(snapshot.spanTwo, /1 \/ -1/); + assert(!/span 2/.test(snapshot.rowTwo)); + assert(!/span 3/.test(snapshot.rowThree)); + } + } + + await setCustomAllocation(page, "73rem"); + const ownership = await page.evaluate(() => { + const wrapper = document.querySelector("#previewWrapper"); + const manual = document.createElement("section"); + manual.className = "ly-mosaic"; + manual.dataset.lyResponsive = "manual"; + manual.style.gridTemplateColumns = "repeat(3, minmax(0, 1fr))"; + manual.append(document.createElement("div"), document.createElement("div")); + + const nestedScope = document.createElement("div"); + nestedScope.className = "ly-root"; + nestedScope.style.inlineSize = "32rem"; + const nested = document.createElement("section"); + nested.className = "ly-mosaic"; + nested.append(document.createElement("div"), document.createElement("div")); + nestedScope.append(nested); + wrapper.replaceChildren(manual, nestedScope); + + return { + manualTracks: getComputedStyle(manual).gridTemplateColumns.split(/\s+/).filter(Boolean).length, + nestedTracks: getComputedStyle(nested).gridTemplateColumns.split(/\s+/).filter(Boolean).length + }; + }); + + assert.equal(ownership.manualTracks, 3, "Manual Mosaic must retain application-owned tracks."); + assert.equal(ownership.nestedTracks, 1, "Nested Mosaic must use its nearest layout scope."); +}; + const installExternalFixtures = async (page) => { await page.route("https://unpkg.com/**", async (route) => { const url = route.request().url(); @@ -1663,6 +1778,7 @@ try { await verifyBreakoutGeometry(page, server.baseUrl); await verifyProfileAndUtilityIsolation(page, server.baseUrl); await verifyContentResilience(page, server.baseUrl); + await verifyMosaicComposition(page, server.baseUrl); await verifyPrimitiveOverflow(page, server.baseUrl); await verifyCodeBlockContrast(page, server.baseUrl); await verifyInteractions(page, server.baseUrl); diff --git a/test/layout-css-contract.test.mjs b/test/layout-css-contract.test.mjs index 40404a0..888bdec 100644 --- a/test/layout-css-contract.test.mjs +++ b/test/layout-css-contract.test.mjs @@ -308,6 +308,7 @@ for (const primitive of [ "switcher", "sidebar", "grid", + "mosaic", "split", "panes", "media", @@ -318,7 +319,15 @@ for (const primitive of [ assert(primitives.includes(`.ly-${primitive}`), `Missing composition primitive: ${primitive}`); } 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"); +assert.deepEqual( + [...primitives.matchAll(/@container ly-scope \(min-width: ([^)]+)\)/g)].map(([, width]) => width), + ["42rem", "72rem"], + "Only Mosaic may use the approved shared primitive thresholds." +); +assert( + !/grid-auto-flow:\s*dense/.test(primitives), + "Mosaic must preserve DOM reading and focus order." +); assert( /--ly-cover-min:\s*100vh/.test(foundation) && /--ly-shell-min:\s*100vh/.test(foundation) && @@ -465,6 +474,9 @@ assert(!/\bly-(?:md|lg)-/.test(utilities), "Fixed responsive utility families mu 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"); +for (const utility of ["ly-span-6", "ly-row-span-2", "ly-row-span-3"]) { + assert(utilities.includes(`.${utility}`), `Missing Mosaic utility: ${utility}`); +} for (let gap = 0; gap <= 9; gap += 1) { const rule = utilities.match(new RegExp(`\\.ly-gap-${gap}\\s*\\{([^}]*)\\}`))?.[1] ?? ""; assert( diff --git a/test/manifest-contract.test.mjs b/test/manifest-contract.test.mjs index 4ee0c6a..cc137b1 100644 --- a/test/manifest-contract.test.mjs +++ b/test/manifest-contract.test.mjs @@ -58,7 +58,8 @@ const geometryTokens = [ "--ly-sticky-position", "--ly-cover-min", "--ly-shell-min", "--ly-scroll-max", "--ly-scroll-viewport-max", "--ly-switcher-threshold", "--ly-sidebar-size", - "--ly-sidebar-content-min", "--ly-grid-columns", "--ly-grid-min", "--ly-split-min", + "--ly-sidebar-content-min", "--ly-grid-columns", "--ly-grid-min", "--ly-mosaic-medium-columns", + "--ly-mosaic-wide-columns", "--ly-split-min", "--ly-pane-min", "--ly-pane-size", "--ly-media-min", "--ly-media-size", "--ly-reel-item-min", "--ly-reel-item-max", "--ly-frame-ratio", "--ly-split-primary", "--ly-split-secondary", "--ly-recipe-main-min", "--ly-recipe-rail", "--ly-recipe-aside", "--ly-gallery-min", @@ -225,7 +226,8 @@ test("ecosystem manifest describes real structural selectors, thresholds, and to ]); assert.deepEqual(manifest.primitives, [ "page", "header", "footer", "main", "section", "surface", "readable", "stack", "cluster", - "center", "cover", "switcher", "sidebar", "grid", "split", "panes", "media", "reel", "frame", "scroll" + "center", "cover", "switcher", "sidebar", "grid", "mosaic", "split", "panes", "media", + "reel", "frame", "scroll" ]); assert.deepEqual(manifest.recipes, [ "app-shell", "dashboard", "docs", "list-detail", "split-hero", "gallery", "card-grid" @@ -244,6 +246,9 @@ test("ecosystem manifest describes real structural selectors, thresholds, and to docs: { wide: "48rem" }, appShell: { medium: "52rem", wide: "72rem" }, dashboard: { medium: "52rem", wide: "72rem" } + }, + compositions: { + mosaic: { medium: "42rem", wide: "72rem" } } }); const recipesCss = readFileSync(join(root, "styles", "recipes.css"), "utf8"); From 7bbf76c57b9691163910ae45d08ed36ab157cae5 Mon Sep 17 00:00:00 2001 From: Foscat Date: Thu, 3 Sep 2026 09:17:06 -0500 Subject: [PATCH 04/11] feat: add workflow action bar composition --- dist/layout-style-css.css | 27 ++++++++++ dist/layout-style-css.min.css | 2 +- dist/primitives.css | 27 ++++++++++ manifest.json | 2 +- styles/primitives.css | 27 ++++++++++ test/demo-smoke.test.mjs | 88 +++++++++++++++++++++++++++++++ test/layout-css-contract.test.mjs | 19 +++++++ test/manifest-contract.test.mjs | 4 +- 8 files changed, 192 insertions(+), 4 deletions(-) diff --git a/dist/layout-style-css.css b/dist/layout-style-css.css index 8355376..cada81e 100644 --- a/dist/layout-style-css.css +++ b/dist/layout-style-css.css @@ -572,6 +572,33 @@ min-block-size: 0; } + .ly-action-bar { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: var(--ly-cluster-gap); + min-inline-size: 0; + padding-block-end: var(--ly-safe-area-block-end); + } + + .ly-action-bar > :where([data-ly-actions="start"], [data-ly-actions="end"]) { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: var(--ly-cluster-gap); + min-inline-size: 0; + } + + .ly-action-bar > [data-ly-actions="end"] { + margin-inline-start: auto; + } + + .ly-action-bar--sticky { + position: var(--ly-sticky-position, sticky); + inset-block-end: 0; + z-index: var(--ly-z-header, 20); + } + .ly-split { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-split-min)), 1fr)); diff --git a/dist/layout-style-css.min.css b/dist/layout-style-css.min.css index 2629ad6..1473910 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.context;@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-workspace:96rem;--ly-wrapper-wide:112rem;--ly-page-padding-inline:clamp(1rem,3vw,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:var(--ly-page-padding-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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem);--ly-header-height:4.5rem;--ly-sticky-position:sticky;--ly-cover-min:100vh;--ly-shell-min:100vh;--ly-scroll-max:50rem;--ly-scroll-viewport-max:min(70vh,50rem);--ly-switcher-threshold:42rem;--ly-sidebar-size:18rem;--ly-sidebar-content-min:50%;--ly-grid-columns:12;--ly-grid-min:16rem;--ly-mosaic-medium-columns:6;--ly-mosaic-wide-columns:12;--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-split-primary:1fr;--ly-split-secondary:1fr;--ly-recipe-main-min:20rem;--ly-recipe-rail:18rem;--ly-recipe-aside:22rem;--ly-gallery-min:12rem;--ly-card-grid-min:16rem;--ly-app-shell-base-rows:auto auto minmax(0,1fr) auto auto;--ly-app-shell-medium-areas:"header header" "sidebar main" "aside main" "footer footer";--ly-app-shell-medium-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-medium-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),1fr);--ly-app-shell-wide-areas:"sidebar header header" "sidebar main aside" "sidebar footer footer";--ly-app-shell-wide-rows:auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1fr);--ly-list-detail-wide-areas:"primary secondary" "actions actions";--ly-list-detail-wide-columns:minmax(min(100%,max(var(--ly-pane-min),var(--ly-pane-size))),0.7fr) minmax(min(100%,var(--ly-pane-min)),1fr);--ly-split-hero-wide-areas:"content media" "actions media";--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),var(--ly-split-primary,1fr)) minmax(min(100%,var(--ly-split-min)),var(--ly-split-secondary,1fr));container-name:ly-scope;container-type:inline-size;min-inline-size:0;min-block-size:0}@supports (width:1cqi){:where(.ly-root){--ly-page-padding-inline:clamp(1rem,3cqi,3rem)}}@supports (height:100dvh){:where(.ly-root){--ly-cover-min:100dvh;--ly-shell-min:100dvh;--ly-scroll-viewport-max:min(70dvh,50rem)}}}@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),3vh);--ly-cluster-gap:min(var(--ly-space-3),2vh);--ly-section-padding-block:clamp(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem);--ly-header-height:3.5rem;--ly-scroll-viewport-max:min(62vh,34rem)}@supports (height:100dvh){:where(.ly-root){--ly-stack-gap:min(var(--ly-space-4),3dvh);--ly-cluster-gap:min(var(--ly-space-3),2dvh);--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem);--ly-scroll-viewport-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-4);--ly-section-padding-block-compact:var(--ly-space-2);--ly-scroll-viewport-max:max(12rem,calc(100vh - 8rem))}@supports (height:100dvh){:where(.ly-root){--ly-scroll-viewport-max:max(12rem,calc(100dvh - 8rem))}}}}@layer ly.context{:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(1rem,2.5vh,2rem);--ly-section-padding-block-compact:clamp(0.5rem,1.5vh,1rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:max(var(--ly-profile-gap),var(--ly-space-6));--ly-grid-gap:var(--ly-gap);--ly-stack-gap:var(--ly-space-5);--ly-cluster-gap:var(--ly-space-4);--ly-section-padding-block:clamp(3rem,7vh,6rem);--ly-section-padding-block-compact:clamp(1.5rem,3.5vh,3rem)}@media (max-height:44rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(0.75rem,2vh,1.25rem);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-gap:min(var(--ly-profile-gap),var(--ly-space-4));--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(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:var(--ly-space-5);--ly-grid-gap:var(--ly-space-5);--ly-stack-gap:var(--ly-space-4);--ly-cluster-gap:var(--ly-space-3);--ly-section-padding-block:clamp(1.5rem,6vh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3vh,1.25rem)}@supports (height:100dvh){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--ly-section-padding-block:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-section-padding-block:clamp(1.5rem,6dvh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3dvh,1.25rem)}}}@media (max-height:30rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-1);--ly-section-padding-block:var(--ly-space-3);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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-2);--ly-section-padding-block:var(--ly-space-4);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--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-3);--ly-section-padding-block:var(--ly-space-5);--ly-section-padding-block-compact:var(--ly-space-3)}}}@layer ly.wrappers{.ly-wrapper{--ly-wrapper-max:var(--ly-personality-wrapper-max,var(--ly-wrapper-content));--ly-wrapper-fluid-gutter:var(--ly-wrapper-gutter);--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--workspace{--ly-wrapper-max:var(--ly-wrapper-workspace)}.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,sticky);inset-block-start:0;z-index:var(--ly-z-header,20)}.ly-section{padding-block:var(--ly-section-padding-block)}.ly-section--compact{padding-block:var(--ly-section-padding-block-compact)}.ly-section--flush{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-mosaic{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--ly-grid-gap)}.ly-mosaic>*{min-inline-size:0;min-block-size:0}.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;overflow:auto;overscroll-behavior-block:contain}.ly-scroll--bounded{max-block-size:var(--ly-scroll-max)}.ly-scroll--viewport{max-block-size:var(--ly-scroll-viewport-max)}}@layer ly.context{.ly-mosaic:not([data-ly-responsive="manual"])>:where( .ly-span-1,.ly-span-2,.ly-span-3,.ly-span-4,.ly-span-6,.ly-span-full ){grid-column:1 / -1}.ly-mosaic:not([data-ly-responsive="manual"])>:where( .ly-row-span-2,.ly-row-span-3 ){grid-row:auto}@container ly-scope (min-width:42rem){.ly-mosaic:not([data-ly-responsive="manual"]){grid-template-columns:repeat( var(--ly-mosaic-medium-columns),minmax(0,1fr) )}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-1{grid-column:span 1}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-2{grid-column:span 2}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-3{grid-column:span 3}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-4{grid-column:span 4}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-6{grid-column:span 6}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-full{grid-column:1 / -1}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-row-span-2{grid-row:span 2}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-row-span-3{grid-row:span 3}}@container ly-scope (min-width:72rem){.ly-mosaic:not([data-ly-responsive="manual"]){grid-template-columns:repeat( var(--ly-mosaic-wide-columns),minmax(0,1fr) )}}}@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:var(--ly-app-shell-base-rows)}[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="gallery"],[data-ly-recipe="card-grid"] )[data-ly-responsive="manual"]{grid-template-columns:minmax(0,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);grid-template-rows:var(--ly-app-shell-medium-rows)}[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);grid-template-rows:var(--ly-app-shell-wide-rows)}[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-6{grid-column:span 6}.ly-span-full{grid-column:1 / -1}.ly-row-span-2{grid-row:span 2}.ly-row-span-3{grid-row:span 3}.ly-gap-0{gap:var(--ly-space-0)}.ly-gap-1{gap:var(--ly-space-1)}.ly-gap-2{gap:var(--ly-space-2)}.ly-gap-3{gap:var(--ly-space-3)}.ly-gap-4{gap:var(--ly-space-4)}.ly-gap-5{gap:var(--ly-space-5)}.ly-gap-6{gap:var(--ly-space-6)}.ly-gap-7{gap:var(--ly-space-7)}.ly-gap-8{gap:var(--ly-space-8)}.ly-gap-9{gap:var(--ly-space-9)}.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-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.3fr) minmax(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.28fr) minmax(min(100%,var(--ly-recipe-main-min)),1fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),0.5fr) minmax(min(100%,var(--ly-pane-min)),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-rows:auto minmax(0,1fr) auto auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-rail)),0.3fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),1.1fr) minmax(min(100%,var(--ly-pane-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1.35fr) minmax(min(100%,var(--ly-recipe-aside)),0.65fr);--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),1.8fr) minmax(min(100%,var(--ly-split-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-split-min)),1.5fr) minmax(min(100%,var(--ly-split-min)),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-rows:auto minmax(0,1fr) auto auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(0,1fr);--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),1fr) minmax(min(100%,var(--ly-split-min)),1fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),1fr) minmax(min(100%,var(--ly-pane-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.34fr);--ly-reel-item-min:20rem}} +@layer ly.reset,ly.tokens,ly.wrappers,ly.primitives,ly.recipes,ly.utilities,ly.personalities,ly.context;@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-workspace:96rem;--ly-wrapper-wide:112rem;--ly-page-padding-inline:clamp(1rem,3vw,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:var(--ly-page-padding-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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem);--ly-header-height:4.5rem;--ly-sticky-position:sticky;--ly-cover-min:100vh;--ly-shell-min:100vh;--ly-scroll-max:50rem;--ly-scroll-viewport-max:min(70vh,50rem);--ly-switcher-threshold:42rem;--ly-sidebar-size:18rem;--ly-sidebar-content-min:50%;--ly-grid-columns:12;--ly-grid-min:16rem;--ly-mosaic-medium-columns:6;--ly-mosaic-wide-columns:12;--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-split-primary:1fr;--ly-split-secondary:1fr;--ly-recipe-main-min:20rem;--ly-recipe-rail:18rem;--ly-recipe-aside:22rem;--ly-gallery-min:12rem;--ly-card-grid-min:16rem;--ly-app-shell-base-rows:auto auto minmax(0,1fr) auto auto;--ly-app-shell-medium-areas:"header header" "sidebar main" "aside main" "footer footer";--ly-app-shell-medium-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-medium-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),1fr);--ly-app-shell-wide-areas:"sidebar header header" "sidebar main aside" "sidebar footer footer";--ly-app-shell-wide-rows:auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1fr);--ly-list-detail-wide-areas:"primary secondary" "actions actions";--ly-list-detail-wide-columns:minmax(min(100%,max(var(--ly-pane-min),var(--ly-pane-size))),0.7fr) minmax(min(100%,var(--ly-pane-min)),1fr);--ly-split-hero-wide-areas:"content media" "actions media";--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),var(--ly-split-primary,1fr)) minmax(min(100%,var(--ly-split-min)),var(--ly-split-secondary,1fr));container-name:ly-scope;container-type:inline-size;min-inline-size:0;min-block-size:0}@supports (width:1cqi){:where(.ly-root){--ly-page-padding-inline:clamp(1rem,3cqi,3rem)}}@supports (height:100dvh){:where(.ly-root){--ly-cover-min:100dvh;--ly-shell-min:100dvh;--ly-scroll-viewport-max:min(70dvh,50rem)}}}@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),3vh);--ly-cluster-gap:min(var(--ly-space-3),2vh);--ly-section-padding-block:clamp(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem);--ly-header-height:3.5rem;--ly-scroll-viewport-max:min(62vh,34rem)}@supports (height:100dvh){:where(.ly-root){--ly-stack-gap:min(var(--ly-space-4),3dvh);--ly-cluster-gap:min(var(--ly-space-3),2dvh);--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem);--ly-scroll-viewport-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-4);--ly-section-padding-block-compact:var(--ly-space-2);--ly-scroll-viewport-max:max(12rem,calc(100vh - 8rem))}@supports (height:100dvh){:where(.ly-root){--ly-scroll-viewport-max:max(12rem,calc(100dvh - 8rem))}}}}@layer ly.context{:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(1rem,2.5vh,2rem);--ly-section-padding-block-compact:clamp(0.5rem,1.5vh,1rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:max(var(--ly-profile-gap),var(--ly-space-6));--ly-grid-gap:var(--ly-gap);--ly-stack-gap:var(--ly-space-5);--ly-cluster-gap:var(--ly-space-4);--ly-section-padding-block:clamp(3rem,7vh,6rem);--ly-section-padding-block-compact:clamp(1.5rem,3.5vh,3rem)}@media (max-height:44rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(0.75rem,2vh,1.25rem);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-gap:min(var(--ly-profile-gap),var(--ly-space-4));--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(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:var(--ly-space-5);--ly-grid-gap:var(--ly-space-5);--ly-stack-gap:var(--ly-space-4);--ly-cluster-gap:var(--ly-space-3);--ly-section-padding-block:clamp(1.5rem,6vh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3vh,1.25rem)}@supports (height:100dvh){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--ly-section-padding-block:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-section-padding-block:clamp(1.5rem,6dvh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3dvh,1.25rem)}}}@media (max-height:30rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-1);--ly-section-padding-block:var(--ly-space-3);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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-2);--ly-section-padding-block:var(--ly-space-4);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--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-3);--ly-section-padding-block:var(--ly-space-5);--ly-section-padding-block-compact:var(--ly-space-3)}}}@layer ly.wrappers{.ly-wrapper{--ly-wrapper-max:var(--ly-personality-wrapper-max,var(--ly-wrapper-content));--ly-wrapper-fluid-gutter:var(--ly-wrapper-gutter);--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--workspace{--ly-wrapper-max:var(--ly-wrapper-workspace)}.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,sticky);inset-block-start:0;z-index:var(--ly-z-header,20)}.ly-section{padding-block:var(--ly-section-padding-block)}.ly-section--compact{padding-block:var(--ly-section-padding-block-compact)}.ly-section--flush{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-mosaic{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--ly-grid-gap)}.ly-mosaic>*{min-inline-size:0;min-block-size:0}.ly-action-bar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ly-cluster-gap);min-inline-size:0;padding-block-end:var(--ly-safe-area-block-end)}.ly-action-bar>:where([data-ly-actions="start"],[data-ly-actions="end"]){display:flex;flex-wrap:wrap;align-items:center;gap:var(--ly-cluster-gap);min-inline-size:0}.ly-action-bar>[data-ly-actions="end"]{margin-inline-start:auto}.ly-action-bar--sticky{position:var(--ly-sticky-position,sticky);inset-block-end:0;z-index:var(--ly-z-header,20)}.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;overflow:auto;overscroll-behavior-block:contain}.ly-scroll--bounded{max-block-size:var(--ly-scroll-max)}.ly-scroll--viewport{max-block-size:var(--ly-scroll-viewport-max)}}@layer ly.context{.ly-mosaic:not([data-ly-responsive="manual"])>:where( .ly-span-1,.ly-span-2,.ly-span-3,.ly-span-4,.ly-span-6,.ly-span-full ){grid-column:1 / -1}.ly-mosaic:not([data-ly-responsive="manual"])>:where( .ly-row-span-2,.ly-row-span-3 ){grid-row:auto}@container ly-scope (min-width:42rem){.ly-mosaic:not([data-ly-responsive="manual"]){grid-template-columns:repeat( var(--ly-mosaic-medium-columns),minmax(0,1fr) )}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-1{grid-column:span 1}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-2{grid-column:span 2}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-3{grid-column:span 3}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-4{grid-column:span 4}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-6{grid-column:span 6}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-full{grid-column:1 / -1}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-row-span-2{grid-row:span 2}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-row-span-3{grid-row:span 3}}@container ly-scope (min-width:72rem){.ly-mosaic:not([data-ly-responsive="manual"]){grid-template-columns:repeat( var(--ly-mosaic-wide-columns),minmax(0,1fr) )}}}@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:var(--ly-app-shell-base-rows)}[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="gallery"],[data-ly-recipe="card-grid"] )[data-ly-responsive="manual"]{grid-template-columns:minmax(0,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);grid-template-rows:var(--ly-app-shell-medium-rows)}[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);grid-template-rows:var(--ly-app-shell-wide-rows)}[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-6{grid-column:span 6}.ly-span-full{grid-column:1 / -1}.ly-row-span-2{grid-row:span 2}.ly-row-span-3{grid-row:span 3}.ly-gap-0{gap:var(--ly-space-0)}.ly-gap-1{gap:var(--ly-space-1)}.ly-gap-2{gap:var(--ly-space-2)}.ly-gap-3{gap:var(--ly-space-3)}.ly-gap-4{gap:var(--ly-space-4)}.ly-gap-5{gap:var(--ly-space-5)}.ly-gap-6{gap:var(--ly-space-6)}.ly-gap-7{gap:var(--ly-space-7)}.ly-gap-8{gap:var(--ly-space-8)}.ly-gap-9{gap:var(--ly-space-9)}.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-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.3fr) minmax(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.28fr) minmax(min(100%,var(--ly-recipe-main-min)),1fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),0.5fr) minmax(min(100%,var(--ly-pane-min)),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-rows:auto minmax(0,1fr) auto auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-rail)),0.3fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),1.1fr) minmax(min(100%,var(--ly-pane-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1.35fr) minmax(min(100%,var(--ly-recipe-aside)),0.65fr);--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),1.8fr) minmax(min(100%,var(--ly-split-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-split-min)),1.5fr) minmax(min(100%,var(--ly-split-min)),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-rows:auto minmax(0,1fr) auto auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(0,1fr);--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),1fr) minmax(min(100%,var(--ly-split-min)),1fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),1fr) minmax(min(100%,var(--ly-pane-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.34fr);--ly-reel-item-min:20rem}} diff --git a/dist/primitives.css b/dist/primitives.css index ae4ae38..7c314d9 100644 --- a/dist/primitives.css +++ b/dist/primitives.css @@ -126,6 +126,33 @@ min-block-size: 0; } + .ly-action-bar { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: var(--ly-cluster-gap); + min-inline-size: 0; + padding-block-end: var(--ly-safe-area-block-end); + } + + .ly-action-bar > :where([data-ly-actions="start"], [data-ly-actions="end"]) { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: var(--ly-cluster-gap); + min-inline-size: 0; + } + + .ly-action-bar > [data-ly-actions="end"] { + margin-inline-start: auto; + } + + .ly-action-bar--sticky { + position: var(--ly-sticky-position, sticky); + inset-block-end: 0; + z-index: var(--ly-z-header, 20); + } + .ly-split { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-split-min)), 1fr)); diff --git a/manifest.json b/manifest.json index 58ed597..bf3c627 100644 --- a/manifest.json +++ b/manifest.json @@ -24,7 +24,7 @@ "deprecated": [] }, "wrappers": ["compact", "prose", "content", "workspace", "wide", "full", "breakout"], - "primitives": ["page", "header", "footer", "main", "section", "surface", "readable", "stack", "cluster", "center", "cover", "switcher", "sidebar", "grid", "mosaic", "split", "panes", "media", "reel", "frame", "scroll"], + "primitives": ["page", "header", "footer", "main", "section", "surface", "readable", "stack", "cluster", "center", "cover", "switcher", "sidebar", "grid", "mosaic", "action-bar", "split", "panes", "media", "reel", "frame", "scroll"], "recipes": ["app-shell", "dashboard", "docs", "list-detail", "split-hero", "gallery", "card-grid"], "areas": ["header", "nav", "sidebar", "main", "aside", "footer", "content", "media", "actions", "primary", "secondary"], "personalities": ["minimal-saas", "bento", "maximalist", "bauhaus", "tactile", "neumorphism", "retrofuturism", "brutalism", "cyberpunk", "y2k", "retro-glass", "f-pattern", "z-pattern", "split-screen", "mondrian", "synthwave"], diff --git a/styles/primitives.css b/styles/primitives.css index ae4ae38..7c314d9 100644 --- a/styles/primitives.css +++ b/styles/primitives.css @@ -126,6 +126,33 @@ min-block-size: 0; } + .ly-action-bar { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: var(--ly-cluster-gap); + min-inline-size: 0; + padding-block-end: var(--ly-safe-area-block-end); + } + + .ly-action-bar > :where([data-ly-actions="start"], [data-ly-actions="end"]) { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: var(--ly-cluster-gap); + min-inline-size: 0; + } + + .ly-action-bar > [data-ly-actions="end"] { + margin-inline-start: auto; + } + + .ly-action-bar--sticky { + position: var(--ly-sticky-position, sticky); + inset-block-end: 0; + z-index: var(--ly-z-header, 20); + } + .ly-split { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--ly-split-min)), 1fr)); diff --git a/test/demo-smoke.test.mjs b/test/demo-smoke.test.mjs index 579a291..4794ba6 100644 --- a/test/demo-smoke.test.mjs +++ b/test/demo-smoke.test.mjs @@ -646,6 +646,93 @@ const verifyMosaicComposition = async (page, baseUrl) => { assert.equal(ownership.nestedTracks, 1, "Nested Mosaic must use its nearest layout scope."); }; +/** + * Verifies Action Bar alignment, intrinsic wrapping, focus order, safe-area + * padding, and shallow-height sticky fallback. + * + * @param {import("@playwright/test").Page} page Active browser page. + * @param {string} baseUrl Demo server URL. + * @returns {Promise} + */ +const verifyActionBarComposition = async (page, baseUrl) => { + await page.setViewportSize({ width: 1440, height: 900 }); + await page.goto(`${baseUrl}?ecosystem=layout-only&wrapper=full`, { + waitUntil: "domcontentloaded" + }); + await page.waitForFunction(() => document.body.dataset.demoReady === "true"); + await setCustomAllocation(page, "53rem"); + + const wide = await page.evaluate(() => { + const wrapper = document.querySelector("#previewWrapper"); + wrapper.style.setProperty("--ly-safe-area-block-end", "12px"); + const actionBar = document.createElement("div"); + actionBar.className = "ly-action-bar ly-action-bar--sticky"; + + for (const groupName of ["start", "end"]) { + const group = document.createElement("div"); + group.dataset.lyActions = groupName; + const action = document.createElement("button"); + action.type = "button"; + action.dataset.actionFocus = groupName; + action.textContent = groupName === "start" ? "Cancel workflow" : "Publish changes"; + group.append(action); + actionBar.append(group); + } + + wrapper.replaceChildren(actionBar); + const [start, end] = actionBar.children; + const barRect = actionBar.getBoundingClientRect(); + const startRect = start.getBoundingClientRect(); + const endRect = end.getBoundingClientRect(); + const style = getComputedStyle(actionBar); + return { + sameRow: Math.abs(startRect.top - endRect.top) <= 1, + logicalEndGap: Math.abs(barRect.right - endRect.right), + paddingBlockEnd: style.paddingBlockEnd, + position: style.position, + domOrder: [...actionBar.querySelectorAll("button")].map( + (button) => button.dataset.actionFocus + ) + }; + }); + + assert(wide.sameRow, "Action groups must share a row when allocation permits."); + assert(wide.logicalEndGap <= 1, "End actions must reach logical inline-end."); + assert.equal(wide.paddingBlockEnd, "12px", "Action Bar must honor safe-area padding."); + assert.equal(wide.position, "sticky", "Regular-height Action Bar must remain sticky."); + assert.deepEqual(wide.domOrder, ["start", "end"]); + + const narrow = await page.evaluate(() => { + const wrapper = document.querySelector("#previewWrapper"); + const actionBar = wrapper.querySelector(".ly-action-bar"); + wrapper.style.inlineSize = "20rem"; + for (const group of actionBar.children) group.style.inlineSize = "12rem"; + const [start, end] = actionBar.children; + return { + wrapped: end.getBoundingClientRect().top > start.getBoundingClientRect().top + 1, + domOrder: [...actionBar.querySelectorAll("button")].map( + (button) => button.dataset.actionFocus + ), + orderValues: [...actionBar.children].map((group) => getComputedStyle(group).order) + }; + }); + + assert(narrow.wrapped, "Action groups must wrap when their intrinsic widths no longer fit."); + assert.deepEqual(narrow.domOrder, ["start", "end"], "Action Bar must retain DOM focus order."); + assert.deepEqual(narrow.orderValues, ["0", "0"], "Action Bar must not visually reorder groups."); + + await page.setViewportSize({ width: 800, height: 464 }); + await page.reload({ waitUntil: "domcontentloaded" }); + await page.waitForFunction(() => document.body.dataset.demoReady === "true"); + const shallowPosition = await page.locator("#previewWrapper").evaluate((wrapper) => { + const actionBar = document.createElement("div"); + actionBar.className = "ly-action-bar ly-action-bar--sticky"; + wrapper.replaceChildren(actionBar); + return getComputedStyle(actionBar).position; + }); + assert.equal(shallowPosition, "static", "Shallow-height Action Bar must disable stickiness."); +}; + const installExternalFixtures = async (page) => { await page.route("https://unpkg.com/**", async (route) => { const url = route.request().url(); @@ -1779,6 +1866,7 @@ try { await verifyProfileAndUtilityIsolation(page, server.baseUrl); await verifyContentResilience(page, server.baseUrl); await verifyMosaicComposition(page, server.baseUrl); + await verifyActionBarComposition(page, server.baseUrl); await verifyPrimitiveOverflow(page, server.baseUrl); await verifyCodeBlockContrast(page, server.baseUrl); await verifyInteractions(page, server.baseUrl); diff --git a/test/layout-css-contract.test.mjs b/test/layout-css-contract.test.mjs index 888bdec..1b030bf 100644 --- a/test/layout-css-contract.test.mjs +++ b/test/layout-css-contract.test.mjs @@ -309,6 +309,7 @@ for (const primitive of [ "sidebar", "grid", "mosaic", + "action-bar", "split", "panes", "media", @@ -328,6 +329,24 @@ assert( !/grid-auto-flow:\s*dense/.test(primitives), "Mosaic must preserve DOM reading and focus order." ); +assert( + /\.ly-action-bar\s*\{[^}]*display:\s*flex[^}]*flex-wrap:\s*wrap[^}]*gap:\s*var\(--ly-cluster-gap\)[^}]*padding-block-end:\s*var\(--ly-safe-area-block-end\)/s.test( + primitives + ), + "Action Bar must be a wrapping, safe-area-aware structural cluster." +); +assert( + /\.ly-action-bar\s*>\s*\[data-ly-actions="end"\]\s*\{[^}]*margin-inline-start:\s*auto/s.test( + primitives + ), + "Action Bar end actions must align through logical margin." +); +assert( + /\.ly-action-bar--sticky\s*\{[^}]*position:\s*var\(--ly-sticky-position,\s*sticky\)/s.test( + primitives + ), + "Sticky Action Bar must honor the shallow-height position token." +); assert( /--ly-cover-min:\s*100vh/.test(foundation) && /--ly-shell-min:\s*100vh/.test(foundation) && diff --git a/test/manifest-contract.test.mjs b/test/manifest-contract.test.mjs index cc137b1..52e3693 100644 --- a/test/manifest-contract.test.mjs +++ b/test/manifest-contract.test.mjs @@ -226,8 +226,8 @@ test("ecosystem manifest describes real structural selectors, thresholds, and to ]); assert.deepEqual(manifest.primitives, [ "page", "header", "footer", "main", "section", "surface", "readable", "stack", "cluster", - "center", "cover", "switcher", "sidebar", "grid", "mosaic", "split", "panes", "media", - "reel", "frame", "scroll" + "center", "cover", "switcher", "sidebar", "grid", "mosaic", "action-bar", "split", + "panes", "media", "reel", "frame", "scroll" ]); assert.deepEqual(manifest.recipes, [ "app-shell", "dashboard", "docs", "list-detail", "split-hero", "gallery", "card-grid" From 7c4aa827a2d8522fccddd09849e3ad6b5a094e69 Mon Sep 17 00:00:00 2001 From: Foscat Date: Thu, 3 Sep 2026 09:19:18 -0500 Subject: [PATCH 05/11] feat: make app shell area aware --- dist/layout-style-css.css | 83 +++++++++++++++++++ dist/layout-style-css.min.css | 2 +- dist/recipes.css | 83 +++++++++++++++++++ styles/recipes.css | 83 +++++++++++++++++++ test/demo-smoke.test.mjs | 129 ++++++++++++++++++++++++++++++ test/layout-css-contract.test.mjs | 20 +++++ 6 files changed, 399 insertions(+), 1 deletion(-) diff --git a/dist/layout-style-css.css b/dist/layout-style-css.css index cada81e..3fefea1 100644 --- a/dist/layout-style-css.css +++ b/dist/layout-style-css.css @@ -941,6 +941,89 @@ grid-template-columns: var(--ly-dashboard-wide-columns); } } + + /* + Feature-detected presence rules remove absent side tracks without changing + the canonical area vocabulary or personality-owned both-side topologies. + */ + @supports selector(:has(*)) { + @container ly-scope (min-width: 52rem) { + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):has( + > [data-ly-area="sidebar"] + ):not(:has(> [data-ly-area="aside"])) { + grid-template-areas: + "header header" + "sidebar main" + "footer footer"; + grid-template-columns: + minmax(min(100%, var(--ly-recipe-rail)), auto) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr); + grid-template-rows: auto minmax(0, 1fr) auto; + } + + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not( + :has(> [data-ly-area="sidebar"]) + ):has(> [data-ly-area="aside"]) { + grid-template-areas: + "header header" + "main aside" + "footer footer"; + grid-template-columns: + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); + grid-template-rows: auto minmax(0, 1fr) auto; + } + + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not( + :has(> [data-ly-area="sidebar"]) + ):not(:has(> [data-ly-area="aside"])) { + grid-template-areas: + "header" + "main" + "footer"; + grid-template-columns: + minmax(min(100%, var(--ly-recipe-main-min)), 1fr); + grid-template-rows: auto minmax(0, 1fr) auto; + } + } + + @container ly-scope (min-width: 72rem) { + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):has( + > [data-ly-area="sidebar"] + ):not(:has(> [data-ly-area="aside"])) { + grid-template-areas: + "sidebar header" + "sidebar main" + "sidebar footer"; + grid-template-columns: + minmax(min(100%, var(--ly-recipe-rail)), auto) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr); + } + + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not( + :has(> [data-ly-area="sidebar"]) + ):has(> [data-ly-area="aside"]) { + grid-template-areas: + "header header" + "main aside" + "footer footer"; + grid-template-columns: + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); + } + + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not( + :has(> [data-ly-area="sidebar"]) + ):not(:has(> [data-ly-area="aside"])) { + grid-template-areas: + "header" + "main" + "footer"; + grid-template-columns: + minmax(min(100%, var(--ly-recipe-main-min)), 1fr); + } + } + } } /* utilities.css */ diff --git a/dist/layout-style-css.min.css b/dist/layout-style-css.min.css index 1473910..7ddefe9 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.context;@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-workspace:96rem;--ly-wrapper-wide:112rem;--ly-page-padding-inline:clamp(1rem,3vw,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:var(--ly-page-padding-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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem);--ly-header-height:4.5rem;--ly-sticky-position:sticky;--ly-cover-min:100vh;--ly-shell-min:100vh;--ly-scroll-max:50rem;--ly-scroll-viewport-max:min(70vh,50rem);--ly-switcher-threshold:42rem;--ly-sidebar-size:18rem;--ly-sidebar-content-min:50%;--ly-grid-columns:12;--ly-grid-min:16rem;--ly-mosaic-medium-columns:6;--ly-mosaic-wide-columns:12;--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-split-primary:1fr;--ly-split-secondary:1fr;--ly-recipe-main-min:20rem;--ly-recipe-rail:18rem;--ly-recipe-aside:22rem;--ly-gallery-min:12rem;--ly-card-grid-min:16rem;--ly-app-shell-base-rows:auto auto minmax(0,1fr) auto auto;--ly-app-shell-medium-areas:"header header" "sidebar main" "aside main" "footer footer";--ly-app-shell-medium-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-medium-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),1fr);--ly-app-shell-wide-areas:"sidebar header header" "sidebar main aside" "sidebar footer footer";--ly-app-shell-wide-rows:auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1fr);--ly-list-detail-wide-areas:"primary secondary" "actions actions";--ly-list-detail-wide-columns:minmax(min(100%,max(var(--ly-pane-min),var(--ly-pane-size))),0.7fr) minmax(min(100%,var(--ly-pane-min)),1fr);--ly-split-hero-wide-areas:"content media" "actions media";--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),var(--ly-split-primary,1fr)) minmax(min(100%,var(--ly-split-min)),var(--ly-split-secondary,1fr));container-name:ly-scope;container-type:inline-size;min-inline-size:0;min-block-size:0}@supports (width:1cqi){:where(.ly-root){--ly-page-padding-inline:clamp(1rem,3cqi,3rem)}}@supports (height:100dvh){:where(.ly-root){--ly-cover-min:100dvh;--ly-shell-min:100dvh;--ly-scroll-viewport-max:min(70dvh,50rem)}}}@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),3vh);--ly-cluster-gap:min(var(--ly-space-3),2vh);--ly-section-padding-block:clamp(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem);--ly-header-height:3.5rem;--ly-scroll-viewport-max:min(62vh,34rem)}@supports (height:100dvh){:where(.ly-root){--ly-stack-gap:min(var(--ly-space-4),3dvh);--ly-cluster-gap:min(var(--ly-space-3),2dvh);--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem);--ly-scroll-viewport-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-4);--ly-section-padding-block-compact:var(--ly-space-2);--ly-scroll-viewport-max:max(12rem,calc(100vh - 8rem))}@supports (height:100dvh){:where(.ly-root){--ly-scroll-viewport-max:max(12rem,calc(100dvh - 8rem))}}}}@layer ly.context{:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(1rem,2.5vh,2rem);--ly-section-padding-block-compact:clamp(0.5rem,1.5vh,1rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:max(var(--ly-profile-gap),var(--ly-space-6));--ly-grid-gap:var(--ly-gap);--ly-stack-gap:var(--ly-space-5);--ly-cluster-gap:var(--ly-space-4);--ly-section-padding-block:clamp(3rem,7vh,6rem);--ly-section-padding-block-compact:clamp(1.5rem,3.5vh,3rem)}@media (max-height:44rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(0.75rem,2vh,1.25rem);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-gap:min(var(--ly-profile-gap),var(--ly-space-4));--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(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:var(--ly-space-5);--ly-grid-gap:var(--ly-space-5);--ly-stack-gap:var(--ly-space-4);--ly-cluster-gap:var(--ly-space-3);--ly-section-padding-block:clamp(1.5rem,6vh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3vh,1.25rem)}@supports (height:100dvh){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--ly-section-padding-block:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-section-padding-block:clamp(1.5rem,6dvh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3dvh,1.25rem)}}}@media (max-height:30rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-1);--ly-section-padding-block:var(--ly-space-3);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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-2);--ly-section-padding-block:var(--ly-space-4);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--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-3);--ly-section-padding-block:var(--ly-space-5);--ly-section-padding-block-compact:var(--ly-space-3)}}}@layer ly.wrappers{.ly-wrapper{--ly-wrapper-max:var(--ly-personality-wrapper-max,var(--ly-wrapper-content));--ly-wrapper-fluid-gutter:var(--ly-wrapper-gutter);--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--workspace{--ly-wrapper-max:var(--ly-wrapper-workspace)}.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,sticky);inset-block-start:0;z-index:var(--ly-z-header,20)}.ly-section{padding-block:var(--ly-section-padding-block)}.ly-section--compact{padding-block:var(--ly-section-padding-block-compact)}.ly-section--flush{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-mosaic{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--ly-grid-gap)}.ly-mosaic>*{min-inline-size:0;min-block-size:0}.ly-action-bar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ly-cluster-gap);min-inline-size:0;padding-block-end:var(--ly-safe-area-block-end)}.ly-action-bar>:where([data-ly-actions="start"],[data-ly-actions="end"]){display:flex;flex-wrap:wrap;align-items:center;gap:var(--ly-cluster-gap);min-inline-size:0}.ly-action-bar>[data-ly-actions="end"]{margin-inline-start:auto}.ly-action-bar--sticky{position:var(--ly-sticky-position,sticky);inset-block-end:0;z-index:var(--ly-z-header,20)}.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;overflow:auto;overscroll-behavior-block:contain}.ly-scroll--bounded{max-block-size:var(--ly-scroll-max)}.ly-scroll--viewport{max-block-size:var(--ly-scroll-viewport-max)}}@layer ly.context{.ly-mosaic:not([data-ly-responsive="manual"])>:where( .ly-span-1,.ly-span-2,.ly-span-3,.ly-span-4,.ly-span-6,.ly-span-full ){grid-column:1 / -1}.ly-mosaic:not([data-ly-responsive="manual"])>:where( .ly-row-span-2,.ly-row-span-3 ){grid-row:auto}@container ly-scope (min-width:42rem){.ly-mosaic:not([data-ly-responsive="manual"]){grid-template-columns:repeat( var(--ly-mosaic-medium-columns),minmax(0,1fr) )}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-1{grid-column:span 1}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-2{grid-column:span 2}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-3{grid-column:span 3}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-4{grid-column:span 4}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-6{grid-column:span 6}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-full{grid-column:1 / -1}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-row-span-2{grid-row:span 2}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-row-span-3{grid-row:span 3}}@container ly-scope (min-width:72rem){.ly-mosaic:not([data-ly-responsive="manual"]){grid-template-columns:repeat( var(--ly-mosaic-wide-columns),minmax(0,1fr) )}}}@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:var(--ly-app-shell-base-rows)}[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="gallery"],[data-ly-recipe="card-grid"] )[data-ly-responsive="manual"]{grid-template-columns:minmax(0,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);grid-template-rows:var(--ly-app-shell-medium-rows)}[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);grid-template-rows:var(--ly-app-shell-wide-rows)}[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-6{grid-column:span 6}.ly-span-full{grid-column:1 / -1}.ly-row-span-2{grid-row:span 2}.ly-row-span-3{grid-row:span 3}.ly-gap-0{gap:var(--ly-space-0)}.ly-gap-1{gap:var(--ly-space-1)}.ly-gap-2{gap:var(--ly-space-2)}.ly-gap-3{gap:var(--ly-space-3)}.ly-gap-4{gap:var(--ly-space-4)}.ly-gap-5{gap:var(--ly-space-5)}.ly-gap-6{gap:var(--ly-space-6)}.ly-gap-7{gap:var(--ly-space-7)}.ly-gap-8{gap:var(--ly-space-8)}.ly-gap-9{gap:var(--ly-space-9)}.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-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.3fr) minmax(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.28fr) minmax(min(100%,var(--ly-recipe-main-min)),1fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),0.5fr) minmax(min(100%,var(--ly-pane-min)),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-rows:auto minmax(0,1fr) auto auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-rail)),0.3fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),1.1fr) minmax(min(100%,var(--ly-pane-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1.35fr) minmax(min(100%,var(--ly-recipe-aside)),0.65fr);--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),1.8fr) minmax(min(100%,var(--ly-split-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-split-min)),1.5fr) minmax(min(100%,var(--ly-split-min)),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-rows:auto minmax(0,1fr) auto auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(0,1fr);--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),1fr) minmax(min(100%,var(--ly-split-min)),1fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),1fr) minmax(min(100%,var(--ly-pane-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.34fr);--ly-reel-item-min:20rem}} +@layer ly.reset,ly.tokens,ly.wrappers,ly.primitives,ly.recipes,ly.utilities,ly.personalities,ly.context;@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-workspace:96rem;--ly-wrapper-wide:112rem;--ly-page-padding-inline:clamp(1rem,3vw,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:var(--ly-page-padding-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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem);--ly-header-height:4.5rem;--ly-sticky-position:sticky;--ly-cover-min:100vh;--ly-shell-min:100vh;--ly-scroll-max:50rem;--ly-scroll-viewport-max:min(70vh,50rem);--ly-switcher-threshold:42rem;--ly-sidebar-size:18rem;--ly-sidebar-content-min:50%;--ly-grid-columns:12;--ly-grid-min:16rem;--ly-mosaic-medium-columns:6;--ly-mosaic-wide-columns:12;--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-split-primary:1fr;--ly-split-secondary:1fr;--ly-recipe-main-min:20rem;--ly-recipe-rail:18rem;--ly-recipe-aside:22rem;--ly-gallery-min:12rem;--ly-card-grid-min:16rem;--ly-app-shell-base-rows:auto auto minmax(0,1fr) auto auto;--ly-app-shell-medium-areas:"header header" "sidebar main" "aside main" "footer footer";--ly-app-shell-medium-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-medium-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),1fr);--ly-app-shell-wide-areas:"sidebar header header" "sidebar main aside" "sidebar footer footer";--ly-app-shell-wide-rows:auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1fr);--ly-list-detail-wide-areas:"primary secondary" "actions actions";--ly-list-detail-wide-columns:minmax(min(100%,max(var(--ly-pane-min),var(--ly-pane-size))),0.7fr) minmax(min(100%,var(--ly-pane-min)),1fr);--ly-split-hero-wide-areas:"content media" "actions media";--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),var(--ly-split-primary,1fr)) minmax(min(100%,var(--ly-split-min)),var(--ly-split-secondary,1fr));container-name:ly-scope;container-type:inline-size;min-inline-size:0;min-block-size:0}@supports (width:1cqi){:where(.ly-root){--ly-page-padding-inline:clamp(1rem,3cqi,3rem)}}@supports (height:100dvh){:where(.ly-root){--ly-cover-min:100dvh;--ly-shell-min:100dvh;--ly-scroll-viewport-max:min(70dvh,50rem)}}}@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),3vh);--ly-cluster-gap:min(var(--ly-space-3),2vh);--ly-section-padding-block:clamp(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem);--ly-header-height:3.5rem;--ly-scroll-viewport-max:min(62vh,34rem)}@supports (height:100dvh){:where(.ly-root){--ly-stack-gap:min(var(--ly-space-4),3dvh);--ly-cluster-gap:min(var(--ly-space-3),2dvh);--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem);--ly-scroll-viewport-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-4);--ly-section-padding-block-compact:var(--ly-space-2);--ly-scroll-viewport-max:max(12rem,calc(100vh - 8rem))}@supports (height:100dvh){:where(.ly-root){--ly-scroll-viewport-max:max(12rem,calc(100dvh - 8rem))}}}}@layer ly.context{:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(1rem,2.5vh,2rem);--ly-section-padding-block-compact:clamp(0.5rem,1.5vh,1rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:max(var(--ly-profile-gap),var(--ly-space-6));--ly-grid-gap:var(--ly-gap);--ly-stack-gap:var(--ly-space-5);--ly-cluster-gap:var(--ly-space-4);--ly-section-padding-block:clamp(3rem,7vh,6rem);--ly-section-padding-block-compact:clamp(1.5rem,3.5vh,3rem)}@media (max-height:44rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(0.75rem,2vh,1.25rem);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-gap:min(var(--ly-profile-gap),var(--ly-space-4));--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(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:var(--ly-space-5);--ly-grid-gap:var(--ly-space-5);--ly-stack-gap:var(--ly-space-4);--ly-cluster-gap:var(--ly-space-3);--ly-section-padding-block:clamp(1.5rem,6vh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3vh,1.25rem)}@supports (height:100dvh){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--ly-section-padding-block:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-section-padding-block:clamp(1.5rem,6dvh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3dvh,1.25rem)}}}@media (max-height:30rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-1);--ly-section-padding-block:var(--ly-space-3);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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-2);--ly-section-padding-block:var(--ly-space-4);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--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-3);--ly-section-padding-block:var(--ly-space-5);--ly-section-padding-block-compact:var(--ly-space-3)}}}@layer ly.wrappers{.ly-wrapper{--ly-wrapper-max:var(--ly-personality-wrapper-max,var(--ly-wrapper-content));--ly-wrapper-fluid-gutter:var(--ly-wrapper-gutter);--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--workspace{--ly-wrapper-max:var(--ly-wrapper-workspace)}.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,sticky);inset-block-start:0;z-index:var(--ly-z-header,20)}.ly-section{padding-block:var(--ly-section-padding-block)}.ly-section--compact{padding-block:var(--ly-section-padding-block-compact)}.ly-section--flush{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-mosaic{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--ly-grid-gap)}.ly-mosaic>*{min-inline-size:0;min-block-size:0}.ly-action-bar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ly-cluster-gap);min-inline-size:0;padding-block-end:var(--ly-safe-area-block-end)}.ly-action-bar>:where([data-ly-actions="start"],[data-ly-actions="end"]){display:flex;flex-wrap:wrap;align-items:center;gap:var(--ly-cluster-gap);min-inline-size:0}.ly-action-bar>[data-ly-actions="end"]{margin-inline-start:auto}.ly-action-bar--sticky{position:var(--ly-sticky-position,sticky);inset-block-end:0;z-index:var(--ly-z-header,20)}.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;overflow:auto;overscroll-behavior-block:contain}.ly-scroll--bounded{max-block-size:var(--ly-scroll-max)}.ly-scroll--viewport{max-block-size:var(--ly-scroll-viewport-max)}}@layer ly.context{.ly-mosaic:not([data-ly-responsive="manual"])>:where( .ly-span-1,.ly-span-2,.ly-span-3,.ly-span-4,.ly-span-6,.ly-span-full ){grid-column:1 / -1}.ly-mosaic:not([data-ly-responsive="manual"])>:where( .ly-row-span-2,.ly-row-span-3 ){grid-row:auto}@container ly-scope (min-width:42rem){.ly-mosaic:not([data-ly-responsive="manual"]){grid-template-columns:repeat( var(--ly-mosaic-medium-columns),minmax(0,1fr) )}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-1{grid-column:span 1}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-2{grid-column:span 2}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-3{grid-column:span 3}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-4{grid-column:span 4}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-6{grid-column:span 6}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-full{grid-column:1 / -1}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-row-span-2{grid-row:span 2}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-row-span-3{grid-row:span 3}}@container ly-scope (min-width:72rem){.ly-mosaic:not([data-ly-responsive="manual"]){grid-template-columns:repeat( var(--ly-mosaic-wide-columns),minmax(0,1fr) )}}}@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:var(--ly-app-shell-base-rows)}[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="gallery"],[data-ly-recipe="card-grid"] )[data-ly-responsive="manual"]{grid-template-columns:minmax(0,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);grid-template-rows:var(--ly-app-shell-medium-rows)}[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);grid-template-rows:var(--ly-app-shell-wide-rows)}[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)}}@supports selector(:has(*)){@container ly-scope (min-width:52rem){[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):has(>[data-ly-area="sidebar"] ):not(:has(>[data-ly-area="aside"])){grid-template-areas:"header header" "sidebar main" "footer footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),1fr);grid-template-rows:auto minmax(0,1fr) auto}[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not(:has(>[data-ly-area="sidebar"]) ):has(>[data-ly-area="aside"]){grid-template-areas:"header header" "main aside" "footer footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.35fr);grid-template-rows:auto minmax(0,1fr) auto}[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not(:has(>[data-ly-area="sidebar"]) ):not(:has(>[data-ly-area="aside"])){grid-template-areas:"header" "main" "footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr);grid-template-rows:auto minmax(0,1fr) auto}}@container ly-scope (min-width:72rem){[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):has(>[data-ly-area="sidebar"] ):not(:has(>[data-ly-area="aside"])){grid-template-areas:"sidebar header" "sidebar main" "sidebar footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),1fr)}[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not(:has(>[data-ly-area="sidebar"]) ):has(>[data-ly-area="aside"]){grid-template-areas:"header header" "main aside" "footer footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.35fr)}[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not(:has(>[data-ly-area="sidebar"]) ):not(:has(>[data-ly-area="aside"])){grid-template-areas:"header" "main" "footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr)}}}}@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-6{grid-column:span 6}.ly-span-full{grid-column:1 / -1}.ly-row-span-2{grid-row:span 2}.ly-row-span-3{grid-row:span 3}.ly-gap-0{gap:var(--ly-space-0)}.ly-gap-1{gap:var(--ly-space-1)}.ly-gap-2{gap:var(--ly-space-2)}.ly-gap-3{gap:var(--ly-space-3)}.ly-gap-4{gap:var(--ly-space-4)}.ly-gap-5{gap:var(--ly-space-5)}.ly-gap-6{gap:var(--ly-space-6)}.ly-gap-7{gap:var(--ly-space-7)}.ly-gap-8{gap:var(--ly-space-8)}.ly-gap-9{gap:var(--ly-space-9)}.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-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.3fr) minmax(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.28fr) minmax(min(100%,var(--ly-recipe-main-min)),1fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),0.5fr) minmax(min(100%,var(--ly-pane-min)),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-rows:auto minmax(0,1fr) auto auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-rail)),0.3fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),1.1fr) minmax(min(100%,var(--ly-pane-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1.35fr) minmax(min(100%,var(--ly-recipe-aside)),0.65fr);--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),1.8fr) minmax(min(100%,var(--ly-split-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-split-min)),1.5fr) minmax(min(100%,var(--ly-split-min)),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-rows:auto minmax(0,1fr) auto auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(0,1fr);--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),1fr) minmax(min(100%,var(--ly-split-min)),1fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),1fr) minmax(min(100%,var(--ly-pane-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.34fr);--ly-reel-item-min:20rem}} diff --git a/dist/recipes.css b/dist/recipes.css index de91861..d4731cc 100644 --- a/dist/recipes.css +++ b/dist/recipes.css @@ -194,4 +194,87 @@ grid-template-columns: var(--ly-dashboard-wide-columns); } } + + /* + Feature-detected presence rules remove absent side tracks without changing + the canonical area vocabulary or personality-owned both-side topologies. + */ + @supports selector(:has(*)) { + @container ly-scope (min-width: 52rem) { + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):has( + > [data-ly-area="sidebar"] + ):not(:has(> [data-ly-area="aside"])) { + grid-template-areas: + "header header" + "sidebar main" + "footer footer"; + grid-template-columns: + minmax(min(100%, var(--ly-recipe-rail)), auto) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr); + grid-template-rows: auto minmax(0, 1fr) auto; + } + + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not( + :has(> [data-ly-area="sidebar"]) + ):has(> [data-ly-area="aside"]) { + grid-template-areas: + "header header" + "main aside" + "footer footer"; + grid-template-columns: + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); + grid-template-rows: auto minmax(0, 1fr) auto; + } + + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not( + :has(> [data-ly-area="sidebar"]) + ):not(:has(> [data-ly-area="aside"])) { + grid-template-areas: + "header" + "main" + "footer"; + grid-template-columns: + minmax(min(100%, var(--ly-recipe-main-min)), 1fr); + grid-template-rows: auto minmax(0, 1fr) auto; + } + } + + @container ly-scope (min-width: 72rem) { + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):has( + > [data-ly-area="sidebar"] + ):not(:has(> [data-ly-area="aside"])) { + grid-template-areas: + "sidebar header" + "sidebar main" + "sidebar footer"; + grid-template-columns: + minmax(min(100%, var(--ly-recipe-rail)), auto) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr); + } + + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not( + :has(> [data-ly-area="sidebar"]) + ):has(> [data-ly-area="aside"]) { + grid-template-areas: + "header header" + "main aside" + "footer footer"; + grid-template-columns: + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); + } + + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not( + :has(> [data-ly-area="sidebar"]) + ):not(:has(> [data-ly-area="aside"])) { + grid-template-areas: + "header" + "main" + "footer"; + grid-template-columns: + minmax(min(100%, var(--ly-recipe-main-min)), 1fr); + } + } + } } diff --git a/styles/recipes.css b/styles/recipes.css index de91861..d4731cc 100644 --- a/styles/recipes.css +++ b/styles/recipes.css @@ -194,4 +194,87 @@ grid-template-columns: var(--ly-dashboard-wide-columns); } } + + /* + Feature-detected presence rules remove absent side tracks without changing + the canonical area vocabulary or personality-owned both-side topologies. + */ + @supports selector(:has(*)) { + @container ly-scope (min-width: 52rem) { + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):has( + > [data-ly-area="sidebar"] + ):not(:has(> [data-ly-area="aside"])) { + grid-template-areas: + "header header" + "sidebar main" + "footer footer"; + grid-template-columns: + minmax(min(100%, var(--ly-recipe-rail)), auto) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr); + grid-template-rows: auto minmax(0, 1fr) auto; + } + + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not( + :has(> [data-ly-area="sidebar"]) + ):has(> [data-ly-area="aside"]) { + grid-template-areas: + "header header" + "main aside" + "footer footer"; + grid-template-columns: + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); + grid-template-rows: auto minmax(0, 1fr) auto; + } + + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not( + :has(> [data-ly-area="sidebar"]) + ):not(:has(> [data-ly-area="aside"])) { + grid-template-areas: + "header" + "main" + "footer"; + grid-template-columns: + minmax(min(100%, var(--ly-recipe-main-min)), 1fr); + grid-template-rows: auto minmax(0, 1fr) auto; + } + } + + @container ly-scope (min-width: 72rem) { + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):has( + > [data-ly-area="sidebar"] + ):not(:has(> [data-ly-area="aside"])) { + grid-template-areas: + "sidebar header" + "sidebar main" + "sidebar footer"; + grid-template-columns: + minmax(min(100%, var(--ly-recipe-rail)), auto) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr); + } + + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not( + :has(> [data-ly-area="sidebar"]) + ):has(> [data-ly-area="aside"]) { + grid-template-areas: + "header header" + "main aside" + "footer footer"; + grid-template-columns: + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.35fr); + } + + [data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not( + :has(> [data-ly-area="sidebar"]) + ):not(:has(> [data-ly-area="aside"])) { + grid-template-areas: + "header" + "main" + "footer"; + grid-template-columns: + minmax(min(100%, var(--ly-recipe-main-min)), 1fr); + } + } + } } diff --git a/test/demo-smoke.test.mjs b/test/demo-smoke.test.mjs index 4794ba6..7ff0aea 100644 --- a/test/demo-smoke.test.mjs +++ b/test/demo-smoke.test.mjs @@ -733,6 +733,134 @@ const verifyActionBarComposition = async (page, baseUrl) => { assert.equal(shallowPosition, "static", "Shallow-height Action Bar must disable stickiness."); }; +/** + * Verifies that automatic App Shells remove absent side tracks while preserving + * personality-owned both-side topology and the manual stacked fallback. + * + * @param {import("@playwright/test").Page} page Active browser page. + * @param {string} baseUrl Demo server URL. + * @returns {Promise} + */ +const verifyAreaAwareAppShell = async (page, baseUrl) => { + await page.setViewportSize({ width: 1920, height: 1080 }); + await page.goto(`${baseUrl}?ecosystem=layout-only&wrapper=full`, { + waitUntil: "domcontentloaded" + }); + await page.waitForFunction(() => document.body.dataset.demoReady === "true"); + + const combinations = [ + { + label: "both", + areas: ["header", "sidebar", "main", "aside", "footer"], + tracks: { "53rem": 2, "73rem": null }, + areaFragment: { "53rem": "sidebar main", "73rem": null } + }, + { + label: "sidebar-only", + areas: ["header", "sidebar", "main", "footer"], + tracks: { "53rem": 2, "73rem": 2 }, + areaFragment: { "53rem": "sidebar main", "73rem": "sidebar main" } + }, + { + label: "aside-only", + areas: ["header", "main", "aside", "footer"], + tracks: { "53rem": 2, "73rem": 2 }, + areaFragment: { "53rem": "main aside", "73rem": "main aside" } + }, + { + label: "neither", + areas: ["header", "main", "footer"], + tracks: { "53rem": 1, "73rem": 1 }, + areaFragment: { "53rem": '"main"', "73rem": '"main"' } + } + ]; + + for (const personality of [ + "minimal-saas", + "retrofuturism", + "cyberpunk", + "y2k", + "retro-glass", + "split-screen" + ]) { + await setControl(page, "personalitySelect", personality); + for (const width of ["53rem", "73rem"]) { + await setCustomAllocation(page, width); + for (const combination of combinations) { + const snapshot = await page.evaluate(({ areas }) => { + const wrapper = document.querySelector("#previewWrapper"); + wrapper.style.setProperty("--ly-shell-min", "auto"); + const recipe = document.createElement("section"); + recipe.dataset.lyRecipe = "app-shell"; + for (const areaName of areas) { + const region = document.createElement("article"); + region.dataset.lyArea = areaName; + region.textContent = `${areaName} workspace`; + recipe.append(region); + } + wrapper.replaceChildren(recipe); + const style = getComputedStyle(recipe); + const rootStyle = getComputedStyle(wrapper); + const rootFontSize = Number.parseFloat(getComputedStyle(document.documentElement).fontSize); + return { + areas: style.gridTemplateAreas, + tracks: style.gridTemplateColumns.split(/\s+/).filter(Boolean).length, + overflow: recipe.scrollWidth - recipe.clientWidth, + mainWidth: recipe.querySelector('[data-ly-area="main"]').getBoundingClientRect().width, + mainFloor: + Number.parseFloat(rootStyle.getPropertyValue("--ly-recipe-main-min")) * rootFontSize + }; + }, combination); + + const expectedTracks = combination.tracks[width]; + if (expectedTracks !== null) { + assert.equal( + snapshot.tracks, + expectedTracks, + `${personality} ${width} ${combination.label} reserved an empty side track.` + ); + } + const expectedFragment = combination.areaFragment[width]; + if (expectedFragment !== null) { + assert( + snapshot.areas.includes(expectedFragment), + `${personality} ${width} ${combination.label} topology drifted: ${snapshot.areas}` + ); + } + assert( + snapshot.mainWidth + 1 >= snapshot.mainFloor, + `${personality} ${width} ${combination.label} main fell below its usable floor.` + ); + assert( + snapshot.overflow <= 2, + `${personality} ${width} ${combination.label} overflowed by ${snapshot.overflow}px.` + ); + } + } + } + + await setCustomAllocation(page, "73rem"); + const manual = await page.evaluate(() => { + const wrapper = document.querySelector("#previewWrapper"); + const recipe = document.createElement("section"); + recipe.dataset.lyRecipe = "app-shell"; + recipe.dataset.lyResponsive = "manual"; + for (const areaName of ["header", "main", "footer"]) { + const region = document.createElement("article"); + region.dataset.lyArea = areaName; + recipe.append(region); + } + wrapper.replaceChildren(recipe); + const style = getComputedStyle(recipe); + return { + areas: style.gridTemplateAreas, + tracks: style.gridTemplateColumns.split(/\s+/).filter(Boolean).length + }; + }); + assert.equal(manual.tracks, 1, "Manual App Shell must retain its stacked track."); + assert.match(manual.areas, /"header" "sidebar" "main" "aside" "footer"/); +}; + const installExternalFixtures = async (page) => { await page.route("https://unpkg.com/**", async (route) => { const url = route.request().url(); @@ -1867,6 +1995,7 @@ try { await verifyContentResilience(page, server.baseUrl); await verifyMosaicComposition(page, server.baseUrl); await verifyActionBarComposition(page, server.baseUrl); + await verifyAreaAwareAppShell(page, server.baseUrl); await verifyPrimitiveOverflow(page, server.baseUrl); await verifyCodeBlockContrast(page, server.baseUrl); await verifyInteractions(page, server.baseUrl); diff --git a/test/layout-css-contract.test.mjs b/test/layout-css-contract.test.mjs index 1b030bf..9600495 100644 --- a/test/layout-css-contract.test.mjs +++ b/test/layout-css-contract.test.mjs @@ -457,6 +457,26 @@ assert( recipes.includes(':not([data-ly-responsive="manual"])'), "Automatic topology rules must exclude manual recipes" ); +assert( + recipes.includes("@supports selector(:has(*))"), + "Area-aware App Shell enhancement must be feature-detected." +); +for (const presenceSelector of [ + ':has(> [data-ly-area="sidebar"]):not(:has(> [data-ly-area="aside"]))', + ':not(:has(> [data-ly-area="sidebar"])):has(> [data-ly-area="aside"])', + ':not(:has(> [data-ly-area="sidebar"])):not(:has(> [data-ly-area="aside"]))' +]) { + assert( + recipes.replace(/\s+/g, "").includes(presenceSelector.replace(/\s+/g, "")), + `Missing App Shell presence selector: ${presenceSelector}` + ); +} +for (const name of personalityNames) { + assert( + !readStyle(`personalities/${name}.css`).includes(":has("), + `${name} must rely on shared area-awareness.` + ); +} assert( /\[data-ly-recipe="gallery"\][\s\S]*\[data-ly-recipe="card-grid"\][\s\S]*\[data-ly-responsive="manual"\][\s\S]*grid-template-columns:\s*minmax\(0,\s*1fr\)/.test( recipes From dbf2afef2fc4745fed258bfa89bb16cc9a5c3e7b Mon Sep 17 00:00:00 2001 From: Foscat Date: Thu, 3 Sep 2026 09:25:19 -0500 Subject: [PATCH 06/11] refactor: align existing layout personalities --- dist/layout-style-css.css | 102 +++++++-------------------- dist/layout-style-css.min.css | 2 +- dist/personalities/bauhaus.css | 13 +--- dist/personalities/bento.css | 10 --- dist/personalities/brutalism.css | 12 +--- dist/personalities/maximalist.css | 11 +-- dist/personalities/neumorphism.css | 11 +-- dist/personalities/retro-glass.css | 20 +++--- dist/personalities/tactile.css | 11 +-- dist/personalities/y2k.css | 14 ++-- styles/personalities/bauhaus.css | 13 +--- styles/personalities/bento.css | 10 --- styles/personalities/brutalism.css | 12 +--- styles/personalities/maximalist.css | 11 +-- styles/personalities/neumorphism.css | 11 +-- styles/personalities/retro-glass.css | 20 +++--- styles/personalities/tactile.css | 11 +-- styles/personalities/y2k.css | 14 ++-- test/demo-smoke.test.mjs | 77 ++++++++++++++++++-- test/layout-css-contract.test.mjs | 68 +++++++++++++++++- 20 files changed, 216 insertions(+), 237 deletions(-) diff --git a/dist/layout-style-css.css b/dist/layout-style-css.css index 3fefea1..4d6a5a6 100644 --- a/dist/layout-style-css.css +++ b/dist/layout-style-css.css @@ -1125,16 +1125,6 @@ --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-rows: auto auto minmax(0, 1fr) auto; - --ly-app-shell-wide-columns: - minmax(min(100%, var(--ly-recipe-rail)), 0.3fr) - minmax(min(100%, var(--ly-recipe-main-min)), 1fr) - minmax(0, 1fr); } } @@ -1142,21 +1132,12 @@ @layer ly.personalities.maximalist { :where(.ly-root[data-ly-layout="maximalist"]) { --ly-personality-wrapper-max: 100%; - --ly-profile-gap: var(--ly-space-7); + --ly-profile-gap: var(--ly-space-3); --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(min(100%, var(--ly-recipe-main-min)), 1.4fr) - minmax(0, 0.6fr) - minmax(min(100%, var(--ly-recipe-rail)), 0.32fr) - minmax(min(100%, var(--ly-recipe-aside)), 0.38fr); } } @@ -1164,39 +1145,23 @@ @layer ly.personalities.bauhaus { :where(.ly-root[data-ly-layout="bauhaus"]) { --ly-personality-wrapper-max: 96rem; - --ly-profile-gap: var(--ly-space-6); + --ly-profile-gap: var(--ly-space-2); --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(min(100%, var(--ly-recipe-main-min)), 0.7fr) - minmax(0, 1.3fr) - minmax(min(100%, var(--ly-recipe-aside)), 0.3fr); + --ly-split-primary: 0.7fr; + --ly-split-secondary: 1.3fr; } } /* personalities/tactile.css */ @layer ly.personalities.tactile { :where(.ly-root[data-ly-layout="tactile"]) { - --ly-personality-wrapper-max: 82rem; + --ly-personality-wrapper-max: 96rem; --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-rows: auto auto minmax(0, 1fr) auto; - --ly-app-shell-wide-columns: - minmax(min(100%, var(--ly-recipe-rail)), 0.28fr) - minmax(min(100%, var(--ly-recipe-main-min)), 1fr); --ly-list-detail-wide-columns: minmax(min(100%, var(--ly-pane-min)), 0.5fr) minmax(min(100%, var(--ly-pane-min)), 0.9fr); @@ -1210,16 +1175,7 @@ --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-rows: auto minmax(0, 1fr) auto auto; - --ly-app-shell-wide-columns: - minmax(min(100%, var(--ly-recipe-main-min)), 1fr) - minmax(min(100%, var(--ly-recipe-rail)), 0.3fr); + --ly-recipe-aside: 22rem; --ly-list-detail-wide-columns: minmax(min(100%, var(--ly-pane-min)), 1.1fr) minmax(min(100%, var(--ly-pane-min)), 0.7fr); @@ -1248,19 +1204,11 @@ /* personalities/brutalism.css */ @layer ly.personalities.brutalism { :where(.ly-root[data-ly-layout="brutalism"]) { - --ly-personality-wrapper-max: 100rem; - --ly-profile-gap: var(--ly-space-3); + --ly-personality-wrapper-max: 100%; + --ly-profile-gap: var(--ly-space-1); --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(min(100%, var(--ly-recipe-main-min)), 1.3fr) - minmax(0, 0.7fr) - minmax(min(100%, var(--ly-recipe-rail)), 0.34fr); } } @@ -1286,38 +1234,38 @@ /* personalities/y2k.css */ @layer ly.personalities.y2k { :where(.ly-root[data-ly-layout="y2k"]) { - --ly-personality-wrapper-max: 90rem; - --ly-profile-gap: var(--ly-space-6); + --ly-personality-wrapper-max: 100%; + --ly-profile-gap: var(--ly-space-2); --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"; + "header header header" + "sidebar main aside" + "footer footer footer"; --ly-app-shell-wide-columns: - minmax(min(100%, var(--ly-recipe-aside)), 0.34fr) + minmax(min(100%, var(--ly-recipe-rail)), 0.28fr) minmax(min(100%, var(--ly-recipe-main-min)), 1fr) - minmax(min(100%, var(--ly-recipe-rail)), 0.28fr); + minmax(min(100%, var(--ly-recipe-aside)), 0.26fr); } } /* personalities/retro-glass.css */ @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-personality-wrapper-max: 100%; + --ly-profile-gap: var(--ly-space-2); --ly-grid-min: 15rem; - --ly-recipe-rail: 18rem; - --ly-recipe-aside: 18rem; + --ly-recipe-rail: 16rem; + --ly-recipe-aside: 17rem; --ly-app-shell-wide-areas: - "header header sidebar" - "main main sidebar" - "aside footer footer"; + "header header header" + "sidebar main aside" + "footer footer footer"; --ly-app-shell-wide-columns: - minmax(min(100%, var(--ly-recipe-main-min)), 1.25fr) - minmax(0, 0.75fr) - minmax(min(100%, var(--ly-recipe-rail)), 0.32fr); + minmax(min(100%, var(--ly-recipe-rail)), 0.3fr) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.28fr); } } diff --git a/dist/layout-style-css.min.css b/dist/layout-style-css.min.css index 7ddefe9..40c657b 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.context;@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-workspace:96rem;--ly-wrapper-wide:112rem;--ly-page-padding-inline:clamp(1rem,3vw,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:var(--ly-page-padding-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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem);--ly-header-height:4.5rem;--ly-sticky-position:sticky;--ly-cover-min:100vh;--ly-shell-min:100vh;--ly-scroll-max:50rem;--ly-scroll-viewport-max:min(70vh,50rem);--ly-switcher-threshold:42rem;--ly-sidebar-size:18rem;--ly-sidebar-content-min:50%;--ly-grid-columns:12;--ly-grid-min:16rem;--ly-mosaic-medium-columns:6;--ly-mosaic-wide-columns:12;--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-split-primary:1fr;--ly-split-secondary:1fr;--ly-recipe-main-min:20rem;--ly-recipe-rail:18rem;--ly-recipe-aside:22rem;--ly-gallery-min:12rem;--ly-card-grid-min:16rem;--ly-app-shell-base-rows:auto auto minmax(0,1fr) auto auto;--ly-app-shell-medium-areas:"header header" "sidebar main" "aside main" "footer footer";--ly-app-shell-medium-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-medium-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),1fr);--ly-app-shell-wide-areas:"sidebar header header" "sidebar main aside" "sidebar footer footer";--ly-app-shell-wide-rows:auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1fr);--ly-list-detail-wide-areas:"primary secondary" "actions actions";--ly-list-detail-wide-columns:minmax(min(100%,max(var(--ly-pane-min),var(--ly-pane-size))),0.7fr) minmax(min(100%,var(--ly-pane-min)),1fr);--ly-split-hero-wide-areas:"content media" "actions media";--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),var(--ly-split-primary,1fr)) minmax(min(100%,var(--ly-split-min)),var(--ly-split-secondary,1fr));container-name:ly-scope;container-type:inline-size;min-inline-size:0;min-block-size:0}@supports (width:1cqi){:where(.ly-root){--ly-page-padding-inline:clamp(1rem,3cqi,3rem)}}@supports (height:100dvh){:where(.ly-root){--ly-cover-min:100dvh;--ly-shell-min:100dvh;--ly-scroll-viewport-max:min(70dvh,50rem)}}}@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),3vh);--ly-cluster-gap:min(var(--ly-space-3),2vh);--ly-section-padding-block:clamp(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem);--ly-header-height:3.5rem;--ly-scroll-viewport-max:min(62vh,34rem)}@supports (height:100dvh){:where(.ly-root){--ly-stack-gap:min(var(--ly-space-4),3dvh);--ly-cluster-gap:min(var(--ly-space-3),2dvh);--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem);--ly-scroll-viewport-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-4);--ly-section-padding-block-compact:var(--ly-space-2);--ly-scroll-viewport-max:max(12rem,calc(100vh - 8rem))}@supports (height:100dvh){:where(.ly-root){--ly-scroll-viewport-max:max(12rem,calc(100dvh - 8rem))}}}}@layer ly.context{:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(1rem,2.5vh,2rem);--ly-section-padding-block-compact:clamp(0.5rem,1.5vh,1rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:max(var(--ly-profile-gap),var(--ly-space-6));--ly-grid-gap:var(--ly-gap);--ly-stack-gap:var(--ly-space-5);--ly-cluster-gap:var(--ly-space-4);--ly-section-padding-block:clamp(3rem,7vh,6rem);--ly-section-padding-block-compact:clamp(1.5rem,3.5vh,3rem)}@media (max-height:44rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(0.75rem,2vh,1.25rem);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-gap:min(var(--ly-profile-gap),var(--ly-space-4));--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(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:var(--ly-space-5);--ly-grid-gap:var(--ly-space-5);--ly-stack-gap:var(--ly-space-4);--ly-cluster-gap:var(--ly-space-3);--ly-section-padding-block:clamp(1.5rem,6vh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3vh,1.25rem)}@supports (height:100dvh){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--ly-section-padding-block:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-section-padding-block:clamp(1.5rem,6dvh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3dvh,1.25rem)}}}@media (max-height:30rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-1);--ly-section-padding-block:var(--ly-space-3);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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-2);--ly-section-padding-block:var(--ly-space-4);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--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-3);--ly-section-padding-block:var(--ly-space-5);--ly-section-padding-block-compact:var(--ly-space-3)}}}@layer ly.wrappers{.ly-wrapper{--ly-wrapper-max:var(--ly-personality-wrapper-max,var(--ly-wrapper-content));--ly-wrapper-fluid-gutter:var(--ly-wrapper-gutter);--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--workspace{--ly-wrapper-max:var(--ly-wrapper-workspace)}.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,sticky);inset-block-start:0;z-index:var(--ly-z-header,20)}.ly-section{padding-block:var(--ly-section-padding-block)}.ly-section--compact{padding-block:var(--ly-section-padding-block-compact)}.ly-section--flush{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-mosaic{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--ly-grid-gap)}.ly-mosaic>*{min-inline-size:0;min-block-size:0}.ly-action-bar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ly-cluster-gap);min-inline-size:0;padding-block-end:var(--ly-safe-area-block-end)}.ly-action-bar>:where([data-ly-actions="start"],[data-ly-actions="end"]){display:flex;flex-wrap:wrap;align-items:center;gap:var(--ly-cluster-gap);min-inline-size:0}.ly-action-bar>[data-ly-actions="end"]{margin-inline-start:auto}.ly-action-bar--sticky{position:var(--ly-sticky-position,sticky);inset-block-end:0;z-index:var(--ly-z-header,20)}.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;overflow:auto;overscroll-behavior-block:contain}.ly-scroll--bounded{max-block-size:var(--ly-scroll-max)}.ly-scroll--viewport{max-block-size:var(--ly-scroll-viewport-max)}}@layer ly.context{.ly-mosaic:not([data-ly-responsive="manual"])>:where( .ly-span-1,.ly-span-2,.ly-span-3,.ly-span-4,.ly-span-6,.ly-span-full ){grid-column:1 / -1}.ly-mosaic:not([data-ly-responsive="manual"])>:where( .ly-row-span-2,.ly-row-span-3 ){grid-row:auto}@container ly-scope (min-width:42rem){.ly-mosaic:not([data-ly-responsive="manual"]){grid-template-columns:repeat( var(--ly-mosaic-medium-columns),minmax(0,1fr) )}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-1{grid-column:span 1}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-2{grid-column:span 2}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-3{grid-column:span 3}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-4{grid-column:span 4}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-6{grid-column:span 6}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-full{grid-column:1 / -1}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-row-span-2{grid-row:span 2}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-row-span-3{grid-row:span 3}}@container ly-scope (min-width:72rem){.ly-mosaic:not([data-ly-responsive="manual"]){grid-template-columns:repeat( var(--ly-mosaic-wide-columns),minmax(0,1fr) )}}}@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:var(--ly-app-shell-base-rows)}[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="gallery"],[data-ly-recipe="card-grid"] )[data-ly-responsive="manual"]{grid-template-columns:minmax(0,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);grid-template-rows:var(--ly-app-shell-medium-rows)}[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);grid-template-rows:var(--ly-app-shell-wide-rows)}[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)}}@supports selector(:has(*)){@container ly-scope (min-width:52rem){[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):has(>[data-ly-area="sidebar"] ):not(:has(>[data-ly-area="aside"])){grid-template-areas:"header header" "sidebar main" "footer footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),1fr);grid-template-rows:auto minmax(0,1fr) auto}[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not(:has(>[data-ly-area="sidebar"]) ):has(>[data-ly-area="aside"]){grid-template-areas:"header header" "main aside" "footer footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.35fr);grid-template-rows:auto minmax(0,1fr) auto}[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not(:has(>[data-ly-area="sidebar"]) ):not(:has(>[data-ly-area="aside"])){grid-template-areas:"header" "main" "footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr);grid-template-rows:auto minmax(0,1fr) auto}}@container ly-scope (min-width:72rem){[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):has(>[data-ly-area="sidebar"] ):not(:has(>[data-ly-area="aside"])){grid-template-areas:"sidebar header" "sidebar main" "sidebar footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),1fr)}[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not(:has(>[data-ly-area="sidebar"]) ):has(>[data-ly-area="aside"]){grid-template-areas:"header header" "main aside" "footer footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.35fr)}[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not(:has(>[data-ly-area="sidebar"]) ):not(:has(>[data-ly-area="aside"])){grid-template-areas:"header" "main" "footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr)}}}}@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-6{grid-column:span 6}.ly-span-full{grid-column:1 / -1}.ly-row-span-2{grid-row:span 2}.ly-row-span-3{grid-row:span 3}.ly-gap-0{gap:var(--ly-space-0)}.ly-gap-1{gap:var(--ly-space-1)}.ly-gap-2{gap:var(--ly-space-2)}.ly-gap-3{gap:var(--ly-space-3)}.ly-gap-4{gap:var(--ly-space-4)}.ly-gap-5{gap:var(--ly-space-5)}.ly-gap-6{gap:var(--ly-space-6)}.ly-gap-7{gap:var(--ly-space-7)}.ly-gap-8{gap:var(--ly-space-8)}.ly-gap-9{gap:var(--ly-space-9)}.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-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.3fr) minmax(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),0.28fr) minmax(min(100%,var(--ly-recipe-main-min)),1fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),0.5fr) minmax(min(100%,var(--ly-pane-min)),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-rows:auto minmax(0,1fr) auto auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-rail)),0.3fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),1.1fr) minmax(min(100%,var(--ly-pane-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1.35fr) minmax(min(100%,var(--ly-recipe-aside)),0.65fr);--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),1.8fr) minmax(min(100%,var(--ly-split-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-split-min)),1.5fr) minmax(min(100%,var(--ly-split-min)),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-rows:auto minmax(0,1fr) auto auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(0,1fr);--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),1fr) minmax(min(100%,var(--ly-split-min)),1fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),1fr) minmax(min(100%,var(--ly-pane-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.34fr);--ly-reel-item-min:20rem}} +@layer ly.reset,ly.tokens,ly.wrappers,ly.primitives,ly.recipes,ly.utilities,ly.personalities,ly.context;@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-workspace:96rem;--ly-wrapper-wide:112rem;--ly-page-padding-inline:clamp(1rem,3vw,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:var(--ly-page-padding-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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem);--ly-header-height:4.5rem;--ly-sticky-position:sticky;--ly-cover-min:100vh;--ly-shell-min:100vh;--ly-scroll-max:50rem;--ly-scroll-viewport-max:min(70vh,50rem);--ly-switcher-threshold:42rem;--ly-sidebar-size:18rem;--ly-sidebar-content-min:50%;--ly-grid-columns:12;--ly-grid-min:16rem;--ly-mosaic-medium-columns:6;--ly-mosaic-wide-columns:12;--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-split-primary:1fr;--ly-split-secondary:1fr;--ly-recipe-main-min:20rem;--ly-recipe-rail:18rem;--ly-recipe-aside:22rem;--ly-gallery-min:12rem;--ly-card-grid-min:16rem;--ly-app-shell-base-rows:auto auto minmax(0,1fr) auto auto;--ly-app-shell-medium-areas:"header header" "sidebar main" "aside main" "footer footer";--ly-app-shell-medium-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-medium-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),1fr);--ly-app-shell-wide-areas:"sidebar header header" "sidebar main aside" "sidebar footer footer";--ly-app-shell-wide-rows:auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1fr);--ly-list-detail-wide-areas:"primary secondary" "actions actions";--ly-list-detail-wide-columns:minmax(min(100%,max(var(--ly-pane-min),var(--ly-pane-size))),0.7fr) minmax(min(100%,var(--ly-pane-min)),1fr);--ly-split-hero-wide-areas:"content media" "actions media";--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),var(--ly-split-primary,1fr)) minmax(min(100%,var(--ly-split-min)),var(--ly-split-secondary,1fr));container-name:ly-scope;container-type:inline-size;min-inline-size:0;min-block-size:0}@supports (width:1cqi){:where(.ly-root){--ly-page-padding-inline:clamp(1rem,3cqi,3rem)}}@supports (height:100dvh){:where(.ly-root){--ly-cover-min:100dvh;--ly-shell-min:100dvh;--ly-scroll-viewport-max:min(70dvh,50rem)}}}@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),3vh);--ly-cluster-gap:min(var(--ly-space-3),2vh);--ly-section-padding-block:clamp(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem);--ly-header-height:3.5rem;--ly-scroll-viewport-max:min(62vh,34rem)}@supports (height:100dvh){:where(.ly-root){--ly-stack-gap:min(var(--ly-space-4),3dvh);--ly-cluster-gap:min(var(--ly-space-3),2dvh);--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem);--ly-scroll-viewport-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-4);--ly-section-padding-block-compact:var(--ly-space-2);--ly-scroll-viewport-max:max(12rem,calc(100vh - 8rem))}@supports (height:100dvh){:where(.ly-root){--ly-scroll-viewport-max:max(12rem,calc(100dvh - 8rem))}}}}@layer ly.context{:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(1rem,2.5vh,2rem);--ly-section-padding-block-compact:clamp(0.5rem,1.5vh,1rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:max(var(--ly-profile-gap),var(--ly-space-6));--ly-grid-gap:var(--ly-gap);--ly-stack-gap:var(--ly-space-5);--ly-cluster-gap:var(--ly-space-4);--ly-section-padding-block:clamp(3rem,7vh,6rem);--ly-section-padding-block-compact:clamp(1.5rem,3.5vh,3rem)}@media (max-height:44rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(0.75rem,2vh,1.25rem);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-gap:min(var(--ly-profile-gap),var(--ly-space-4));--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(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:var(--ly-space-5);--ly-grid-gap:var(--ly-space-5);--ly-stack-gap:var(--ly-space-4);--ly-cluster-gap:var(--ly-space-3);--ly-section-padding-block:clamp(1.5rem,6vh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3vh,1.25rem)}@supports (height:100dvh){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--ly-section-padding-block:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-section-padding-block:clamp(1.5rem,6dvh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3dvh,1.25rem)}}}@media (max-height:30rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-1);--ly-section-padding-block:var(--ly-space-3);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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-2);--ly-section-padding-block:var(--ly-space-4);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--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-3);--ly-section-padding-block:var(--ly-space-5);--ly-section-padding-block-compact:var(--ly-space-3)}}}@layer ly.wrappers{.ly-wrapper{--ly-wrapper-max:var(--ly-personality-wrapper-max,var(--ly-wrapper-content));--ly-wrapper-fluid-gutter:var(--ly-wrapper-gutter);--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--workspace{--ly-wrapper-max:var(--ly-wrapper-workspace)}.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,sticky);inset-block-start:0;z-index:var(--ly-z-header,20)}.ly-section{padding-block:var(--ly-section-padding-block)}.ly-section--compact{padding-block:var(--ly-section-padding-block-compact)}.ly-section--flush{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-mosaic{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--ly-grid-gap)}.ly-mosaic>*{min-inline-size:0;min-block-size:0}.ly-action-bar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ly-cluster-gap);min-inline-size:0;padding-block-end:var(--ly-safe-area-block-end)}.ly-action-bar>:where([data-ly-actions="start"],[data-ly-actions="end"]){display:flex;flex-wrap:wrap;align-items:center;gap:var(--ly-cluster-gap);min-inline-size:0}.ly-action-bar>[data-ly-actions="end"]{margin-inline-start:auto}.ly-action-bar--sticky{position:var(--ly-sticky-position,sticky);inset-block-end:0;z-index:var(--ly-z-header,20)}.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;overflow:auto;overscroll-behavior-block:contain}.ly-scroll--bounded{max-block-size:var(--ly-scroll-max)}.ly-scroll--viewport{max-block-size:var(--ly-scroll-viewport-max)}}@layer ly.context{.ly-mosaic:not([data-ly-responsive="manual"])>:where( .ly-span-1,.ly-span-2,.ly-span-3,.ly-span-4,.ly-span-6,.ly-span-full ){grid-column:1 / -1}.ly-mosaic:not([data-ly-responsive="manual"])>:where( .ly-row-span-2,.ly-row-span-3 ){grid-row:auto}@container ly-scope (min-width:42rem){.ly-mosaic:not([data-ly-responsive="manual"]){grid-template-columns:repeat( var(--ly-mosaic-medium-columns),minmax(0,1fr) )}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-1{grid-column:span 1}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-2{grid-column:span 2}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-3{grid-column:span 3}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-4{grid-column:span 4}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-6{grid-column:span 6}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-full{grid-column:1 / -1}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-row-span-2{grid-row:span 2}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-row-span-3{grid-row:span 3}}@container ly-scope (min-width:72rem){.ly-mosaic:not([data-ly-responsive="manual"]){grid-template-columns:repeat( var(--ly-mosaic-wide-columns),minmax(0,1fr) )}}}@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:var(--ly-app-shell-base-rows)}[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="gallery"],[data-ly-recipe="card-grid"] )[data-ly-responsive="manual"]{grid-template-columns:minmax(0,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);grid-template-rows:var(--ly-app-shell-medium-rows)}[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);grid-template-rows:var(--ly-app-shell-wide-rows)}[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)}}@supports selector(:has(*)){@container ly-scope (min-width:52rem){[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):has(>[data-ly-area="sidebar"] ):not(:has(>[data-ly-area="aside"])){grid-template-areas:"header header" "sidebar main" "footer footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),1fr);grid-template-rows:auto minmax(0,1fr) auto}[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not(:has(>[data-ly-area="sidebar"]) ):has(>[data-ly-area="aside"]){grid-template-areas:"header header" "main aside" "footer footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.35fr);grid-template-rows:auto minmax(0,1fr) auto}[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not(:has(>[data-ly-area="sidebar"]) ):not(:has(>[data-ly-area="aside"])){grid-template-areas:"header" "main" "footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr);grid-template-rows:auto minmax(0,1fr) auto}}@container ly-scope (min-width:72rem){[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):has(>[data-ly-area="sidebar"] ):not(:has(>[data-ly-area="aside"])){grid-template-areas:"sidebar header" "sidebar main" "sidebar footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),1fr)}[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not(:has(>[data-ly-area="sidebar"]) ):has(>[data-ly-area="aside"]){grid-template-areas:"header header" "main aside" "footer footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.35fr)}[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not(:has(>[data-ly-area="sidebar"]) ):not(:has(>[data-ly-area="aside"])){grid-template-areas:"header" "main" "footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr)}}}}@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-6{grid-column:span 6}.ly-span-full{grid-column:1 / -1}.ly-row-span-2{grid-row:span 2}.ly-row-span-3{grid-row:span 3}.ly-gap-0{gap:var(--ly-space-0)}.ly-gap-1{gap:var(--ly-space-1)}.ly-gap-2{gap:var(--ly-space-2)}.ly-gap-3{gap:var(--ly-space-3)}.ly-gap-4{gap:var(--ly-space-4)}.ly-gap-5{gap:var(--ly-space-5)}.ly-gap-6{gap:var(--ly-space-6)}.ly-gap-7{gap:var(--ly-space-7)}.ly-gap-8{gap:var(--ly-space-8)}.ly-gap-9{gap:var(--ly-space-9)}.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}}@layer ly.personalities.maximalist{:where(.ly-root[data-ly-layout="maximalist"]){--ly-personality-wrapper-max:100%;--ly-profile-gap:var(--ly-space-3);--ly-grid-min:10rem;--ly-card-grid-min:13rem;--ly-gallery-min:10rem;--ly-recipe-rail:15rem;--ly-recipe-aside:18rem}}@layer ly.personalities.bauhaus{:where(.ly-root[data-ly-layout="bauhaus"]){--ly-personality-wrapper-max:96rem;--ly-profile-gap:var(--ly-space-2);--ly-grid-min:13rem;--ly-recipe-rail:14rem;--ly-recipe-aside:18rem;--ly-split-primary:0.7fr;--ly-split-secondary:1.3fr}}@layer ly.personalities.tactile{:where(.ly-root[data-ly-layout="tactile"]){--ly-personality-wrapper-max:96rem;--ly-profile-gap:var(--ly-space-4);--ly-grid-min:15rem;--ly-recipe-rail:17rem;--ly-recipe-aside:20rem;--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),0.5fr) minmax(min(100%,var(--ly-pane-min)),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:22rem;--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),1.1fr) minmax(min(100%,var(--ly-pane-min)),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(min(100%,var(--ly-recipe-main-min)),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:100%;--ly-profile-gap:var(--ly-space-1);--ly-grid-min:14rem;--ly-recipe-rail:16rem;--ly-recipe-aside:18rem}}@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(min(100%,var(--ly-recipe-main-min)),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:100%;--ly-profile-gap:var(--ly-space-2);--ly-grid-min:13rem;--ly-recipe-rail:18rem;--ly-recipe-aside:16rem;--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(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.26fr)}}@layer ly.personalities.retro-glass{:where(.ly-root[data-ly-layout="retro-glass"]){--ly-personality-wrapper-max:100%;--ly-profile-gap:var(--ly-space-2);--ly-grid-min:15rem;--ly-recipe-rail:16rem;--ly-recipe-aside:17rem;--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.3fr) minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.28fr)}}@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(min(100%,var(--ly-recipe-main-min)),1.35fr) minmax(min(100%,var(--ly-recipe-aside)),0.65fr);--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),1.8fr) minmax(min(100%,var(--ly-split-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-split-min)),1.5fr) minmax(min(100%,var(--ly-split-min)),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-rows:auto minmax(0,1fr) auto auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(0,1fr);--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),1fr) minmax(min(100%,var(--ly-split-min)),1fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),1fr) minmax(min(100%,var(--ly-pane-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.34fr);--ly-reel-item-min:20rem}} diff --git a/dist/personalities/bauhaus.css b/dist/personalities/bauhaus.css index 886e579..3ec1c8f 100644 --- a/dist/personalities/bauhaus.css +++ b/dist/personalities/bauhaus.css @@ -3,18 +3,11 @@ @layer ly.personalities.bauhaus { :where(.ly-root[data-ly-layout="bauhaus"]) { --ly-personality-wrapper-max: 96rem; - --ly-profile-gap: var(--ly-space-6); + --ly-profile-gap: var(--ly-space-2); --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(min(100%, var(--ly-recipe-main-min)), 0.7fr) - minmax(0, 1.3fr) - minmax(min(100%, var(--ly-recipe-aside)), 0.3fr); + --ly-split-primary: 0.7fr; + --ly-split-secondary: 1.3fr; } } diff --git a/dist/personalities/bento.css b/dist/personalities/bento.css index d799469..e88273f 100644 --- a/dist/personalities/bento.css +++ b/dist/personalities/bento.css @@ -9,15 +9,5 @@ --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-rows: auto auto minmax(0, 1fr) auto; - --ly-app-shell-wide-columns: - minmax(min(100%, var(--ly-recipe-rail)), 0.3fr) - minmax(min(100%, var(--ly-recipe-main-min)), 1fr) - minmax(0, 1fr); } } diff --git a/dist/personalities/brutalism.css b/dist/personalities/brutalism.css index 79dc216..d092da9 100644 --- a/dist/personalities/brutalism.css +++ b/dist/personalities/brutalism.css @@ -2,18 +2,10 @@ @layer ly.personalities.brutalism { :where(.ly-root[data-ly-layout="brutalism"]) { - --ly-personality-wrapper-max: 100rem; - --ly-profile-gap: var(--ly-space-3); + --ly-personality-wrapper-max: 100%; + --ly-profile-gap: var(--ly-space-1); --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(min(100%, var(--ly-recipe-main-min)), 1.3fr) - minmax(0, 0.7fr) - minmax(min(100%, var(--ly-recipe-rail)), 0.34fr); } } diff --git a/dist/personalities/maximalist.css b/dist/personalities/maximalist.css index cae11df..2c2c077 100644 --- a/dist/personalities/maximalist.css +++ b/dist/personalities/maximalist.css @@ -3,20 +3,11 @@ @layer ly.personalities.maximalist { :where(.ly-root[data-ly-layout="maximalist"]) { --ly-personality-wrapper-max: 100%; - --ly-profile-gap: var(--ly-space-7); + --ly-profile-gap: var(--ly-space-3); --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(min(100%, var(--ly-recipe-main-min)), 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/neumorphism.css b/dist/personalities/neumorphism.css index f39f925..55641c0 100644 --- a/dist/personalities/neumorphism.css +++ b/dist/personalities/neumorphism.css @@ -6,16 +6,7 @@ --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-rows: auto minmax(0, 1fr) auto auto; - --ly-app-shell-wide-columns: - minmax(min(100%, var(--ly-recipe-main-min)), 1fr) - minmax(min(100%, var(--ly-recipe-rail)), 0.3fr); + --ly-recipe-aside: 22rem; --ly-list-detail-wide-columns: minmax(min(100%, var(--ly-pane-min)), 1.1fr) minmax(min(100%, var(--ly-pane-min)), 0.7fr); diff --git a/dist/personalities/retro-glass.css b/dist/personalities/retro-glass.css index 672a10e..3dd481e 100644 --- a/dist/personalities/retro-glass.css +++ b/dist/personalities/retro-glass.css @@ -2,18 +2,18 @@ @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-personality-wrapper-max: 100%; + --ly-profile-gap: var(--ly-space-2); --ly-grid-min: 15rem; - --ly-recipe-rail: 18rem; - --ly-recipe-aside: 18rem; + --ly-recipe-rail: 16rem; + --ly-recipe-aside: 17rem; --ly-app-shell-wide-areas: - "header header sidebar" - "main main sidebar" - "aside footer footer"; + "header header header" + "sidebar main aside" + "footer footer footer"; --ly-app-shell-wide-columns: - minmax(min(100%, var(--ly-recipe-main-min)), 1.25fr) - minmax(0, 0.75fr) - minmax(min(100%, var(--ly-recipe-rail)), 0.32fr); + minmax(min(100%, var(--ly-recipe-rail)), 0.3fr) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.28fr); } } diff --git a/dist/personalities/tactile.css b/dist/personalities/tactile.css index db5ce59..5d19972 100644 --- a/dist/personalities/tactile.css +++ b/dist/personalities/tactile.css @@ -2,20 +2,11 @@ @layer ly.personalities.tactile { :where(.ly-root[data-ly-layout="tactile"]) { - --ly-personality-wrapper-max: 82rem; + --ly-personality-wrapper-max: 96rem; --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-rows: auto auto minmax(0, 1fr) auto; - --ly-app-shell-wide-columns: - minmax(min(100%, var(--ly-recipe-rail)), 0.28fr) - minmax(min(100%, var(--ly-recipe-main-min)), 1fr); --ly-list-detail-wide-columns: minmax(min(100%, var(--ly-pane-min)), 0.5fr) minmax(min(100%, var(--ly-pane-min)), 0.9fr); diff --git a/dist/personalities/y2k.css b/dist/personalities/y2k.css index 1327693..a41e8c2 100644 --- a/dist/personalities/y2k.css +++ b/dist/personalities/y2k.css @@ -2,18 +2,18 @@ @layer ly.personalities.y2k { :where(.ly-root[data-ly-layout="y2k"]) { - --ly-personality-wrapper-max: 90rem; - --ly-profile-gap: var(--ly-space-6); + --ly-personality-wrapper-max: 100%; + --ly-profile-gap: var(--ly-space-2); --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"; + "header header header" + "sidebar main aside" + "footer footer footer"; --ly-app-shell-wide-columns: - minmax(min(100%, var(--ly-recipe-aside)), 0.34fr) + minmax(min(100%, var(--ly-recipe-rail)), 0.28fr) minmax(min(100%, var(--ly-recipe-main-min)), 1fr) - minmax(min(100%, var(--ly-recipe-rail)), 0.28fr); + minmax(min(100%, var(--ly-recipe-aside)), 0.26fr); } } diff --git a/styles/personalities/bauhaus.css b/styles/personalities/bauhaus.css index 886e579..3ec1c8f 100644 --- a/styles/personalities/bauhaus.css +++ b/styles/personalities/bauhaus.css @@ -3,18 +3,11 @@ @layer ly.personalities.bauhaus { :where(.ly-root[data-ly-layout="bauhaus"]) { --ly-personality-wrapper-max: 96rem; - --ly-profile-gap: var(--ly-space-6); + --ly-profile-gap: var(--ly-space-2); --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(min(100%, var(--ly-recipe-main-min)), 0.7fr) - minmax(0, 1.3fr) - minmax(min(100%, var(--ly-recipe-aside)), 0.3fr); + --ly-split-primary: 0.7fr; + --ly-split-secondary: 1.3fr; } } diff --git a/styles/personalities/bento.css b/styles/personalities/bento.css index d799469..e88273f 100644 --- a/styles/personalities/bento.css +++ b/styles/personalities/bento.css @@ -9,15 +9,5 @@ --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-rows: auto auto minmax(0, 1fr) auto; - --ly-app-shell-wide-columns: - minmax(min(100%, var(--ly-recipe-rail)), 0.3fr) - minmax(min(100%, var(--ly-recipe-main-min)), 1fr) - minmax(0, 1fr); } } diff --git a/styles/personalities/brutalism.css b/styles/personalities/brutalism.css index 79dc216..d092da9 100644 --- a/styles/personalities/brutalism.css +++ b/styles/personalities/brutalism.css @@ -2,18 +2,10 @@ @layer ly.personalities.brutalism { :where(.ly-root[data-ly-layout="brutalism"]) { - --ly-personality-wrapper-max: 100rem; - --ly-profile-gap: var(--ly-space-3); + --ly-personality-wrapper-max: 100%; + --ly-profile-gap: var(--ly-space-1); --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(min(100%, var(--ly-recipe-main-min)), 1.3fr) - minmax(0, 0.7fr) - minmax(min(100%, var(--ly-recipe-rail)), 0.34fr); } } diff --git a/styles/personalities/maximalist.css b/styles/personalities/maximalist.css index cae11df..2c2c077 100644 --- a/styles/personalities/maximalist.css +++ b/styles/personalities/maximalist.css @@ -3,20 +3,11 @@ @layer ly.personalities.maximalist { :where(.ly-root[data-ly-layout="maximalist"]) { --ly-personality-wrapper-max: 100%; - --ly-profile-gap: var(--ly-space-7); + --ly-profile-gap: var(--ly-space-3); --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(min(100%, var(--ly-recipe-main-min)), 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/neumorphism.css b/styles/personalities/neumorphism.css index f39f925..55641c0 100644 --- a/styles/personalities/neumorphism.css +++ b/styles/personalities/neumorphism.css @@ -6,16 +6,7 @@ --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-rows: auto minmax(0, 1fr) auto auto; - --ly-app-shell-wide-columns: - minmax(min(100%, var(--ly-recipe-main-min)), 1fr) - minmax(min(100%, var(--ly-recipe-rail)), 0.3fr); + --ly-recipe-aside: 22rem; --ly-list-detail-wide-columns: minmax(min(100%, var(--ly-pane-min)), 1.1fr) minmax(min(100%, var(--ly-pane-min)), 0.7fr); diff --git a/styles/personalities/retro-glass.css b/styles/personalities/retro-glass.css index 672a10e..3dd481e 100644 --- a/styles/personalities/retro-glass.css +++ b/styles/personalities/retro-glass.css @@ -2,18 +2,18 @@ @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-personality-wrapper-max: 100%; + --ly-profile-gap: var(--ly-space-2); --ly-grid-min: 15rem; - --ly-recipe-rail: 18rem; - --ly-recipe-aside: 18rem; + --ly-recipe-rail: 16rem; + --ly-recipe-aside: 17rem; --ly-app-shell-wide-areas: - "header header sidebar" - "main main sidebar" - "aside footer footer"; + "header header header" + "sidebar main aside" + "footer footer footer"; --ly-app-shell-wide-columns: - minmax(min(100%, var(--ly-recipe-main-min)), 1.25fr) - minmax(0, 0.75fr) - minmax(min(100%, var(--ly-recipe-rail)), 0.32fr); + minmax(min(100%, var(--ly-recipe-rail)), 0.3fr) + minmax(min(100%, var(--ly-recipe-main-min)), 1fr) + minmax(min(100%, var(--ly-recipe-aside)), 0.28fr); } } diff --git a/styles/personalities/tactile.css b/styles/personalities/tactile.css index db5ce59..5d19972 100644 --- a/styles/personalities/tactile.css +++ b/styles/personalities/tactile.css @@ -2,20 +2,11 @@ @layer ly.personalities.tactile { :where(.ly-root[data-ly-layout="tactile"]) { - --ly-personality-wrapper-max: 82rem; + --ly-personality-wrapper-max: 96rem; --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-rows: auto auto minmax(0, 1fr) auto; - --ly-app-shell-wide-columns: - minmax(min(100%, var(--ly-recipe-rail)), 0.28fr) - minmax(min(100%, var(--ly-recipe-main-min)), 1fr); --ly-list-detail-wide-columns: minmax(min(100%, var(--ly-pane-min)), 0.5fr) minmax(min(100%, var(--ly-pane-min)), 0.9fr); diff --git a/styles/personalities/y2k.css b/styles/personalities/y2k.css index 1327693..a41e8c2 100644 --- a/styles/personalities/y2k.css +++ b/styles/personalities/y2k.css @@ -2,18 +2,18 @@ @layer ly.personalities.y2k { :where(.ly-root[data-ly-layout="y2k"]) { - --ly-personality-wrapper-max: 90rem; - --ly-profile-gap: var(--ly-space-6); + --ly-personality-wrapper-max: 100%; + --ly-profile-gap: var(--ly-space-2); --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"; + "header header header" + "sidebar main aside" + "footer footer footer"; --ly-app-shell-wide-columns: - minmax(min(100%, var(--ly-recipe-aside)), 0.34fr) + minmax(min(100%, var(--ly-recipe-rail)), 0.28fr) minmax(min(100%, var(--ly-recipe-main-min)), 1fr) - minmax(min(100%, var(--ly-recipe-rail)), 0.28fr); + minmax(min(100%, var(--ly-recipe-aside)), 0.26fr); } } diff --git a/test/demo-smoke.test.mjs b/test/demo-smoke.test.mjs index 7ff0aea..0e9bd2d 100644 --- a/test/demo-smoke.test.mjs +++ b/test/demo-smoke.test.mjs @@ -1122,9 +1122,7 @@ const verifyAppShellRowGeometry = async (page, baseUrl) => { label: `wide ${personality}`, width: "73rem", personality, - rows: ["bento", "neumorphism", "split-screen", "tactile"].includes(personality) - ? 4 - : 3 + rows: personality === "split-screen" ? 4 : 3 })) ]; @@ -1579,6 +1577,76 @@ const verifyPersonalityMatrix = async (page, baseUrl) => { } }; +/** + * Verifies the defining rendered signatures for changed and deliberately + * preserved 3.2 personalities at a wide allocation. + * + * @param {import("@playwright/test").Page} page Active browser page. + * @param {string} baseUrl Demo server URL. + * @returns {Promise} + */ +const verifyPersonalityGeometry = async (page, baseUrl) => { + await page.setViewportSize({ width: 1920, height: 1080 }); + await page.goto( + `${baseUrl}?ecosystem=layout-only&wrapper=full&recipe=app-shell&container=73rem&height=50rem`, + { waitUntil: "domcontentloaded" } + ); + await page.waitForFunction(() => document.body.dataset.demoReady === "true"); + + const snapshots = {}; + for (const personality of [ + "bento", + "maximalist", + "bauhaus", + "tactile", + "neumorphism", + "brutalism", + "y2k", + "retro-glass", + "retrofuturism", + "cyberpunk", + "split-screen" + ]) { + await setControl(page, "personalitySelect", personality); + snapshots[personality] = await page.evaluate(() => { + const root = document.querySelector("#previewRoot"); + const recipe = document.querySelector('[data-ly-recipe="app-shell"]'); + const style = getComputedStyle(recipe); + const rootStyle = getComputedStyle(root); + const sidebar = recipe.querySelector('[data-ly-area="sidebar"]').getBoundingClientRect(); + const main = recipe.querySelector('[data-ly-area="main"]').getBoundingClientRect(); + return { + areas: style.gridTemplateAreas, + tracks: style.gridTemplateColumns.split(/\s+/).filter(Boolean).map(Number.parseFloat), + trackCount: style.gridTemplateColumns.split(/\s+/).filter(Boolean).length, + profileGap: rootStyle.getPropertyValue("--ly-profile-gap").trim(), + wrapper: rootStyle.getPropertyValue("--ly-personality-wrapper-max").trim(), + sidebarBeforeMain: sidebar.left < main.left + }; + }); + } + + assert.equal(snapshots.bento.trackCount, 3, "Bento must remove its old four-track shell."); + assert.equal(snapshots.maximalist.profileGap, "0.75rem"); + assert.equal(snapshots.bauhaus.profileGap, "0.5rem"); + assert.equal(snapshots.tactile.wrapper, "96rem"); + assert(snapshots.neumorphism.sidebarBeforeMain, "Neumorphism must not keep a right sidebar."); + assert.equal(snapshots.brutalism.wrapper, "100%"); + assert.equal(snapshots.brutalism.profileGap, "0.25rem"); + for (const personality of ["y2k", "retro-glass"]) { + assert.match(snapshots[personality].areas, /"header header header"/); + assert.match(snapshots[personality].areas, /"sidebar main aside"/); + assert.match(snapshots[personality].areas, /"footer footer footer"/); + } + assert.match(snapshots.retrofuturism.areas, /"sidebar header aside"/); + assert.match(snapshots.cyberpunk.areas, /"sidebar header header"/); + assert.equal(snapshots["split-screen"].trackCount, 2); + assert( + Math.abs(snapshots["split-screen"].tracks[0] - snapshots["split-screen"].tracks[1]) <= 2, + "Split Screen must preserve equal App Shell halves." + ); +}; + const verifyMinimumWidth = async (page, baseUrl) => { await page.setViewportSize({ width: 320, height: 800 }); await page.goto(`${baseUrl}?ecosystem=layout-only&device=custom&container=auto`, { @@ -1705,7 +1773,7 @@ const verifyProfileAndUtilityIsolation = async (page, baseUrl) => { const result = await page.evaluate(() => { const innerRoot = document.createElement("section"); innerRoot.className = "ly-root"; - innerRoot.dataset.lyLayout = "bauhaus"; + innerRoot.dataset.lyLayout = "bento"; innerRoot.dataset.lyDensity = "normal"; innerRoot.style.inlineSize = "50rem"; innerRoot.style.maxInlineSize = "100%"; @@ -1988,6 +2056,7 @@ try { await verifyDefaultFontHeightTiers(server.baseUrl); await verifyDeviceMatrix(page, server.baseUrl); await verifyPersonalityMatrix(page, server.baseUrl); + await verifyPersonalityGeometry(page, server.baseUrl); await verifyMinimumWidth(page, server.baseUrl); await verifyWorkspaceMeasure(page, server.baseUrl); await verifyBreakoutGeometry(page, server.baseUrl); diff --git a/test/layout-css-contract.test.mjs b/test/layout-css-contract.test.mjs index 9600495..0b81a5a 100644 --- a/test/layout-css-contract.test.mjs +++ b/test/layout-css-contract.test.mjs @@ -106,6 +106,19 @@ function minifyCss(css) { .trim(); } +/** + * Returns one normalized custom-property value from authored CSS. + * + * @param {string} css Authored stylesheet source. + * @param {string} property Custom-property name. + * @returns {string} Whitespace-normalized custom-property value. + */ +function customPropertyValue(css, property) { + const value = css.match(new RegExp(`${property}\\s*:\\s*([^;]+);`, "s"))?.[1]; + assert(value, `Missing required personality token ${property}.`); + return value.replace(/\s+/g, " ").trim(); +} + assert.equal(packageJson.version, "3.1.0", "The minor branch must expose version 3.1.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"); @@ -208,6 +221,59 @@ assert.equal( "Every personality must expose a unique spatial signature" ); +const personalityTargets = { + "minimal-saas": ["88rem", "var(--ly-space-5)", "16rem", "15rem", "16rem"], + bento: ["112rem", "var(--ly-space-4)", "12rem", "14rem", "18rem"], + maximalist: ["100%", "var(--ly-space-3)", "10rem", "15rem", "18rem"], + bauhaus: ["96rem", "var(--ly-space-2)", "13rem", "14rem", "18rem"], + tactile: ["96rem", "var(--ly-space-4)", "15rem", "17rem", "20rem"], + neumorphism: ["84rem", "var(--ly-space-6)", "17rem", "17rem", "22rem"], + retrofuturism: ["106rem", "var(--ly-space-5)", "14rem", "14rem", "17rem"], + brutalism: ["100%", "var(--ly-space-1)", "14rem", "16rem", "18rem"], + cyberpunk: ["112rem", "var(--ly-space-4)", "12rem", "13rem", "19rem"], + y2k: ["100%", "var(--ly-space-2)", "13rem", "18rem", "16rem"], + "retro-glass": ["100%", "var(--ly-space-2)", "15rem", "16rem", "17rem"], + "f-pattern": ["92rem", "var(--ly-space-4)", "14rem", "16rem", "18rem"], + "z-pattern": ["108rem", "var(--ly-space-5)", "14rem", "17rem", "19rem"], + "split-screen": ["100%", "var(--ly-space-4)", "20rem", "24rem", "24rem"], + mondrian: ["112rem", "var(--ly-space-3)", "11rem", "13rem", "18rem"], + synthwave: ["112rem", "var(--ly-space-6)", "14rem", "16rem", "20rem"] +}; +const targetProperties = [ + "--ly-personality-wrapper-max", + "--ly-profile-gap", + "--ly-grid-min", + "--ly-recipe-rail", + "--ly-recipe-aside" +]; +for (const [name, values] of Object.entries(personalityTargets)) { + const css = readStyle(`personalities/${name}.css`); + assert.deepEqual( + targetProperties.map((property) => customPropertyValue(css, property)), + values, + `${name} geometry drifted from the approved 3.2 target table.` + ); +} +for (const name of ["bento", "maximalist", "bauhaus", "tactile", "neumorphism", "brutalism"]) { + assert( + !readStyle(`personalities/${name}.css`).includes("--ly-app-shell-wide-areas:"), + `${name} must use the shared area-aware App Shell.` + ); +} +assert.equal(customPropertyValue(readStyle("personalities/minimal-saas.css"), "--ly-split-primary"), "1.05fr"); +assert.equal(customPropertyValue(readStyle("personalities/minimal-saas.css"), "--ly-split-secondary"), "0.95fr"); +assert.equal(customPropertyValue(readStyle("personalities/bento.css"), "--ly-card-grid-min"), "14rem"); +assert.equal(customPropertyValue(readStyle("personalities/bento.css"), "--ly-gallery-min"), "11rem"); +assert.equal(customPropertyValue(readStyle("personalities/maximalist.css"), "--ly-card-grid-min"), "13rem"); +assert.equal(customPropertyValue(readStyle("personalities/maximalist.css"), "--ly-gallery-min"), "10rem"); +assert.equal(customPropertyValue(readStyle("personalities/bauhaus.css"), "--ly-split-primary"), "0.7fr"); +assert.equal(customPropertyValue(readStyle("personalities/bauhaus.css"), "--ly-split-secondary"), "1.3fr"); +assert.match(customPropertyValue(readStyle("personalities/tactile.css"), "--ly-list-detail-wide-columns"), /0\.5fr[\s\S]*0\.9fr/); +assert.match(customPropertyValue(readStyle("personalities/neumorphism.css"), "--ly-list-detail-wide-columns"), /1\.1fr[\s\S]*0\.7fr/); +assert.match(customPropertyValue(readStyle("personalities/f-pattern.css"), "--ly-split-hero-wide-columns"), /1\.8fr[\s\S]*0\.8fr/); +assert.match(customPropertyValue(readStyle("personalities/z-pattern.css"), "--ly-split-hero-wide-columns"), /1\.5fr[\s\S]*0\.5fr/); +assert.equal(customPropertyValue(readStyle("personalities/synthwave.css"), "--ly-reel-item-min"), "20rem"); + 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( @@ -498,7 +564,7 @@ for (const [topology, token] of Object.entries(appShellRowTokens)) { `App Shell ${topology} topology must consume ${token}.` ); } -for (const personality of ["bento", "neumorphism", "split-screen", "tactile"]) { +for (const personality of ["split-screen"]) { assert( readStyle(`personalities/${personality}.css`).includes("--ly-app-shell-wide-rows:"), `${personality} must describe its four-row wide App Shell.` From b591f3028b500559dd0562390c7b26d4d1931427 Mon Sep 17 00:00:00 2001 From: Foscat Date: Thu, 3 Sep 2026 09:29:01 -0500 Subject: [PATCH 07/11] feat: add specialized layout personalities --- dist/layout-style-css.css | 51 +++++++++++++++ dist/layout-style-css.min.css | 2 +- dist/personalities.css | 4 ++ dist/personalities/data-terminal.css | 13 ++++ dist/personalities/editorial.css | 14 ++++ dist/personalities/industrial-hmi.css | 11 ++++ dist/personalities/technical-blueprint.css | 13 ++++ scripts/build.mjs | 28 +++++++- styles/personalities.css | 4 ++ styles/personalities/data-terminal.css | 13 ++++ styles/personalities/editorial.css | 14 ++++ styles/personalities/industrial-hmi.css | 11 ++++ styles/personalities/technical-blueprint.css | 13 ++++ test/demo-smoke.test.mjs | 68 ++++++++++++++++++++ test/layout-css-contract.test.mjs | 40 ++++++++++-- 15 files changed, 291 insertions(+), 8 deletions(-) create mode 100644 dist/personalities/data-terminal.css create mode 100644 dist/personalities/editorial.css create mode 100644 dist/personalities/industrial-hmi.css create mode 100644 dist/personalities/technical-blueprint.css create mode 100644 styles/personalities/data-terminal.css create mode 100644 styles/personalities/editorial.css create mode 100644 styles/personalities/industrial-hmi.css create mode 100644 styles/personalities/technical-blueprint.css diff --git a/dist/layout-style-css.css b/dist/layout-style-css.css index 4d6a5a6..ad96cb4 100644 --- a/dist/layout-style-css.css +++ b/dist/layout-style-css.css @@ -1381,3 +1381,54 @@ --ly-reel-item-min: 20rem; } } + +/* personalities/technical-blueprint.css */ +@layer ly.personalities.technical-blueprint { + :where(.ly-root[data-ly-layout="technical-blueprint"]) { + --ly-personality-wrapper-max: 100%; + --ly-profile-gap: var(--ly-space-1); + --ly-grid-min: 10rem; + --ly-recipe-rail: 11rem; + --ly-recipe-aside: 26rem; + --ly-split-primary: 2.2fr; + --ly-split-secondary: 0.8fr; + } +} + +/* personalities/data-terminal.css */ +@layer ly.personalities.data-terminal { + :where(.ly-root[data-ly-layout="data-terminal"]) { + --ly-personality-wrapper-max: 100%; + --ly-profile-gap: var(--ly-space-1); + --ly-grid-min: 10rem; + --ly-card-grid-min: 10rem; + --ly-gallery-min: 10rem; + --ly-recipe-rail: 12rem; + --ly-recipe-aside: 18rem; + } +} + +/* personalities/industrial-hmi.css */ +@layer ly.personalities.industrial-hmi { + :where(.ly-root[data-ly-layout="industrial-hmi"]) { + --ly-personality-wrapper-max: 100%; + --ly-profile-gap: var(--ly-space-2); + --ly-grid-min: 11rem; + --ly-recipe-rail: 7rem; + --ly-recipe-aside: 32rem; + } +} + +/* personalities/editorial.css */ +@layer ly.personalities.editorial { + :where(.ly-root[data-ly-layout="editorial"]) { + --ly-personality-wrapper-max: 108rem; + --ly-profile-gap: var(--ly-space-6); + --ly-grid-min: 16rem; + --ly-recipe-rail: 10rem; + --ly-recipe-aside: 18rem; + --ly-split-primary: 1.65fr; + --ly-split-secondary: 0.75fr; + --ly-frame-ratio: 4 / 5; + } +} diff --git a/dist/layout-style-css.min.css b/dist/layout-style-css.min.css index 40c657b..fe88b52 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.context;@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-workspace:96rem;--ly-wrapper-wide:112rem;--ly-page-padding-inline:clamp(1rem,3vw,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:var(--ly-page-padding-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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem);--ly-header-height:4.5rem;--ly-sticky-position:sticky;--ly-cover-min:100vh;--ly-shell-min:100vh;--ly-scroll-max:50rem;--ly-scroll-viewport-max:min(70vh,50rem);--ly-switcher-threshold:42rem;--ly-sidebar-size:18rem;--ly-sidebar-content-min:50%;--ly-grid-columns:12;--ly-grid-min:16rem;--ly-mosaic-medium-columns:6;--ly-mosaic-wide-columns:12;--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-split-primary:1fr;--ly-split-secondary:1fr;--ly-recipe-main-min:20rem;--ly-recipe-rail:18rem;--ly-recipe-aside:22rem;--ly-gallery-min:12rem;--ly-card-grid-min:16rem;--ly-app-shell-base-rows:auto auto minmax(0,1fr) auto auto;--ly-app-shell-medium-areas:"header header" "sidebar main" "aside main" "footer footer";--ly-app-shell-medium-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-medium-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),1fr);--ly-app-shell-wide-areas:"sidebar header header" "sidebar main aside" "sidebar footer footer";--ly-app-shell-wide-rows:auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1fr);--ly-list-detail-wide-areas:"primary secondary" "actions actions";--ly-list-detail-wide-columns:minmax(min(100%,max(var(--ly-pane-min),var(--ly-pane-size))),0.7fr) minmax(min(100%,var(--ly-pane-min)),1fr);--ly-split-hero-wide-areas:"content media" "actions media";--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),var(--ly-split-primary,1fr)) minmax(min(100%,var(--ly-split-min)),var(--ly-split-secondary,1fr));container-name:ly-scope;container-type:inline-size;min-inline-size:0;min-block-size:0}@supports (width:1cqi){:where(.ly-root){--ly-page-padding-inline:clamp(1rem,3cqi,3rem)}}@supports (height:100dvh){:where(.ly-root){--ly-cover-min:100dvh;--ly-shell-min:100dvh;--ly-scroll-viewport-max:min(70dvh,50rem)}}}@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),3vh);--ly-cluster-gap:min(var(--ly-space-3),2vh);--ly-section-padding-block:clamp(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem);--ly-header-height:3.5rem;--ly-scroll-viewport-max:min(62vh,34rem)}@supports (height:100dvh){:where(.ly-root){--ly-stack-gap:min(var(--ly-space-4),3dvh);--ly-cluster-gap:min(var(--ly-space-3),2dvh);--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem);--ly-scroll-viewport-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-4);--ly-section-padding-block-compact:var(--ly-space-2);--ly-scroll-viewport-max:max(12rem,calc(100vh - 8rem))}@supports (height:100dvh){:where(.ly-root){--ly-scroll-viewport-max:max(12rem,calc(100dvh - 8rem))}}}}@layer ly.context{:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(1rem,2.5vh,2rem);--ly-section-padding-block-compact:clamp(0.5rem,1.5vh,1rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:max(var(--ly-profile-gap),var(--ly-space-6));--ly-grid-gap:var(--ly-gap);--ly-stack-gap:var(--ly-space-5);--ly-cluster-gap:var(--ly-space-4);--ly-section-padding-block:clamp(3rem,7vh,6rem);--ly-section-padding-block-compact:clamp(1.5rem,3.5vh,3rem)}@media (max-height:44rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(0.75rem,2vh,1.25rem);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-gap:min(var(--ly-profile-gap),var(--ly-space-4));--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(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:var(--ly-space-5);--ly-grid-gap:var(--ly-space-5);--ly-stack-gap:var(--ly-space-4);--ly-cluster-gap:var(--ly-space-3);--ly-section-padding-block:clamp(1.5rem,6vh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3vh,1.25rem)}@supports (height:100dvh){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--ly-section-padding-block:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-section-padding-block:clamp(1.5rem,6dvh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3dvh,1.25rem)}}}@media (max-height:30rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-1);--ly-section-padding-block:var(--ly-space-3);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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-2);--ly-section-padding-block:var(--ly-space-4);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--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-3);--ly-section-padding-block:var(--ly-space-5);--ly-section-padding-block-compact:var(--ly-space-3)}}}@layer ly.wrappers{.ly-wrapper{--ly-wrapper-max:var(--ly-personality-wrapper-max,var(--ly-wrapper-content));--ly-wrapper-fluid-gutter:var(--ly-wrapper-gutter);--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--workspace{--ly-wrapper-max:var(--ly-wrapper-workspace)}.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,sticky);inset-block-start:0;z-index:var(--ly-z-header,20)}.ly-section{padding-block:var(--ly-section-padding-block)}.ly-section--compact{padding-block:var(--ly-section-padding-block-compact)}.ly-section--flush{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-mosaic{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--ly-grid-gap)}.ly-mosaic>*{min-inline-size:0;min-block-size:0}.ly-action-bar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ly-cluster-gap);min-inline-size:0;padding-block-end:var(--ly-safe-area-block-end)}.ly-action-bar>:where([data-ly-actions="start"],[data-ly-actions="end"]){display:flex;flex-wrap:wrap;align-items:center;gap:var(--ly-cluster-gap);min-inline-size:0}.ly-action-bar>[data-ly-actions="end"]{margin-inline-start:auto}.ly-action-bar--sticky{position:var(--ly-sticky-position,sticky);inset-block-end:0;z-index:var(--ly-z-header,20)}.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;overflow:auto;overscroll-behavior-block:contain}.ly-scroll--bounded{max-block-size:var(--ly-scroll-max)}.ly-scroll--viewport{max-block-size:var(--ly-scroll-viewport-max)}}@layer ly.context{.ly-mosaic:not([data-ly-responsive="manual"])>:where( .ly-span-1,.ly-span-2,.ly-span-3,.ly-span-4,.ly-span-6,.ly-span-full ){grid-column:1 / -1}.ly-mosaic:not([data-ly-responsive="manual"])>:where( .ly-row-span-2,.ly-row-span-3 ){grid-row:auto}@container ly-scope (min-width:42rem){.ly-mosaic:not([data-ly-responsive="manual"]){grid-template-columns:repeat( var(--ly-mosaic-medium-columns),minmax(0,1fr) )}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-1{grid-column:span 1}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-2{grid-column:span 2}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-3{grid-column:span 3}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-4{grid-column:span 4}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-6{grid-column:span 6}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-full{grid-column:1 / -1}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-row-span-2{grid-row:span 2}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-row-span-3{grid-row:span 3}}@container ly-scope (min-width:72rem){.ly-mosaic:not([data-ly-responsive="manual"]){grid-template-columns:repeat( var(--ly-mosaic-wide-columns),minmax(0,1fr) )}}}@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:var(--ly-app-shell-base-rows)}[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="gallery"],[data-ly-recipe="card-grid"] )[data-ly-responsive="manual"]{grid-template-columns:minmax(0,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);grid-template-rows:var(--ly-app-shell-medium-rows)}[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);grid-template-rows:var(--ly-app-shell-wide-rows)}[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)}}@supports selector(:has(*)){@container ly-scope (min-width:52rem){[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):has(>[data-ly-area="sidebar"] ):not(:has(>[data-ly-area="aside"])){grid-template-areas:"header header" "sidebar main" "footer footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),1fr);grid-template-rows:auto minmax(0,1fr) auto}[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not(:has(>[data-ly-area="sidebar"]) ):has(>[data-ly-area="aside"]){grid-template-areas:"header header" "main aside" "footer footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.35fr);grid-template-rows:auto minmax(0,1fr) auto}[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not(:has(>[data-ly-area="sidebar"]) ):not(:has(>[data-ly-area="aside"])){grid-template-areas:"header" "main" "footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr);grid-template-rows:auto minmax(0,1fr) auto}}@container ly-scope (min-width:72rem){[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):has(>[data-ly-area="sidebar"] ):not(:has(>[data-ly-area="aside"])){grid-template-areas:"sidebar header" "sidebar main" "sidebar footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),1fr)}[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not(:has(>[data-ly-area="sidebar"]) ):has(>[data-ly-area="aside"]){grid-template-areas:"header header" "main aside" "footer footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.35fr)}[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not(:has(>[data-ly-area="sidebar"]) ):not(:has(>[data-ly-area="aside"])){grid-template-areas:"header" "main" "footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr)}}}}@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-6{grid-column:span 6}.ly-span-full{grid-column:1 / -1}.ly-row-span-2{grid-row:span 2}.ly-row-span-3{grid-row:span 3}.ly-gap-0{gap:var(--ly-space-0)}.ly-gap-1{gap:var(--ly-space-1)}.ly-gap-2{gap:var(--ly-space-2)}.ly-gap-3{gap:var(--ly-space-3)}.ly-gap-4{gap:var(--ly-space-4)}.ly-gap-5{gap:var(--ly-space-5)}.ly-gap-6{gap:var(--ly-space-6)}.ly-gap-7{gap:var(--ly-space-7)}.ly-gap-8{gap:var(--ly-space-8)}.ly-gap-9{gap:var(--ly-space-9)}.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}}@layer ly.personalities.maximalist{:where(.ly-root[data-ly-layout="maximalist"]){--ly-personality-wrapper-max:100%;--ly-profile-gap:var(--ly-space-3);--ly-grid-min:10rem;--ly-card-grid-min:13rem;--ly-gallery-min:10rem;--ly-recipe-rail:15rem;--ly-recipe-aside:18rem}}@layer ly.personalities.bauhaus{:where(.ly-root[data-ly-layout="bauhaus"]){--ly-personality-wrapper-max:96rem;--ly-profile-gap:var(--ly-space-2);--ly-grid-min:13rem;--ly-recipe-rail:14rem;--ly-recipe-aside:18rem;--ly-split-primary:0.7fr;--ly-split-secondary:1.3fr}}@layer ly.personalities.tactile{:where(.ly-root[data-ly-layout="tactile"]){--ly-personality-wrapper-max:96rem;--ly-profile-gap:var(--ly-space-4);--ly-grid-min:15rem;--ly-recipe-rail:17rem;--ly-recipe-aside:20rem;--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),0.5fr) minmax(min(100%,var(--ly-pane-min)),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:22rem;--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),1.1fr) minmax(min(100%,var(--ly-pane-min)),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(min(100%,var(--ly-recipe-main-min)),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:100%;--ly-profile-gap:var(--ly-space-1);--ly-grid-min:14rem;--ly-recipe-rail:16rem;--ly-recipe-aside:18rem}}@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(min(100%,var(--ly-recipe-main-min)),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:100%;--ly-profile-gap:var(--ly-space-2);--ly-grid-min:13rem;--ly-recipe-rail:18rem;--ly-recipe-aside:16rem;--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(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.26fr)}}@layer ly.personalities.retro-glass{:where(.ly-root[data-ly-layout="retro-glass"]){--ly-personality-wrapper-max:100%;--ly-profile-gap:var(--ly-space-2);--ly-grid-min:15rem;--ly-recipe-rail:16rem;--ly-recipe-aside:17rem;--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.3fr) minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.28fr)}}@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(min(100%,var(--ly-recipe-main-min)),1.35fr) minmax(min(100%,var(--ly-recipe-aside)),0.65fr);--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),1.8fr) minmax(min(100%,var(--ly-split-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-split-min)),1.5fr) minmax(min(100%,var(--ly-split-min)),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-rows:auto minmax(0,1fr) auto auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(0,1fr);--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),1fr) minmax(min(100%,var(--ly-split-min)),1fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),1fr) minmax(min(100%,var(--ly-pane-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.34fr);--ly-reel-item-min:20rem}} +@layer ly.reset,ly.tokens,ly.wrappers,ly.primitives,ly.recipes,ly.utilities,ly.personalities,ly.context;@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-workspace:96rem;--ly-wrapper-wide:112rem;--ly-page-padding-inline:clamp(1rem,3vw,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:var(--ly-page-padding-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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem);--ly-header-height:4.5rem;--ly-sticky-position:sticky;--ly-cover-min:100vh;--ly-shell-min:100vh;--ly-scroll-max:50rem;--ly-scroll-viewport-max:min(70vh,50rem);--ly-switcher-threshold:42rem;--ly-sidebar-size:18rem;--ly-sidebar-content-min:50%;--ly-grid-columns:12;--ly-grid-min:16rem;--ly-mosaic-medium-columns:6;--ly-mosaic-wide-columns:12;--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-split-primary:1fr;--ly-split-secondary:1fr;--ly-recipe-main-min:20rem;--ly-recipe-rail:18rem;--ly-recipe-aside:22rem;--ly-gallery-min:12rem;--ly-card-grid-min:16rem;--ly-app-shell-base-rows:auto auto minmax(0,1fr) auto auto;--ly-app-shell-medium-areas:"header header" "sidebar main" "aside main" "footer footer";--ly-app-shell-medium-rows:auto auto minmax(0,1fr) auto;--ly-app-shell-medium-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),1fr);--ly-app-shell-wide-areas:"sidebar header header" "sidebar main aside" "sidebar footer footer";--ly-app-shell-wide-rows:auto minmax(0,1fr) auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1fr);--ly-list-detail-wide-areas:"primary secondary" "actions actions";--ly-list-detail-wide-columns:minmax(min(100%,max(var(--ly-pane-min),var(--ly-pane-size))),0.7fr) minmax(min(100%,var(--ly-pane-min)),1fr);--ly-split-hero-wide-areas:"content media" "actions media";--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),var(--ly-split-primary,1fr)) minmax(min(100%,var(--ly-split-min)),var(--ly-split-secondary,1fr));container-name:ly-scope;container-type:inline-size;min-inline-size:0;min-block-size:0}@supports (width:1cqi){:where(.ly-root){--ly-page-padding-inline:clamp(1rem,3cqi,3rem)}}@supports (height:100dvh){:where(.ly-root){--ly-cover-min:100dvh;--ly-shell-min:100dvh;--ly-scroll-viewport-max:min(70dvh,50rem)}}}@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),3vh);--ly-cluster-gap:min(var(--ly-space-3),2vh);--ly-section-padding-block:clamp(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem);--ly-header-height:3.5rem;--ly-scroll-viewport-max:min(62vh,34rem)}@supports (height:100dvh){:where(.ly-root){--ly-stack-gap:min(var(--ly-space-4),3dvh);--ly-cluster-gap:min(var(--ly-space-3),2dvh);--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem);--ly-scroll-viewport-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-4);--ly-section-padding-block-compact:var(--ly-space-2);--ly-scroll-viewport-max:max(12rem,calc(100vh - 8rem))}@supports (height:100dvh){:where(.ly-root){--ly-scroll-viewport-max:max(12rem,calc(100dvh - 8rem))}}}}@layer ly.context{:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(1rem,2.5vh,2rem);--ly-section-padding-block-compact:clamp(0.5rem,1.5vh,1rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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(2rem,4vh,4rem);--ly-section-padding-block-compact:clamp(1rem,2.5vh,2rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:max(var(--ly-profile-gap),var(--ly-space-6));--ly-grid-gap:var(--ly-gap);--ly-stack-gap:var(--ly-space-5);--ly-cluster-gap:var(--ly-space-4);--ly-section-padding-block:clamp(3rem,7vh,6rem);--ly-section-padding-block-compact:clamp(1.5rem,3.5vh,3rem)}@media (max-height:44rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-2);--ly-section-padding-block:clamp(0.75rem,2vh,1.25rem);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-gap:min(var(--ly-profile-gap),var(--ly-space-4));--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(1.25rem,4vh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2vh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-gap:var(--ly-space-5);--ly-grid-gap:var(--ly-space-5);--ly-stack-gap:var(--ly-space-4);--ly-cluster-gap:var(--ly-space-3);--ly-section-padding-block:clamp(1.5rem,6vh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3vh,1.25rem)}@supports (height:100dvh){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--ly-section-padding-block:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--ly-section-padding-block:clamp(1.25rem,4dvh,2rem);--ly-section-padding-block-compact:clamp(0.75rem,2dvh,1.25rem)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--ly-section-padding-block:clamp(1.5rem,6dvh,3rem);--ly-section-padding-block-compact:clamp(0.75rem,3dvh,1.25rem)}}}@media (max-height:30rem){:where( .ly-root[data-ly-density="compact"],.ly-root [data-ly-density="compact"] ){--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-1);--ly-section-padding-block:var(--ly-space-3);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="normal"],.ly-root [data-ly-density="normal"] ){--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-2);--ly-section-padding-block:var(--ly-space-4);--ly-section-padding-block-compact:var(--ly-space-2)}:where( .ly-root[data-ly-density="spacious"],.ly-root [data-ly-density="spacious"] ){--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-3);--ly-section-padding-block:var(--ly-space-5);--ly-section-padding-block-compact:var(--ly-space-3)}}}@layer ly.wrappers{.ly-wrapper{--ly-wrapper-max:var(--ly-personality-wrapper-max,var(--ly-wrapper-content));--ly-wrapper-fluid-gutter:var(--ly-wrapper-gutter);--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--workspace{--ly-wrapper-max:var(--ly-wrapper-workspace)}.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,sticky);inset-block-start:0;z-index:var(--ly-z-header,20)}.ly-section{padding-block:var(--ly-section-padding-block)}.ly-section--compact{padding-block:var(--ly-section-padding-block-compact)}.ly-section--flush{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-mosaic{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--ly-grid-gap)}.ly-mosaic>*{min-inline-size:0;min-block-size:0}.ly-action-bar{display:flex;flex-wrap:wrap;align-items:center;gap:var(--ly-cluster-gap);min-inline-size:0;padding-block-end:var(--ly-safe-area-block-end)}.ly-action-bar>:where([data-ly-actions="start"],[data-ly-actions="end"]){display:flex;flex-wrap:wrap;align-items:center;gap:var(--ly-cluster-gap);min-inline-size:0}.ly-action-bar>[data-ly-actions="end"]{margin-inline-start:auto}.ly-action-bar--sticky{position:var(--ly-sticky-position,sticky);inset-block-end:0;z-index:var(--ly-z-header,20)}.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;overflow:auto;overscroll-behavior-block:contain}.ly-scroll--bounded{max-block-size:var(--ly-scroll-max)}.ly-scroll--viewport{max-block-size:var(--ly-scroll-viewport-max)}}@layer ly.context{.ly-mosaic:not([data-ly-responsive="manual"])>:where( .ly-span-1,.ly-span-2,.ly-span-3,.ly-span-4,.ly-span-6,.ly-span-full ){grid-column:1 / -1}.ly-mosaic:not([data-ly-responsive="manual"])>:where( .ly-row-span-2,.ly-row-span-3 ){grid-row:auto}@container ly-scope (min-width:42rem){.ly-mosaic:not([data-ly-responsive="manual"]){grid-template-columns:repeat( var(--ly-mosaic-medium-columns),minmax(0,1fr) )}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-1{grid-column:span 1}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-2{grid-column:span 2}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-3{grid-column:span 3}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-4{grid-column:span 4}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-6{grid-column:span 6}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-span-full{grid-column:1 / -1}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-row-span-2{grid-row:span 2}.ly-mosaic:not([data-ly-responsive="manual"])>.ly-row-span-3{grid-row:span 3}}@container ly-scope (min-width:72rem){.ly-mosaic:not([data-ly-responsive="manual"]){grid-template-columns:repeat( var(--ly-mosaic-wide-columns),minmax(0,1fr) )}}}@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:var(--ly-app-shell-base-rows)}[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="gallery"],[data-ly-recipe="card-grid"] )[data-ly-responsive="manual"]{grid-template-columns:minmax(0,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);grid-template-rows:var(--ly-app-shell-medium-rows)}[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);grid-template-rows:var(--ly-app-shell-wide-rows)}[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)}}@supports selector(:has(*)){@container ly-scope (min-width:52rem){[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):has(>[data-ly-area="sidebar"] ):not(:has(>[data-ly-area="aside"])){grid-template-areas:"header header" "sidebar main" "footer footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),1fr);grid-template-rows:auto minmax(0,1fr) auto}[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not(:has(>[data-ly-area="sidebar"]) ):has(>[data-ly-area="aside"]){grid-template-areas:"header header" "main aside" "footer footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.35fr);grid-template-rows:auto minmax(0,1fr) auto}[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not(:has(>[data-ly-area="sidebar"]) ):not(:has(>[data-ly-area="aside"])){grid-template-areas:"header" "main" "footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr);grid-template-rows:auto minmax(0,1fr) auto}}@container ly-scope (min-width:72rem){[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):has(>[data-ly-area="sidebar"] ):not(:has(>[data-ly-area="aside"])){grid-template-areas:"sidebar header" "sidebar main" "sidebar footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-rail)),auto) minmax(min(100%,var(--ly-recipe-main-min)),1fr)}[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not(:has(>[data-ly-area="sidebar"]) ):has(>[data-ly-area="aside"]){grid-template-areas:"header header" "main aside" "footer footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.35fr)}[data-ly-recipe="app-shell"]:not([data-ly-responsive="manual"]):not(:has(>[data-ly-area="sidebar"]) ):not(:has(>[data-ly-area="aside"])){grid-template-areas:"header" "main" "footer";grid-template-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr)}}}}@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-6{grid-column:span 6}.ly-span-full{grid-column:1 / -1}.ly-row-span-2{grid-row:span 2}.ly-row-span-3{grid-row:span 3}.ly-gap-0{gap:var(--ly-space-0)}.ly-gap-1{gap:var(--ly-space-1)}.ly-gap-2{gap:var(--ly-space-2)}.ly-gap-3{gap:var(--ly-space-3)}.ly-gap-4{gap:var(--ly-space-4)}.ly-gap-5{gap:var(--ly-space-5)}.ly-gap-6{gap:var(--ly-space-6)}.ly-gap-7{gap:var(--ly-space-7)}.ly-gap-8{gap:var(--ly-space-8)}.ly-gap-9{gap:var(--ly-space-9)}.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}}@layer ly.personalities.maximalist{:where(.ly-root[data-ly-layout="maximalist"]){--ly-personality-wrapper-max:100%;--ly-profile-gap:var(--ly-space-3);--ly-grid-min:10rem;--ly-card-grid-min:13rem;--ly-gallery-min:10rem;--ly-recipe-rail:15rem;--ly-recipe-aside:18rem}}@layer ly.personalities.bauhaus{:where(.ly-root[data-ly-layout="bauhaus"]){--ly-personality-wrapper-max:96rem;--ly-profile-gap:var(--ly-space-2);--ly-grid-min:13rem;--ly-recipe-rail:14rem;--ly-recipe-aside:18rem;--ly-split-primary:0.7fr;--ly-split-secondary:1.3fr}}@layer ly.personalities.tactile{:where(.ly-root[data-ly-layout="tactile"]){--ly-personality-wrapper-max:96rem;--ly-profile-gap:var(--ly-space-4);--ly-grid-min:15rem;--ly-recipe-rail:17rem;--ly-recipe-aside:20rem;--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),0.5fr) minmax(min(100%,var(--ly-pane-min)),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:22rem;--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),1.1fr) minmax(min(100%,var(--ly-pane-min)),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(min(100%,var(--ly-recipe-main-min)),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:100%;--ly-profile-gap:var(--ly-space-1);--ly-grid-min:14rem;--ly-recipe-rail:16rem;--ly-recipe-aside:18rem}}@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(min(100%,var(--ly-recipe-main-min)),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:100%;--ly-profile-gap:var(--ly-space-2);--ly-grid-min:13rem;--ly-recipe-rail:18rem;--ly-recipe-aside:16rem;--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(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.26fr)}}@layer ly.personalities.retro-glass{:where(.ly-root[data-ly-layout="retro-glass"]){--ly-personality-wrapper-max:100%;--ly-profile-gap:var(--ly-space-2);--ly-grid-min:15rem;--ly-recipe-rail:16rem;--ly-recipe-aside:17rem;--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.3fr) minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.28fr)}}@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(min(100%,var(--ly-recipe-main-min)),1.35fr) minmax(min(100%,var(--ly-recipe-aside)),0.65fr);--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),1.8fr) minmax(min(100%,var(--ly-split-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-split-min)),1.5fr) minmax(min(100%,var(--ly-split-min)),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-rows:auto minmax(0,1fr) auto auto;--ly-app-shell-wide-columns:minmax(min(100%,var(--ly-recipe-main-min)),1fr) minmax(0,1fr);--ly-split-hero-wide-columns:minmax(min(100%,var(--ly-split-min)),1fr) minmax(min(100%,var(--ly-split-min)),1fr);--ly-list-detail-wide-columns:minmax(min(100%,var(--ly-pane-min)),1fr) minmax(min(100%,var(--ly-pane-min)),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(min(100%,var(--ly-recipe-main-min)),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(min(100%,var(--ly-recipe-main-min)),1fr) minmax(min(100%,var(--ly-recipe-aside)),0.34fr);--ly-reel-item-min:20rem}}@layer ly.personalities.technical-blueprint{:where(.ly-root[data-ly-layout="technical-blueprint"]){--ly-personality-wrapper-max:100%;--ly-profile-gap:var(--ly-space-1);--ly-grid-min:10rem;--ly-recipe-rail:11rem;--ly-recipe-aside:26rem;--ly-split-primary:2.2fr;--ly-split-secondary:0.8fr}}@layer ly.personalities.data-terminal{:where(.ly-root[data-ly-layout="data-terminal"]){--ly-personality-wrapper-max:100%;--ly-profile-gap:var(--ly-space-1);--ly-grid-min:10rem;--ly-card-grid-min:10rem;--ly-gallery-min:10rem;--ly-recipe-rail:12rem;--ly-recipe-aside:18rem}}@layer ly.personalities.industrial-hmi{:where(.ly-root[data-ly-layout="industrial-hmi"]){--ly-personality-wrapper-max:100%;--ly-profile-gap:var(--ly-space-2);--ly-grid-min:11rem;--ly-recipe-rail:7rem;--ly-recipe-aside:32rem}}@layer ly.personalities.editorial{:where(.ly-root[data-ly-layout="editorial"]){--ly-personality-wrapper-max:108rem;--ly-profile-gap:var(--ly-space-6);--ly-grid-min:16rem;--ly-recipe-rail:10rem;--ly-recipe-aside:18rem;--ly-split-primary:1.65fr;--ly-split-secondary:0.75fr;--ly-frame-ratio:4 / 5}} diff --git a/dist/personalities.css b/dist/personalities.css index 4fbf79f..abd59c1 100644 --- a/dist/personalities.css +++ b/dist/personalities.css @@ -16,3 +16,7 @@ @import url("./personalities/split-screen.css"); @import url("./personalities/mondrian.css"); @import url("./personalities/synthwave.css"); +@import url("./personalities/technical-blueprint.css"); +@import url("./personalities/data-terminal.css"); +@import url("./personalities/industrial-hmi.css"); +@import url("./personalities/editorial.css"); diff --git a/dist/personalities/data-terminal.css b/dist/personalities/data-terminal.css new file mode 100644 index 0000000..f5a205c --- /dev/null +++ b/dist/personalities/data-terminal.css @@ -0,0 +1,13 @@ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.context; + +@layer ly.personalities.data-terminal { + :where(.ly-root[data-ly-layout="data-terminal"]) { + --ly-personality-wrapper-max: 100%; + --ly-profile-gap: var(--ly-space-1); + --ly-grid-min: 10rem; + --ly-card-grid-min: 10rem; + --ly-gallery-min: 10rem; + --ly-recipe-rail: 12rem; + --ly-recipe-aside: 18rem; + } +} diff --git a/dist/personalities/editorial.css b/dist/personalities/editorial.css new file mode 100644 index 0000000..0854fbd --- /dev/null +++ b/dist/personalities/editorial.css @@ -0,0 +1,14 @@ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.context; + +@layer ly.personalities.editorial { + :where(.ly-root[data-ly-layout="editorial"]) { + --ly-personality-wrapper-max: 108rem; + --ly-profile-gap: var(--ly-space-6); + --ly-grid-min: 16rem; + --ly-recipe-rail: 10rem; + --ly-recipe-aside: 18rem; + --ly-split-primary: 1.65fr; + --ly-split-secondary: 0.75fr; + --ly-frame-ratio: 4 / 5; + } +} diff --git a/dist/personalities/industrial-hmi.css b/dist/personalities/industrial-hmi.css new file mode 100644 index 0000000..96bcd9e --- /dev/null +++ b/dist/personalities/industrial-hmi.css @@ -0,0 +1,11 @@ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.context; + +@layer ly.personalities.industrial-hmi { + :where(.ly-root[data-ly-layout="industrial-hmi"]) { + --ly-personality-wrapper-max: 100%; + --ly-profile-gap: var(--ly-space-2); + --ly-grid-min: 11rem; + --ly-recipe-rail: 7rem; + --ly-recipe-aside: 32rem; + } +} diff --git a/dist/personalities/technical-blueprint.css b/dist/personalities/technical-blueprint.css new file mode 100644 index 0000000..dd824b1 --- /dev/null +++ b/dist/personalities/technical-blueprint.css @@ -0,0 +1,13 @@ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.context; + +@layer ly.personalities.technical-blueprint { + :where(.ly-root[data-ly-layout="technical-blueprint"]) { + --ly-personality-wrapper-max: 100%; + --ly-profile-gap: var(--ly-space-1); + --ly-grid-min: 10rem; + --ly-recipe-rail: 11rem; + --ly-recipe-aside: 26rem; + --ly-split-primary: 2.2fr; + --ly-split-secondary: 0.8fr; + } +} diff --git a/scripts/build.mjs b/scripts/build.mjs index 3b0b8e8..94604bc 100644 --- a/scripts/build.mjs +++ b/scripts/build.mjs @@ -54,10 +54,36 @@ function buildPersonalityMetadata(sourceManifest) { }; } +/** + * Reads the ordered personality module inventory from the authored aggregate + * entry so newly staged modules can be built before their manifest publication. + * + * @param {string} css Authored `styles/personalities.css` source. + * @returns {string[]} Ordered paths relative to the styles directory. + * @throws {Error} When the entry contains no personality imports or duplicates. + */ +function readPersonalityImports(css) { + const files = [...css.matchAll(/@import\s+url\(["']\.\/(personalities\/[a-z0-9-]+\.css)["']\);/g)] + .map(([, file]) => file); + + if (files.length === 0 || new Set(files).size !== files.length) { + throw new Error("styles/personalities.css must provide unique ordered personality imports."); + } + + return files; +} + /* Manifest pairing records drive profile assets and generated demo fallbacks. */ const personalityMetadata = buildPersonalityMetadata(manifest); const personalityNames = personalityMetadata.personalities.map(({ id }) => id); -const personalityFiles = personalityNames.map((name) => `personalities/${name}.css`); +const manifestPersonalityFiles = personalityNames.map((name) => `personalities/${name}.css`); +const personalitiesEntry = await readFile(join(sourceDir, "personalities.css"), "utf8"); +const personalityFiles = readPersonalityImports(personalitiesEntry); +const missingManifestModules = manifestPersonalityFiles.filter((file) => !personalityFiles.includes(file)); + +if (missingManifestModules.length > 0) { + throw new Error(`styles/personalities.css is missing manifest modules: ${missingManifestModules.join(", ")}`); +} const authoredEntryFiles = [ "core.css", ...coreModuleFiles, diff --git a/styles/personalities.css b/styles/personalities.css index 4fbf79f..abd59c1 100644 --- a/styles/personalities.css +++ b/styles/personalities.css @@ -16,3 +16,7 @@ @import url("./personalities/split-screen.css"); @import url("./personalities/mondrian.css"); @import url("./personalities/synthwave.css"); +@import url("./personalities/technical-blueprint.css"); +@import url("./personalities/data-terminal.css"); +@import url("./personalities/industrial-hmi.css"); +@import url("./personalities/editorial.css"); diff --git a/styles/personalities/data-terminal.css b/styles/personalities/data-terminal.css new file mode 100644 index 0000000..f5a205c --- /dev/null +++ b/styles/personalities/data-terminal.css @@ -0,0 +1,13 @@ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.context; + +@layer ly.personalities.data-terminal { + :where(.ly-root[data-ly-layout="data-terminal"]) { + --ly-personality-wrapper-max: 100%; + --ly-profile-gap: var(--ly-space-1); + --ly-grid-min: 10rem; + --ly-card-grid-min: 10rem; + --ly-gallery-min: 10rem; + --ly-recipe-rail: 12rem; + --ly-recipe-aside: 18rem; + } +} diff --git a/styles/personalities/editorial.css b/styles/personalities/editorial.css new file mode 100644 index 0000000..0854fbd --- /dev/null +++ b/styles/personalities/editorial.css @@ -0,0 +1,14 @@ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.context; + +@layer ly.personalities.editorial { + :where(.ly-root[data-ly-layout="editorial"]) { + --ly-personality-wrapper-max: 108rem; + --ly-profile-gap: var(--ly-space-6); + --ly-grid-min: 16rem; + --ly-recipe-rail: 10rem; + --ly-recipe-aside: 18rem; + --ly-split-primary: 1.65fr; + --ly-split-secondary: 0.75fr; + --ly-frame-ratio: 4 / 5; + } +} diff --git a/styles/personalities/industrial-hmi.css b/styles/personalities/industrial-hmi.css new file mode 100644 index 0000000..96bcd9e --- /dev/null +++ b/styles/personalities/industrial-hmi.css @@ -0,0 +1,11 @@ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.context; + +@layer ly.personalities.industrial-hmi { + :where(.ly-root[data-ly-layout="industrial-hmi"]) { + --ly-personality-wrapper-max: 100%; + --ly-profile-gap: var(--ly-space-2); + --ly-grid-min: 11rem; + --ly-recipe-rail: 7rem; + --ly-recipe-aside: 32rem; + } +} diff --git a/styles/personalities/technical-blueprint.css b/styles/personalities/technical-blueprint.css new file mode 100644 index 0000000..dd824b1 --- /dev/null +++ b/styles/personalities/technical-blueprint.css @@ -0,0 +1,13 @@ +@layer ly.reset, ly.tokens, ly.wrappers, ly.primitives, ly.recipes, ly.utilities, ly.personalities, ly.context; + +@layer ly.personalities.technical-blueprint { + :where(.ly-root[data-ly-layout="technical-blueprint"]) { + --ly-personality-wrapper-max: 100%; + --ly-profile-gap: var(--ly-space-1); + --ly-grid-min: 10rem; + --ly-recipe-rail: 11rem; + --ly-recipe-aside: 26rem; + --ly-split-primary: 2.2fr; + --ly-split-secondary: 0.8fr; + } +} diff --git a/test/demo-smoke.test.mjs b/test/demo-smoke.test.mjs index 0e9bd2d..5282a64 100644 --- a/test/demo-smoke.test.mjs +++ b/test/demo-smoke.test.mjs @@ -1647,6 +1647,73 @@ const verifyPersonalityGeometry = async (page, baseUrl) => { ); }; +/** + * Verifies the defining computed and rendered signatures of the four new 3.2 + * personality modules before they are added to the public manifest selector. + * + * @param {import("@playwright/test").Page} page Active browser page. + * @param {string} baseUrl Demo server URL. + * @returns {Promise} + */ +const verifySpecializedPersonalityGeometry = async (page, baseUrl) => { + await page.setViewportSize({ width: 1920, height: 1080 }); + await page.goto( + `${baseUrl}?ecosystem=layout-only&wrapper=full&recipe=split-hero&container=73rem&height=50rem`, + { waitUntil: "domcontentloaded" } + ); + await page.waitForFunction(() => document.body.dataset.demoReady === "true"); + + /** + * Captures resolved layout tokens and split geometry for one staged profile. + * + * @param {string} personality Canonical layout personality identifier. + * @returns {Promise>} Resolved profile snapshot. + */ + const snapshotProfile = async (personality) => + page.evaluate(async (name) => { + const root = document.querySelector("#previewRoot"); + root.dataset.lyLayout = name; + await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(resolve))); + const rootStyle = getComputedStyle(root); + const recipe = document.querySelector('[data-ly-recipe="split-hero"]'); + const content = recipe.querySelector('[data-ly-area="content"]').getBoundingClientRect(); + const media = recipe.querySelector('[data-ly-area="media"]').getBoundingClientRect(); + return { + wrapper: rootStyle.getPropertyValue("--ly-personality-wrapper-max").trim(), + gridMin: rootStyle.getPropertyValue("--ly-grid-min").trim(), + cardGridMin: rootStyle.getPropertyValue("--ly-card-grid-min").trim(), + galleryMin: rootStyle.getPropertyValue("--ly-gallery-min").trim(), + rail: rootStyle.getPropertyValue("--ly-recipe-rail").trim(), + aside: rootStyle.getPropertyValue("--ly-recipe-aside").trim(), + primary: rootStyle.getPropertyValue("--ly-split-primary").trim(), + secondary: rootStyle.getPropertyValue("--ly-split-secondary").trim(), + frameRatio: rootStyle.getPropertyValue("--ly-frame-ratio").trim(), + contentWidth: content.width, + mediaWidth: media.width + }; + }, personality); + + const blueprint = await snapshotProfile("technical-blueprint"); + const terminal = await snapshotProfile("data-terminal"); + const hmi = await snapshotProfile("industrial-hmi"); + const editorial = await snapshotProfile("editorial"); + + assert.equal(blueprint.wrapper, "100%"); + assert.equal(blueprint.primary, "2.2fr"); + assert.equal(blueprint.secondary, "0.8fr"); + assert(blueprint.contentWidth > blueprint.mediaWidth * 2, "Blueprint canvas must dominate its split."); + assert.equal(terminal.wrapper, "100%"); + assert.equal(terminal.gridMin, "10rem"); + assert.equal(terminal.cardGridMin, "10rem"); + assert.equal(terminal.galleryMin, "10rem"); + assert.equal(hmi.rail, "7rem"); + assert.equal(hmi.aside, "32rem"); + assert.equal(editorial.frameRatio, "4 / 5"); + assert.equal(editorial.primary, "1.65fr"); + assert.equal(editorial.secondary, "0.75fr"); + assert(editorial.contentWidth > editorial.mediaWidth, "Editorial split must favor its content rail."); +}; + const verifyMinimumWidth = async (page, baseUrl) => { await page.setViewportSize({ width: 320, height: 800 }); await page.goto(`${baseUrl}?ecosystem=layout-only&device=custom&container=auto`, { @@ -2057,6 +2124,7 @@ try { await verifyDeviceMatrix(page, server.baseUrl); await verifyPersonalityMatrix(page, server.baseUrl); await verifyPersonalityGeometry(page, server.baseUrl); + await verifySpecializedPersonalityGeometry(page, server.baseUrl); await verifyMinimumWidth(page, server.baseUrl); await verifyWorkspaceMeasure(page, server.baseUrl); await verifyBreakoutGeometry(page, server.baseUrl); diff --git a/test/layout-css-contract.test.mjs b/test/layout-css-contract.test.mjs index 0b81a5a..1d7a165 100644 --- a/test/layout-css-contract.test.mjs +++ b/test/layout-css-contract.test.mjs @@ -21,6 +21,13 @@ const focusedFiles = [ "personalities.css" ]; const personalityNames = manifest.personalities; +const specializedPersonalityNames = [ + "technical-blueprint", + "data-terminal", + "industrial-hmi", + "editorial" +]; +const authoredPersonalityNames = [...new Set([...personalityNames, ...specializedPersonalityNames])]; const recipeNames = [ "app-shell", "dashboard", @@ -82,7 +89,7 @@ const flattenedSourceFiles = [ "primitives.css", "recipes.css", "utilities.css", - ...personalityNames.map((name) => `personalities/${name}.css`) + ...authoredPersonalityNames.map((name) => `personalities/${name}.css`) ]; function read(path) { @@ -173,7 +180,7 @@ const expectedTarballFiles = [ "dist/recipes.css", "dist/utilities.css", "dist/personalities.css", - ...personalityNames.map((name) => `dist/personalities/${name}.css`) + ...authoredPersonalityNames.map((name) => `dist/personalities/${name}.css`) ].sort(); assert.deepEqual( packReport.files.map(({ path }) => path).sort(), @@ -208,7 +215,7 @@ for (const name of personalityNames) { assert.equal(generatedCss, css, `${file} generated output drifted from its authored profile`); } -const personalitySignatures = personalityNames.map((name) => { +const personalitySignatures = authoredPersonalityNames.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()}`) @@ -217,7 +224,7 @@ const personalitySignatures = personalityNames.map((name) => { }); assert.equal( new Set(personalitySignatures).size, - personalityNames.length, + authoredPersonalityNames.length, "Every personality must expose a unique spatial signature" ); @@ -246,6 +253,12 @@ const targetProperties = [ "--ly-recipe-rail", "--ly-recipe-aside" ]; +const specializedPersonalityTargets = { + "technical-blueprint": ["100%", "var(--ly-space-1)", "10rem", "11rem", "26rem"], + "data-terminal": ["100%", "var(--ly-space-1)", "10rem", "12rem", "18rem"], + "industrial-hmi": ["100%", "var(--ly-space-2)", "11rem", "7rem", "32rem"], + editorial: ["108rem", "var(--ly-space-6)", "16rem", "10rem", "18rem"] +}; for (const [name, values] of Object.entries(personalityTargets)) { const css = readStyle(`personalities/${name}.css`); assert.deepEqual( @@ -254,6 +267,14 @@ for (const [name, values] of Object.entries(personalityTargets)) { `${name} geometry drifted from the approved 3.2 target table.` ); } +for (const [name, values] of Object.entries(specializedPersonalityTargets)) { + const css = readStyle(`personalities/${name}.css`); + assert.deepEqual( + targetProperties.map((property) => customPropertyValue(css, property)), + values, + `${name} geometry drifted from the approved 3.2 target table.` + ); +} for (const name of ["bento", "maximalist", "bauhaus", "tactile", "neumorphism", "brutalism"]) { assert( !readStyle(`personalities/${name}.css`).includes("--ly-app-shell-wide-areas:"), @@ -273,6 +294,13 @@ assert.match(customPropertyValue(readStyle("personalities/neumorphism.css"), "-- assert.match(customPropertyValue(readStyle("personalities/f-pattern.css"), "--ly-split-hero-wide-columns"), /1\.8fr[\s\S]*0\.8fr/); assert.match(customPropertyValue(readStyle("personalities/z-pattern.css"), "--ly-split-hero-wide-columns"), /1\.5fr[\s\S]*0\.5fr/); assert.equal(customPropertyValue(readStyle("personalities/synthwave.css"), "--ly-reel-item-min"), "20rem"); +assert.equal(customPropertyValue(readStyle("personalities/technical-blueprint.css"), "--ly-split-primary"), "2.2fr"); +assert.equal(customPropertyValue(readStyle("personalities/technical-blueprint.css"), "--ly-split-secondary"), "0.8fr"); +assert.equal(customPropertyValue(readStyle("personalities/data-terminal.css"), "--ly-card-grid-min"), "10rem"); +assert.equal(customPropertyValue(readStyle("personalities/data-terminal.css"), "--ly-gallery-min"), "10rem"); +assert.equal(customPropertyValue(readStyle("personalities/editorial.css"), "--ly-split-primary"), "1.65fr"); +assert.equal(customPropertyValue(readStyle("personalities/editorial.css"), "--ly-split-secondary"), "0.75fr"); +assert.equal(customPropertyValue(readStyle("personalities/editorial.css"), "--ly-frame-ratio"), "4 / 5"); 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"); @@ -299,7 +327,7 @@ const authoredCss = [ recipes, utilities, aggregatePersonalities, - ...personalityNames.map((name) => readStyle(`personalities/${name}.css`)) + ...authoredPersonalityNames.map((name) => readStyle(`personalities/${name}.css`)) ].join("\n"); assert( @@ -479,7 +507,7 @@ assert( ), "Split Hero must guard both content tracks with --ly-split-min." ); -for (const name of personalityNames) { +for (const name of authoredPersonalityNames) { const css = readStyle(`personalities/${name}.css`); const appShellColumns = css.match(/--ly-app-shell-wide-columns:\s*([^;]+);/s)?.[1]; const listDetailColumns = css.match(/--ly-list-detail-wide-columns:\s*([^;]+);/s)?.[1]; From c585606b5f2d53c3f23fdd4ff8bf875320e66a20 Mon Sep 17 00:00:00 2001 From: Foscat Date: Thu, 3 Sep 2026 09:30:53 -0500 Subject: [PATCH 08/11] feat: publish twenty layout personalities --- demo/personality-metadata.js | 2 +- manifest.json | 39 ++++++++------- personalities.json | 85 +++++++++++++++++++++++++++----- scripts/build.mjs | 5 +- test/manifest-contract.test.mjs | 86 ++++++++++++++++++++++++++++++++- 5 files changed, 183 insertions(+), 34 deletions(-) diff --git a/demo/personality-metadata.js b/demo/personality-metadata.js index 76ed3dd..704666d 100644 --- a/demo/personality-metadata.js +++ b/demo/personality-metadata.js @@ -1,2 +1,2 @@ /* Generated from manifest.json by scripts/build.mjs. */ -window.LAYOUT_STYLE_PERSONALITY_METADATA = {"schemaVersion":1,"generatedFrom":"manifest.json","selector":"data-ly-layout","independentSelectors":["data-ly-layout","data-ly-density","data-ui","data-theme","data-mode"],"personalities":[{"id":"minimal-saas","label":"Minimal SaaS","visualCompatibility":"native","recommendedVisualPresets":["minimal-saas"]},{"id":"bento","label":"Bento","visualCompatibility":"native","recommendedVisualPresets":["bento"]},{"id":"maximalist","label":"Maximalist","visualCompatibility":"native","recommendedVisualPresets":["maximalist"]},{"id":"bauhaus","label":"Bauhaus","visualCompatibility":"native","recommendedVisualPresets":["bauhaus"]},{"id":"tactile","label":"Tactile","visualCompatibility":"native","recommendedVisualPresets":["tactile"]},{"id":"neumorphism","label":"Neumorphism","visualCompatibility":"native","recommendedVisualPresets":["neumorphism"]},{"id":"retrofuturism","label":"Retrofuturism","visualCompatibility":"native","recommendedVisualPresets":["retrofuturism"]},{"id":"brutalism","label":"Brutalism","visualCompatibility":"native","recommendedVisualPresets":["brutalism"]},{"id":"cyberpunk","label":"Cyberpunk","visualCompatibility":"native","recommendedVisualPresets":["cyberpunk"]},{"id":"y2k","label":"Y2K","visualCompatibility":"native","recommendedVisualPresets":["y2k"]},{"id":"retro-glass","label":"Retro Glass","visualCompatibility":"native","recommendedVisualPresets":["retro-glass"]},{"id":"f-pattern","label":"F-pattern","visualCompatibility":"any","recommendedVisualPresets":[]},{"id":"z-pattern","label":"Z-pattern","visualCompatibility":"any","recommendedVisualPresets":[]},{"id":"split-screen","label":"Split Screen","visualCompatibility":"any","recommendedVisualPresets":[]},{"id":"mondrian","label":"Mondrian","visualCompatibility":"any","recommendedVisualPresets":[]},{"id":"synthwave","label":"Synthwave","visualCompatibility":"recommended","recommendedVisualPresets":["cyberpunk","retrofuturism"],"visualVerification":{"method":"rendered-computed-style","test":"test/demo-smoke.test.mjs","computedProperties":{"cyberpunk":{"boxShadow":"0px 0px 18px"},"retrofuturism":{"boxShadow":"0px 10px 30px"}},"assertion":"A visible browser contract fixture renders each preset's distinct article box-shadow while data-ly-layout remains synthwave."}}]}; +window.LAYOUT_STYLE_PERSONALITY_METADATA = {"schemaVersion":1,"generatedFrom":"manifest.json","selector":"data-ly-layout","independentSelectors":["data-ly-layout","data-ly-density","data-ui","data-theme","data-mode"],"personalities":[{"id":"minimal-saas","label":"Minimal SaaS","visualCompatibility":"native","recommendedVisualPresets":["minimal-saas"],"compatibleVisualPresets":["organic-modern"]},{"id":"bento","label":"Bento","visualCompatibility":"native","recommendedVisualPresets":["bento"],"compatibleVisualPresets":[]},{"id":"maximalist","label":"Maximalist","visualCompatibility":"native","recommendedVisualPresets":["maximalist"],"compatibleVisualPresets":[]},{"id":"bauhaus","label":"Bauhaus","visualCompatibility":"native","recommendedVisualPresets":["bauhaus"],"compatibleVisualPresets":["art-deco"]},{"id":"tactile","label":"Tactile","visualCompatibility":"native","recommendedVisualPresets":["tactile"],"compatibleVisualPresets":["clay"]},{"id":"neumorphism","label":"Neumorphism","visualCompatibility":"native","recommendedVisualPresets":["neumorphism"],"compatibleVisualPresets":[]},{"id":"retrofuturism","label":"Retrofuturism","visualCompatibility":"native","recommendedVisualPresets":["retrofuturism"],"compatibleVisualPresets":[]},{"id":"brutalism","label":"Brutalism","visualCompatibility":"native","recommendedVisualPresets":["brutalism"],"compatibleVisualPresets":[]},{"id":"cyberpunk","label":"Cyberpunk","visualCompatibility":"native","recommendedVisualPresets":["cyberpunk"],"compatibleVisualPresets":[]},{"id":"y2k","label":"Y2K","visualCompatibility":"native","recommendedVisualPresets":["y2k"],"compatibleVisualPresets":[]},{"id":"retro-glass","label":"Retro Glass","visualCompatibility":"native","recommendedVisualPresets":["retro-glass"],"compatibleVisualPresets":[]},{"id":"f-pattern","label":"F-pattern","visualCompatibility":"any","recommendedVisualPresets":[],"compatibleVisualPresets":[]},{"id":"z-pattern","label":"Z-pattern","visualCompatibility":"any","recommendedVisualPresets":[],"compatibleVisualPresets":[]},{"id":"split-screen","label":"Split Screen","visualCompatibility":"any","recommendedVisualPresets":[],"compatibleVisualPresets":[]},{"id":"mondrian","label":"Mondrian","visualCompatibility":"any","recommendedVisualPresets":[],"compatibleVisualPresets":[]},{"id":"synthwave","label":"Synthwave","visualCompatibility":"recommended","recommendedVisualPresets":["cyberpunk","retrofuturism"],"compatibleVisualPresets":[],"visualVerification":{"method":"rendered-computed-style","test":"test/demo-smoke.test.mjs","computedProperties":{"cyberpunk":{"boxShadow":"0px 0px 18px"},"retrofuturism":{"boxShadow":"0px 10px 30px"}},"assertion":"A visible browser contract fixture renders each preset's distinct article box-shadow while data-ly-layout remains synthwave."}},{"id":"technical-blueprint","label":"Technical Blueprint","visualCompatibility":"native","recommendedVisualPresets":["technical-blueprint"],"compatibleVisualPresets":[]},{"id":"data-terminal","label":"Data Terminal","visualCompatibility":"native","recommendedVisualPresets":["data-terminal"],"compatibleVisualPresets":["neo-noir"]},{"id":"industrial-hmi","label":"Industrial HMI","visualCompatibility":"recommended","recommendedVisualPresets":["industrial-utility"],"compatibleVisualPresets":[]},{"id":"editorial","label":"Editorial","visualCompatibility":"recommended","recommendedVisualPresets":["editorial-luxe","paper-editorial"],"compatibleVisualPresets":[]}]}; diff --git a/manifest.json b/manifest.json index bf3c627..583b82a 100644 --- a/manifest.json +++ b/manifest.json @@ -27,28 +27,29 @@ "primitives": ["page", "header", "footer", "main", "section", "surface", "readable", "stack", "cluster", "center", "cover", "switcher", "sidebar", "grid", "mosaic", "action-bar", "split", "panes", "media", "reel", "frame", "scroll"], "recipes": ["app-shell", "dashboard", "docs", "list-detail", "split-hero", "gallery", "card-grid"], "areas": ["header", "nav", "sidebar", "main", "aside", "footer", "content", "media", "actions", "primary", "secondary"], - "personalities": ["minimal-saas", "bento", "maximalist", "bauhaus", "tactile", "neumorphism", "retrofuturism", "brutalism", "cyberpunk", "y2k", "retro-glass", "f-pattern", "z-pattern", "split-screen", "mondrian", "synthwave"], + "personalities": ["minimal-saas", "bento", "maximalist", "bauhaus", "tactile", "neumorphism", "retrofuturism", "brutalism", "cyberpunk", "y2k", "retro-glass", "f-pattern", "z-pattern", "split-screen", "mondrian", "synthwave", "technical-blueprint", "data-terminal", "industrial-hmi", "editorial"], "personalityPairings": [ - { "id": "minimal-saas", "label": "Minimal SaaS", "visualCompatibility": "native", "recommendedVisualPresets": ["minimal-saas"] }, - { "id": "bento", "label": "Bento", "visualCompatibility": "native", "recommendedVisualPresets": ["bento"] }, - { "id": "maximalist", "label": "Maximalist", "visualCompatibility": "native", "recommendedVisualPresets": ["maximalist"] }, - { "id": "bauhaus", "label": "Bauhaus", "visualCompatibility": "native", "recommendedVisualPresets": ["bauhaus"] }, - { "id": "tactile", "label": "Tactile", "visualCompatibility": "native", "recommendedVisualPresets": ["tactile"] }, - { "id": "neumorphism", "label": "Neumorphism", "visualCompatibility": "native", "recommendedVisualPresets": ["neumorphism"] }, - { "id": "retrofuturism", "label": "Retrofuturism", "visualCompatibility": "native", "recommendedVisualPresets": ["retrofuturism"] }, - { "id": "brutalism", "label": "Brutalism", "visualCompatibility": "native", "recommendedVisualPresets": ["brutalism"] }, - { "id": "cyberpunk", "label": "Cyberpunk", "visualCompatibility": "native", "recommendedVisualPresets": ["cyberpunk"] }, - { "id": "y2k", "label": "Y2K", "visualCompatibility": "native", "recommendedVisualPresets": ["y2k"] }, - { "id": "retro-glass", "label": "Retro Glass", "visualCompatibility": "native", "recommendedVisualPresets": ["retro-glass"] }, - { "id": "f-pattern", "label": "F-pattern", "visualCompatibility": "any", "recommendedVisualPresets": [] }, - { "id": "z-pattern", "label": "Z-pattern", "visualCompatibility": "any", "recommendedVisualPresets": [] }, - { "id": "split-screen", "label": "Split Screen", "visualCompatibility": "any", "recommendedVisualPresets": [] }, - { "id": "mondrian", "label": "Mondrian", "visualCompatibility": "any", "recommendedVisualPresets": [] }, + { "id": "minimal-saas", "label": "Minimal SaaS", "visualCompatibility": "native", "recommendedVisualPresets": ["minimal-saas"], "compatibleVisualPresets": ["organic-modern"] }, + { "id": "bento", "label": "Bento", "visualCompatibility": "native", "recommendedVisualPresets": ["bento"], "compatibleVisualPresets": [] }, + { "id": "maximalist", "label": "Maximalist", "visualCompatibility": "native", "recommendedVisualPresets": ["maximalist"], "compatibleVisualPresets": [] }, + { "id": "bauhaus", "label": "Bauhaus", "visualCompatibility": "native", "recommendedVisualPresets": ["bauhaus"], "compatibleVisualPresets": ["art-deco"] }, + { "id": "tactile", "label": "Tactile", "visualCompatibility": "native", "recommendedVisualPresets": ["tactile"], "compatibleVisualPresets": ["clay"] }, + { "id": "neumorphism", "label": "Neumorphism", "visualCompatibility": "native", "recommendedVisualPresets": ["neumorphism"], "compatibleVisualPresets": [] }, + { "id": "retrofuturism", "label": "Retrofuturism", "visualCompatibility": "native", "recommendedVisualPresets": ["retrofuturism"], "compatibleVisualPresets": [] }, + { "id": "brutalism", "label": "Brutalism", "visualCompatibility": "native", "recommendedVisualPresets": ["brutalism"], "compatibleVisualPresets": [] }, + { "id": "cyberpunk", "label": "Cyberpunk", "visualCompatibility": "native", "recommendedVisualPresets": ["cyberpunk"], "compatibleVisualPresets": [] }, + { "id": "y2k", "label": "Y2K", "visualCompatibility": "native", "recommendedVisualPresets": ["y2k"], "compatibleVisualPresets": [] }, + { "id": "retro-glass", "label": "Retro Glass", "visualCompatibility": "native", "recommendedVisualPresets": ["retro-glass"], "compatibleVisualPresets": [] }, + { "id": "f-pattern", "label": "F-pattern", "visualCompatibility": "any", "recommendedVisualPresets": [], "compatibleVisualPresets": [] }, + { "id": "z-pattern", "label": "Z-pattern", "visualCompatibility": "any", "recommendedVisualPresets": [], "compatibleVisualPresets": [] }, + { "id": "split-screen", "label": "Split Screen", "visualCompatibility": "any", "recommendedVisualPresets": [], "compatibleVisualPresets": [] }, + { "id": "mondrian", "label": "Mondrian", "visualCompatibility": "any", "recommendedVisualPresets": [], "compatibleVisualPresets": [] }, { "id": "synthwave", "label": "Synthwave", "visualCompatibility": "recommended", "recommendedVisualPresets": ["cyberpunk", "retrofuturism"], + "compatibleVisualPresets": [], "visualVerification": { "method": "rendered-computed-style", "test": "test/demo-smoke.test.mjs", @@ -58,7 +59,11 @@ }, "assertion": "A visible browser contract fixture renders each preset's distinct article box-shadow while data-ly-layout remains synthwave." } - } + }, + { "id": "technical-blueprint", "label": "Technical Blueprint", "visualCompatibility": "native", "recommendedVisualPresets": ["technical-blueprint"], "compatibleVisualPresets": [] }, + { "id": "data-terminal", "label": "Data Terminal", "visualCompatibility": "native", "recommendedVisualPresets": ["data-terminal"], "compatibleVisualPresets": ["neo-noir"] }, + { "id": "industrial-hmi", "label": "Industrial HMI", "visualCompatibility": "recommended", "recommendedVisualPresets": ["industrial-utility"], "compatibleVisualPresets": [] }, + { "id": "editorial", "label": "Editorial", "visualCompatibility": "recommended", "recommendedVisualPresets": ["editorial-luxe", "paper-editorial"], "compatibleVisualPresets": [] } ], "containers": { "names": ["ly-scope"], diff --git a/personalities.json b/personalities.json index 2d02da3..a7c1857 100644 --- a/personalities.json +++ b/personalities.json @@ -16,6 +16,9 @@ "visualCompatibility": "native", "recommendedVisualPresets": [ "minimal-saas" + ], + "compatibleVisualPresets": [ + "organic-modern" ] }, { @@ -24,7 +27,8 @@ "visualCompatibility": "native", "recommendedVisualPresets": [ "bento" - ] + ], + "compatibleVisualPresets": [] }, { "id": "maximalist", @@ -32,7 +36,8 @@ "visualCompatibility": "native", "recommendedVisualPresets": [ "maximalist" - ] + ], + "compatibleVisualPresets": [] }, { "id": "bauhaus", @@ -40,6 +45,9 @@ "visualCompatibility": "native", "recommendedVisualPresets": [ "bauhaus" + ], + "compatibleVisualPresets": [ + "art-deco" ] }, { @@ -48,6 +56,9 @@ "visualCompatibility": "native", "recommendedVisualPresets": [ "tactile" + ], + "compatibleVisualPresets": [ + "clay" ] }, { @@ -56,7 +67,8 @@ "visualCompatibility": "native", "recommendedVisualPresets": [ "neumorphism" - ] + ], + "compatibleVisualPresets": [] }, { "id": "retrofuturism", @@ -64,7 +76,8 @@ "visualCompatibility": "native", "recommendedVisualPresets": [ "retrofuturism" - ] + ], + "compatibleVisualPresets": [] }, { "id": "brutalism", @@ -72,7 +85,8 @@ "visualCompatibility": "native", "recommendedVisualPresets": [ "brutalism" - ] + ], + "compatibleVisualPresets": [] }, { "id": "cyberpunk", @@ -80,7 +94,8 @@ "visualCompatibility": "native", "recommendedVisualPresets": [ "cyberpunk" - ] + ], + "compatibleVisualPresets": [] }, { "id": "y2k", @@ -88,7 +103,8 @@ "visualCompatibility": "native", "recommendedVisualPresets": [ "y2k" - ] + ], + "compatibleVisualPresets": [] }, { "id": "retro-glass", @@ -96,31 +112,36 @@ "visualCompatibility": "native", "recommendedVisualPresets": [ "retro-glass" - ] + ], + "compatibleVisualPresets": [] }, { "id": "f-pattern", "label": "F-pattern", "visualCompatibility": "any", - "recommendedVisualPresets": [] + "recommendedVisualPresets": [], + "compatibleVisualPresets": [] }, { "id": "z-pattern", "label": "Z-pattern", "visualCompatibility": "any", - "recommendedVisualPresets": [] + "recommendedVisualPresets": [], + "compatibleVisualPresets": [] }, { "id": "split-screen", "label": "Split Screen", "visualCompatibility": "any", - "recommendedVisualPresets": [] + "recommendedVisualPresets": [], + "compatibleVisualPresets": [] }, { "id": "mondrian", "label": "Mondrian", "visualCompatibility": "any", - "recommendedVisualPresets": [] + "recommendedVisualPresets": [], + "compatibleVisualPresets": [] }, { "id": "synthwave", @@ -130,6 +151,7 @@ "cyberpunk", "retrofuturism" ], + "compatibleVisualPresets": [], "visualVerification": { "method": "rendered-computed-style", "test": "test/demo-smoke.test.mjs", @@ -143,6 +165,45 @@ }, "assertion": "A visible browser contract fixture renders each preset's distinct article box-shadow while data-ly-layout remains synthwave." } + }, + { + "id": "technical-blueprint", + "label": "Technical Blueprint", + "visualCompatibility": "native", + "recommendedVisualPresets": [ + "technical-blueprint" + ], + "compatibleVisualPresets": [] + }, + { + "id": "data-terminal", + "label": "Data Terminal", + "visualCompatibility": "native", + "recommendedVisualPresets": [ + "data-terminal" + ], + "compatibleVisualPresets": [ + "neo-noir" + ] + }, + { + "id": "industrial-hmi", + "label": "Industrial HMI", + "visualCompatibility": "recommended", + "recommendedVisualPresets": [ + "industrial-utility" + ], + "compatibleVisualPresets": [] + }, + { + "id": "editorial", + "label": "Editorial", + "visualCompatibility": "recommended", + "recommendedVisualPresets": [ + "editorial-luxe", + "paper-editorial" + ], + "compatibleVisualPresets": [] } ] } diff --git a/scripts/build.mjs b/scripts/build.mjs index 94604bc..d5e9666 100644 --- a/scripts/build.mjs +++ b/scripts/build.mjs @@ -79,10 +79,9 @@ const personalityNames = personalityMetadata.personalities.map(({ id }) => id); const manifestPersonalityFiles = personalityNames.map((name) => `personalities/${name}.css`); const personalitiesEntry = await readFile(join(sourceDir, "personalities.css"), "utf8"); const personalityFiles = readPersonalityImports(personalitiesEntry); -const missingManifestModules = manifestPersonalityFiles.filter((file) => !personalityFiles.includes(file)); -if (missingManifestModules.length > 0) { - throw new Error(`styles/personalities.css is missing manifest modules: ${missingManifestModules.join(", ")}`); +if (JSON.stringify(personalityFiles) !== JSON.stringify(manifestPersonalityFiles)) { + throw new Error("styles/personalities.css imports must match manifest personality order exactly."); } const authoredEntryFiles = [ "core.css", diff --git a/test/manifest-contract.test.mjs b/test/manifest-contract.test.mjs index 52e3693..1265951 100644 --- a/test/manifest-contract.test.mjs +++ b/test/manifest-contract.test.mjs @@ -45,6 +45,40 @@ const entrypointExports = { personalityMetadata: "./personalities.json" }; const personalities = manifest.personalities; +const expectedPersonalities = [ + "minimal-saas", "bento", "maximalist", "bauhaus", "tactile", "neumorphism", + "retrofuturism", "brutalism", "cyberpunk", "y2k", "retro-glass", "f-pattern", + "z-pattern", "split-screen", "mondrian", "synthwave", "technical-blueprint", + "data-terminal", "industrial-hmi", "editorial" +]; +const expectedVisualPresets = [ + "minimal-saas", "bento", "maximalist", "bauhaus", "tactile", "neumorphism", + "retrofuturism", "brutalism", "cyberpunk", "y2k", "retro-glass", "editorial-luxe", + "organic-modern", "industrial-utility", "technical-blueprint", "art-deco", "clay", + "data-terminal", "paper-editorial", "neo-noir" +]; +const expectedPairingContract = [ + ["minimal-saas", "native", ["minimal-saas"], ["organic-modern"]], + ["bento", "native", ["bento"], []], + ["maximalist", "native", ["maximalist"], []], + ["bauhaus", "native", ["bauhaus"], ["art-deco"]], + ["tactile", "native", ["tactile"], ["clay"]], + ["neumorphism", "native", ["neumorphism"], []], + ["retrofuturism", "native", ["retrofuturism"], []], + ["brutalism", "native", ["brutalism"], []], + ["cyberpunk", "native", ["cyberpunk"], []], + ["y2k", "native", ["y2k"], []], + ["retro-glass", "native", ["retro-glass"], []], + ["f-pattern", "any", [], []], + ["z-pattern", "any", [], []], + ["split-screen", "any", [], []], + ["mondrian", "any", [], []], + ["synthwave", "recommended", ["cyberpunk", "retrofuturism"], []], + ["technical-blueprint", "native", ["technical-blueprint"], []], + ["data-terminal", "native", ["data-terminal"], ["neo-noir"]], + ["industrial-hmi", "recommended", ["industrial-utility"], []], + ["editorial", "recommended", ["editorial-luxe", "paper-editorial"], []] +]; // These are stable consumer overrides; wrapper calculation variables remain implementation details below. const geometryTokens = [ "--ly-space-0", "--ly-space-1", "--ly-space-2", "--ly-space-3", "--ly-space-4", @@ -169,11 +203,30 @@ test("public personality pairings inventory every exported layout profile withou ); assert.deepEqual(personalityMetadata.personalities, manifest.personalityPairings); assert.deepEqual(personalityMetadata.personalities.map(({ id }) => id), personalities); + assert.deepEqual(personalities, expectedPersonalities); + assert( + personalityMetadata.personalities.every(({ compatibleVisualPresets }) => + Array.isArray(compatibleVisualPresets) + ), + "Every personality pairing must expose additive compatibleVisualPresets metadata." + ); + assert.deepEqual( + personalityMetadata.personalities.map( + ({ id, visualCompatibility, recommendedVisualPresets, compatibleVisualPresets }) => [ + id, + visualCompatibility, + recommendedVisualPresets, + compatibleVisualPresets + ] + ), + expectedPairingContract + ); const pairings = new Map(personalityMetadata.personalities.map((pairing) => [pairing.id, pairing])); for (const id of [ "minimal-saas", "bento", "maximalist", "bauhaus", "tactile", "neumorphism", - "retrofuturism", "brutalism", "cyberpunk", "y2k", "retro-glass" + "retrofuturism", "brutalism", "cyberpunk", "y2k", "retro-glass", + "technical-blueprint", "data-terminal" ]) { assert.equal(pairings.get(id)?.visualCompatibility, "native", `${id} needs its verified native visual match.`); assert.deepEqual(pairings.get(id)?.recommendedVisualPresets, [id]); @@ -189,6 +242,33 @@ test("public personality pairings inventory every exported layout profile withou cyberpunk: { boxShadow: "0px 0px 18px" }, retrofuturism: { boxShadow: "0px 10px 30px" } }); + assert.deepEqual(pairings.get("minimal-saas")?.compatibleVisualPresets, ["organic-modern"]); + assert.deepEqual(pairings.get("bauhaus")?.compatibleVisualPresets, ["art-deco"]); + assert.deepEqual(pairings.get("tactile")?.compatibleVisualPresets, ["clay"]); + assert.deepEqual(pairings.get("data-terminal")?.compatibleVisualPresets, ["neo-noir"]); + assert.equal(pairings.get("industrial-hmi")?.visualCompatibility, "recommended"); + assert.deepEqual(pairings.get("industrial-hmi")?.recommendedVisualPresets, ["industrial-utility"]); + assert.equal(pairings.get("editorial")?.visualCompatibility, "recommended"); + assert.deepEqual(pairings.get("editorial")?.recommendedVisualPresets, ["editorial-luxe", "paper-editorial"]); + + const coveredVisualPresets = new Set( + personalityMetadata.personalities.flatMap( + ({ recommendedVisualPresets, compatibleVisualPresets }) => [ + ...recommendedVisualPresets, + ...compatibleVisualPresets + ] + ) + ); + assert.deepEqual([...coveredVisualPresets].sort(), [...expectedVisualPresets].sort()); +}); + +test("authored personality imports match the canonical manifest inventory exactly", () => { + const personalitiesCss = readFileSync(join(root, "styles", "personalities.css"), "utf8"); + const importedPersonalities = [ + ...personalitiesCss.matchAll(/@import\s+url\(["']\.\/personalities\/([a-z0-9-]+)\.css["']\);/g) + ].map(([, id]) => id); + + assert.deepEqual(importedPersonalities, expectedPersonalities); }); test("build regenerates public pairing metadata from manifest records", () => { @@ -208,6 +288,10 @@ test("build regenerates public pairing metadata from manifest records", () => { assert.equal(rebuiltMetadata.generatedFrom, "manifest.json"); assert.deepEqual(rebuiltMetadata.personalities, manifest.personalityPairings); + assert.deepEqual( + rebuiltMetadata.personalities.map(({ compatibleVisualPresets }) => compatibleVisualPresets), + manifest.personalityPairings.map(({ compatibleVisualPresets }) => compatibleVisualPresets) + ); assert.match(fallbackScript, /Generated from manifest\.json by scripts\/build\.mjs/); assert.ok(fallbackMatch, "The generated demo fallback must embed public pairing metadata."); assert.deepEqual(JSON.parse(fallbackMatch[1]), rebuiltMetadata); From b94fb02608279ed20bfd204a54a87421cc83ac35 Mon Sep 17 00:00:00 2001 From: Foscat Date: Thu, 3 Sep 2026 09:41:32 -0500 Subject: [PATCH 09/11] chore: align ui style kit 2.3 fixture --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9bb0887..c329c5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "css-tree": "3.2.1", "interactive-surface-css": "1.5.0", "stylelint": "17.14.0", - "ui-style-kit-css": "2.1.0" + "ui-style-kit-css": "2.3.0" }, "engines": { "node": ">=20" @@ -1606,9 +1606,9 @@ } }, "node_modules/ui-style-kit-css": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ui-style-kit-css/-/ui-style-kit-css-2.1.0.tgz", - "integrity": "sha512-GSMpvsxzr0Hr2rGDRGRxYM8y1mLEwt/q49OgCxik5EGH8L0bobe28wc1OYJ3xvOn0H9OtM2gKFLlkJZZL2zajw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ui-style-kit-css/-/ui-style-kit-css-2.3.0.tgz", + "integrity": "sha512-Au2CYyzIlnqFYkVpg1qu9PrKLUowgjy+m1k1DvW9n8v0kMmq+yVnYx1/dcl6j9AmWgFzerfRaE6UC+OCsgXm+Q==", "dev": true, "license": "MIT", "engines": { diff --git a/package.json b/package.json index cb8b217..c115003 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "css-tree": "3.2.1", "interactive-surface-css": "1.5.0", "stylelint": "17.14.0", - "ui-style-kit-css": "2.1.0" + "ui-style-kit-css": "2.3.0" }, "overrides": { "fast-uri": "3.1.5", From bb9ca1f5b66c20b784e0621975c83302891a983e Mon Sep 17 00:00:00 2001 From: Foscat Date: Thu, 3 Sep 2026 09:48:46 -0500 Subject: [PATCH 10/11] docs: add 3.2 layout reference and lab fixtures --- README.md | 22 ++-- demo/demo.css | 73 ++++++++++++- demo/demo.js | 63 ++++++++++- demo/index.html | 99 +++++++++++++---- design-qa.md | 82 ++++++++++++++ docs/wiki/Demo-And-GitHub-Pages.md | 6 +- docs/wiki/Getting-Started.md | 2 + docs/wiki/Home.md | 7 +- docs/wiki/Layout-Personality-Reference.md | 67 ++++++++++++ docs/wiki/Layout-Primitives.md | 8 +- docs/wiki/Layout-Recipes.md | 2 +- docs/wiki/Layout-Styles.md | 29 ++--- docs/wiki/Migrating-To-3.2.md | 70 ++++++++++++ docs/wiki/UI-Style-Kit-Compatibility.md | 6 ++ docs/wiki/_Sidebar.md | 2 + test/demo-smoke.test.mjs | 125 ++++++++++++++++++++-- test/layout-css-contract.test.mjs | 2 + test/release-docs-contract.test.mjs | 45 +++++++- 18 files changed, 632 insertions(+), 78 deletions(-) create mode 100644 design-qa.md create mode 100644 docs/wiki/Layout-Personality-Reference.md create mode 100644 docs/wiki/Migrating-To-3.2.md diff --git a/README.md b/README.md index cc3f4b7..96086c4 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Zero-configuration, dependency-free structural CSS that responds to the width and height a layout actually receives. -`layout-style-css@3.1.0` is the current additive v3 release. It provides intrinsic wrappers, composition primitives, seven semantic recipes, explicit local density controls, and sixteen spatial personalities. Layout owns structure; UI Style Kit owns paint; Interactive Surface owns interaction styling. +`layout-style-css@3.1.0` is the current published v3 release. This branch carries the v3.2 implementation preview: intrinsic wrappers, Mosaic and Action Bar compositions, seven semantic recipes, explicit local density controls, and twenty spatial personalities. Layout owns structure; UI Style Kit owns paint; Interactive Surface owns interaction styling. ## Requirements @@ -87,11 +87,11 @@ All lanes clamp to the available inline size, including allocations from 320px t The core includes: - `.ly-stack`, `.ly-cluster`, `.ly-center`, and `.ly-cover` -- `.ly-switcher`, `.ly-sidebar`, `.ly-grid`, and `.ly-split` +- `.ly-switcher`, `.ly-sidebar`, `.ly-grid`, `.ly-mosaic`, and `.ly-split` - `.ly-panes` and `.ly-media` -- `.ly-reel`, `.ly-frame`, and `.ly-scroll` +- `.ly-action-bar`, `.ly-reel`, `.ly-frame`, and `.ly-scroll` -Grid and flex primitives wrap intrinsically whenever track wrapping can replace a query. Base `.ly-scroll` owns overflow but no height cap. Add `.ly-scroll--bounded` for the stable `--ly-scroll-max` cap or `.ly-scroll--viewport` for height-aware `--ly-scroll-viewport-max` behavior. Only `.ly-reel` deliberately scrolls horizontally; only the Scroll family deliberately creates vertical scrolling. +Grid and flex primitives wrap intrinsically whenever track wrapping can replace a query. Mosaic uses one, six, and twelve tracks at its base, `42rem`, and `72rem` tiers while keeping DOM order authoritative. Base `.ly-scroll` owns horizontal and vertical overflow but no height cap. Add `.ly-scroll--bounded` for the stable `--ly-scroll-max` cap or `.ly-scroll--viewport` for height-aware `--ly-scroll-viewport-max` behavior. Gap utilities `.ly-gap-0` through `.ly-gap-9` assign `gap` only on the element carrying the class. They do not alter inherited primitive gap variables. Override `--ly-gap`, `--ly-grid-gap`, `--ly-stack-gap`, or `--ly-cluster-gap` when a shared spacing context is intentional. @@ -111,7 +111,7 @@ Recipes use attributes only. The stacked semantic source order is always safe, a The same ownership is available in `manifest.json` through `thresholds.recipes`, alongside the generic container-width and viewport-height arrays. Release checks verify every mapping against authored queries and require every public geometry token to reach a runtime CSS declaration. -App Shell base, medium, and wide topologies own matching row definitions. This keeps the primary workspace flexible while header and footer tracks remain intrinsic, including personality-specific four-row topologies. +App Shell base, medium, and wide topologies own matching row definitions. The automatic shell is area-aware: absent direct-child side regions do not reserve empty tracks, while full shells preserve personality-approved geometry. `--ly-recipe-main-min: 20rem` guards automatic primary tracks. Canonical regions use `data-ly-area`, including `header`, `sidebar`, `nav`, `main`, `aside`, `footer`, `content`, `media`, `actions`, `primary`, and `secondary`. @@ -155,12 +155,14 @@ Use the public height, gap, measure, ratio, rail, media, card, and grid-minimum ## Personalities -Set one of sixteen canonical `data-ly-layout` values on `.ly-root`: +Set one of twenty canonical `data-ly-layout` values on `.ly-root`: -`minimal-saas`, `bauhaus`, `tactile`, `cyberpunk`, `f-pattern`, `brutalism`, `neumorphism`, `y2k`, `retro-glass`, `z-pattern`, `retrofuturism`, `mondrian`, `synthwave`, `bento`, `maximalist`, or `split-screen`. +`minimal-saas`, `bento`, `maximalist`, `bauhaus`, `tactile`, `neumorphism`, `retrofuturism`, `brutalism`, `cyberpunk`, `y2k`, `retro-glass`, `f-pattern`, `z-pattern`, `split-screen`, `mondrian`, `synthwave`, `technical-blueprint`, `data-terminal`, `industrial-hmi`, or `editorial`. Each personality is a token/topology profile consumed by the shared recipe engine. A profile changes at least two spatial characteristics—such as measure, gap, rail, media size, card minimum, or ratio—but does not declare its own container or viewport breakpoint system. +See the [Layout Personality Reference](docs/wiki/Layout-Personality-Reference.md) for canonical geometry, responsive intent, Mosaic usage, and recommended/compatible UI presets. + ## Public Exports | Import | Contents | @@ -173,7 +175,7 @@ Each personality is a token/topology profile consumed by the shared recipe engin | `layout-style-css/primitives.css` | Intrinsic composition primitives | | `layout-style-css/recipes.css` | Seven attribute-only recipes | | `layout-style-css/utilities.css` | Small structural utility set | -| `layout-style-css/personalities.css` | All sixteen profiles | +| `layout-style-css/personalities.css` | All twenty profiles | | `layout-style-css/personalities/minimal-saas.css` | One profile; substitute any public personality name | | `layout-style-css/personalities.json` | Public layout-to-visual pairing recommendations | | `layout-style-css/package.json` | Package metadata | @@ -204,7 +206,7 @@ This order lets UI Style Kit establish paint and theme roles, Interactive Surfac ## Clean-Break Migration -v3 has no compatibility bundle. It removes `legacy.css`, the deprecated UI Style Kit structural bridge, v1/v2 aliases, responsive `ly-md-*` and `ly-lg-*` utilities, and all visual-order utilities. See [Migrating To 3.0](docs/wiki/Migrating-To-3.0.md) for the major-version mappings and [Migrating To 3.1](docs/wiki/Migrating-To-3.1.md) for density, local gap, and Scroll behavior changes. +v3 has no compatibility bundle. It removes `legacy.css`, the deprecated UI Style Kit structural bridge, v1/v2 aliases, responsive `ly-md-*` and `ly-lg-*` utilities, and all visual-order utilities. See [Migrating To 3.0](docs/wiki/Migrating-To-3.0.md) for the major-version mappings, [Migrating To 3.1](docs/wiki/Migrating-To-3.1.md) for density and local-gap changes, and [Migrating To 3.2](docs/wiki/Migrating-To-3.2.md) for Mosaic, Action Bar, area-aware shells, and content resilience. ## Demo And Verification @@ -229,8 +231,10 @@ npm run release:verify - [Layout Primitives](docs/wiki/Layout-Primitives.md) - [Layout Recipes](docs/wiki/Layout-Recipes.md) - [Layout Styles](docs/wiki/Layout-Styles.md) +- [Layout Personality Reference](docs/wiki/Layout-Personality-Reference.md) - [Migrating To 3.0](docs/wiki/Migrating-To-3.0.md) - [Migrating To 3.1](docs/wiki/Migrating-To-3.1.md) +- [Migrating To 3.2](docs/wiki/Migrating-To-3.2.md) - [Demo And GitHub Pages](docs/wiki/Demo-And-GitHub-Pages.md) - [Release And Publishing](docs/wiki/Release-And-Publishing.md) - [Security And Support](docs/wiki/Security-And-Support.md) diff --git a/demo/demo.css b/demo/demo.css index c6a753f..66f171a 100644 --- a/demo/demo.css +++ b/demo/demo.css @@ -201,6 +201,17 @@ h3 { font-size: 0.875rem; } +.demo-pairing-guidance { + display: grid; + gap: 0.25rem; + padding: 0.75rem; + border: 1px solid var(--demo-line); + border-radius: calc(var(--demo-radius) * 0.6); + background: var(--demo-panel-strong); + color: var(--demo-muted); + font-size: 0.75rem; +} + .demo-readouts { display: grid; justify-items: end; @@ -389,12 +400,72 @@ body[data-ecosystem="all-three"] .demo-status { min-inline-size: 0; gap: 0.75rem; padding: var(--demo-region-padding); - overflow: hidden; border: 1px solid var(--demo-line); border-radius: calc(var(--demo-radius) * 0.65); background: var(--demo-panel); } +.demo-composition-fixtures { + display: grid; + min-inline-size: 0; + gap: var(--demo-density-gap); + margin-block-start: var(--demo-density-gap); +} + +.demo-fixture { + display: grid; + min-inline-size: 0; + gap: 0.75rem; + padding: var(--demo-region-padding); + border: 1px solid var(--demo-line); + border-radius: calc(var(--demo-radius) * 0.65); + background: var(--demo-panel); +} + +.demo-fixture-heading { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + gap: 0.5rem; + color: var(--demo-muted); + font-size: 0.8125rem; +} + +.demo-mosaic { + min-inline-size: 0; +} + +.demo-mosaic-item { + min-block-size: 4rem; + min-inline-size: 0; + padding: 0.75rem; + border: 1px solid var(--demo-line); + border-radius: calc(var(--demo-radius) * 0.45); + background: var(--demo-panel-strong); +} + +.demo-resilience-scroll { + --ly-scroll-max: 8rem; +} + +.demo-resilience-scroll table { + min-inline-size: 50rem; + border-collapse: collapse; +} + +.demo-resilience-scroll th, +.demo-resilience-scroll td { + padding: 0.5rem 0.75rem; + border: 1px solid var(--demo-line); + text-align: start; + white-space: nowrap; +} + +.demo-resilience-scroll th { + background: var(--demo-panel-strong); +} + .demo-region[data-ly-area="main"], .demo-region[data-ly-area="secondary"], .demo-region[data-ly-area="content"] { diff --git a/demo/demo.js b/demo/demo.js index ca80265..8525807 100644 --- a/demo/demo.js +++ b/demo/demo.js @@ -1,4 +1,4 @@ -const UI_STYLE_KIT_VERSION = "2.1.0"; +const UI_STYLE_KIT_VERSION = "2.3.0"; const UI_STYLE_KIT_MANIFEST_URL = `https://unpkg.com/ui-style-kit-css@${UI_STYLE_KIT_VERSION}/manifest.json`; const PERSONALITY_METADATA_URL = document.querySelector("script[data-personalities-url]")?.dataset.personalitiesUrl; const UI_STYLE_KIT_MANIFEST_FALLBACK = Object.freeze({ @@ -14,7 +14,16 @@ const UI_STYLE_KIT_MANIFEST_FALLBACK = Object.freeze({ Object.freeze({ id: "brutalism", label: "Brutalism", prefix: "brutal" }), Object.freeze({ id: "cyberpunk", label: "Cyberpunk", prefix: "cyber" }), Object.freeze({ id: "y2k", label: "Y2K", prefix: "y2k" }), - Object.freeze({ id: "retro-glass", label: "Retro Glass", prefix: "rg" }) + Object.freeze({ id: "retro-glass", label: "Retro Glass", prefix: "rg" }), + Object.freeze({ id: "editorial-luxe", label: "Editorial Luxe", prefix: "luxe" }), + Object.freeze({ id: "organic-modern", label: "Organic Modern", prefix: "organic" }), + Object.freeze({ id: "industrial-utility", label: "Industrial Utility", prefix: "utility" }), + Object.freeze({ id: "technical-blueprint", label: "Technical Blueprint", prefix: "blueprint" }), + Object.freeze({ id: "art-deco", label: "Art Deco", prefix: "deco" }), + Object.freeze({ id: "clay", label: "Clay", prefix: "clay" }), + Object.freeze({ id: "data-terminal", label: "Data Terminal", prefix: "terminal" }), + Object.freeze({ id: "paper-editorial", label: "Paper Editorial", prefix: "paper" }), + Object.freeze({ id: "neo-noir", label: "Neo Noir", prefix: "noir" }) ]), themes: Object.freeze([ "midnight-gold", @@ -70,9 +79,9 @@ async function loadUiStyleKitManifest() { } catch (error) { /* The published demo can render before the companion UI release reaches every CDN edge. - The fallback mirrors the 2.1 manifest contract so layout behavior stays testable. + The fallback mirrors the 2.3 manifest contract so layout behavior stays testable. */ - console.warn("UI Style Kit 2.1 manifest unavailable; using the packaged fallback.", error); + console.warn("UI Style Kit 2.3 manifest unavailable; using the packaged fallback.", error); return UI_STYLE_KIT_MANIFEST_FALLBACK; } } @@ -87,6 +96,9 @@ function normalizePersonalityMetadata(metadata) { visualCompatibility: String(personality?.visualCompatibility ?? ""), recommendedVisualPresets: Array.isArray(personality?.recommendedVisualPresets) ? personality.recommendedVisualPresets.map(String) + : [], + compatibleVisualPresets: Array.isArray(personality?.compatibleVisualPresets) + ? personality.compatibleVisualPresets.map(String) : [] })); @@ -114,7 +126,8 @@ function minimalPersonalityFallback() { id: "minimal-saas", label: "Minimal SaaS", visualCompatibility: "any", - recommendedVisualPresets: [] + recommendedVisualPresets: [], + compatibleVisualPresets: [] }) ]) }); @@ -301,6 +314,8 @@ const importsSnippet = document.querySelector("#importsSnippet"); const markupSnippet = document.querySelector("#markupSnippet"); const copyStatus = document.querySelector("#copyStatus"); const personalityMetadataStatus = document.querySelector("#personalityMetadataStatus"); +const recommendedUiGuidance = document.querySelector("#recommendedUiGuidance"); +const compatibleUiGuidance = document.querySelector("#compatibleUiGuidance"); const ecosystemStatus = document.querySelector("#ecosystemStatus"); const containerReadout = document.querySelector("#containerReadout"); const topologyReadout = document.querySelector("#topologyReadout"); @@ -313,6 +328,8 @@ const drawer = document.querySelector("#demoControlsDrawer"); const drawerClose = document.querySelector("#demoControlsClose"); const drawerBackdrop = document.querySelector("#demoControlsBackdrop"); const stateToggle = document.querySelector("#stateToggle"); +const actionBarStickyToggle = document.querySelector("#actionBarStickyToggle"); +const fixtureActionBar = document.querySelector("#fixtureActionBar"); const mobileControlsQuery = window.matchMedia("(max-width: 63.999rem)"); body.dataset.uiManifestVersion = UI_STYLE_KIT_MANIFEST.version; @@ -546,6 +563,34 @@ function syncPersonalityMetadataSelectOptions() { select.setAttribute("aria-busy", "false"); } +/** + * Renders advisory visual-preset pairings for the selected layout without + * mutating the independently selected UI preset. + * + * @returns {void} + */ +function syncPairingGuidance() { + const pairing = PERSONALITY_METADATA.personalities.find(({ id }) => id === state.personality); + /** + * Formats visual-preset identifiers for human-readable guidance. + * + * @param {string[]} presets Visual-preset identifiers. + * @param {string} fallback Text shown when no presets are listed. + * @returns {string} Display-ready visual-preset guidance. + */ + const describePresets = (presets, fallback) => + presets.length > 0 ? presets.map(formatLabel).join(", ") : fallback; + + recommendedUiGuidance.textContent = `Recommended UI: ${describePresets( + pairing?.recommendedVisualPresets ?? [], + pairing?.visualCompatibility === "any" ? "Any visual preset" : "None listed" + )}`; + compatibleUiGuidance.textContent = `Compatible UI: ${describePresets( + pairing?.compatibleVisualPresets ?? [], + "None listed" + )}`; +} + function syncUiKitClasses() { const prefix = UI_CLASS_PREFIXES[state.ui]; @@ -715,6 +760,7 @@ function applyState(options = {}) { syncHeightTier(allocation); renderRecipe(); + syncPairingGuidance(); syncUiKitClasses(); syncEcosystem(); syncSnippets(); @@ -852,6 +898,13 @@ stateToggle.addEventListener("click", () => { stateToggle.textContent = pressed ? "Active state on" : "Toggle active state"; }); +actionBarStickyToggle.addEventListener("click", () => { + const pressed = actionBarStickyToggle.getAttribute("aria-pressed") !== "true"; + actionBarStickyToggle.setAttribute("aria-pressed", String(pressed)); + actionBarStickyToggle.textContent = pressed ? "Disable sticky mode" : "Enable sticky mode"; + fixtureActionBar.classList.toggle("ly-action-bar--sticky", pressed); +}); + document.querySelectorAll("[data-copy-target]").forEach((button) => { button.addEventListener("click", () => copySnippet(button)); }); diff --git a/demo/index.html b/demo/index.html index 9518cab..047efb6 100644 --- a/demo/index.html +++ b/demo/index.html @@ -5,9 +5,9 @@ - - - + + + @@ -37,8 +37,8 @@ - - + + @@ -47,13 +47,13 @@ - + - + - + @@ -66,40 +66,40 @@ - Layout Style CSS v3 — Intrinsic Responsive Demo + Layout Style CSS v3.2 Preview — Intrinsic Responsive Demo - - + + - - + + - - + + Skip to the layout lab
- Layout Style CSS v3 + Layout Style CSS v3.2 Preview Intrinsic Responsive Lab
@@ -168,6 +168,10 @@

Layout controls

+
+

Recommended UI: Minimal SaaS

+

Compatible UI: Organic Modern

+