@godxjp/ui 18.4.0 → 18.5.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 (131) hide show
  1. package/README.md +16 -1
  2. package/dist/app/theme-axes.d.ts +11 -3
  3. package/dist/app/theme-axes.js +2 -1
  4. package/dist/components/charts/chart-frame.d.ts +17 -3
  5. package/dist/components/charts/chart-frame.js +7 -1
  6. package/dist/components/charts/chart-summary.d.ts +21 -0
  7. package/dist/components/charts/chart-summary.js +32 -5
  8. package/dist/components/charts/compact-bar-trend.d.ts +29 -0
  9. package/dist/components/charts/compact-bar-trend.js +74 -0
  10. package/dist/components/charts/index.d.ts +3 -0
  11. package/dist/components/charts/index.js +2 -0
  12. package/dist/components/data-display/badge.d.ts +8 -0
  13. package/dist/components/data-display/badge.js +7 -1
  14. package/dist/components/data-display/data-table.d.ts +16 -1
  15. package/dist/components/data-display/data-table.js +56 -0
  16. package/dist/components/data-display/index.d.ts +3 -1
  17. package/dist/components/data-display/index.js +10 -1
  18. package/dist/components/data-display/list-row.d.ts +22 -4
  19. package/dist/components/data-display/list-row.js +21 -3
  20. package/dist/components/data-display/service-launcher-card.d.ts +40 -0
  21. package/dist/components/data-display/service-launcher-card.js +97 -0
  22. package/dist/components/data-entry/command-palette.d.ts +37 -0
  23. package/dist/components/data-entry/command-palette.js +125 -0
  24. package/dist/components/data-entry/index.d.ts +2 -0
  25. package/dist/components/data-entry/index.js +2 -0
  26. package/dist/components/feedback/dialog.d.ts +2 -0
  27. package/dist/components/feedback/dialog.js +42 -33
  28. package/dist/components/feedback/index.d.ts +4 -1
  29. package/dist/components/feedback/index.js +6 -2
  30. package/dist/components/feedback/sheet.d.ts +26 -4
  31. package/dist/components/feedback/sheet.js +54 -7
  32. package/dist/components/feedback/two-factor-setup.d.ts +31 -0
  33. package/dist/components/feedback/two-factor-setup.js +97 -0
  34. package/dist/components/general/index.d.ts +1 -1
  35. package/dist/components/general/logo.d.ts +42 -8
  36. package/dist/components/general/logo.js +67 -14
  37. package/dist/components/layout/app-shell.js +21 -5
  38. package/dist/components/layout/auth-divider.d.ts +7 -0
  39. package/dist/components/layout/auth-divider.js +21 -0
  40. package/dist/components/layout/auth-footer.d.ts +5 -0
  41. package/dist/components/layout/auth-footer.js +24 -0
  42. package/dist/components/layout/auth-identity.d.ts +5 -0
  43. package/dist/components/layout/auth-identity.js +17 -0
  44. package/dist/components/layout/auth-shell.d.ts +8 -1
  45. package/dist/components/layout/auth-shell.js +25 -6
  46. package/dist/components/layout/auth-stack.d.ts +4 -0
  47. package/dist/components/layout/auth-stack.js +8 -0
  48. package/dist/components/layout/centered-shell.d.ts +5 -2
  49. package/dist/components/layout/centered-shell.js +2 -1
  50. package/dist/components/layout/index.d.ts +18 -3
  51. package/dist/components/layout/index.js +17 -2
  52. package/dist/components/layout/legal-document-shell.d.ts +34 -0
  53. package/dist/components/layout/legal-document-shell.js +186 -0
  54. package/dist/components/layout/master-detail.d.ts +24 -0
  55. package/dist/components/layout/master-detail.js +48 -0
  56. package/dist/components/layout/org-switcher.d.ts +9 -0
  57. package/dist/components/layout/org-switcher.js +218 -0
  58. package/dist/components/layout/page-container.d.ts +1 -1
  59. package/dist/components/layout/page-container.js +3 -2
  60. package/dist/components/layout/sidebar-link.d.ts +43 -0
  61. package/dist/components/layout/sidebar-link.js +13 -0
  62. package/dist/components/layout/sidebar.d.ts +42 -5
  63. package/dist/components/layout/sidebar.js +170 -85
  64. package/dist/components/navigation/app-setting-picker.js +17 -6
  65. package/dist/components/navigation/filter-bar.d.ts +12 -3
  66. package/dist/components/navigation/filter-bar.js +8 -2
  67. package/dist/components/navigation/index.d.ts +2 -2
  68. package/dist/components/navigation/index.js +3 -1
  69. package/dist/components/navigation/tabs-scroll.d.ts +70 -0
  70. package/dist/components/navigation/tabs-scroll.js +76 -0
  71. package/dist/components/navigation/tabs.js +35 -20
  72. package/dist/email/brand-mark.d.ts +92 -0
  73. package/dist/email/brand-mark.js +83 -0
  74. package/dist/email/color.d.ts +52 -0
  75. package/dist/email/color.js +37 -0
  76. package/dist/email/geometry.d.ts +112 -0
  77. package/dist/email/geometry.js +89 -0
  78. package/dist/email/index.d.ts +78 -0
  79. package/dist/email/index.js +76 -0
  80. package/dist/email/inline-style.d.ts +25 -0
  81. package/dist/email/inline-style.js +21 -0
  82. package/dist/email/tokens.generated.d.ts +147 -0
  83. package/dist/email/tokens.generated.js +142 -0
  84. package/dist/i18n/messages/en.json +21 -2
  85. package/dist/i18n/messages/ja.json +21 -2
  86. package/dist/i18n/messages/vi.json +21 -2
  87. package/dist/inertia/index.d.ts +50 -0
  88. package/dist/inertia/index.js +5 -0
  89. package/dist/props/components/app.prop.d.ts +11 -1
  90. package/dist/props/components/charts.prop.d.ts +40 -1
  91. package/dist/props/components/data-display.prop.d.ts +13 -1
  92. package/dist/props/components/feedback.prop.d.ts +10 -0
  93. package/dist/props/components/index.d.ts +2 -2
  94. package/dist/props/components/layout.prop.d.ts +373 -10
  95. package/dist/props/components/layout.prop.js +1 -0
  96. package/dist/props/components/navigation.prop.d.ts +19 -1
  97. package/dist/props/registry.d.ts +291 -7
  98. package/dist/props/registry.js +341 -7
  99. package/dist/props/vocabulary/index.d.ts +1 -1
  100. package/dist/props/vocabulary/interaction.prop.d.ts +1 -1
  101. package/dist/props/vocabulary/layout.prop.d.ts +18 -0
  102. package/dist/styles/base.css +8 -2
  103. package/dist/styles/card-layout.css +161 -7
  104. package/dist/styles/chart-layout.css +97 -0
  105. package/dist/styles/control.css +48 -2
  106. package/dist/styles/data-display-layout.css +52 -6
  107. package/dist/styles/dialog-layout.css +105 -4
  108. package/dist/styles/fonts.css +15 -4
  109. package/dist/styles/index.css +11 -3
  110. package/dist/styles/layout.css +367 -1
  111. package/dist/styles/logo-layout.css +62 -0
  112. package/dist/styles/navigation-layout.css +43 -0
  113. package/dist/styles/shell-layout.css +488 -40
  114. package/dist/theme/dxs.canonical.css +76 -0
  115. package/dist/tokens/axes.css +39 -0
  116. package/dist/tokens/base.css +5 -0
  117. package/dist/tokens/components/card.css +48 -0
  118. package/dist/tokens/components/chart.css +47 -0
  119. package/dist/tokens/components/control.css +16 -0
  120. package/dist/tokens/components/email.css +66 -0
  121. package/dist/tokens/components/feedback.css +17 -0
  122. package/dist/tokens/components/legal-document.css +67 -0
  123. package/dist/tokens/components/list-row.css +23 -2
  124. package/dist/tokens/components/logo.css +32 -0
  125. package/dist/tokens/components/navigation.css +13 -0
  126. package/dist/tokens/components/sheet.css +19 -0
  127. package/dist/tokens/components/shell.css +138 -0
  128. package/dist/tokens/components/sidebar.css +33 -0
  129. package/dist/tokens/foundation.css +5 -2
  130. package/dist/tokens/semantic/layout.css +44 -2
  131. package/package.json +16 -5
