kmcom-nuxt-layers 2.6.2 → 2.7.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 (114) hide show
  1. package/docs/ARCHITECTURE.md +21 -17
  2. package/docs/FEEDS.md +42 -34
  3. package/docs/IMPROVE-AUDIT-README.md +9 -10
  4. package/docs/IMPROVE-AUDIT-RESULTS.md +16 -17
  5. package/docs/IMPROVE-DEEP-AUDIT-RESULTS.md +29 -29
  6. package/docs/LAYERS-FIXES.md +1 -0
  7. package/docs/LAYOUT.md +91 -86
  8. package/docs/MIGRATION.md +93 -60
  9. package/docs/UPAGE-GRID-INTEGRATION.md +12 -10
  10. package/docs/USAGE.md +29 -38
  11. package/layers/animations/app/utils/pointerMotion.ts +1 -4
  12. package/layers/baseline/app/components/BaselineStatus.vue +13 -13
  13. package/layers/baseline/app/plugins/baseline-status.client.ts +4 -1
  14. package/layers/canvas/app/composables/useRendererCapabilities.ts +2 -2
  15. package/layers/content/app/components/Blog/Card.vue +1 -0
  16. package/layers/content/app/components/Gallery/Card.vue +1 -1
  17. package/layers/content/app/components/Gallery/Detail.vue +8 -1
  18. package/layers/content/app/components/Portfolio/Card.vue +1 -0
  19. package/layers/content/app/components/Portfolio/ColorPalette.vue +8 -1
  20. package/layers/content/app/components/Portfolio/Typography.vue +12 -2
  21. package/layers/content/app/composables/useGalleryItems.ts +3 -2
  22. package/layers/content/app/composables/usePortfolioItems.ts +3 -2
  23. package/layers/core/app/components/DiagnosticsPage.vue +15 -3
  24. package/layers/core/app/utils/featureClasses.test.ts +1 -3
  25. package/layers/core/app/utils/featureClasses.ts +1 -3
  26. package/layers/core/app/utils/helpers.test.ts +6 -2
  27. package/layers/core/nuxt.config.ts +2 -0
  28. package/layers/feeds/app/assets/css/feeds.css +3 -2
  29. package/layers/feeds/app/components/Feeds/Index.vue +36 -6
  30. package/layers/feeds/app/components/Feeds/RouteCard.vue +1 -3
  31. package/layers/feeds/app/plugins/feed-head.ts +2 -2
  32. package/layers/feeds/package.json +1 -1
  33. package/layers/feeds/public/feed/style.css +9 -9
  34. package/layers/feeds/server/utils/content-adapter.test.ts +3 -4
  35. package/layers/feeds/server/utils/content-adapter.ts +1 -1
  36. package/layers/feeds/server/utils/feed-author.test.ts +3 -3
  37. package/layers/feeds/server/utils/feed-config.test.ts +28 -6
  38. package/layers/feeds/server/utils/feed-config.ts +1 -4
  39. package/layers/feeds/server/utils/feed-service.ts +1 -1
  40. package/layers/feeds/server/utils/formats/rss.ts +1 -1
  41. package/layers/feeds/server/utils/formats.test.ts +1 -1
  42. package/layers/forms/app/utils/fieldProps.ts +1 -2
  43. package/layers/forms/server/api/contact.post.ts +4 -1
  44. package/layers/layout/app/assets/css/layout/grids.css +12 -3
  45. package/layers/layout/app/assets/css/layout/modes/fluid.css +9 -0
  46. package/layers/layout/app/components/Layout/Section/Sidebar.vue +11 -4
  47. package/layers/layout/app/utils/gridPlacementStyle.test.ts +3 -9
  48. package/layers/layout/app/utils/gridPlacementStyle.ts +10 -7
  49. package/layers/mailer/server/utils/email.ts +4 -3
  50. package/layers/mailer/server/utils/hooks.ts +1 -1
  51. package/layers/metadata/app/composables/useMetadataItem.ts +6 -2
  52. package/layers/metadata/app/composables/useMetadataSearch.ts +6 -2
  53. package/layers/metadata/providers/comicvine/server/utils/metadata-comicvine/client.ts +5 -5
  54. package/layers/metadata/providers/comicvine/server/utils/metadata-comicvine/provider.ts +11 -3
  55. package/layers/metadata/providers/google-books/server/utils/metadata-google-books/client.ts +9 -6
  56. package/layers/metadata/providers/google-books/server/utils/metadata-google-books/provider.ts +6 -3
  57. package/layers/metadata/providers/openlibrary/server/utils/metadata-openlibrary/normalise.test.ts +3 -1
  58. package/layers/metadata/providers/openlibrary/server/utils/metadata-openlibrary/provider.ts +4 -2
  59. package/layers/metadata/providers/themoviedb/server/utils/metadata-tmdb/client.test.ts +1 -3
  60. package/layers/metadata/providers/themoviedb/server/utils/metadata-tmdb/provider.ts +3 -1
  61. package/layers/metadata/server/api/metadata/status.get.ts +13 -18
  62. package/layers/metadata/server/utils/metadata/provider-registry.test.ts +1 -1
  63. package/layers/metadata/server/utils/metadata/search.test.ts +18 -18
  64. package/layers/metadata/server/utils/metadata/search.ts +16 -8
  65. package/layers/navigation/app/utils/site.test.ts +1 -3
  66. package/layers/scroll/app/components/Motion/PinnedSection.vue +11 -1
  67. package/layers/scroll/app/composables/useSectionProgress.ts +1 -1
  68. package/layers/scroll/app/plugins/locomotive-scroll.client.ts +6 -0
  69. package/layers/scroll/app/utils/scroll.ts +5 -1
  70. package/layers/seo/app/utils/seoConfig.test.ts +1 -1
  71. package/layers/shader/app/assets/css/shader.css +1 -1
  72. package/layers/shader/app/components/Material/AmbientAurora.client.vue +16 -4
  73. package/layers/shader/app/components/Material/AmbientFlow.client.vue +21 -5
  74. package/layers/shader/app/components/Material/AmbientGradientMesh.client.vue +21 -5
  75. package/layers/shader/app/components/Material/AmbientNebula.client.vue +21 -5
  76. package/layers/shader/app/components/Material/AmbientOcean.client.vue +16 -4
  77. package/layers/shader/app/components/Material/Gradient.client.vue +1 -1
  78. package/layers/shader/app/components/Material/Image.client.vue +1 -1
  79. package/layers/shader/app/components/Material/Noise.client.vue +11 -3
  80. package/layers/shader/app/composables/useAmbientMaterials.ts +0 -1
  81. package/layers/shader/app/shaders/common/blend.ts +5 -1
  82. package/layers/shader/app/shaders/common/grain.ts +5 -1
  83. package/layers/shader/app/shaders/common/lighting.ts +1 -6
  84. package/layers/shader/app/shaders/common/noise.ts +3 -1
  85. package/layers/shader/app/shaders/common/patterns.ts +1 -1
  86. package/layers/shader/app/shaders/common/shapes.ts +5 -1
  87. package/layers/shader/app/shaders/common/uv.ts +19 -2
  88. package/layers/shader/app/shaders/createMaterial.ts +11 -6
  89. package/layers/shader/app/shaders/layers/shaderGradient.ts +2 -12
  90. package/layers/shader/app/shaders/types.ts +1 -1
  91. package/layers/shader/app/types/uniforms.ts +1 -0
  92. package/layers/shader/app/utils/tsl/animation.ts +34 -36
  93. package/layers/starter/app/components/StarterDesignSystem.vue +120 -120
  94. package/layers/starter/app/components/StarterHome.vue +233 -208
  95. package/layers/theme/app/assets/css/theme.css +1 -1
  96. package/layers/theme/server/utils/accent-css.test.ts +17 -2
  97. package/layers/theme/server/utils/fouc-config.test.ts +7 -3
  98. package/layers/theme/server/utils/fouc-config.ts +24 -12
  99. package/layers/transitions/app/assets/css/transitions.css +6 -0
  100. package/layers/typography/app/assets/css/typography.css +313 -0
  101. package/layers/typography/app/components/Typography/Headline.vue +23 -14
  102. package/layers/typography/app/components/Typography/HeadlineScreen.vue +5 -12
  103. package/layers/typography/app/components/Typography/index.vue +4 -0
  104. package/layers/typography/app/composables/typography.ts +45 -5
  105. package/layers/typography/app/types/typography.ts +36 -7
  106. package/layers/typography/nuxt.config.ts +2 -0
  107. package/layers/visual/app/app.config.ts +1 -1
  108. package/layers/visual/app/assets/css/visual.css +1 -1
  109. package/layers/visual/app/composables/accent.ts +1 -2
  110. package/layers/visual/app/composables/tint.ts +1 -2
  111. package/layers/visual/app/types/media.ts +2 -2
  112. package/layers/visual/app/utils/gradientStyle.test.ts +1 -2
  113. package/layers/visual/app/utils/responsiveSizes.ts +0 -1
  114. package/package.json +36 -16
