@godxjp/ui 18.9.0 → 18.10.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 (85) hide show
  1. package/LICENSE +202 -0
  2. package/dist/components/data-display/badge.d.ts +7 -0
  3. package/dist/components/data-display/badge.js +1 -1
  4. package/dist/components/data-display/card.d.ts +3 -27
  5. package/dist/components/data-display/card.js +1 -4
  6. package/dist/components/data-display/data-table.js +5 -4
  7. package/dist/components/data-display/index.d.ts +2 -0
  8. package/dist/components/data-display/index.js +2 -0
  9. package/dist/components/data-display/permission-matrix.d.ts +26 -0
  10. package/dist/components/data-display/permission-matrix.js +219 -0
  11. package/dist/components/data-display/table.d.ts +12 -0
  12. package/dist/components/data-entry/branch-scope-picker.d.ts +43 -0
  13. package/dist/components/data-entry/branch-scope-picker.js +200 -0
  14. package/dist/components/data-entry/command-palette.d.ts +1 -42
  15. package/dist/components/data-entry/command-palette.js +2 -31
  16. package/dist/components/data-entry/index.d.ts +2 -0
  17. package/dist/components/data-entry/index.js +2 -0
  18. package/dist/components/data-entry/input-otp.d.ts +1 -1
  19. package/dist/components/feedback/alert.d.ts +2 -20
  20. package/dist/components/feedback/alert.js +1 -11
  21. package/dist/components/feedback/banner.d.ts +21 -0
  22. package/dist/components/feedback/banner.js +15 -0
  23. package/dist/components/feedback/index.d.ts +4 -2
  24. package/dist/components/feedback/index.js +2 -2
  25. package/dist/components/general/typography.d.ts +1 -0
  26. package/dist/components/general/typography.js +32 -13
  27. package/dist/components/layout/auth-shell.d.ts +2 -2
  28. package/dist/components/layout/index.d.ts +2 -2
  29. package/dist/components/layout/index.js +2 -2
  30. package/dist/components/layout/page-container.d.ts +1 -1
  31. package/dist/components/layout/page-container.js +45 -19
  32. package/dist/components/layout/service-role-panel.d.ts +25 -0
  33. package/dist/components/layout/service-role-panel.js +206 -0
  34. package/dist/components/navigation/filter-bar.d.ts +2 -2
  35. package/dist/components/navigation/filter-bar.js +113 -34
  36. package/dist/components/navigation/index.d.ts +1 -1
  37. package/dist/components/navigation/steps.d.ts +2 -2
  38. package/dist/components/navigation/steps.js +2 -4
  39. package/dist/components/ui/avatar.d.ts +1 -1
  40. package/dist/components/ui/avatar.js +1 -2
  41. package/dist/components/ui/input-otp.d.ts +3 -15
  42. package/dist/components/ui/input-otp.js +1 -2
  43. package/dist/email/tokens.generated.d.ts +2 -2
  44. package/dist/email/tokens.generated.js +2 -2
  45. package/dist/i18n/messages/en.json +56 -4
  46. package/dist/i18n/messages/ja.json +51 -5
  47. package/dist/i18n/messages/vi.json +50 -4
  48. package/dist/props/components/data-display.prop.d.ts +66 -16
  49. package/dist/props/components/data-entry.prop.d.ts +54 -7
  50. package/dist/props/components/feedback.prop.d.ts +3 -3
  51. package/dist/props/components/general.prop.d.ts +8 -1
  52. package/dist/props/components/layout.prop.d.ts +75 -54
  53. package/dist/props/components/navigation.prop.d.ts +77 -59
  54. package/dist/props/registry.d.ts +274 -73
  55. package/dist/props/registry.js +362 -93
  56. package/dist/props/vocabulary/content.prop.d.ts +5 -0
  57. package/dist/props/vocabulary/index.d.ts +1 -1
  58. package/dist/props/vocabulary/interaction.prop.d.ts +4 -7
  59. package/dist/props/vocabulary/layout.prop.d.ts +2 -2
  60. package/dist/styles/alert-layout.css +15 -32
  61. package/dist/styles/badge-layout.css +5 -0
  62. package/dist/styles/base.css +0 -28
  63. package/dist/styles/card-layout.css +13 -49
  64. package/dist/styles/control.css +2 -12
  65. package/dist/styles/data-display-layout.css +0 -16
  66. package/dist/styles/layout.css +102 -108
  67. package/dist/styles/navigation-layout.css +3 -8
  68. package/dist/styles/shell-layout.css +17 -17
  69. package/dist/styles/table-layout.css +77 -29
  70. package/dist/styles/text-layout.css +13 -0
  71. package/dist/tokens/base.css +1 -0
  72. package/dist/tokens/components/badge.css +5 -0
  73. package/dist/tokens/components/banner.css +16 -0
  74. package/dist/tokens/components/card.css +0 -12
  75. package/dist/tokens/components/control.css +0 -16
  76. package/dist/tokens/components/data-display.css +0 -12
  77. package/dist/tokens/components/email.css +2 -8
  78. package/dist/tokens/components/feedback.css +0 -20
  79. package/dist/tokens/components/navigation.css +10 -34
  80. package/dist/tokens/components/shell.css +24 -36
  81. package/dist/tokens/components/table.css +41 -22
  82. package/dist/tokens/semantic/layout.css +5 -12
  83. package/package.json +15 -2
  84. package/dist/components/layout/page-header.d.ts +0 -22
  85. package/dist/components/layout/page-header.js +0 -89
@@ -284,8 +284,23 @@
284
284
 