@@ -0,0 +1,76 @@
1
+ /* ───────────────────────────────────────────────────────────────────────────
2
+ * THE CANONICAL DXS THEME — gh#214
3
+ *
4
+ * The one stylesheet a DXS surface imports INSTEAD of `@godxjp/ui/styles`. It
5
+ * makes the canonical contract the DEFAULT for every surface in the app, so no
6
+ * page ever needs local CSS for auth geometry, density, page insets, the brand
7
+ * logo colour, the auth divider, or the legal footer.
8
+ *
9
+ * import "@godxjp/ui/theme/dxs.canonical.css"; // instead of @godxjp/ui/styles
10
+ *
11
+ * Prefer the RUNTIME route when the app already mounts the provider — it is the
12
+ * same contract, switchable at runtime and persisted with the other axes:
13
+ *
14
+ * <AppProvider brand="dxs"> … </AppProvider> // writes <html data-brand="dxs">
15
+ *
16
+ * NOT A NEW BRAND. Every value below is canonical evidence already encoded in
17
+ * this package — the shipped GodX Navy primary ramp, and the
18
+ * `--auth-shell-canonical-*` measures declared in
19
+ * `src/tokens/components/shell.css`. This file only re-points the generic knob
20
+ * at the canonical one; it invents no colour and no geometry.
21
+ *
22
+ * SOURCE OF TRUTH: `src/tokens/axes.css` · `:root[data-brand="dxs"]`. This file
23
+ * mirrors that block at `:root` for stylesheet-only apps (no provider). They are
24
+ * asserted identical by `src/tokens/__tests__/dxs-canonical-theme.test.ts` — add
25
+ * a knob to BOTH or to neither.
26
+ *
27
+ * OVERRIDING: declare your own root block AFTER this import; at equal
28
+ * specificity the later declaration wins. Token overrides only — never component
29
+ * CSS or Tailwind utilities in a theme file.
30
+ * ─────────────────────────────────────────────────────────────────────────── */
31
+
32
+ @import "@godxjp/ui/styles";
33
+
34
+ :root {
35
+ /* ── Brand palette — the shipped GodX Navy ramp (identical to the `brand`
36
+ * axis preset). The brand-green IDENTITY mark is deliberately NOT here:
37
+ * `--logo-godx-color` / `--logo-wordmark-color` default to the `--success`
38
+ * identity role at their call sites and never read `--primary`, so a
39
+ * re-themed action colour can never recolour the GoDX mark or wordmark. */
40
+ --primary: 211 73% 15%;
41
+ --primary-foreground: 0 0% 100%;
42
+ --ring: 24 99% 46%;
43
+ --accent: 24 99% 95%;
44
+ --accent-foreground: 24 99% 28%;
45
+
46
+ /* ── Canonical auth surface — 36px controls, 22.5rem card measure, 16px page
47
+ * inset (15px below 30rem, see the media query below). This is what
48
+ * `AuthShell variant="canonical"` applies per-instance, made the default
49
+ * for every auth surface in the app. `variant="canonical"` still owns the
50
+ * COMPACT CARD density (`[data-density="compact"]` is element-scoped and
51
+ * cannot be reached from a token), so keep passing it for the full
52
+ * canonical card rhythm. */
53
+ --auth-shell-control-height: var(--auth-shell-canonical-control-height);
54
+ --auth-shell-heading-size: var(--auth-shell-canonical-heading-size);
55
+ --auth-shell-card-max-width: var(--auth-shell-canonical-card-max-width);
56
+ --auth-shell-main-padding: var(--auth-shell-canonical-main-padding);
57
+ }
58
+
59
+ /* Canonical 15px mobile page inset. */
60
+ @media (max-width: 30rem) {
61
+ :root {
62
+ --auth-shell-main-padding: var(--auth-shell-canonical-main-padding-mobile);
63
+ }
64
+ }
65
+
66
+ /* ── TODO (no canonical in-repo source yet — do NOT guess) ───────────────────
67
+ * · AppShell rail width / collapsed rail width / responsive breakpoint are
68
+ * still CSS literals, not tokens (gh#213), so there is nothing for a theme to
69
+ * bind. Add the bindings here once `--app-shell-sidebar-width` /
70
+ * `--app-shell-rail-width` / the breakpoint knob ship.
71
+ * · Standalone `.ui-topbar` height/gap/inset knobs do not exist yet (gh#213).
72
+ * · A real DXS wordmark ASSET (logotype artwork) has not been supplied by
73
+ * design. `<Logo wordmark="GoDX" />` typesets the name in the design-system
74
+ * display face via `--logo-wordmark-font-family`; swap in the real logotype
75
+ * (an inline `<svg>` passed as `wordmark`) when it exists.
76
+ * ─────────────────────────────────────────────────────────────────────────── */
@@ -57,3 +57,42 @@
57
57
  --accent: 215 25% 94%;
