roadmap-kit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/INSTALL.md +358 -0
- package/LICENSE +21 -0
- package/README.md +503 -0
- package/cli.js +548 -0
- package/dashboard/dist/assets/index-BzYzLB7u.css +1 -0
- package/dashboard/dist/assets/index-DIonhzlK.js +506 -0
- package/dashboard/dist/index.html +18 -0
- package/dashboard/dist/roadmap.json +268 -0
- package/dashboard/index.html +17 -0
- package/dashboard/package-lock.json +4172 -0
- package/dashboard/package.json +37 -0
- package/dashboard/postcss.config.js +6 -0
- package/dashboard/public/roadmap.json +268 -0
- package/dashboard/server.js +1366 -0
- package/dashboard/src/App.jsx +6979 -0
- package/dashboard/src/components/CircularProgress.jsx +55 -0
- package/dashboard/src/components/ProgressBar.jsx +33 -0
- package/dashboard/src/components/ProjectSettings.jsx +420 -0
- package/dashboard/src/components/SharedResources.jsx +239 -0
- package/dashboard/src/components/TaskList.jsx +273 -0
- package/dashboard/src/components/TechnicalDebt.jsx +170 -0
- package/dashboard/src/components/ui/accordion.jsx +46 -0
- package/dashboard/src/components/ui/badge.jsx +38 -0
- package/dashboard/src/components/ui/card.jsx +60 -0
- package/dashboard/src/components/ui/progress.jsx +22 -0
- package/dashboard/src/components/ui/tabs.jsx +47 -0
- package/dashboard/src/index.css +440 -0
- package/dashboard/src/lib/utils.js +6 -0
- package/dashboard/src/main.jsx +10 -0
- package/dashboard/tailwind.config.js +142 -0
- package/dashboard/vite.config.js +18 -0
- package/docker/Dockerfile +35 -0
- package/docker/docker-compose.yml +30 -0
- package/docker/entrypoint.sh +31 -0
- package/package.json +68 -0
- package/scanner.js +351 -0
- package/setup.sh +354 -0
- package/templates/clinerules.template +130 -0
- package/templates/roadmap.template.json +30 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import * as AccordionPrimitive from "@radix-ui/react-accordion"
|
|
3
|
+
import { ChevronDown } from "lucide-react"
|
|
4
|
+
import { cn } from "../../lib/utils"
|
|
5
|
+
|
|
6
|
+
const Accordion = AccordionPrimitive.Root
|
|
7
|
+
|
|
8
|
+
const AccordionItem = React.forwardRef(({ className, ...props }, ref) => (
|
|
9
|
+
<AccordionPrimitive.Item
|
|
10
|
+
ref={ref}
|
|
11
|
+
className={cn("border-b border-slate-700", className)}
|
|
12
|
+
{...props}
|
|
13
|
+
/>
|
|
14
|
+
))
|
|
15
|
+
AccordionItem.displayName = "AccordionItem"
|
|
16
|
+
|
|
17
|
+
const AccordionTrigger = React.forwardRef(({ className, children, ...props }, ref) => (
|
|
18
|
+
<AccordionPrimitive.Header className="flex">
|
|
19
|
+
<AccordionPrimitive.Trigger
|
|
20
|
+
ref={ref}
|
|
21
|
+
className={cn(
|
|
22
|
+
"flex flex-1 items-center justify-between py-4 font-medium transition-all hover:bg-slate-800/30 px-4 rounded-lg [&[data-state=open]>svg]:rotate-180",
|
|
23
|
+
className
|
|
24
|
+
)}
|
|
25
|
+
{...props}
|
|
26
|
+
>
|
|
27
|
+
{children}
|
|
28
|
+
<ChevronDown className="h-4 w-4 shrink-0 transition-transform duration-200 text-slate-400" />
|
|
29
|
+
</AccordionPrimitive.Trigger>
|
|
30
|
+
</AccordionPrimitive.Header>
|
|
31
|
+
))
|
|
32
|
+
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName
|
|
33
|
+
|
|
34
|
+
const AccordionContent = React.forwardRef(({ className, children, ...props }, ref) => (
|
|
35
|
+
<AccordionPrimitive.Content
|
|
36
|
+
ref={ref}
|
|
37
|
+
className="overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
|
|
38
|
+
{...props}
|
|
39
|
+
>
|
|
40
|
+
<div className={cn("pb-4 pt-0 px-4", className)}>{children}</div>
|
|
41
|
+
</AccordionPrimitive.Content>
|
|
42
|
+
))
|
|
43
|
+
|
|
44
|
+
AccordionContent.displayName = AccordionPrimitive.Content.displayName
|
|
45
|
+
|
|
46
|
+
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { cva } from "class-variance-authority"
|
|
3
|
+
import { cn } from "../../lib/utils"
|
|
4
|
+
|
|
5
|
+
const badgeVariants = cva(
|
|
6
|
+
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-medium font-mono transition-all",
|
|
7
|
+
{
|
|
8
|
+
variants: {
|
|
9
|
+
variant: {
|
|
10
|
+
default:
|
|
11
|
+
"border-cyan-500/30 bg-cyan-500/10 text-cyan-400",
|
|
12
|
+
secondary:
|
|
13
|
+
"border-slate-600 bg-slate-800/50 text-slate-300",
|
|
14
|
+
success:
|
|
15
|
+
"border-emerald-500/30 bg-emerald-500/10 text-emerald-400",
|
|
16
|
+
warning:
|
|
17
|
+
"border-amber-500/30 bg-amber-500/10 text-amber-400",
|
|
18
|
+
danger:
|
|
19
|
+
"border-rose-500/30 bg-rose-500/10 text-rose-400",
|
|
20
|
+
outline:
|
|
21
|
+
"border-slate-600 text-slate-400 bg-transparent",
|
|
22
|
+
info:
|
|
23
|
+
"border-blue-500/30 bg-blue-500/10 text-blue-400",
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
defaultVariants: {
|
|
27
|
+
variant: "default",
|
|
28
|
+
},
|
|
29
|
+
}
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
function Badge({ className, variant, ...props }) {
|
|
33
|
+
return (
|
|
34
|
+
<div className={cn(badgeVariants({ variant }), className)} {...props} />
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export { Badge, badgeVariants }
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { cn } from "../../lib/utils"
|
|
3
|
+
|
|
4
|
+
const Card = React.forwardRef(({ className, ...props }, ref) => (
|
|
5
|
+
<div
|
|
6
|
+
ref={ref}
|
|
7
|
+
className={cn(
|
|
8
|
+
"rounded-lg border border-slate-800 bg-slate-900/50 backdrop-blur text-slate-50 shadow-sm",
|
|
9
|
+
className
|
|
10
|
+
)}
|
|
11
|
+
{...props}
|
|
12
|
+
/>
|
|
13
|
+
))
|
|
14
|
+
Card.displayName = "Card"
|
|
15
|
+
|
|
16
|
+
const CardHeader = React.forwardRef(({ className, ...props }, ref) => (
|
|
17
|
+
<div
|
|
18
|
+
ref={ref}
|
|
19
|
+
className={cn("flex flex-col space-y-1.5 p-6", className)}
|
|
20
|
+
{...props}
|
|
21
|
+
/>
|
|
22
|
+
))
|
|
23
|
+
CardHeader.displayName = "CardHeader"
|
|
24
|
+
|
|
25
|
+
const CardTitle = React.forwardRef(({ className, ...props }, ref) => (
|
|
26
|
+
<h3
|
|
27
|
+
ref={ref}
|
|
28
|
+
className={cn(
|
|
29
|
+
"text-2xl font-semibold leading-none tracking-tight",
|
|
30
|
+
className
|
|
31
|
+
)}
|
|
32
|
+
{...props}
|
|
33
|
+
/>
|
|
34
|
+
))
|
|
35
|
+
CardTitle.displayName = "CardTitle"
|
|
36
|
+
|
|
37
|
+
const CardDescription = React.forwardRef(({ className, ...props }, ref) => (
|
|
38
|
+
<p
|
|
39
|
+
ref={ref}
|
|
40
|
+
className={cn("text-sm text-slate-400", className)}
|
|
41
|
+
{...props}
|
|
42
|
+
/>
|
|
43
|
+
))
|
|
44
|
+
CardDescription.displayName = "CardDescription"
|
|
45
|
+
|
|
46
|
+
const CardContent = React.forwardRef(({ className, ...props }, ref) => (
|
|
47
|
+
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
|
|
48
|
+
))
|
|
49
|
+
CardContent.displayName = "CardContent"
|
|
50
|
+
|
|
51
|
+
const CardFooter = React.forwardRef(({ className, ...props }, ref) => (
|
|
52
|
+
<div
|
|
53
|
+
ref={ref}
|
|
54
|
+
className={cn("flex items-center p-6 pt-0", className)}
|
|
55
|
+
{...props}
|
|
56
|
+
/>
|
|
57
|
+
))
|
|
58
|
+
CardFooter.displayName = "CardFooter"
|
|
59
|
+
|
|
60
|
+
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import * as ProgressPrimitive from "@radix-ui/react-progress"
|
|
3
|
+
import { cn } from "../../lib/utils"
|
|
4
|
+
|
|
5
|
+
const Progress = React.forwardRef(({ className, value, ...props }, ref) => (
|
|
6
|
+
<ProgressPrimitive.Root
|
|
7
|
+
ref={ref}
|
|
8
|
+
className={cn(
|
|
9
|
+
"relative h-4 w-full overflow-hidden rounded-full bg-slate-800",
|
|
10
|
+
className
|
|
11
|
+
)}
|
|
12
|
+
{...props}
|
|
13
|
+
>
|
|
14
|
+
<ProgressPrimitive.Indicator
|
|
15
|
+
className="h-full w-full flex-1 bg-gradient-to-r from-emerald-500 to-emerald-400 transition-all"
|
|
16
|
+
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
|
|
17
|
+
/>
|
|
18
|
+
</ProgressPrimitive.Root>
|
|
19
|
+
))
|
|
20
|
+
Progress.displayName = ProgressPrimitive.Root.displayName
|
|
21
|
+
|
|
22
|
+
export { Progress }
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import * as TabsPrimitive from "@radix-ui/react-tabs"
|
|
3
|
+
import { cn } from "../../lib/utils"
|
|
4
|
+
|
|
5
|
+
const Tabs = TabsPrimitive.Root
|
|
6
|
+
|
|
7
|
+
const TabsList = React.forwardRef(({ className, ...props }, ref) => (
|
|
8
|
+
<TabsPrimitive.List
|
|
9
|
+
ref={ref}
|
|
10
|
+
className={cn(
|
|
11
|
+
"inline-flex h-auto items-center justify-center rounded-xl bg-navy-900/80 backdrop-blur-sm p-1.5 text-slate-400 border border-cyan-500/10",
|
|
12
|
+
className
|
|
13
|
+
)}
|
|
14
|
+
{...props}
|
|
15
|
+
/>
|
|
16
|
+
))
|
|
17
|
+
TabsList.displayName = TabsPrimitive.List.displayName
|
|
18
|
+
|
|
19
|
+
const TabsTrigger = React.forwardRef(({ className, ...props }, ref) => (
|
|
20
|
+
<TabsPrimitive.Trigger
|
|
21
|
+
ref={ref}
|
|
22
|
+
className={cn(
|
|
23
|
+
"inline-flex items-center justify-center whitespace-nowrap rounded-lg px-4 py-2 text-sm font-medium transition-all",
|
|
24
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-cyan-500/50",
|
|
25
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
26
|
+
"data-[state=active]:bg-cyan-500/20 data-[state=active]:text-cyan-400 data-[state=active]:shadow-sm",
|
|
27
|
+
"hover:text-slate-300 hover:bg-navy-800/50",
|
|
28
|
+
className
|
|
29
|
+
)}
|
|
30
|
+
{...props}
|
|
31
|
+
/>
|
|
32
|
+
))
|
|
33
|
+
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName
|
|
34
|
+
|
|
35
|
+
const TabsContent = React.forwardRef(({ className, ...props }, ref) => (
|
|
36
|
+
<TabsPrimitive.Content
|
|
37
|
+
ref={ref}
|
|
38
|
+
className={cn(
|
|
39
|
+
"mt-4 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-cyan-500/50",
|
|
40
|
+
className
|
|
41
|
+
)}
|
|
42
|
+
{...props}
|
|
43
|
+
/>
|
|
44
|
+
))
|
|
45
|
+
TabsContent.displayName = TabsPrimitive.Content.displayName
|
|
46
|
+
|
|
47
|
+
export { Tabs, TabsList, TabsTrigger, TabsContent }
|
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
@tailwind base;
|
|
2
|
+
@tailwind components;
|
|
3
|
+
@tailwind utilities;
|
|
4
|
+
|
|
5
|
+
@layer base {
|
|
6
|
+
:root {
|
|
7
|
+
--matrix: #00ff88;
|
|
8
|
+
--signal: #ff9500;
|
|
9
|
+
--cyber: #00d4ff;
|
|
10
|
+
--alert: #ff3366;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
::selection {
|
|
14
|
+
background-color: rgba(0, 255, 136, 0.3);
|
|
15
|
+
color: white;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/* Custom scrollbar */
|
|
19
|
+
::-webkit-scrollbar {
|
|
20
|
+
width: 6px;
|
|
21
|
+
height: 6px;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
::-webkit-scrollbar-track {
|
|
25
|
+
background: transparent;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
::-webkit-scrollbar-thumb {
|
|
29
|
+
background: rgba(0, 255, 136, 0.2);
|
|
30
|
+
border-radius: 3px;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
::-webkit-scrollbar-thumb:hover {
|
|
34
|
+
background: rgba(0, 255, 136, 0.4);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* Select styling */
|
|
38
|
+
select {
|
|
39
|
+
background-color: #0a0a0a;
|
|
40
|
+
color: #00ff88;
|
|
41
|
+
border: 1px solid rgba(0, 255, 136, 0.2);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
select option {
|
|
45
|
+
background-color: #0a0a0a;
|
|
46
|
+
color: #e0e0e0;
|
|
47
|
+
padding: 12px;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
select option:hover,
|
|
51
|
+
select option:focus,
|
|
52
|
+
select option:checked {
|
|
53
|
+
background-color: rgba(0, 255, 136, 0.1);
|
|
54
|
+
color: #00ff88;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* Focus styles */
|
|
58
|
+
input:focus,
|
|
59
|
+
textarea:focus,
|
|
60
|
+
select:focus {
|
|
61
|
+
outline: none;
|
|
62
|
+
border-color: var(--matrix);
|
|
63
|
+
box-shadow: 0 0 0 1px var(--matrix), 0 0 20px rgba(0, 255, 136, 0.2);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@layer components {
|
|
68
|
+
/* Terminal card */
|
|
69
|
+
.terminal-card {
|
|
70
|
+
background: linear-gradient(180deg, #0d0d0d 0%, #0a0a0a 100%);
|
|
71
|
+
border: 1px solid rgba(0, 255, 136, 0.15);
|
|
72
|
+
position: relative;
|
|
73
|
+
overflow: hidden;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.terminal-card::before {
|
|
77
|
+
content: '';
|
|
78
|
+
position: absolute;
|
|
79
|
+
top: 0;
|
|
80
|
+
left: 0;
|
|
81
|
+
right: 0;
|
|
82
|
+
height: 1px;
|
|
83
|
+
background: linear-gradient(90deg, transparent, var(--matrix), transparent);
|
|
84
|
+
opacity: 0.5;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/* Sidebar style */
|
|
88
|
+
.sidebar-terminal {
|
|
89
|
+
background: linear-gradient(180deg, #050505 0%, #0a0a0a 50%, #050505 100%);
|
|
90
|
+
border-right: 1px solid rgba(0, 255, 136, 0.1);
|
|
91
|
+
position: relative;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.sidebar-terminal::after {
|
|
95
|
+
content: '';
|
|
96
|
+
position: absolute;
|
|
97
|
+
top: 0;
|
|
98
|
+
right: 0;
|
|
99
|
+
bottom: 0;
|
|
100
|
+
width: 1px;
|
|
101
|
+
background: linear-gradient(180deg, transparent, var(--matrix), transparent);
|
|
102
|
+
opacity: 0.3;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* Glowing border */
|
|
106
|
+
.glow-border {
|
|
107
|
+
position: relative;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.glow-border::before {
|
|
111
|
+
content: '';
|
|
112
|
+
position: absolute;
|
|
113
|
+
inset: -1px;
|
|
114
|
+
border-radius: inherit;
|
|
115
|
+
padding: 1px;
|
|
116
|
+
background: linear-gradient(135deg, var(--matrix), var(--cyber));
|
|
117
|
+
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
|
|
118
|
+
mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
|
|
119
|
+
-webkit-mask-composite: xor;
|
|
120
|
+
mask-composite: exclude;
|
|
121
|
+
opacity: 0.5;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/* LED indicator */
|
|
125
|
+
.led {
|
|
126
|
+
width: 8px;
|
|
127
|
+
height: 8px;
|
|
128
|
+
border-radius: 50%;
|
|
129
|
+
position: relative;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.led::after {
|
|
133
|
+
content: '';
|
|
134
|
+
position: absolute;
|
|
135
|
+
inset: -3px;
|
|
136
|
+
border-radius: 50%;
|
|
137
|
+
background: inherit;
|
|
138
|
+
filter: blur(4px);
|
|
139
|
+
opacity: 0.6;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.led-green {
|
|
143
|
+
background: var(--matrix);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.led-amber {
|
|
147
|
+
background: var(--signal);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.led-red {
|
|
151
|
+
background: var(--alert);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.led-gray {
|
|
155
|
+
background: #444;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.led-gray::after {
|
|
159
|
+
opacity: 0;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* Progress bar brutalist */
|
|
163
|
+
.progress-brutal {
|
|
164
|
+
height: 6px;
|
|
165
|
+
background: #1a1a1a;
|
|
166
|
+
border: 1px solid #333;
|
|
167
|
+
position: relative;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.progress-brutal-fill {
|
|
171
|
+
height: 100%;
|
|
172
|
+
background: linear-gradient(90deg, var(--matrix), var(--cyber));
|
|
173
|
+
box-shadow: 0 0 10px var(--matrix);
|
|
174
|
+
transition: width 0.5s ease-out;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/* Nav item terminal style */
|
|
178
|
+
.nav-terminal {
|
|
179
|
+
position: relative;
|
|
180
|
+
font-family: 'IBM Plex Mono', monospace;
|
|
181
|
+
letter-spacing: 0.05em;
|
|
182
|
+
transition: all 0.2s ease;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.nav-terminal::before {
|
|
186
|
+
content: '>';
|
|
187
|
+
position: absolute;
|
|
188
|
+
left: 12px;
|
|
189
|
+
opacity: 0;
|
|
190
|
+
color: var(--matrix);
|
|
191
|
+
transition: all 0.2s ease;
|
|
192
|
+
transform: translateX(-5px);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.nav-terminal:hover::before,
|
|
196
|
+
.nav-terminal.active::before {
|
|
197
|
+
opacity: 1;
|
|
198
|
+
transform: translateX(0);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.nav-terminal.active {
|
|
202
|
+
background: rgba(0, 255, 136, 0.05);
|
|
203
|
+
color: var(--matrix);
|
|
204
|
+
border-left: 2px solid var(--matrix);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/* ASCII box decorations */
|
|
208
|
+
.ascii-box {
|
|
209
|
+
position: relative;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.ascii-box::before {
|
|
213
|
+
content: '┌──';
|
|
214
|
+
position: absolute;
|
|
215
|
+
top: -8px;
|
|
216
|
+
left: 0;
|
|
217
|
+
font-family: 'IBM Plex Mono', monospace;
|
|
218
|
+
font-size: 10px;
|
|
219
|
+
color: rgba(0, 255, 136, 0.3);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.ascii-box::after {
|
|
223
|
+
content: '──┘';
|
|
224
|
+
position: absolute;
|
|
225
|
+
bottom: -8px;
|
|
226
|
+
right: 0;
|
|
227
|
+
font-family: 'IBM Plex Mono', monospace;
|
|
228
|
+
font-size: 10px;
|
|
229
|
+
color: rgba(0, 255, 136, 0.3);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/* Scanline overlay */
|
|
233
|
+
.scanlines {
|
|
234
|
+
pointer-events: none;
|
|
235
|
+
position: fixed;
|
|
236
|
+
inset: 0;
|
|
237
|
+
background: repeating-linear-gradient(
|
|
238
|
+
0deg,
|
|
239
|
+
transparent,
|
|
240
|
+
transparent 2px,
|
|
241
|
+
rgba(0, 0, 0, 0.05) 2px,
|
|
242
|
+
rgba(0, 0, 0, 0.05) 4px
|
|
243
|
+
);
|
|
244
|
+
z-index: 9999;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/* CRT glow effect */
|
|
248
|
+
.crt-glow {
|
|
249
|
+
text-shadow: 0 0 5px currentColor, 0 0 10px currentColor;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/* Button terminal */
|
|
253
|
+
.btn-terminal {
|
|
254
|
+
font-family: 'IBM Plex Mono', monospace;
|
|
255
|
+
font-size: 12px;
|
|
256
|
+
letter-spacing: 0.1em;
|
|
257
|
+
text-transform: uppercase;
|
|
258
|
+
background: transparent;
|
|
259
|
+
border: 1px solid var(--matrix);
|
|
260
|
+
color: var(--matrix);
|
|
261
|
+
padding: 10px 20px;
|
|
262
|
+
position: relative;
|
|
263
|
+
overflow: hidden;
|
|
264
|
+
transition: all 0.3s ease;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.btn-terminal::before {
|
|
268
|
+
content: '';
|
|
269
|
+
position: absolute;
|
|
270
|
+
inset: 0;
|
|
271
|
+
background: var(--matrix);
|
|
272
|
+
transform: translateX(-100%);
|
|
273
|
+
transition: transform 0.3s ease;
|
|
274
|
+
z-index: -1;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.btn-terminal:hover {
|
|
278
|
+
color: black;
|
|
279
|
+
box-shadow: 0 0 20px rgba(0, 255, 136, 0.4);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.btn-terminal:hover::before {
|
|
283
|
+
transform: translateX(0);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/* Status badge */
|
|
287
|
+
.status-badge {
|
|
288
|
+
font-family: 'IBM Plex Mono', monospace;
|
|
289
|
+
font-size: 10px;
|
|
290
|
+
letter-spacing: 0.1em;
|
|
291
|
+
text-transform: uppercase;
|
|
292
|
+
padding: 4px 8px;
|
|
293
|
+
border: 1px solid currentColor;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/* Grid background */
|
|
297
|
+
.grid-bg {
|
|
298
|
+
background-image:
|
|
299
|
+
linear-gradient(rgba(0, 255, 136, 0.02) 1px, transparent 1px),
|
|
300
|
+
linear-gradient(90deg, rgba(0, 255, 136, 0.02) 1px, transparent 1px);
|
|
301
|
+
background-size: 40px 40px;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
/* Typing cursor */
|
|
305
|
+
.typing-cursor::after {
|
|
306
|
+
content: '█';
|
|
307
|
+
animation: blink 1s step-end infinite;
|
|
308
|
+
color: var(--matrix);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/* Metric display */
|
|
312
|
+
.metric-display {
|
|
313
|
+
font-family: 'Orbitron', monospace;
|
|
314
|
+
font-variant-numeric: tabular-nums;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/* Feature card */
|
|
318
|
+
.feature-card {
|
|
319
|
+
background: #0d0d0d;
|
|
320
|
+
border: 1px solid #00ff88;
|
|
321
|
+
transition: all 0.3s ease;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.feature-card:hover {
|
|
325
|
+
border-color: #00ff88;
|
|
326
|
+
box-shadow: 0 0 30px rgba(0, 255, 136, 0.2);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/* Task row */
|
|
330
|
+
.task-row {
|
|
331
|
+
background: #0d0d0d;
|
|
332
|
+
border: 1px solid #1a1a1a;
|
|
333
|
+
transition: all 0.2s ease;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.task-row:hover {
|
|
337
|
+
background: #111;
|
|
338
|
+
border-color: #333;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/* Input terminal style */
|
|
342
|
+
.input-terminal {
|
|
343
|
+
background: #0a0a0a;
|
|
344
|
+
border: 1px solid #333;
|
|
345
|
+
color: #e0e0e0;
|
|
346
|
+
font-family: 'IBM Plex Mono', monospace;
|
|
347
|
+
transition: all 0.2s ease;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.input-terminal::placeholder {
|
|
351
|
+
color: #555;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.input-terminal:focus {
|
|
355
|
+
border-color: var(--matrix);
|
|
356
|
+
box-shadow: 0 0 0 1px var(--matrix), 0 0 20px rgba(0, 255, 136, 0.1);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/* Modal overlay */
|
|
360
|
+
.modal-overlay {
|
|
361
|
+
background: rgba(0, 0, 0, 0.9);
|
|
362
|
+
backdrop-filter: blur(4px);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/* Animated gradient text */
|
|
366
|
+
.text-matrix {
|
|
367
|
+
color: var(--matrix);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.text-signal {
|
|
371
|
+
color: var(--signal);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.text-cyber {
|
|
375
|
+
color: var(--cyber);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
.text-alert {
|
|
379
|
+
color: var(--alert);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
@layer utilities {
|
|
384
|
+
/* Stagger animations - elements always visible, animation is just enhancement */
|
|
385
|
+
.stagger > * {
|
|
386
|
+
opacity: 1 !important;
|
|
387
|
+
animation: slide-up 0.4s ease-out forwards;
|
|
388
|
+
}
|
|
389
|
+
.stagger > *:nth-child(1) { animation-delay: 0ms; }
|
|
390
|
+
.stagger > *:nth-child(2) { animation-delay: 50ms; }
|
|
391
|
+
.stagger > *:nth-child(3) { animation-delay: 100ms; }
|
|
392
|
+
.stagger > *:nth-child(4) { animation-delay: 150ms; }
|
|
393
|
+
.stagger > *:nth-child(5) { animation-delay: 200ms; }
|
|
394
|
+
.stagger > *:nth-child(6) { animation-delay: 250ms; }
|
|
395
|
+
.stagger > *:nth-child(7) { animation-delay: 300ms; }
|
|
396
|
+
.stagger > *:nth-child(8) { animation-delay: 350ms; }
|
|
397
|
+
|
|
398
|
+
/* Glow utilities */
|
|
399
|
+
.glow-matrix {
|
|
400
|
+
box-shadow: 0 0 20px rgba(0, 255, 136, 0.3);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.glow-signal {
|
|
404
|
+
box-shadow: 0 0 20px rgba(255, 149, 0, 0.3);
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
.glow-cyber {
|
|
408
|
+
box-shadow: 0 0 20px rgba(0, 212, 255, 0.3);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
.glow-alert {
|
|
412
|
+
box-shadow: 0 0 20px rgba(255, 51, 102, 0.3);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/* Keyframes */
|
|
417
|
+
@keyframes blink {
|
|
418
|
+
0%, 100% { opacity: 1; }
|
|
419
|
+
50% { opacity: 0; }
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
@keyframes slide-up {
|
|
423
|
+
0% {
|
|
424
|
+
opacity: 0;
|
|
425
|
+
transform: translateY(20px);
|
|
426
|
+
}
|
|
427
|
+
100% {
|
|
428
|
+
opacity: 1;
|
|
429
|
+
transform: translateY(0);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
@keyframes fade-in {
|
|
434
|
+
from { opacity: 0; }
|
|
435
|
+
to { opacity: 1; }
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
.animate-fade-in {
|
|
439
|
+
animation: fade-in 0.3s ease-out forwards;
|
|
440
|
+
}
|