@kiva/kv-tokens 4.0.2 → 4.1.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.
- package/README.md +31 -0
- package/dist/make-kit/guidelines/Guidelines.md +13 -0
- package/dist/make-kit/guidelines/foundations/color-themes.md +317 -0
- package/dist/make-kit/guidelines/foundations/color.md +235 -0
- package/dist/make-kit/guidelines/foundations/layout.md +194 -0
- package/dist/make-kit/guidelines/foundations/radius.md +176 -0
- package/dist/make-kit/guidelines/foundations/spacing.md +210 -0
- package/dist/make-kit/guidelines/foundations/tailwind.md +226 -0
- package/dist/make-kit/guidelines/foundations/typography.md +257 -0
- package/dist/make-kit/guidelines/setup.md +34 -0
- package/dist/make-kit/styles.css +4912 -0
- package/package.json +8 -4
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# Kiva Tailwind
|
|
2
|
+
|
|
3
|
+
**When to use:** When authoring or reviewing Tailwind utility classes in any repo that uses the Kiva preset (kv-components, kiva/ui, and other consumers), when setting up the preset in a new project, when a Tailwind class behaves differently than stock Tailwind would suggest (e.g. tw-text-lg or tw-font-bold "not working"), or when modifying the design-token → Tailwind pipeline inside this monorepo. Read this for how the system works and how to use it; read color/spacing/radius/typography/layout for which value to choose.
|
|
4
|
+
|
|
5
|
+
## Source of truth
|
|
6
|
+
|
|
7
|
+
The canonical definition of Kiva's Tailwind setup is the **preset itself** — [`@kiva/kv-tokens/configs/tailwind.config.js`](../../configs/tailwind.config.js) — and the design tokens it compiles from. Unlike the design-intent skills (color, spacing, etc.), which describe Figma intent that code may temporarily lag, this skill describes **shipped mechanics**: how the preset reshapes Tailwind and how to author against it.
|
|
8
|
+
|
|
9
|
+
This skill deliberately **does not enumerate class values**. Exact scales drift as tokens change, and listing them here would duplicate the per-topic skills and the config. For specific values, read the config or the relevant skill:
|
|
10
|
+
|
|
11
|
+
- **[color](color.md)** / **[color-themes](color-themes.md)** — which color token, what the themes are.
|
|
12
|
+
- **[spacing](spacing.md)** — which spacing token for a given relationship.
|
|
13
|
+
- **[radius](radius.md)** — which corner radius per component.
|
|
14
|
+
- **[typography](typography.md)** — which text style, the type scale.
|
|
15
|
+
- **[layout](layout.md)** — the breakpoint/grid system and content placement.
|
|
16
|
+
|
|
17
|
+
Verify any specific class or value against the current config before depending on it.
|
|
18
|
+
|
|
19
|
+
## What the preset is (mental model)
|
|
20
|
+
|
|
21
|
+
Kiva does not ship a stylesheet you import — it ships a **Tailwind preset**: a partial `tailwind.config.js` that a consuming project merges into its own config via the `presets` array. Tailwind then generates utility classes from the merged result.
|
|
22
|
+
|
|
23
|
+
The preset is itself generated from design tokens. The full path a value travels:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
tokens/*.json (DTCG) → Style Dictionary build → dist/js/tokens.js
|
|
27
|
+
│ │
|
|
28
|
+
│ ▼
|
|
29
|
+
│ configs/tailwind.config.js (the preset)
|
|
30
|
+
│ │
|
|
31
|
+
└──────────────► dist/css/tokens.css ▼
|
|
32
|
+
(themed CSS custom properties) your project's tailwind.config.js
|
|
33
|
+
(presets: [tailwindConfig])
|
|
34
|
+
│
|
|
35
|
+
▼
|
|
36
|
+
generated tw-* utilities
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Two consequences worth internalizing up front:
|
|
40
|
+
|
|
41
|
+
1. **You author Tailwind utilities as normal** — the preset changes *which* utilities exist and what they resolve to, not *how* Tailwind works.
|
|
42
|
+
2. **Themable colors are not baked into the CSS at build time.** They compile to `var(--token)` references and are resolved at runtime from CSS custom properties (see [Color](#color-is-semantic-themable-and-runtime-resolved) below). This is the single biggest departure from stock Tailwind.
|
|
43
|
+
|
|
44
|
+
## Consuming the preset
|
|
45
|
+
|
|
46
|
+
This is the common case: a project that installs `@kiva/kv-tokens` and wants Kiva styling.
|
|
47
|
+
|
|
48
|
+
### 1. Install
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
npm i --save-dev @kiva/kv-tokens
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 2. Register the preset
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
// tailwind.config.js
|
|
58
|
+
import { tailwindConfig } from '@kiva/kv-tokens';
|
|
59
|
+
|
|
60
|
+
export default {
|
|
61
|
+
presets: [tailwindConfig],
|
|
62
|
+
content: [
|
|
63
|
+
// YOUR project's template globs — the preset does not set these for you
|
|
64
|
+
'./src/**/*.{vue,js,ts}',
|
|
65
|
+
],
|
|
66
|
+
};
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Two equivalent import paths exist:
|
|
70
|
+
|
|
71
|
+
- `import { tailwindConfig } from '@kiva/kv-tokens'` — named export from the package index.
|
|
72
|
+
- `import tailwindConfig from '@kiva/kv-tokens/tailwind'` — the config file directly, via the `./tailwind` export.
|
|
73
|
+
|
|
74
|
+
Use either. **You own `content`** — Tailwind purges any class it can't find in your templates, so an incomplete `content` glob is the most common reason a Kiva class "doesn't show up."
|
|
75
|
+
|
|
76
|
+
### 3. Make themable colors resolve (required for color to render)
|
|
77
|
+
|
|
78
|
+
Themable color utilities (`tw-bg-primary`, `tw-text-primary`, …) emit `rgb(var(--bg-primary))`-style values. Those custom properties must exist on the page. The preset already injects the **default theme** onto `:root` via its base layer, so a project that registers the preset gets working colors out of the box.
|
|
79
|
+
|
|
80
|
+
To switch themes, swap the custom-property values for a subtree. In `@kiva/kv-components` this is done by `KvThemeProvider`; at the token layer, `@kiva/kv-tokens/css` ([`dist/css/tokens.css`](../../dist/css/tokens.css)) ships a `:root` block plus `[data-theme="…"]` blocks you can apply directly. See [color](color.md) for the theme catalog.
|
|
81
|
+
|
|
82
|
+
### 4. Safelist dynamically generated classes (only if you need it)
|
|
83
|
+
|
|
84
|
+
Tailwind only emits classes it can statically find in `content`. If you generate class names at runtime (e.g. a styleguide that renders every color name), build a `safelist`. `@kiva/kv-components` does this by resolving the preset and enumerating theme keys:
|
|
85
|
+
|
|
86
|
+
```js
|
|
87
|
+
import resolveConfig from 'tailwindcss/resolveConfig';
|
|
88
|
+
import { tailwindConfig as sharedConfig } from '@kiva/kv-tokens';
|
|
89
|
+
|
|
90
|
+
const { theme } = resolveConfig(sharedConfig);
|
|
91
|
+
// …walk theme.backgroundColor, theme.spacing, etc. to build a safelist array
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Most projects do **not** need this — reach for it only when class names aren't present as literal strings in your source.
|
|
95
|
+
|
|
96
|
+
## Authoring with the Kiva preset
|
|
97
|
+
|
|
98
|
+
This section is the heart of the skill: how stock Tailwind v3 knowledge changes once the preset is in place. Each item is a rule, the reason, and what to do instead.
|
|
99
|
+
|
|
100
|
+
### Every utility carries the `tw-` prefix
|
|
101
|
+
|
|
102
|
+
The preset sets `prefix: 'tw-'`. Every generated class is prefixed: `tw-flex`, `tw-mb-2`, `tw-bg-primary`.
|
|
103
|
+
|
|
104
|
+
- The prefix sits **after** any variant: `hover:tw-bg-primary`, `md:tw-flex`, `dark:tw-text-primary` — not `tw-hover:...`.
|
|
105
|
+
- It sits **after** a negative sign: `-tw-mt-2`.
|
|
106
|
+
- Arbitrary values keep the prefix: `tw-mt-[3px]`.
|
|
107
|
+
|
|
108
|
+
If a class isn't taking effect, the missing `tw-` is the first thing to check. When porting markup from a stock-Tailwind project, every utility needs the prefix added.
|
|
109
|
+
|
|
110
|
+
### Color is semantic, themable, and runtime-resolved
|
|
111
|
+
|
|
112
|
+
The preset replaces Tailwind's default color palette. There are two families:
|
|
113
|
+
|
|
114
|
+
- **Themable (semantic) colors** — role-based names like `primary`, `secondary`, `action`, etc., available on text, background, border, ring, divide, placeholder, and gradient-stop utilities: `tw-text-primary`, `tw-bg-secondary`, `tw-border-primary`. These compile to `rgb(var(--…))` and change with the active theme. **This is what you should reach for by default.**
|
|
115
|
+
- **Static colors** — fixed palettes that do *not* change with theme: `brand`, `eco-green`, `marigold`, `desert-rose`, `stone`, `gray`, `social`, plus `black` / `white` / `transparent` / `current`. Use these only when a color must stay constant regardless of theme.
|
|
116
|
+
|
|
117
|
+
Opacity modifiers work on both: `tw-bg-primary/50` resolves to `rgba(var(--bg-primary), 0.5)`. Do **not** assume stock Tailwind color names exist — `tw-bg-gray-500` works (gray is a static palette) but `tw-bg-slate-500`, `tw-text-red-600`, etc. do not. For *which* token, see **[color](color.md)**.
|
|
118
|
+
|
|
119
|
+
### Spacing is an 8px scale with 4px half-steps
|
|
120
|
+
|
|
121
|
+
The spacing scale is token-driven: each whole step is **8px** (`tw-p-1` = 8px, `tw-m-2` = 16px), with `.5` half-steps at **4px** granularity (`tw-p-0.5` = 4px, `tw-gap-1.5` = 12px), running up to `16` (128px). This differs from stock Tailwind's 4px-per-step scale, so the *same number means a different size* — `tw-p-4` is 32px here, not 16px. Apply a scale token, never a raw pixel value; see **[spacing](spacing.md)**.
|
|
122
|
+
|
|
123
|
+
### Text sizing utilities don't exist — use semantic text styles
|
|
124
|
+
|
|
125
|
+
The preset **disables the `fontSize`, `lineHeight`, and `letterSpacing` core plugins.** That means these stock utilities are **not generated**:
|
|
126
|
+
|
|
127
|
+
- No `tw-text-xs` / `tw-text-lg` / `tw-text-2xl` (font-size scale)
|
|
128
|
+
- No `tw-leading-*` (line-height)
|
|
129
|
+
- No `tw-tracking-*` (letter-spacing)
|
|
130
|
+
|
|
131
|
+
Size, line-height, and letter-spacing are bundled into **semantic text-style utilities** instead — `tw-text-h1`, `tw-text-body`, `tw-text-caption`, and the 2026 styles (`tw-text-display`, `tw-text-headline`, `tw-text-title`, …). Note `tw-text-{color}` still works (color is a separate concern); only the *sizing* `tw-text-*` utilities are gone. So `tw-text-primary` (color) is valid; `tw-text-lg` (size) is not. Reach for a semantic style; see **[typography](typography.md)**.
|
|
132
|
+
|
|
133
|
+
### Font weight tops out at `medium` (500)
|
|
134
|
+
|
|
135
|
+
Available weights are `light` (300), `normal` (400), and `medium` (500) — plus `book` as a legacy alias for 300. There is **no `tw-font-bold`** (700) or `tw-font-semibold`. Additionally, the base layer sets `strong` / `b` to normal weight (400), so bolding text requires an explicit weight utility and the design system's heaviest weight is `medium`.
|
|
136
|
+
|
|
137
|
+
### Border-radius is token-driven and `tw-rounded` ≠ pill
|
|
138
|
+
|
|
139
|
+
`tw-rounded` (the unsuffixed utility) resolves to **16px**, not a small radius, and `tw-rounded-full` is the pill/circle. This is a frequent porting bug from stock Tailwind. See **[radius](radius.md)** for the full scale and the concentric-corner rules.
|
|
140
|
+
|
|
141
|
+
### Breakpoints are `md` / `lg` / `xl` (mobile-first, no `sm`)
|
|
142
|
+
|
|
143
|
+
The preset defines only three min-width screens — `md`, `lg`, `xl` — plus a `print` screen. There is **no `sm:` and no `2xl:`**. Unprefixed utilities are the mobile/base tier; the design system's smaller tiers (XS, SM in the layout skill) both fall under "no prefix" in Tailwind. Use `print:` to target print styles. For the grid and tier semantics, see **[layout](layout.md)**.
|
|
144
|
+
|
|
145
|
+
### Z-index, shadow, and opacity are small named scales
|
|
146
|
+
|
|
147
|
+
- **z-index** uses semantic names (`tw-z-modal`, `tw-z-dropdown`, `tw-z-sticky`, `tw-z-toast`, …) rather than `tw-z-10` / `tw-z-50`. Pick by role.
|
|
148
|
+
- **box-shadow** ships only `tw-shadow` (default) and `tw-shadow-lg`. There is no `tw-shadow-md` / `tw-shadow-xl` scale.
|
|
149
|
+
- **opacity** utilities are limited (`tw-opacity-0`, `tw-opacity-10`, `tw-opacity-low`, `tw-opacity-full`) — the full `0–100` scale is not generated. (Color opacity *modifiers* like `tw-bg-primary/50` are unaffected and work normally.)
|
|
150
|
+
|
|
151
|
+
### The base layer styles bare HTML
|
|
152
|
+
|
|
153
|
+
The preset's plugin injects global element styles via `addBase`: web fonts, `body` typography and color, `h1`–`h5`, `small`, `code`, `blockquote`, links (`a`), `hr`, and input placeholders, plus a button focus reset. Two implications:
|
|
154
|
+
|
|
155
|
+
- Bare semantic HTML is already styled — don't re-apply utilities to recreate what the base layer provides.
|
|
156
|
+
- `h6` is **not** styled by the base layer, and `strong`/`b` are set to normal (400) weight. Don't assume browser defaults for those.
|
|
157
|
+
|
|
158
|
+
The `@tailwindcss/typography` plugin is included with Kiva overrides, so `tw-prose` is available for long-form rich text.
|
|
159
|
+
|
|
160
|
+
### Escape hatches
|
|
161
|
+
|
|
162
|
+
When no token fits, Tailwind's arbitrary-value syntax still works with the prefix (`tw-mt-[7px]`, `tw-bg-[#123456]`). Treat this as a last resort and a signal: a recurring need for an off-scale value is a design-system conversation, not a one-off. Prefer a token every time one exists.
|
|
163
|
+
|
|
164
|
+
## How the preset is compiled
|
|
165
|
+
|
|
166
|
+
Read this section when working **inside this monorepo** to change a value or understand where one comes from.
|
|
167
|
+
|
|
168
|
+
### Token authoring
|
|
169
|
+
|
|
170
|
+
Tokens are authored as [W3C DTCG](https://design-tokens.github.io/community-group/format/) JSON under [`tokens/`](../../tokens/):
|
|
171
|
+
|
|
172
|
+
- [`tokens/core/`](../../tokens/core/) — primitives (color, size/space/radius/border-width, typography, z-index, opacity).
|
|
173
|
+
- [`tokens/semantic/themes/`](../../tokens/semantic/themes/) — per-theme semantic tokens that reference primitives.
|
|
174
|
+
|
|
175
|
+
### Build pipeline
|
|
176
|
+
|
|
177
|
+
`npm run build` (also run automatically by the `prepare` lifecycle hook on install) does three things:
|
|
178
|
+
|
|
179
|
+
1. **Style Dictionary** ([`build/style-dictionary.config.js`](../../build/style-dictionary.config.js)) emits `dist/js/tokens.js` (flat named exports **and** a nested default export), `dist/css/tokens.css` (themed CSS custom properties as `R, G, B` triples so opacity composes), and `dist/scss/tokens.scss`.
|
|
180
|
+
2. **`build/build-dtcg.js`** deep-merges all source files into the single manifest `dist/dtcg/tokens.json`.
|
|
181
|
+
3. **`build/build.js`** copies fonts and emits the heading-underline SVG sprite.
|
|
182
|
+
|
|
183
|
+
`dist/` is gitignored but regenerated by `prepare`, so a fresh `npm install` leaves it ready for workspace consumers like `@kiva/kv-components`.
|
|
184
|
+
|
|
185
|
+
### How the config assembles the theme
|
|
186
|
+
|
|
187
|
+
[`configs/tailwind.config.js`](../../configs/tailwind.config.js) imports the generated `dist/js/tokens.js` plus two helper modules and builds the Tailwind `theme`:
|
|
188
|
+
|
|
189
|
+
- **[`configs/kivaColors.js`](../../configs/kivaColors.js)** — `buildColorChoices(category)` maps each semantic token name to a `withOpacity('--token')` function so utilities emit `rgb(var(--token))` / `rgba(var(--token), <opacity>)`. It also exports per-theme objects (`defaultTheme`, `greenLightTheme`, …) that are sets of CSS custom properties.
|
|
190
|
+
- **[`configs/kivaTypography.js`](../../configs/kivaTypography.js)** — text styles, web-font `@font-face` rules, and prose overrides.
|
|
191
|
+
|
|
192
|
+
The config then:
|
|
193
|
+
|
|
194
|
+
- Sets `prefix`, `screens`, `spacing`, `borderRadius`, `fontFamily`, `fontWeight`, `borderWidth`, `opacity`, `zIndex`, `boxShadow`, and static `colors` directly from token values.
|
|
195
|
+
- Disables `container`, `fontSize`, `letterSpacing`, and `lineHeight` core plugins.
|
|
196
|
+
- In `theme.extend`, wires themable color categories (`textColor`, `backgroundColor`, `borderColor`, …) to `buildColorChoices` output.
|
|
197
|
+
- Registers a custom plugin that: `addBase` for element styles and web fonts, injects `:root` = `defaultTheme` custom properties, and `addUtilities` for the semantic text styles (which inherit the `tw-` prefix → `tw-text-h1`, etc.).
|
|
198
|
+
|
|
199
|
+
### Changing a value safely
|
|
200
|
+
|
|
201
|
+
- **To change a token value** (a color, a spacing step, a radius), edit the relevant file under `tokens/`, then run `npm run build` to regenerate `dist/`. Do **not** hand-edit `dist/` — it is generated.
|
|
202
|
+
- **To change Tailwind structure** (add a utility category, adjust a base style, enable a core plugin), edit `configs/tailwind.config.js` directly.
|
|
203
|
+
- After either change, rebuild and verify against a consumer (e.g. run Storybook in `@kiva/kv-components`).
|
|
204
|
+
- Package exports (which subpath resolves to what) are documented in the [README](../../README.md#package-exports).
|
|
205
|
+
|
|
206
|
+
## Common mistakes
|
|
207
|
+
|
|
208
|
+
- Forgetting the **`tw-` prefix** on a utility (or writing `tw-hover:` instead of `hover:tw-`).
|
|
209
|
+
- Using **stock Tailwind color names** (`tw-bg-slate-500`, `tw-text-red-600`) that the preset doesn't define.
|
|
210
|
+
- Reaching for **`tw-text-lg` / `tw-leading-*` / `tw-tracking-*`** — disabled; use semantic text styles.
|
|
211
|
+
- Expecting **`tw-font-bold`** — the heaviest weight is `medium` (500).
|
|
212
|
+
- Treating **`tw-rounded`** as a small radius — it's 16px; use `tw-rounded-full` for pills.
|
|
213
|
+
- Assuming a **`sm:`** breakpoint or the full **opacity / shadow / z-index** numeric scales exist.
|
|
214
|
+
- Using **raw pixel values** instead of scale tokens; or assuming a spacing number matches stock Tailwind (`tw-p-4` is 32px here).
|
|
215
|
+
- An incomplete **`content`** glob (or missing `safelist` for runtime-generated classes), so Tailwind purges classes you expected.
|
|
216
|
+
- Hand-editing **`dist/`** instead of editing `tokens/` and rebuilding.
|
|
217
|
+
|
|
218
|
+
## Current code state (verify before depending)
|
|
219
|
+
|
|
220
|
+
This skill describes shipped mechanics, but specifics still change as tokens and the config evolve. Before relying on an exact class or value:
|
|
221
|
+
|
|
222
|
+
- **The preset is authoritative:** [`configs/tailwind.config.js`](../../configs/tailwind.config.js) defines exactly which utilities exist and what they resolve to. The token values feeding it live in [`tokens/`](../../tokens/) and the generated [`dist/js/tokens.js`](../../dist/js/tokens.js).
|
|
223
|
+
- **Disabled core plugins** (`container`, `fontSize`, `letterSpacing`, `lineHeight`) are the source of the "missing utility" surprises above — confirm the list in the config if a utility you expect is absent.
|
|
224
|
+
- **Semantic color and text-style names** are the categories most likely to gain or rename entries over time; treat [color](color.md) and [typography](typography.md) as companions and cross-check the config.
|
|
225
|
+
|
|
226
|
+
When you find a divergence between this skill and the shipped preset, flag it — each instance is a data point for the design-system team.
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# Kiva Typography
|
|
2
|
+
|
|
3
|
+
**When to use:** When designing or implementing UI that involves text styling — choosing a heading level, applying a type token, picking a font family, building a section that pairs multiple type styles, or reasoning about typographic hierarchy. Reference design intent first; verify token names against current code before relying on them.
|
|
4
|
+
|
|
5
|
+
## Source of truth
|
|
6
|
+
|
|
7
|
+
This skill captures the **semantic typography system** as defined in Figma (the Kiva Ecosystem 2026 file). Figma is the canonical source for design intent: which token exists, what it means, when to use it, and how styles pair together.
|
|
8
|
+
|
|
9
|
+
Numeric values, token names, and Tailwind utility class names in this document reflect the Figma specifications. The shipped code in `@kiva/kv-tokens` may temporarily lag behind these specs while the token sync work is in progress. **Verify any class name or token reference against the current code before depending on it.**
|
|
10
|
+
|
|
11
|
+
## How to apply type styles
|
|
12
|
+
|
|
13
|
+
Always apply type styles by using the right **semantic HTML element** or by adding a **provided typography utility class**. Do not write custom CSS to set font family, size, weight, line height, or letter spacing for text. If no existing element default or class fits the use case, that is a signal to talk to the design system team — not to author bespoke styles.
|
|
14
|
+
|
|
15
|
+
The typography utility classes shipped today (defined in `configs/tailwind.config.js`, served with the `tw-` prefix the project's Tailwind config applies to all classes):
|
|
16
|
+
|
|
17
|
+
- `tw-text-base`
|
|
18
|
+
- `tw-text-display`
|
|
19
|
+
- `tw-text-headline`
|
|
20
|
+
- `tw-text-headline-two`
|
|
21
|
+
- `tw-text-subheadline`
|
|
22
|
+
- `tw-text-title`
|
|
23
|
+
- `tw-text-button-link`
|
|
24
|
+
- `tw-text-upper`
|
|
25
|
+
- `tw-text-caption`
|
|
26
|
+
- `tw-text-label`
|
|
27
|
+
- `tw-text-small`
|
|
28
|
+
- `tw-text-link`
|
|
29
|
+
- `tw-text-blockquote`
|
|
30
|
+
|
|
31
|
+
## Design principles
|
|
32
|
+
|
|
33
|
+
1. **Hierarchy first.** Kiva serves borrowers, lenders, and partners on the same page. Stick to the predefined scale to maintain visual balance and communicate an immediate reading order.
|
|
34
|
+
2. **Simple semantics.** Semantic groupings tell teams how a style is *intended* to be used, while leaving room for context-specific decisions.
|
|
35
|
+
|
|
36
|
+
A typography token is a complete unit — it bundles font family, size, weight, line height, and letter spacing. Apply tokens whole; do not override individual attributes.
|
|
37
|
+
|
|
38
|
+
## Typefaces
|
|
39
|
+
|
|
40
|
+
| Role | Family | Used for |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| Serif (brand) | **Dovetail MVB** | Display, Headline 1, Headline 2 — structural hierarchy that anchors a page |
|
|
43
|
+
| Sans (product) | **Kiva Post Grotesk** | Subheadline, Title, Base, all utility styles — content, UI, long-form reading |
|
|
44
|
+
|
|
45
|
+
**Fallbacks**
|
|
46
|
+
|
|
47
|
+
| Primary | Fallback |
|
|
48
|
+
|---|---|
|
|
49
|
+
| Dovetail MVB | Georgia |
|
|
50
|
+
| Kiva Post Grotesk | Arial |
|
|
51
|
+
|
|
52
|
+
Fallbacks are tuned to closely match the metrics of the primary typefaces to minimize layout shift if brand fonts fail to load.
|
|
53
|
+
|
|
54
|
+
## Type scale
|
|
55
|
+
|
|
56
|
+
Each style is responsive across three device tiers: **Large** (desktop), **Medium** (tablet), **Small** (mobile). `Base` and the small-tier utility styles (Button, Label, Caption, Upper) are universal across all devices.
|
|
57
|
+
|
|
58
|
+
### Display — `Dovetail MVB Medium`
|
|
59
|
+
|
|
60
|
+
Expressive, large-scale text reserved for the single most important headline on a marketing page (homepage hero, campaign title). Limit to one per page; marketing pages only.
|
|
61
|
+
|
|
62
|
+
| Tier | Size | Line height | Letter spacing | Example use |
|
|
63
|
+
|---|---|---|---|---|
|
|
64
|
+
| Large (desktop) | 44px | 57px (1.3) | -0.88px (-0.02em) | Homepage hero, campaign hero |
|
|
65
|
+
| Medium (tablet) | 40px | 52px (1.3) | -0.80px (-0.02em) | Same content, tablet |
|
|
66
|
+
| Small (mobile) | 36px | 52px (1.3) | -0.72px (-0.02em) | Same content, mobile |
|
|
67
|
+
|
|
68
|
+
### Headline 1 — `Dovetail MVB Medium`
|
|
69
|
+
|
|
70
|
+
Primary section headers that establish top-level hierarchy within a page below the hero.
|
|
71
|
+
|
|
72
|
+
| Tier | Size | Line height | Letter spacing | Example use |
|
|
73
|
+
|---|---|---|---|---|
|
|
74
|
+
| Large | 26px | 36px (1.4) | -0.52px (-0.02em) | Section headers |
|
|
75
|
+
| Medium | 22px | 31px (1.4) | -0.22px (-0.01em) | Section headers, tablet |
|
|
76
|
+
| Small | 22px | 31px (1.4) | -0.22px (-0.01em) | Section headers, mobile |
|
|
77
|
+
|
|
78
|
+
> **Why are Medium and Small identical?** At this level of hierarchy, further size reduction from tablet to mobile interferes with rather than improves readability.
|
|
79
|
+
|
|
80
|
+
### Headline 2 — `Dovetail MVB Medium`
|
|
81
|
+
|
|
82
|
+
Secondary headers that organize and support content within a section.
|
|
83
|
+
|
|
84
|
+
| Tier | Size | Line height | Letter spacing | Example use |
|
|
85
|
+
|---|---|---|---|---|
|
|
86
|
+
| Large | 22px | 31px (1.4) | -0.22px (-0.01em) | Category labels, subsection titles |
|
|
87
|
+
| Medium | 20px | 26px (1.3) | -0.20px (-0.01em) | Same content, tablet |
|
|
88
|
+
| Small | 20px | 26px (1.3) | -0.20px (-0.01em) | Same content, mobile |
|
|
89
|
+
|
|
90
|
+
### Subheadline — `Kiva Post Grotesk Book`
|
|
91
|
+
|
|
92
|
+
Supporting text that sits below a Headline to expand on it.
|
|
93
|
+
|
|
94
|
+
| Tier | Size | Line height | Letter spacing | Example use |
|
|
95
|
+
|---|---|---|---|---|
|
|
96
|
+
| Large | 20px | 26px (1.3) | 0 | Subheading below the headline |
|
|
97
|
+
| Medium | 18px | 23px (1.3) | 0 | Same content, tablet |
|
|
98
|
+
| Small | 18px | 23px (1.3) | 0 | Same content, mobile |
|
|
99
|
+
|
|
100
|
+
### Title — `Kiva Post Grotesk Medium`
|
|
101
|
+
|
|
102
|
+
Component-level headings used to label cards, modules, or distinct content blocks. Same size/line-height as Subheadline but **Medium weight** instead of Book — this is what distinguishes a component title from a supporting subheadline.
|
|
103
|
+
|
|
104
|
+
| Tier | Size | Line height | Letter spacing | Example use |
|
|
105
|
+
|---|---|---|---|---|
|
|
106
|
+
| Large | 20px | 26px (1.3) | 0 | Card headers, modal titles, list titles |
|
|
107
|
+
| Medium | 18px | 23px (1.3) | 0 | Same content, tablet |
|
|
108
|
+
| Small | 18px | 23px (1.3) | 0 | Same content, mobile |
|
|
109
|
+
|
|
110
|
+
### Base — `Kiva Post Grotesk Book`
|
|
111
|
+
|
|
112
|
+
Default body text for paragraphs and most reading content. **Universal across all devices.**
|
|
113
|
+
|
|
114
|
+
| Token | Size | Line height | Letter spacing | Example use |
|
|
115
|
+
|---|---|---|---|---|
|
|
116
|
+
| Base | 16px | 22px (1.4) | 0 | Borrower stories, loan descriptions |
|
|
117
|
+
|
|
118
|
+
### Utility / Small styles — `Kiva Post Grotesk`
|
|
119
|
+
|
|
120
|
+
Functional UI text. Universal across all devices.
|
|
121
|
+
|
|
122
|
+
| Token | Size | Weight | Line height | Letter spacing | Example use |
|
|
123
|
+
|---|---|---|---|---|---|
|
|
124
|
+
| Button | 16px | Medium | 21px (1.25) | 0 | CTA labels |
|
|
125
|
+
| Label | 14px | Medium | 18px (1.25) | 0 | Form labels, filter names |
|
|
126
|
+
| Caption | 14px | Book | 18px (1.25) | 0 | Disclaimers, captions |
|
|
127
|
+
| Upper | 14px | Medium | 18px (1.25) | 0 | Tags, status badges (always UPPERCASE) |
|
|
128
|
+
|
|
129
|
+
## Heading hierarchy & semantic HTML mapping
|
|
130
|
+
|
|
131
|
+
The design system defines semantic type tokens for heading levels **h1 through h4 only**. Do not use `<h5>` or `<h6>`. For deeper content hierarchy, use a paragraph element with the appropriate type token (see "Going deeper than h4" below).
|
|
132
|
+
|
|
133
|
+
### Default mapping (most contexts)
|
|
134
|
+
|
|
135
|
+
| Style token | HTML element | Tailwind class | Mobile | Tablet | Desktop | Notes |
|
|
136
|
+
|---|---|---|---|---|---|---|
|
|
137
|
+
| Headline 1 | `<h1>` | `tw-text-headline` | 22px | 22px | 26px | Global h1 default via base CSS |
|
|
138
|
+
| Headline 2 | `<h2>` | `tw-text-headline-two` | 20px | 20px | 22px | Global h2 default via base CSS |
|
|
139
|
+
| Subheadline | `<h3>` | `tw-text-subheadline` | 18px | 18px | 20px | Global h3 default via base CSS |
|
|
140
|
+
| Title | `<h4>` | `tw-text-title` | 18px | 18px | 20px | Global h4 default via base CSS |
|
|
141
|
+
| Base / Body | `<p>`, `<body>` | `tw-text-base` | 16px | 16px | 16px | Global paragraph and body default |
|
|
142
|
+
| Button | `<button>` | `tw-text-button-link` | 16px | 16px | 16px | Global button default; primary CTA labels |
|
|
143
|
+
| Label | `<label>` | `tw-text-label` | 14px | 14px | 14px | Global label default |
|
|
144
|
+
| Caption | `<figcaption>` | `tw-text-caption` | 14px | 14px | 14px | Use for disclaimers and captions |
|
|
145
|
+
| Upper | — (utility only) | `tw-text-upper` | 14px | 14px | 14px | No element default; always UPPERCASE |
|
|
146
|
+
| Small | `<small>` | `tw-text-small` | 14px | 14px | 14px | Supportive UI text |
|
|
147
|
+
| Blockquote | `<blockquote>` | `tw-text-blockquote` | 20px | 20px | 22px | Italic Dovetail serif |
|
|
148
|
+
| Link | `<a>` | `tw-text-link` | 16px | 16px | 16px | Underline + action color; inherits size from parent |
|
|
149
|
+
|
|
150
|
+
### Going deeper than h4
|
|
151
|
+
|
|
152
|
+
For content that needs sub-h4 hierarchy, do not reach for `<h5>`. Use a semantic text element with a type token instead:
|
|
153
|
+
|
|
154
|
+
- "Small heading" feel → `<p>` + `tw-text-title` or `tw-text-label`
|
|
155
|
+
- Supportive / metadata text → `<p>` or `<span>` + `tw-text-caption` or `tw-text-small`
|
|
156
|
+
- Form field labels → `<label>` + `tw-text-label`
|
|
157
|
+
|
|
158
|
+
### Contentful-specific shifted header mapping
|
|
159
|
+
|
|
160
|
+
Marketing pages rendered through Contentful shift each heading element down one level so that `<h1>` can be reserved for the Display style on hero modules. Use this mapping only in the Contentful context; a CSS override is needed for it.
|
|
161
|
+
|
|
162
|
+
| Style token | HTML element | Tailwind class | Mobile | Tablet | Desktop | Notes |
|
|
163
|
+
|---|---|---|---|---|---|---|
|
|
164
|
+
| Display | `<h1>` | `tw-text-display` | 36px | 40px | 44px | Marketing hero only; CSS override required |
|
|
165
|
+
| Headline 1 | `<h2>` | `tw-text-headline` | 22px | 22px | 26px | |
|
|
166
|
+
| Headline 2 | `<h3>` | `tw-text-headline-two` | 20px | 20px | 22px | |
|
|
167
|
+
| Subheadline | `<h4>` | `tw-text-subheadline` | 18px | 18px | 20px | |
|
|
168
|
+
| Title | `<h5>` | `tw-text-title` | 18px | 18px | 20px | Permitted only inside the Contentful shift |
|
|
169
|
+
|
|
170
|
+
## Pairing guidelines
|
|
171
|
+
|
|
172
|
+
The full marketing pairing pattern stacks five elements in this order:
|
|
173
|
+
|
|
174
|
+
1. **Upper** — short eyebrow / category label above the headline
|
|
175
|
+
2. **Display** — hero headline (one per page, marketing only)
|
|
176
|
+
3. **Subheadline** — supporting paragraph that expands the headline
|
|
177
|
+
4. **Button** — primary CTA
|
|
178
|
+
5. **Caption** — supportive metadata, e.g., a contact prompt
|
|
179
|
+
|
|
180
|
+
The standard in-page (non-hero) pairing pattern stacks:
|
|
181
|
+
|
|
182
|
+
1. **Headline 1** — section header (with a paragraph of Subheadline beneath it)
|
|
183
|
+
2. **Subheadline** — supporting paragraph
|
|
184
|
+
3. **Headline 2** — subsection header (with a paragraph of Base beneath it)
|
|
185
|
+
4. **Base** — body content
|
|
186
|
+
5. **Title** — card/module heading (with a paragraph of Base beneath it)
|
|
187
|
+
|
|
188
|
+
The semantic distinction worth remembering: **Subheadline** and **Title** share the same size at every tier — Subheadline (Book weight) describes/expands the thing above it, Title (Medium weight) names the thing it sits inside (a card, a modal, a module).
|
|
189
|
+
|
|
190
|
+
## Best practices
|
|
191
|
+
|
|
192
|
+
### Hierarchy and legibility
|
|
193
|
+
|
|
194
|
+
- **Do** clearly differentiate heading sizes to create hierarchy. Use Base for long-form body paragraphs.
|
|
195
|
+
- **Don't** make headings and body text look too similar. Don't use Caption or Label for long paragraphs.
|
|
196
|
+
|
|
197
|
+
### All caps
|
|
198
|
+
|
|
199
|
+
- **Do** use the Upper style for short, 1–3 word labels (tags, eyebrows, status badges).
|
|
200
|
+
- **Don't** use all caps for full sentences or long paragraphs.
|
|
201
|
+
|
|
202
|
+
## Usage rules
|
|
203
|
+
|
|
204
|
+
### Do
|
|
205
|
+
|
|
206
|
+
- Use the correct size tier (Large / Medium / Small) for the target device.
|
|
207
|
+
- Respect the Dovetail MVB / Kiva Post Grotesk family boundary — serif for Display and Headlines, sans for everything else.
|
|
208
|
+
- Limit Display to one per page, and only on marketing pages.
|
|
209
|
+
- Default to Base for any paragraph content.
|
|
210
|
+
|
|
211
|
+
### Don't
|
|
212
|
+
|
|
213
|
+
- Override individual attributes of a token (size, weight, line height, letter spacing). Apply the token whole, or pick a different token.
|
|
214
|
+
- Write custom CSS (or one-off Tailwind utility combinations like `tw-text-[18px] tw-font-medium tw-leading-[23px]`) to set type styles. Use a semantic HTML element or one of the provided typography utility classes.
|
|
215
|
+
- Create new styles outside this system without design system team review.
|
|
216
|
+
|
|
217
|
+
### Need something not covered here?
|
|
218
|
+
|
|
219
|
+
Open a request with the design system team. Include the use case, the component, and why existing tokens don't work.
|
|
220
|
+
|
|
221
|
+
## How to use in Figma
|
|
222
|
+
|
|
223
|
+
All tokens are published as text styles in the Kiva Ecosystem library.
|
|
224
|
+
|
|
225
|
+
- Match the size tier to your frame: Desktop frames get Large variants, Tablet frames get Medium, Mobile frames get Small. Utility styles and Base are universal.
|
|
226
|
+
- A detached style breaks the connection to the library — the element stops receiving updates and becomes an undocumented variant.
|
|
227
|
+
- Hover over a text style to see a description of where it's used.
|
|
228
|
+
- Before handing off, inspect every text layer. If a layer shows raw values (e.g. "Dovetail / 26px / Medium") instead of a style name (e.g. "Headline 1 Large"), it's detached — reapply the matching style from the library.
|
|
229
|
+
|
|
230
|
+
## Using with Tailwind
|
|
231
|
+
|
|
232
|
+
The typography utilities come from the `@kiva/kv-tokens` Tailwind preset. Haven't registered it yet? See [tailwind → Consuming the preset](tailwind.md#consuming-the-preset). Not using the preset? See [Without the preset](#without-the-preset) below.
|
|
233
|
+
|
|
234
|
+
Type styles ship as **semantic, whole-style utilities** (e.g. `tw-text-base`, `tw-text-headline`, `tw-text-caption`) — each bundles font-family, size, line-height, and letter-spacing together. Pick one from [How to apply type styles](#how-to-apply-type-styles) or the [HTML + Tailwind mapping](#heading-hierarchy--semantic-html-mapping) tables above; don't assemble a style from individual utilities.
|
|
235
|
+
|
|
236
|
+
Two stock-Tailwind habits won't work here, by design:
|
|
237
|
+
|
|
238
|
+
- **No `tw-text-lg` / `tw-text-2xl` / `tw-leading-*` / `tw-tracking-*`.** The preset disables the `fontSize`, `lineHeight`, and `letterSpacing` core plugins, so those utilities aren't generated — use a semantic text style instead. (`tw-text-{color}` like `tw-text-primary` still works; that's color, a separate concern.) See [tailwind → Text sizing utilities don't exist](tailwind.md#text-sizing-utilities-dont-exist--use-semantic-text-styles).
|
|
239
|
+
- **No `tw-font-bold` / `tw-font-semibold`.** The heaviest weight is `medium` (500), and the base layer resets `strong` / `b` to normal (400). See [tailwind → Font weight tops out at `medium`](tailwind.md#font-weight-tops-out-at-medium-500).
|
|
240
|
+
|
|
241
|
+
These utilities are defined in `@kiva/kv-tokens/configs/tailwind.config.js` (via `kivaTypography.js`) — verify a class name against the current config before depending on it.
|
|
242
|
+
|
|
243
|
+
### Without the preset
|
|
244
|
+
|
|
245
|
+
- **Kiva (or Kiva-adjacent) repo, preset not registered yet:** install and register it — [tailwind → Consuming the preset](tailwind.md#consuming-the-preset).
|
|
246
|
+
- **Stock-Tailwind / non-Kiva project:** the semantic `tw-text-*` styles won't exist. Replicate a style by reading its font-family, size, and line-height from the [type scale](#type-scale) and the mapping tables, and load the web fonts with the `@font-face` rules the package ships. Copied values are point-in-time.
|
|
247
|
+
|
|
248
|
+
> The in-progress `<h1>`–`<h6>` / `tw-text-h1`–`tw-text-h6` semantic remap is tracked separately — see the `header-element-audit` skill before doing heading cleanup.
|
|
249
|
+
|
|
250
|
+
## Figma source references
|
|
251
|
+
|
|
252
|
+
- Typography Overview: node `17279:6062`
|
|
253
|
+
- Type Scales & Tokens: node `17443:6589`
|
|
254
|
+
- Typography Guidelines: node `17279:6478`
|
|
255
|
+
- HTML + Tailwind Reference: node `19446:186`
|
|
256
|
+
|
|
257
|
+
File: `TPmBUB4olYPMF6glEhBGDG` (Ecosystem 2026 — WIP)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Setup
|
|
2
|
+
|
|
3
|
+
**When to use:** Read this first, before generating any UI, to consume Kiva's design system correctly.
|
|
4
|
+
|
|
5
|
+
Kiva's design system is a Tailwind CSS v3 preset, compiled to a full stylesheet that ships as `../styles.css` (base layer, token-backed utilities, the `tw-text-*` type system, and themable color variables).
|
|
6
|
+
|
|
7
|
+
## Primary: use the compiled stylesheet
|
|
8
|
+
|
|
9
|
+
Link `../styles.css` into the app and apply its `tw-`-prefixed classes directly — `tw-p-4`, `tw-text-h1`, `tw-bg-primary`, `tw-rounded-md`, etc. This needs no build step and works regardless of the app's framework or CSS setup.
|
|
10
|
+
|
|
11
|
+
- Every utility carries a `tw-` prefix (e.g. `tw-bg-primary`, `tw-mb-2`).
|
|
12
|
+
- Use the semantic type utilities (`tw-text-h1`, `tw-text-display`, `tw-text-caption`, …) for text — there is no `tw-text-lg`-style sizing.
|
|
13
|
+
- Colors are themable: the default theme is in `:root`; set `data-theme="…"` on a container to switch (theme variables ship in `../styles.css`).
|
|
14
|
+
- The foundation guidelines explain which class/token to choose for a given decision.
|
|
15
|
+
|
|
16
|
+
## Optional: install the Kiva Tailwind preset
|
|
17
|
+
|
|
18
|
+
If the generated app builds Tailwind itself and can add the package, this gives the full preset (utilities generated on demand rather than shipped):
|
|
19
|
+
|
|
20
|
+
1. Install: `npm i -D tailwindcss@^3 @kiva/kv-tokens @tailwindcss/typography`.
|
|
21
|
+
2. `tailwind.config.js`:
|
|
22
|
+
|
|
23
|
+
```js
|
|
24
|
+
import { tailwindConfig } from '@kiva/kv-tokens';
|
|
25
|
+
|
|
26
|
+
export default {
|
|
27
|
+
presets: [tailwindConfig],
|
|
28
|
+
content: ['./src/**/*.{js,jsx,ts,tsx,html}'],
|
|
29
|
+
};
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
3. Import `@tailwind base; @tailwind components; @tailwind utilities;` in your root CSS.
|
|
33
|
+
|
|
34
|
+
The same `tw-` prefix and semantic type utilities apply. See `foundations/tailwind.md` for the full mechanics.
|