58
58
  --accent-foreground: 215 25% 20%;
59
59
  }
60
+
61
+ /* ── THE CANONICAL DXS PRESET (gh#214) ──────────────────────────────────────
62
+ * `dxs` is the one brand value that is NOT just a primary tint: it binds the
63
+ * canonical DXS SURFACE CONTRACT that every hosted-identity screen shares, so a
64
+ * service selects it once (`<AppProvider brand="dxs">`, or import
65
+ * `@godxjp/ui/theme/dxs.canonical.css`) and needs ZERO page CSS for auth
66
+ * geometry, density, insets, logo colour, divider or footer.
67
+ *
68
+ * SINGLE SOURCE OF TRUTH — every value below is already canonical evidence in
69
+ * this package: the palette is the shipped GodX Navy ramp (identical to
70
+ * `data-brand="brand"`), and the auth knobs simply re-point the generic
71
+ * AuthShell tokens at the `--auth-shell-canonical-*` values declared in
72
+ * `tokens/components/shell.css`. Nothing here is a new brand colour.
73
+ * `src/theme/dxs.canonical.css` mirrors this block for stylesheet-only apps;
74
+ * `src/tokens/__tests__/dxs-canonical-theme.test.ts` fails if the two drift.
75
+ *
76
+ * The brand-green GoDX identity mark needs no binding: `--logo-godx-color` /
77
+ * `--logo-wordmark-color` already default to the `--success` identity role at
78
+ * their call sites and never reference `--primary`. */
79
+ :root[data-brand="dxs"] {
80
+ --primary: 211 73% 15%;
81
+ --primary-foreground: 0 0% 100%;
82
+ --ring: 24 99% 46%;
83
+ --accent: 24 99% 95%;
84
+ --accent-foreground: 24 99% 28%;
85
+
86
+ /* Canonical auth surface — 36px controls, 22.5rem card measure, 16px page
87
+ * inset (15px below 30rem, see the media query). Matches AuthShell
88
+ * `variant="canonical"`, which still owns the compact CARD density knob. */
89
+ --auth-shell-control-height: var(--auth-shell-canonical-control-height);
90
+ --auth-shell-heading-size: var(--auth-shell-canonical-heading-size);
91
+ --auth-shell-card-max-width: var(--auth-shell-canonical-card-max-width);
92
+ --auth-shell-main-padding: var(--auth-shell-canonical-main-padding);
93
+ }
94
+ @media (max-width: 30rem) {
95
+ :root[data-brand="dxs"] {
96
+ --auth-shell-main-padding: var(--auth-shell-canonical-main-padding-mobile);
97
+ }
98
+ }
@@ -9,13 +9,18 @@
9
9
  @import "./components/control.css";
10
10
  @import "./components/form.css";
11
11
  @import "./components/card.css";
12
+ @import "./components/chart.css";
12
13
  @import "./components/descriptions.css";
13
14
  @import "./components/table.css";
14
15
  @import "./components/feedback.css";
16
+ @import "./components/sheet.css";
15
17
  @import "./components/badge.css";
16
18
  @import "./components/navigation.css";
17
19
  @import "./components/data-display.css";
18
20
  @import "./components/list-row.css";
19
21
  @import "./components/logo.css";
22
+ @import "./components/email.css";
20
23
  @import "./components/data-entry.css";
21
24
  @import "./components/shell.css";
25
+ @import "./components/sidebar.css";
26
+ @import "./components/legal-document.css";
@@ -4,11 +4,28 @@
4
4
  /* Horizontal inset of every slot (header / content / footer) + the resting top/bottom
5
5
  * shell padding. This is the column the title, body and footer all align to. */
6
6
  --card-space-inset: var(--space-section-active);
7
+ /* BLOCK-axis (top/bottom) shell padding of the slotted card rhythm — a plain header's top, a
8
+ * `solo` body's top, and the terminal slot's bottom (gh#232). Split off --card-space-inset so a
9
+ * shell (AuthShell compact) can retune the card's height WITHOUT moving the inline column.
10
+ * Declared `initial` — NOT `var(--card-space-inset)` — so the default resolves at the CALL SITE:
11
+ * a :root binding would freeze at the :root inset and `[data-density="tight"|"cozy"]` (which
12
+ * override --card-space-inset on the card element) would stop reaching it. See docs/TOKENS.md ·
13
+ * "Role-mirror knobs MUST be `initial`" — the same call-site rule applies to derived knobs. */
14
+ --card-space-shell-y: initial; /* default = var(--card-space-inset) */
7
15
  /* Vertical padding of a BANDED header band (top = bottom). Drives --card-space-divided-y. */
8
16
  --card-space-header-y: var(--space-stack-sm);