@@ -0,0 +1,313 @@
1
+ /*
2
+ * Loaded as its own global stylesheet (see layers/typography/nuxt.config.ts
3
+ * `css:` array), not @import-chained through core.css's Tailwind root — so
4
+ * @utility below is invisible to Tailwind unless this file is its own build
5
+ * root. theme+utilities only (no preflight) to avoid double-emitting the
6
+ * reset core.css already provides.
7
+ */
8
+ @import 'tailwindcss/theme' layer(theme);
9
+ @import 'tailwindcss/utilities' layer(utilities);
10
+
11
+ @source '../../../../*/app/**/*.{vue,ts}';
12
+ @source '../../../../../apps/*/app/**/*.{vue,ts}';
13
+
14
+ :root {
15
+ /* Fluid type scale — rounding interval. rem, never px (see §5 a11y). */
16
+ --fluid-step: 0.25rem;
17
+
18
+ /* Unrounded fluid ranges. Endpoints MUST be integer multiples of --fluid-step. */
19
+ --fluid-text-xs-raw: clamp(0.5rem, 0.475rem + 0.1vi, 0.75rem);
20
+ --fluid-text-sm-raw: clamp(0.75rem, 0.7rem + 0.15vi, 1rem);
21
+ --fluid-text-md-raw: clamp(1rem, 0.9375rem + 0.35vi, 1.25rem);
22
+ --fluid-text-lg-raw: clamp(1.25rem, 1.125rem + 0.75vi, 1.75rem);
23
+ --fluid-text-xl-raw: clamp(1.5rem, 1.25rem + 1.5vi, 2.5rem);
24
+ --fluid-text-2xl-raw: clamp(2rem, 1.5rem + 2.5vi, 3.5rem);
25
+ --fluid-text-3xl-raw: clamp(2.5rem, 1.75rem + 4vi, 5rem);
26
+ --fluid-text-4xl-raw: clamp(3rem, 2rem + 5vi, 6rem);
27
+ --fluid-text-5xl-raw: clamp(3.75rem, 2.5rem + 6.5vi, 7.5rem);
28
+ --fluid-text-6xl-raw: clamp(4.5rem, 3rem + 8vi, 9rem);
29
+ --fluid-text-7xl-raw: clamp(5.5rem, 3.5rem + 10vi, 11rem);
30
+ --fluid-text-8xl-raw: clamp(6.75rem, 4rem + 14vi, 13.5rem);
31
+ --fluid-text-9xl-raw: clamp(8rem, 4.5rem + 20vi, 16rem);
32
+
33
+ /* Damp heading growth under large OS text-scale prefs (>100%) so words
34
+ don't break to one-per-line. Root font-size (rem) already scales by
35
+ env(preferred-text-scale); this backs that out then re-applies it at
36
+ half rate. No-op at 100% scale or without support (env() undefined → 1). */
37
+ --heading-text-scale-damp: calc(1 + (env(preferred-text-scale, 1) - 1) * 0.5);
38
+
39
+ /* Container-relative counterparts — same rem endpoints, cqi instead of vi.
40
+ Require a `container-type` ancestor (e.g. `@container`); with none, cqi
41
+ falls back to the small viewport per spec, so these are opt-in, not a
42
+ replacement for the vi-based scale above. */
43
+ /* Coefficients retuned vs the vi scale (not a straight port): small steps'
44
+ min→max diff is only 0.25-0.5rem (1-2 --fluid-step increments), so vi's
45
+ slope needs 250+rem of container width to cross even one rounding step —
46
+ reads as frozen. Retuned so the full min→max transition happens between
47
+ an 8rem and 24rem container (the actual draggable range in practice). */
48
+ --fluid-text-xs-cq-raw: clamp(0.5rem, 0.375rem + 1.5625cqi, 0.75rem);
49
+ --fluid-text-sm-cq-raw: clamp(0.75rem, 0.625rem + 1.5625cqi, 1rem);
50
+ --fluid-text-md-cq-raw: clamp(1rem, 0.875rem + 1.5625cqi, 1.25rem);
51
+ --fluid-text-lg-cq-raw: clamp(1.25rem, 1rem + 3.125cqi, 1.75rem);
52
+ --fluid-text-xl-cq-raw: clamp(1.5rem, 1.25rem + 1.5cqi, 2.5rem);
53
+ --fluid-text-2xl-cq-raw: clamp(2rem, 1.5rem + 2.5cqi, 3.5rem);
54
+ --fluid-text-3xl-cq-raw: clamp(2.5rem, 1.75rem + 4cqi, 5rem);
55
+ --fluid-text-4xl-cq-raw: clamp(3rem, 2rem + 5cqi, 6rem);
56
+ --fluid-text-5xl-cq-raw: clamp(3.75rem, 2.5rem + 6.5cqi, 7.5rem);
57
+ --fluid-text-6xl-cq-raw: clamp(4.5rem, 3rem + 8cqi, 9rem);
58
+ --fluid-text-7xl-cq-raw: clamp(5.5rem, 3.5rem + 10cqi, 11rem);
59
+ --fluid-text-8xl-cq-raw: clamp(6.75rem, 4rem + 14cqi, 13.5rem);
60
+ --fluid-text-9xl-cq-raw: clamp(8rem, 4.5rem + 20cqi, 16rem);
61
+ }
62
+
63
+ /*
64
+ * Fluid type utilities, parallel to Tailwind's --text-* namespace.
65
+ * Do not override --text-xs..--text-9xl — Nuxt UI components consume those.
66
+ * round() must live in the utility declaration (not a custom property) so
67
+ * var(--fluid-step) resolves per-element, not frozen at :root.
68
+ */
69
+ @utility text-fluid-xs {
70
+ font-size: var(--fluid-text-xs-raw);
71
+ line-height: 1.5;
72
+
73
+ @supports (font-size: round(1rem, 1rem)) {
74
+ font-size: round(down, var(--fluid-text-xs-raw), var(--fluid-step));
75
+ }
76
+ }
77
+
78
+ @utility text-fluid-sm {
79
+ font-size: var(--fluid-text-sm-raw);
80
+ line-height: 1.45;
81
+
82
+ @supports (font-size: round(1rem, 1rem)) {
83
+ font-size: round(down, var(--fluid-text-sm-raw), var(--fluid-step));
84
+ }
85
+ }
86
+
87
+ @utility text-fluid-md {
88
+ font-size: var(--fluid-text-md-raw);
89
+ line-height: 1.4;
90
+
91
+ @supports (font-size: round(1rem, 1rem)) {
92
+ font-size: round(down, var(--fluid-text-md-raw), var(--fluid-step));
93
+ }
94
+ }
95
+
96
+ @utility text-fluid-lg {
97
+ font-size: var(--fluid-text-lg-raw);
98
+ line-height: 1.25;
99
+
100
+ @supports (font-size: round(1rem, 1rem)) {
101
+ font-size: round(down, var(--fluid-text-lg-raw), var(--fluid-step));
102
+ }
103
+ }
104
+
105
+ @utility text-fluid-xl {
106
+ font-size: var(--fluid-text-xl-raw);
107
+ line-height: 1.15;
108
+
109
+ @supports (font-size: round(1rem, 1rem)) {
110
+ font-size: round(down, var(--fluid-text-xl-raw), var(--fluid-step));
111
+ }
112
+ }
113
+
114
+ @utility text-fluid-2xl {
115
+ font-size: var(--fluid-text-2xl-raw);
116
+ line-height: 1.1;
117
+
118
+ @supports (font-size: round(1rem, 1rem)) {
119
+ font-size: round(down, var(--fluid-text-2xl-raw), var(--fluid-step));
120
+ }
121
+ }
122
+
123
+ @utility text-fluid-3xl {
124
+ font-size: var(--fluid-text-3xl-raw);
125
+ line-height: 1.05;
126
+
127
+ @supports (font-size: round(1rem, 1rem)) {
128
+ font-size: round(down, var(--fluid-text-3xl-raw), var(--fluid-step));
129
+ }
130
+ }
131
+
132
+ @utility text-fluid-4xl {
133
+ font-size: calc(var(--fluid-text-4xl-raw) * var(--heading-text-scale-damp));
134
+ line-height: 1;
135
+
136
+ @supports (font-size: round(1rem, 1rem)) {
137
+ font-size: calc(
138
+ round(down, var(--fluid-text-4xl-raw), var(--fluid-step)) * var(--heading-text-scale-damp)
139
+ );
140
+ }
141
+ }
142
+
143
+ @utility text-fluid-5xl {
144
+ font-size: calc(var(--fluid-text-5xl-raw) * var(--heading-text-scale-damp));
145
+ line-height: 1;
146
+
147
+ @supports (font-size: round(1rem, 1rem)) {
148
+ font-size: calc(
149
+ round(down, var(--fluid-text-5xl-raw), var(--fluid-step)) * var(--heading-text-scale-damp)
150
+ );
151
+ }
152
+ }
153
+
154
+ @utility text-fluid-6xl {
155
+ font-size: calc(var(--fluid-text-6xl-raw) * var(--heading-text-scale-damp));
156
+ line-height: 1;
157
+
158
+ @supports (font-size: round(1rem, 1rem)) {
159
+ font-size: calc(
160
+ round(down, var(--fluid-text-6xl-raw), var(--fluid-step)) * var(--heading-text-scale-damp)
161
+ );
162
+ }
163
+ }
164
+
165
+ @utility text-fluid-7xl {
166
+ font-size: calc(var(--fluid-text-7xl-raw) * var(--heading-text-scale-damp));
167
+ line-height: 1;
168
+
169
+ @supports (font-size: round(1rem, 1rem)) {
170
+ font-size: calc(
171
+ round(down, var(--fluid-text-7xl-raw), var(--fluid-step)) * var(--heading-text-scale-damp)
172
+ );
173
+ }
174
+ }
175
+
176
+ @utility text-fluid-8xl {
177
+ font-size: calc(var(--fluid-text-8xl-raw) * var(--heading-text-scale-damp));
178
+ line-height: 1;
179
+
180
+ @supports (font-size: round(1rem, 1rem)) {
181
+ font-size: calc(
182
+ round(down, var(--fluid-text-8xl-raw), var(--fluid-step)) * var(--heading-text-scale-damp)
183
+ );
184
+ }
185
+ }
186
+
187
+ @utility text-fluid-9xl {
188
+ font-size: calc(var(--fluid-text-9xl-raw) * var(--heading-text-scale-damp));
189
+ line-height: 1;
190
+
191
+ @supports (font-size: round(1rem, 1rem)) {
192
+ font-size: calc(
193
+ round(down, var(--fluid-text-9xl-raw), var(--fluid-step)) * var(--heading-text-scale-damp)
194
+ );
195
+ }
196
+ }
197
+
198
+ @utility text-fluid-xs-cq {
199
+ font-size: var(--fluid-text-xs-cq-raw);
200
+ line-height: 1.5;
201
+
202
+ @supports (font-size: round(1rem, 1rem)) {
203
+ font-size: round(down, var(--fluid-text-xs-cq-raw), var(--fluid-step));
204
+ }
205
+ }
206
+
207
+ @utility text-fluid-sm-cq {
208
+ font-size: var(--fluid-text-sm-cq-raw);
209
+ line-height: 1.45;
210
+
211
+ @supports (font-size: round(1rem, 1rem)) {
212
+ font-size: round(down, var(--fluid-text-sm-cq-raw), var(--fluid-step));
213
+ }
214
+ }
215
+
216
+ @utility text-fluid-md-cq {
217
+ font-size: var(--fluid-text-md-cq-raw);
218
+ line-height: 1.4;
219
+
220
+ @supports (font-size: round(1rem, 1rem)) {
221
+ font-size: round(down, var(--fluid-text-md-cq-raw), var(--fluid-step));
222
+ }
223
+ }
224
+
225
+ @utility text-fluid-lg-cq {
226
+ font-size: var(--fluid-text-lg-cq-raw);
227
+ line-height: 1.25;
228
+
229
+ @supports (font-size: round(1rem, 1rem)) {
230
+ font-size: round(down, var(--fluid-text-lg-cq-raw), var(--fluid-step));
231
+ }
232
+ }
233
+
234
+ @utility text-fluid-xl-cq {
235
+ font-size: var(--fluid-text-xl-cq-raw);
236
+ line-height: 1.15;
237
+
238
+ @supports (font-size: round(1rem, 1rem)) {
239
+ font-size: round(down, var(--fluid-text-xl-cq-raw), var(--fluid-step));
240
+ }
241
+ }
242
+
243
+ @utility text-fluid-2xl-cq {
244
+ font-size: var(--fluid-text-2xl-cq-raw);
245
+ line-height: 1.1;
246
+
247
+ @supports (font-size: round(1rem, 1rem)) {
248
+ font-size: round(down, var(--fluid-text-2xl-cq-raw), var(--fluid-step));
249
+ }
250
+ }
251
+
252
+ @utility text-fluid-3xl-cq {
253
+ font-size: var(--fluid-text-3xl-cq-raw);
254
+ line-height: 1.05;
255
+
256
+ @supports (font-size: round(1rem, 1rem)) {
257
+ font-size: round(down, var(--fluid-text-3xl-cq-raw), var(--fluid-step));
258
+ }
259
+ }
260
+
261
+ @utility text-fluid-4xl-cq {
262
+ font-size: var(--fluid-text-4xl-cq-raw);
263
+ line-height: 1;
264
+
265
+ @supports (font-size: round(1rem, 1rem)) {
266
+ font-size: round(down, var(--fluid-text-4xl-cq-raw), var(--fluid-step));
267
+ }
268
+ }
269
+
270
+ @utility text-fluid-5xl-cq {
271
+ font-size: var(--fluid-text-5xl-cq-raw);
272
+ line-height: 1;
273
+
274
+ @supports (font-size: round(1rem, 1rem)) {
275
+ font-size: round(down, var(--fluid-text-5xl-cq-raw), var(--fluid-step));
276
+ }
277
+ }
278
+
279
+ @utility text-fluid-6xl-cq {
280
+ font-size: var(--fluid-text-6xl-cq-raw);
281
+ line-height: 1;
282
+
283
+ @supports (font-size: round(1rem, 1rem)) {
284
+ font-size: round(down, var(--fluid-text-6xl-cq-raw), var(--fluid-step));
285
+ }
286
+ }
287
+
288
+ @utility text-fluid-7xl-cq {
289
+ font-size: var(--fluid-text-7xl-cq-raw);
290
+ line-height: 1;
291
+
292
+ @supports (font-size: round(1rem, 1rem)) {
293
+ font-size: round(down, var(--fluid-text-7xl-cq-raw), var(--fluid-step));
294
+ }
295
+ }
296
+
297
+ @utility text-fluid-8xl-cq {
298
+ font-size: var(--fluid-text-8xl-cq-raw);
299
+ line-height: 1;
300
+
301
+ @supports (font-size: round(1rem, 1rem)) {
302
+ font-size: round(down, var(--fluid-text-8xl-cq-raw), var(--fluid-step));
303
+ }
304
+ }
305
+
306
+ @utility text-fluid-9xl-cq {
307
+ font-size: var(--fluid-text-9xl-cq-raw);
308
+ line-height: 1;
309
+
310
+ @supports (font-size: round(1rem, 1rem)) {
311
+ font-size: round(down, var(--fluid-text-9xl-cq-raw), var(--fluid-step));
312
+ }
313
+ }
@@ -3,6 +3,7 @@
3
3
  import { useTypography } from '../../composables/typography'