285
285
  .ui-table-collection :is([data-slot="table-head"], [data-slot="table-cell"]) {
286
286
  /* The column measure comes from `priority`; an unmarked column takes what is left (`auto`),
287
- * which is the free-text column. */
288
- inline-size: var(--table-action-collection-column-width, auto);
287
+ * which is the free-text column — EXCEPT past the seven-column budget below the collapse
288
+ * step, where the `:has()` tier re-points the middle fallback at the flex floor (gh#262):
289
+ * the fixed algorithm hands an auto column 0px once the marked columns over-constrain the
290
+ * table, which is the one-character-per-line shredding this preset must never produce.
291
+ * There every column carries a rem floor-measure; once the floors outgrow the container the
292
+ * table's used width grows past its specified 100% (CSS 2.1 §17.5.2.1) and the DIRECT
293
+ * wrapper's keyboard-reachable overflow-x region scrolls — the SC 1.4.10-permitted
294
+ * one-dimensional scroll, instead of unreadable shredding (see tokens/components/table.css). */
295
+ inline-size: var(
296
+ --table-action-collection-column-width,
297
+ var(--table-action-collection-flex-width, auto)
298
+ );
299
+ /* Wrapping guard, considered for gh#262: this stays `overflow-wrap: anywhere`, NOT
300
+ * `word-break: keep-all`. Under `table-layout: fixed` a column cannot grow to fit an
301
+ * unbreakable CJK run, so keep-all would overflow/clip a long JA header instead of widening
302
+ * its column. With the floors guaranteeing a ~5-glyph measure, a wrapped JA header is two
303
+ * readable lines — never a vertical character column — and losing no text beats clipping. */
289
304
  overflow-wrap: anywhere;
290
305
  white-space: normal;
291
306
  vertical-align: top;
@@ -307,18 +322,7 @@
307
322
  --table-action-collection-column-width: var(--table-action-collection-actions-width);
308
323
  text-align: end;
309
324
  }
310
- }
311
325
 
312
- /* The compact tier lives in `godxjp-ui-responsive` — the LAST layer, declared after Tailwind in
313
- * styles/base.css — not in `@layer components`. `<table>` carries `text-sm`, a Tailwind utility,
314
- * and `utilities` outranks `components` by LAYER ORDER, so a `font-size:` re-point written here as
315
- * a component rule can never apply however specific it is: that is exactly why
316
- * `--table-action-collection-font-size-compact` was dead at every width (gh#412), leaving the
317
- * narrow frame at 14px where a 5–6 character Japanese label overflows its column measure. The
318
- * column measures move with it so the whole compact tier is decided in ONE place, and so a
319
- * consumer utility on the table can't half-collapse it either. See styles/base.css · THE LAYER
320
- * CONTRACT. */
321
- @layer godxjp-ui-responsive {
322
326
  /* Below the step the SOURCE measures are re-pointed to their compact tier (and the type / row
323
327
  * density with them); nothing else moves. One block per canonical step — a media/container
324
328
  * query cannot read a `var()`, so the tokenized scale is written out (sm 40rem · md 48rem ·
@@ -335,10 +339,6 @@
335
339
  --table-cell-space-x: var(--table-action-collection-cell-space-x-compact);
336
340
  --table-cell-padding-y: var(--table-action-collection-cell-padding-y-compact);
337
341
  font-size: var(--table-action-collection-font-size-compact);
338
- /* The legibility floor. Default `0` keeps the table fitted to its container exactly as
339
- * before; a consumer whose column count exceeds the priority budget raises it and the
340
- * surrounding scroll region takes the overflow instead of the cells. */
341
- min-inline-size: var(--table-action-collection-min-inline-size-compact);
342
342
  }
343
343
 
344
344
  /* A nowrap child (a Badge pill, a chip) would otherwise bleed into the next column at the
@@ -346,6 +346,21 @@
346
346
  [data-collapse-below="sm"] [data-slot="table-cell"] * {
347
347
  white-space: normal;
348
348
  }
349
+
350
+ /* SEVEN columns and up — the wide-collection floor tier (gh#262). Percent shares are
351
+ * guaranteed to sum past 100% here and fixed layout would normalize them into sub-glyph
352
+ * columns, so every column (the unmarked free-text one included) takes its rem floor
353
+ * instead; the over-constrained table grows past 100% and its wrapper scrolls. Up to six
354
+ * columns this rule never matches and the percent tier above keeps the canonical queues
355
+ * scroll-free — the preset's documented column-count ceiling. */
356
+ [data-collapse-below="sm"] [data-slot="table"]:has([data-slot="table-head"]:nth-child(7)) {
357
+ --table-action-collection-primary-width: var(--table-action-collection-primary-width-floor);
358
+ --table-action-collection-secondary-width: var(
359
+ --table-action-collection-secondary-width-floor
360
+ );
361
+ --table-action-collection-meta-width: var(--table-action-collection-meta-width-floor);
362
+ --table-action-collection-flex-width: var(--table-action-collection-flex-width-floor);
363
+ }
349
364
  }
350
365
 
351
366
  @container ui-table-collection (width < 48rem) {
@@ -360,10 +375,6 @@
360
375
  --table-cell-space-x: var(--table-action-collection-cell-space-x-compact);
361
376
  --table-cell-padding-y: var(--table-action-collection-cell-padding-y-compact);
362
377
  font-size: var(--table-action-collection-font-size-compact);
363
- /* The legibility floor. Default `0` keeps the table fitted to its container exactly as
364
- * before; a consumer whose column count exceeds the priority budget raises it and the
365
- * surrounding scroll region takes the overflow instead of the cells. */
366
- min-inline-size: var(--table-action-collection-min-inline-size-compact);
367
378
  }
368
379
 