9
17
  /* Gap between the header and the body, and the body's own top padding — the breathing
10
18
  * room under a title before content begins. */
11
19
  --card-space-body-y: var(--space-section-active);
20
+ /* Symmetric block padding for a SOLO content slot, so a composed shell can tune block and
21
+ * inline spacing independently without targeting CardContent.
22
+ * Declared `initial` for the SAME reason as --card-space-shell-y above: written as
23
+ * `var(--card-space-inset)` here it would freeze at the :root inset, and a card carrying
24
+ * [data-density="tight"|"cozy"] (which override --card-space-inset ON THE CARD) would keep the
25
+ * :root value. The default now resolves at the call site through the chain
26
+ * solo-y → shell-y → inset, so a solo body follows the general block knob when only that is
27
+ * set, and an explicit solo-y still wins. */
28
+ --card-space-solo-y: initial; /* default = var(--card-space-shell-y, var(--card-space-inset)) */
12
29
  /* Vertical padding of a SEPARATED footer band (top = bottom). Drives --card-space-divided-y. */
13
30
  --card-space-footer-y: var(--space-stack-sm);
14
31
  /* DIVIDED-section vertical padding (rule #44/#45). A header/footer that carries a divider
@@ -75,4 +92,35 @@
75
92
  --stat-card-icon-background: initial;
76
93
  --stat-card-icon-foreground: initial;
77
94
  --stat-card-delta-font-size: var(--font-size-xs);
95
+ /* ── ServiceLauncherCard (gh#219) ───────────────────────────────────────────────────
96
+ * Internal rhythm of a launcher tile: one gap knob drives the vertical stack AND the
97
+ * icon↔title↔status row, so a service theme retunes the whole tile density once. */
98
+ --card-service-launcher-space-gap: var(--space-stack-sm);
99
+ /* Semantic icon surface. `--control-height-lg` is the 36px control tier the hi-fi calls for —
100
+ * a tier token, never a literal, so the medallion tracks --scaling with its sibling controls. */
101
+ --card-service-launcher-icon-size: var(--control-height-lg);
102
+ --card-service-launcher-icon-glyph-size: var(--space-5);
103
+ --card-service-launcher-icon-radius: var(--radius-md);
104
+ /* Available-service medallion tint. `initial` (role-mirror rule, docs/TOKENS.md) so the role
105
+ * defaults resolve at the CALL SITE and a scoped [data-tenant]/.dark override reaches them.
106
+ * Defaults = hsl(var(--accent)) fill · hsl(var(--primary)) glyph. */
107
+ --card-service-launcher-icon-background: initial;
108
+ --card-service-launcher-icon-foreground: initial;
109
+ /* Unavailable medallion tint — applied when the consumer supplies `disabledReason`, so an
110
+ * un-launchable service never reads as brand-live. `initial` for the same role-mirror reason.
111
+ * Defaults = hsl(var(--muted)) fill · hsl(var(--muted-foreground)) glyph. */
112
+ --card-service-launcher-unavailable-icon-background: initial;
113
+ --card-service-launcher-unavailable-icon-foreground: initial;
114
+ /* Description prose — also drives the disabled-reason line and the catalog-CTA caption. */
115
+ --card-service-launcher-description-font-size: var(--font-size-xs);
116
+ --card-service-launcher-description-line-height: var(--line-height-body);
117
+ /* Mono metadata line (hostname · plan) — tighter leading than prose by design. */
118
+ --card-service-launcher-metadata-font-size: var(--font-size-xs);
119
+ --card-service-launcher-metadata-line-height: var(--line-height-normal);
120
+ /* Dashed catalog/add companion tile: kept tall enough to sit level with a populated launcher
121
+ * tile in the same grid row. Four control tiers ≈ medallion + title + description + action. */
122
+ --card-service-launcher-cta-min-height: calc(var(--control-height-lg) * 4);
123
+ /* Skeleton bar widths — shape-matched placeholders for the title and status badge. */
124
+ --card-service-launcher-skeleton-title-width: var(--space-12);
125
+ --card-service-launcher-skeleton-status-width: var(--space-10);
78
126
  }
@@ -0,0 +1,47 @@
1
+ /* Chart component tokens — the dependency-free `CompactBarTrend` primitive
2
+ * (`@godxjp/ui/charts`). Every piece of its geometry and every fill is a public knob so a
3
+ * service theme can match its own design grid WITHOUT page-local CSS or inline heights
4
+ * (cardinal rules #44/#45). The recharts-backed charts draw their own SVG and only use the
5
+ * foundation `--chart-1..6` palette. */
6
+
7
+ :root {
8
+ /* ── Plot height tiers (size = xs|sm|md|lg) ───────────────────────────────────────────
9
+ * `xs` is the canonical dashboard-summary-card density: a seven-day trend that sits under
10
+ * a KPI headline without stealing its vertical rhythm. A service retunes the whole scale
11
+ * here; a screen picks a step with the `size` prop. */
12
+ --chart-trend-plot-height-xs: 3.5rem;
13
+ --chart-trend-plot-height-sm: 5rem;
14
+ --chart-trend-plot-height-md: 7.5rem;
15
+ --chart-trend-plot-height-lg: 10rem;
16
+ /* Active tier — chart-layout.css re-points this per `data-size`; overriding it directly
17
+ * pins one height for every trend regardless of `size`. */
18
+ --chart-trend-plot-height: var(--chart-trend-plot-height-xs);
19
+
20
+ /* ── Bar marks ────────────────────────────────────────────────────────────────────────
21
+ * Thin marks, a surface gap between neighbours and a rounded data-end anchored to the
22
+ * baseline (the data-visualization mark spec). */
23
+ --chart-trend-bar-gap: var(--space-2);
24
+ --chart-trend-bar-radius: var(--radius-sm);
25
+ /* Ceiling on a single mark so a 3-point trend does not render slabs. */
26
+ --chart-trend-bar-max-width: 1.5rem;
27
+ /* Floor so a zero/absent value still reads as a plotted category rather than a hole. */
28
+ --chart-trend-bar-min-height: 2px;
29
+ /* Muted mark fill — role-mirror knob, declared `initial` so the role default re-resolves
30
+ * at the CALL SITE under `.dark` / `[data-tenant]` (docs/TOKENS.md · "Role-mirror knobs
31
+ * MUST be `initial`"). Default = hsl(var(--muted-foreground) / 0.75), which clears the
32
+ * 3:1 non-text contrast floor (WCAG 1.4.11) against the card surface. */
33
+ --chart-trend-bar-background: initial;
34
+ /* Opacity applied to the muted-fill role default. */
35
+ --chart-trend-bar-background-alpha: 0.75;
36
+ /* Emphasized ("current") mark fill — role-mirror knob. Default = hsl(var(--primary)). */
37
+ --chart-trend-bar-emphasis-background: initial;
38
+
39
+ /* ── Baseline + category ticks ────────────────────────────────────────────────────────
40
+ * Chrome defaults QUIET (rule #44): no baseline rule at rest. A service opts in with
41
+ * `--chart-trend-baseline-border: 1px solid hsl(var(--border));`. */
42
+ --chart-trend-baseline-border: initial;
43
+ --chart-trend-tick-gap: var(--space-1);
44
+ --chart-trend-tick-font-size: var(--font-size-xs);
45
+ /* Gap between the plot block and the optional activity footer slot. */
46
+ --chart-trend-footer-gap: var(--space-2);
47
+ }
@@ -58,6 +58,16 @@
58
58
  --slider-track-height: 0.375rem;
