layout-style-css 1.0.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/CONTRIBUTING.md +50 -0
  3. package/README.md +205 -16
  4. package/SECURITY.md +45 -0
  5. package/demo/assets/social-card.png +0 -0
  6. package/demo/index.html +358 -82
  7. package/dist/layout-all.css +5 -0
  8. package/dist/layout-base.css +67 -0
  9. package/dist/layout-style-css.css +571 -0
  10. package/dist/layout-style-css.min.css +1 -1
  11. package/dist/layout-style-f-pattern.css +76 -0
  12. package/dist/layout-style-mondrian.css +77 -0
  13. package/dist/layout-style-split-screen.css +62 -0
  14. package/dist/layout-style-synthwave.css +88 -0
  15. package/dist/layout-style-z-pattern.css +76 -0
  16. package/dist/layout-ui-style-kit-bridge.css +115 -0
  17. package/docs/wiki/Contributing.md +30 -0
  18. package/docs/wiki/Demo-And-GitHub-Pages.md +39 -0
  19. package/docs/wiki/Getting-Started.md +68 -0
  20. package/docs/wiki/Home.md +48 -0
  21. package/docs/wiki/Installation-And-CDN.md +58 -0
  22. package/docs/wiki/Layout-Primitives.md +57 -0
  23. package/docs/wiki/Layout-Recipes.md +80 -0
  24. package/docs/wiki/Layout-Styles.md +43 -0
  25. package/docs/wiki/Release-And-Publishing.md +69 -0
  26. package/docs/wiki/Security-And-Support.md +34 -0
  27. package/docs/wiki/UI-Style-Kit-Compatibility.md +54 -0
  28. package/docs/wiki/_Sidebar.md +14 -0
  29. package/package.json +12 -2
  30. package/styles/layout-base.css +67 -0
  31. package/styles/layout-style-f-pattern.css +76 -0
  32. package/styles/layout-style-mondrian.css +77 -0
  33. package/styles/layout-style-split-screen.css +62 -0
  34. package/styles/layout-style-synthwave.css +88 -0
  35. package/styles/layout-style-z-pattern.css +76 -0
  36. package/styles/layout-ui-style-kit-bridge.css +115 -0
  37. package/demo/assets/social-card.svg +0 -17
package/demo/index.html CHANGED
@@ -29,7 +29,8 @@
29
29
  <meta name="apple-mobile-web-app-capable" content="yes">
30
30
  <meta name="apple-mobile-web-app-title" content="layout-style-css">
31
31
  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
32
- <meta name="theme-color" content="#111827">
32
+ <meta name="theme-color" content="#111827" media="(prefers-color-scheme: dark)">
33
+ <meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)">
33
34
  <meta name="msapplication-TileColor" content="#111827">
34
35
  <meta name="msapplication-config" content="./browserconfig.xml">
35
36
  <meta name="color-scheme" content="light dark">
@@ -37,10 +38,10 @@
37
38
  <meta property="og:locale" content="en_US">
38
39
  <meta property="og:title" content="layout-style-css + UI Style Kit CSS Demo">
39
40
  <meta property="og:description" content="Swap layout shells independently from UI styles while keeping ui-style-kit-css in charge of visual identity.">
40
- <meta property="og:image" content="https://foscat.github.io/layout-style-css/assets/social-card.svg">
41
- <meta property="og:image:secure_url" content="https://foscat.github.io/layout-style-css/assets/social-card.svg">
41
+ <meta property="og:image" content="https://foscat.github.io/layout-style-css/assets/social-card.png">
42
+ <meta property="og:image:secure_url" content="https://foscat.github.io/layout-style-css/assets/social-card.png">
42
43
  <meta property="og:image:alt" content="layout-style-css shell-first CSS social card">
43
- <meta property="og:image:type" content="image/svg+xml">
44
+ <meta property="og:image:type" content="image/png">
44
45
  <meta property="og:image:width" content="1200">
45
46
  <meta property="og:image:height" content="630">
46
47
  <meta property="og:url" content="https://foscat.github.io/layout-style-css/">
@@ -49,15 +50,15 @@
49
50
  <meta name="twitter:card" content="summary_large_image">
50
51
  <meta name="twitter:title" content="layout-style-css + UI Style Kit CSS Demo">
