designlang 4.0.0 → 4.0.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 +56 -2
- package/bin/design-extract.js +1 -1
- package/package.json +1 -1
- package/src/crawler.js +10 -6
- package/src/extractors/interactions.js +3 -2
- package/src/extractors/responsive.js +3 -2
- package/website/.claude/launch.json +11 -0
- package/website/AGENTS.md +5 -0
- package/website/CLAUDE.md +1 -0
- package/website/README.md +36 -0
- package/website/app/favicon.ico +0 -0
- package/website/app/globals.css +432 -0
- package/website/app/layout.js +19 -0
- package/website/app/page.js +162 -0
- package/website/jsconfig.json +7 -0
- package/website/next.config.mjs +6 -0
- package/website/package-lock.json +912 -0
- package/website/package.json +15 -0
- package/website/public/file.svg +1 -0
- package/website/public/globe.svg +1 -0
- package/website/public/next.svg +1 -0
- package/website/public/vercel.svg +1 -0
- package/website/public/window.svg +1 -0
- package/designlang.png +0 -0
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<h1 align="center">
|
|
2
|
+
<h1 align="center">DESIGNLANG</h1>
|
|
3
3
|
<p align="center">Reverse-engineer any website's complete design system in one command.</p>
|
|
4
4
|
</p>
|
|
5
5
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
<a href="https://www.npmjs.com/package/designlang"><img src="https://img.shields.io/npm/v/designlang?color=blue&label=npm" alt="npm version"></a>
|
|
8
8
|
<a href="https://github.com/Manavarya09/design-extract/blob/main/LICENSE"><img src="https://img.shields.io/github/license/Manavarya09/design-extract" alt="license"></a>
|
|
9
9
|
<a href="https://nodejs.org"><img src="https://img.shields.io/node/v/designlang" alt="node version"></a>
|
|
10
|
+
<a href="https://website-five-lime-65.vercel.app"><img src="https://img.shields.io/badge/website-live-red" alt="website"></a>
|
|
10
11
|
</p>
|
|
11
12
|
|
|
12
13
|
---
|
|
@@ -127,6 +128,47 @@ designlang brands stripe.com vercel.com github.com linear.app
|
|
|
127
128
|
|
|
128
129
|
Generates a matrix with color overlap analysis, typography comparison, spacing systems, and accessibility scores. Outputs both `brands.md` and `brands.html`.
|
|
129
130
|
|
|
131
|
+
### 6. Clone Command
|
|
132
|
+
|
|
133
|
+
Generate a working Next.js app with the extracted design applied:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
designlang clone https://stripe.com
|
|
137
|
+
cd cloned-design && npm install && npm run dev
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
One command → a running app with the site's colors, fonts, spacing, and component patterns.
|
|
141
|
+
|
|
142
|
+
### 7. Design System Scoring
|
|
143
|
+
|
|
144
|
+
Rate any site's design quality across 7 categories:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
designlang score https://vercel.com
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
68/100 Grade: D
|
|
152
|
+
|
|
153
|
+
Color Discipline ██████████░░░░░░░░░░ 50
|
|
154
|
+
Typography ██████████████░░░░░░ 70
|
|
155
|
+
Spacing System ████████████████░░░░ 80
|
|
156
|
+
Shadows ██████████░░░░░░░░░░ 50
|
|
157
|
+
Border Radii ████████░░░░░░░░░░░░ 40
|
|
158
|
+
Accessibility ███████████████████░ 94
|
|
159
|
+
Tokenization ████████████████████ 100
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### 8. Watch Mode
|
|
163
|
+
|
|
164
|
+
Monitor a site for design changes:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
designlang watch https://stripe.com --interval 60
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Checks hourly and alerts when colors, fonts, or accessibility scores change.
|
|
171
|
+
|
|
130
172
|
## All Features
|
|
131
173
|
|
|
132
174
|
| Feature | Flag / Command | Description |
|
|
@@ -134,12 +176,16 @@ Generates a matrix with color overlap analysis, typography comparison, spacing s
|
|
|
134
176
|
| Base extraction | `designlang <url>` | Colors, typography, spacing, shadows, radii, CSS vars, breakpoints, animations, components |
|
|
135
177
|
| Layout system | automatic | Grid patterns, flex usage, container widths, gap values |
|
|
136
178
|
| Accessibility | automatic | WCAG 2.1 contrast ratios for all fg/bg pairs |
|
|
179
|
+
| Design scoring | automatic | 7-category quality rating (A-F) with actionable issues |
|
|
137
180
|
| Dark mode | `--dark` | Extracts dark color scheme |
|
|
138
181
|
| Multi-page | `--depth <n>` | Crawl N internal pages for site-wide tokens |
|
|
139
182
|
| Screenshots | `--screenshots` | Capture buttons, cards, inputs, nav, hero, full page |
|
|
140
183
|
| Responsive | `--responsive` | Crawl at 4 viewports, map breakpoint changes |
|
|
141
184
|
| Interactions | `--interactions` | Capture hover/focus/active state transitions |
|
|
142
185
|
| Everything | `--full` | Enable screenshots + responsive + interactions |
|
|
186
|
+
| Clone | `designlang clone <url>` | Generate a working Next.js starter with extracted design |
|
|
187
|
+
| Score | `designlang score <url>` | Rate design quality with visual bar chart breakdown |
|
|
188
|
+
| Watch | `designlang watch <url>` | Monitor for design changes on interval |
|
|
143
189
|
| Diff | `designlang diff <A> <B>` | Compare two sites (MD + HTML) |
|
|
144
190
|
| Multi-brand | `designlang brands <urls...>` | N-site comparison matrix |
|
|
145
191
|
| Sync | `designlang sync <url>` | Update local tokens from live site |
|
|
@@ -167,6 +213,9 @@ Options:
|
|
|
167
213
|
--verbose Detailed progress output
|
|
168
214
|
|
|
169
215
|
Commands:
|
|
216
|
+
clone <url> Generate a working Next.js starter from extracted design
|
|
217
|
+
score <url> Rate design quality (7 categories, A-F, bar chart)
|
|
218
|
+
watch <url> Monitor for design changes on interval
|
|
170
219
|
diff <urlA> <urlB> Compare two sites' design languages
|
|
171
220
|
brands <urls...> Multi-brand comparison matrix
|
|
172
221
|
sync <url> Sync local tokens with live site
|
|
@@ -203,12 +252,13 @@ Running `designlang https://vercel.com --full`:
|
|
|
203
252
|
Shadows: 11 unique shadows
|
|
204
253
|
Radii: 10 unique values
|
|
205
254
|
Breakpoints: 45 breakpoints
|
|
206
|
-
Components:
|
|
255
|
+
Components: 11 types detected
|
|
207
256
|
CSS Vars: 407 custom properties
|
|
208
257
|
Layout: 55 grids, 492 flex containers
|
|
209
258
|
Responsive: 4 viewports, 3 breakpoint changes
|
|
210
259
|
Interactions: 8 state changes captured
|
|
211
260
|
A11y: 94% WCAG score (7 failing pairs)
|
|
261
|
+
Design Score: 68/100 (D) — 4 issues
|
|
212
262
|
```
|
|
213
263
|
|
|
214
264
|
## How It Works
|
|
@@ -230,6 +280,10 @@ npx skills add Manavarya09/design-extract
|
|
|
230
280
|
|
|
231
281
|
In Claude Code, use `/extract-design <url>`.
|
|
232
282
|
|
|
283
|
+
## Website
|
|
284
|
+
|
|
285
|
+
**[website-five-lime-65.vercel.app](https://website-five-lime-65.vercel.app)** — the brutalist product page.
|
|
286
|
+
|
|
233
287
|
## Contributing
|
|
234
288
|
|
|
235
289
|
See [CONTRIBUTING.md](CONTRIBUTING.md). PRs welcome!
|
package/bin/design-extract.js
CHANGED
|
@@ -28,7 +28,7 @@ const program = new Command();
|
|
|
28
28
|
program
|
|
29
29
|
.name('designlang')
|
|
30
30
|
.description('Extract the complete design language from any website')
|
|
31
|
-
.version('4.0.
|
|
31
|
+
.version('4.0.1');
|
|
32
32
|
|
|
33
33
|
// ── Main command: extract ──────────────────────────────────────
|
|
34
34
|
program
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "designlang",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"description": "Extract the complete design language from any website — colors, typography, spacing, shadows, and more. Outputs AI-optimized markdown, W3C design tokens, Tailwind config, and CSS variables.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/crawler.js
CHANGED
|
@@ -14,9 +14,11 @@ export async function crawlPage(url, options = {}) {
|
|
|
14
14
|
});
|
|
15
15
|
const page = await context.newPage();
|
|
16
16
|
|
|
17
|
-
await page.goto(url, { waitUntil: '
|
|
17
|
+
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 });
|
|
18
|
+
// Wait for network to settle — but don't hang on sites with persistent connections
|
|
19
|
+
await page.waitForLoadState('networkidle').catch(() => {});
|
|
18
20
|
if (wait > 0) await page.waitForTimeout(wait);
|
|
19
|
-
await page.evaluate(() => document.fonts.ready);
|
|
21
|
+
await page.evaluate(() => document.fonts.ready).catch(() => {});
|
|
20
22
|
|
|
21
23
|
const title = await page.title();
|
|
22
24
|
const lightData = await extractPageData(page);
|
|
@@ -33,8 +35,9 @@ export async function crawlPage(url, options = {}) {
|
|
|
33
35
|
const internalLinks = await discoverInternalLinks(page, url, depth);
|
|
34
36
|
for (const link of internalLinks) {
|
|
35
37
|
try {
|
|
36
|
-
await page.goto(link, { waitUntil: '
|
|
37
|
-
await page.
|
|
38
|
+
await page.goto(link, { waitUntil: 'domcontentloaded', timeout: 20000 });
|
|
39
|
+
await page.waitForLoadState('networkidle').catch(() => {});
|
|
40
|
+
await page.evaluate(() => document.fonts.ready).catch(() => {});
|
|
38
41
|
const pageData = await extractPageData(page);
|
|
39
42
|
additionalPages.push({ url: link, data: pageData });
|
|
40
43
|
} catch { /* skip failed pages */ }
|
|
@@ -50,8 +53,9 @@ export async function crawlPage(url, options = {}) {
|
|
|
50
53
|
colorScheme: 'dark',
|
|
51
54
|
});
|
|
52
55
|
const darkPage = await darkContext.newPage();
|
|
53
|
-
await darkPage.goto(url, { waitUntil: '
|
|
54
|
-
await darkPage.
|
|
56
|
+
await darkPage.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 });
|
|
57
|
+
await darkPage.waitForLoadState('networkidle').catch(() => {});
|
|
58
|
+
await darkPage.evaluate(() => document.fonts.ready).catch(() => {});
|
|
55
59
|
darkData = await extractPageData(darkPage);
|
|
56
60
|
await darkContext.close();
|
|
57
61
|
} else {
|
|
@@ -8,9 +8,10 @@ export async function captureInteractions(url, options = {}) {
|
|
|
8
8
|
const context = await browser.newContext({ viewport: { width, height } });
|
|
9
9
|
const page = await context.newPage();
|
|
10
10
|
|
|
11
|
-
await page.goto(url, { waitUntil: '
|
|
11
|
+
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 });
|
|
12
|
+
await page.waitForLoadState('networkidle').catch(() => {});
|
|
12
13
|
if (wait > 0) await page.waitForTimeout(wait);
|
|
13
|
-
await page.evaluate(() => document.fonts.ready);
|
|
14
|
+
await page.evaluate(() => document.fonts.ready).catch(() => {});
|
|
14
15
|
|
|
15
16
|
const results = { buttons: [], links: [], inputs: [] };
|
|
16
17
|
|
|
@@ -20,9 +20,10 @@ export async function captureResponsive(url, options = {}) {
|
|
|
20
20
|
const page = await context.newPage();
|
|
21
21
|
|
|
22
22
|
try {
|
|
23
|
-
await page.goto(url, { waitUntil: '
|
|
23
|
+
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 20000 });
|
|
24
|
+
await page.waitForLoadState('networkidle').catch(() => {});
|
|
24
25
|
if (wait > 0) await page.waitForTimeout(wait);
|
|
25
|
-
await page.evaluate(() => document.fonts.ready);
|
|
26
|
+
await page.evaluate(() => document.fonts.ready).catch(() => {});
|
|
26
27
|
|
|
27
28
|
const data = await page.evaluate(() => {
|
|
28
29
|
const body = document.body;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<!-- BEGIN:nextjs-agent-rules -->
|
|
2
|
+
# This is NOT the Next.js you know
|
|
3
|
+
|
|
4
|
+
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices.
|
|
5
|
+
<!-- END:nextjs-agent-rules -->
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@AGENTS.md
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
|
|
2
|
+
|
|
3
|
+
## Getting Started
|
|
4
|
+
|
|
5
|
+
First, run the development server:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm run dev
|
|
9
|
+
# or
|
|
10
|
+
yarn dev
|
|
11
|
+
# or
|
|
12
|
+
pnpm dev
|
|
13
|
+
# or
|
|
14
|
+
bun dev
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
|
18
|
+
|
|
19
|
+
You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file.
|
|
20
|
+
|
|
21
|
+
This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
|
|
22
|
+
|
|
23
|
+
## Learn More
|
|
24
|
+
|
|
25
|
+
To learn more about Next.js, take a look at the following resources:
|
|
26
|
+
|
|
27
|
+
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
|
28
|
+
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
|
29
|
+
|
|
30
|
+
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
|
|
31
|
+
|
|
32
|
+
## Deploy on Vercel
|
|
33
|
+
|
|
34
|
+
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
|
35
|
+
|
|
36
|
+
Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
|
|
Binary file
|
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--red: #ff0000;
|
|
3
|
+
--black: #0a0a0a;
|
|
4
|
+
--white: #f5f0e8;
|
|
5
|
+
--cream: #e8e0d0;
|
|
6
|
+
--yellow: #ffdd00;
|
|
7
|
+
--gray: #333;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
11
|
+
|
|
12
|
+
html { scroll-behavior: smooth; }
|
|
13
|
+
|
|
14
|
+
body {
|
|
15
|
+
background: var(--black);
|
|
16
|
+
color: var(--white);
|
|
17
|
+
font-family: 'Inter', sans-serif;
|
|
18
|
+
overflow-x: hidden;
|
|
19
|
+
cursor: crosshair;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
::selection {
|
|
23
|
+
background: var(--red);
|
|
24
|
+
color: var(--black);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
a { color: inherit; }
|
|
28
|
+
|
|
29
|
+
/* ── HERO ── */
|
|
30
|
+
.hero {
|
|
31
|
+
min-height: 100vh;
|
|
32
|
+
display: flex;
|
|
33
|
+
flex-direction: column;
|
|
34
|
+
justify-content: center;
|
|
35
|
+
align-items: center;
|
|
36
|
+
position: relative;
|
|
37
|
+
border-bottom: 4px solid var(--red);
|
|
38
|
+
overflow: hidden;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.hero::before {
|
|
42
|
+
content: 'DESIGNLANG DESIGNLANG DESIGNLANG DESIGNLANG DESIGNLANG ';
|
|
43
|
+
position: absolute;
|
|
44
|
+
top: 0;
|
|
45
|
+
left: 0;
|
|
46
|
+
width: 300%;
|
|
47
|
+
font-family: 'Unbounded', sans-serif;
|
|
48
|
+
font-size: 14vw;
|
|
49
|
+
font-weight: 900;
|
|
50
|
+
color: rgba(255, 0, 0, 0.03);
|
|
51
|
+
white-space: nowrap;
|
|
52
|
+
pointer-events: none;
|
|
53
|
+
animation: scroll-text 20s linear infinite;
|
|
54
|
+
line-height: 1;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@keyframes scroll-text {
|
|
58
|
+
0% { transform: translateX(0); }
|
|
59
|
+
100% { transform: translateX(-33.33%); }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.hero-title {
|
|
63
|
+
font-family: 'Unbounded', sans-serif;
|
|
64
|
+
font-size: clamp(4rem, 12vw, 10rem);
|
|
65
|
+
font-weight: 900;
|
|
66
|
+
text-transform: uppercase;
|
|
67
|
+
letter-spacing: -0.04em;
|
|
68
|
+
line-height: 0.9;
|
|
69
|
+
text-align: center;
|
|
70
|
+
position: relative;
|
|
71
|
+
z-index: 1;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.hero-title span {
|
|
75
|
+
display: block;
|
|
76
|
+
color: var(--red);
|
|
77
|
+
font-size: 0.4em;
|
|
78
|
+
letter-spacing: 0.2em;
|
|
79
|
+
margin-top: 16px;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.hero-sub {
|
|
83
|
+
font-family: 'JetBrains Mono', monospace;
|
|
84
|
+
font-size: clamp(14px, 1.5vw, 18px);
|
|
85
|
+
color: #888;
|
|
86
|
+
margin-top: 32px;
|
|
87
|
+
text-align: center;
|
|
88
|
+
max-width: 600px;
|
|
89
|
+
line-height: 1.6;
|
|
90
|
+
z-index: 1;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.hero-cmd {
|
|
94
|
+
margin-top: 48px;
|
|
95
|
+
background: #111;
|
|
96
|
+
border: 2px solid var(--red);
|
|
97
|
+
padding: 20px 40px;
|
|
98
|
+
font-family: 'JetBrains Mono', monospace;
|
|
99
|
+
font-size: clamp(16px, 2vw, 22px);
|
|
100
|
+
color: var(--yellow);
|
|
101
|
+
position: relative;
|
|
102
|
+
z-index: 1;
|
|
103
|
+
transition: all 0.2s;
|
|
104
|
+
text-decoration: none;
|
|
105
|
+
display: inline-block;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.hero-cmd:hover {
|
|
109
|
+
background: var(--red);
|
|
110
|
+
color: var(--black);
|
|
111
|
+
transform: translate(-4px, -4px);
|
|
112
|
+
box-shadow: 4px 4px 0 var(--yellow);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.hero-cmd::before {
|
|
116
|
+
content: '$ ';
|
|
117
|
+
color: var(--red);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.hero-cmd:hover::before {
|
|
121
|
+
color: var(--black);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.scroll-hint {
|
|
125
|
+
position: absolute;
|
|
126
|
+
bottom: 40px;
|
|
127
|
+
font-family: 'JetBrains Mono', monospace;
|
|
128
|
+
font-size: 12px;
|
|
129
|
+
color: #444;
|
|
130
|
+
letter-spacing: 0.3em;
|
|
131
|
+
text-transform: uppercase;
|
|
132
|
+
animation: pulse 2s ease-in-out infinite;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
@keyframes pulse {
|
|
136
|
+
0%, 100% { opacity: 0.3; }
|
|
137
|
+
50% { opacity: 1; }
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* ── SECTION LAYOUT ── */
|
|
141
|
+
section {
|
|
142
|
+
padding: 100px 24px;
|
|
143
|
+
max-width: 1400px;
|
|
144
|
+
margin: 0 auto;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.section-red {
|
|
148
|
+
background: var(--red);
|
|
149
|
+
color: var(--black);
|
|
150
|
+
max-width: 100%;
|
|
151
|
+
padding: 80px 24px;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.section-cream {
|
|
155
|
+
background: var(--cream);
|
|
156
|
+
color: var(--black);
|
|
157
|
+
max-width: 100%;
|
|
158
|
+
padding: 80px 24px;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.section-inner {
|
|
162
|
+
max-width: 1400px;
|
|
163
|
+
margin: 0 auto;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.section-title {
|
|
167
|
+
font-family: 'Unbounded', sans-serif;
|
|
168
|
+
font-size: clamp(2rem, 5vw, 4rem);
|
|
169
|
+
font-weight: 900;
|
|
170
|
+
text-transform: uppercase;
|
|
171
|
+
letter-spacing: -0.02em;
|
|
172
|
+
margin-bottom: 48px;
|
|
173
|
+
line-height: 1;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.section-title::after {
|
|
177
|
+
content: ' ///';
|
|
178
|
+
color: var(--red);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.section-red .section-title::after {
|
|
182
|
+
color: var(--black);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.section-cream .section-title::after {
|
|
186
|
+
color: var(--red);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/* ── OUTPUT FILES ── */
|
|
190
|
+
.files-grid {
|
|
191
|
+
display: grid;
|
|
192
|
+
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
|
193
|
+
gap: 2px;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.file-card {
|
|
197
|
+
background: #111;
|
|
198
|
+
border: 2px solid #222;
|
|
199
|
+
padding: 28px;
|
|
200
|
+
transition: all 0.15s;
|
|
201
|
+
position: relative;
|
|
202
|
+
overflow: hidden;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.file-card:hover {
|
|
206
|
+
border-color: var(--red);
|
|
207
|
+
transform: translate(-2px, -2px);
|
|
208
|
+
box-shadow: 2px 2px 0 var(--red);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.file-card::before {
|
|
212
|
+
content: attr(data-num);
|
|
213
|
+
position: absolute;
|
|
214
|
+
top: -10px;
|
|
215
|
+
right: 10px;
|
|
216
|
+
font-family: 'Unbounded', sans-serif;
|
|
217
|
+
font-size: 80px;
|
|
218
|
+
font-weight: 900;
|
|
219
|
+
color: rgba(255, 0, 0, 0.06);
|
|
220
|
+
line-height: 1;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.file-name {
|
|
224
|
+
font-family: 'JetBrains Mono', monospace;
|
|
225
|
+
font-size: 15px;
|
|
226
|
+
color: var(--yellow);
|
|
227
|
+
margin-bottom: 8px;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.file-desc {
|
|
231
|
+
font-size: 14px;
|
|
232
|
+
color: #888;
|
|
233
|
+
line-height: 1.5;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/* ── FEATURES ── */
|
|
237
|
+
.features-list {
|
|
238
|
+
display: grid;
|
|
239
|
+
grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
|
|
240
|
+
gap: 0;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.feature {
|
|
244
|
+
padding: 32px;
|
|
245
|
+
border: 1px solid #222;
|
|
246
|
+
transition: all 0.15s;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.feature:hover {
|
|
250
|
+
background: #111;
|
|
251
|
+
border-color: var(--red);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.feature-name {
|
|
255
|
+
font-family: 'Unbounded', sans-serif;
|
|
256
|
+
font-size: 18px;
|
|
257
|
+
font-weight: 700;
|
|
258
|
+
text-transform: uppercase;
|
|
259
|
+
margin-bottom: 8px;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.feature-cmd {
|
|
263
|
+
font-family: 'JetBrains Mono', monospace;
|
|
264
|
+
font-size: 13px;
|
|
265
|
+
color: var(--yellow);
|
|
266
|
+
margin-bottom: 12px;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.feature-desc {
|
|
270
|
+
font-size: 14px;
|
|
271
|
+
color: #888;
|
|
272
|
+
line-height: 1.5;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/* ── SCORE DEMO ── */
|
|
276
|
+
.score-demo {
|
|
277
|
+
background: #111;
|
|
278
|
+
border: 2px solid var(--red);
|
|
279
|
+
padding: 40px;
|
|
280
|
+
font-family: 'JetBrains Mono', monospace;
|
|
281
|
+
font-size: 14px;
|
|
282
|
+
line-height: 2;
|
|
283
|
+
overflow-x: auto;
|
|
284
|
+
color: #ccc;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.score-grade {
|
|
288
|
+
font-family: 'Unbounded', sans-serif;
|
|
289
|
+
font-size: 64px;
|
|
290
|
+
font-weight: 900;
|
|
291
|
+
color: var(--red);
|
|
292
|
+
display: inline;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/* ── COMMANDS ── */
|
|
296
|
+
.commands-grid {
|
|
297
|
+
display: grid;
|
|
298
|
+
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
|
|
299
|
+
gap: 2px;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.command-card {
|
|
303
|
+
background: var(--black);
|
|
304
|
+
padding: 32px;
|
|
305
|
+
border: 2px solid rgba(255,0,0,0.3);
|
|
306
|
+
transition: all 0.15s;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.command-card:hover {
|
|
310
|
+
border-color: var(--red);
|
|
311
|
+
background: rgba(255, 0, 0, 0.05);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.command-name {
|
|
315
|
+
font-family: 'JetBrains Mono', monospace;
|
|
316
|
+
font-size: 18px;
|
|
317
|
+
font-weight: 700;
|
|
318
|
+
color: var(--yellow);
|
|
319
|
+
margin-bottom: 12px;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.command-desc {
|
|
323
|
+
font-size: 14px;
|
|
324
|
+
color: #ccc;
|
|
325
|
+
line-height: 1.5;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/* ── STATS STRIP ── */
|
|
329
|
+
.stats-strip {
|
|
330
|
+
display: flex;
|
|
331
|
+
flex-wrap: wrap;
|
|
332
|
+
border-top: 2px solid var(--red);
|
|
333
|
+
border-bottom: 2px solid var(--red);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.stat {
|
|
337
|
+
flex: 1;
|
|
338
|
+
min-width: 150px;
|
|
339
|
+
padding: 32px 24px;
|
|
340
|
+
text-align: center;
|
|
341
|
+
border-right: 1px solid #222;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
.stat:last-child { border-right: none; }
|
|
345
|
+
|
|
346
|
+
.stat-value {
|
|
347
|
+
font-family: 'Unbounded', sans-serif;
|
|
348
|
+
font-size: 48px;
|
|
349
|
+
font-weight: 900;
|
|
350
|
+
color: var(--red);
|
|
351
|
+
line-height: 1;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.stat-label {
|
|
355
|
+
font-family: 'JetBrains Mono', monospace;
|
|
356
|
+
font-size: 11px;
|
|
357
|
+
color: #666;
|
|
358
|
+
text-transform: uppercase;
|
|
359
|
+
letter-spacing: 0.15em;
|
|
360
|
+
margin-top: 8px;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/* ── FOOTER ── */
|
|
364
|
+
footer {
|
|
365
|
+
padding: 60px 24px;
|
|
366
|
+
text-align: center;
|
|
367
|
+
border-top: 4px solid var(--red);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
footer a {
|
|
371
|
+
text-decoration: underline;
|
|
372
|
+
text-underline-offset: 4px;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
footer a:hover {
|
|
376
|
+
color: var(--red);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.footer-title {
|
|
380
|
+
font-family: 'Unbounded', sans-serif;
|
|
381
|
+
font-size: 24px;
|
|
382
|
+
font-weight: 900;
|
|
383
|
+
text-transform: uppercase;
|
|
384
|
+
margin-bottom: 16px;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
.footer-links {
|
|
388
|
+
display: flex;
|
|
389
|
+
gap: 32px;
|
|
390
|
+
justify-content: center;
|
|
391
|
+
margin-top: 24px;
|
|
392
|
+
font-family: 'JetBrains Mono', monospace;
|
|
393
|
+
font-size: 14px;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
.footer-copy {
|
|
397
|
+
margin-top: 48px;
|
|
398
|
+
font-size: 12px;
|
|
399
|
+
color: #444;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/* ── MARQUEE ── */
|
|
403
|
+
.marquee {
|
|
404
|
+
overflow: hidden;
|
|
405
|
+
white-space: nowrap;
|
|
406
|
+
border-top: 2px solid #222;
|
|
407
|
+
border-bottom: 2px solid #222;
|
|
408
|
+
padding: 12px 0;
|
|
409
|
+
font-family: 'JetBrains Mono', monospace;
|
|
410
|
+
font-size: 13px;
|
|
411
|
+
color: #444;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
.marquee-inner {
|
|
415
|
+
display: inline-block;
|
|
416
|
+
animation: marquee 30s linear infinite;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
@keyframes marquee {
|
|
420
|
+
0% { transform: translateX(0); }
|
|
421
|
+
100% { transform: translateX(-50%); }
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/* ── RESPONSIVE ── */
|
|
425
|
+
@media (max-width: 768px) {
|
|
426
|
+
.features-list { grid-template-columns: 1fr; }
|
|
427
|
+
.commands-grid { grid-template-columns: 1fr; }
|
|
428
|
+
.files-grid { grid-template-columns: 1fr; }
|
|
429
|
+
.stats-strip { flex-direction: column; }
|
|
430
|
+
.stat { border-right: none; border-bottom: 1px solid #222; }
|
|
431
|
+
.hero-cmd { font-size: 14px; padding: 16px 24px; }
|
|
432
|
+
}
|