59
59
  --slider-thumb-size: 1rem;
60
60
 
61
+ /* InputOTP slot box (gh#233). Its own knob so an auth surface can widen the 6-slot challenge row
62
+ * to fill a wide panel WITHOUT re-scoping --control-height (which would resize every other
63
+ * control in the same card). Declared `initial` — the tier-mirror form of the role-mirror rule in
64
+ * docs/TOKENS.md: the default must resolve at the CALL SITE (`var(--otp-slot-size,
65
+ * var(--control-height))`), because `--otp-slot-size: var(--control-height)` here would FREEZE at
66
+ * the :root tier (32px) and an OTP row inside `.ui-auth-shell[data-variant="canonical"]`, which
67
+ * re-scopes --control-height to 36px, would silently shrink. Verified in Chromium: 36px before
68
+ * and after. A service opts in with a NAMED tier (`var(--control-height-lg)`), never a calc. */
69
+ --otp-slot-size: initial; /* default = var(--control-height) at the call site */
70
+
61
71
  /* Checked/on/active fills — `initial` so the --primary default re-resolves at the call site
62
72
  * under a scoped theme (a :root binding to var(--primary) freezes at the :root value and a scoped
63
73
  * [data-tenant] override of --primary never reaches it). A service retints the "selected" state
@@ -75,6 +85,12 @@
75
85
  --command-group-padding: var(--space-1);
76
86
  --command-item-padding-y: var(--space-2);
77
87
  --command-item-padding-x: var(--space-2);
88
+ --command-palette-width: 35rem;
89
+ --command-palette-inset-top: calc(var(--space-6) * 4);
90
+ --command-palette-viewport-inset: var(--space-3);
91
+ --command-palette-hint-padding-y: var(--space-2);
92
+ --command-palette-hint-padding-x: var(--space-4);
93
+ --command-palette-hint-gap: var(--space-4);
78
94
  --search-input-edge-inset: var(--space-3);
79
95
  --search-input-start-padding: calc(
80
96
  var(--search-input-edge-inset) + var(--control-icon-size) + var(--control-gap)
@@ -0,0 +1,66 @@
1
+ /* EMAIL component tokens — the geometry/typography half of the transactional-email contract
2
+ * (`@godxjp/ui/email`). HTML email cannot read CSS custom properties: Outlook/Gmail strip <style>
3
+ * blocks and require LITERAL inline values, so a Blade/Twig/MJML template can never `var()` these.
4
+ * They still live in the component tier because this is the ONE source a maintainer edits — the
5
+ * `@godxjp/ui/email` export is GENERATED from this file plus the colour roles in foundation.css
6
+ * (scripts/gen-email-tokens.mjs), so an email template and a web screen can never drift apart.
7
+ *
8
+ * Every value is a LITERAL px/number (never rem, never calc, never var): email clients resolve
9
+ * neither the cascade nor relative units reliably, and the export must serialise to a plain hex/px
10
+ * string. Where a value mirrors a web token the comment names it, so a retune stays traceable.
11
+ *
12
+ * Colours are deliberately NOT redeclared here — they derive from the semantic roles
13
+ * (--card/--background/--foreground/--muted/--border/--primary/--ring/--success) and are converted
14
+ * HSL→hex at module load, so a re-themed role re-tints the email with zero copy-paste.
15
+ */
16
+ :root {
17
+ /* ── Shell — the 480px transactional-email geometry ─────────────────────────────────────── */
18
+ --email-shell-width: 480px; /* canonical transactional card width */
19
+ --email-shell-padding: 32px; /* card inset — mirrors --space-8 (2rem) */
20
+ --email-shell-page-padding: 24px; /* gutter between the client viewport and the card (--space-6) */
21
+ --email-shell-border-width: 1px; /* card edge — mirrors the 1px --border hairline */
22
+ --email-card-radius: 10px; /* mirrors --card-radius (--radius-xl = 6px × φ ≈ 10px) */
23
+ --email-card-reference-height: 407px; /* canonical invitation reference measures 480×407 */
24
+ --email-stack-gap: 24px; /* block rhythm — mirrors --space-stack-lg (1.5rem) */
25
+ --email-stack-gap-sm: 12px; /* tight rhythm — mirrors --space-3 (0.75rem) */
26
+
27
+ /* ── Brand mark — the canonical GoDX capsule (see EMAIL_BRAND_MARK) ─────────────────────── */
28
+ --email-mark-width: 32px; /* mirrors --logo-godx-size (2rem) */
29
+ --email-mark-height: 32px;
30
+
31
+ /* ── Typography — literal px so no client has to resolve the rem scale ──────────────────── */
32
+ --email-font-family-sans:
33
+ -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif;
34
+ --email-body-font-size: 14px; /* mirrors --font-size-base (0.875rem) */
35
+ --email-body-line-height: 1.7; /* mirrors --line-height-body */
36
+ --email-body-font-weight: 400; /* mirrors --font-weight-normal */
37
+ --email-heading-font-size: 20px; /* mirrors --heading-h1 (base × φ^¼³ ≈ 19.8px) */
38
+ --email-heading-line-height: 1.25; /* mirrors --line-height-tight */
39
+ --email-heading-font-weight: 700; /* mirrors --font-weight-bold */
40
+
41
+ /* ── Primary CTA — the one action button ────────────────────────────────────────────────── */
42
+ --email-cta-height: 44px; /* mirrors --control-height-comfortable (2.75rem coarse-pointer target) */
43
+ --email-cta-line-height: 44px; /* equal to the height: bulletproof vertical centring in Outlook */
44
+ --email-cta-padding-x: 24px; /* mirrors --space-6 */
45
+ --email-cta-radius: 6px; /* mirrors the --radius base (0.375rem) */
46
+ --email-cta-font-size: 14px; /* mirrors --font-size-base */
47
+ --email-cta-font-weight: 700; /* mirrors --font-weight-bold */
48
+
49
+ /* ── Legal footer ───────────────────────────────────────────────────────────────────────── */
50
+ --email-footer-font-size: 12px; /* mirrors --font-size-xs (base ÷ φ^¼ ≈ 12.5px) */
51
+ --email-footer-line-height: 1.5; /* mirrors --line-height-normal */
52
+ --email-footer-link-gap: 12px; /* horizontal separation between footer links (--space-3) */
53
+ --email-footer-padding-top: 20px; /* space above the legal band */
54
+ --email-footer-border-width: 1px; /* the hairline above the legal band */
55
+
56
+ /* ── Focus affordance (webmail preview panes that DO honour :focus) ─────────────────────── */
57
+ --email-focus-border-width: 2px; /* mirrors --focus-ring-width */
58
+
59
+ /* ── Mobile reflow — applied under the narrow media query and by inline fallbacks ───────── */
60
+ --email-mobile-max-width: 520px; /* the reflow breakpoint (card width + both gutters) */
61
+ --email-mobile-width: 100%; /* the card goes fluid below the breakpoint */
62
+ --email-mobile-padding: 20px; /* reduced card inset — mirrors --space-5 */
63
+ --email-mobile-page-padding: 12px; /* reduced viewport gutter — mirrors --space-3 */
64
+ --email-mobile-heading-font-size: 18px; /* mirrors --heading-h2 (base × φ^¼² ≈ 17.6px) */
65
+ --email-mobile-cta-width: 100%; /* the CTA goes full-bleed so the tap target spans the card */
66
+ }
@@ -1,6 +1,19 @@
1
1
  /* Feedback primitive tokens: dialog, alert, empty state. */
