@sableui/react 0.1.0 → 0.2.0

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 (61) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/dist/{_contract-CYScOdf5.d.ts → _contract-o3tUc8Ig.d.ts} +1 -1
  3. package/dist/{chunk-J23ELQQZ.js → chunk-AOWBYEQ6.js} +4177 -1917
  4. package/dist/{chunk-RWP4XBSK.js → chunk-KFZ43RKU.js} +1 -1
  5. package/dist/{chunk-JI7WJP2L.js → chunk-X276MF2W.js} +5 -0
  6. package/dist/foundations/index.js +1 -1
  7. package/dist/index.d.ts +155 -101
  8. package/dist/index.js +582 -2778
  9. package/dist/ios/index.d.ts +6 -1
  10. package/dist/ios/index.js +4 -4
  11. package/dist/ios/preview.js +1 -1
  12. package/dist/ios/styles.css +20 -6
  13. package/dist/patterns/index.js +1683 -469
  14. package/dist/presets/index.d.ts +1 -1
  15. package/dist/presets/index.js +1 -1
  16. package/dist/styles.css +238 -40
  17. package/dist/{theme-provider-BWcizhAt.d.ts → theme-provider-BE-KqUG-.d.ts} +1 -1
  18. package/dist/themes/atelier/atelier.css +3 -0
  19. package/dist/themes/atelier/index.d.ts +1 -1
  20. package/dist/themes/base/base.css +11 -4
  21. package/dist/themes/base/index.d.ts +1 -1
  22. package/dist/themes/ember/ember.css +3 -0
  23. package/dist/themes/ember/index.d.ts +1 -1
  24. package/dist/themes/index.d.ts +2 -2
  25. package/dist/themes/meridian/index.d.ts +1 -1
  26. package/dist/themes/meridian/meridian.css +10 -5
  27. package/dist/themes/poppy/index.d.ts +1 -1
  28. package/dist/themes/poppy/poppy.css +16 -0
  29. package/dist/themes/prism/index.d.ts +1 -1
  30. package/dist/themes/prism/prism.css +4 -1
  31. package/dist/themes/verdant/index.d.ts +1 -1
  32. package/dist/themes/verdant/verdant.css +7 -2
  33. package/llms/components/bubble.md +5 -5
  34. package/llms/components/checkbox-card.md +1 -1
  35. package/llms/components/context-card.md +2 -2
  36. package/llms/components/dialog.md +1 -1
  37. package/llms/components/empty-state.md +4 -4
  38. package/llms/components/entity.md +1 -1
  39. package/llms/components/fieldset.md +1 -1
  40. package/llms/components/kbd.md +18 -6
  41. package/llms/components/pill.md +1 -1
  42. package/llms/components/side-nav.md +1 -1
  43. package/llms/components/skeleton.md +1 -1
  44. package/llms/components/theme-selector.md +1 -1
  45. package/llms/foundations/shape.md +1 -1
  46. package/llms/patterns/auth-page.md +132 -42
  47. package/llms/patterns/brand-landing-page.md +271 -175
  48. package/llms/patterns/chat-panel.md +120 -39
  49. package/llms/patterns/dashboard-page.md +277 -65
  50. package/llms/patterns/feed-page.md +245 -64
  51. package/llms/patterns/landing-page.md +473 -75
  52. package/llms/patterns/list-detail-page.md +385 -68
  53. package/llms/patterns/settings-page.md +279 -67
  54. package/llms/reference/token-intent.md +4 -2
  55. package/llms/reference/utilities.md +20 -5
  56. package/llms-full.txt +2244 -727
  57. package/llms.txt +14 -15
  58. package/package.json +1 -1
  59. package/registry.json +261 -238
  60. package/targets/ios.json +4 -15
  61. package/llms/components/description.md +0 -96
@@ -1,4 +1,4 @@
1
- import { T as ThemeManifest } from '../_contract-CYScOdf5.js';
1
+ import { T as ThemeManifest } from '../_contract-o3tUc8Ig.js';
2
2
 
3
3
  /** The public theme vocabulary. Presets never need component overrides. */
4
4
  declare const PRESET_TOKEN_NAMES: readonly string[];
@@ -1,4 +1,4 @@
1
- import { SEMANTIC_TOKENS, WORKSPACE_SURFACE_TOKENS, DERIVED_EDGE_TOKENS, RADIUS_TOKENS, MOTION_TOKENS, TYPE_SCALE_TOKENS, TYPE_REFINEMENT_TOKENS, TYPE_OVERLINE_TOKENS, DENSITY_TOKENS, LAYERING_TOKENS, TYPE_UI_TOKENS } from '../chunk-JI7WJP2L.js';
1
+ import { SEMANTIC_TOKENS, WORKSPACE_SURFACE_TOKENS, DERIVED_EDGE_TOKENS, RADIUS_TOKENS, MOTION_TOKENS, TYPE_SCALE_TOKENS, TYPE_REFINEMENT_TOKENS, TYPE_OVERLINE_TOKENS, DENSITY_TOKENS, LAYERING_TOKENS, TYPE_UI_TOKENS } from '../chunk-X276MF2W.js';
2
2
 
3
3
  // src/presets/index.ts