369
380
  /* A nowrap child (a Badge pill, a chip) would otherwise bleed into the next column at the
@@ -371,6 +382,21 @@
371
382
  [data-collapse-below="md"] [data-slot="table-cell"] * {
372
383
  white-space: normal;
373
384
  }
385
+
386
+ /* SEVEN columns and up — the wide-collection floor tier (gh#262). Percent shares are
387
+ * guaranteed to sum past 100% here and fixed layout would normalize them into sub-glyph
388
+ * columns, so every column (the unmarked free-text one included) takes its rem floor
389
+ * instead; the over-constrained table grows past 100% and its wrapper scrolls. Up to six
390
+ * columns this rule never matches and the percent tier above keeps the canonical queues
391
+ * scroll-free — the preset's documented column-count ceiling. */
392
+ [data-collapse-below="md"] [data-slot="table"]:has([data-slot="table-head"]:nth-child(7)) {
393
+ --table-action-collection-primary-width: var(--table-action-collection-primary-width-floor);
394
+ --table-action-collection-secondary-width: var(
395
+ --table-action-collection-secondary-width-floor
396
+ );
397
+ --table-action-collection-meta-width: var(--table-action-collection-meta-width-floor);
398
+ --table-action-collection-flex-width: var(--table-action-collection-flex-width-floor);
399
+ }
374
400
  }
375
401
 
376
402
  @container ui-table-collection (width < 64rem) {
@@ -385,10 +411,6 @@
385
411
  --table-cell-space-x: var(--table-action-collection-cell-space-x-compact);
386
412
  --table-cell-padding-y: var(--table-action-collection-cell-padding-y-compact);
387
413
  font-size: var(--table-action-collection-font-size-compact);
388
- /* The legibility floor. Default `0` keeps the table fitted to its container exactly as
389
- * before; a consumer whose column count exceeds the priority budget raises it and the
390
- * surrounding scroll region takes the overflow instead of the cells. */
391
- min-inline-size: var(--table-action-collection-min-inline-size-compact);
392
414
  }
393
415
 
394
416
  /* A nowrap child (a Badge pill, a chip) would otherwise bleed into the next column at the
@@ -396,6 +418,21 @@
396
418
  [data-collapse-below="lg"] [data-slot="table-cell"] * {
397
419
  white-space: normal;
398
420
  }
421
+
422
+ /* SEVEN columns and up — the wide-collection floor tier (gh#262). Percent shares are
423
+ * guaranteed to sum past 100% here and fixed layout would normalize them into sub-glyph
424
+ * columns, so every column (the unmarked free-text one included) takes its rem floor
425
+ * instead; the over-constrained table grows past 100% and its wrapper scrolls. Up to six
426
+ * columns this rule never matches and the percent tier above keeps the canonical queues
427
+ * scroll-free — the preset's documented column-count ceiling. */
428
+ [data-collapse-below="lg"] [data-slot="table"]:has([data-slot="table-head"]:nth-child(7)) {
429
+ --table-action-collection-primary-width: var(--table-action-collection-primary-width-floor);
430
+ --table-action-collection-secondary-width: var(
431
+ --table-action-collection-secondary-width-floor
432
+ );
433
+ --table-action-collection-meta-width: var(--table-action-collection-meta-width-floor);
434
+ --table-action-collection-flex-width: var(--table-action-collection-flex-width-floor);
435
+ }
399
436
  }
400
437
 
401
438
  @container ui-table-collection (width < 80rem) {
@@ -410,10 +447,6 @@
410
447
  --table-cell-space-x: var(--table-action-collection-cell-space-x-compact);
411
448
  --table-cell-padding-y: var(--table-action-collection-cell-padding-y-compact);
412
449
  font-size: var(--table-action-collection-font-size-compact);
413
- /* The legibility floor. Default `0` keeps the table fitted to its container exactly as
414
- * before; a consumer whose column count exceeds the priority budget raises it and the
415
- * surrounding scroll region takes the overflow instead of the cells. */
416
- min-inline-size: var(--table-action-collection-min-inline-size-compact);
417
450
  }
418
451
 
419
452
  /* A nowrap child (a Badge pill, a chip) would otherwise bleed into the next column at the
@@ -421,5 +454,20 @@
421
454
  [data-collapse-below="xl"] [data-slot="table-cell"] * {
422
455
  white-space: normal;
423
456
  }
457
+
458
+ /* SEVEN columns and up — the wide-collection floor tier (gh#262). Percent shares are
459
+ * guaranteed to sum past 100% here and fixed layout would normalize them into sub-glyph
460
+ * columns, so every column (the unmarked free-text one included) takes its rem floor
461
+ * instead; the over-constrained table grows past 100% and its wrapper scrolls. Up to six
462
+ * columns this rule never matches and the percent tier above keeps the canonical queues
463
+ * scroll-free — the preset's documented column-count ceiling. */
464
+ [data-collapse-below="xl"] [data-slot="table"]:has([data-slot="table-head"]:nth-child(7)) {
465
+ --table-action-collection-primary-width: var(--table-action-collection-primary-width-floor);
466
+ --table-action-collection-secondary-width: var(
467
+ --table-action-collection-secondary-width-floor
468
+ );
469
+ --table-action-collection-meta-width: var(--table-action-collection-meta-width-floor);
470
+ --table-action-collection-flex-width: var(--table-action-collection-flex-width-floor);
471
+ }
424
472
  }
425
473
  }
@@ -107,6 +107,19 @@
107
107
  * having to add `min-w-0` — the documented flex-truncate idiom (issue #114). */
108
108
  min-width: 0;
109
109
  }
110
+ /* Multi-line clamp (`clamp` prop, issue #261) — the token-owned line-clamp so consumers never
111
+ * write a page-local `line-clamp-N` utility. Visual-only: the full text stays in the DOM and
112
+ * the accessible name. `--text-clamp` is set inline by the component from the prop value. */
113
+ [data-slot="text"][data-clamp] {
114
+ display: -webkit-box;
115
+ -webkit-box-orient: vertical;
116
+ -webkit-line-clamp: var(--text-clamp, 2);
117
+ line-clamp: var(--text-clamp, 2);
118
+ overflow: hidden;
119
+ /* Same flex-shrink contract as truncate (issue #114): clamps inside a flex row without
120
+ * the consumer adding `min-w-0`. */
121
+ min-width: 0;
122
+ }
110
123
  [data-slot="text"][data-tabular] {
111
124
  font-variant-numeric: tabular-nums;
112
125
  }