51
52
  <meta name="twitter:description" content="Shell-first responsive layouts that mix and match with ui-style-kit-css v2.0.1.">
52
- <meta name="twitter:image" content="https://foscat.github.io/layout-style-css/assets/social-card.svg">
53
+ <meta name="twitter:image" content="https://foscat.github.io/layout-style-css/assets/social-card.png">
53
54
  <meta name="twitter:image:alt" content="layout-style-css shell-first CSS social card">
54
55
  <meta itemprop="name" content="layout-style-css + UI Style Kit CSS Demo">
55
56
  <meta itemprop="description" content="Shell-first responsive layouts that mix and match with ui-style-kit-css v2.0.1.">
56
- <meta itemprop="image" content="https://foscat.github.io/layout-style-css/assets/social-card.svg">
57
+ <meta itemprop="image" content="https://foscat.github.io/layout-style-css/assets/social-card.png">
57
58
  <link rel="canonical" href="https://foscat.github.io/layout-style-css/">
58
59
  <link rel="dns-prefetch" href="https://unpkg.com">
59
60
  <link rel="preconnect" href="https://unpkg.com" crossorigin>
60
- <link rel="image_src" href="./assets/social-card.svg">
61
+ <link rel="image_src" href="./assets/social-card.png">
61
62
  <link rel="icon" type="image/svg+xml" href="./assets/favicon.svg">
62
63
  <link rel="shortcut icon" href="./assets/favicon.svg">
63
64
  <link rel="apple-touch-icon" href="./assets/apple-touch-icon.svg">
@@ -76,7 +77,7 @@
76
77
  "programmingLanguage": "CSS",
77
78
  "applicationCategory": "DeveloperApplication",
78
79
  "url": "https://foscat.github.io/layout-style-css/",
79
- "image": "https://foscat.github.io/layout-style-css/assets/social-card.svg",
80
+ "image": "https://foscat.github.io/layout-style-css/assets/social-card.png",
80
81
  "datePublished": "2026-06-30",
81
82
  "dateModified": "2026-06-30",
82
83
  "keywords": [
@@ -124,6 +125,24 @@
124
125
  gap: 0.625rem;
125
126
  }
126
127
 
128
+ .demo-controls-shell {
129
+ min-width: 0;
130
+ }
131
+
132
+ .demo-controls-panel {
133
+ min-width: 0;
134
+ }
135
+
136
+ .demo-controls-heading {
137
+ display: none;
138
+ }
139
+
140
+ #demoControlsToggle,
141
+ #demoControlsClose,
142
+ #demoControlsBackdrop {
143
+ display: none;
144
+ }
145
+
127
146
  .demo-select {
128
147
  min-width: 10.5rem;
129
148
  }
@@ -224,30 +243,103 @@
224
243
  overflow-wrap: anywhere;
225
244
  }
226
245
 
246
+ .demo-recipe-swatch {
247
+ min-block-size: 3.75rem;
248
+ }
249
+
227
250
  @media (min-width: 90rem) {
228
251
  .demo-detail-layout {
229
252
  grid-template-columns: minmax(10rem, 0.4fr) minmax(0, 1fr);
230
253
  }
231
254
  }
232
255
 
233
- @media (max-width: 48rem) {
256
+ @media (max-width: 74.999rem) {
234
257
  .demo-header {
235
- align-items: stretch;
236
- flex-direction: column;
258
+ align-items: center;
259
+ gap: 0.75rem;
260
+ }
261
+
262
+ .demo-brand {
263
+ flex: 1 1 min(100%, 13rem);
264
+ min-width: 0;
265
+ }
266
+
267
+ #demoControlsToggle {
268
+ display: inline-flex;
269
+ flex: 0 0 auto;
270
+ }
271
+
272
+ #demoControlsClose {
273
+ display: inline-flex;
274
+ }
275
+
276
+ #demoControlsBackdrop {
277
+ position: fixed;
278
+ inset: 0;
279
+ z-index: calc(var(--ly-z-header) + 10);
280
+ }
281
+
282
+ #demoControlsBackdrop[data-open="true"] {
283
+ display: block;
284
+ }
285
+
286
+ .demo-controls-shell {
287
+ position: fixed;
288
+ inset-block: 0;
289
+ inset-inline-end: 0;
290
+ z-index: calc(var(--ly-z-header) + 20);
291
+ width: min(calc(100% - 2rem), 24rem);
292
+ padding: var(--ly-space-4);
293
+ overflow: auto;
294
+ pointer-events: none;
295
+ transform: translateX(100%);
296
+ transition: transform 160ms ease;
297
+ }
298
+
299
+ .demo-controls-shell[aria-hidden="false"] {
300
+ pointer-events: auto;
301
+ transform: translateX(0);
302
+ }
303
+
304
+ .demo-controls-panel {
305
+ min-height: 100%;
306
+ display: grid;
307
+ grid-auto-rows: max-content;
308
+ align-content: start;
309
+ gap: var(--ly-space-4);
310
+ }
311
+
312
+ .demo-controls-heading {
313
+ display: flex;
314
+ align-items: center;
315
+ justify-content: space-between;
316
+ gap: var(--ly-space-3);
237
317
  }