4
4
  var PRESET_TOKEN_NAMES = [.../* @__PURE__ */ new Set([
package/dist/styles.css CHANGED
@@ -52,8 +52,8 @@
52
52
 
53
53
  /* Elevation — theme-provided so docs/app shells can express a different surface
54
54
  feel without touching component code. */
55
- --shadow-sm: var(--theme-shadow-sm, 0 1px 2px 0 rgb(0 0 0 / 0.04), 0 1px 3px 0 rgb(0 0 0 / 0.03));
56
- --shadow: var(--theme-shadow, 0 1px 2px 0 rgb(0 0 0 / 0.04), 0 2px 6px -1px rgb(0 0 0 / 0.05));
55
+ --shadow-sm: var(--theme-shadow-sm, 0 1px 2px 0 rgb(0 0 0 / 0.05));
56
+ --shadow: var(--theme-shadow, 0 1px 2px 0 rgb(0 0 0 / 0.05), 0 3px 8px -2px rgb(0 0 0 / 0.08));
57
57
  --shadow-md: var(--theme-shadow-md, 0 1px 2px 0 rgb(0 0 0 / 0.04), 0 4px 8px -2px rgb(0 0 0 / 0.06), 0 12px 24px -6px rgb(0 0 0 / 0.07));
58
58
  --shadow-lg: var(--theme-shadow-lg, 0 2px 4px 0 rgb(0 0 0 / 0.04), 0 8px 16px -4px rgb(0 0 0 / 0.07), 0 24px 48px -12px rgb(0 0 0 / 0.11));
59
59
  --shadow-xl: var(--theme-shadow-xl, 0 2px 4px 0 rgb(0 0 0 / 0.04), 0 12px 24px -6px rgb(0 0 0 / 0.08), 0 32px 64px -16px rgb(0 0 0 / 0.13));
@@ -81,6 +81,7 @@
81
81
  --color-border-strong: var(--border-strong);
82
82
  --color-border-floating: var(--border-floating);
83
83
  --color-input: var(--input);
84
+ --color-control-border: var(--control-border);
84
85
  --color-ring: var(--ring);
85
86
 
86
87
  /* Sidebar set */
@@ -160,6 +161,27 @@
160
161
  --z-skip-link: 100; /* the skip-to-content link — above all chrome */
161
162
  }
162
163
 
164
+ /* ==========================================================================
165
+ Scrim strength — how much a modal's backdrop (`bg-overlay/(--scrim-alpha)`)
166
+ dims what is behind it, per mode.
167
+
168
+ `--overlay` is near-black in every theme and mode, which is right for a
169
+ scrim. But a dark page is near-black too: Base's dark `--background` IS its
170
+ `--overlay`, so a 50% scrim over it changed nothing, and with a dialog open
171
+ the page's text stayed at nearly full strength — while foundations/surfaces
172
+ calls the scrim "the primary depth cue" for a modal. Dark mode needs more of
173
+ the same scrim to dim the lighter things (cards, text, imagery) by as much.
174
+ A token rather than a `dark:` variant, like everything else mode-dependent.
175
+ ========================================================================== */
176
+
177
+ :root,
178
+ .light {
179
+ --scrim-alpha: 50%;
180
+ }
181
+ .dark {
182
+ --scrim-alpha: 72%;
183
+ }
184
+
163
185
  /* ==========================================================================
164
186
  The page ground. Without it, `.dark` on <html> turned the ink light while the
165
187
  page stayed the browser's white, so a fresh install in dark mode was
@@ -319,41 +341,50 @@
319
341
  Typography — six tiers. Each utility bundles size + weight + line-height +
320
342
  tracking. Compose with color/margin only; never override the four paired
321
343
  properties individually. Mono uses the theme's --font-mono.
344
+
345
+ Leading is authored as a RATIO (the `--type-*-leading` hooks every theme
346
+ tunes) and rendered on the 0.25rem grid: `round(nearest, ratio × 1em,
347
+ 0.25rem)`. Ratios alone landed almost nowhere on the grid DESIGN.md
348
+ promises (15px body at 1.55 = 23.25px, a 36px h1 at 1.15 = 41.4px), so
349
+ stacked text drifted off the vertical rhythm a fraction of a pixel per
350
+ line. Rounding keeps each tier's (and each theme's) intended proportion and
351
+ snaps the result — 24px and 40px there — at any root size, because the grid
352
+ step is in rem too. The `ui-*` tier is already whole px on the grid.
322
353
  ========================================================================== */
323
354
 
324
355
  @utility text-display-4xl {
325
356
  font-family: var(--font-display, var(--font-sans));
326
357
  font-size: var(--type-display-4xl-size, clamp(4.5rem, 12vw, 12rem));
327
358
  font-weight: var(--type-display-4xl-weight, 800);
328
- line-height: var(--type-display-4xl-leading, 0.9);
359
+ line-height: round(nearest, calc(var(--type-display-4xl-leading, 0.9) * 1em), 0.25rem);
329
360
  letter-spacing: var(--type-display-4xl-tracking, -0.05em);
330
361
  }
331
362
  @utility text-display-3xl {
332
363
  font-family: var(--font-display, var(--font-sans));
333
364
  font-size: var(--type-display-3xl-size, 6rem);
334
365
  font-weight: var(--type-display-3xl-weight, 700);
335
- line-height: var(--type-display-3xl-leading, 0.95);
366
+ line-height: round(nearest, calc(var(--type-display-3xl-leading, 0.95) * 1em), 0.25rem);
336
367
  letter-spacing: var(--type-display-3xl-tracking, -0.045em);
337
368
  }
338
369
  @utility text-display-2xl {
339
370
  font-family: var(--font-display, var(--font-sans));
340
371
  font-size: var(--type-display-2xl-size, 4.5rem);
341
372
  font-weight: var(--type-display-2xl-weight, 700);
342
- line-height: var(--type-display-2xl-leading, 1);
373
+ line-height: round(nearest, calc(var(--type-display-2xl-leading, 1) * 1em), 0.25rem);
343
374
  letter-spacing: var(--type-display-2xl-tracking, -0.04em);
344
375
  }
345
376
  @utility text-display-xl {
346
377
  font-family: var(--font-display, var(--font-sans));
347
378
  font-size: var(--type-display-xl-size, 3.75rem);
348
379
  font-weight: var(--type-display-xl-weight, 700);
349
- line-height: var(--type-display-xl-leading, 1.05);
380
+ line-height: round(nearest, calc(var(--type-display-xl-leading, 1.05) * 1em), 0.25rem);
350
381
  letter-spacing: var(--type-display-xl-tracking, -0.035em);
351
382
  }
352
383
  @utility text-display-lg {
353
384
  font-family: var(--font-display, var(--font-sans));
354
385
  font-size: var(--type-display-lg-size, 3rem);
355
386
  font-weight: var(--type-display-lg-weight, 700);
356
- line-height: var(--type-display-lg-leading, 1.1);
387
+ line-height: round(nearest, calc(var(--type-display-lg-leading, 1.1) * 1em), 0.25rem);
357
388
  letter-spacing: var(--type-display-lg-tracking, -0.03em);
358
389
  }
359
390
 
@@ -361,28 +392,28 @@
361
392
  font-family: var(--font-display, var(--font-sans));
362
393
  font-size: var(--type-heading-1-size, 2.25rem);
363
394
  font-weight: var(--type-heading-weight, 600);
364
- line-height: var(--type-heading-1-leading, 1.15);
395
+ line-height: round(nearest, calc(var(--type-heading-1-leading, 1.15) * 1em), 0.25rem);
365
396
  letter-spacing: var(--type-heading-1-tracking, -0.025em);
366
397
  }
367
398
  @utility text-heading-2 {
368
399
  font-family: var(--font-display, var(--font-sans));
369
400
  font-size: var(--type-heading-2-size, 1.75rem);
370
401
  font-weight: var(--type-heading-weight, 600);
371
- line-height: var(--type-heading-2-leading, 1.2);
402
+ line-height: round(nearest, calc(var(--type-heading-2-leading, 1.2) * 1em), 0.25rem);
372
403
  letter-spacing: var(--type-heading-2-tracking, -0.02em);
373
404
  }
374
405
  @utility text-heading-3 {
375
406
  font-family: var(--font-display, var(--font-sans));
376
407
  font-size: var(--type-heading-3-size, 1.375rem);
377
408
  font-weight: var(--type-heading-weight, 600);
378
- line-height: var(--type-heading-3-leading, 1.25);
409
+ line-height: round(nearest, calc(var(--type-heading-3-leading, 1.25) * 1em), 0.25rem);
379
410
  letter-spacing: var(--type-heading-3-tracking, -0.015em);
380
411
  }
381
412
  @utility text-heading-4 {
382
413
  font-family: var(--font-display, var(--font-sans));
383
414
  font-size: var(--type-heading-4-size, 1.125rem);
384
415
  font-weight: var(--type-heading-weight, 600);
385
- line-height: var(--type-heading-4-leading, 1.3);
416
+ line-height: round(nearest, calc(var(--type-heading-4-leading, 1.3) * 1em), 0.25rem);
386
417
  letter-spacing: var(--type-heading-4-tracking, -0.01em);
387
418
  }
388
419
 
@@ -397,13 +428,13 @@
397
428
  @utility text-title-lg {
398
429
  font-size: var(--type-title-lg-size, 1rem);
399
430
  font-weight: var(--type-title-weight, 600);
400
- line-height: var(--type-title-leading, 1.4);
431
+ line-height: round(nearest, calc(var(--type-title-leading, 1.4) * 1em), 0.25rem);
401
432
  letter-spacing: var(--type-title-tracking, -0.01em);
402
433
  }
403
434
  @utility text-title-sm {
404
435
  font-size: var(--type-title-sm-size, 0.875rem);
405
436
  font-weight: var(--type-title-weight, 600);
406
- line-height: var(--type-title-leading, 1.4);
437
+ line-height: round(nearest, calc(var(--type-title-leading, 1.4) * 1em), 0.25rem);
407
438
  letter-spacing: var(--type-title-sm-tracking, -0.005em);
408
439
  }
409
440
 
@@ -422,20 +453,20 @@
422
453
  @utility text-body-lg {
423
454
  font-size: var(--type-body-lg-size, 1.0625rem);
424
455
  font-weight: var(--type-body-lg-weight, 400);
425
- line-height: var(--type-body-lg-leading, 1.6);
456
+ line-height: round(nearest, calc(var(--type-body-lg-leading, 1.6) * 1em), 0.25rem);
426
457
  letter-spacing: var(--type-body-lg-tracking, -0.005em);
427
458
  text-wrap: pretty;
428
459
  }
429
460
  @utility text-body-md {
430
461
  font-size: var(--type-body-md-size, 0.9375rem);
431
462
  font-weight: var(--type-body-md-weight, 400);
432
- line-height: var(--type-body-md-leading, 1.55);
463
+ line-height: round(nearest, calc(var(--type-body-md-leading, 1.55) * 1em), 0.25rem);
433
464
  letter-spacing: var(--type-body-md-tracking, -0.005em);
434
465
  }
435
466
  @utility text-body-sm {
436
467
  font-size: var(--type-body-sm-size, 0.8125rem);
437
468
  font-weight: var(--type-body-sm-weight, 400);
438
- line-height: var(--type-body-sm-leading, 1.5);
469
+ line-height: round(nearest, calc(var(--type-body-sm-leading, 1.5) * 1em), 0.25rem);
439
470
  letter-spacing: var(--type-body-sm-tracking, 0);
440
471
  }
441
472
  /* The dense floor of the body ramp — running text in operator consoles,
@@ -444,26 +475,104 @@
444
475
  @utility text-body-xs {
445
476
  font-size: var(--type-body-xs-size, 0.75rem);
446
477
  font-weight: var(--type-body-xs-weight, 400);
447
- line-height: var(--type-body-xs-leading, 1.5);
478
+ line-height: round(nearest, calc(var(--type-body-xs-leading, 1.5) * 1em), 0.25rem);
448
479
  letter-spacing: var(--type-body-xs-tracking, 0);
449
480
  }
450
481
 
482
+ /* ==========================================================================
483
+ Lists — typography for semantic HTML lists, not components. A list is text
484
+ with structure, so it is styled where the rest of the type is: put the class
485
+ on the native <ul>, <ol> or <dl> and keep the elements' own semantics.
486
+
487
+ - sable-list / sable-list-numbered: body type, a hanging marker in the muted
488
+ ink (the marker is punctuation, not content), and the same rhythm between
489
+ items as between a stacked label and its control.
490
+ - sable-list-dl: label/value pairs on a two-column grid — muted label tier
491
+ for the <dt>, body tier for the <dd>, aligned on the baseline. A long
492
+ unbroken value (an address, a hash, a URL) wraps inside its column rather
493
+ than widening the grid. Colour a status value with a text-* utility on the
494
+ <dd> (text-success, text-destructive…).
495
+ - sable-list-dl-2: two pairs a row once the nearest @container ancestor is
496
+ at least 28rem wide — the room the list actually has, not the viewport, so
497
+ it does not overflow a narrow card on a wide screen.
498
+ Compact density retunes all of them with the rest of the type (see the
499
+ [data-density="compact"] block).
500
+ ========================================================================== */
501
+ @utility sable-list {
502
+ list-style: disc;
503
+ padding-inline-start: 1.25em;
504
+ font-size: var(--type-body-md-size, 0.9375rem);
505
+ line-height: round(nearest, calc(var(--type-body-md-leading, 1.55) * 1em), 0.25rem);
506
+ color: var(--foreground);
507
+ & > li + li {
508
+ margin-block-start: --spacing(1.5);
509
+ }
510
+ & > li::marker {
511
+ color: var(--muted-foreground);
512
+ }
513
+ }
514
+ @utility sable-list-numbered {
515
+ list-style: decimal;
516
+ padding-inline-start: 1.5em;
517
+ font-size: var(--type-body-md-size, 0.9375rem);
518
+ line-height: round(nearest, calc(var(--type-body-md-leading, 1.55) * 1em), 0.25rem);
519
+ color: var(--foreground);
520
+ & > li + li {
521
+ margin-block-start: --spacing(1.5);
522
+ }
523
+ & > li::marker {
524
+ color: var(--muted-foreground);
525
+ font-variant-numeric: tabular-nums;
526
+ }
527
+ }
528
+ @utility sable-list-dl {
529
+ display: grid;
530
+ grid-template-columns: max-content minmax(0, 1fr);
531
+ align-items: baseline;
532
+ column-gap: --spacing(6);
533
+ row-gap: --spacing(3);
534
+ /* The values' type and ink live on the list and the <dd>s inherit them, so a
535
+ text-* utility on a <dd> (text-success, text-mono-md) simply wins. The term
536
+ and the wrapping rules sit in :where(), which adds no specificity. */
537
+ font-size: var(--type-body-md-size, 0.9375rem);
538
+ line-height: round(nearest, calc(var(--type-body-md-leading, 1.55) * 1em), 0.25rem);
539
+ letter-spacing: var(--type-body-md-tracking, -0.005em);
540
+ color: var(--foreground);
541
+ & > :where(dt) {
542
+ font-size: var(--type-label-md-size, 0.75rem);
543
+ font-weight: var(--type-label-md-weight, 600);
544
+ line-height: round(nearest, calc(var(--type-label-md-leading, 1.2) * 1em), 0.25rem);
545
+ letter-spacing: var(--type-label-md-tracking, 0);
546
+ color: var(--muted-foreground);
547
+ }
548
+ & > :where(dd) {
549
+ margin: 0;
550
+ min-width: 0;
551
+ overflow-wrap: break-word;
552
+ }
553
+ }
554
+ @utility sable-list-dl-2 {
555
+ @container (min-width: 28rem) {
556
+ grid-template-columns: max-content minmax(0, 1fr) max-content minmax(0, 1fr);
557
+ }
558
+ }
559
+
451
560
  @utility text-label-lg {
452
561
  font-size: var(--type-label-lg-size, 0.875rem);
453
562
  font-weight: var(--type-label-lg-weight, 600);
454
- line-height: var(--type-label-lg-leading, 1.25);
563
+ line-height: round(nearest, calc(var(--type-label-lg-leading, 1.25) * 1em), 0.25rem);
455
564
  letter-spacing: var(--type-label-lg-tracking, -0.005em);
456
565
  }
457
566
  @utility text-label-md {
458
567
  font-size: var(--type-label-md-size, 0.75rem);
459
568
  font-weight: var(--type-label-md-weight, 600);
460
- line-height: var(--type-label-md-leading, 1.2);
569
+ line-height: round(nearest, calc(var(--type-label-md-leading, 1.2) * 1em), 0.25rem);
461
570
  letter-spacing: var(--type-label-md-tracking, 0);
462
571
  }
463
572
  @utility text-label-sm {
464
573
  font-size: var(--type-label-sm-size, 0.6875rem);
465
574
  font-weight: var(--type-label-sm-weight, 600);
466
- line-height: var(--type-label-sm-leading, 1.2);
575
+ line-height: round(nearest, calc(var(--type-label-sm-leading, 1.2) * 1em), 0.25rem);
467
576
  letter-spacing: var(--type-label-sm-tracking, 0);
468
577
  }
469
578
  /* Sentence case like every other label (UI text is sentence case). The
@@ -473,14 +582,14 @@
473
582
  @utility text-label-xs {
474
583
  font-size: var(--type-label-xs-size, 0.6875rem);
475
584
  font-weight: var(--type-label-xs-weight, 600);
476
- line-height: var(--type-label-xs-leading, 1.2);
585
+ line-height: round(nearest, calc(var(--type-label-xs-leading, 1.2) * 1em), 0.25rem);
477
586
  letter-spacing: var(--type-label-xs-tracking, 0.01em);
478
587
  text-transform: var(--type-label-xs-transform, none);
479
588
  }
480
589
  @utility text-caption {
481
590
  font-size: var(--type-caption-size, 0.75rem);
482
591
  font-weight: var(--type-caption-weight, 400);
483
- line-height: var(--type-caption-leading, 1.4);
592
+ line-height: round(nearest, calc(var(--type-caption-leading, 1.4) * 1em), 0.25rem);
484
593
  letter-spacing: var(--type-caption-tracking, 0);
485
594
  }
486
595
 
@@ -491,7 +600,7 @@
491
600
  @utility text-overline {
492
601
  font-size: var(--type-overline-size, 0.75rem);
493
602
  font-weight: var(--type-overline-weight, 600);
494
- line-height: var(--type-overline-leading, 1.2);
603
+ line-height: round(nearest, calc(var(--type-overline-leading, 1.2) * 1em), 0.25rem);
495
604
  letter-spacing: var(--type-overline-tracking, 0.08em);
496
605
  text-transform: var(--type-overline-transform, uppercase);
497
606
  }
@@ -503,7 +612,7 @@
503
612
  font-family: var(--font-mono);
504
613
  font-size: var(--type-mono-xl-size, 1.75rem);
505
614
  font-weight: var(--type-mono-xl-weight, 500);
506
- line-height: var(--type-mono-xl-leading, 1.15);
615
+ line-height: round(nearest, calc(var(--type-mono-xl-leading, 1.15) * 1em), 0.25rem);
507
616
  letter-spacing: var(--type-mono-xl-tracking, -0.01em);
508
617
  font-variant-numeric: tabular-nums;
509
618
  }
@@ -511,7 +620,7 @@
511
620
  font-family: var(--font-mono);
512
621
  font-size: var(--type-mono-lg-size, 1.25rem);
513
622
  font-weight: var(--type-mono-lg-weight, 500);
514
- line-height: var(--type-mono-lg-leading, 1.25);
623
+ line-height: round(nearest, calc(var(--type-mono-lg-leading, 1.25) * 1em), 0.25rem);
515
624
  letter-spacing: var(--type-mono-lg-tracking, 0);
516
625
  font-variant-numeric: tabular-nums;
517
626
  }
@@ -519,7 +628,7 @@
519
628
  font-family: var(--font-mono);
520
629
  font-size: var(--type-mono-md-size, 0.8125rem);
521
630
  font-weight: var(--type-mono-md-weight, 400);
522
- line-height: var(--type-mono-md-leading, 1.5);
631
+ line-height: round(nearest, calc(var(--type-mono-md-leading, 1.5) * 1em), 0.25rem);
523
632
  letter-spacing: var(--type-mono-md-tracking, 0);
524
633
  font-variant-numeric: tabular-nums;
525
634
  }
@@ -530,7 +639,7 @@
530
639
  font-family: var(--font-mono);
531
640
  font-size: var(--type-mono-caption-size, 0.75rem);
532
641
  font-weight: var(--type-mono-caption-weight, 400);
533
- line-height: var(--type-mono-caption-leading, 1.4);
642
+ line-height: round(nearest, calc(var(--type-mono-caption-leading, 1.4) * 1em), 0.25rem);
534
643
  letter-spacing: var(--type-mono-caption-tracking, 0);
535
644
  font-variant-numeric: tabular-nums;
536
645
  }
@@ -538,7 +647,7 @@
538
647
  font-family: var(--font-mono);
539
648
  font-size: var(--type-mono-sm-size, 0.6875rem);
540
649
  font-weight: var(--type-mono-sm-weight, 500);
541
- line-height: var(--type-mono-sm-leading, 1.2);
650
+ line-height: round(nearest, calc(var(--type-mono-sm-leading, 1.2) * 1em), 0.25rem);
542
651
  letter-spacing: var(--type-mono-sm-tracking, 0.02em);
543
652
  font-variant-numeric: tabular-nums;
544
653
  }
@@ -736,13 +845,16 @@
736
845
  concentrically at every corner setting (Menu, Select, Combobox, ContextMenu). The inset grows with the radius: a rounder popup needs more
737
846
  room, or its rows' corners approach half their height and every row turns
738
847
  into a pill. The row radius is what is left. At the default ladder (md 12px)
739
- this is exactly the old 4px inset and 8px rows. Utilities rather than :root
740
- tokens so the math runs on the element, inside whatever preset it sits in. */
848
+ this is a 4px inset and 7px rows: the popup's 1px border is part of the
849
+ distance from the outer curve, so it comes off the radius too (sable-frame
850
+ already subtracts it; this used to be the one formula that did not).
851
+ Utilities rather than :root tokens so the math runs on the element, inside
852
+ whatever preset it sits in. */
741
853
  @utility popup-inset {
742
854
  padding: max(--spacing(1), calc(var(--radius-md) / 3));
743
855
  }
744
856
  @utility rounded-popup-item {
745
- border-radius: max(0px, calc(var(--radius-md) - max(--spacing(1), calc(var(--radius-md) / 3))));
857
+ border-radius: max(0px, calc(var(--radius-md) - max(--spacing(1), calc(var(--radius-md) / 3)) - 1px));
746
858
  }
747
859
  /* A rule (separator) that runs edge to edge through the popup padding. It
748
860
  bleeds by exactly popup-inset, so it reaches both edges at every radius; a
@@ -771,11 +883,40 @@
771
883
  border: var(--sable-frame-border-width) solid var(--sable-frame-edge);
772
884
  border-radius: var(--sable-frame-radius);
773
885
  }
886
+ /* The same geometry and elevation as the Menu / Select / Combobox popups, so a
887
+ list hosted in a frame floats beside a menu as its equal: popup-inset's
888
+ padding (it grows with the radius) and shadow-md, the floating-surface step
889
+ (shadow-lg is for surfaces with a scrim — foundations/surfaces). */
774
890
  @utility sable-frame-popover {
775
891
  --sable-frame-radius: var(--radius-md);
776
- --sable-frame-padding: --spacing(1);
892
+ --sable-frame-padding: max(--spacing(1), calc(var(--radius-md) / 3));
777
893
  --sable-frame-edge: var(--border-floating);
778
- box-shadow: var(--shadow-lg);
894
+ box-shadow: var(--shadow-md);
895
+ }
896
+ /* A frame around edge-to-edge tool chrome — panel sections, a tree, a status
897
+ bar — at the theme's own radius. It publishes the geometry its contents need
898
+ to stay concentric with it, the way Card does with --card-inner-radius and
899
+ popups with popup-inset:
900
+ - --panel-field-radius: a compact field's corner. It aims for the theme's small
901
+ radius but no more than a quarter of the field's height (a rounder preset
902
+ would otherwise turn 24px fields into pills), and is then whatever keeps it
903
+ parallel to the frame's curve.
904
+ - --panel-inset: the rows' side padding, frame radius less that field radius,
905
+ never under the 8px a tool row always has. A rounder preset gets more room
906
+ instead of crowding its first label and last field into the corners.
907
+ - --panel-edge: the extra the first and last section take top and bottom, so
908
+ the vertical edge breathes by the same amount.
909
+ Unframed — a square Workspace column — none of these are set, and panels fall
910
+ back to the 8px inset and the field shell's own radius. Custom properties only,
911
+ like every sable-frame-* modifier: a real property would sort this rule ahead of
912
+ .sable-frame and lose to it. Clip with overflow-hidden on the element. */
913
+ @utility sable-frame-tool {
914
+ --sable-frame-radius: var(--radius-lg);
915
+ --sable-frame-padding: 0px;
916
+ --panel-field-target: min(var(--radius-sm), calc(var(--control-xs) / 4));
917
+ --panel-inset: max(--spacing(2), calc(var(--sable-frame-radius) - var(--panel-field-target)));
918
+ --panel-field-radius: max(0px, calc(var(--sable-frame-radius) - var(--panel-inset)));
919
+ --panel-edge: calc(var(--panel-inset) - --spacing(2));
779
920
  }
780
921
  @utility sable-frame-borderless {
781
922
  --sable-frame-border-width: 0px;
@@ -790,13 +931,17 @@
790
931
  @utility sable-frame-inner {
791
932
  border-radius: var(--sable-frame-inner-radius, var(--radius-sm));
792
933
  }
934
+ /* Floored at radius-xs, not zero: an inset at or past the outer radius left a
935
+ 1-2px sliver (the docs' composer measured 2px, Toast's close 1.5px) that is
936
+ neither square nor round and reads as a mistake. A square theme's xs is 0,
937
+ so it still goes square. */
793
938
  @utility rounded-concentric-* {
794
939
  border-radius: max(
795
- 0px,
940
+ var(--radius-xs),
796
941
  calc(--value(--radius-*, [*]) - --modifier(--spacing-*, [*]))
797
942
  );
798
943
  border-radius: max(
799
- 0px,
944
+ var(--radius-xs),
800
945
  calc(--value(--radius-*, [*]) - --spacing(--modifier(number)))
801
946
  );
802
947
  }
@@ -1154,6 +1299,17 @@
1154
1299
  font-weight: var(--type-ui-md-weight, 500);
1155
1300
  line-height: var(--type-ui-leading, 16px);
1156
1301
  }
1302
+ /* The list utilities carry their own type, so they follow the same tiers:
1303
+ items and values as body-md, terms as label-md. */
1304
+ & :is(.sable-list, .sable-list-numbered, .sable-list-dl) {
1305
+ font-size: min(0.9375rem, var(--type-ui-md-size, 12px));
1306
+ line-height: var(--type-ui-leading, 16px);
1307
+ }
1308
+ & .sable-list-dl > :where(dt) {
1309
+ font-size: min(0.75rem, var(--type-ui-md-size, 12px));
1310
+ font-weight: var(--type-ui-md-weight, 500);
1311
+ line-height: var(--type-ui-leading, 16px);
1312
+ }
1157
1313
  & .text-label-sm,
1158
1314
  & .text-label-xs {
1159
1315
  font-size: min(0.6875rem, var(--type-ui-micro-size, 10px));
@@ -1340,6 +1496,20 @@
1340
1496
  background-position: -200% 0;
1341
1497
  }
1342
1498
  }