@@ -13,6 +13,7 @@
13
13
  @import "./components/descriptions.css";
14
14
  @import "./components/table.css";
15
15
  @import "./components/feedback.css";
16
+ @import "./components/banner.css";
16
17
  @import "./components/sheet.css";
17
18
  @import "./components/badge.css";
18
19
  @import "./components/navigation.css";
@@ -7,4 +7,9 @@
7
7
  /* Small-by-design (badge/pill/counter). A knob (rule #45) so a service can
8
8
  * re-tune badge text without touching the global --font-size-xs step. */
9
9
  --badge-font-size: var(--font-size-xs);
10
+ /* Companion to --badge-font-size (gh#260). The cva's old `text-xs` utility also set
11
+ * line-height via Tailwind's default `--text-xs--line-height: calc(1 / 0.75)` (the theme
12
+ * remaps --text-xs but never that companion). Same unitless ratio here keeps the default
13
+ * badge pixel-identical now that badge-layout.css owns the type metrics. */
14
+ --badge-line-height: calc(1 / 0.75);
10
15
  }
@@ -0,0 +1,16 @@
1
+ /* Banner — the full-bleed attention strip (<Banner> = Alert variant="banner").
2
+ * Colour stays with the alert tone rules; these tokens own ONLY the strip geometry,
3
+ * so a service retunes the banner once here instead of forking alert-layout.css
4
+ * (rule #45 — every service-tunable constant gets a knob). */
5
+
6
+ :root {
7
+ /* Square corners — a strip spans its container edge-to-edge, so it carries no radius. */
8
+ --banner-radius: 0;
9
+ /* The strip keeps a single hairline block-end rule (tone-coloured via the alert
10
+ * border rules); inline/block-start edges are open so it reads as part of the frame. */
11
+ --banner-border-width: 1px;
12
+ /* Strip inset. Block is denser than the inline Alert card; inline defaults to the
13
+ * page gutter so banner text aligns with page content under AppShell/PageContainer. */
14
+ --banner-space-inset-block: var(--space-3);
15
+ --banner-space-inset-inline: var(--space-page-active-x, var(--space-6));
16
+ }
@@ -74,18 +74,6 @@
74
74
  * The slot padding compensation in card-layout.css subtracts the same token,
75
75
  * so content stays aligned on the shell whatever the rail width. */
76
76
  --card-accent-rail-width: 6px;
77
- /* Accent placement `perimeter` (gh#12) — the FULL attention border. Two knobs so a service can
78
- * tune the edge weight and the outer ring independently; the defaults reproduce the optical
79
- * weight of `variant="featured"` (1px border + 1px ring) in the card's own semantic accent tone
80
- * instead of --primary. Structural 1px literals, like the base card hairline. */
81
- --card-accent-perimeter-width: 1px;
82
- --card-accent-perimeter-ring-width: 1px;
83
- /* `variant="featured"` edge — role-mirror knob (docs/TOKENS.md). `initial` so the --primary
84
- * default resolves at the CALL SITE and a scoped [data-tenant]/.dark override of --primary
85
- * reaches it; a service points it anywhere (e.g. var(--attention)) to retint every featured card
86
- * at once. Default = hsl(var(--primary)). */
87
- --card-featured-border-color: initial;
88
- --card-featured-ring-width: 1px;
89
77
  --stat-card-label-font-size: var(--font-size-xs);
90
78
  --stat-card-label-font-weight: var(--font-weight-medium);
91
79
  --stat-card-label-letter-spacing: 0.04em;
@@ -67,22 +67,6 @@
67
67
  * re-scopes --control-height to 36px, would silently shrink. Verified in Chromium: 36px before
68
68
  * and after. A service opts in with a NAMED tier (`var(--control-height-lg)`), never a calc. */
69
69
  --otp-slot-size: initial; /* default = var(--control-height) at the call site */
70
- /* Per-AXIS overrides of the slot box (gh#12). --otp-slot-size stays the square shorthand; these
71
- * two win over it when set, so a code field can be WIDER-than-tall or TALLER-than-wide without
72
- * abandoning the token. A canonical device-grant code field is 27.5x52 per slot (a 4-slot
73
- * `appearance="grouped"` box of 112x54 with its 1px group border) — not expressible with one
74
- * square knob, which is why grouped OTP measured 146x38 against that artboard. `initial` for the
75
- * same tier-mirror reason as --otp-slot-size: the whole fallback chain
76
- * (axis → square → --control-height) must resolve at the CALL SITE so a shell that re-scopes
77
- * --control-height still reaches an OTP row that sets neither axis. */
78
- --otp-slot-inline-size: initial; /* default = var(--otp-slot-size, var(--control-height)) */
79
- --otp-slot-block-size: initial; /* default = var(--otp-slot-size, var(--control-height)) */
80
- /* Main-axis alignment of the whole OTP row (rule #44/#45 — chrome is a token, default quiet).
81
- * `flex-start` is the historical behaviour, so an existing field is byte-identical; a centred
82
- * code field is `align="center"` on InputOTP (which wins over this knob) or this token set once
83
- * in a service theme. It exists because EVERY consumer was wrapping .ui-otp-container in a
84
- * flex-centring div to get a centred challenge. */
85
- --otp-container-align: flex-start;
86
70
 