2
2
 
3
3
  :root {
4
+ --sheet-width-default: 22.5rem;
5
+ /* Overlay scrims — `initial` so the shared semantic --overlay-background re-resolves at the CALL
6
+ * SITE under a scoped [data-tenant]/.dark theme (a :root binding to it freezes at :root and a
7
+ * scoped override never reaches the overlay). Each surface takes a SHARE of that one scrim rather
8
+ * than a private literal, so a service retints every backdrop with one --overlay-background while
9
+ * the calibrated per-surface depth survives: a slide-in Sheet washes the page more lightly than a
10
+ * modal Dialog. Defaults resolve to rgb(0 0 0 / 0.2) (sheet) and rgb(0 0 0 / 0.3) (dialog). */
11
+ --sheet-overlay-background: initial;
12
+ --sheet-overlay-alpha: 40%;
13
+ --dialog-width-default: 32rem;
14
+ --dialog-viewport-inset: 1.5rem;
15
+ --dialog-overlay-background: initial;
16
+ --dialog-overlay-alpha: 60%;
4
17
  /* Dialog inset defaults to the shared global chrome tokens (override --space-chrome-* once for the
5
18
  * whole system, or --dialog-space-x/-y for dialogs only). */
6
19
  --dialog-space-x: var(--space-chrome-x);
@@ -22,6 +35,10 @@
22
35
  --dialog-content-glow: 0 0 0 0 transparent;
23
36
  --empty-state-space-y: var(--space-10);
24
37
  --empty-state-space-x: var(--space-6);
38
+ /* Measure of the description paragraph (rule #45 — a service-tunable constant gets a knob).
39
+ * 28rem reads ~65 Latin characters per line; a JA/VI service that needs a shorter or longer
40
+ * measure for its own copy retunes this once instead of forking `.ui-empty-state-description`. */
41
+ --empty-state-description-max-width: 28rem;
25
42
  --empty-state-section-space-y: var(--space-6);
26
43
  --empty-state-section-space-x: var(--space-4);
27
44
  --empty-state-compact-space-y: var(--space-3);
@@ -0,0 +1,67 @@
1
+ /* LegalDocumentShell component tokens — the long-form legal/policy document surface
2
+ * (terms of service, privacy policy, DPA, cookie policy, SLA, EULA) with a sticky
3
+ * table-of-contents rail.
4
+ *
5
+ * Rule #45 — every service-tunable constant is a knob: the readable measure, the rail
6
+ * width/offset, the section rhythm and the body leading are exactly the values a service
7
+ * theme wants to re-tune to match its design grid, so NONE of them are hard-coded in
8
+ * `src/styles/layout.css`.
9
+ *
10
+ * Rule #44 — chrome is a token, default QUIET: every divider (`*-border`) defaults to
11
+ * `none`. A service opts IN via theme, e.g.
12
+ * --legal-document-toc-border: 1px solid hsl(var(--border));
13
+ *
14
+ * Colour knobs whose default is a ROLE token are declared `initial` here with the role
15
+ * default at the CALL SITE (`var(--knob, var(--role))`) — see docs/TOKENS.md ·
16
+ * "Role-mirror knobs MUST be `initial`" — so a scoped `[data-tenant]` / `.dark`
17
+ * override of the role still reaches them.
18
+ */
19
+
20
+ :root {
21
+ /* ── Geometry ─────────────────────────────────────────────────────────────── */
22
+ /* Readable document measure. Caps the header, the section column and the footer so
23
+ * a 1440px viewport still reads at ~75-90 characters per line. */
24
+ --legal-document-measure-max-width: 46rem;
25
+ /* Rail ↔ document column gutter (two-column mode only). */
26
+ --legal-document-column-gap: var(--space-10);
27
+ /* Sticky table-of-contents rail width (two-column mode only). */
28
+ --legal-document-toc-width: 15rem;
29
+ /* Distance the pinned rail keeps from the top of the scrollport. */
30
+ --legal-document-toc-inset-block-start: var(--space-6);
31
+ /* Cap for a long contents list so the rail never outgrows the viewport. */
32
+ --legal-document-toc-max-height: calc(100dvh - var(--space-12));
33
+ --legal-document-toc-gap: var(--space-1);
34
+ --legal-document-toc-item-padding: var(--space-1) var(--space-2);
35
+ --legal-document-toc-item-radius: var(--radius);
36
+ --legal-document-toc-title-font-size: var(--font-size-2xs);
37
+ --legal-document-toc-font-size: var(--font-size-xs);
38
+ /* Leading marker on the active contents entry — a non-colour affordance so the
39
+ * active state is never colour-only (WCAG 1.4.1). */
40
+ --legal-document-toc-marker-width: 2px;
41
+ /* Gap between the `documentNavigation` slot and the contents list inside the rail. */
42
+ --legal-document-nav-gap: var(--space-4);
43
+ --legal-document-header-gap: var(--space-2);
44
+ --legal-document-meta-gap: var(--space-2);
45
+ --legal-document-meta-font-size: var(--font-size-xs);
46
+ --legal-document-section-gap: var(--space-10);
47
+ --legal-document-section-title-gap: var(--space-3);
48
+ /* Long-form leading — legal prose reads looser than UI text. */
49
+ --legal-document-body-line-height: 1.8;
50
+ /* `scroll-margin-block-start` on every section: the offset a hash jump / anchor
51
+ * activation leaves above the heading so it is not hidden under sticky chrome. */
52
+ --legal-document-scroll-offset: var(--space-6);
53
+ --legal-document-footer-gap: var(--space-4);
54
+
55
+ /* ── Chrome — quiet by default (rule #44) ─────────────────────────────────── */
56
+ --legal-document-toc-border: none;
57
+ --legal-document-header-border: none;
58
+ --legal-document-footer-border: none;
59
+
60
+ /* ── Role-mirror knobs — `initial` here, role default at the call site ─────── */
61
+ --legal-document-meta-foreground: initial; /* default = hsl(var(--muted-foreground)) */
62
+ --legal-document-summary-foreground: initial; /* default = hsl(var(--muted-foreground)) */
63
+ --legal-document-toc-foreground: initial; /* default = hsl(var(--muted-foreground)) */
64
+ --legal-document-toc-active-foreground: initial; /* default = hsl(var(--foreground)) */
65
+ --legal-document-toc-active-background: initial; /* default = hsl(var(--accent)) */
66
+ --legal-document-toc-marker-color: initial; /* default = hsl(var(--primary)) */
67
+ }
@@ -1,6 +1,7 @@
1
1
  /* ListRow component tokens — a single-line entity row for short lists inside a Card
2
- * (sessions / API tokens / linked accounts / passkeys …). Sits in a flush CardContent;
3
- * rows separate with a quiet divider (#44 — chrome defaults to the calm semantic border). */
2
+ * (sessions / API tokens / linked accounts / passkeys / notifications …). Sits in a flush
3
+ * CardContent; rows separate with a quiet divider (#44 — chrome defaults to the calm
4
+ * semantic border). */
4
5
  :root {
5
6
  --list-row-padding-y: var(--space-3);
6
7
  --list-row-padding-x: var(--space-4);
@@ -8,4 +9,24 @@
8
9
  /* Row divider — `initial` so the --border default re-resolves at the call site under a scoped
9
10
  * theme (a :root binding to a role var freezes at :root). Default = 1px solid hsl(var(--border)). */
10
11
  --list-row-border: initial;
12
+ /* Inline size the content column keeps before the trailing actions wrap onto their own line
13
+ * (#45 — a service retunes the stack threshold to its grid). Clamped with min(…, 100%) at the
14
+ * call site, so a container narrower than the knob can never force page-root overflow (#224). */
15
+ --list-row-body-min-width: 12rem;
16
+ /* Gap BETWEEN trailing actions — they also wrap among themselves at narrow widths (#224). */
17
+ --list-row-trailing-gap: var(--space-2);
18
+ /* Read (default) row surface — `initial`, documented default = transparent, i.e. the Card
19
+ * surface shows through untouched (#44 — chrome defaults to the quietest state). */
20
+ --list-row-read-background: initial;
21
+ /* Unread emphasis surface (`unread` rows) — `initial` so the --muted default re-resolves at the
22
+ * call site under a scoped theme. Documented default = hsl(var(--muted)), the same quiet
23
+ * emphasis role the table header uses; it keeps the xs muted description line at WCAG AA
24
+ * (4.63:1 light / 5.47:1 dark), which hsl(var(--accent)) would not (4.23:1 light). */
25
+ --list-row-unread-background: initial;
26
+ /* Unread indicator dot fill — `initial` so the --primary default re-resolves at the call site
27
+ * under a scoped theme. Documented default = hsl(var(--primary)). */
28
+ --list-row-indicator-color: initial;
29
+ /* Diameter of the read/unread indicator dot; the gutter is reserved on read rows too so the
30
+ * titles of a mixed list stay on one optical axis. */
31
+ --list-row-indicator-size: var(--space-2);
11
32
  }
@@ -12,4 +12,36 @@
12
12
  --logo-font-size-sm: var(--font-size-xs);
13
13
  --logo-font-size-md: var(--font-size-sm);
14
14
  --logo-font-size-lg: var(--font-size-base);
15
+ /* Semantic identity fill is deliberately independent from --primary so a green brand mark never
16
+ * recolours primary buttons or links. Services can retune the role once for every Logo.
17
+ * ROLE-MIRROR KNOBS — declared `initial` here with the role default at the CALL SITE
18
+ * (logo-layout.css), so a scoped `.dark` / `[data-tenant]` override of --success actually
19
+ * reaches the mark instead of freezing at the :root value (docs/TOKENS.md ·
20
+ * "Role-mirror knobs MUST be `initial`"). Documented defaults:
21
+ * --logo-success-background = hsl(var(--success))
22
+ * --logo-success-foreground = hsl(var(--success-foreground))
23
+ * --logo-godx-color = hsl(var(--success)) */
24
+ --logo-success-background: initial;
25
+ --logo-success-foreground: initial;
26
+ --logo-godx-size: 2rem;
27
+ --logo-godx-color: initial;
28
+
29
+ /* ── Wordmark / lockup (`<Logo wordmark="GoDX" />`) ─────────────────────────────────────────
30
+ * The readable product name set beside the mark. The package ships NO wordmark artwork: the
31
+ * wordmark is typeset in the design-system display face, so a service retunes face, weight,
32
+ * tracking, size and the mark↔wordmark gap here instead of writing page CSS. The colour is a
33
+ * role-mirror knob whose default is the IDENTITY role (never --primary): the GoDX/`success`
34
+ * lockup is brand-green out of the box, and every other lockup reads --foreground.
35
+ * Documented defaults: --logo-wordmark-font-family = var(--font-family-display);
36
+ * --logo-wordmark-color = hsl(var(--foreground)), or hsl(var(--success)) on the
37
+ * godx / tone="success" lockup. */
38
+ --logo-wordmark-gap: var(--space-2);
39
+ --logo-wordmark-font-size-xs: var(--font-size-xs);
40
+ --logo-wordmark-font-size-sm: var(--font-size-sm);
41
+ --logo-wordmark-font-size-md: var(--font-size-base);
42
+ --logo-wordmark-font-size-lg: var(--font-size-lg);
43
+ --logo-wordmark-font-weight: 700;
44
+ --logo-wordmark-letter-spacing: -0.01em;
45
+ --logo-wordmark-font-family: initial;
46
+ --logo-wordmark-color: initial;
15
47
  }