1499
+ /* The skeleton sweep. One pass eases in, glides and settles (no constant-speed
1500
+ conveyor), then the band waits off-screen for the last 30% before the next.
1501
+ The resting position — the from/to — is off-screen right, so a frozen
1502
+ animation (reduced motion) leaves a plain block, not a stuck highlight. */
1503
+ @keyframes sable-sweep {
1504
+ 0% {
1505
+ background-position: 100% 0;
1506
+ animation-timing-function: cubic-bezier(0.55, 0, 0.2, 1);
1507
+ }
1508
+ 70%,
1509
+ 100% {
1510
+ background-position: 0% 0;
1511
+ }
1512
+ }
1343
1513
  @keyframes sable-pulse-soft {
1344
1514
  0%,
1345
1515
  100% {
@@ -1681,16 +1851,44 @@
1681
1851
  animation: sable-pulse-soft calc(1600ms * var(--motion-scale))
1682
1852
  var(--motion-ease-standard) infinite;
1683
1853
  }
1854
+ /*
1855
+ * The skeleton sweep: ONE band of light passing through a whole loading layout,
1856
+ * not a separate flash per block.
1857
+ *
1858
+ * - `background-attachment: fixed` lays the gradient against the viewport, so
1859
+ * every skeleton on screen is a window onto the same band. A text line, an
1860
+ * avatar and a card below it light up in sequence, a single wave, instead of
1861
+ * each box sweeping at its own speed (a 40px line and a 600px card used to
1862
+ * race each other). iOS Safari ignores fixed backgrounds and falls back to a
1863
+ * per-box sweep, which is the old behaviour, not a broken one.
1864
+ * - The image is two viewports plus 600px wide with the band at its centre, so
1865
+ * from 100% to 0% the band travels from 300px off the left edge to 300px off
1866
+ * the right, and its width (360px, feathered over five stops) holds at any
1867
+ * screen size rather than scaling with the box.
1868
+ * - The band is light catching the block, not a shadow crossing it: the skeleton's
1869
+ * own muted fill, a few lightness steps up, so it is a sheen in light AND dark
1870
+ * mode with no per-theme value (mixing in the foreground darkened it in light).
1871
+ * - The base position is the resting one, off-screen: under --motion-scale 0
1872
+ * the skeleton is a calm block.
1873
+ *
1874
+ * Background-position is painted, not composited, unlike most recipes here. It
1875
+ * buys the coherent wave, which a per-element transform cannot, and skeletons
1876
+ * are small and short-lived.
1877
+ */
1684
1878
  @utility motion-shimmer {
1685
1879
  background-image: linear-gradient(
1686
1880
  100deg,
1687
- transparent 40%,
1688
- color-mix(in oklab, var(--foreground) 8%, transparent) 50%,
1689
- transparent 60%
1881
+ transparent calc(50% - 180px),
1882
+ oklch(from var(--muted) calc(l + 0.02) c h / 0.6) calc(50% - 90px),
1883
+ oklch(from var(--muted) calc(l + 0.055) c h / 0.9) 50%,
1884
+ oklch(from var(--muted) calc(l + 0.02) c h / 0.6) calc(50% + 90px),
1885
+ transparent calc(50% + 180px)
1690
1886
  );
1691
- background-size: 200% 100%;
1887
+ background-size: calc(200% + 600px) 100%;
1692
1888
  background-repeat: no-repeat;
1693
- animation: sable-shimmer calc(1800ms * var(--motion-scale)) linear infinite;
1889
+ background-attachment: fixed;
1890
+ background-position: 0% 0;
1891
+ animation: sable-sweep calc(2400ms * var(--motion-scale)) infinite;
1694
1892
  }
1695
1893
  /*
1696
1894
  * The same sweep, but through the glyphs instead of behind them — for live
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
- import { T as ThemeManifest } from './_contract-CYScOdf5.js';
3
+ import { T as ThemeManifest } from './_contract-o3tUc8Ig.js';
4
4
 
5
5
  declare const SABLE_THEME_ATTRIBUTE: "data-sable-theme";
6
6
  declare const DEFAULT_THEME_ID: string;
@@ -100,6 +100,8 @@
100
100
  --border: oklch(92% 0 0);
101
101
  --border-strong: oklch(85% 0 0);
102
102
  --input: oklch(92% 0 0);
103
+ /* The resting edge of a control whose outline IS the control (checkbox, radio, an off switch track). Held to WCAG 1.4.11 3:1 on every surface, unlike the quieter --input field outline. */
104
+ --control-border: oklch(62.3% 0 0);
103
105
  --ring: #000000;
104
106
  --primary: #000000;
105
107
  --primary-foreground: #ffffff;
@@ -177,6 +179,7 @@
177
179
  --border: oklch(29% 0 0);
178
180
  --border-strong: oklch(36% 0 0);
179
181
  --input: oklch(29% 0 0);
182
+ --control-border: oklch(54.9% 0 0);
180
183
  --ring: #ffffff;
181
184
  --primary: #ffffff;
182
185
  --primary-foreground: #000000;
@@ -1,4 +1,4 @@
1
- import { T as ThemeManifest } from '../../_contract-CYScOdf5.js';
1
+ import { T as ThemeManifest } from '../../_contract-o3tUc8Ig.js';
2
2
 
3
3
  /**
4
4
  * Mono Editorial — a Sable theme. Concrete token values live in
@@ -31,8 +31,10 @@
31
31
  /* Elevation, light. Layered: a tight contact shadow plus one or two soft drops
32
32
  whose offsets roughly double per step. A single 5% blur read mushy and
33
33
  barely separated a menu from the page (DESIGN.md → Elevation). */
34
- --theme-shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.04), 0 1px 3px 0 rgb(0 0 0 / 0.03);
35
- --theme-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.04), 0 2px 6px -1px rgb(0 0 0 / 0.05);
34
+ --theme-shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
35
+ /* A visible step above sm: sm and this differed by one 5% layer, which no
36
+ one could tell apart. */
37
+ --theme-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05), 0 3px 8px -2px rgb(0 0 0 / 0.08);
36
38
  --theme-shadow-md: 0 1px 2px 0 rgb(0 0 0 / 0.04), 0 4px 8px -2px rgb(0 0 0 / 0.06), 0 12px 24px -6px rgb(0 0 0 / 0.07);