4
4
  import type { UiColors } from '../../types/colors'
5
5
  import type {
6
+ FluidFontSize,
6
7
  FontLeading,
7
8
  FontSize,
8
9
  FontSlant,
@@ -26,6 +27,7 @@
26
27
  transform = 'none',
27
28
  color = undefined,
28
29
  size = undefined,
30
+ fluidSize = undefined,
29
31
  class: classProp = '',
30
32
  } = defineProps<{
31
33
  level?: 1 | 2 | 3 | 4 | 5 | 6
@@ -38,23 +40,25 @@
38
40
  transform?: TextTransform
39
41
  color?: UiColors
40
42
  size?: FontSize
43
+ fluidSize?: FluidFontSize
41
44
  class?: string
42
45
  }>()
43
46
  const tag = computed(() => `h${level}` as const)
44
47
 
45
- const sizeClass = computed(() => {
46
- if (size) return null
48
+ // Fluid by default (continuous scaling, no mobile-first breakpoint step) —
49
+ // only used when the caller passes neither `size` nor `fluidSize`.
50
+ const defaultFluidSizes: Record<number, FluidFontSize> = {
51
+ 1: '6xl',
52
+ 2: '5xl',
53
+ 3: '4xl',
54
+ 4: '3xl',
55
+ 5: 'xl',
56
+ 6: 'lg',
57
+ }
47
58
 
48
- const sizes: Record<number, string> = {
49
- 1: 'text-4xl sm:text-5xl',
50
- 2: 'text-3xl sm:text-4xl',
51
- 3: 'text-2xl sm:text-3xl',
52
- 4: 'text-xl sm:text-2xl',
53
- 5: 'text-lg sm:text-xl',
54
- 6: 'text-base sm:text-lg',
55
- }
56
- return sizes[level]
57
- })
59
+ const appliedFluidSize = computed(() =>
60
+ size !== undefined ? undefined : (fluidSize ?? defaultFluidSizes[level])
61
+ )
58
62
 