@@ -10,6 +10,15 @@
10
10
  --filter-label-font-size: var(--font-size-xs);
11
11
  --filter-picker-width-sm: 11rem;
12
12
  --filter-picker-width-md: 14rem;
13
+
14
+ /* AppSettingPicker `compact` (gh#217) — the small, content-hugging labelled trigger used in an
15
+ * auth/legal footer, where the square icon-only default reads as a stray button and the full
16
+ * labelled trigger is too tall. Box height comes from the official --control-height-sm tier (never
17
+ * a literal / ad-hoc calc), and every other knob is themeable (rule #45). */
18
+ --app-setting-picker-compact-control-height: var(--control-height-sm);
19
+ --app-setting-picker-compact-padding-x: var(--space-2);
20
+ --app-setting-picker-compact-gap: var(--space-1);
21
+ --app-setting-picker-compact-font-size: var(--font-size-xs);
13
22
  --breadcrumb-font-size: var(--font-size-xs);
14
23
  --menubar-shortcut-font-size: var(--font-size-xs);
15
24
  --tabs-list-max-inline-size: 100%;
@@ -27,4 +36,8 @@
27
36
  /* Fill painted only when the filter strip is pinned. Role-mirror knob (rule #45): `initial`
28
37
  * so --background re-resolves at the call site under a scoped [data-tenant]/.dark theme. */