238
318
 
239
319
  .demo-controls {
320
+ display: grid;
321
+ grid-auto-rows: max-content;
322
+ align-content: start;
240
323
  justify-content: stretch;
241
324
  }
242
325
 
243
326
  .demo-controls > * {
244
- flex: 1 1 100%;
245
327
  min-width: 0;
246
328
  }
247
329
 
248
330
  .demo-select {
249
331
  width: 100%;
250
332
  }
333
+
334
+ .ly-root[data-demo-controls-open="true"] {
335
+ overflow: hidden;
336
+ }
337
+ }
338
+
339
+ @media (min-width: 75rem) {
340
+ .demo-controls-panel {
341
+ display: contents;
342
+ }
251
343
  }
252
344
  </style>
253
345
  </head>
@@ -260,63 +352,87 @@
260
352
  <span>Independent shell layouts for ui-style-kit-css@2.0.1</span>
261
353
  </div>
262
354
 
263
- <div class="demo-controls">
264
- <label>
265
- <span class="ly-visually-hidden">UI system</span>
266
- <select class="demo-select" id="uiSelect" data-ui-kit="select">
267
- <option value="minimal-saas">Minimal SaaS UI</option>
268
- <option value="bento">Bento UI</option>
269
- <option value="maximalist">Maximalist UI</option>
270
- <option value="bauhaus">Bauhaus UI</option>
271
- <option value="tactile">Tactile UI</option>
272
- <option value="neumorphism">Neumorphism UI</option>
273
- <option value="retrofuturism">Retrofuturism UI</option>
274
- <option value="brutalism">Brutalism UI</option>
275
- <option value="cyberpunk">Cyberpunk UI</option>
276
- <option value="y2k">Y2K UI</option>
277
- <option value="retro-glass">Retro Glass UI</option>
278
- </select>
279
- </label>
280
- <label>
281
- <span class="ly-visually-hidden">Layout style</span>
282
- <select class="demo-select" id="layoutSelect" data-ui-kit="select">
283
- <option value="minimal-saas">Minimal SaaS Layout</option>
284
- <option value="bento">Bento Layout</option>
285
- <option value="maximalist">Maximalist Layout</option>
286
- <option value="bauhaus">Bauhaus Layout</option>
287
- <option value="tactile">Tactile Layout</option>
288
- <option value="neumorphism">Neumorphism Layout</option>
289
- <option value="retrofuturism">Retrofuturism Layout</option>
290
- <option value="brutalism">Brutalism Layout</option>
291
- <option value="cyberpunk">Cyberpunk Layout</option>
292
- <option value="y2k">Y2K Layout</option>
293
- <option value="retro-glass">Retro Glass Layout</option>
294
- </select>
295
- </label>
296
- <label>
297
- <span class="ly-visually-hidden">Theme</span>
298
- <select class="demo-select" id="themeSelect" data-ui-kit="select">
299
- <option value="arctic-indigo">Arctic Indigo</option>
300
- <option value="midnight-gold">Midnight Gold</option>
301
- <option value="ocean-steel">Ocean Steel</option>
302
- <option value="forest-moss">Forest Moss</option>
303
- <option value="sunset-ember">Sunset Ember</option>
304
- <option value="royal-plum">Royal Plum</option>
305
- <option value="graphite-cyan">Graphite Cyan</option>
306
- <option value="desert-sage">Desert Sage</option>
307
- <option value="rose-quartz">Rose Quartz</option>
308
- <option value="cyber-lime">Cyber Lime</option>
309
- </select>
310
- </label>
311
- <label>
312
- <span class="ly-visually-hidden">Mode</span>
313
- <select class="demo-select" id="modeSelect" data-ui-kit="select">
314
- <option value="light">Light</option>
315
- <option value="dark">Dark</option>
316
- <option value="contrast">Contrast</option>
317
- </select>
318
- </label>
319
- <button type="button" id="mixedPreset" data-ui-kit="button button-secondary">Cyberpunk UI + Maximalist Layout</button>
355
+ <button
356
+ type="button"
357
+ id="demoControlsToggle"
358
+ aria-controls="demoControlsDrawer"
359
+ aria-expanded="false"
360
+ data-ui-kit="button button-secondary"
361
+ >Controls</button>
362
+
363
+ <span id="demoControlsBackdrop" aria-hidden="true"></span>
364
+
365
+ <div class="demo-controls-shell" id="demoControlsDrawer" aria-hidden="true">
366
+ <div class="demo-controls-panel" data-ui-kit="panel">
367
+ <div class="demo-controls-heading">
368
+ <strong>Demo controls</strong>
369
+ <button type="button" id="demoControlsClose" data-ui-kit="button">Close</button>
370
+ </div>
371
+
372
+ <div class="demo-controls">
373
+ <label>
374
+ <span class="ly-visually-hidden">UI system</span>
375
+ <select class="demo-select" id="uiSelect" data-ui-kit="select">
376
+ <option value="minimal-saas">Minimal SaaS UI</option>
377
+ <option value="bento">Bento UI</option>
378
+ <option value="maximalist">Maximalist UI</option>
379
+ <option value="bauhaus">Bauhaus UI</option>
380
+ <option value="tactile">Tactile UI</option>
381
+ <option value="neumorphism">Neumorphism UI</option>
382
+ <option value="retrofuturism">Retrofuturism UI</option>
383
+ <option value="brutalism">Brutalism UI</option>
384
+ <option value="cyberpunk">Cyberpunk UI</option>
385
+ <option value="y2k">Y2K UI</option>
386
+ <option value="retro-glass">Retro Glass UI</option>
387
+ </select>
388
+ </label>
389
+ <label>
390
+ <span class="ly-visually-hidden">Layout style</span>
391
+ <select class="demo-select" id="layoutSelect" data-ui-kit="select">
392
+ <option value="minimal-saas">Minimal SaaS Layout</option>
393
+ <option value="bento">Bento Layout</option>
394
+ <option value="maximalist">Maximalist Layout</option>
395
+ <option value="bauhaus">Bauhaus Layout</option>
396
+ <option value="tactile">Tactile Layout</option>
397
+ <option value="neumorphism">Neumorphism Layout</option>
398
+ <option value="retrofuturism">Retrofuturism Layout</option>
399
+ <option value="brutalism">Brutalism Layout</option>
400
+ <option value="cyberpunk">Cyberpunk Layout</option>
401
+ <option value="y2k">Y2K Layout</option>
402
+ <option value="retro-glass">Retro Glass Layout</option>
403
+ <option value="f-pattern">F-pattern Layout</option>
404
+ <option value="z-pattern">Z-pattern Layout</option>
405
+ <option value="split-screen">Split-Screen Layout</option>
406
+ <option value="mondrian">Mondrian Layout</option>
407
+ <option value="synthwave">Synthwave Layout</option>
408
+ </select>
409
+ </label>
410
+ <label>
411
+ <span class="ly-visually-hidden">Theme</span>
412
+ <select class="demo-select" id="themeSelect" data-ui-kit="select">
413
+ <option value="arctic-indigo">Arctic Indigo</option>
414
+ <option value="midnight-gold">Midnight Gold</option>
415
+ <option value="ocean-steel">Ocean Steel</option>
416
+ <option value="forest-moss">Forest Moss</option>
417
+ <option value="sunset-ember">Sunset Ember</option>
418
+ <option value="royal-plum">Royal Plum</option>
419
+ <option value="graphite-cyan">Graphite Cyan</option>
420
+ <option value="desert-sage">Desert Sage</option>
421
+ <option value="rose-quartz">Rose Quartz</option>
422
+ <option value="cyber-lime">Cyber Lime</option>
423
+ </select>
424
+ </label>
425
+ <label>
426
+ <span class="ly-visually-hidden">Mode</span>
427
+ <select class="demo-select" id="modeSelect" data-ui-kit="select">
428
+ <option value="light">Light</option>
429
+ <option value="dark">Dark</option>
430
+ <option value="contrast">Contrast</option>
431
+ </select>
432
+ </label>
433
+ <button type="button" id="mixedPreset" data-ui-kit="button button-secondary">Cyberpunk UI + Maximalist Layout</button>
434
+ </div>
435
+ </div>
320
436
  </div>