37
39
  --theme-shadow-lg: 0 2px 4px 0 rgb(0 0 0 / 0.04), 0 8px 16px -4px rgb(0 0 0 / 0.07), 0 24px 48px -12px rgb(0 0 0 / 0.11);
38
40
  --theme-shadow-xl: 0 2px 4px 0 rgb(0 0 0 / 0.04), 0 12px 24px -6px rgb(0 0 0 / 0.08), 0 32px 64px -16px rgb(0 0 0 / 0.13);
@@ -239,6 +241,8 @@
239
241
  step on the same neutral ramp as --border. */
240
242
  --border-strong: var(--zinc-300);
241
243
  --input: var(--zinc-200);
244
+ /* The resting edge of a control whose outline IS the control (checkbox, radio, an off switch track). Held to WCAG 1.4.11 3:1 on every surface, unlike the quieter --input field outline. */
245
+ --control-border: var(--zinc-500);
242
246
  --ring: var(--zinc-500);
243
247
 
244
248
  /* Tones — light (all clear WCAG AA on white) */
@@ -375,7 +379,7 @@
375
379
  catches "light" on anything floating. Deeper drops than light mode, since
376
380
  black on near-black needs more alpha to read at all. */
377
381
  --theme-shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.3);
378
- --theme-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.3), 0 2px 6px -1px rgb(0 0 0 / 0.25);
382
+ --theme-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.3), 0 4px 10px -2px rgb(0 0 0 / 0.4);
379
383
  --theme-shadow-md: inset 0 1px 0 0 rgb(255 255 255 / 0.04), 0 1px 2px 0 rgb(0 0 0 / 0.3), 0 8px 20px -6px rgb(0 0 0 / 0.45);
