diff --git a/docs/theming/configuration/css-variables.md b/docs/theming/configuration/css-variables.md
index 34e94f8b..e2202113 100644
--- a/docs/theming/configuration/css-variables.md
+++ b/docs/theming/configuration/css-variables.md
@@ -43,12 +43,12 @@ Variables defined in `:root` or theme-specific selectors are for component-speci
```css
@theme {
- --font-family-header: system-ui, sans-serif;
- --font-family-body: system-ui, sans-serif;
- --font-family-code: 'Courier New', monospace;
- --font-family-label: system-ui, sans-serif;
- --font-family-caption: system-ui, sans-serif;
- --font-family-marquee: system-ui, sans-serif;
+ --font-header: system-ui, sans-serif;
+ --font-body: system-ui, sans-serif;
+ --font-code: 'Courier New', monospace;
+ --font-label: system-ui, sans-serif;
+ --font-caption: system-ui, sans-serif;
+ --font-marquee: system-ui, sans-serif;
}
```
@@ -303,9 +303,9 @@ Or per-theme:
}
@theme {
- --font-family-header: 'Inter', system-ui, sans-serif;
- --font-family-body: 'Inter', system-ui, sans-serif;
- --font-family-label: 'Inter', system-ui, sans-serif;
+ --font-header: 'Inter', system-ui, sans-serif;
+ --font-body: 'Inter', system-ui, sans-serif;
+ --font-label: 'Inter', system-ui, sans-serif;
}
```
diff --git a/docs/theming/configuration/customization.md b/docs/theming/configuration/customization.md
index a0d7521b..90761190 100644
--- a/docs/theming/configuration/customization.md
+++ b/docs/theming/configuration/customization.md
@@ -116,10 +116,10 @@ Override font families for different text categories:
}
@theme {
- --font-family-header: 'Inter', system-ui, sans-serif;
- --font-family-body: 'Inter', system-ui, sans-serif;
- --font-family-label: 'Inter', system-ui, sans-serif;
- --font-family-code: 'JetBrains Mono', monospace;
+ --font-header: 'Inter', system-ui, sans-serif;
+ --font-body: 'Inter', system-ui, sans-serif;
+ --font-label: 'Inter', system-ui, sans-serif;
+ --font-code: 'JetBrains Mono', monospace;
}
```
@@ -130,12 +130,12 @@ Use different fonts for light and dark themes:
```css
.light,
.dark .theme-inverse {
- --font-family-body: 'Inter', system-ui, sans-serif;
+ --font-body: 'Inter', system-ui, sans-serif;
}
.dark,
.light .theme-inverse {
- --font-family-body: 'Geist', system-ui, sans-serif;
+ --font-body: 'Geist', system-ui, sans-serif;
}
```
@@ -368,9 +368,9 @@ module.exports = frontile({
@theme {
/* Typography */
- --font-family-header: 'Poppins', system-ui, sans-serif;
- --font-family-body: 'Poppins', system-ui, sans-serif;
- --font-family-label: 'Poppins', system-ui, sans-serif;
+ --font-header: 'Poppins', system-ui, sans-serif;
+ --font-body: 'Poppins', system-ui, sans-serif;
+ --font-label: 'Poppins', system-ui, sans-serif;
/* Rounded design */
--radius: 12px;
diff --git a/docs/theming/design-tokens/borders.md b/docs/theming/design-tokens/borders.md
index 685c0482..d5bca013 100644
--- a/docs/theming/design-tokens/borders.md
+++ b/docs/theming/design-tokens/borders.md
@@ -120,55 +120,6 @@ Control corner rounding with radius tokens that range from sharp edges to fully
| Default (Custom) | `rounded-default` | Custom default radius value, soft friendly corners |
| Pill | `rounded-pill` | Pills, badges, fully rounded buttons |
-### Border Radius Examples
-
-```gts preview
-
-
- {{! Button group with different radii }}
-
-
- Sharp (SM)
-
-
- Default
-
-
- Soft (XL)
-
-
- Pill
-
-
-
- {{! Cards with different radii }}
-
-
-
-
Uses rounded-md for subtle corners
-
-
-
-
Uses rounded-2xl for prominent display
-
-
-
- {{! Badges and pills }}
-
-
- Rounded Badge
-
-
- Pill Badge
-
-
- Soft Badge
-
-
-
-
-```
-
## Combining Borders and Radius
Use border widths and radius together to create various UI patterns:
@@ -197,54 +148,6 @@ Use border widths and radius together to create various UI patterns:
```
-## Directional Border Utilities
-
-Tailwind's directional utilities work with Frontile's border width tokens:
-
-```gts preview
-
-
- {{! Top border only }}
-
-
- {{! Left border accent }}
-
-
Left border accent (aggressive)
-
-
- {{! Bottom divider }}
-
-
Bottom divider (thin)
-
-
-
-```
-
-## Directional Border Radius
-
-Apply radius to specific corners:
-
-```gts preview
-
-
-
-
Top rounded
-
rounded-t-xl
-
-
-
Bottom rounded
-
rounded-b-xl
-
-
-
Left rounded
-
rounded-l-xl
-
-
-
-```
-
## Best Practices
### Maintain Consistency
diff --git a/docs/theming/design-tokens/elevation.md b/docs/theming/design-tokens/elevation.md
index 653eb467..9024c43b 100644
--- a/docs/theming/design-tokens/elevation.md
+++ b/docs/theming/design-tokens/elevation.md
@@ -21,34 +21,34 @@ Higher elevations indicate elements that are more prominent or interactive, such
-
-
No shadow
-
Flat surface
+
Level 0
+
No shadow
+
Flat surface
-
-
Subtle lift
-
Hover states
+
Level 1
+
Subtle lift
+
Hover states
-
-
Raised surface
-
Cards, panels
+
Level 2
+
Raised surface
+
Cards, panels
-
-
Floating element
-
Dropdowns
+
Level 3
+
Floating element
+
Dropdowns
-
-
Elevated overlay
-
Modals, dialogs
+
Level 4
+
Elevated overlay
+
Modals, dialogs
-
-
Maximum depth
-
Top layer
+
Level 5
+
Maximum depth
+
Top layer
@@ -74,8 +74,8 @@ Higher elevations indicate elements that are more prominent or interactive, such
{{! Basic card with level 2 elevation }}
-
-
+
Product Card
+
Standard card with level 2 elevation provides subtle depth.
@@ -85,8 +85,8 @@ Higher elevations indicate elements that are more prominent or interactive, such
{{! Feature card with no shadow }}
-
-
+
Flat Card
+
Uses border instead of shadow for a flatter appearance.
@@ -113,116 +113,8 @@ Higher elevations indicate elements that are more prominent or interactive, such
-
-
Elevation increases on hover
-
-
-
-```
-
-### Dropdown Menus
-
-```gts preview
-
-
-
- Open Menu
-
- {{! Dropdown with level 3 elevation }}
-
-
-
-```
-
-### Modal Dialog
-
-```gts preview
-
-
- {{! Modal with level 4 elevation }}
-
-
-
- Are you sure you want to proceed with this action?
-
-
-
- Cancel
-
-
- Confirm
-
-
-
-
-
-```
-
-### Alert Notifications
-
-```gts preview
-
-
- {{! Standard alert with level 2 elevation }}
-
-
Information
-
Standard notification with moderate elevation.
-
-
- {{! Critical alert with level 5 elevation }}
-
-
Critical Alert
-
Maximum elevation draws immediate attention.
-
-
-
-```
-
-## Combining with Other Tokens
-
-### Elevation with Border Radius
-
-Pair elevation with border radius for polished UI:
-
-```gts preview
-
-
-
-
Sharp corners
-
rounded-sm
-
-
-
Soft corners
-
rounded-xl
-
-
-
Very soft
-
rounded-2xl
-
-
-
-```
-
-### Elevation with Colors
-
-Use semantic colors with elevation:
-
-```gts preview
-
-
-
-
Success
-
Elevated success message
-
-
-
Warning
-
High-elevation warning
+
Interactive Card
+
Elevation increases on hover
diff --git a/docs/theming/design-tokens/icons.md b/docs/theming/design-tokens/icons.md
index 1fb41206..70f36ae3 100644
--- a/docs/theming/design-tokens/icons.md
+++ b/docs/theming/design-tokens/icons.md
@@ -77,59 +77,148 @@ Apply icon sizes using the `size-icon-*` utilities, which set both width and hei
| Kilo | `size-icon-kilo` | Very large decorative icons |
| Mega | `size-icon-mega` | Largest decorative icons |
+## All Icon Sizes
+
+Here are all available icon sizes with visual examples:
+
+```gts preview
+import { CheckIcon } from 'site/components/icons';
+
+
+
+
+
+
+
Pico
+
size-icon-pico
+
+
+
+
+
+
Nano
+
size-icon-nano
+
+
+
+
+
+
Micro
+
size-icon-micro
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Kilo
+
size-icon-kilo
+
+
+
+
+
+
Mega
+
size-icon-mega
+
+
+
+
+```
+
## Pairing with Typography
Icon sizes are designed to pair harmoniously with text styles. Use these recommended pairings for visual alignment:
```gts preview
+import { CheckIcon, ViewIcon, StarIcon } from 'site/components/icons';
+
- {{! Small text with small icon }}
+ {{! Small icon pairing }}
-
-
-
-
Small body text with size-icon-xs
+
+
Small text with size-icon-xs
- {{! Medium text with medium icon }}
+ {{! Medium icon pairing }}
-
-
-
-
Default body text with size-icon-md
+
+
Default text with size-icon-md
- {{! Large text with large icon }}
+ {{! Large icon pairing }}
-
-
-
-
Large body text with size-icon-lg
+
+
Larger text with size-icon-lg
- {{! Header with large icon }}
+ {{! Extra large icon pairing }}
-
-
-
-
+
+
Header with size-icon-xl
@@ -147,100 +236,6 @@ Icon sizes are designed to pair harmoniously with text styles. Use these recomme
| `text-header-lg` | `size-icon-lg` or `size-icon-xl` |
| `text-header-xl` | `size-icon-xl` or `size-icon-2xl` |
-## Common Use Cases
-
-### Buttons with Icons
-
-```gts preview
-
-
-
-
-
-
- Add Item
-
-
-
-
-
-
- Download
-
-
-
-```
-
-### List Items with Icons
-
-```gts preview
-
-
-
-
-
-
- Task completed successfully
-
-
-
-
-
- Warning: Review required
-
-
-
-
-
- Error: Action failed
-
-
-
-```
-
-### Input Fields with Icons
-
-```gts preview
-
-
-
-```
-
## Customization
Override icon sizes using CSS variables in your `@theme` block:
diff --git a/docs/theming/design-tokens/typography.md b/docs/theming/design-tokens/typography.md
index e45fcc40..fe8806cb 100644
--- a/docs/theming/design-tokens/typography.md
+++ b/docs/theming/design-tokens/typography.md
@@ -28,10 +28,10 @@ Large, bold display text for hero sections and prominent headings.
```gts preview
-
Marquee XL: Hero Heading
-
Marquee LG: Large Display
-
Marquee MD: Medium Display
-
Marquee SM: Small Display
+
Marquee XL: Hero Heading
+
Marquee LG: Large Display
+
Marquee MD: Medium Display
+
Marquee SM: Small Display
```
@@ -46,16 +46,16 @@ Semantic headings for content hierarchy with bold weight and condensed letter sp
```gts preview
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
```
@@ -70,34 +70,34 @@ Standard body text with spacious line height optimized for readability.
```gts preview
-
+
Body XL: The quick brown fox jumps over the lazy dog. This is extra large body text with spacious line height for comfortable reading.
-
+
Body LG: The quick brown fox jumps over the lazy dog. This is large body text with spacious line height for comfortable reading.
-
+
Body MD: The quick brown fox jumps over the lazy dog. This is default body text with spacious line height for comfortable reading.
-
+
Body SM: The quick brown fox jumps over the lazy dog. This is small body text with spacious line height for comfortable reading.
-
+
Body XS: The quick brown fox jumps over the lazy dog. This is extra small body text.
-
+
Body 2XS: The quick brown fox jumps over the lazy dog. This is 2XS body text.
-
+
Body 3XS: The quick brown fox jumps over the lazy dog. This is 3XS body text.
-
+
Body Micro: The quick brown fox jumps over the lazy dog. This is micro body text.
-
+
Body Nano: The quick brown fox jumps over the lazy dog. This is nano body text.
-
+
Body Pico: The quick brown fox jumps over the lazy dog. This is pico body text.
@@ -114,10 +114,10 @@ Monospace text for code snippets and technical content.
```gts preview
-
+
const greeting = "Hello, World!";
-
+
npm install frontile
@@ -138,10 +138,10 @@ Secondary descriptive text with relaxed letter spacing.
Example Image
- Caption MD: Figure 1 - Example image caption with medium size
+ Caption MD: Figure 1 - Example image caption with medium size
- Caption SM: Small caption text for supplementary information
+ Caption SM: Small caption text for supplementary information
@@ -157,16 +157,16 @@ UI labels and form labels with bold weight and tight letter spacing.
```gts preview
-
Label 3XL: Extra Large Label
-
Label 2XL: Double Extra Large Label
-
Label XL: Extra Large Label
-
Label LG: Large Label
-
Label MD: Medium Label
-
Label SM: Small Label
-
Label XS: Extra Small Label
-
Label 2XS: Double Extra Small Label
-
Label Micro: Micro Label
-
Label Nano: Nano Label
+
Label 3XL: Extra Large Label
+
Label 2XL: Double Extra Large Label
+
Label XL: Extra Large Label
+
Label LG: Large Label
+
Label MD: Medium Label
+
Label SM: Small Label
+
Label XS: Extra Small Label
+
Label 2XS: Double Extra Small Label
+
Label Micro: Micro Label
+
Label Nano: Nano Label
```
@@ -174,20 +174,18 @@ UI labels and form labels with bold weight and tight letter spacing.
**Available sizes:** `nano`, `micro`, `2xs`, `xs`, `sm`, `md`, `lg`, `xl`, `2xl`, `3xl`
**Best for:** Form labels, UI labels, buttons, navigation items, badges
-## Default Sizes
+## Available Utilities
-Each text style category has a default size that can be used without specifying the size modifier:
+All text style utilities require both a font-family utility and a sized text style utility:
```html
-
-...
-...
-
-
-
-
-...
-...
+
+...
+
+...
+...
+...
+...
```
## Combining with Other Utilities
@@ -198,20 +196,20 @@ Typography utilities work seamlessly with other Tailwind utilities:
{{! Colored header }}
-
Colored Header
+
Colored Header
{{! Truncated body text }}
-
+
This is a very long paragraph that will be truncated with an ellipsis when it exceeds the maximum width.
{{! Centered caption }}
-
+
Centered caption text
{{! Responsive header }}
-
@@ -220,36 +218,32 @@ Typography utilities work seamlessly with other Tailwind utilities:
## How It Works
-The typography system uses a two-part approach:
+The typography system uses Tailwind v4's `@theme` directive to automatically generate utilities from CSS variables:
-1. **Base tokens** defined in `@theme` provide the foundation (font families, weights, sizes, etc.)
-2. **Composite utilities** defined in `@layer utilities` bundle these tokens into semantic text styles
+1. **Base tokens** defined in `@theme` automatically generate individual utilities:
+ - `--font-header` → `font-header` utility
+ - `--font-size-14` → `text-14` utility
+ - `--font-weight-bold` → `font-bold` utility
+ - `--letter-spacing-condensed` → `tracking-condensed` utility
+ - `--line-height-comfy` → `leading-comfy` utility
-Each text utility is explicitly defined to combine all typography properties:
+2. **Composite text style tokens** generate size/weight/spacing utilities (but NOT font-family):
+ - `--text-header-md` → `text-header-md` utility (sets size, weight, spacing, line-height)
+ - `--text-body-lg` → `text-body-lg` utility (sets size, weight, spacing, line-height)
-```css
-@theme {
- /* Base typography tokens */
- --font-family-header: "Open Sans";
- --font-size-14: 1.14rem;
- --font-weight-bold: 700;
- --letter-spacing-condensed: -0.0625rem;
- --line-height-comfy: 1.4;
-}
+**Usage pattern:** Combine font-family with text style for complete typography:
-@layer utilities {
- /* Composite utility that references base tokens */
- .text-header-md {
- font-size: var(--font-size-14);
- font-family: var(--font-family-header);
- font-weight: var(--font-weight-bold);
- letter-spacing: var(--letter-spacing-condensed);
- line-height: var(--line-height-comfy);
- }
-}
+```html
+
+
+Body text with larger size
+Small label
+
+
+
```
-When you use `.text-header-md`, all five typography properties are applied together as a cohesive style. The system uses a modular scale (ratio: 1.067) to ensure harmonious sizing relationships across all text styles.
+The separation of font-family from text styles provides flexibility to mix font families with different text styles while maintaining consistent sizing, weight, spacing, and line-height.
## Customization
@@ -262,9 +256,9 @@ Customize typography by overriding CSS variables in your app's CSS file:
/* Override font families */
@theme {
- --font-family-header: "Inter", system-ui, sans-serif;
- --font-family-body: "Inter", system-ui, sans-serif;
- --font-family-code: "JetBrains Mono", monospace;
+ --font-header: "Inter", system-ui, sans-serif;
+ --font-body: "Inter", system-ui, sans-serif;
+ --font-code: "JetBrains Mono", monospace;
}
```
@@ -276,13 +270,13 @@ Customize for light and dark themes using theme selectors:
/* Light theme customization */
.light,
.dark .theme-inverse {
- --font-family-body: "Inter", system-ui, sans-serif;
+ --font-body: "Inter", system-ui, sans-serif;
}
/* Dark theme customization */
.dark,
.light .theme-inverse {
- --font-family-body: "Geist", system-ui, sans-serif;
+ --font-body: "Geist", system-ui, sans-serif;
}
```
@@ -299,9 +293,9 @@ Add custom fonts by declaring them with `@font-face` and overriding the font fam
}
@theme {
- --font-family-header: 'Inter', system-ui, sans-serif;
- --font-family-body: 'Inter', system-ui, sans-serif;
- --font-family-label: 'Inter', system-ui, sans-serif;
+ --font-header: 'Inter', system-ui, sans-serif;
+ --font-body: 'Inter', system-ui, sans-serif;
+ --font-label: 'Inter', system-ui, sans-serif;
}
```
@@ -315,7 +309,7 @@ Always prefer semantic text style utilities over combining individual properties
{{! Good - semantic text style }}
-
+
✓ Semantic: Easy to maintain
@@ -334,21 +328,21 @@ Use size variants to create clear content hierarchy:
```gts preview
-
- Published on December 7, 2024
+
+ Published on December 7, 2024
-
-
+
+
This is the main body content with comfortable line height for easy reading. The text flows naturally and maintains good readability.
-
-
+
+
Subsection content continues the hierarchy with appropriately sized headers.
-
+
Figure 1: Caption providing additional context
@@ -363,10 +357,10 @@ Scale typography for different screen sizes:
```gts preview
-
+
Body text that scales up on larger screens for better readability across all devices.
diff --git a/packages/theme/src/styles/typography.css b/packages/theme/src/styles/typography.css
index 27071c30..b322205b 100644
--- a/packages/theme/src/styles/typography.css
+++ b/packages/theme/src/styles/typography.css
@@ -1,17 +1,24 @@
-/**
+/*
* Tailwind CSS v4 Typography Configuration
+ *
+ * Defines base typography tokens that Tailwind v4 automatically converts to utilities:
+ * - font-{family} → font-family utilities (e.g., font-body, font-header)
+ * - text-{size} → font-size utilities (e.g., text-12, text-16)
+ * - font-{weight} → font-weight utilities (e.g., font-regular, font-bold)
+ * - tracking-{spacing} → letter-spacing utilities (e.g., tracking-default, tracking-tight)
+ * - leading-{height} → line-height utilities (e.g., leading-spacious, leading-tight)
*/
@theme {
/* ==================== Base Typography Tokens ==================== */
/* Font Families */
- --font-family-marquee: "STIX Two Text";
- --font-family-header: "Open Sans";
- --font-family-body: "Open Sans";
- --font-family-code: "Source Code Pro";
- --font-family-caption: "Open Sans";
- --font-family-label: "Open Sans";
+ --font-marquee: "STIX Two Text";
+ --font-header: "Open Sans";
+ --font-body: "Open Sans";
+ --font-code: "Source Code Pro";
+ --font-caption: "Open Sans";
+ --font-label: "Open Sans";
/* Font Weights */
--font-weight-regular: 400;
@@ -75,375 +82,210 @@
--font-size-32: calc(var(--font-size-31) * var(--typescale-ratio)); /* typescale-32 */
--font-size-33: calc(var(--font-size-32) * var(--typescale-ratio)); /* typescale-33 */
--font-size-34: calc(var(--font-size-33) * var(--typescale-ratio)); /* typescale-34 */
-}
-/* ==================== Text Style Utilities ==================== */
-/* Composite utilities that apply all typography properties together */
-/* These directly reference base tokens from @theme */
-
-@layer utilities {
- /* marquee text style utilities */
- .text-marquee-sm {
- font-size: var(--font-size-23);
- font-family: var(--font-family-marquee);
- font-weight: var(--font-weight-semibold);
- letter-spacing: var(--letter-spacing-default);
- line-height: var(--line-height-tight);
- }
-
- .text-marquee-md {
- font-size: var(--font-size-26);
- font-family: var(--font-family-marquee);
- font-weight: var(--font-weight-semibold);
- letter-spacing: var(--letter-spacing-default);
- line-height: var(--line-height-tight);
- }
-
- .text-marquee-lg {
- font-size: var(--font-size-29);
- font-family: var(--font-family-marquee);
- font-weight: var(--font-weight-semibold);
- letter-spacing: var(--letter-spacing-default);
- line-height: var(--line-height-tight);
- }
-
- .text-marquee-xl {
- font-size: var(--font-size-31);
- font-family: var(--font-family-marquee);
- font-weight: var(--font-weight-semibold);
- letter-spacing: var(--letter-spacing-default);
- line-height: var(--line-height-tight);
- }
-
- /* Default marquee utility (maps to md) */
- .text-marquee {
- font-size: var(--font-size-26);
- font-family: var(--font-family-marquee);
- font-weight: var(--font-weight-semibold);
- letter-spacing: var(--letter-spacing-default);
- line-height: var(--line-height-tight);
- }
-
- /* header text style utilities */
- .text-header-2xs {
- font-size: var(--font-size-8);
- font-family: var(--font-family-header);
- font-weight: var(--font-weight-bold);
- letter-spacing: var(--letter-spacing-condensed);
- line-height: var(--line-height-comfy);
- }
-
- .text-header-micro {
- font-size: var(--font-size-5);
- font-family: var(--font-family-header);
- font-weight: var(--font-weight-bold);
- letter-spacing: var(--letter-spacing-condensed);
- line-height: var(--line-height-comfy);
- }
-
- .text-header-nano {
- font-size: var(--font-size-3);
- font-family: var(--font-family-header);
- font-weight: var(--font-weight-bold);
- letter-spacing: var(--letter-spacing-condensed);
- line-height: var(--line-height-comfy);
- }
-
- .text-header-xs {
- font-size: var(--font-size-10);
- font-family: var(--font-family-header);
- font-weight: var(--font-weight-bold);
- letter-spacing: var(--letter-spacing-condensed);
- line-height: var(--line-height-comfy);
- }
-
- .text-header-sm {
- font-size: var(--font-size-12);
- font-family: var(--font-family-header);
- font-weight: var(--font-weight-bold);
- letter-spacing: var(--letter-spacing-condensed);
- line-height: var(--line-height-comfy);
- }
-
- .text-header-md {
- font-size: var(--font-size-14);
- font-family: var(--font-family-header);
- font-weight: var(--font-weight-bold);
- letter-spacing: var(--letter-spacing-condensed);
- line-height: var(--line-height-comfy);
- }
-
- .text-header-lg {
- font-size: var(--font-size-17);
- font-family: var(--font-family-header);
- font-weight: var(--font-weight-bold);
- letter-spacing: var(--letter-spacing-condensed);
- line-height: var(--line-height-tight);
- }
-
- .text-header-xl {
- font-size: var(--font-size-19);
- font-family: var(--font-family-header);
- font-weight: var(--font-weight-bold);
- letter-spacing: var(--letter-spacing-condensed);
- line-height: var(--line-height-tight);
- }
-
- .text-header-2xl {
- font-size: var(--font-size-23);
- font-family: var(--font-family-header);
- font-weight: var(--font-weight-bold);
- letter-spacing: var(--letter-spacing-condensed);
- line-height: var(--line-height-tight);
- }
-
- .text-header-3xl {
- font-size: var(--font-size-26);
- font-family: var(--font-family-header);
- font-weight: var(--font-weight-bold);
- letter-spacing: var(--letter-spacing-condensed);
- line-height: var(--line-height-tight);
- }
-
- /* Default header utility (maps to md) */
- .text-header {
- font-size: var(--font-size-14);
- font-family: var(--font-family-header);
- font-weight: var(--font-weight-bold);
- letter-spacing: var(--letter-spacing-condensed);
- line-height: var(--line-height-comfy);
- }
-
- /* body text style utilities */
- .text-body-2xs {
- font-size: var(--font-size-10);
- font-family: var(--font-family-body);
- font-weight: var(--font-weight-regular);
- letter-spacing: var(--letter-spacing-default);
- line-height: var(--line-height-spacious);
- }
-
- .text-body-3xs {
- font-size: var(--font-size-9);
- font-family: var(--font-family-body);
- font-weight: var(--font-weight-regular);
- letter-spacing: var(--letter-spacing-default);
- line-height: var(--line-height-spacious);
- }
-
- .text-body-micro {
- font-size: var(--font-size-8);
- font-family: var(--font-family-body);
- font-weight: var(--font-weight-regular);
- letter-spacing: var(--letter-spacing-default);
- line-height: var(--line-height-spacious);
- }
-
- .text-body-nano {
- font-size: var(--font-size-7);
- font-family: var(--font-family-body);
- font-weight: var(--font-weight-regular);
- letter-spacing: var(--letter-spacing-default);
- line-height: var(--line-height-spacious);
- }
-
- .text-body-pico {
- font-size: var(--font-size-6);
- font-family: var(--font-family-body);
- font-weight: var(--font-weight-regular);
- letter-spacing: var(--letter-spacing-default);
- line-height: var(--line-height-spacious);
- }
-
- .text-body-xs {
- font-size: var(--font-size-12);
- font-family: var(--font-family-body);
- font-weight: var(--font-weight-regular);
- letter-spacing: var(--letter-spacing-default);
- line-height: var(--line-height-spacious);
- }
-
- .text-body-sm {
- font-size: var(--font-size-14);
- font-family: var(--font-family-body);
- font-weight: var(--font-weight-regular);
- letter-spacing: var(--letter-spacing-default);
- line-height: var(--line-height-spacious);
- }
-
- .text-body-md {
- font-size: var(--font-size-16);
- font-family: var(--font-family-body);
- font-weight: var(--font-weight-regular);
- letter-spacing: var(--letter-spacing-default);
- line-height: var(--line-height-spacious);
- }
-
- .text-body-lg {
- font-size: var(--font-size-18);
- font-family: var(--font-family-body);
- font-weight: var(--font-weight-regular);
- letter-spacing: var(--letter-spacing-default);
- line-height: var(--line-height-spacious);
- }
-
- .text-body-xl {
- font-size: var(--font-size-21);
- font-family: var(--font-family-body);
- font-weight: var(--font-weight-regular);
- letter-spacing: var(--letter-spacing-default);
- line-height: var(--line-height-spacious);
- }
-
- /* Default body utility (maps to md) */
- .text-body {
- font-size: var(--font-size-16);
- font-family: var(--font-family-body);
- font-weight: var(--font-weight-regular);
- letter-spacing: var(--letter-spacing-default);
- line-height: var(--line-height-spacious);
- }
-
- /* code text style utilities */
- .text-code-sm {
- font-size: var(--font-size-10);
- font-family: var(--font-family-code);
- font-weight: var(--font-weight-regular);
- letter-spacing: var(--letter-spacing-default);
- line-height: var(--line-height-spacious);
- }
-
- .text-code-md {
- font-size: var(--font-size-12);
- font-family: var(--font-family-code);
- font-weight: var(--font-weight-regular);
- letter-spacing: var(--letter-spacing-default);
- line-height: var(--line-height-spacious);
- }
-
- /* Default code utility (maps to md) */
- .text-code {
- font-size: var(--font-size-12);
- font-family: var(--font-family-code);
- font-weight: var(--font-weight-regular);
- letter-spacing: var(--letter-spacing-default);
- line-height: var(--line-height-spacious);
- }
-
- /* caption text style utilities */
- .text-caption-sm {
- font-size: var(--font-size-8);
- font-family: var(--font-family-caption);
- font-weight: var(--font-weight-regular);
- letter-spacing: var(--letter-spacing-relaxed);
- line-height: var(--line-height-spacious);
- }
-
- .text-caption-md {
- font-size: var(--font-size-10);
- font-family: var(--font-family-caption);
- font-weight: var(--font-weight-regular);
- letter-spacing: var(--letter-spacing-relaxed);
- line-height: var(--line-height-spacious);
- }
-
- /* Default caption utility (maps to md) */
- .text-caption {
- font-size: var(--font-size-10);
- font-family: var(--font-family-caption);
- font-weight: var(--font-weight-regular);
- letter-spacing: var(--letter-spacing-relaxed);
- line-height: var(--line-height-spacious);
- }
-
- /* label text style utilities */
- .text-label-2xs {
- font-size: var(--font-size-8);
- font-family: var(--font-family-header);
- font-weight: var(--font-weight-bold);
- letter-spacing: var(--letter-spacing-tight);
- line-height: var(--line-height-single);
- }
-
- .text-label-micro {
- font-size: var(--font-size-5);
- font-family: var(--font-family-header);
- font-weight: var(--font-weight-bold);
- letter-spacing: var(--letter-spacing-tight);
- line-height: var(--line-height-single);
- }
-
- .text-label-nano {
- font-size: var(--font-size-3);
- font-family: var(--font-family-header);
- font-weight: var(--font-weight-bold);
- letter-spacing: var(--letter-spacing-condensed);
- line-height: var(--line-height-comfy);
- }
-
- .text-label-xs {
- font-size: var(--font-size-10);
- font-family: var(--font-family-header);
- font-weight: var(--font-weight-bold);
- letter-spacing: var(--letter-spacing-tight);
- line-height: var(--line-height-single);
- }
-
- .text-label-sm {
- font-size: var(--font-size-12);
- font-family: var(--font-family-header);
- font-weight: var(--font-weight-bold);
- letter-spacing: var(--letter-spacing-tight);
- line-height: var(--line-height-single);
- }
-
- .text-label-md {
- font-size: var(--font-size-14);
- font-family: var(--font-family-header);
- font-weight: var(--font-weight-bold);
- letter-spacing: var(--letter-spacing-tight);
- line-height: var(--line-height-single);
- }
-
- .text-label-lg {
- font-size: var(--font-size-17);
- font-family: var(--font-family-header);
- font-weight: var(--font-weight-bold);
- letter-spacing: var(--letter-spacing-tight);
- line-height: var(--line-height-single);
- }
-
- .text-label-xl {
- font-size: var(--font-size-19);
- font-family: var(--font-family-header);
- font-weight: var(--font-weight-bold);
- letter-spacing: var(--letter-spacing-tight);
- line-height: var(--line-height-single);
- }
-
- .text-label-2xl {
- font-size: var(--font-size-23);
- font-family: var(--font-family-header);
- font-weight: var(--font-weight-bold);
- letter-spacing: var(--letter-spacing-tight);
- line-height: var(--line-height-single);
- }
-
- .text-label-3xl {
- font-size: var(--font-size-26);
- font-family: var(--font-family-header);
- font-weight: var(--font-weight-bold);
- letter-spacing: var(--letter-spacing-tight);
- line-height: var(--line-height-single);
- }
-
- /* Default label utility (maps to md) */
- .text-label {
- font-size: var(--font-size-14);
- font-family: var(--font-family-header);
- font-weight: var(--font-weight-bold);
- letter-spacing: var(--letter-spacing-tight);
- line-height: var(--line-height-single);
- }
+ /* ==================== Text Style Tokens ==================== */
+ /* Composite text styles (without font-family for flexibility) */
+ /* Usage: Apply font-family separately, then use text style tokens */
+
+ /* marquee text styles */
+ --text-marquee-sm: var(--font-size-23);
+ --text-marquee-sm--font-weight: var(--font-weight-semibold);
+ --text-marquee-sm--letter-spacing: var(--letter-spacing-default);
+ --text-marquee-sm--line-height: var(--line-height-tight);
+
+ --text-marquee-md: var(--font-size-26);
+ --text-marquee-md--font-weight: var(--font-weight-semibold);
+ --text-marquee-md--letter-spacing: var(--letter-spacing-default);
+ --text-marquee-md--line-height: var(--line-height-tight);
+
+ --text-marquee-lg: var(--font-size-29);
+ --text-marquee-lg--font-weight: var(--font-weight-semibold);
+ --text-marquee-lg--letter-spacing: var(--letter-spacing-default);
+ --text-marquee-lg--line-height: var(--line-height-tight);
+
+ --text-marquee-xl: var(--font-size-31);
+ --text-marquee-xl--font-weight: var(--font-weight-semibold);
+ --text-marquee-xl--letter-spacing: var(--letter-spacing-default);
+ --text-marquee-xl--line-height: var(--line-height-tight);
+
+
+ /* header text styles */
+ --text-header-2xs: var(--font-size-8);
+ --text-header-2xs--font-weight: var(--font-weight-bold);
+ --text-header-2xs--letter-spacing: var(--letter-spacing-condensed);
+ --text-header-2xs--line-height: var(--line-height-comfy);
+
+ --text-header-micro: var(--font-size-5);
+ --text-header-micro--font-weight: var(--font-weight-bold);
+ --text-header-micro--letter-spacing: var(--letter-spacing-condensed);
+ --text-header-micro--line-height: var(--line-height-comfy);
+
+ --text-header-nano: var(--font-size-3);
+ --text-header-nano--font-weight: var(--font-weight-bold);
+ --text-header-nano--letter-spacing: var(--letter-spacing-condensed);
+ --text-header-nano--line-height: var(--line-height-comfy);
+
+ --text-header-xs: var(--font-size-10);
+ --text-header-xs--font-weight: var(--font-weight-bold);
+ --text-header-xs--letter-spacing: var(--letter-spacing-condensed);
+ --text-header-xs--line-height: var(--line-height-comfy);
+
+ --text-header-sm: var(--font-size-12);
+ --text-header-sm--font-weight: var(--font-weight-bold);
+ --text-header-sm--letter-spacing: var(--letter-spacing-condensed);
+ --text-header-sm--line-height: var(--line-height-comfy);
+
+ --text-header-md: var(--font-size-14);
+ --text-header-md--font-weight: var(--font-weight-bold);
+ --text-header-md--letter-spacing: var(--letter-spacing-condensed);
+ --text-header-md--line-height: var(--line-height-comfy);
+
+ --text-header-lg: var(--font-size-17);
+ --text-header-lg--font-weight: var(--font-weight-bold);
+ --text-header-lg--letter-spacing: var(--letter-spacing-condensed);
+ --text-header-lg--line-height: var(--line-height-tight);
+
+ --text-header-xl: var(--font-size-19);
+ --text-header-xl--font-weight: var(--font-weight-bold);
+ --text-header-xl--letter-spacing: var(--letter-spacing-condensed);
+ --text-header-xl--line-height: var(--line-height-tight);
+
+ --text-header-2xl: var(--font-size-23);
+ --text-header-2xl--font-weight: var(--font-weight-bold);
+ --text-header-2xl--letter-spacing: var(--letter-spacing-condensed);
+ --text-header-2xl--line-height: var(--line-height-tight);
+
+ --text-header-3xl: var(--font-size-26);
+ --text-header-3xl--font-weight: var(--font-weight-bold);
+ --text-header-3xl--letter-spacing: var(--letter-spacing-condensed);
+ --text-header-3xl--line-height: var(--line-height-tight);
+
+
+ /* body text styles */
+ --text-body-2xs: var(--font-size-10);
+ --text-body-2xs--font-weight: var(--font-weight-regular);
+ --text-body-2xs--letter-spacing: var(--letter-spacing-default);
+ --text-body-2xs--line-height: var(--line-height-spacious);
+
+ --text-body-3xs: var(--font-size-9);
+ --text-body-3xs--font-weight: var(--font-weight-regular);
+ --text-body-3xs--letter-spacing: var(--letter-spacing-default);
+ --text-body-3xs--line-height: var(--line-height-spacious);
+
+ --text-body-micro: var(--font-size-8);
+ --text-body-micro--font-weight: var(--font-weight-regular);
+ --text-body-micro--letter-spacing: var(--letter-spacing-default);
+ --text-body-micro--line-height: var(--line-height-spacious);
+
+ --text-body-nano: var(--font-size-7);
+ --text-body-nano--font-weight: var(--font-weight-regular);
+ --text-body-nano--letter-spacing: var(--letter-spacing-default);
+ --text-body-nano--line-height: var(--line-height-spacious);
+
+ --text-body-pico: var(--font-size-6);
+ --text-body-pico--font-weight: var(--font-weight-regular);
+ --text-body-pico--letter-spacing: var(--letter-spacing-default);
+ --text-body-pico--line-height: var(--line-height-spacious);
+
+ --text-body-xs: var(--font-size-12);
+ --text-body-xs--font-weight: var(--font-weight-regular);
+ --text-body-xs--letter-spacing: var(--letter-spacing-default);
+ --text-body-xs--line-height: var(--line-height-spacious);
+
+ --text-body-sm: var(--font-size-14);
+ --text-body-sm--font-weight: var(--font-weight-regular);
+ --text-body-sm--letter-spacing: var(--letter-spacing-default);
+ --text-body-sm--line-height: var(--line-height-spacious);
+
+ --text-body-md: var(--font-size-16);
+ --text-body-md--font-weight: var(--font-weight-regular);
+ --text-body-md--letter-spacing: var(--letter-spacing-default);
+ --text-body-md--line-height: var(--line-height-spacious);
+
+ --text-body-lg: var(--font-size-18);
+ --text-body-lg--font-weight: var(--font-weight-regular);
+ --text-body-lg--letter-spacing: var(--letter-spacing-default);
+ --text-body-lg--line-height: var(--line-height-spacious);
+
+ --text-body-xl: var(--font-size-21);
+ --text-body-xl--font-weight: var(--font-weight-regular);
+ --text-body-xl--letter-spacing: var(--letter-spacing-default);
+ --text-body-xl--line-height: var(--line-height-spacious);
+
+
+ /* code text styles */
+ --text-code-sm: var(--font-size-10);
+ --text-code-sm--font-weight: var(--font-weight-regular);
+ --text-code-sm--letter-spacing: var(--letter-spacing-default);
+ --text-code-sm--line-height: var(--line-height-spacious);
+
+ --text-code-md: var(--font-size-12);
+ --text-code-md--font-weight: var(--font-weight-regular);
+ --text-code-md--letter-spacing: var(--letter-spacing-default);
+ --text-code-md--line-height: var(--line-height-spacious);
+
+
+ /* caption text styles */
+ --text-caption-sm: var(--font-size-8);
+ --text-caption-sm--font-weight: var(--font-weight-regular);
+ --text-caption-sm--letter-spacing: var(--letter-spacing-relaxed);
+ --text-caption-sm--line-height: var(--line-height-spacious);
+
+ --text-caption-md: var(--font-size-10);
+ --text-caption-md--font-weight: var(--font-weight-regular);
+ --text-caption-md--letter-spacing: var(--letter-spacing-relaxed);
+ --text-caption-md--line-height: var(--line-height-spacious);
+
+
+ /* label text styles */
+ --text-label-2xs: var(--font-size-8);
+ --text-label-2xs--font-weight: var(--font-weight-bold);
+ --text-label-2xs--letter-spacing: var(--letter-spacing-tight);
+ --text-label-2xs--line-height: var(--line-height-single);
+
+ --text-label-micro: var(--font-size-5);
+ --text-label-micro--font-weight: var(--font-weight-bold);
+ --text-label-micro--letter-spacing: var(--letter-spacing-tight);
+ --text-label-micro--line-height: var(--line-height-single);
+
+ --text-label-nano: var(--font-size-3);
+ --text-label-nano--font-weight: var(--font-weight-bold);
+ --text-label-nano--letter-spacing: var(--letter-spacing-condensed);
+ --text-label-nano--line-height: var(--line-height-comfy);
+
+ --text-label-xs: var(--font-size-10);
+ --text-label-xs--font-weight: var(--font-weight-bold);
+ --text-label-xs--letter-spacing: var(--letter-spacing-tight);
+ --text-label-xs--line-height: var(--line-height-single);
+
+ --text-label-sm: var(--font-size-12);
+ --text-label-sm--font-weight: var(--font-weight-bold);
+ --text-label-sm--letter-spacing: var(--letter-spacing-tight);
+ --text-label-sm--line-height: var(--line-height-single);
+
+ --text-label-md: var(--font-size-14);
+ --text-label-md--font-weight: var(--font-weight-bold);
+ --text-label-md--letter-spacing: var(--letter-spacing-tight);
+ --text-label-md--line-height: var(--line-height-single);
+
+ --text-label-lg: var(--font-size-17);
+ --text-label-lg--font-weight: var(--font-weight-bold);
+ --text-label-lg--letter-spacing: var(--letter-spacing-tight);
+ --text-label-lg--line-height: var(--line-height-single);
+
+ --text-label-xl: var(--font-size-19);
+ --text-label-xl--font-weight: var(--font-weight-bold);
+ --text-label-xl--letter-spacing: var(--letter-spacing-tight);
+ --text-label-xl--line-height: var(--line-height-single);
+
+ --text-label-2xl: var(--font-size-23);
+ --text-label-2xl--font-weight: var(--font-weight-bold);
+ --text-label-2xl--letter-spacing: var(--letter-spacing-tight);
+ --text-label-2xl--line-height: var(--line-height-single);
+
+ --text-label-3xl: var(--font-size-26);
+ --text-label-3xl--font-weight: var(--font-weight-bold);
+ --text-label-3xl--letter-spacing: var(--letter-spacing-tight);
+ --text-label-3xl--line-height: var(--line-height-single);
}
diff --git a/packages/theme/src/tw.ts b/packages/theme/src/tw.ts
index ead1da0e..3a16068d 100644
--- a/packages/theme/src/tw.ts
+++ b/packages/theme/src/tw.ts
@@ -1,6 +1,6 @@
import { extendTailwindMerge } from 'tailwind-merge';
+import { createTV } from 'tailwind-variants';
import type { ClassValue } from 'tailwind-variants';
-export { tv } from 'tailwind-variants';
export type { VariantProps } from 'tailwind-variants';
function flat(arr: ClassValue[], target: ClassValue[]): void {
@@ -23,9 +23,62 @@ const clsx = (...classes: ClassValue[]): string | undefined => {
return voidEmpty(flatArray(classes).filter(Boolean).join(' '));
};
-// This is empty for now as we don't have any configuration
-const twMergeConfig = {};
-const twMergeBase = extendTailwindMerge({ extend: twMergeConfig });
+// Common size units used across all design tokens (icons, typography, etc.)
+const COMMON_UNITS = [
+ 'pico',
+ 'nano',
+ 'micro',
+ '3xs',
+ '2xs',
+ 'xs',
+ 'sm',
+ 'md',
+ 'lg',
+ 'xl',
+ '2xl',
+ '3xl',
+ 'kilo',
+ 'mega'
+] as const;
+
+const ELEVATION_LEVELS = ['0', '1', '2', '3', '4', '5'];
+
+const twMergeConfig = {
+ extend: {
+ classGroups: {
+ // Icon sizes
+ 'icon-size': [{ 'size-icon': COMMON_UNITS }],
+
+ // Border widths (directional variants handled automatically)
+ 'border-w': [{ border: ['thin', 'heavy', 'aggressive'] }],
+
+ // Border radius (extend existing rounded utilities)
+ rounded: [{ rounded: ['default', 'pill'] }],
+
+ // Elevation shadows
+ shadow: [{ 'shadow-elevation': ELEVATION_LEVELS }],
+
+ // Opacity
+ opacity: [{ opacity: ['hover', 'disabled'] }],
+
+ // Typography composite text styles (extend font-size class group)
+ // These set font-size + other properties, so they should conflict with text-* utilities
+ 'font-size': [
+ { 'text-marquee': [...COMMON_UNITS] },
+ { 'text-header': [...COMMON_UNITS] },
+ { 'text-body': [...COMMON_UNITS] },
+ { 'text-code': [...COMMON_UNITS] },
+ { 'text-caption': [...COMMON_UNITS] },
+ { 'text-label': [...COMMON_UNITS] }
+ ]
+ },
+ conflictingClassGroups: {
+ 'icon-size': ['w', 'h', 'size']
+ }
+ }
+} as const;
+
+const twMergeBase = extendTailwindMerge<'icon-size'>(twMergeConfig);
export function twMerge(defaultClass: ClassValue, overwrites: ClassValue) {
if (overwrites) {
@@ -33,3 +86,8 @@ export function twMerge(defaultClass: ClassValue, overwrites: ClassValue) {
}
return clsx(defaultClass);
}
+
+export const tv = createTV({
+ twMerge: true,
+ twMergeConfig
+});
diff --git a/site/app/components/icons.gts b/site/app/components/icons.gts
index b3ff17f3..6e132028 100644
--- a/site/app/components/icons.gts
+++ b/site/app/components/icons.gts
@@ -9,7 +9,7 @@ export const ViewIcon =
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
- class="w-4 h-4"
+ class="size-icon-lg"
...attributes
>
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
- class="w-4 h-4"
+ class="size-icon-lg"
...attributes
>
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
- class="w-4 h-4"
+ class="size-icon-lg"
...attributes
>
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
- class="w-4 h-4"
+ class="size-icon-lg"
...attributes
>
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
- class="w-4 h-4"
+ class="size-icon-lg"
...attributes
>
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
- class="w-4 h-4"
+ class="size-icon-lg"
...attributes
>
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
- class="w-4 h-4"
+ class="size-icon-lg"
...attributes
>
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
- class="w-5 h-5"
+ class="size-icon-md"
...attributes
>
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
- class="w-6 h-6"
+ class="size-icon-lg"
...attributes
>
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
- class="size-5"
+ class="size-icon-md"
...attributes
>
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
- class="size-4"
+ class="size-icon-sm"
...attributes
>
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
- class="size-4"
+ class="size-icon-sm"
...attributes
>
;
export const UserIcon =
-
+
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
- class="w-6 h-6"
+ class="size-icon-lg"
...attributes
>
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
- class="w-6 h-6"
+ class="size-icon-lg"
...attributes
>
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
- class="w-6 h-6"
+ class="size-icon-lg"
...attributes
>
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
- class="w-6 h-6"
+ class="size-icon-lg"
...attributes
>
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
- class="w-6 h-6"
+ class="size-icon-lg"
...attributes
>
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
- class="w-6 h-6"
+ class="size-icon-lg"
...attributes
>
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
- class="w-6 h-6"
+ class="size-icon-lg"
...attributes
>
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
- class="w-6 h-6"
+ class="size-icon-lg"
...attributes
>
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
- class="w-6 h-6"
+ class="size-icon-lg"
...attributes
>
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
- class="w-6 h-6"
+ class="size-icon-lg"
...attributes
>
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
- class="w-4 h-4"
+ class="size-icon-lg"
...attributes
>
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
- class="w-4 h-4"
+ class="size-icon-lg"
...attributes
>