321
437
  </div>
322
438
  </header>
@@ -333,7 +449,7 @@
333
449
  </ul>
334
450
  </nav>
335
451
  <p>
336
- This same rail becomes a steady SaaS sidebar, a narrow Cyberpunk utility rail, a floating Y2K dock, or a Retro Glass side panel.
452
+ This same rail becomes a SaaS sidebar, Z-pattern support rail, Split-Screen half, Mondrian block, Synthwave dock, or Retro Glass side panel.
337
453
  </p>
338
454
  </div>
339
455
  </aside>
@@ -381,7 +497,7 @@
381
497
  <div class="ly-grid ly-grid--auto" id="metrics">
382
498
  <article class="ly-surface ly-pad-6 demo-stat" data-ui-kit="card">
383
499
  <span>Shell mode</span>
384
- <strong>11</strong>
500
+ <strong>16</strong>
385
501
  <span>layout styles</span>
386
502
  </article>
387
503
  <article class="ly-surface ly-pad-6 demo-stat" data-ui-kit="card">
@@ -429,14 +545,14 @@
429
545
  <section class="ly-stack ly-gap-5" id="recipes" aria-labelledby="recipes-title">
430
546
  <div class="ly-wrapper ly-wrapper--readable ly-stack ly-gap-3">
431
547
  <span class="demo-pill" data-ui-kit="badge badge-secondary">Layout Recipes</span>