87
71
  /* Checked/on/active fills — `initial` so the --primary default re-resolves at the call site
88
72
  * under a scoped theme (a :root binding to var(--primary) freezes at the :root value and a scoped
@@ -28,18 +28,6 @@
28
28
  --avatar-square-background: initial;
29
29
  --avatar-square-foreground: initial;
30
30
 
31
- /* Capability medallion — `<Avatar appearance="tinted">` (gh#12): the tinted plate a capability /
32
- feature glyph sits on, as opposed to the SOLID entity mark above. Pair it with shape="square"
33
- for the canonical rounded square. --avatar-tinted-background / --avatar-tinted-foreground are
34
- role-mirror knobs (`initial`, docs/TOKENS.md) so the --primary defaults resolve at the CALL
35
- SITE and a scoped [data-tenant]/.dark override of --primary reaches them — the exact reason
36
- this is a token and not the `hsl(var(--primary) / 0.1)` literal consumers were writing in page
37
- CSS. Defaults = hsl(var(--primary) / 0.1) wash · hsl(var(--primary)) glyph ·
38
- --control-icon-size glyph box. */
39
- --avatar-tinted-background: initial;
40
- --avatar-tinted-foreground: initial;
41
- --avatar-tinted-glyph-size: var(--control-icon-size);
42
-
43
31
  /* Progress track + fill — `initial` so the role defaults re-resolve under a scoped theme.
44
32
  Track reads --secondary, fill reads --success; a service re-tones once.
45
33
  Defaults = hsl(var(--secondary)) track · hsl(var(--success)) fill. */
@@ -63,14 +63,8 @@
63
63
  --email-heading-font-weight: 500; /* mirrors --font-weight-medium — an email title is calm, not bold */
64
64
 
65
65
  /* ── Primary CTA — the one action button ────────────────────────────────────────────────── */
66
- /* TOUCH TARGET, deliberately DECOUPLED from --control-height-lg (36px). Do not "restore" the
67
- * mirror: email is a mobile-first, touch-only medium. There is no hover state, no precise
68
- * pointer, and mail clients do not reliably offer zoom or a focus affordance — so the web's AA
69
- * floor (SC 2.5.8, 24x24, which 36px clears) is the wrong bar here. 44px is the AAA target size
70
- * (SC 2.5.5, 44x44) and the Apple HIG 44pt / Material 48dp convention. A service that must keep
71
- * the old box sets --email-cta-height + --email-cta-line-height in its own theme. */
72
- --email-cta-height: 44px;
73
- --email-cta-line-height: 44px; /* equal to the height: bulletproof vertical centring in Outlook */
66
+ --email-cta-height: 36px; /* mirrors --control-height-lg (2.25rem) the canonical CTA box */
67
+ --email-cta-line-height: 36px; /* equal to the height: bulletproof vertical centring in Outlook */
74
68
  --email-cta-padding-x: 16px; /* mirrors --space-4 */
75
69
  --email-cta-radius: 6px; /* mirrors the --radius base (0.375rem) */
76
70
  --email-cta-font-size: 14px; /* mirrors --font-size-base */
@@ -29,26 +29,6 @@
29
29
  * (a brand's success-bg/-border are often more present than the faint 5%/30% default). */
30
30
  --alert-bg-alpha: 0.05;
31
31
  --alert-border-alpha: 0.3;
32
- /* BANNER — the page-level Alert treatment (gh#255). Every constant a service would want to
33
- * match to its page grid is a knob (rule #45): a banner that must keep the app's rounded card
34
- * language sets --banner-radius, one that rules its top edge too sets --banner-border-width.
35
- * The inline inset tracks the live page gutter, so a banner mounted above a PageContainer lines
36
- * its text up with the page title instead of sitting at a second, unrelated margin. */
37
- --banner-radius: 0;
38
- --banner-border-width: 0;
39
- --banner-border-block-end-width: 1px;
40
- --banner-space-block: var(--space-3);
41
- /* Inline inset tracks the page gutter so a banner's text lines up with the page title.
42
- * `--space-page-active-x` steps down to the compact gutter on `.ui-page-container` only, and
43
- * custom properties inherit — so a banner rendered INSIDE the container picks the compact value
44
- * up for free, while the normal case (a banner mounted ABOVE the container, or in AppShell) would
45
- * keep the desktop gutter and sit 8px out at 390px. The compact step below is what actually keeps
46
- * the two aligned; retune it rather than hard-coding a mobile inset at the call site. */
47
- --banner-space-inline: var(--space-page-active-x);
48
- --banner-space-inline-compact: var(--space-page-compact-x);
49
- /* Dismiss offset is measured from the banner's own (shorter) block inset, so the ✕ stays
50
- * optically centred on a one-line strip instead of floating at the inline-alert offset. */
51
- --banner-dismiss-space-offset: var(--space-2);
52
32
  /* Brand glow layer for the raised dialog/sheet panel — invisible no-op at rest (rule #44).
53
33
  * Paired AFTER --shadow-lg in the surface box-shadow so a service can wash the overlay with the
54
34
  * global glow, e.g. --dialog-content-glow: var(--shadow-glow), with no markup change. */
@@ -14,15 +14,6 @@
14
14
  --steps-inline-item-gap: var(--space-1);
15
15
  --steps-inline-font-size: var(--font-size-xs);
16
16
  --steps-inline-separator-size: var(--control-icon-size-sm);
17
- /* Inline-step emphasis (gh#12). The step number's weight and tint are separate knobs so a
18
- * service can express progression the canonical way — an accent TINT at normal weight — instead
19
- * of the original bold. --steps-inline-index-color / --steps-inline-separator-color are
20
- * role-mirror knobs (docs/TOKENS.md): `initial` so their defaults (the inherited step colour and
21
- * the --muted-foreground role) resolve at the CALL SITE and a scoped [data-tenant]/.dark
22
- * override still reaches them. Defaults reproduce today's row byte for byte. */
23
- --steps-inline-index-font-weight: var(--font-weight-bold);
24
- --steps-inline-index-color: initial; /* default = currentColor at the call site */
25
- --steps-inline-separator-color: initial; /* default = hsl(var(--muted-foreground)) */
26
17
 
27
18
  /* AppSettingPicker `compact` (gh#217) — the small, content-hugging labelled trigger used in an
28
19
  * auth/legal footer, where the square icon-only default reads as a stray button and the full
@@ -65,29 +56,14 @@
65
56
  * (0 on an overlay-scrollbar platform). */
66
57
  --filter-bar-scroll-padding-y: var(--space-1);
67
58
 
68
- /* FilterBar typed model (#258) — the search / chip / result-count regions the bar now OWNS, so a
69
- * list page never re-decides them. Every constant is a knob (rule #45): a service matches its own
70
- * grid by retuning these once instead of per page.
71
- *
72
- * Search MEASURE — the whole point of the `search` slot. Below the 640px step the control is
73
- * full-width (a bounded search box on a 390px screen wastes the row), so this binds only at and
74
- * above it. 18rem = 288px: comfortable for a JA/VI query without crowding the filter groups. */
75
- --filter-bar-search-width: 18rem;
76
-
77
- /* Applied-filter chips. */
78
- --filter-bar-chip-gap: var(--space-inline-xs);
79
- --filter-bar-chip-row-gap: var(--space-inline-xs);
80
- --filter-bar-chip-padding-inline: var(--space-2);
81
- --filter-bar-chip-padding-block: var(--space-1);
82
- --filter-bar-chip-radius: var(--radius-sm);
83
- --filter-bar-chip-font-size: var(--font-size-xs);
84
- /* Role-mirror knobs (docs/TOKENS.md) — `initial` at :root so --muted / --muted-foreground
85
- * re-resolve at the CALL SITE under a scoped [data-tenant]/.dark theme. Binding a role var here
86
- * would freeze the chip at the :root palette and a tenant override would never reach it. */
87
- --filter-bar-chip-background: initial;
88
- --filter-bar-chip-foreground: initial;
89
-
90
- /* Result-count live region. */
91
- --filter-bar-count-font-size: var(--font-size-xs);
92
- --filter-bar-count-foreground: initial;
59
+ /* FilterBar typed model (gh#258) — token-owned geometry so every list page gets the SAME
60
+ * search width, filter width, chip rhythm and section stacking without page-local CSS.
61
+ * All are rule-#45 knobs: a service theme retunes them once, props/className override per
62
+ * instance. Below 640px the strip stacks (search/filters full-width); the widths apply from
63
+ * the 640px breakpoint up, always clamped by min(100%, …) so a narrow container never
64
+ * overflows at 390px with long JA/EN/VI labels. */
65
+ --filter-bar-search-width: 20rem;
66
+ --filter-bar-filter-width: var(--filter-picker-width-md);
67
+ --filter-bar-chip-gap: var(--space-2);
68
+ --filter-bar-section-gap: var(--space-2);
93
69
  }