380
384
  --theme-shadow-lg: inset 0 1px 0 0 rgb(255 255 255 / 0.05), 0 2px 4px 0 rgb(0 0 0 / 0.3), 0 20px 40px -12px rgb(0 0 0 / 0.55);
381
385
  --theme-shadow-xl: inset 0 1px 0 0 rgb(255 255 255 / 0.05), 0 2px 4px 0 rgb(0 0 0 / 0.3), 0 28px 56px -16px rgb(0 0 0 / 0.6);
@@ -409,6 +413,7 @@
409
413
  --border: oklch(from var(--zinc-700) l c h / 0.4);
410
414
  --border-strong: oklch(from var(--zinc-500) l c h / 0.55);
411
415
  --input: oklch(from var(--zinc-700) l c h / 0.4);
416
+ --control-border: var(--zinc-500);
412
417
  --ring: var(--zinc-500);
413
418
 
414
419
  /* Tones — dark-tuned (boosted chroma for vibrancy on the dark canvas) */
@@ -438,6 +443,8 @@
438
443
  --sidebar-primary-foreground: var(--zinc-950);
439
444
  --sidebar-accent: var(--zinc-800);
440
445
  --sidebar-accent-foreground: var(--zinc-50);
441
- --sidebar-border: var(--zinc-900);
446
+ /* zinc-800, not zinc-900: on the zinc-950 sidebar zinc-900 measured 1.16:1,
447
+ fainter than the page's own border. */
448
+ --sidebar-border: var(--zinc-800);
442
449
  --sidebar-ring: var(--zinc-500);