29
38
  --filter-bar-sticky-background: initial;
39
+ /* Scrollbar gutter reserved under a `overflow="scroll"` filter strip (#216) so the inline
40
+ * scrollbar never overlaps the controls. Rule #45 — a service theme retunes it to its grid
41
+ * (0 on an overlay-scrollbar platform). */
42
+ --filter-bar-scroll-padding-y: var(--space-1);
30
43
  }
@@ -0,0 +1,19 @@
1
+ /* Sheet RESPONSIVE (drawer / detail-panel) geometry.
2
+ *
3
+ * Lives in its own tier file rather than in feedback.css because these two knobs are the
4
+ * *responsive* contract (`SheetContent responsive="auto"`), not the static panel chrome —
5
+ * see feedback.css for --sheet-width-default / --sheet-pad-* / --sheet-overlay-background.
6
+ */
7
+
8
+ :root {
9
+ /* Viewport width at and below which `SheetContent responsive="auto"` renders the mobile bottom
10
+ * sheet instead of the desktop side panel. Read at runtime by useSheetResponsiveMode() (a CSS
11
+ * @media cannot resolve a custom property), so a service moves the drawer breakpoint from ONE
12
+ * knob for every overlay that opts into the responsive contract — Sheet and OrgSwitcher alike.
13
+ * 48rem = 768px mirrors the library's canonical mobile line (useIsMobile). Accepts px/rem/em. */
14
+ --sheet-responsive-breakpoint-width: 48rem;
15
+ /* Block size cap for the responsive BOTTOM presentation only (never for a plain
16
+ * `side="bottom"` sheet, which stays content-sized). Keeps the sheet below the viewport so the
17
+ * SheetBody scrolls and the page behind it stays visible/dismissable. */
18
+ --sheet-bottom-max-height: 85dvh;
19
+ }