432
- <h2 class="demo-panel-title" id="recipes-title">Recipe-style organization for common wrappers.</h2>
548
+ <h2 class="demo-panel-title" id="recipes-title">Recipe-style organization for major wrapper contracts.</h2>
433
549
  <p>
434
550
  Start with a recipe, then mix UI style, layout style, theme, and mode without changing the wrapper contract.
435
551
  </p>
436
552
  </div>
437
553
 
438
- <div class="demo-recipe-grid">
439
- <article class="ly-surface ly-pad-5 demo-recipe-card" data-ui-kit="card">
554
+ <div class="ly-card-grid demo-recipe-grid">
555
+ <article class="ly-surface ly-pad-5 ly-card-md demo-recipe-card" data-ui-kit="card">
440
556
  <h3 class="demo-panel-title">App shell</h3>
441
557
  <p>Use one root shell for a persistent header, sidebar, and main workspace.</p>
442
558
  <div class="ly-wrapper ly-wrapper--readable demo-recipe-preview">
@@ -447,7 +563,7 @@
447
563
  </div>
448
564
  </article>
449
565
 
450
- <article class="ly-surface ly-pad-5 demo-recipe-card" data-ui-kit="card">
566
+ <article class="ly-surface ly-pad-5 ly-card-md demo-recipe-card" data-ui-kit="card">
451
567
  <h3 class="demo-panel-title">Content page</h3>
452
568
  <p>Use a readable wrapper for documentation, articles, and focused landing sections.</p>
453
569
  <div class="ly-wrapper ly-wrapper--readable demo-recipe-preview">
@@ -458,18 +574,17 @@
458
574
  </div>
459
575
  </article>
460
576
 
461
- <article class="ly-surface ly-pad-5 demo-recipe-card" data-ui-kit="card">
462
- <h3 class="demo-panel-title">Dashboard grid</h3>
577
+ <article class="ly-surface ly-pad-5 ly-card-md demo-recipe-card" data-ui-kit="card">
578
+ <h3 class="demo-panel-title">Card grid</h3>
463
579
  <p>Use auto-fit tracks for cards that collapse from desktop to tablet and mobile.</p>