443
450
  }
@@ -1,4 +1,4 @@
1
- import { T as ThemeManifest } from '../../_contract-CYScOdf5.js';
1
+ import { T as ThemeManifest } from '../../_contract-o3tUc8Ig.js';
2
2
 
3
3
  /**
4
4
  * Base — the default Sable theme. Concrete token values live in
@@ -156,6 +156,8 @@
156
156
  --border: oklch(88% 0.008 74);
157
157
  --border-strong: oklch(82% 0.010 73);
158
158
  --input: oklch(85% 0.009 74);
159
+ /* The resting edge of a control whose outline IS the control (checkbox, radio, an off switch track). Held to WCAG 1.4.11 3:1 on every surface, unlike the quieter --input field outline. */
160
+ --control-border: oklch(60.2% 0.0095 70);
159
161
  --ring: oklch(58% 0.245 32.9);
160
162
  --primary: oklch(58% 0.245 32.9);
161
163
  --primary-foreground: oklch(100% 0 0);
@@ -234,6 +236,7 @@
234
236
  --border: oklch(32% 0.012 67.2); /* lifted with the fills: a hairline must still show on muted */
235
237
  --border-strong: oklch(37% 0.010 61.1);
236
238
  --input: oklch(33% 0.012 65);
239
+ --control-border: oklch(55.6% 0.0084 67.7);
237
240
  --ring: oklch(65.2% 0.235 32.9);