59
63
  const { classes } = useTypography({
60
64
  weight: weight,
@@ -65,6 +69,7 @@
65
69
  align: align,
66
70
  transform: transform,
67
71
  ...(size !== undefined && { size: size }),
72
+ ...(appliedFluidSize.value !== undefined && { fluidSize: appliedFluidSize.value }),
68
73
  })
69
74
  const colorClass = useColor(color, 'text')
70
75
  </script>
@@ -79,8 +84,12 @@
79
84
  :tracking
80
85
  :align
81
86
  :transform
82
- :class="[sizeClass, classes, colorClass, classProp]"
83
- v-bind="{ ...(size !== undefined && { size: size }), ...$attrs }"
87
+ :class="[classes, colorClass, classProp]"
88
+ v-bind="{
89
+ ...(size !== undefined && { size: size }),
90
+ ...(appliedFluidSize !== undefined && { fluidSize: appliedFluidSize }),
91
+ ...$attrs,
92
+ }"
84
93
  >
85
94
  <slot />
86
95
  </Typography>
@@ -3,8 +3,8 @@
3
3
  import { useTypography } from '../../composables/typography'
4
4
  import type { UiColors } from '../../types/colors'
5
5
  import type {
6
+ FluidFontSize,
6
7
  FontLeading,
7
- FontScreenSize,
8
8
  FontSlant,
9
9
  FontTracking,
10
10
  FontWeight,
@@ -17,7 +17,7 @@
17
17
 
18
18
  const {
19
19
  level = 1,
20
- size = 'screen-xxl',
20
+ fluidSize = '2xl',
21
21
  weight = 'font-bold',
22
22
  width = 'font-stretch-normal',
23
23
  slant = 'normal',
@@ -29,7 +29,7 @@
29
29
  class: classProp = '',
30
30
  } = defineProps<{
31
31
  level?: 1 | 2 | 3 | 4 | 5 | 6
32
- size?: FontScreenSize
32
+ fluidSize?: FluidFontSize
33
33
  weight?: FontWeight
34
34
  width?: FontWidth
35
35
  slant?: FontSlant
@@ -43,14 +43,6 @@
43
43
 
44
44
  const tag = computed(() => `h${level}` as const)
45
45
 
46
- const sizeMap: Record<string, string> = {
47
- screen: 'text-screen',
48
- 'screen-xl': 'text-screen-xl',
49
- 'screen-xxl': 'text-screen-xxl',
50
- 'screen-xxxl': 'text-screen-xxxl',
51
- }
52
- const sizeClass = computed(() => sizeMap[size] ?? 'text-screen-xxl')
53
-
54
46
  const { classes } = useTypography({
55
47
  weight: weight,
56
48
  width: width,
@@ -59,13 +51,14 @@
59
51
  tracking: tracking,
60
52
  align: align,
61
53
  transform: transform,
54
+ fluidSize: fluidSize,
62
55
  })
63
56
 
64
57
  const colorClass = useColor(color, 'text')
65
58
  </script>
66
59
 
67
60
  <template>
68
- <component :is="tag" :class="[sizeClass, classes, colorClass, classProp]" v-bind="$attrs">
61
+ <component :is="tag" :class="[classes, colorClass, classProp]" v-bind="$attrs">
69
62
  <slot />
70
63
  </component>
71
64
  </template>
@@ -3,6 +3,7 @@
3
3
  import { useTypography } from '../../composables/typography'
4
4
  import type { UiColors } from '../../types/colors'
5
5
  import type {
6
+ FluidFontSize,
6
7
  FontLeading,
7
8
  FontSize,
8
9
  FontSlant,
@@ -27,6 +28,7 @@
27
28
  transform = 'none',
28
29
  color = undefined,
29
30
  size = 'base',
31
+ fluidSize = undefined,
30
32
  } = defineProps<{
31
33
  tag?: TypographyTag
32
34
  weight?: FontWeight
@@ -38,6 +40,7 @@
38
40
  transform?: TextTransform
39
41
  color?: UiColors
40
42
  size?: FontSize
43
+ fluidSize?: FluidFontSize
41
44
  }>()
42
45
  const { classes } = useTypography(() => ({
43
46
  weight,
@@ -48,6 +51,7 @@
48
51
  align,
49
52
  transform,
50
53
  size,
54
+ ...(fluidSize !== undefined && { fluidSize }),
51
55
  }))
52
56
  const colorClass = useColor(color, 'text')
53
57
  </script>
@@ -1,7 +1,7 @@
1
- import type { MaybeRefOrGetter } from 'vue'
2
- import { toValue } from 'vue'
1
+ import { toValue, type MaybeRefOrGetter } from 'vue'
3
2
 
4
3
  import type {
4
+ FluidFontSize,
5
5
  FontLeading,
6
6
  FontSize,
7
7
  FontSlant,
@@ -25,8 +25,8 @@ function normalizeAxis(
25
25
  const { prefix = '', fallback = '', numericFormatter } = options
26
26
 
27
27
  return typeof value === 'number'
28
- ? numericFormatter?.(value) ?? (prefix ? `${prefix}-[${value}]` : `[${value}]`)
29
- : value ?? fallback
28
+ ? (numericFormatter?.(value) ?? (prefix ? `${prefix}-[${value}]` : `[${value}]`))
29
+ : (value ?? fallback)
30
30
  }
31
31
 
32
32
  function getSizeClass(size: FontSize | undefined): string {
@@ -34,6 +34,42 @@ function getSizeClass(size: FontSize | undefined): string {
34
34
  return typeof size === 'number' ? `text-[${size}]` : `text-${size}`
35
35
  }
36
36
 
37
+ // Literal map, not template-literal interpolation — Tailwind's content scanner
38
+ // looks for complete class-name strings in source, so `text-fluid-${x}` is
39
+ // invisible to it and silently drops the utility.
40
+ const FLUID_SIZE_CLASSES: Record<FluidFontSize, string> = {
41
+ xs: 'text-fluid-xs',
42
+ sm: 'text-fluid-sm',
43
+ md: 'text-fluid-md',
44
+ lg: 'text-fluid-lg',
45
+ xl: 'text-fluid-xl',
46
+ '2xl': 'text-fluid-2xl',
47
+ '3xl': 'text-fluid-3xl',
48
+ '4xl': 'text-fluid-4xl',
49
+ '5xl': 'text-fluid-5xl',
50
+ '6xl': 'text-fluid-6xl',
51
+ '7xl': 'text-fluid-7xl',
52
+ '8xl': 'text-fluid-8xl',
53
+ '9xl': 'text-fluid-9xl',
54
+ 'xs-cq': 'text-fluid-xs-cq',
55
+ 'sm-cq': 'text-fluid-sm-cq',
56
+ 'md-cq': 'text-fluid-md-cq',
57
+ 'lg-cq': 'text-fluid-lg-cq',
58
+ 'xl-cq': 'text-fluid-xl-cq',
59
+ '2xl-cq': 'text-fluid-2xl-cq',
60
+ '3xl-cq': 'text-fluid-3xl-cq',
61
+ '4xl-cq': 'text-fluid-4xl-cq',
62
+ '5xl-cq': 'text-fluid-5xl-cq',
63
+ '6xl-cq': 'text-fluid-6xl-cq',
64
+ '7xl-cq': 'text-fluid-7xl-cq',
65
+ '8xl-cq': 'text-fluid-8xl-cq',
66
+ '9xl-cq': 'text-fluid-9xl-cq',
67
+ }
68
+
69
+ function getFluidSizeClass(fluidSize: FluidFontSize | undefined): string {
70
+ return fluidSize ? FLUID_SIZE_CLASSES[fluidSize] : ''
71
+ }
72
+
37
73
  export function useTypography(
38
74
  props: MaybeRefOrGetter<{
39
75
  weight?: FontWeight
@@ -44,6 +80,7 @@ export function useTypography(
44
80
  align?: TextAlign
45
81
  transform?: TextTransform
46
82
  size?: FontSize
83
+ fluidSize?: FluidFontSize
47
84
  }>
48
85
  ) {
49
86
  const classes = computed(() => {
@@ -72,7 +109,10 @@ export function useTypography(
72
109
  fallback: 'tracking-normal',
73
110
  }),
74
111
 
75
- getSizeClass(p.size),
112
+ // fluidSize is the parallel, opt-in namespace (see typography.css) — takes
113
+ // precedence over size when both are set, rather than emitting two
114
+ // conflicting font-size utilities.
115
+ p.fluidSize ? getFluidSizeClass(p.fluidSize) : getSizeClass(p.size),
76
116
 
77
117
  p.align ? `text-${p.align}` : '',
78
118
 
@@ -60,6 +60,42 @@ export type FontSize =
60
60
  | '9xl'
61
61
  | number
62
62
 
63
+ /* ======================================================
64
+ Fluid Font Size
65
+ - Stepped clamp() scale, parallel to Tailwind's --text-*
66
+ - Companion to text-fluid-* utilities (typography.css)
67
+ ====================================================== */
68
+
69
+ export type FluidFontSize =
70
+ | 'xs'
71
+ | 'sm'
72
+ | 'md'
73
+ | 'lg'
74
+ | 'xl'
75
+ | '2xl'
76
+ | '3xl'
77
+ | '4xl'
78
+ | '5xl'
79
+ | '6xl'
80
+ | '7xl'
81
+ | '8xl'
82
+ | '9xl'
83
+ // Container-relative (cqi) variants — require a `container-type` ancestor
84
+ // (e.g. `@container`), otherwise cqi resolves against the small viewport.
85
+ | 'xs-cq'
86
+ | 'sm-cq'
87
+ | 'md-cq'
88
+ | 'lg-cq'
89
+ | 'xl-cq'
90
+ | '2xl-cq'
91
+ | '3xl-cq'
92
+ | '4xl-cq'
93
+ | '5xl-cq'
94
+ | '6xl-cq'
95
+ | '7xl-cq'
96
+ | '8xl-cq'
97
+ | '9xl-cq'
98
+
63
99
  /* ======================================================
64
100
  Font Width
65
101
  - Semantic abstraction over wdth axis
@@ -112,13 +148,6 @@ export type FontTracking =
112
148
  | 'tracking-widest'
113
149
  | FontTrackingNumber
114
150
 
115
- /* ======================================================
116
- Screen-scale Font Sizes
117
- - Companion to text-screen-* fluid tokens
118
- ====================================================== */
119
-
120
- export type FontScreenSize = 'screen' | 'screen-xl' | 'screen-xxl' | 'screen-xxxl'
121
-
122
151
  /* ======================================================
123
152
  Text Layout
124
153
  ====================================================== */
@@ -8,6 +8,8 @@ export default defineNuxtConfig({
8
8
  '#layers/typography/types': `${import.meta.dirname}/app/types`,
9
9
  },
10
10
 
11
+ css: ['#layers/typography/app/assets/css/typography.css'],
12
+
11
13
  compatibilityDate: '2026-06-06',
12
14
 
13
15
  typescript: {
@@ -1,5 +1,5 @@
1
- import type { GradientConfig } from './types/gradient'
2
1
  import type { AccentSceneConfig } from './types/accent'
2
+ import type { GradientConfig } from './types/gradient'
3
3
 
4
4
  export default defineAppConfig({
5
5
  uiLayer: {
@@ -1,5 +1,5 @@
1
1
  .gradient-text {
2
- -webkit-background-clip: text;
2
+ background-clip: text;
3
3
  background-clip: text;
4
4
  color: transparent;
5
5
  }
@@ -1,5 +1,4 @@
1
- import type { ComputedRef, CSSProperties, MaybeRefOrGetter } from 'vue'
2
- import { toValue } from 'vue'
1
+ import { toValue, type ComputedRef, type CSSProperties, type MaybeRefOrGetter } from 'vue'
3
2
 
4
3
  import type { BlobBlur, BlobConfig } from '../types/accent'
5
4
  import { resolveUiColorToken } from '../utils/colorTokens'
@@ -1,5 +1,4 @@
1
- import type { ComputedRef, CSSProperties, MaybeRefOrGetter } from 'vue'
2
- import { toValue } from 'vue'
1
+ import { toValue, type ComputedRef, type CSSProperties, type MaybeRefOrGetter } from 'vue'
3
2
 
4
3
  import { TINT_LEVEL_OPACITY, type TintConfig } from '../types/tint'
5
4
 
@@ -1,3 +1,5 @@
1
+ import type { ComputedRef } from 'vue'
2
+
1
3
  /**
2
4
  * Media Types
3
5
  *
@@ -174,8 +176,6 @@ export type PictureProps = {
174
176
  decoding?: 'sync' | 'async' | 'auto'
175
177
  }
176
178
 
177
- import type { ComputedRef } from 'vue'
178
-
179
179
  /**
180
180
  * Return type for usePicture composable
181
181
  */
@@ -69,8 +69,7 @@ describe('buildGradientStyle', () => {
69
69
  it('builds a conic gradient', () => {
70
70
  const cfg: GradientConfig = { from, to, shape: 'conic' }
71
71
  expect(buildGradientStyle(cfg)).toEqual({
72
- backgroundImage:
73
- 'conic-gradient(var(--ui-color-primary-500), var(--ui-color-secondary-500))',
72
+ backgroundImage: 'conic-gradient(var(--ui-color-primary-500), var(--ui-color-secondary-500))',
74
73
  })
75
74
  })
76
75
  })
@@ -4,7 +4,6 @@ import {
4
4
  PHONE_BREAKPOINT_VALUES,
5
5
  TABLET_BREAKPOINT_VALUES,
6
6
  } from '../types/breakpoints'
7
-
8
7
  import type { ResponsiveSizes } from '../types/media'
9
8
 
10
9
  type BreakpointGroup = readonly [keyof ResponsiveSizes, number]