464
580
  <div class="ly-wrapper ly-wrapper--readable demo-recipe-preview">
465
581
  <code>.ly-wrapper--wide</code>
466
- <code>.ly-grid</code>
467
- <code>.ly-grid--auto</code>
582
+ <code>.ly-card-grid</code>
468
583
  <code>.ly-surface</code>
469
584
  </div>
470
585
  </article>
471
586
 
472
- <article class="ly-surface ly-pad-5 demo-recipe-card" data-ui-kit="card">
587
+ <article class="ly-surface ly-pad-5 ly-card-md demo-recipe-card" data-ui-kit="card">
473
588
  <h3 class="demo-panel-title">Split hero</h3>
474
589
  <p>Use a split when one message needs a supporting panel or interactive preview.</p>
475
590
  <div class="ly-wrapper ly-wrapper--readable demo-recipe-preview">
@@ -480,7 +595,7 @@
480
595
  </div>
481
596
  </article>
482
597
 
483
- <article class="ly-surface ly-pad-5 demo-recipe-card" data-ui-kit="card">
598
+ <article class="ly-surface ly-pad-5 ly-card-md demo-recipe-card" data-ui-kit="card">
484
599
  <h3 class="demo-panel-title">Docs sidebar</h3>
485
600
  <p>Use a local sidebar inside the main content when the global shell is not enough.</p>
486
601
  <div class="ly-wrapper ly-wrapper--readable demo-recipe-preview">
@@ -491,7 +606,7 @@
491
606
  </div>
492
607
  </article>
493
608
 
494
- <article class="ly-surface ly-pad-5 demo-recipe-card" data-ui-kit="card">
609
+ <article class="ly-surface ly-pad-5 ly-card-md demo-recipe-card" data-ui-kit="card">
495
610
  <h3 class="demo-panel-title">List detail</h3>
496
611
  <p>Use adaptive panes for inboxes, editors, queues, and preview-driven workflows.</p>
497
612
  <div class="ly-wrapper ly-wrapper--readable demo-recipe-preview">
@@ -501,6 +616,69 @@
501
616
  <code>.ly-surface</code>
502
617
  </div>
503
618
  </article>
619
+
620
+ <article class="ly-surface ly-pad-5 ly-card-sm demo-recipe-card" data-ui-kit="card">
621
+ <h3 class="demo-panel-title">Button group</h3>
622
+ <p>Use a wrapping action row without forcing buttons to fill the mobile viewport.</p>
623
+ <div class="ly-button-group">
624
+ <button type="button" data-ui-kit="button button-primary">Primary</button>
625
+ <button type="button" data-ui-kit="button">Secondary</button>
626
+ </div>
627
+ <div class="demo-recipe-preview">
628
+ <code>.ly-button-group</code>
629
+ <code>.saas-button-group</code>
630
+ </div>
631
+ </article>
632
+
633
+ <article class="ly-surface ly-pad-5 ly-card-lg demo-recipe-card" data-ui-kit="card">
634
+ <h3 class="demo-panel-title">Card size</h3>
635
+ <p>Use sizing helpers when cards need consistent rhythm without hard-coded visual styles.</p>
636
+ <div class="demo-recipe-preview">
637
+ <code>.ly-card-sm</code>
638
+ <code>.ly-card-md</code>
639
+ <code>.ly-card-lg</code>
640
+ <code>.saas-card-grid</code>
641
+ </div>
642
+ </article>
643
+
644
+ <article class="ly-surface ly-pad-5 ly-card-md demo-recipe-card" data-ui-kit="card">
645
+ <h3 class="demo-panel-title">Gallery</h3>
646
+ <p>Use gallery tracks for image or media groups that should reflow without a script.</p>
647
+ <div class="ly-gallery">
648
+ <div class="ly-frame ly-frame-4x3 demo-recipe-swatch" data-ui-kit="panel"></div>
649
+ <div class="ly-frame ly-frame-4x3 demo-recipe-swatch" data-ui-kit="panel"></div>
650
+ <div class="ly-frame ly-frame-4x3 demo-recipe-swatch" data-ui-kit="panel"></div>
651
+ </div>
652
+ <div class="demo-recipe-preview">
653
+ <code>.ly-gallery</code>
654
+ <code>.rg-gallery</code>
655
+ </div>
656
+ </article>
657
+
658
+ <article class="ly-surface ly-pad-5 ly-card-md demo-recipe-card" data-ui-kit="card">
659
+ <h3 class="demo-panel-title">Carousel</h3>
660
+ <p>Use horizontal snap tracks for preview rows while keeping card visuals external.</p>
661
+ <div class="ly-carousel">
662
+ <div class="ly-surface ly-pad-4 ly-card-sm" data-ui-kit="panel">One</div>
663
+ <div class="ly-surface ly-pad-4 ly-card-sm" data-ui-kit="panel">Two</div>
664
+ <div class="ly-surface ly-pad-4 ly-card-sm" data-ui-kit="panel">Three</div>
665
+ </div>
666
+ <div class="demo-recipe-preview">
667
+ <code>.ly-carousel</code>
668
+ <code>.bento-carousel</code>
669
+ </div>
670
+ </article>
671
+
672
+ <article class="ly-surface ly-pad-5 ly-card-md demo-recipe-card" data-ui-kit="card">
673
+ <h3 class="demo-panel-title">Frame and scroll</h3>
674
+ <p>Use frames for media ratios and scroll areas for bounded content regions.</p>
675
+ <div class="demo-recipe-preview">
676
+ <code>.ly-frame</code>
677
+ <code>.ly-frame-16x9</code>
678
+ <code>.ly-scroll-area</code>
679
+ <code>.ly-overflow-auto</code>
680
+ </div>
681
+ </article>
504
682
  </div>