238
241
  --primary: oklch(65.2% 0.235 32.9);
239
242
  --primary-foreground: oklch(14.1% 0.018 70.5);
@@ -1,4 +1,4 @@
1
- import { T as ThemeManifest } from '../../_contract-CYScOdf5.js';
1
+ import { T as ThemeManifest } from '../../_contract-o3tUc8Ig.js';
2
2
 
3
3
  /**
4
4
  * Ember — a Sable theme. Concrete token values live in
@@ -1,4 +1,4 @@
1
- export { A as AnyThemeId, D as DEFAULT_THEME_ID, S as SABLE_COLOR_STORAGE_KEY, a as SABLE_THEME_ATTRIBUTE, b as SABLE_THEME_STORAGE_KEY, c as SableColorMode, d as SableThemeContextValue, e as SableThemePreference, f as SableThemeProvider, g as SableThemeProviderProps, T as ThemeId, h as applySableColorMode, i as applySableTheme, j as buildThemeManifestById, k as defaultThemeId, l as featuredThemeManifests, m as getThemeManifest, n as isKnownThemeId, o as isThemeId, t as themeIds, p as themeManifestById, q as themeManifests, u as useSableTheme } from '../theme-provider-BWcizhAt.js';
1
+ export { A as AnyThemeId, D as DEFAULT_THEME_ID, S as SABLE_COLOR_STORAGE_KEY, a as SABLE_THEME_ATTRIBUTE, b as SABLE_THEME_STORAGE_KEY, c as SableColorMode, d as SableThemeContextValue, e as SableThemePreference, f as SableThemeProvider, g as SableThemeProviderProps, T as ThemeId, h as applySableColorMode, i as applySableTheme, j as buildThemeManifestById, k as defaultThemeId, l as featuredThemeManifests, m as getThemeManifest, n as isKnownThemeId, o as isThemeId, t as themeIds, p as themeManifestById, q as themeManifests, u as useSableTheme } from '../theme-provider-BE-KqUG-.js';
2
2
  export { atelierTheme } from './atelier/index.js';
3
3
  export { baseTheme } from './base/index.js';
4
4
  export { default as emberTheme } from './ember/index.js';
@@ -7,4 +7,4 @@ export { default as poppyTheme } from './poppy/index.js';
7
7
  export { default as prismTheme } from './prism/index.js';
8
8
  export { default as verdantTheme } from './verdant/index.js';
9
9
  import 'react';
10
- import '../_contract-CYScOdf5.js';
10
+ import '../_contract-o3tUc8Ig.js';