@@ -81,21 +81,10 @@
81
81
  --topbar-height: auto;
82
82
  --topbar-inset: 0px;
83
83
  --topbar-gap: var(--space-2);
84
- /* THIS KNOB DELETES CONTENT AT 1100px AND BELOW read before you ship a center slot.
85
- * At compact desktop/tablet widths the docked sidebar leaves too little inline room for three
86
- * intrinsically-sized clusters, so the package hides the optional center slot before it can
87
- * cover the breadcrumb/title or end utilities (gh#244). The default is `none`, which means a
88
- * global search trigger placed in `center` is INVISIBLE from 1100px down — including on every
89
- * phone — unless the consumer opts back in. That default arrived in 18.6.0 and removed the slot
90
- * for consumers who never changed a line of their own code (gh#12); it stays because the
91
- * overlap it prevents is a real defect and flipping a shipped default twice is worse than
92
- * documenting it once, but it is a DECISION, not an accident:
93
- *
94
- * :root { --topbar-center-compact-display: flex; } ← restore the slot at every width
95
- *
96
- * Opt back in only once the center content has a compact presentation of its own (an icon-only
97
- * search trigger, a collapsing field). A page-local media query is the anti-pattern this knob
98
- * replaces. */
84
+ /* At compact desktop/tablet widths the docked sidebar leaves too little inline room for three
85
+ * intrinsically-sized clusters. The package hides the optional center slot before it can cover
86
+ * the breadcrumb/title or end utilities. Consumers may opt back into another display strategy
87
+ * (for example `flex`) once their center content has its own compact presentation. */
99
88
  --topbar-center-compact-display: none;
100
89
  --org-switcher-trigger-height: 2.75rem;
101
90
  --org-switcher-trigger-padding-x: var(--space-2);
@@ -183,27 +172,17 @@
183
172
  --auth-shell-login-main-padding-block-end: 1rem;
184
173
  --auth-shell-login-identity-slot-block-size: 7rem;
185
174
  --auth-shell-login-card-stack-gap: 1.25rem;
186
- --auth-shell-login-card-padding-block-compact: calc(
187
- var(--auth-shell-compact-card-inset) + var(--control-border-width) + var(--control-border-width)
188
- );
175
+ /* Canonical SCR-001 block inset is a FLAT 24px — the same measure as the inline inset. The card
176
+ * draws its own 1px border and a border-box rect already contains it, so the former
177
+ * `+ 2 x --control-border-width` double-counted the border and pushed the passkey CTA to y=390
178
+ * instead of the canonical y=388 (gh#263). */
179
+ --auth-shell-login-card-padding-block-compact: var(--auth-shell-compact-card-inset);
189
180
 
190
181
  /* Device-authorization preset — 380px card measure, 15px block · 5px inline mobile gutter
191
182
  * (at a 390px viewport the card is x=5px, width=380px). */
192
183
  --auth-shell-device-card-max-width: 23.75rem;
193
184
  --auth-shell-device-main-padding: 1rem;