505
683
  </section>
506
684
  </div>
@@ -514,9 +692,15 @@
514
692
  const layoutSelect = document.querySelector("#layoutSelect");
515
693
  const themeSelect = document.querySelector("#themeSelect");
516
694
  const modeSelect = document.querySelector("#modeSelect");
695
+ const controlsToggle = document.querySelector("#demoControlsToggle");
696
+ const controlsDrawer = document.querySelector("#demoControlsDrawer");
697
+ const controlsBackdrop = document.querySelector("#demoControlsBackdrop");
698
+ const controlsClose = document.querySelector("#demoControlsClose");
517
699
  const mixedPreset = document.querySelector("#mixedPreset");
518
700
  const matchedPreset = document.querySelector("#matchedPreset");
519
701
  const contrastPreset = document.querySelector("#contrastPreset");
702
+ const mobileControlsQuery = window.matchMedia("(max-width: 74.999rem)");
703
+ let previousDemoControlsFocus = null;
520
704
  const uiClassPrefixes = {
521
705
  "minimal-saas": "saas",
522
706
  bento: "bento",
@@ -568,6 +752,44 @@
568
752
  modeSelect.value = mode;
569
753
  }
570
754
 
755
+ // Mobile and tablet controls use a drawer so the sticky header stays compact.
756
+ function setDemoControlsOpen(open, { returnFocus = true } = {}) {
757
+ if (!mobileControlsQuery.matches) {
758
+ controlsToggle.setAttribute("aria-expanded", "false");
759
+ controlsDrawer.setAttribute("aria-hidden", "false");
760
+ controlsBackdrop.dataset.open = "false";
761
+ delete body.dataset.demoControlsOpen;
762
+ previousDemoControlsFocus = null;
763
+ return;
764
+ }
765
+
766
+ controlsToggle.setAttribute("aria-expanded", String(open));
767
+ controlsDrawer.setAttribute("aria-hidden", String(!open));
768
+ controlsBackdrop.dataset.open = String(open);
769
+
770
+ if (open) {
771
+ previousDemoControlsFocus = document.activeElement;
772
+ body.dataset.demoControlsOpen = "true";
773
+ controlsDrawer.querySelector("select, button, a, input")?.focus({ preventScroll: true });
774
+ return;
775
+ }
776
+
777
+ delete body.dataset.demoControlsOpen;
778
+
779
+ if (returnFocus) {
780
+ const focusTarget = previousDemoControlsFocus instanceof HTMLElement
781
+ ? previousDemoControlsFocus
782
+ : controlsToggle;
783
+ focusTarget.focus({ preventScroll: true });
784
+ }
785
+
786
+ previousDemoControlsFocus = null;
787
+ }
788
+
789
+ function syncDemoControlsMode() {
790
+ setDemoControlsOpen(false, { returnFocus: false });
791
+ }
792
+
571
793
  // Deep-linked state keeps visual regression checks and shared demos reproducible.
