@felan-ai/design-system 0.1.0 → 0.1.1
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 +10 -9
- package/package.json +3 -1
- package/project/README.md +6 -4
- package/project/SKILL.md +2 -1
- package/project/colors_and_type.css +2 -309
- package/project/styles.css +2 -2
- package/project/tokens.css +306 -0
package/README.md
CHANGED
|
@@ -13,8 +13,9 @@ The full design spec — palette, typography, spacing, component anatomy, voice
|
|
|
13
13
|
├── project/ ← the design system itself
|
|
14
14
|
│ ├── README.md ← full design spec (start here)
|
|
15
15
|
│ ├── SKILL.md ← skill contract for Claude Code / agents
|
|
16
|
-
│ ├──
|
|
17
|
-
│ ├──
|
|
16
|
+
│ ├── tokens.css ← canonical tokens + semantic type classes
|
|
17
|
+
│ ├── colors_and_type.css ← preview entry with hosted Geist fonts
|
|
18
|
+
│ ├── styles.css ← font-free production entry
|
|
18
19
|
│ ├── assets/ ← logos, icons, customer & integration marks
|
|
19
20
|
│ ├── templates/ ← reusable customer-facing artifacts, including commercial quotes
|
|
20
21
|
│ └── preview/ ← design-system cards (brand, colors, type, components…)
|
|
@@ -49,12 +50,12 @@ pnpm add @felan-ai/design-system
|
|
|
49
50
|
@import "@felan-ai/design-system/styles.css";
|
|
50
51
|
```
|
|
51
52
|
|
|
52
|
-
The package's HSL-triplet tokens are consumed with `hsl(var(--token))`.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
`./
|
|
57
|
-
`./eslint/shadcn`.
|
|
53
|
+
The package's HSL-triplet tokens are consumed with `hsl(var(--token))`.
|
|
54
|
+
`styles.css` and `tokens.css` are font-free so production applications can
|
|
55
|
+
self-host Geist. Static previews use `colors_and_type.css`, which also loads
|
|
56
|
+
Geist from Google Fonts. Public exports are documented in the package README
|
|
57
|
+
and include `./styles.css`, `./tokens.css`, `./colors_and_type.css`, `./spec`,
|
|
58
|
+
`./skill`, `./assets/*`, `./templates/quote.html`, and `./eslint/shadcn`.
|
|
58
59
|
|
|
59
60
|
See [`docs/consuming.md`](docs/consuming.md) for the complete export table,
|
|
60
61
|
package exclusions, lint limitations, asset policy, and consumer rollout.
|
|
@@ -77,5 +78,5 @@ Tailwind 4 migration. `go-to-market` consumes the assets and templates only.
|
|
|
77
78
|
- The reusable commercial quote template lives in `project/templates/quote/`; see its README for
|
|
78
79
|
placeholders and print instructions.
|
|
79
80
|
- `project/_ds_manifest.json` and `project/_ds_bundle.js` are generated by the design tooling; the catalog renders from the manifest, so regenerating it keeps the catalog in sync.
|
|
80
|
-
- Geist Sans/Mono
|
|
81
|
+
- Static previews load Geist Sans/Mono from the Google Fonts CDN; production consumers provide their own font files.
|
|
81
82
|
- `npm pack --dry-run` and the package verifier are the source of truth for the published file surface; catalog previews and generated metadata are repository-only.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@felan-ai/design-system",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Felan design tokens, brand guidance, reusable assets, templates, and lint policy",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
},
|
|
22
22
|
"files": [
|
|
23
23
|
"project/styles.css",
|
|
24
|
+
"project/tokens.css",
|
|
24
25
|
"project/colors_and_type.css",
|
|
25
26
|
"project/README.md",
|
|
26
27
|
"project/SKILL.md",
|
|
@@ -40,6 +41,7 @@
|
|
|
40
41
|
"exports": {
|
|
41
42
|
".": "./project/styles.css",
|
|
42
43
|
"./styles.css": "./project/styles.css",
|
|
44
|
+
"./tokens.css": "./project/tokens.css",
|
|
43
45
|
"./colors_and_type.css": "./project/colors_and_type.css",
|
|
44
46
|
"./spec": "./project/README.md",
|
|
45
47
|
"./skill": "./project/SKILL.md",
|
package/project/README.md
CHANGED
|
@@ -13,7 +13,7 @@ This system began as a reverse-engineering of the **Bugzy** (QA agent) codebase
|
|
|
13
13
|
|
|
14
14
|
- **Visual origin:** the Bugzy web app (Next.js + Tailwind + shadcn/ui) — token structure, warm-neutral ramp, Geist type, orb/glow treatment, component anatomy all carried over and are approved as-is. Those legacy `web/` code paths are historical provenance only; do not treat them as Felan product spec.
|
|
15
15
|
- **Brand:** `assets/felan-logo.svg` / `.png` — the forest-green geometric aperture mark.
|
|
16
|
-
- **Canonical tokens:** `
|
|
16
|
+
- **Canonical tokens:** `tokens.css`. All extracted assets live in `assets/`.
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
@@ -237,7 +237,9 @@ These are all copied into `assets/integrations/` and `assets/customers/` here.
|
|
|
237
237
|
```
|
|
238
238
|
├── README.md ← you are here
|
|
239
239
|
├── SKILL.md ← skill contract for Claude Code / agents
|
|
240
|
-
├──
|
|
240
|
+
├── tokens.css ← canonical tokens + semantic type classes
|
|
241
|
+
├── colors_and_type.css ← preview entry with hosted Geist fonts
|
|
242
|
+
├── styles.css ← font-free production entry
|
|
241
243
|
├── assets/ ← logos, icons, customer & integration marks, avatars
|
|
242
244
|
│ ├── felan-logo.png ← primary mark (forest-green “io” aperture on cream)
|
|
243
245
|
│ ├── felan-logo.svg ← primary mark, vector (forest green, transparent)
|
|
@@ -250,11 +252,11 @@ These are all copied into `assets/integrations/` and `assets/customers/` here.
|
|
|
250
252
|
├── preview/ ← design-system cards (rendered in Design System tab)
|
|
251
253
|
├── templates/ ← reusable customer-facing artifacts
|
|
252
254
|
│ └── quote/ ← A4 commercial quote HTML template + placeholder contract
|
|
253
|
-
└── fonts/ ← (empty) —
|
|
255
|
+
└── fonts/ ← (empty) — production consumers self-host Geist
|
|
254
256
|
```
|
|
255
257
|
|
|
256
258
|
## Font substitution — flagged
|
|
257
259
|
|
|
258
|
-
|
|
260
|
+
Production consumers provide **Geist Sans** and **Geist Mono** locally. The design-system previews load the equivalent Google Fonts families through `colors_and_type.css` without adding a remote font dependency to `styles.css` or `tokens.css`.
|
|
259
261
|
|
|
260
262
|
No other font substitutions were needed — the Geist family is available on Google Fonts at the exact weights the codebase uses (400/500/600/700/800).
|
package/project/SKILL.md
CHANGED
|
@@ -17,7 +17,8 @@ An agentic engineering platform — the team layer for AI-native software develo
|
|
|
17
17
|
## What's in here
|
|
18
18
|
|
|
19
19
|
- `README.md` — voice, tone, visual foundations, iconography, content fundamentals
|
|
20
|
-
- `
|
|
20
|
+
- `tokens.css` — canonical HSL tokens (light + dark) and semantic typography classes
|
|
21
|
+
- `colors_and_type.css` — preview entry that adds hosted Geist fonts
|
|
21
22
|
- `assets/` — logo (`felan-logo.svg`/`.png`, forest-green geometric mark), app icons, customer marks, integration SVGs
|
|
22
23
|
- `preview/` — design-system cards: colors, type, spacing, components, brand
|
|
23
24
|
|
|
@@ -1,309 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Source of truth: web/app/globals.css (HSL var system) +
|
|
4
|
-
web/tailwind.config.ts (font families)
|
|
5
|
-
|
|
6
|
-
Fonts: Geist Sans + Geist Mono (via Google Fonts CDN)
|
|
7
|
-
The production app uses the `geist` npm package; the
|
|
8
|
-
Google Fonts equivalent is visually identical.
|
|
9
|
-
|
|
10
|
-
Modes: default is LIGHT; add class="dark" on root for DARK.
|
|
11
|
-
The marketing site actually ships in forced-dark mode — see
|
|
12
|
-
web/app/page.tsx which wraps the homepage in <div className="dark">.
|
|
13
|
-
============================================================ */
|
|
14
|
-
|
|
15
|
-
@import url('https://fonts.googleapis.com/css2?family=Geist:wght@300;400;500;600;700;800&family=Geist+Mono:wght@400;500;600&display=swap');
|
|
16
|
-
|
|
17
|
-
:root {
|
|
18
|
-
/* ---------- Brand palette (raw) ---------- */
|
|
19
|
-
--felan-green: hsl(152 44% 26%); /* @kind color */ /* primary brand */
|
|
20
|
-
--felan-green-hot: hsl(150 55% 34%); /* @kind color */ /* hero glow / gradient orb */
|
|
21
|
-
--felan-green-dark: hsl(152 48% 20%); /* @kind color */
|
|
22
|
-
--felan-ink: hsl(20 14% 11%); /* @kind color */ /* near-black, warm */
|
|
23
|
-
--felan-paper: hsl(0 0% 99%); /* @kind color */ /* warm off-white */
|
|
24
|
-
|
|
25
|
-
/* ---------- Core tokens (HSL triplets, Tailwind-compatible) ---------- */
|
|
26
|
-
/* Backgrounds */
|
|
27
|
-
--background: 0 0% 99%; /* @kind color */
|
|
28
|
-
--foreground: 20 14% 11%; /* @kind color */
|
|
29
|
-
|
|
30
|
-
/* Cards & Popovers */
|
|
31
|
-
--card: 0 0% 100%; /* @kind color */
|
|
32
|
-
--card-foreground: 20 14% 11%; /* @kind color */
|
|
33
|
-
--popover: 0 0% 100%; /* @kind color */
|
|
34
|
-
--popover-foreground: 20 14% 11%; /* @kind color */
|
|
35
|
-
|
|
36
|
-
/* Primary — neutral ink for high contrast */
|
|
37
|
-
--primary: 20 14% 11%; /* @kind color */
|
|
38
|
-
--primary-foreground: 0 0% 99%; /* @kind color */
|
|
39
|
-
|
|
40
|
-
/* Secondary */
|
|
41
|
-
--secondary: 30 10% 95%; /* @kind color */
|
|
42
|
-
--secondary-foreground: 20 14% 20%; /* @kind color */
|
|
43
|
-
|
|
44
|
-
/* Muted */
|
|
45
|
-
--muted: 30 10% 95%; /* @kind color */
|
|
46
|
-
--muted-foreground: 20 6% 44%; /* @kind color */
|
|
47
|
-
|
|
48
|
-
/* Accent (shadcn hover) */
|
|
49
|
-
--accent: 30 10% 95%; /* @kind color */
|
|
50
|
-
--accent-foreground: 20 14% 11%; /* @kind color */
|
|
51
|
-
|
|
52
|
-
/* Brand — the green identity */
|
|
53
|
-
--brand: 152 44% 26%; /* @kind color */
|
|
54
|
-
--brand-foreground: 0 0% 100%; /* @kind color */
|
|
55
|
-
|
|
56
|
-
/* Destructive */
|
|
57
|
-
--destructive: 0 84% 60%; /* @kind color */
|
|
58
|
-
--destructive-foreground: 0 0% 98%; /* @kind color */
|
|
59
|
-
|
|
60
|
-
/* Structural */
|
|
61
|
-
--border: 30 10% 90%; /* @kind color */
|
|
62
|
-
--input: 30 10% 90%; /* @kind color */
|
|
63
|
-
--ring: 152 44% 26%; /* @kind color */
|
|
64
|
-
--radius: 0.5rem; /* @kind radius */
|
|
65
|
-
|
|
66
|
-
/* Surface elevation layers (warm neutrals) */
|
|
67
|
-
--surface-1: 30 8% 97%; /* @kind color */
|
|
68
|
-
--surface-2: 30 8% 94%; /* @kind color */
|
|
69
|
-
--surface-3: 30 8% 91%; /* @kind color */
|
|
70
|
-
|
|
71
|
-
/* Charts / categorical */
|
|
72
|
-
--chart-1: 152 44% 26%; /* @kind color */ /* brand green */
|
|
73
|
-
--chart-2: 180 55% 42%; /* @kind color */ /* teal */
|
|
74
|
-
--chart-3: 220 65% 50%; /* @kind color */ /* blue */
|
|
75
|
-
--chart-4: 45 85% 50%; /* @kind color */ /* amber */
|
|
76
|
-
--chart-5: 280 60% 55%; /* @kind color */ /* violet */
|
|
77
|
-
|
|
78
|
-
/* Status (marketing + product) */
|
|
79
|
-
--success: 142 71% 45%; /* @kind color */
|
|
80
|
-
--warning: 38 92% 50%; /* @kind color */
|
|
81
|
-
--info: 210 90% 55%; /* @kind color */
|
|
82
|
-
|
|
83
|
-
/* Sidebar (product app) */
|
|
84
|
-
--sidebar-background: 30 8% 97%; /* @kind color */
|
|
85
|
-
--sidebar-foreground: 20 6% 40%; /* @kind color */
|
|
86
|
-
--sidebar-primary: 152 44% 26%; /* @kind color */
|
|
87
|
-
--sidebar-primary-foreground: 0 0% 100%; /* @kind color */
|
|
88
|
-
--sidebar-accent: 30 12% 91%; /* @kind color */
|
|
89
|
-
--sidebar-accent-foreground: 20 14% 9%; /* @kind color */
|
|
90
|
-
--sidebar-border: 30 10% 90%; /* @kind color */
|
|
91
|
-
--sidebar-ring: 152 44% 26%; /* @kind color */
|
|
92
|
-
|
|
93
|
-
/* ---------- Typography ---------- */
|
|
94
|
-
--font-sans: 'Geist', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
|
|
95
|
-
--font-mono: 'Geist Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
|
|
96
|
-
|
|
97
|
-
/* Type scale — matches Tailwind defaults used across the app */
|
|
98
|
-
--text-xs: 0.75rem; /* @kind font */ /* 12px — micro labels, tags */
|
|
99
|
-
--text-sm: 0.875rem; /* @kind font */ /* 14px — body small, nav */
|
|
100
|
-
--text-base: 1rem; /* @kind font */ /* 16px — body */
|
|
101
|
-
--text-lg: 1.125rem; /* @kind font */ /* 18px — lead paragraph */
|
|
102
|
-
--text-xl: 1.25rem; /* @kind font */ /* 20px — eyebrow/sub-head */
|
|
103
|
-
--text-2xl: 1.5rem; /* @kind font */ /* 24px — h3 */
|
|
104
|
-
--text-3xl: 1.875rem; /* @kind font */ /* 30px — h2 small */
|
|
105
|
-
--text-4xl: 2.25rem; /* @kind font */ /* 36px — h2 */
|
|
106
|
-
--text-5xl: 3rem; /* @kind font */ /* 48px — h1 mid */
|
|
107
|
-
--text-6xl: 3.75rem; /* @kind font */ /* 60px — hero h1 */
|
|
108
|
-
--text-hero: 4.5rem; /* @kind font */ /* 72px — landing hero */
|
|
109
|
-
|
|
110
|
-
--leading-tight: 1.08; /* @kind font */ /* hero lines */
|
|
111
|
-
--leading-snug: 1.2; /* @kind font */
|
|
112
|
-
--leading-normal: 1.5; /* @kind font */
|
|
113
|
-
--leading-relaxed: 1.65; /* @kind font */
|
|
114
|
-
|
|
115
|
-
--tracking-tight: -0.02em; /* @kind font */
|
|
116
|
-
--tracking-normal: 0; /* @kind font */
|
|
117
|
-
|
|
118
|
-
--weight-regular: 400; /* @kind font */
|
|
119
|
-
--weight-medium: 500; /* @kind font */
|
|
120
|
-
--weight-semibold: 600; /* @kind font */
|
|
121
|
-
--weight-bold: 700; /* @kind font */
|
|
122
|
-
--weight-extrabold: 800; /* @kind font */
|
|
123
|
-
|
|
124
|
-
/* ---------- Elevation & spacing ---------- */
|
|
125
|
-
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
|
126
|
-
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.07), 0 2px 4px -2px rgb(0 0 0 / 0.05);
|
|
127
|
-
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.08), 0 4px 6px -4px rgb(0 0 0 / 0.04);
|
|
128
|
-
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.10), 0 8px 10px -6px rgb(0 0 0 / 0.06);
|
|
129
|
-
--shadow-brand: 0 10px 30px -8px hsl(152 44% 26% / 0.35);
|
|
130
|
-
|
|
131
|
-
--radius-sm: calc(var(--radius) - 4px); /* 4px */
|
|
132
|
-
--radius-md: calc(var(--radius) - 2px); /* 6px */
|
|
133
|
-
--radius-lg: var(--radius); /* 8px */
|
|
134
|
-
--radius-xl: 0.75rem; /* 12px — cards */
|
|
135
|
-
--radius-2xl: 1rem; /* 16px */
|
|
136
|
-
--radius-full: 9999px;
|
|
137
|
-
|
|
138
|
-
/* Signature gradients */
|
|
139
|
-
--gradient-hero-green: radial-gradient(ellipse, hsla(150,55%,34%,0.20) 0%, transparent 70%); /* @kind other */
|
|
140
|
-
--gradient-hero-blue: radial-gradient(ellipse, hsla(220,80%,50%,0.14) 0%, transparent 70%); /* @kind other */
|
|
141
|
-
--gradient-text-fade: linear-gradient(to bottom, hsl(0 0% 100%) 0%, hsl(0 0% 100% / 0.7) 100%); /* @kind other */
|
|
142
|
-
--gradient-divider: linear-gradient(to right, transparent, hsl(0 0% 100% / 0.08), transparent); /* @kind other */
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/* ============================================================
|
|
146
|
-
DARK MODE (default for marketing homepage)
|
|
147
|
-
============================================================ */
|
|
148
|
-
.dark {
|
|
149
|
-
--background: 20 10% 7%; /* @kind color */ /* warm near-black */
|
|
150
|
-
--foreground: 30 10% 90%; /* @kind color */
|
|
151
|
-
|
|
152
|
-
--card: 20 8% 10%; /* @kind color */
|
|
153
|
-
--card-foreground: 30 10% 90%; /* @kind color */
|
|
154
|
-
--popover: 20 8% 10%; /* @kind color */
|
|
155
|
-
--popover-foreground: 30 10% 90%; /* @kind color */
|
|
156
|
-
|
|
157
|
-
--primary: 30 10% 90%; /* @kind color */
|
|
158
|
-
--primary-foreground: 20 10% 7%; /* @kind color */
|
|
159
|
-
|
|
160
|
-
--secondary: 20 8% 15%; /* @kind color */
|
|
161
|
-
--secondary-foreground: 30 10% 90%; /* @kind color */
|
|
162
|
-
|
|
163
|
-
--muted: 20 8% 15%; /* @kind color */
|
|
164
|
-
--muted-foreground: 20 5% 55%; /* @kind color */
|
|
165
|
-
|
|
166
|
-
--accent: 20 8% 15%; /* @kind color */
|
|
167
|
-
--accent-foreground: 30 10% 90%; /* @kind color */
|
|
168
|
-
|
|
169
|
-
--brand: 152 46% 34%; /* @kind color */ /* brighter on dark */
|
|
170
|
-
--brand-foreground: 0 0% 100%; /* @kind color */
|
|
171
|
-
|
|
172
|
-
--destructive: 0 63% 31%; /* @kind color */
|
|
173
|
-
--destructive-foreground: 0 0% 98%; /* @kind color */
|
|
174
|
-
|
|
175
|
-
--border: 20 6% 18%; /* @kind color */
|
|
176
|
-
--input: 20 6% 18%; /* @kind color */
|
|
177
|
-
--ring: 152 46% 34%; /* @kind color */
|
|
178
|
-
|
|
179
|
-
--surface-1: 20 8% 9%; /* @kind color */
|
|
180
|
-
--surface-2: 20 8% 12%; /* @kind color */
|
|
181
|
-
--surface-3: 20 8% 15%; /* @kind color */
|
|
182
|
-
|
|
183
|
-
--sidebar-background: 20 8% 9%; /* @kind color */
|
|
184
|
-
--sidebar-foreground: 20 5% 55%; /* @kind color */
|
|
185
|
-
--sidebar-primary: 152 46% 34%; /* @kind color */
|
|
186
|
-
--sidebar-primary-foreground: 0 0% 100%; /* @kind color */
|
|
187
|
-
--sidebar-accent: 20 8% 16%; /* @kind color */
|
|
188
|
-
--sidebar-accent-foreground: 0 0% 98%; /* @kind color */
|
|
189
|
-
--sidebar-border: 20 6% 15%; /* @kind color */
|
|
190
|
-
--sidebar-ring: 152 46% 34%; /* @kind color */
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/* ============================================================
|
|
194
|
-
SEMANTIC UTILITIES
|
|
195
|
-
============================================================ */
|
|
196
|
-
.felan-bg { background-color: hsl(var(--background)); color: hsl(var(--foreground)); }
|
|
197
|
-
.felan-card { background-color: hsl(var(--card)); color: hsl(var(--card-foreground)); border: 1px solid hsl(var(--border)); border-radius: var(--radius-xl); }
|
|
198
|
-
.felan-surface-1 { background-color: hsl(var(--surface-1)); }
|
|
199
|
-
.felan-surface-2 { background-color: hsl(var(--surface-2)); }
|
|
200
|
-
.felan-surface-3 { background-color: hsl(var(--surface-3)); }
|
|
201
|
-
|
|
202
|
-
/* Hero headline treatment — gradient text fade (dark mode signature) */
|
|
203
|
-
.felan-headline-fade {
|
|
204
|
-
background: linear-gradient(to bottom, #fff 0%, rgba(255,255,255,0.7) 100%);
|
|
205
|
-
-webkit-background-clip: text;
|
|
206
|
-
background-clip: text;
|
|
207
|
-
color: transparent;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/* ============================================================
|
|
211
|
-
SEMANTIC TYPOGRAPHY
|
|
212
|
-
============================================================ */
|
|
213
|
-
body, .felan-body {
|
|
214
|
-
font-family: var(--font-sans);
|
|
215
|
-
font-size: var(--text-base);
|
|
216
|
-
line-height: var(--leading-normal);
|
|
217
|
-
color: hsl(var(--foreground));
|
|
218
|
-
background: hsl(var(--background));
|
|
219
|
-
-webkit-font-smoothing: antialiased;
|
|
220
|
-
text-rendering: optimizeLegibility;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
.felan-h1, h1.felan {
|
|
224
|
-
font-family: var(--font-sans);
|
|
225
|
-
font-size: clamp(var(--text-4xl), 6vw, var(--text-hero));
|
|
226
|
-
font-weight: var(--weight-extrabold);
|
|
227
|
-
letter-spacing: var(--tracking-tight);
|
|
228
|
-
line-height: var(--leading-tight);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
.felan-h2, h2.felan {
|
|
232
|
-
font-family: var(--font-sans);
|
|
233
|
-
font-size: clamp(var(--text-3xl), 4vw, var(--text-5xl));
|
|
234
|
-
font-weight: var(--weight-bold);
|
|
235
|
-
letter-spacing: var(--tracking-tight);
|
|
236
|
-
line-height: 1.15;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
.felan-h3, h3.felan {
|
|
240
|
-
font-family: var(--font-sans);
|
|
241
|
-
font-size: var(--text-2xl);
|
|
242
|
-
font-weight: var(--weight-bold);
|
|
243
|
-
letter-spacing: var(--tracking-tight);
|
|
244
|
-
line-height: 1.25;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
.felan-h4, h4.felan {
|
|
248
|
-
font-family: var(--font-sans);
|
|
249
|
-
font-size: var(--text-xl);
|
|
250
|
-
font-weight: var(--weight-semibold);
|
|
251
|
-
line-height: 1.3;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
.felan-lead {
|
|
255
|
-
font-family: var(--font-sans);
|
|
256
|
-
font-size: var(--text-xl);
|
|
257
|
-
font-weight: var(--weight-regular);
|
|
258
|
-
color: hsl(var(--muted-foreground));
|
|
259
|
-
line-height: var(--leading-relaxed);
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
.felan-p, p.felan {
|
|
263
|
-
font-family: var(--font-sans);
|
|
264
|
-
font-size: var(--text-base);
|
|
265
|
-
line-height: var(--leading-relaxed);
|
|
266
|
-
color: hsl(var(--foreground));
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
.felan-small {
|
|
270
|
-
font-size: var(--text-sm);
|
|
271
|
-
color: hsl(var(--muted-foreground));
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
.felan-eyebrow {
|
|
275
|
-
display: inline-flex;
|
|
276
|
-
align-items: center;
|
|
277
|
-
gap: 0.375rem;
|
|
278
|
-
font-size: var(--text-sm);
|
|
279
|
-
font-weight: var(--weight-medium);
|
|
280
|
-
background: hsl(var(--muted));
|
|
281
|
-
color: hsl(var(--foreground));
|
|
282
|
-
padding: 0.25rem 0.75rem;
|
|
283
|
-
border-radius: var(--radius-lg);
|
|
284
|
-
letter-spacing: 0;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
.felan-overline {
|
|
288
|
-
font-size: var(--text-xs);
|
|
289
|
-
font-weight: var(--weight-medium);
|
|
290
|
-
text-transform: uppercase;
|
|
291
|
-
letter-spacing: 0.08em;
|
|
292
|
-
color: hsl(var(--muted-foreground));
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
.felan-code, code.felan {
|
|
296
|
-
font-family: var(--font-mono);
|
|
297
|
-
font-size: 0.9em;
|
|
298
|
-
background: hsl(var(--muted));
|
|
299
|
-
color: hsl(var(--foreground));
|
|
300
|
-
padding: 0.125em 0.375em;
|
|
301
|
-
border-radius: var(--radius-sm);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
.felan-link {
|
|
305
|
-
color: hsl(var(--brand));
|
|
306
|
-
text-decoration: none;
|
|
307
|
-
font-weight: var(--weight-medium);
|
|
308
|
-
}
|
|
309
|
-
.felan-link:hover { text-decoration: underline; }
|
|
1
|
+
@import url("https://fonts.googleapis.com/css2?family=Geist:wght@300;400;500;600;700;800&family=Geist+Mono:wght@400;500;600&display=swap");
|
|
2
|
+
@import url("./tokens.css");
|
package/project/styles.css
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* ============================================================
|
|
2
2
|
Felan AI — Design System entry stylesheet
|
|
3
|
-
|
|
3
|
+
Import THIS file to get the production foundation (tokens + type).
|
|
4
4
|
Consumers: <link rel="stylesheet" href="styles.css">
|
|
5
5
|
|
|
6
6
|
The per-kit stylesheets (ui_kits/marketing/marketing.css,
|
|
@@ -9,4 +9,4 @@
|
|
|
9
9
|
NOT globally (each sets its own html/body background).
|
|
10
10
|
============================================================ */
|
|
11
11
|
|
|
12
|
-
@import
|
|
12
|
+
@import "./tokens.css";
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
/* ============================================================
|
|
2
|
+
Felan AI — Foundations: Colors & Type
|
|
3
|
+
Source of truth: web/app/globals.css (HSL var system) +
|
|
4
|
+
web/tailwind.config.ts (font families)
|
|
5
|
+
|
|
6
|
+
Fonts: Geist Sans + Geist Mono. Consumers provide the font files;
|
|
7
|
+
static previews load the Google Fonts equivalents separately.
|
|
8
|
+
|
|
9
|
+
Modes: default is LIGHT; add class="dark" on root for DARK.
|
|
10
|
+
The marketing site actually ships in forced-dark mode — see
|
|
11
|
+
web/app/page.tsx which wraps the homepage in <div className="dark">.
|
|
12
|
+
============================================================ */
|
|
13
|
+
|
|
14
|
+
:root {
|
|
15
|
+
/* ---------- Brand palette (raw) ---------- */
|
|
16
|
+
--felan-green: hsl(152 44% 26%); /* @kind color */ /* primary brand */
|
|
17
|
+
--felan-green-hot: hsl(150 55% 34%); /* @kind color */ /* hero glow / gradient orb */
|
|
18
|
+
--felan-green-dark: hsl(152 48% 20%); /* @kind color */
|
|
19
|
+
--felan-ink: hsl(20 14% 11%); /* @kind color */ /* near-black, warm */
|
|
20
|
+
--felan-paper: hsl(0 0% 99%); /* @kind color */ /* warm off-white */
|
|
21
|
+
|
|
22
|
+
/* ---------- Core tokens (HSL triplets, Tailwind-compatible) ---------- */
|
|
23
|
+
/* Backgrounds */
|
|
24
|
+
--background: 0 0% 99%; /* @kind color */
|
|
25
|
+
--foreground: 20 14% 11%; /* @kind color */
|
|
26
|
+
|
|
27
|
+
/* Cards & Popovers */
|
|
28
|
+
--card: 0 0% 100%; /* @kind color */
|
|
29
|
+
--card-foreground: 20 14% 11%; /* @kind color */
|
|
30
|
+
--popover: 0 0% 100%; /* @kind color */
|
|
31
|
+
--popover-foreground: 20 14% 11%; /* @kind color */
|
|
32
|
+
|
|
33
|
+
/* Primary — neutral ink for high contrast */
|
|
34
|
+
--primary: 20 14% 11%; /* @kind color */
|
|
35
|
+
--primary-foreground: 0 0% 99%; /* @kind color */
|
|
36
|
+
|
|
37
|
+
/* Secondary */
|
|
38
|
+
--secondary: 30 10% 95%; /* @kind color */
|
|
39
|
+
--secondary-foreground: 20 14% 20%; /* @kind color */
|
|
40
|
+
|
|
41
|
+
/* Muted */
|
|
42
|
+
--muted: 30 10% 95%; /* @kind color */
|
|
43
|
+
--muted-foreground: 20 6% 44%; /* @kind color */
|
|
44
|
+
|
|
45
|
+
/* Accent (shadcn hover) */
|
|
46
|
+
--accent: 30 10% 95%; /* @kind color */
|
|
47
|
+
--accent-foreground: 20 14% 11%; /* @kind color */
|
|
48
|
+
|
|
49
|
+
/* Brand — the green identity */
|
|
50
|
+
--brand: 152 44% 26%; /* @kind color */
|
|
51
|
+
--brand-foreground: 0 0% 100%; /* @kind color */
|
|
52
|
+
|
|
53
|
+
/* Destructive */
|
|
54
|
+
--destructive: 0 84% 60%; /* @kind color */
|
|
55
|
+
--destructive-foreground: 0 0% 98%; /* @kind color */
|
|
56
|
+
|
|
57
|
+
/* Structural */
|
|
58
|
+
--border: 30 10% 90%; /* @kind color */
|
|
59
|
+
--input: 30 10% 90%; /* @kind color */
|
|
60
|
+
--ring: 152 44% 26%; /* @kind color */
|
|
61
|
+
--radius: 0.5rem; /* @kind radius */
|
|
62
|
+
|
|
63
|
+
/* Surface elevation layers (warm neutrals) */
|
|
64
|
+
--surface-1: 30 8% 97%; /* @kind color */
|
|
65
|
+
--surface-2: 30 8% 94%; /* @kind color */
|
|
66
|
+
--surface-3: 30 8% 91%; /* @kind color */
|
|
67
|
+
|
|
68
|
+
/* Charts / categorical */
|
|
69
|
+
--chart-1: 152 44% 26%; /* @kind color */ /* brand green */
|
|
70
|
+
--chart-2: 180 55% 42%; /* @kind color */ /* teal */
|
|
71
|
+
--chart-3: 220 65% 50%; /* @kind color */ /* blue */
|
|
72
|
+
--chart-4: 45 85% 50%; /* @kind color */ /* amber */
|
|
73
|
+
--chart-5: 280 60% 55%; /* @kind color */ /* violet */
|
|
74
|
+
|
|
75
|
+
/* Status (marketing + product) */
|
|
76
|
+
--success: 142 71% 45%; /* @kind color */
|
|
77
|
+
--warning: 38 92% 50%; /* @kind color */
|
|
78
|
+
--info: 210 90% 55%; /* @kind color */
|
|
79
|
+
|
|
80
|
+
/* Sidebar (product app) */
|
|
81
|
+
--sidebar-background: 30 8% 97%; /* @kind color */
|
|
82
|
+
--sidebar-foreground: 20 6% 40%; /* @kind color */
|
|
83
|
+
--sidebar-primary: 152 44% 26%; /* @kind color */
|
|
84
|
+
--sidebar-primary-foreground: 0 0% 100%; /* @kind color */
|
|
85
|
+
--sidebar-accent: 30 12% 91%; /* @kind color */
|
|
86
|
+
--sidebar-accent-foreground: 20 14% 9%; /* @kind color */
|
|
87
|
+
--sidebar-border: 30 10% 90%; /* @kind color */
|
|
88
|
+
--sidebar-ring: 152 44% 26%; /* @kind color */
|
|
89
|
+
|
|
90
|
+
/* ---------- Typography ---------- */
|
|
91
|
+
--font-sans: 'Geist', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
|
|
92
|
+
--font-mono: 'Geist Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
|
|
93
|
+
|
|
94
|
+
/* Type scale — matches Tailwind defaults used across the app */
|
|
95
|
+
--text-xs: 0.75rem; /* @kind font */ /* 12px — micro labels, tags */
|
|
96
|
+
--text-sm: 0.875rem; /* @kind font */ /* 14px — body small, nav */
|
|
97
|
+
--text-base: 1rem; /* @kind font */ /* 16px — body */
|
|
98
|
+
--text-lg: 1.125rem; /* @kind font */ /* 18px — lead paragraph */
|
|
99
|
+
--text-xl: 1.25rem; /* @kind font */ /* 20px — eyebrow/sub-head */
|
|
100
|
+
--text-2xl: 1.5rem; /* @kind font */ /* 24px — h3 */
|
|
101
|
+
--text-3xl: 1.875rem; /* @kind font */ /* 30px — h2 small */
|
|
102
|
+
--text-4xl: 2.25rem; /* @kind font */ /* 36px — h2 */
|
|
103
|
+
--text-5xl: 3rem; /* @kind font */ /* 48px — h1 mid */
|
|
104
|
+
--text-6xl: 3.75rem; /* @kind font */ /* 60px — hero h1 */
|
|
105
|
+
--text-hero: 4.5rem; /* @kind font */ /* 72px — landing hero */
|
|
106
|
+
|
|
107
|
+
--leading-tight: 1.08; /* @kind font */ /* hero lines */
|
|
108
|
+
--leading-snug: 1.2; /* @kind font */
|
|
109
|
+
--leading-normal: 1.5; /* @kind font */
|
|
110
|
+
--leading-relaxed: 1.65; /* @kind font */
|
|
111
|
+
|
|
112
|
+
--tracking-tight: -0.02em; /* @kind font */
|
|
113
|
+
--tracking-normal: 0; /* @kind font */
|
|
114
|
+
|
|
115
|
+
--weight-regular: 400; /* @kind font */
|
|
116
|
+
--weight-medium: 500; /* @kind font */
|
|
117
|
+
--weight-semibold: 600; /* @kind font */
|
|
118
|
+
--weight-bold: 700; /* @kind font */
|
|
119
|
+
--weight-extrabold: 800; /* @kind font */
|
|
120
|
+
|
|
121
|
+
/* ---------- Elevation & spacing ---------- */
|
|
122
|
+
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
|
123
|
+
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.07), 0 2px 4px -2px rgb(0 0 0 / 0.05);
|
|
124
|
+
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.08), 0 4px 6px -4px rgb(0 0 0 / 0.04);
|
|
125
|
+
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.10), 0 8px 10px -6px rgb(0 0 0 / 0.06);
|
|
126
|
+
--shadow-brand: 0 10px 30px -8px hsl(152 44% 26% / 0.35);
|
|
127
|
+
|
|
128
|
+
--radius-sm: calc(var(--radius) - 4px); /* 4px */
|
|
129
|
+
--radius-md: calc(var(--radius) - 2px); /* 6px */
|
|
130
|
+
--radius-lg: var(--radius); /* 8px */
|
|
131
|
+
--radius-xl: 0.75rem; /* 12px — cards */
|
|
132
|
+
--radius-2xl: 1rem; /* 16px */
|
|
133
|
+
--radius-full: 9999px;
|
|
134
|
+
|
|
135
|
+
/* Signature gradients */
|
|
136
|
+
--gradient-hero-green: radial-gradient(ellipse, hsla(150,55%,34%,0.20) 0%, transparent 70%); /* @kind other */
|
|
137
|
+
--gradient-hero-blue: radial-gradient(ellipse, hsla(220,80%,50%,0.14) 0%, transparent 70%); /* @kind other */
|
|
138
|
+
--gradient-text-fade: linear-gradient(to bottom, hsl(0 0% 100%) 0%, hsl(0 0% 100% / 0.7) 100%); /* @kind other */
|
|
139
|
+
--gradient-divider: linear-gradient(to right, transparent, hsl(0 0% 100% / 0.08), transparent); /* @kind other */
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* ============================================================
|
|
143
|
+
DARK MODE (default for marketing homepage)
|
|
144
|
+
============================================================ */
|
|
145
|
+
.dark {
|
|
146
|
+
--background: 20 10% 7%; /* @kind color */ /* warm near-black */
|
|
147
|
+
--foreground: 30 10% 90%; /* @kind color */
|
|
148
|
+
|
|
149
|
+
--card: 20 8% 10%; /* @kind color */
|
|
150
|
+
--card-foreground: 30 10% 90%; /* @kind color */
|
|
151
|
+
--popover: 20 8% 10%; /* @kind color */
|
|
152
|
+
--popover-foreground: 30 10% 90%; /* @kind color */
|
|
153
|
+
|
|
154
|
+
--primary: 30 10% 90%; /* @kind color */
|
|
155
|
+
--primary-foreground: 20 10% 7%; /* @kind color */
|
|
156
|
+
|
|
157
|
+
--secondary: 20 8% 15%; /* @kind color */
|
|
158
|
+
--secondary-foreground: 30 10% 90%; /* @kind color */
|
|
159
|
+
|
|
160
|
+
--muted: 20 8% 15%; /* @kind color */
|
|
161
|
+
--muted-foreground: 20 5% 55%; /* @kind color */
|
|
162
|
+
|
|
163
|
+
--accent: 20 8% 15%; /* @kind color */
|
|
164
|
+
--accent-foreground: 30 10% 90%; /* @kind color */
|
|
165
|
+
|
|
166
|
+
--brand: 152 46% 34%; /* @kind color */ /* brighter on dark */
|
|
167
|
+
--brand-foreground: 0 0% 100%; /* @kind color */
|
|
168
|
+
|
|
169
|
+
--destructive: 0 63% 31%; /* @kind color */
|
|
170
|
+
--destructive-foreground: 0 0% 98%; /* @kind color */
|
|
171
|
+
|
|
172
|
+
--border: 20 6% 18%; /* @kind color */
|
|
173
|
+
--input: 20 6% 18%; /* @kind color */
|
|
174
|
+
--ring: 152 46% 34%; /* @kind color */
|
|
175
|
+
|
|
176
|
+
--surface-1: 20 8% 9%; /* @kind color */
|
|
177
|
+
--surface-2: 20 8% 12%; /* @kind color */
|
|
178
|
+
--surface-3: 20 8% 15%; /* @kind color */
|
|
179
|
+
|
|
180
|
+
--sidebar-background: 20 8% 9%; /* @kind color */
|
|
181
|
+
--sidebar-foreground: 20 5% 55%; /* @kind color */
|
|
182
|
+
--sidebar-primary: 152 46% 34%; /* @kind color */
|
|
183
|
+
--sidebar-primary-foreground: 0 0% 100%; /* @kind color */
|
|
184
|
+
--sidebar-accent: 20 8% 16%; /* @kind color */
|
|
185
|
+
--sidebar-accent-foreground: 0 0% 98%; /* @kind color */
|
|
186
|
+
--sidebar-border: 20 6% 15%; /* @kind color */
|
|
187
|
+
--sidebar-ring: 152 46% 34%; /* @kind color */
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/* ============================================================
|
|
191
|
+
SEMANTIC UTILITIES
|
|
192
|
+
============================================================ */
|
|
193
|
+
.felan-bg { background-color: hsl(var(--background)); color: hsl(var(--foreground)); }
|
|
194
|
+
.felan-card { background-color: hsl(var(--card)); color: hsl(var(--card-foreground)); border: 1px solid hsl(var(--border)); border-radius: var(--radius-xl); }
|
|
195
|
+
.felan-surface-1 { background-color: hsl(var(--surface-1)); }
|
|
196
|
+
.felan-surface-2 { background-color: hsl(var(--surface-2)); }
|
|
197
|
+
.felan-surface-3 { background-color: hsl(var(--surface-3)); }
|
|
198
|
+
|
|
199
|
+
/* Hero headline treatment — gradient text fade (dark mode signature) */
|
|
200
|
+
.felan-headline-fade {
|
|
201
|
+
background: linear-gradient(to bottom, #fff 0%, rgba(255,255,255,0.7) 100%);
|
|
202
|
+
-webkit-background-clip: text;
|
|
203
|
+
background-clip: text;
|
|
204
|
+
color: transparent;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/* ============================================================
|
|
208
|
+
SEMANTIC TYPOGRAPHY
|
|
209
|
+
============================================================ */
|
|
210
|
+
body, .felan-body {
|
|
211
|
+
font-family: var(--font-sans);
|
|
212
|
+
font-size: var(--text-base);
|
|
213
|
+
line-height: var(--leading-normal);
|
|
214
|
+
color: hsl(var(--foreground));
|
|
215
|
+
background: hsl(var(--background));
|
|
216
|
+
-webkit-font-smoothing: antialiased;
|
|
217
|
+
text-rendering: optimizeLegibility;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.felan-h1, h1.felan {
|
|
221
|
+
font-family: var(--font-sans);
|
|
222
|
+
font-size: clamp(var(--text-4xl), 6vw, var(--text-hero));
|
|
223
|
+
font-weight: var(--weight-extrabold);
|
|
224
|
+
letter-spacing: var(--tracking-tight);
|
|
225
|
+
line-height: var(--leading-tight);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.felan-h2, h2.felan {
|
|
229
|
+
font-family: var(--font-sans);
|
|
230
|
+
font-size: clamp(var(--text-3xl), 4vw, var(--text-5xl));
|
|
231
|
+
font-weight: var(--weight-bold);
|
|
232
|
+
letter-spacing: var(--tracking-tight);
|
|
233
|
+
line-height: 1.15;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.felan-h3, h3.felan {
|
|
237
|
+
font-family: var(--font-sans);
|
|
238
|
+
font-size: var(--text-2xl);
|
|
239
|
+
font-weight: var(--weight-bold);
|
|
240
|
+
letter-spacing: var(--tracking-tight);
|
|
241
|
+
line-height: 1.25;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.felan-h4, h4.felan {
|
|
245
|
+
font-family: var(--font-sans);
|
|
246
|
+
font-size: var(--text-xl);
|
|
247
|
+
font-weight: var(--weight-semibold);
|
|
248
|
+
line-height: 1.3;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.felan-lead {
|
|
252
|
+
font-family: var(--font-sans);
|
|
253
|
+
font-size: var(--text-xl);
|
|
254
|
+
font-weight: var(--weight-regular);
|
|
255
|
+
color: hsl(var(--muted-foreground));
|
|
256
|
+
line-height: var(--leading-relaxed);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.felan-p, p.felan {
|
|
260
|
+
font-family: var(--font-sans);
|
|
261
|
+
font-size: var(--text-base);
|
|
262
|
+
line-height: var(--leading-relaxed);
|
|
263
|
+
color: hsl(var(--foreground));
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.felan-small {
|
|
267
|
+
font-size: var(--text-sm);
|
|
268
|
+
color: hsl(var(--muted-foreground));
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.felan-eyebrow {
|
|
272
|
+
display: inline-flex;
|
|
273
|
+
align-items: center;
|
|
274
|
+
gap: 0.375rem;
|
|
275
|
+
font-size: var(--text-sm);
|
|
276
|
+
font-weight: var(--weight-medium);
|
|
277
|
+
background: hsl(var(--muted));
|
|
278
|
+
color: hsl(var(--foreground));
|
|
279
|
+
padding: 0.25rem 0.75rem;
|
|
280
|
+
border-radius: var(--radius-lg);
|
|
281
|
+
letter-spacing: 0;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
.felan-overline {
|
|
285
|
+
font-size: var(--text-xs);
|
|
286
|
+
font-weight: var(--weight-medium);
|
|
287
|
+
text-transform: uppercase;
|
|
288
|
+
letter-spacing: 0.08em;
|
|
289
|
+
color: hsl(var(--muted-foreground));
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.felan-code, code.felan {
|
|
293
|
+
font-family: var(--font-mono);
|
|
294
|
+
font-size: 0.9em;
|
|
295
|
+
background: hsl(var(--muted));
|
|
296
|
+
color: hsl(var(--foreground));
|
|
297
|
+
padding: 0.125em 0.375em;
|
|
298
|
+
border-radius: var(--radius-sm);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
.felan-link {
|
|
302
|
+
color: hsl(var(--brand));
|
|
303
|
+
text-decoration: none;
|
|
304
|
+
font-weight: var(--weight-medium);
|
|
305
|
+
}
|
|
306
|
+
.felan-link:hover { text-decoration: underline; }
|