194
185
  --auth-shell-device-main-padding-mobile: 0.9375rem 0.3125rem;
195
- /* CODE FIELD measure — the preset owns it (gh#12). A device grant is the one canonical flow whose
196
- * PRIMARY control is the code field, so leaving it on the generic square --otp-slot-size made the
197
- * preset own the page but not its own subject: two 4-slot `appearance="grouped"` boxes rendered
198
- * 146x38 (4 x the canonical 36px control tier + the 1px group border) against a 112x54 artboard.
199
- * These are the per-slot boxes that ADD UP to that artboard group:
200
- * inline 27.5px x 4 + 2 x 1px group border = 112px
201
- * block 52px + 2 x 1px group border = 54px
202
- * Literal artboard lengths, like every other preset measure here — they must not drift with
203
- * --scaling. A service that groups its code differently overrides --otp-slot-inline-size /
204
- * --otp-slot-block-size on its own field; the generic square knob is untouched everywhere else. */
205
- --auth-shell-device-otp-slot-inline-size: 1.71875rem;
206
- --auth-shell-device-otp-slot-block-size: 3.25rem;
207
186
 
208
187
  /* Context-selection preset — 25rem card measure on desktop/tablet, edge-to-edge on mobile
209
188
  * (0 inline gutter) with a 16px rhythm between the intro, the card and the remember row. */
@@ -256,14 +235,19 @@
256
235
  --auth-shell-registration-main-padding-block-end-mobile: 2rem;
257
236
  --auth-shell-registration-card-stack-gap: 1.25rem;
258
237
  /* Fixed identity track, the same 112px `login` proved (gh#237). Without it the card anchor moves
259
- * with the title/requester line count measured here at 82.69px for one wrapped requester so
260
- * the canonical y above would hold for exactly one copy length and drift for every other. The
261
- * slot absorbs absent / one-line / two-line identity content instead. */
238
+ * with the title/requester line count, so the canonical y above would hold for exactly one copy
239
+ * length and drift for every other. The slot absorbs absent / one-line / two-line identity
240
+ * content instead. */
262
241
  --auth-shell-registration-identity-slot-block-size: 7rem;
263
242
 
264
- /* Labelled auth divider geometry. */
243
+ /* Labelled auth divider geometry. The canonical SCR-001 divider row is 19px tall at the 11px
244
+ * label (the artboard label inherits the page's line-height instead of collapsing to a 1.0 line
245
+ * box). 19/11 pins the row at exactly 19px and keeps it proportional if a service retunes the
246
+ * label font-size. The previous hardcoded `line-height: 1` rendered an 11px row, sitting the
247
+ * whole lower half of the Login card 8px high (gh#263). */
265
248
  --auth-shell-divider-gap: 0.625rem;
266
249
  --auth-shell-divider-label-font-size: 0.6875rem;
250
+ --auth-shell-divider-label-line-height: calc(19 / 11);
267
251
  --auth-shell-divider-rule-color: var(--border);
268
252
  --auth-shell-divider-label-color: var(--muted-foreground);
269
253
  --auth-identity-gap: 0.375rem;
@@ -281,8 +265,12 @@
281
265
  --auth-footer-text-font-size: 0.6875rem;
282
266
  --auth-stack-gap: var(--space-3);
283
267
  --auth-shell-field-label-gap: var(--space-1);
284
- --auth-shell-field-label-font-size: var(--font-size-xs);
285
- --auth-shell-field-label-line-height: 1.25;
268
+ /* Canonical SCR-001 field label: a LITERAL 12px (the golden-ratio --font-size-xs ≈ 12.47px would
269
+ * drift the 18px line box to 18.7px and push the email input off its y=489 anchor) with a 1.5
270
+ * line box = 18px. The former var(--font-size-xs)/1.25 pair rendered a 14px box, sitting the
271
+ * email input 4px high (gh#263). */
272
+ --auth-shell-field-label-font-size: 0.75rem;
273
+ --auth-shell-field-label-line-height: 1.5;
286
274
 
287
275
  /* CenteredShell — authenticated, no-sidebar, centred-column page shell (hosted-ID "My Page",
288
276
  * account, standalone settings). The bar mirrors AppShell's `.app-topbar` chrome (fixed height +
@@ -59,34 +59,53 @@
59
59
  --table-action-collection-secondary-width: 22%; /* target / resource */
60
60
  --table-action-collection-meta-width: 12%; /* timestamps, ids — lowest priority */
61
61
  --table-action-collection-actions-width: 3.5rem; /* row-action affordance, never clipped */
62
- /* Compact tier, applied below the collapse step (the 390px acceptance frame). */
62
+ /* Compact tier, applied below the collapse step (the 390px acceptance frame). Percentages,
63
+ * like the desktop tier: while the priority ratios FIT (the canonical queues up to the
64
+ * six-column budget below), they keep the table filling its container edge-to-edge with no
65
+ * horizontal scroll — the gh#253 acceptance. */
63
66
  --table-action-collection-primary-width-compact: 24%;
64
67
  --table-action-collection-secondary-width-compact: 22%;
65
68
  --table-action-collection-meta-width-compact: 20%;
66
69
  --table-action-collection-actions-width-compact: 2.75rem;