572
794
  const queryState = new URLSearchParams(window.location.search);
573
795
  const presetState = {
@@ -642,6 +864,36 @@
642
864
  layout: "maximalist",
643
865
  theme: "sunset-ember",
644
866
  mode: "light"
867
+ },
868
+ fPattern: {
869
+ ui: "minimal-saas",
870
+ layout: "f-pattern",
871
+ theme: "arctic-indigo",
872
+ mode: "light"
873
+ },
874
+ zPattern: {
875
+ ui: "bento",
876
+ layout: "z-pattern",
877
+ theme: "ocean-steel",
878
+ mode: "light"
879
+ },
880
+ splitScreen: {
881
+ ui: "maximalist",
882
+ layout: "split-screen",
883
+ theme: "sunset-ember",
884
+ mode: "light"
885
+ },
886
+ mondrian: {
887
+ ui: "bauhaus",
888
+ layout: "mondrian",
889
+ theme: "graphite-cyan",
890
+ mode: "contrast"
891
+ },
892
+ synthwave: {
893
+ ui: "cyberpunk",
894
+ layout: "synthwave",
895
+ theme: "cyber-lime",
896
+ mode: "dark"
645
897
  }
646
898
  };
647
899
  applyDemoState(presetState[queryState.get("preset")] || {
@@ -650,6 +902,7 @@
650
902
  theme: queryState.get("theme") || body.dataset.theme,
651
903
  mode: queryState.get("mode") || body.dataset.mode
652
904
  });
905
+ syncDemoControlsMode();
653
906
 
654
907
  uiSelect.addEventListener("change", () => {
655
908
  body.dataset.ui = uiSelect.value;
@@ -669,6 +922,26 @@
669
922
  body.dataset.mode = modeSelect.value;
670
923
  });
671
924
 
925
+ controlsToggle.addEventListener("click", () => {
926
+ setDemoControlsOpen(controlsToggle.getAttribute("aria-expanded") !== "true");
927
+ });
928
+
929
+ controlsClose.addEventListener("click", () => {
930
+ setDemoControlsOpen(false);
931
+ });
932
+
933
+ controlsBackdrop.addEventListener("click", () => {
934
+ setDemoControlsOpen(false);
935
+ });
936
+
937
+ document.addEventListener("keydown", (event) => {
938
+ if (event.key === "Escape" && controlsToggle.getAttribute("aria-expanded") === "true") {
939
+ setDemoControlsOpen(false);
940
+ }
941
+ });
942
+
943
+ mobileControlsQuery.addEventListener("change", syncDemoControlsMode);
944
+
672
945
  mixedPreset.addEventListener("click", () => {
673
946
  applyDemoState({
674
947
  ui: "cyberpunk",
@@ -676,6 +949,7 @@
676
949
  theme: "arctic-indigo",
677
950
  mode: "dark"
678
951
  });
952
+ setDemoControlsOpen(false);
679
953
  });
680
954
 
681
955
  matchedPreset.addEventListener("click", () => {
@@ -685,6 +959,7 @@
685
959
  theme: themeSelect.value,
686
960
  mode: modeSelect.value
687
961
  });
962
+ setDemoControlsOpen(false);
688
963
  });
689
964
 
690
965
  contrastPreset.addEventListener("click", () => {
@@ -694,6 +969,7 @@
694
969
  theme: "graphite-cyan",
695
970
  mode: "dark"
696
971
  });
972
+ setDemoControlsOpen(false);
697
973
  });
698
974
  </script>
699
975
  </body>
@@ -11,3 +11,8 @@
11
11
  @import url("./layout-style-cyberpunk.css");
12
12
  @import url("./layout-style-y2k.css");
13
13
  @import url("./layout-style-retro-glass.css");
14
+ @import url("./layout-style-f-pattern.css");
15
+ @import url("./layout-style-z-pattern.css");
16
+ @import url("./layout-style-split-screen.css");
17
+ @import url("./layout-style-mondrian.css");
18
+ @import url("./layout-style-synthwave.css");