70
+ /* Wide-collection FLOORS — the compact measures from SEVEN columns up (gh#262).
71
+ *
72
+ * Percentage measures stop working once a queue carries enough columns for the shares to sum
73
+ * past 100%: `table-layout: fixed` NORMALIZES them back into the table's specified width, so at
74
+ * ~10 columns on a 390px frame a "24%" column really renders at a tenth of the frame, every
75
+ * column drops below one CJK glyph, and JA headers shred into a vertical one-character-per-line
76
+ * column (the failure mode WCAG 2.2 SC 1.4.10 Reflow exists to prevent). Cell `min-inline-size`
77
+ * and `max(%, length)` widths are equally inert in the fixed algorithm, and the intrinsic
78
+ * (max-content) size of a fixed-layout table is degenerate — all verified in Chromium — so a
79
+ * LENGTH is the only floor an engine respects: length columns are never squeezed, and when
80
+ * their sum outgrows the container the table's used width grows past its specified 100%
81
+ * (CSS 2.1 §17.5.2.1) into the keyboard-reachable overflow-x wrapper, which scrolls.
82
+ * ONE-dimensional scrolling of a data table is explicitly permitted by SC 1.4.10;
83
+ * one-character-per-line is not readable at all.
84
+ *
85
+ * The stylesheet switches tiers on a COLUMN BUDGET, not on width: up to six columns the
86
+ * percentage ratios above still resolve to readable measures at every acceptance artboard
87
+ * (320 · 375 · 390), so the canonical five-column approval queue keeps its documented
88
+ * scroll-free 390 frame byte-for-byte; from seven columns the shares are guaranteed to
89
+ * over-sum and the floors + intentional scroll take over. That budget is the preset's
90
+ * documented column-count ceiling (gh#262 expectation 3): past six columns the preset stops
91
+ * compressing and starts scrolling.
92
+ *
93
+ * Units are rem, not ch: `ch` tracks the "0" glyph (~half a CJK em), so a ch-denominated floor
94
+ * would silently halve for the JA copy these floors exist to protect. At the compact type tier
95
+ * (font-size-xs = 0.75rem, space-2 inline padding each side) the 5rem meta floor keeps a ~4rem
96
+ * text measure = 5 full-width glyphs per line — a JA header wraps to two readable lines, never
97
+ * a character column. */
98
+ --table-action-collection-primary-width-floor: 6rem;
99
+ --table-action-collection-secondary-width-floor: 5.5rem;
100
+ --table-action-collection-meta-width-floor: 5rem;
101
+ /* Floor for a column with NO `priority` (the free-text column, `auto` up to the budget). It
102
+ * cannot stay `auto` past the budget: once the marked columns over-constrain the table, the
103
+ * fixed algorithm hands an auto column exactly 0px (verified in Chromium) — the same
104
+ * shredding, moved to the free-text column. The actions floor is simply
105
+ * `--table-action-collection-actions-width-compact`, already an absolute measure. */
106
+ --table-action-collection-flex-width-floor: 5rem;
67
107
  --table-action-collection-font-size-compact: var(--font-size-xs);
68
108
  --table-action-collection-cell-space-x-compact: var(--space-2);
69
109
  --table-action-collection-cell-padding-y-compact: var(--space-2);
70
110
  --table-action-collection-row-height-compact: var(--table-row-height-compact);
71
- /* Compact-tier LEGIBILITY FLOOR — the measure below which the preset stops fitting the table
72
- * to its container and lets the scroll region it already owns take over.
73
- *
74
- * The percentage budget above is sized for ONE column per priority tier plus one free-text
75
- * column. A queue that repeats a tier — two `secondary` columns, three `meta` columns, or an
76
- * unmarked column beside them — asks for more than 100%, and under `table-layout: fixed` the
77
- * surplus is taken out of the columns rather than out of the table: measured on a seven-column
78
- * Japanese admin queue at 390, every column landed at 44–59px and CJK labels wrapped at ONE to
79
- * TWO characters per line (dxs-platform/platform#680). That is a WCAG 2.2 SC 1.4.10 Reflow (AA)
80
- * failure, and it is the failure mode this floor removes.
81
- *
82
- * Scrolling is the correct escape, not a concession: SC 1.4.10 exempts "parts of the content
83
- * which require two-dimensional layout for usage or meaning", and its own note names data
84
- * tables as the example. A table that scrolls horizontally inside its card conforms; a table
85
- * whose cells are one character wide does not.
86
- *
87
- * Default `0` so nothing changes for any existing consumer: a queue that fits its priority
88
- * budget keeps fitting. A consumer whose queue carries more columns than the budget sets this
89
- * to the measure at which its narrowest column is still readable (roughly 5rem per column for
90
- * Japanese at the compact type tier) and the table scrolls instead of crushing. */
91
- --table-action-collection-min-inline-size-compact: 0;
92
111
  }
@@ -83,18 +83,11 @@
83
83
  * page moves. 11rem = 176px, i.e. the control ends flush with the compact page gutter. */
84
84
  --page-header-extra-measure: 11rem; /* 176px */
85
85
 
86
- /* Inline gap between the `<h1>` and the PageHeader `meta` slot (a status Badge, a record ID) when
87
- * they share the title band (gh#255). Only consumed when `meta` is passed a header without it
88
- * emits no band wrapper at all, so no existing page moves. */
89
- --page-header-meta-gap: var(--space-inline-sm);
90
-
91
- /* PageHeader `loading` placeholders (gh#255). The title/subtitle elements wear the shared
92
- * `.ui-skeleton-block` skin, so they need only a MEASURE and a block size — a service retunes the
93
- * pending band's proportions here instead of per page. */
94
- --page-title-placeholder-measure: 14rem; /* 224px */
95
- --page-title-placeholder-block-size: 1.5em;
96
- --page-subtitle-placeholder-measure: 22rem; /* 352px */
97
- --page-subtitle-placeholder-block-size: 1.25em;
86
+ /* Gap between the page title and its status/meta band (PageContainer `status`,
87
+ * godxjp-ui#255), and between the band's own items. One knob aligns the badge row
88
+ * to a service's grid; a page that never passes `status` reads neither the token
89
+ * nor the wrapping row. */
90
+ --page-header-status-gap: var(--space-inline-sm);
98
91
 
99
92
  /* Bounded page MEASURE (gh#245 / gh#247) — the shared inline cap applied to the page HEADER and
100
93
  * BODY together, so the header `extra` action ends on the same edge as the body surface (the