shell-mirror 1.5.132 → 1.5.138
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/package.json +1 -1
- package/public/.htaccess +7 -0
- package/public/app/dashboard.html +4 -3
- package/public/app/dashboard.js +4 -0
- package/public/app/terminal.html +1 -0
- package/public/contact.html +492 -0
- package/public/how-it-works.html +442 -0
- package/public/images/favicon.png +0 -0
- package/public/images/hero_mockup.png +0 -0
- package/public/images/private_by_design.png +0 -0
- package/public/images/real_terminal_view.png +0 -0
- package/public/images/same_session.png +0 -0
- package/public/images/shellmirror_clean_hero.png +0 -0
- package/public/images/shellmirror_macbook_hero.png +0 -0
- package/public/images/terminal-svgrepo-com.svg +7 -0
- package/public/index.html +909 -570
- package/public/privacy.html +362 -0
- package/server.js +9 -0
package/public/index.html
CHANGED
|
@@ -3,46 +3,44 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<
|
|
7
|
-
<
|
|
8
|
-
<meta name="
|
|
9
|
-
|
|
6
|
+
<link rel="icon" type="image/png" href="/images/favicon.png">
|
|
7
|
+
<title>>shell-mirror — Mirror your terminal session to your phone</title>
|
|
8
|
+
<meta name="description" content="Open the same terminal session on your phone when you step away from your computer. Works with Claude Code, Gemini CLI, and other terminal tools.">
|
|
9
|
+
<meta name="keywords" content="terminal mirror, mobile terminal, Claude Code mobile, Gemini CLI phone, remote terminal session, shell mirror">
|
|
10
|
+
|
|
10
11
|
<!-- Open Graph / Facebook -->
|
|
11
12
|
<meta property="og:type" content="website">
|
|
12
|
-
<meta property="og:title" content="
|
|
13
|
-
<meta property="og:description" content="
|
|
13
|
+
<meta property="og:title" content=">shell-mirror — Your terminal, on your phone">
|
|
14
|
+
<meta property="og:description" content="Keep the same terminal session running on your computer and open it on your phone when you leave the desk.">
|
|
14
15
|
<meta property="og:url" content="https://shellmirror.app">
|
|
15
|
-
|
|
16
|
+
|
|
16
17
|
<!-- Twitter -->
|
|
17
18
|
<meta property="twitter:card" content="summary_large_image">
|
|
18
|
-
<meta property="twitter:title" content="
|
|
19
|
-
<meta property="twitter:description" content="
|
|
20
|
-
|
|
19
|
+
<meta property="twitter:title" content=">shell-mirror — Your terminal, on your phone">
|
|
20
|
+
<meta property="twitter:description" content="Open the same terminal session on your phone without starting over.">
|
|
21
|
+
|
|
22
|
+
<!-- Fonts -->
|
|
23
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
24
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
25
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700;800;900&family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;700&display=swap" rel="stylesheet">
|
|
26
|
+
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet">
|
|
27
|
+
|
|
21
28
|
<!-- Google Analytics 4 -->
|
|
22
29
|
<script>
|
|
23
|
-
// Initialize dataLayer and gtag function first
|
|
24
30
|
window.dataLayer = window.dataLayer || [];
|
|
25
31
|
function gtag(){dataLayer.push(arguments);}
|
|
26
32
|
gtag('js', new Date());
|
|
27
33
|
gtag('config', 'G-LG7ZGLB8FK');
|
|
28
|
-
|
|
29
|
-
// Load gtag script with proper error handling
|
|
30
34
|
(function() {
|
|
31
35
|
var script = document.createElement('script');
|
|
32
36
|
script.async = true;
|
|
33
37
|
script.src = 'https://www.googletagmanager.com/gtag/js?id=G-LG7ZGLB8FK';
|
|
34
|
-
script.onload = function() {
|
|
35
|
-
|
|
36
|
-
window.gtagLoaded = true;
|
|
37
|
-
};
|
|
38
|
-
script.onerror = function() {
|
|
39
|
-
console.warn('❌ Failed to load Google Analytics script');
|
|
40
|
-
window.gtagLoaded = false;
|
|
41
|
-
};
|
|
38
|
+
script.onload = function() { window.gtagLoaded = true; };
|
|
39
|
+
script.onerror = function() { window.gtagLoaded = false; };
|
|
42
40
|
document.head.appendChild(script);
|
|
43
41
|
})();
|
|
44
42
|
</script>
|
|
45
|
-
|
|
43
|
+
|
|
46
44
|
<!-- Microsoft Clarity -->
|
|
47
45
|
<script type="text/javascript">
|
|
48
46
|
(function(c,l,a,r,i,t,y){
|
|
@@ -51,99 +49,166 @@
|
|
|
51
49
|
y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
|
|
52
50
|
})(window, document, "clarity", "script", "sy1w2d7il7");
|
|
53
51
|
</script>
|
|
54
|
-
|
|
52
|
+
|
|
55
53
|
<style>
|
|
56
54
|
:root {
|
|
57
|
-
--bg-primary: #
|
|
58
|
-
--bg-secondary: #
|
|
59
|
-
--bg-tertiary: #
|
|
60
|
-
--bg-hover: #
|
|
61
|
-
--text-primary: #
|
|
55
|
+
--bg-primary: #121315;
|
|
56
|
+
--bg-secondary: #1b1c1e;
|
|
57
|
+
--bg-tertiary: #1f2022;
|
|
58
|
+
--bg-hover: #292a2c;
|
|
59
|
+
--text-primary: #e3e2e5;
|
|
62
60
|
--text-secondary: #8a8f98;
|
|
63
61
|
--text-muted: #5a5f6a;
|
|
64
|
-
--accent: #
|
|
65
|
-
--accent-
|
|
62
|
+
--accent: #7c4dff;
|
|
63
|
+
--accent-light: #cdbdff;
|
|
64
|
+
--accent-hover: #6833ea;
|
|
66
65
|
--success: #00c853;
|
|
67
|
-
--border:
|
|
66
|
+
--border: rgba(73, 68, 85, 0.15);
|
|
67
|
+
--border-visible: rgba(73, 68, 85, 0.3);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
* {
|
|
71
|
-
margin: 0;
|
|
72
|
-
padding: 0;
|
|
73
|
-
box-sizing: border-box;
|
|
74
|
-
}
|
|
70
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
75
71
|
|
|
76
72
|
body {
|
|
77
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
73
|
+
font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
78
74
|
line-height: 1.6;
|
|
79
75
|
color: var(--text-primary);
|
|
80
76
|
background: var(--bg-primary);
|
|
81
77
|
min-height: 100vh;
|
|
78
|
+
-webkit-font-smoothing: antialiased;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.material-symbols-outlined {
|
|
82
|
+
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
.container {
|
|
85
86
|
max-width: 1200px;
|
|
86
87
|
margin: 0 auto;
|
|
87
|
-
padding: 0
|
|
88
|
+
padding: 0 32px;
|
|
88
89
|
}
|
|
89
90
|
|
|
90
|
-
/* Header */
|
|
91
|
+
/* ========== Header ========== */
|
|
91
92
|
header {
|
|
92
|
-
|
|
93
|
-
|
|
93
|
+
position: fixed;
|
|
94
|
+
top: 0;
|
|
95
|
+
width: 100%;
|
|
94
96
|
z-index: 100;
|
|
95
|
-
background:
|
|
96
|
-
|
|
97
|
+
background: rgba(18, 19, 21, 0.6);
|
|
98
|
+
backdrop-filter: blur(20px);
|
|
99
|
+
-webkit-backdrop-filter: blur(20px);
|
|
100
|
+
box-shadow: 0 8px 32px rgba(124, 77, 255, 0.04);
|
|
97
101
|
}
|
|
98
102
|
|
|
99
|
-
|
|
103
|
+
header .container {
|
|
100
104
|
display: flex;
|
|
101
105
|
justify-content: space-between;
|
|
102
106
|
align-items: center;
|
|
107
|
+
padding-top: 16px;
|
|
108
|
+
padding-bottom: 16px;
|
|
103
109
|
}
|
|
104
110
|
|
|
105
111
|
.logo {
|
|
106
|
-
font-size: 1.
|
|
107
|
-
font-weight:
|
|
112
|
+
font-size: 1.3rem;
|
|
113
|
+
font-weight: 800;
|
|
114
|
+
color: #f0eff2;
|
|
115
|
+
letter-spacing: -0.03em;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.nav-links {
|
|
119
|
+
display: flex;
|
|
120
|
+
gap: 32px;
|
|
121
|
+
align-items: center;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.nav-links a {
|
|
125
|
+
color: var(--text-muted);
|
|
126
|
+
text-decoration: none;
|
|
127
|
+
font-size: 0.9rem;
|
|
128
|
+
font-weight: 500;
|
|
129
|
+
transition: color 0.2s ease;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.nav-links a:hover {
|
|
108
133
|
color: var(--text-primary);
|
|
109
134
|
}
|
|
110
135
|
|
|
136
|
+
.header-right {
|
|
137
|
+
display: flex;
|
|
138
|
+
align-items: center;
|
|
139
|
+
gap: 16px;
|
|
140
|
+
}
|
|
141
|
+
|
|
111
142
|
.cta-button {
|
|
112
143
|
background: var(--accent);
|
|
113
144
|
color: white;
|
|
114
|
-
padding: 10px
|
|
145
|
+
padding: 10px 22px;
|
|
115
146
|
text-decoration: none;
|
|
116
|
-
border-radius:
|
|
117
|
-
font-weight:
|
|
147
|
+
border-radius: 8px;
|
|
148
|
+
font-weight: 600;
|
|
118
149
|
border: none;
|
|
119
|
-
|
|
150
|
+
cursor: pointer;
|
|
151
|
+
transition: all 0.2s ease;
|
|
152
|
+
font-size: 0.9rem;
|
|
153
|
+
box-shadow: 0 4px 16px rgba(124, 77, 255, 0.2);
|
|
120
154
|
}
|
|
121
155
|
|
|
122
156
|
.cta-button:hover {
|
|
123
157
|
background: var(--accent-hover);
|
|
158
|
+
box-shadow: 0 4px 20px rgba(124, 77, 255, 0.35);
|
|
124
159
|
}
|
|
125
160
|
|
|
126
|
-
/* Hero
|
|
161
|
+
/* ========== Hero ========== */
|
|
127
162
|
.hero {
|
|
128
163
|
text-align: center;
|
|
129
|
-
padding:
|
|
130
|
-
|
|
164
|
+
padding: 140px 0 40px;
|
|
165
|
+
position: relative;
|
|
166
|
+
overflow: visible;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.hero-glow {
|
|
170
|
+
position: absolute;
|
|
171
|
+
top: -100px;
|
|
172
|
+
left: 50%;
|
|
173
|
+
transform: translateX(-50%);
|
|
174
|
+
width: 600px;
|
|
175
|
+
height: 500px;
|
|
176
|
+
background: radial-gradient(ellipse, rgba(124, 77, 255, 0.1) 0%, transparent 70%);
|
|
177
|
+
pointer-events: none;
|
|
178
|
+
z-index: -1;
|
|
131
179
|
}
|
|
132
180
|
|
|
133
181
|
.hero h1 {
|
|
134
|
-
font-size: clamp(
|
|
135
|
-
font-weight:
|
|
136
|
-
margin-bottom:
|
|
137
|
-
line-height:
|
|
182
|
+
font-size: clamp(2.5rem, 6vw, 4.5rem);
|
|
183
|
+
font-weight: 800;
|
|
184
|
+
margin-bottom: 24px;
|
|
185
|
+
line-height: 0.95;
|
|
186
|
+
letter-spacing: -0.03em;
|
|
138
187
|
}
|
|
139
188
|
|
|
140
|
-
.hero
|
|
141
|
-
|
|
142
|
-
|
|
189
|
+
.hero h1 .accent-glow {
|
|
190
|
+
color: var(--accent-light);
|
|
191
|
+
text-shadow: 0 0 30px rgba(124, 77, 255, 0.3);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.hero-sub {
|
|
195
|
+
font-size: clamp(1.05rem, 1.5vw, 1.2rem);
|
|
196
|
+
margin-bottom: 12px;
|
|
143
197
|
color: var(--text-secondary);
|
|
144
198
|
max-width: 600px;
|
|
145
199
|
margin-left: auto;
|
|
146
200
|
margin-right: auto;
|
|
201
|
+
font-weight: 500;
|
|
202
|
+
line-height: 1.6;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
.hero-support {
|
|
206
|
+
font-size: 0.9rem;
|
|
207
|
+
color: var(--text-muted);
|
|
208
|
+
margin-bottom: 48px;
|
|
209
|
+
max-width: 600px;
|
|
210
|
+
margin-left: auto;
|
|
211
|
+
margin-right: auto;
|
|
147
212
|
}
|
|
148
213
|
|
|
149
214
|
.hero-buttons {
|
|
@@ -151,644 +216,940 @@
|
|
|
151
216
|
gap: 16px;
|
|
152
217
|
justify-content: center;
|
|
153
218
|
flex-wrap: wrap;
|
|
154
|
-
margin-bottom:
|
|
219
|
+
margin-bottom: 80px;
|
|
155
220
|
}
|
|
156
221
|
|
|
157
222
|
.btn-primary {
|
|
158
|
-
background: var(--accent);
|
|
159
|
-
color:
|
|
160
|
-
padding:
|
|
223
|
+
background: linear-gradient(135deg, var(--accent-light), var(--accent));
|
|
224
|
+
color: #1a0050;
|
|
225
|
+
padding: 16px 36px;
|
|
161
226
|
text-decoration: none;
|
|
162
|
-
border-radius:
|
|
163
|
-
font-weight:
|
|
227
|
+
border-radius: 8px;
|
|
228
|
+
font-weight: 700;
|
|
164
229
|
font-size: 1rem;
|
|
165
|
-
transition: all 0.
|
|
230
|
+
transition: all 0.2s ease;
|
|
166
231
|
border: none;
|
|
232
|
+
cursor: pointer;
|
|
233
|
+
letter-spacing: 0.02em;
|
|
234
|
+
box-shadow: 0 0 40px rgba(124, 77, 255, 0.25);
|
|
167
235
|
}
|
|
168
236
|
|
|
169
237
|
.btn-primary:hover {
|
|
170
|
-
|
|
238
|
+
box-shadow: 0 0 50px rgba(124, 77, 255, 0.4);
|
|
239
|
+
transform: translateY(-1px);
|
|
171
240
|
}
|
|
172
241
|
|
|
173
242
|
.btn-secondary {
|
|
174
|
-
background:
|
|
243
|
+
background: var(--bg-tertiary);
|
|
175
244
|
color: var(--text-primary);
|
|
176
|
-
padding:
|
|
245
|
+
padding: 16px 36px;
|
|
177
246
|
text-decoration: none;
|
|
178
|
-
border-radius:
|
|
179
|
-
font-weight:
|
|
247
|
+
border-radius: 8px;
|
|
248
|
+
font-weight: 600;
|
|
180
249
|
font-size: 1rem;
|
|
181
|
-
border: 1px solid var(--border);
|
|
182
|
-
transition: all 0.
|
|
250
|
+
border: 1px solid var(--border-visible);
|
|
251
|
+
transition: all 0.2s ease;
|
|
183
252
|
}
|
|
184
253
|
|
|
185
254
|
.btn-secondary:hover {
|
|
186
255
|
background: var(--bg-hover);
|
|
187
|
-
border-color: var(--text-muted);
|
|
188
256
|
}
|
|
189
257
|
|
|
190
|
-
/*
|
|
191
|
-
.
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
flex-direction: column;
|
|
196
|
-
gap: 16px;
|
|
258
|
+
/* ========== Terminal Visual ========== */
|
|
259
|
+
.terminal-visual {
|
|
260
|
+
max-width: 960px;
|
|
261
|
+
margin: 0 auto;
|
|
262
|
+
position: relative;
|
|
197
263
|
}
|
|
198
264
|
|
|
199
|
-
.
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
265
|
+
.terminal-visual-glow {
|
|
266
|
+
position: absolute;
|
|
267
|
+
inset: -2px;
|
|
268
|
+
background: linear-gradient(135deg, rgba(124,77,255,0.4), rgba(193,193,255,0.2));
|
|
269
|
+
border-radius: 20px;
|
|
270
|
+
filter: blur(1px);
|
|
271
|
+
opacity: 0.3;
|
|
272
|
+
z-index: 0;
|
|
203
273
|
}
|
|
204
274
|
|
|
205
|
-
.
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
275
|
+
.terminal-visual-inner {
|
|
276
|
+
position: relative;
|
|
277
|
+
z-index: 1;
|
|
278
|
+
background: rgba(31, 32, 34, 0.6);
|
|
279
|
+
backdrop-filter: blur(16px);
|
|
280
|
+
-webkit-backdrop-filter: blur(16px);
|
|
281
|
+
border: 1px solid var(--border);
|
|
282
|
+
border-radius: 20px;
|
|
283
|
+
padding: 32px;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.terminal-visual-mockups {
|
|
211
287
|
display: flex;
|
|
288
|
+
gap: 32px;
|
|
212
289
|
align-items: center;
|
|
213
|
-
justify-content: center;
|
|
214
|
-
background: var(--bg-tertiary);
|
|
215
|
-
border-radius: 50%;
|
|
216
290
|
}
|
|
217
291
|
|
|
218
|
-
/*
|
|
219
|
-
.
|
|
220
|
-
background: var(--bg-tertiary);
|
|
221
|
-
padding: 16px 20px;
|
|
222
|
-
border-radius: 6px;
|
|
223
|
-
border: 1px solid var(--border);
|
|
224
|
-
position: relative;
|
|
292
|
+
/* Desktop terminal mockup */
|
|
293
|
+
.mock-desktop {
|
|
225
294
|
flex: 1;
|
|
226
|
-
|
|
295
|
+
max-width: 520px;
|
|
296
|
+
background: var(--bg-primary);
|
|
297
|
+
border-radius: 12px;
|
|
298
|
+
overflow: hidden;
|
|
299
|
+
border: 1px solid var(--border);
|
|
300
|
+
box-shadow: 0 8px 32px rgba(0,0,0,0.4);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.mock-titlebar {
|
|
304
|
+
background: var(--bg-tertiary);
|
|
305
|
+
padding: 10px 14px;
|
|
227
306
|
display: flex;
|
|
307
|
+
gap: 7px;
|
|
228
308
|
align-items: center;
|
|
229
309
|
}
|
|
230
310
|
|
|
231
|
-
.
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
margin: 0;
|
|
236
|
-
padding-right: 40px;
|
|
237
|
-
flex: 1;
|
|
311
|
+
.mock-dot {
|
|
312
|
+
width: 10px;
|
|
313
|
+
height: 10px;
|
|
314
|
+
border-radius: 50%;
|
|
238
315
|
}
|
|
239
316
|
|
|
240
|
-
.
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
transition: all 0.15s ease;
|
|
252
|
-
font-size: 0.75rem;
|
|
317
|
+
.mock-dot.red { background: rgba(255, 95, 87, 0.5); }
|
|
318
|
+
.mock-dot.yellow { background: rgba(255, 189, 46, 0.5); }
|
|
319
|
+
.mock-dot.green { background: rgba(39, 201, 63, 0.5); }
|
|
320
|
+
|
|
321
|
+
.mock-terminal {
|
|
322
|
+
padding: 20px;
|
|
323
|
+
font-family: 'JetBrains Mono', 'Monaco', 'Menlo', monospace;
|
|
324
|
+
font-size: 0.85rem;
|
|
325
|
+
line-height: 1.7;
|
|
326
|
+
min-height: 260px;
|
|
327
|
+
text-align: left;
|
|
253
328
|
}
|
|
254
329
|
|
|
255
|
-
.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
330
|
+
.mock-prompt { color: var(--accent-light); }
|
|
331
|
+
.mock-path { color: #c1c1ff; }
|
|
332
|
+
.mock-cmd { color: var(--text-secondary); }
|
|
333
|
+
.mock-output { color: rgba(227, 226, 229, 0.5); }
|
|
334
|
+
.mock-modified { color: #ff8a80; }
|
|
335
|
+
.mock-cursor {
|
|
336
|
+
display: inline-block;
|
|
337
|
+
width: 8px;
|
|
338
|
+
height: 16px;
|
|
339
|
+
background: rgba(227, 226, 229, 0.3);
|
|
340
|
+
animation: blink 1.2s step-end infinite;
|
|
341
|
+
vertical-align: text-bottom;
|
|
259
342
|
}
|
|
260
343
|
|
|
261
|
-
|
|
262
|
-
|
|
344
|
+
@keyframes blink {
|
|
345
|
+
50% { opacity: 0; }
|
|
263
346
|
}
|
|
264
347
|
|
|
265
|
-
|
|
266
|
-
|
|
348
|
+
/* Phone mockup */
|
|
349
|
+
.mock-phone {
|
|
350
|
+
width: 220px;
|
|
351
|
+
min-height: 380px;
|
|
352
|
+
background: var(--bg-primary);
|
|
353
|
+
border-radius: 36px;
|
|
354
|
+
border: 6px solid var(--bg-hover);
|
|
355
|
+
overflow: hidden;
|
|
356
|
+
flex-shrink: 0;
|
|
357
|
+
display: flex;
|
|
358
|
+
flex-direction: column;
|
|
359
|
+
box-shadow: 0 8px 32px rgba(0,0,0,0.4);
|
|
267
360
|
}
|
|
268
361
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
color: #3c4043;
|
|
273
|
-
padding: 16px 20px;
|
|
274
|
-
border: none;
|
|
275
|
-
border-radius: 6px;
|
|
276
|
-
font-weight: 500;
|
|
277
|
-
font-size: 0.95rem;
|
|
362
|
+
.mock-notch {
|
|
363
|
+
background: var(--bg-hover);
|
|
364
|
+
height: 24px;
|
|
278
365
|
display: flex;
|
|
279
|
-
align-items: center;
|
|
280
366
|
justify-content: center;
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
367
|
+
align-items: flex-end;
|
|
368
|
+
padding-bottom: 2px;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
.mock-notch-pill {
|
|
372
|
+
width: 60px;
|
|
373
|
+
height: 16px;
|
|
374
|
+
background: var(--bg-primary);
|
|
375
|
+
border-radius: 999px;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
.mock-phone-header {
|
|
379
|
+
display: flex;
|
|
380
|
+
justify-content: space-between;
|
|
381
|
+
align-items: center;
|
|
382
|
+
padding: 8px 14px;
|
|
383
|
+
font-family: 'Space Grotesk', sans-serif;
|
|
384
|
+
font-size: 9px;
|
|
385
|
+
color: var(--accent);
|
|
386
|
+
font-weight: 600;
|
|
387
|
+
letter-spacing: 0.05em;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.mock-phone-terminal {
|
|
284
391
|
flex: 1;
|
|
285
|
-
|
|
392
|
+
margin: 0 10px 14px;
|
|
393
|
+
background: rgba(13, 14, 16, 0.8);
|
|
394
|
+
border-radius: 12px;
|
|
395
|
+
padding: 12px;
|
|
396
|
+
text-align: left;
|
|
397
|
+
font-family: 'JetBrains Mono', monospace;
|
|
398
|
+
font-size: 9px;
|
|
399
|
+
line-height: 1.6;
|
|
286
400
|
}
|
|
287
401
|
|
|
288
|
-
|
|
289
|
-
|
|
402
|
+
/* ========== Clarifying line (inside terminal visual) ========== */
|
|
403
|
+
.clarifying-line {
|
|
404
|
+
text-align: center;
|
|
405
|
+
padding: 20px 32px 0;
|
|
290
406
|
}
|
|
291
407
|
|
|
292
|
-
.
|
|
293
|
-
|
|
408
|
+
.clarifying-line p {
|
|
409
|
+
color: var(--text-muted);
|
|
410
|
+
font-size: 0.85rem;
|
|
411
|
+
font-style: italic;
|
|
294
412
|
}
|
|
295
413
|
|
|
296
|
-
/*
|
|
297
|
-
.
|
|
298
|
-
|
|
299
|
-
position: fixed;
|
|
300
|
-
top: 0;
|
|
301
|
-
left: 0;
|
|
302
|
-
width: 100%;
|
|
303
|
-
height: 100%;
|
|
304
|
-
background: rgba(0, 0, 0, 0.8);
|
|
305
|
-
z-index: 1000;
|
|
306
|
-
align-items: center;
|
|
307
|
-
justify-content: center;
|
|
414
|
+
/* ========== Benefits ========== */
|
|
415
|
+
.benefits {
|
|
416
|
+
padding: 120px 0;
|
|
308
417
|
}
|
|
309
418
|
|
|
310
|
-
.
|
|
311
|
-
display:
|
|
419
|
+
.benefit-grid {
|
|
420
|
+
display: grid;
|
|
421
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
422
|
+
gap: 24px;
|
|
312
423
|
}
|
|
313
424
|
|
|
314
|
-
.
|
|
315
|
-
background:
|
|
316
|
-
|
|
317
|
-
|
|
425
|
+
.glass-card {
|
|
426
|
+
background: rgba(31, 32, 34, 0.6);
|
|
427
|
+
backdrop-filter: blur(16px);
|
|
428
|
+
-webkit-backdrop-filter: blur(16px);
|
|
318
429
|
border: 1px solid var(--border);
|
|
319
|
-
|
|
320
|
-
margin: 20px;
|
|
321
|
-
text-align: center;
|
|
322
|
-
position: relative;
|
|
430
|
+
border-radius: 16px;
|
|
323
431
|
}
|
|
324
432
|
|
|
325
|
-
.
|
|
326
|
-
|
|
327
|
-
|
|
433
|
+
.benefit-block {
|
|
434
|
+
padding: 40px 32px;
|
|
435
|
+
transition: transform 0.3s ease;
|
|
436
|
+
position: relative;
|
|
437
|
+
overflow: hidden;
|
|
438
|
+
background-size: cover;
|
|
439
|
+
background-position: top center;
|
|
440
|
+
background-repeat: no-repeat;
|
|
441
|
+
min-height: 380px;
|
|
442
|
+
display: flex;
|
|
443
|
+
flex-direction: column;
|
|
444
|
+
justify-content: flex-end;
|
|
328
445
|
}
|
|
329
446
|
|
|
330
|
-
.
|
|
331
|
-
|
|
332
|
-
|
|
447
|
+
.benefit-block::before {
|
|
448
|
+
content: '';
|
|
449
|
+
position: absolute;
|
|
450
|
+
inset: 0;
|
|
451
|
+
background: linear-gradient(to bottom, rgba(18,19,21,0) 0%, rgba(18,19,21,0.1) 30%, rgba(18,19,21,0.75) 50%, rgba(18,19,21,1) 65%);
|
|
452
|
+
z-index: 0;
|
|
333
453
|
}
|
|
334
454
|
|
|
335
|
-
.
|
|
336
|
-
|
|
337
|
-
margin: 16px 0;
|
|
455
|
+
.benefit-block:hover {
|
|
456
|
+
transform: translateY(-6px);
|
|
338
457
|
}
|
|
339
458
|
|
|
340
|
-
.
|
|
341
|
-
|
|
459
|
+
.benefit-block h3,
|
|
460
|
+
.benefit-block p {
|
|
461
|
+
position: relative;
|
|
462
|
+
z-index: 1;
|
|
342
463
|
}
|
|
343
464
|
|
|
344
|
-
.
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
font-size: 24px;
|
|
351
|
-
cursor: pointer;
|
|
352
|
-
color: var(--text-muted);
|
|
465
|
+
.benefit-block h3 {
|
|
466
|
+
color: #fff;
|
|
467
|
+
margin-bottom: 12px;
|
|
468
|
+
font-size: 1.35rem;
|
|
469
|
+
font-weight: 700;
|
|
470
|
+
text-shadow: 0 1px 4px rgba(0,0,0,0.6);
|
|
353
471
|
}
|
|
354
472
|
|
|
355
|
-
.
|
|
356
|
-
color: var(--text-
|
|
473
|
+
.benefit-block p {
|
|
474
|
+
color: var(--text-secondary);
|
|
475
|
+
font-size: 0.95rem;
|
|
476
|
+
line-height: 1.7;
|
|
477
|
+
text-shadow: 0 1px 3px rgba(0,0,0,0.5);
|
|
357
478
|
}
|
|
358
479
|
|
|
359
|
-
/*
|
|
360
|
-
.
|
|
361
|
-
|
|
362
|
-
|
|
480
|
+
/* ========== Why Section ========== */
|
|
481
|
+
.why-section {
|
|
482
|
+
padding: 120px 0;
|
|
483
|
+
background: var(--bg-primary);
|
|
363
484
|
}
|
|
364
485
|
|
|
365
486
|
.section-title {
|
|
366
487
|
text-align: center;
|
|
367
|
-
font-size: 1.
|
|
368
|
-
font-weight:
|
|
488
|
+
font-size: clamp(1.5rem, 3vw, 2.25rem);
|
|
489
|
+
font-weight: 800;
|
|
369
490
|
margin-bottom: 48px;
|
|
370
491
|
color: var(--text-primary);
|
|
492
|
+
letter-spacing: -0.02em;
|
|
371
493
|
}
|
|
372
494
|
|
|
373
|
-
.
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
gap: 32px;
|
|
377
|
-
margin-bottom: 48px;
|
|
495
|
+
.why-content {
|
|
496
|
+
max-width: 680px;
|
|
497
|
+
margin: 0 auto;
|
|
378
498
|
}
|
|
379
499
|
|
|
380
|
-
.
|
|
381
|
-
text-
|
|
382
|
-
|
|
500
|
+
.why-content p {
|
|
501
|
+
color: var(--text-secondary);
|
|
502
|
+
font-size: 1.05rem;
|
|
503
|
+
line-height: 1.8;
|
|
504
|
+
margin-bottom: 24px;
|
|
383
505
|
}
|
|
384
506
|
|
|
385
|
-
.
|
|
386
|
-
|
|
387
|
-
|
|
507
|
+
.why-content p:last-child { margin-bottom: 0; }
|
|
508
|
+
|
|
509
|
+
/* ========== Use Cases ========== */
|
|
510
|
+
.use-cases {
|
|
511
|
+
padding: 120px 0;
|
|
512
|
+
background: var(--bg-secondary);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
.use-case-grid {
|
|
516
|
+
max-width: 700px;
|
|
517
|
+
margin: 0 auto;
|
|
518
|
+
display: flex;
|
|
519
|
+
flex-direction: column;
|
|
520
|
+
gap: 12px;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
.use-case-item {
|
|
524
|
+
display: flex;
|
|
525
|
+
align-items: center;
|
|
526
|
+
gap: 16px;
|
|
527
|
+
padding: 18px 20px;
|
|
388
528
|
background: var(--bg-tertiary);
|
|
529
|
+
border-radius: 12px;
|
|
389
530
|
border: 1px solid var(--border);
|
|
531
|
+
transition: background 0.2s ease;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
.use-case-item:hover {
|
|
535
|
+
background: var(--bg-hover);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
.use-case-icon {
|
|
539
|
+
width: 40px;
|
|
540
|
+
height: 40px;
|
|
390
541
|
border-radius: 50%;
|
|
542
|
+
background: rgba(124, 77, 255, 0.1);
|
|
391
543
|
display: flex;
|
|
392
544
|
align-items: center;
|
|
393
545
|
justify-content: center;
|
|
394
|
-
|
|
395
|
-
font-size: 1.25rem;
|
|
396
|
-
font-weight: 600;
|
|
397
|
-
color: var(--text-secondary);
|
|
546
|
+
flex-shrink: 0;
|
|
398
547
|
}
|
|
399
548
|
|
|
400
|
-
.
|
|
401
|
-
|
|
402
|
-
font-
|
|
403
|
-
|
|
549
|
+
.use-case-icon .material-symbols-outlined {
|
|
550
|
+
color: var(--accent-light);
|
|
551
|
+
font-size: 20px;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
.use-case-item span:last-child {
|
|
404
555
|
color: var(--text-primary);
|
|
556
|
+
font-size: 1rem;
|
|
557
|
+
font-weight: 500;
|
|
405
558
|
}
|
|
406
559
|
|
|
407
|
-
|
|
560
|
+
/* ========== Privacy / Locality ========== */
|
|
561
|
+
.privacy-section {
|
|
562
|
+
padding: 120px 0;
|
|
563
|
+
background: rgba(13, 14, 16, 0.8);
|
|
564
|
+
text-align: center;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
.privacy-content {
|
|
568
|
+
max-width: 680px;
|
|
569
|
+
margin: 0 auto;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
.privacy-content p {
|
|
408
573
|
color: var(--text-secondary);
|
|
409
|
-
|
|
410
|
-
|
|
574
|
+
font-size: 1.05rem;
|
|
575
|
+
line-height: 1.8;
|
|
576
|
+
margin-bottom: 20px;
|
|
411
577
|
}
|
|
412
578
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
579
|
+
.privacy-content p:last-child { margin-bottom: 0; }
|
|
580
|
+
|
|
581
|
+
/* ========== How It Works ========== */
|
|
582
|
+
.how-it-works {
|
|
583
|
+
padding: 120px 0;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
.steps {
|
|
587
|
+
display: grid;
|
|
588
|
+
grid-template-columns: repeat(3, 1fr);
|
|
589
|
+
gap: 48px;
|
|
590
|
+
max-width: 900px;
|
|
591
|
+
margin: 0 auto 32px;
|
|
592
|
+
position: relative;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
.steps-connector {
|
|
596
|
+
display: none;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
.step {
|
|
600
|
+
text-align: center;
|
|
601
|
+
position: relative;
|
|
417
602
|
}
|
|
418
603
|
|
|
419
|
-
.
|
|
604
|
+
.step-circle {
|
|
605
|
+
width: 80px;
|
|
606
|
+
height: 80px;
|
|
607
|
+
border-radius: 50%;
|
|
608
|
+
background: var(--bg-primary);
|
|
609
|
+
border: 3px solid var(--bg-hover);
|
|
420
610
|
display: flex;
|
|
421
611
|
align-items: center;
|
|
422
612
|
justify-content: center;
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
613
|
+
margin: 0 auto 24px;
|
|
614
|
+
position: relative;
|
|
615
|
+
transition: border-color 0.4s ease;
|
|
426
616
|
}
|
|
427
617
|
|
|
428
|
-
.
|
|
429
|
-
|
|
430
|
-
padding: 20px;
|
|
431
|
-
border-radius: 6px;
|
|
432
|
-
border: 1px solid var(--border);
|
|
433
|
-
text-align: center;
|
|
434
|
-
min-width: 180px;
|
|
618
|
+
.step:hover .step-circle {
|
|
619
|
+
border-color: var(--accent);
|
|
435
620
|
}
|
|
436
621
|
|
|
437
|
-
.
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
622
|
+
.step-circle .material-symbols-outlined {
|
|
623
|
+
font-size: 32px;
|
|
624
|
+
color: var(--text-secondary);
|
|
625
|
+
transition: color 0.4s ease;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
.step:hover .step-circle .material-symbols-outlined {
|
|
629
|
+
color: var(--accent-light);
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
.step-num {
|
|
633
|
+
position: absolute;
|
|
634
|
+
top: -6px;
|
|
635
|
+
left: -6px;
|
|
636
|
+
width: 28px;
|
|
637
|
+
height: 28px;
|
|
638
|
+
border-radius: 50%;
|
|
639
|
+
background: var(--accent);
|
|
640
|
+
color: white;
|
|
641
|
+
font-weight: 800;
|
|
642
|
+
font-size: 0.8rem;
|
|
643
|
+
display: flex;
|
|
644
|
+
align-items: center;
|
|
645
|
+
justify-content: center;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
.step h3 {
|
|
649
|
+
font-size: 1.15rem;
|
|
650
|
+
font-weight: 700;
|
|
651
|
+
margin-bottom: 10px;
|
|
652
|
+
color: var(--text-primary);
|
|
441
653
|
}
|
|
442
654
|
|
|
443
|
-
.
|
|
655
|
+
.step p {
|
|
444
656
|
color: var(--text-secondary);
|
|
445
|
-
|
|
657
|
+
line-height: 1.6;
|
|
658
|
+
font-size: 0.9rem;
|
|
446
659
|
}
|
|
447
660
|
|
|
448
|
-
.
|
|
449
|
-
|
|
661
|
+
.steps-closing {
|
|
662
|
+
text-align: center;
|
|
450
663
|
color: var(--text-muted);
|
|
664
|
+
font-size: 0.95rem;
|
|
665
|
+
margin-top: 24px;
|
|
451
666
|
}
|
|
452
667
|
|
|
453
|
-
/*
|
|
454
|
-
.
|
|
455
|
-
padding:
|
|
668
|
+
/* ========== Comparison ========== */
|
|
669
|
+
.comparison {
|
|
670
|
+
padding: 120px 0;
|
|
456
671
|
background: var(--bg-secondary);
|
|
457
672
|
}
|
|
458
673
|
|
|
459
|
-
.
|
|
674
|
+
.comparison-card {
|
|
675
|
+
max-width: 800px;
|
|
676
|
+
margin: 0 auto;
|
|
677
|
+
padding: 48px;
|
|
678
|
+
position: relative;
|
|
679
|
+
overflow: hidden;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
.comparison-card-glow {
|
|
683
|
+
position: absolute;
|
|
684
|
+
top: 0;
|
|
685
|
+
right: 0;
|
|
686
|
+
width: 250px;
|
|
687
|
+
height: 250px;
|
|
688
|
+
background: rgba(124, 77, 255, 0.04);
|
|
689
|
+
filter: blur(80px);
|
|
690
|
+
pointer-events: none;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
.comparison-card > p {
|
|
694
|
+
color: var(--text-secondary);
|
|
695
|
+
font-size: 1.05rem;
|
|
696
|
+
line-height: 1.8;
|
|
697
|
+
margin-bottom: 32px;
|
|
698
|
+
position: relative;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
.comparison-grid {
|
|
460
702
|
display: grid;
|
|
461
|
-
grid-template-columns:
|
|
462
|
-
gap:
|
|
703
|
+
grid-template-columns: 1fr 1fr;
|
|
704
|
+
gap: 20px 48px;
|
|
705
|
+
position: relative;
|
|
463
706
|
}
|
|
464
707
|
|
|
465
|
-
.
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
border-left: 3px solid var(--accent);
|
|
708
|
+
.comparison-item {
|
|
709
|
+
display: flex;
|
|
710
|
+
gap: 12px;
|
|
711
|
+
align-items: flex-start;
|
|
470
712
|
}
|
|
471
713
|
|
|
472
|
-
.
|
|
473
|
-
color: var(--
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
714
|
+
.comparison-item .material-symbols-outlined {
|
|
715
|
+
color: var(--accent);
|
|
716
|
+
font-size: 22px;
|
|
717
|
+
flex-shrink: 0;
|
|
718
|
+
margin-top: 2px;
|
|
719
|
+
font-variation-settings: 'FILL' 1;
|
|
477
720
|
}
|
|
478
721
|
|
|
479
|
-
.
|
|
722
|
+
.comparison-item p {
|
|
480
723
|
color: var(--text-secondary);
|
|
481
724
|
font-size: 0.95rem;
|
|
725
|
+
line-height: 1.6;
|
|
482
726
|
}
|
|
483
727
|
|
|
484
|
-
|
|
728
|
+
.comparison-item p strong {
|
|
729
|
+
color: var(--text-primary);
|
|
730
|
+
font-weight: 600;
|
|
731
|
+
display: block;
|
|
732
|
+
margin-bottom: 2px;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
/* ========== Footer CTA ========== */
|
|
485
736
|
.footer-cta {
|
|
486
|
-
|
|
487
|
-
border-top: 1px solid var(--border);
|
|
488
|
-
padding: 60px 0;
|
|
737
|
+
padding: 120px 0;
|
|
489
738
|
text-align: center;
|
|
490
|
-
|
|
739
|
+
position: relative;
|
|
740
|
+
overflow: hidden;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
.footer-cta-glow {
|
|
744
|
+
position: absolute;
|
|
745
|
+
bottom: -80px;
|
|
746
|
+
left: 50%;
|
|
747
|
+
transform: translateX(-50%);
|
|
748
|
+
width: 150%;
|
|
749
|
+
height: 300px;
|
|
750
|
+
background: radial-gradient(ellipse, rgba(124, 77, 255, 0.15) 0%, transparent 70%);
|
|
751
|
+
pointer-events: none;
|
|
491
752
|
}
|
|
492
753
|
|
|
493
754
|
.footer-cta h2 {
|
|
494
|
-
font-size:
|
|
495
|
-
font-weight:
|
|
755
|
+
font-size: clamp(2rem, 5vw, 3.5rem);
|
|
756
|
+
font-weight: 800;
|
|
496
757
|
margin-bottom: 16px;
|
|
758
|
+
letter-spacing: -0.03em;
|
|
759
|
+
position: relative;
|
|
497
760
|
}
|
|
498
761
|
|
|
499
762
|
.footer-cta p {
|
|
500
|
-
font-size: 1rem;
|
|
501
|
-
margin-bottom:
|
|
763
|
+
font-size: 1.1rem;
|
|
764
|
+
margin-bottom: 40px;
|
|
502
765
|
color: var(--text-secondary);
|
|
766
|
+
position: relative;
|
|
503
767
|
}
|
|
504
768
|
|
|
505
|
-
/*
|
|
506
|
-
|
|
507
|
-
.
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
769
|
+
/* ========== Footer ========== */
|
|
770
|
+
footer {
|
|
771
|
+
background: rgba(13, 14, 16, 0.8);
|
|
772
|
+
border-top: 1px solid var(--border);
|
|
773
|
+
padding: 40px 0;
|
|
774
|
+
}
|
|
511
775
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
776
|
+
.footer-inner {
|
|
777
|
+
display: flex;
|
|
778
|
+
justify-content: space-between;
|
|
779
|
+
align-items: center;
|
|
780
|
+
}
|
|
515
781
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
782
|
+
.footer-brand {
|
|
783
|
+
font-family: 'Space Grotesk', sans-serif;
|
|
784
|
+
font-weight: 700;
|
|
785
|
+
font-size: 0.85rem;
|
|
786
|
+
color: var(--text-secondary);
|
|
787
|
+
letter-spacing: 0.15em;
|
|
788
|
+
text-transform: uppercase;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
.footer-links {
|
|
792
|
+
display: flex;
|
|
793
|
+
gap: 28px;
|
|
794
|
+
}
|
|
521
795
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
796
|
+
.footer-links a {
|
|
797
|
+
color: var(--text-muted);
|
|
798
|
+
text-decoration: none;
|
|
799
|
+
font-family: 'Space Grotesk', sans-serif;
|
|
800
|
+
font-size: 0.8rem;
|
|
801
|
+
letter-spacing: 0.1em;
|
|
802
|
+
text-transform: uppercase;
|
|
803
|
+
transition: color 0.2s ease;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
.footer-links a:hover {
|
|
807
|
+
color: var(--accent-light);
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
/* ========== Responsive ========== */
|
|
811
|
+
@media (min-width: 769px) {
|
|
812
|
+
.steps-connector {
|
|
813
|
+
display: block;
|
|
814
|
+
position: absolute;
|
|
815
|
+
top: 40px;
|
|
816
|
+
left: 10%;
|
|
817
|
+
width: 80%;
|
|
818
|
+
height: 1px;
|
|
819
|
+
background: linear-gradient(to right, transparent, var(--border-visible), transparent);
|
|
820
|
+
z-index: -1;
|
|
525
821
|
}
|
|
822
|
+
}
|
|
526
823
|
|
|
527
|
-
|
|
528
|
-
|
|
824
|
+
@media (max-width: 768px) {
|
|
825
|
+
.container { padding: 0 20px; }
|
|
826
|
+
|
|
827
|
+
.hero {
|
|
828
|
+
padding: 120px 0 30px;
|
|
529
829
|
}
|
|
530
830
|
|
|
531
|
-
.
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
font-size: 0.85rem;
|
|
831
|
+
.hero h1 {
|
|
832
|
+
font-size: 2.2rem;
|
|
833
|
+
line-height: 1;
|
|
535
834
|
}
|
|
536
835
|
|
|
537
836
|
.hero-buttons {
|
|
538
837
|
flex-direction: column;
|
|
539
838
|
align-items: center;
|
|
839
|
+
margin-bottom: 48px;
|
|
540
840
|
}
|
|
541
841
|
|
|
542
|
-
.btn-primary {
|
|
543
|
-
width:
|
|
842
|
+
.btn-primary, .btn-secondary {
|
|
843
|
+
width: 260px;
|
|
844
|
+
text-align: center;
|
|
544
845
|
}
|
|
545
846
|
|
|
546
|
-
.
|
|
847
|
+
.terminal-visual-inner {
|
|
848
|
+
padding: 20px;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
.terminal-visual-mockups {
|
|
547
852
|
flex-direction: column;
|
|
853
|
+
gap: 20px;
|
|
548
854
|
}
|
|
549
855
|
|
|
550
|
-
.
|
|
551
|
-
|
|
856
|
+
.mock-phone {
|
|
857
|
+
width: 180px;
|
|
858
|
+
min-height: 300px;
|
|
859
|
+
align-self: center;
|
|
552
860
|
}
|
|
553
861
|
|
|
554
|
-
.
|
|
555
|
-
|
|
862
|
+
.mock-terminal {
|
|
863
|
+
min-height: 140px;
|
|
864
|
+
font-size: 0.75rem;
|
|
556
865
|
}
|
|
557
866
|
|
|
558
867
|
.section-title {
|
|
559
868
|
font-size: 1.5rem;
|
|
560
869
|
}
|
|
561
870
|
|
|
562
|
-
.
|
|
563
|
-
|
|
871
|
+
.steps {
|
|
872
|
+
grid-template-columns: 1fr;
|
|
873
|
+
gap: 40px;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
.benefit-grid {
|
|
877
|
+
grid-template-columns: 1fr;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
.comparison-grid {
|
|
881
|
+
grid-template-columns: 1fr;
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
.comparison-card {
|
|
885
|
+
padding: 28px;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
.header-right .nav-links {
|
|
889
|
+
display: none;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
.footer-inner {
|
|
893
|
+
flex-direction: column;
|
|
894
|
+
gap: 16px;
|
|
895
|
+
text-align: center;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
.benefits, .why-section, .use-cases, .privacy-section,
|
|
899
|
+
.how-it-works, .comparison, .footer-cta {
|
|
900
|
+
padding: 80px 0;
|
|
564
901
|
}
|
|
565
902
|
}
|
|
566
903
|
|
|
567
|
-
/*
|
|
904
|
+
/* ========== Animations ========== */
|
|
568
905
|
@keyframes fadeIn {
|
|
569
|
-
from { opacity: 0; }
|
|
570
|
-
to { opacity: 1; }
|
|
906
|
+
from { opacity: 0; transform: translateY(12px); }
|
|
907
|
+
to { opacity: 1; transform: translateY(0); }
|
|
571
908
|
}
|
|
572
909
|
|
|
573
910
|
.hero {
|
|
574
|
-
animation: fadeIn 0.
|
|
911
|
+
animation: fadeIn 0.5s ease-out;
|
|
575
912
|
}
|
|
576
913
|
</style>
|
|
577
914
|
</head>
|
|
578
915
|
<body>
|
|
579
916
|
<header>
|
|
580
|
-
<
|
|
581
|
-
<div class="logo"
|
|
582
|
-
<
|
|
583
|
-
|
|
917
|
+
<div class="container">
|
|
918
|
+
<div class="logo">>shell-mirror</div>
|
|
919
|
+
<div class="header-right">
|
|
920
|
+
<div class="nav-links">
|
|
921
|
+
<a href="/privacy">Privacy</a>
|
|
922
|
+
<a href="/contact">Contact</a>
|
|
923
|
+
</div>
|
|
924
|
+
<div id="header-cta">
|
|
925
|
+
<button class="cta-button" onclick="handleGoogleLogin()">Get Started</button>
|
|
926
|
+
</div>
|
|
927
|
+
</div>
|
|
928
|
+
</div>
|
|
584
929
|
</header>
|
|
585
930
|
|
|
586
931
|
<main>
|
|
587
|
-
<!-- Hero
|
|
588
|
-
<section class="hero">
|
|
932
|
+
<!-- Hero -->
|
|
933
|
+
<section class="hero" data-section="hero">
|
|
934
|
+
<div class="hero-glow"></div>
|
|
589
935
|
<div class="container">
|
|
590
|
-
<h1>
|
|
591
|
-
<p>
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
<div class="setup-step">
|
|
599
|
-
<div class="step-number">1</div>
|
|
600
|
-
<div class="install-code">
|
|
601
|
-
<pre>npm install -g shell-mirror</pre>
|
|
602
|
-
<button class="copy-btn" onclick="copyToClipboard('npm install -g shell-mirror', this)" title="Copy to clipboard">
|
|
603
|
-
<svg width="16" height="16" fill="white" viewBox="0 0 16 16">
|
|
604
|
-
<path d="M4 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V2z"/>
|
|
605
|
-
<path d="M2 6a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2v-2H4a2 2 0 0 1-2-2V6z"/>
|
|
606
|
-
</svg>
|
|
607
|
-
</button>
|
|
608
|
-
</div>
|
|
609
|
-
</div>
|
|
936
|
+
<h1>Your terminal, <span class="accent-glow">on your phone.</span></h1>
|
|
937
|
+
<p class="hero-sub">Keep the same session running on your computer and open it on your phone when you leave the desk.</p>
|
|
938
|
+
<p class="hero-support">Works well for Claude Code, Gemini CLI, and anything else you run in a terminal.</p>
|
|
939
|
+
|
|
940
|
+
<div class="hero-buttons">
|
|
941
|
+
<button class="btn-primary" onclick="trackCTA('start_mirroring','hero'); handleGoogleLogin()">Start mirroring</button>
|
|
942
|
+
<a href="/how-it-works" class="btn-secondary" onclick="trackCTA('how_it_works','hero')">How it works</a>
|
|
943
|
+
</div>
|
|
610
944
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
945
|
+
<!-- Terminal + Phone Visual -->
|
|
946
|
+
<div class="terminal-visual">
|
|
947
|
+
<div class="terminal-visual-glow"></div>
|
|
948
|
+
<div class="terminal-visual-inner">
|
|
949
|
+
<div class="terminal-visual-mockups">
|
|
950
|
+
<!-- Desktop terminal -->
|
|
951
|
+
<div class="mock-desktop">
|
|
952
|
+
<div class="mock-titlebar">
|
|
953
|
+
<div class="mock-dot red"></div>
|
|
954
|
+
<div class="mock-dot yellow"></div>
|
|
955
|
+
<div class="mock-dot green"></div>
|
|
956
|
+
</div>
|
|
957
|
+
<div class="mock-terminal">
|
|
958
|
+
<div><span class="mock-prompt">➜</span> <span class="mock-path">~/projects/app</span> <span class="mock-cmd">git status</span></div>
|
|
959
|
+
<div class="mock-output">On branch main</div>
|
|
960
|
+
<div class="mock-output">Changes not staged for commit:</div>
|
|
961
|
+
<div class="mock-modified"> modified: src/engine.ts</div>
|
|
962
|
+
<div style="margin-top: 12px"><span class="mock-prompt">➜</span> <span class="mock-path">~/projects/app</span> <span class="mock-cursor"></span></div>
|
|
963
|
+
</div>
|
|
621
964
|
</div>
|
|
622
|
-
</div>
|
|
623
965
|
|
|
624
|
-
|
|
625
|
-
<div class="
|
|
626
|
-
|
|
627
|
-
<
|
|
628
|
-
<
|
|
629
|
-
<
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
966
|
+
<!-- Phone mirror -->
|
|
967
|
+
<div class="mock-phone">
|
|
968
|
+
<div class="mock-notch"><div class="mock-notch-pill"></div></div>
|
|
969
|
+
<div class="mock-phone-header">
|
|
970
|
+
<span>>SHELL-MIRROR CONNECTED</span>
|
|
971
|
+
<span class="material-symbols-outlined" style="font-size: 12px; font-variation-settings: 'FILL' 1;">sensors</span>
|
|
972
|
+
</div>
|
|
973
|
+
<div class="mock-phone-terminal">
|
|
974
|
+
<div><span class="mock-prompt">➜</span> <span class="mock-path">~/projects/app</span> <span class="mock-cmd">git status</span></div>
|
|
975
|
+
<div class="mock-output">On branch main</div>
|
|
976
|
+
<div class="mock-output">Changes not staged...</div>
|
|
977
|
+
<div class="mock-modified"> modified: src/engine.ts</div>
|
|
978
|
+
</div>
|
|
979
|
+
</div>
|
|
980
|
+
</div>
|
|
981
|
+
<!-- Clarifying line — part of the visual -->
|
|
982
|
+
<div class="clarifying-line">
|
|
983
|
+
<p>Not a separate agent view. Not a reduced control panel. >shell-mirror shows the terminal session you already have.</p>
|
|
635
984
|
</div>
|
|
636
985
|
</div>
|
|
637
|
-
|
|
638
|
-
<p style="text-align: center; margin-top: 30px;">
|
|
639
|
-
<a href="#how-it-works" class="btn-secondary">Learn More</a>
|
|
640
|
-
</p>
|
|
641
986
|
</div>
|
|
642
987
|
</section>
|
|
643
988
|
|
|
644
|
-
<!--
|
|
645
|
-
<section class="
|
|
989
|
+
<!-- Benefits -->
|
|
990
|
+
<section class="benefits" data-section="benefits">
|
|
646
991
|
<div class="container">
|
|
647
|
-
<
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
<div class="step-icon">1</div>
|
|
652
|
-
<h3>Secure Login</h3>
|
|
653
|
-
<p>Sign in with your Google account. Your credentials are encrypted and secure.</p>
|
|
992
|
+
<div class="benefit-grid">
|
|
993
|
+
<div class="glass-card benefit-block" style="background-image: url(/images/same_session.png)">
|
|
994
|
+
<h3>Same session</h3>
|
|
995
|
+
<p>You do not start over on mobile. You continue the terminal that is already running.</p>
|
|
654
996
|
</div>
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
<
|
|
658
|
-
<h3>Cloud Terminal</h3>
|
|
659
|
-
<p>Access a cloud-based terminal environment with all your favorite command-line tools pre-installed.</p>
|
|
997
|
+
<div class="glass-card benefit-block" style="background-image: url(/images/real_terminal_view.png)">
|
|
998
|
+
<h3>Real terminal view</h3>
|
|
999
|
+
<p>What is on your terminal is what you see on your phone. Useful for long runs, logs, prompts, and command-line tools that do not fit into a simplified remote UI.</p>
|
|
660
1000
|
</div>
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
<
|
|
664
|
-
<h3>Any Device</h3>
|
|
665
|
-
<p>Use from your phone, tablet, or any web browser. Your terminal is always accessible.</p>
|
|
1001
|
+
<div class="glass-card benefit-block" style="background-image: url(/images/private_by_design.png)">
|
|
1002
|
+
<h3>Private by design</h3>
|
|
1003
|
+
<p>Your terminal stays on your own machine. Your phone connects to your session instead of replacing it with a separate mobile workflow.</p>
|
|
666
1004
|
</div>
|
|
667
1005
|
</div>
|
|
668
1006
|
</div>
|
|
669
1007
|
</section>
|
|
670
1008
|
|
|
671
|
-
<!--
|
|
672
|
-
<section class="
|
|
1009
|
+
<!-- Why This Exists -->
|
|
1010
|
+
<section class="why-section" data-section="why">
|
|
673
1011
|
<div class="container">
|
|
674
|
-
<h2 class="section-title">
|
|
675
|
-
<
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
<div class="security-flow">
|
|
680
|
-
<div class="security-step">
|
|
681
|
-
<h4>Your Device</h4>
|
|
682
|
-
<p>Any web browser</p>
|
|
683
|
-
</div>
|
|
684
|
-
<div class="arrow">→</div>
|
|
685
|
-
<div class="security-step">
|
|
686
|
-
<h4>Secure Login</h4>
|
|
687
|
-
<p>Google OAuth 2.0</p>
|
|
688
|
-
</div>
|
|
689
|
-
<div class="arrow">→</div>
|
|
690
|
-
<div class="security-step">
|
|
691
|
-
<h4>Cloud Terminal</h4>
|
|
692
|
-
<p>Instant access</p>
|
|
693
|
-
</div>
|
|
694
|
-
</div>
|
|
695
|
-
|
|
696
|
-
<div style="text-align: center; margin-top: 40px;">
|
|
697
|
-
<p style="color: var(--text-muted); font-size: 0.9rem; line-height: 1.8;">
|
|
698
|
-
Encrypted connections (HTTPS/WSS)<br>
|
|
699
|
-
Google-grade authentication<br>
|
|
700
|
-
Session-based security<br>
|
|
701
|
-
No local installation required
|
|
702
|
-
</p>
|
|
1012
|
+
<h2 class="section-title">Remote control is useful. Sometimes you want the real thing.</h2>
|
|
1013
|
+
<div class="why-content">
|
|
1014
|
+
<p>A lot of tools now let you check or steer a coding session from your phone. That is useful until you need the actual terminal: the real output, the real prompt, the real state, the real tools.</p>
|
|
1015
|
+
<p>>shell-mirror is for that. It gives you a simple way to carry your existing terminal session with you instead of switching to a reduced version of it.</p>
|
|
703
1016
|
</div>
|
|
704
1017
|
</div>
|
|
705
1018
|
</section>
|
|
706
1019
|
|
|
707
1020
|
<!-- Use Cases -->
|
|
708
|
-
<section class="use-cases"
|
|
1021
|
+
<section class="use-cases" data-section="use_cases">
|
|
709
1022
|
<div class="container">
|
|
710
|
-
<h2 class="section-title">
|
|
711
|
-
|
|
1023
|
+
<h2 class="section-title">Good when you need to</h2>
|
|
712
1024
|
<div class="use-case-grid">
|
|
713
|
-
<div class="use-case">
|
|
714
|
-
<
|
|
715
|
-
<
|
|
1025
|
+
<div class="use-case-item">
|
|
1026
|
+
<div class="use-case-icon"><span class="material-symbols-outlined">smart_toy</span></div>
|
|
1027
|
+
<span>Check on Claude Code while away from the desk</span>
|
|
716
1028
|
</div>
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
<
|
|
720
|
-
<p>Use Gemini CLI from your phone. Access Google's AI tools with your own Google account and API access.</p>
|
|
1029
|
+
<div class="use-case-item">
|
|
1030
|
+
<div class="use-case-icon"><span class="material-symbols-outlined">code</span></div>
|
|
1031
|
+
<span>Continue a Gemini CLI session without restarting it</span>
|
|
721
1032
|
</div>
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
<
|
|
725
|
-
<p>Git, npm, pip, Docker, SSH - all your usual command-line tools work normally from your phone.</p>
|
|
1033
|
+
<div class="use-case-item">
|
|
1034
|
+
<div class="use-case-icon"><span class="material-symbols-outlined">monitoring</span></div>
|
|
1035
|
+
<span>Watch logs, builds, installs, or long commands</span>
|
|
726
1036
|
</div>
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
<
|
|
730
|
-
<p>Fix bugs, check logs, or deploy code from your phone. Full access to your development environment.</p>
|
|
1037
|
+
<div class="use-case-item">
|
|
1038
|
+
<div class="use-case-icon"><span class="material-symbols-outlined">content_copy</span></div>
|
|
1039
|
+
<span>Copy output or send one more command on the go</span>
|
|
731
1040
|
</div>
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
<
|
|
735
|
-
<p>Code during commutes or away from your desk. Follow tutorials and practice programming from your phone.</p>
|
|
1041
|
+
<div class="use-case-item">
|
|
1042
|
+
<div class="use-case-icon"><span class="material-symbols-outlined">visibility</span></div>
|
|
1043
|
+
<span>Keep an eye on a machine without opening a full remote desktop setup</span>
|
|
736
1044
|
</div>
|
|
1045
|
+
</div>
|
|
1046
|
+
</div>
|
|
1047
|
+
</section>
|
|
737
1048
|
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
1049
|
+
<!-- Privacy / Locality -->
|
|
1050
|
+
<section class="privacy-section" data-section="privacy">
|
|
1051
|
+
<div class="container">
|
|
1052
|
+
<h2 class="section-title">Your terminal stays yours</h2>
|
|
1053
|
+
<div class="privacy-content">
|
|
1054
|
+
<p>>shell-mirror is a personal tool. It is meant to give you access to your own terminal session from your own phone.</p>
|
|
1055
|
+
<p>Your commands still run on your machine. Your files stay where they already are. The point is not to move your work somewhere else. The point is to keep your place.</p>
|
|
742
1056
|
</div>
|
|
743
1057
|
</div>
|
|
744
1058
|
</section>
|
|
745
1059
|
|
|
746
|
-
<!--
|
|
747
|
-
<section class="
|
|
1060
|
+
<!-- How It Works -->
|
|
1061
|
+
<section class="how-it-works" id="how-it-works" data-section="how_it_works">
|
|
748
1062
|
<div class="container">
|
|
749
|
-
<h2>
|
|
750
|
-
<
|
|
1063
|
+
<h2 class="section-title">How it works</h2>
|
|
1064
|
+
<div class="steps">
|
|
1065
|
+
<div class="steps-connector"></div>
|
|
1066
|
+
<div class="step">
|
|
1067
|
+
<div class="step-circle">
|
|
1068
|
+
<span class="step-num">1</span>
|
|
1069
|
+
<span class="material-symbols-outlined">terminal</span>
|
|
1070
|
+
</div>
|
|
1071
|
+
<h3>Start >shell-mirror on your computer</h3>
|
|
1072
|
+
<p>Install and run the agent where your terminal session is already going.</p>
|
|
1073
|
+
</div>
|
|
1074
|
+
<div class="step">
|
|
1075
|
+
<div class="step-circle">
|
|
1076
|
+
<span class="step-num">2</span>
|
|
1077
|
+
<span class="material-symbols-outlined">login</span>
|
|
1078
|
+
</div>
|
|
1079
|
+
<h3>Sign in</h3>
|
|
1080
|
+
<p>Connect your phone and computer to the same session with your Google account.</p>
|
|
1081
|
+
</div>
|
|
1082
|
+
<div class="step">
|
|
1083
|
+
<div class="step-circle">
|
|
1084
|
+
<span class="step-num">3</span>
|
|
1085
|
+
<span class="material-symbols-outlined">smartphone</span>
|
|
1086
|
+
</div>
|
|
1087
|
+
<h3>Open your session on your phone</h3>
|
|
1088
|
+
<p>Pick up where you left off. Same terminal, same output, same state.</p>
|
|
1089
|
+
</div>
|
|
1090
|
+
</div>
|
|
1091
|
+
<p class="steps-closing">That's it.</p>
|
|
1092
|
+
</div>
|
|
1093
|
+
</section>
|
|
751
1094
|
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
1095
|
+
<!-- Comparison -->
|
|
1096
|
+
<section class="comparison" data-section="comparison">
|
|
1097
|
+
<div class="container">
|
|
1098
|
+
<h2 class="section-title">Why people use this instead of a built-in remote mode</h2>
|
|
1099
|
+
<div class="glass-card comparison-card">
|
|
1100
|
+
<div class="comparison-card-glow"></div>
|
|
1101
|
+
<p>Built-in remote tools can be fine for narrow workflows. >shell-mirror is better when you want access to the terminal itself, not just a product-specific control layer.</p>
|
|
1102
|
+
<div class="comparison-grid">
|
|
1103
|
+
<div class="comparison-item">
|
|
1104
|
+
<span class="material-symbols-outlined">check_circle</span>
|
|
1105
|
+
<p><strong>Same session</strong>The same terminal session, not a separate mobile workflow</p>
|
|
1106
|
+
</div>
|
|
1107
|
+
<div class="comparison-item">
|
|
1108
|
+
<span class="material-symbols-outlined">check_circle</span>
|
|
1109
|
+
<p><strong>Multiple tools</strong>Support for more than one CLI tool</p>
|
|
1110
|
+
</div>
|
|
1111
|
+
<div class="comparison-item">
|
|
1112
|
+
<span class="material-symbols-outlined">check_circle</span>
|
|
1113
|
+
<p><strong>Personal setup</strong>A personal setup tied to your own machine</p>
|
|
1114
|
+
</div>
|
|
1115
|
+
<div class="comparison-item">
|
|
1116
|
+
<span class="material-symbols-outlined">check_circle</span>
|
|
1117
|
+
<p><strong>Direct access</strong>Less abstraction between you and the shell</p>
|
|
1118
|
+
</div>
|
|
1119
|
+
</div>
|
|
755
1120
|
</div>
|
|
756
1121
|
</div>
|
|
757
1122
|
</section>
|
|
758
1123
|
|
|
759
|
-
<!--
|
|
760
|
-
<
|
|
1124
|
+
<!-- Final CTA -->
|
|
1125
|
+
<section class="footer-cta" id="get-started" data-section="final_cta">
|
|
1126
|
+
<div class="footer-cta-glow"></div>
|
|
761
1127
|
<div class="container">
|
|
762
|
-
<
|
|
1128
|
+
<h2>Take your terminal with you</h2>
|
|
1129
|
+
<p>Leave the desk without losing the session.</p>
|
|
1130
|
+
<button class="btn-primary" onclick="trackCTA('start_mirroring','footer_cta'); handleGoogleLogin()">Start mirroring</button>
|
|
1131
|
+
</div>
|
|
1132
|
+
</section>
|
|
1133
|
+
|
|
1134
|
+
<!-- Footer -->
|
|
1135
|
+
<footer>
|
|
1136
|
+
<div class="container footer-inner">
|
|
1137
|
+
<div class="footer-brand" id="version-info">>shell-mirror</div>
|
|
1138
|
+
<div class="footer-links">
|
|
1139
|
+
<a href="/how-it-works">How it works</a>
|
|
1140
|
+
<a href="/privacy">Privacy</a>
|
|
1141
|
+
<a href="/contact">Contact</a>
|
|
1142
|
+
</div>
|
|
763
1143
|
</div>
|
|
764
1144
|
</footer>
|
|
765
1145
|
</main>
|
|
766
1146
|
|
|
767
|
-
|
|
768
1147
|
<script>
|
|
769
|
-
//
|
|
770
|
-
function copyToClipboard(text, button) {
|
|
771
|
-
navigator.clipboard.writeText(text).then(() => {
|
|
772
|
-
// Show feedback
|
|
773
|
-
const originalHTML = button.innerHTML;
|
|
774
|
-
button.innerHTML = '<span style="font-size: 0.9rem;">✓</span>';
|
|
775
|
-
button.style.background = 'rgba(0, 255, 136, 0.3)';
|
|
776
|
-
|
|
777
|
-
setTimeout(() => {
|
|
778
|
-
button.innerHTML = originalHTML;
|
|
779
|
-
button.style.background = 'rgba(255, 255, 255, 0.1)';
|
|
780
|
-
}, 2000);
|
|
781
|
-
}).catch(err => {
|
|
782
|
-
console.error('Failed to copy:', err);
|
|
783
|
-
});
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
// Check authentication status without auto-redirect
|
|
1148
|
+
// ========== Core functions ==========
|
|
787
1149
|
async function checkAuthStatus() {
|
|
788
1150
|
try {
|
|
789
1151
|
const response = await fetch('/php-backend/api/auth-status.php');
|
|
790
1152
|
const data = await response.json();
|
|
791
|
-
|
|
792
1153
|
if (data.success && data.data && data.data.authenticated) {
|
|
793
1154
|
return { isAuthenticated: true, user: data.data.user };
|
|
794
1155
|
}
|
|
@@ -798,155 +1159,133 @@
|
|
|
798
1159
|
return { isAuthenticated: false, user: null };
|
|
799
1160
|
}
|
|
800
1161
|
|
|
801
|
-
// Handle Google login - direct web OAuth
|
|
802
1162
|
async function handleGoogleLogin() {
|
|
803
|
-
console.log('🔍 [DEBUG] Login button clicked');
|
|
804
|
-
|
|
805
|
-
// Track login attempt in Google Analytics
|
|
806
|
-
sendGAEvent('login_attempt', {
|
|
807
|
-
event_category: 'authentication',
|
|
808
|
-
event_label: 'google_oauth'
|
|
809
|
-
});
|
|
810
|
-
|
|
811
|
-
// Direct OAuth flow using the web backend
|
|
812
1163
|
window.location.href = '/php-backend/api/auth-login.php?return=' + encodeURIComponent('/app/dashboard');
|
|
813
1164
|
}
|
|
814
1165
|
|
|
815
|
-
// Handle dashboard navigation
|
|
816
1166
|
async function openDashboard() {
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
// Track dashboard access in Google Analytics
|
|
820
|
-
sendGAEvent('dashboard_access', {
|
|
821
|
-
event_category: 'navigation',
|
|
822
|
-
event_label: 'from_landing_page'
|
|
823
|
-
});
|
|
824
|
-
|
|
1167
|
+
trackCTA('open_dashboard', 'authenticated');
|
|
825
1168
|
window.location.href = '/app/dashboard.html';
|
|
826
1169
|
}
|
|
827
1170
|
|
|
828
|
-
// Load version info
|
|
829
1171
|
async function loadVersionInfo() {
|
|
830
1172
|
try {
|
|
831
1173
|
const response = await fetch('/build-info.json');
|
|
832
1174
|
const buildInfo = await response.json();
|
|
833
|
-
const
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
const buildDate = new Date(buildInfo.buildTime).toLocaleDateString();
|
|
837
|
-
versionElement.textContent = `Shell Mirror v${buildInfo.version}`;
|
|
838
|
-
}
|
|
839
|
-
} catch (error) {
|
|
840
|
-
console.log('Could not load build info:', error);
|
|
841
|
-
}
|
|
1175
|
+
const el = document.getElementById('version-info');
|
|
1176
|
+
if (el && buildInfo) el.textContent = `>shell-mirror v${buildInfo.version}`.toUpperCase();
|
|
1177
|
+
} catch (error) {}
|
|
842
1178
|
}
|
|
843
1179
|
|
|
844
|
-
//
|
|
1180
|
+
// ========== Analytics helpers ==========
|
|
845
1181
|
function sendGAEvent(eventName, eventParams) {
|
|
846
|
-
if (typeof gtag === 'function') {
|
|
847
|
-
|
|
848
|
-
gtag('event', eventName, eventParams);
|
|
849
|
-
return true;
|
|
850
|
-
} else {
|
|
851
|
-
console.warn('❌ [GA] gtag not available, event not sent:', eventName);
|
|
852
|
-
return false;
|
|
853
|
-
}
|
|
1182
|
+
if (typeof gtag === 'function') { gtag('event', eventName, eventParams); return true; }
|
|
1183
|
+
return false;
|
|
854
1184
|
}
|
|
855
1185
|
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
page_title:
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
1186
|
+
function trackCTA(label, location) {
|
|
1187
|
+
sendGAEvent('cta_click', { cta_label: label, cta_location: location });
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
// ========== Scroll depth tracking ==========
|
|
1191
|
+
const scrollFired = {};
|
|
1192
|
+
function checkScrollDepth() {
|
|
1193
|
+
const pct = Math.round((window.scrollY + window.innerHeight) / document.body.scrollHeight * 100);
|
|
1194
|
+
[25, 50, 75, 100].forEach(threshold => {
|
|
1195
|
+
if (pct >= threshold && !scrollFired[threshold]) {
|
|
1196
|
+
scrollFired[threshold] = true;
|
|
1197
|
+
sendGAEvent('scroll_depth', { scroll_percent: threshold, page_title: document.title });
|
|
1198
|
+
}
|
|
1199
|
+
});
|
|
1200
|
+
}
|
|
1201
|
+
window.addEventListener('scroll', checkScrollDepth, { passive: true });
|
|
1202
|
+
|
|
1203
|
+
// ========== Section visibility tracking ==========
|
|
1204
|
+
const sectionObserver = new IntersectionObserver((entries) => {
|
|
1205
|
+
entries.forEach(entry => {
|
|
1206
|
+
if (entry.isIntersecting && entry.target.dataset.section) {
|
|
1207
|
+
sendGAEvent('section_visible', { section_name: entry.target.dataset.section });
|
|
1208
|
+
sectionObserver.unobserve(entry.target);
|
|
1209
|
+
}
|
|
1210
|
+
});
|
|
1211
|
+
}, { threshold: 0.3 });
|
|
1212
|
+
|
|
1213
|
+
// ========== Time on page ==========
|
|
1214
|
+
const pageLoadTime = Date.now();
|
|
1215
|
+
window.addEventListener('beforeunload', () => {
|
|
1216
|
+
const seconds = Math.round((Date.now() - pageLoadTime) / 1000);
|
|
1217
|
+
const maxScroll = Math.max(...Object.keys(scrollFired).map(Number), 0);
|
|
1218
|
+
sendGAEvent('time_on_page', {
|
|
1219
|
+
seconds_on_page: seconds,
|
|
1220
|
+
page_title: document.title,
|
|
1221
|
+
max_scroll_percent: maxScroll
|
|
1222
|
+
});
|
|
874
1223
|
});
|
|
875
1224
|
|
|
876
|
-
//
|
|
1225
|
+
// ========== Auth-aware header ==========
|
|
877
1226
|
async function updateHeaderAndCTA() {
|
|
878
1227
|
const authStatus = await checkAuthStatus();
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
const headerNav = document.querySelector('nav');
|
|
1228
|
+
const headerCta = document.getElementById('header-cta');
|
|
1229
|
+
|
|
882
1230
|
if (authStatus.isAuthenticated) {
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
<
|
|
886
|
-
<div style="display: flex; align-items: center; gap: 15px;">
|
|
887
|
-
<span style="color: white; opacity: 0.9;">Welcome, ${authStatus.user.name || authStatus.user.email}</span>
|
|
888
|
-
<a href="/app/dashboard.html" class="cta-button">Dashboard</a>
|
|
889
|
-
</div>
|
|
890
|
-
`;
|
|
891
|
-
} else {
|
|
892
|
-
// Show sign in option
|
|
893
|
-
headerNav.innerHTML = `
|
|
894
|
-
<div class="logo">Shell Mirror</div>
|
|
895
|
-
<button class="cta-button" onclick="handleGoogleLogin()">Sign In</button>
|
|
1231
|
+
headerCta.innerHTML = `
|
|
1232
|
+
<span style="color: var(--text-secondary); font-size: 0.85rem;">Welcome, ${authStatus.user.name || authStatus.user.email}</span>
|
|
1233
|
+
<a href="/app/dashboard.html" class="cta-button">Dashboard</a>
|
|
896
1234
|
`;
|
|
897
|
-
|
|
1235
|
+
headerCta.style.display = 'flex';
|
|
1236
|
+
headerCta.style.alignItems = 'center';
|
|
1237
|
+
headerCta.style.gap = '15px';
|
|
898
1238
|
|
|
899
|
-
|
|
900
|
-
const primaryButtons = document.querySelectorAll('.btn-primary');
|
|
901
|
-
primaryButtons.forEach(button => {
|
|
902
|
-
if (authStatus.isAuthenticated) {
|
|
1239
|
+
document.querySelectorAll('.btn-primary').forEach(button => {
|
|
903
1240
|
button.textContent = 'Open Dashboard';
|
|
904
1241
|
button.onclick = openDashboard;
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
// Update the Google login button in step 3 for authenticated users
|
|
909
|
-
const googleButton = document.querySelector('.btn-google');
|
|
910
|
-
if (googleButton && authStatus.isAuthenticated) {
|
|
911
|
-
googleButton.innerHTML = 'Enter Dashboard';
|
|
912
|
-
googleButton.onclick = (e) => {
|
|
913
|
-
e.preventDefault();
|
|
914
|
-
openDashboard();
|
|
915
|
-
};
|
|
916
|
-
googleButton.style.background = 'var(--accent)';
|
|
917
|
-
googleButton.style.color = 'white';
|
|
918
|
-
googleButton.style.border = 'none';
|
|
1242
|
+
});
|
|
1243
|
+
} else {
|
|
1244
|
+
headerCta.innerHTML = '<button class="cta-button" onclick="trackCTA(\'sign_in\',\'header\'); handleGoogleLogin()">Sign In</button>';
|
|
919
1245
|
}
|
|
920
1246
|
}
|
|
921
1247
|
|
|
1248
|
+
// ========== Init ==========
|
|
1249
|
+
document.addEventListener('DOMContentLoaded', async () => {
|
|
1250
|
+
// Page view
|
|
1251
|
+
setTimeout(() => {
|
|
1252
|
+
sendGAEvent('page_view', { page_title: '>shell-mirror Landing', page_location: window.location.href });
|
|
1253
|
+
}, 1000);
|
|
1254
|
+
|
|
1255
|
+
await updateHeaderAndCTA();
|
|
1256
|
+
loadVersionInfo();
|
|
1257
|
+
|
|
1258
|
+
// Start section visibility tracking
|
|
1259
|
+
document.querySelectorAll('[data-section]').forEach(el => sectionObserver.observe(el));
|
|
1260
|
+
|
|
1261
|
+
// Check initial scroll position (if page loaded scrolled)
|
|
1262
|
+
checkScrollDepth();
|
|
1263
|
+
});
|
|
1264
|
+
|
|
922
1265
|
// Smooth scrolling for anchor links
|
|
923
1266
|
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
|
924
1267
|
anchor.addEventListener('click', function (e) {
|
|
925
1268
|
e.preventDefault();
|
|
926
|
-
document.querySelector(this.getAttribute('href'))
|
|
927
|
-
|
|
928
|
-
});
|
|
1269
|
+
const target = document.querySelector(this.getAttribute('href'));
|
|
1270
|
+
if (target) target.scrollIntoView({ behavior: 'smooth' });
|
|
929
1271
|
});
|
|
930
1272
|
});
|
|
931
1273
|
|
|
932
|
-
//
|
|
933
|
-
const
|
|
934
|
-
threshold: 0.1,
|
|
935
|
-
rootMargin: '0px 0px -20px 0px'
|
|
936
|
-
};
|
|
937
|
-
|
|
938
|
-
const observer = new IntersectionObserver((entries) => {
|
|
1274
|
+
// Fade-in animations
|
|
1275
|
+
const fadeObserver = new IntersectionObserver((entries) => {
|
|
939
1276
|
entries.forEach(entry => {
|
|
940
1277
|
if (entry.isIntersecting) {
|
|
941
1278
|
entry.target.style.opacity = '1';
|
|
1279
|
+
entry.target.style.transform = 'translateY(0)';
|
|
942
1280
|
}
|
|
943
1281
|
});
|
|
944
|
-
},
|
|
1282
|
+
}, { threshold: 0.1, rootMargin: '0px 0px -20px 0px' });
|
|
945
1283
|
|
|
946
|
-
document.querySelectorAll('.step, .use-case').forEach(el => {
|
|
1284
|
+
document.querySelectorAll('.benefit-block, .step, .use-case-item, .comparison-item').forEach(el => {
|
|
947
1285
|
el.style.opacity = '0';
|
|
948
|
-
el.style.
|
|
949
|
-
|
|
1286
|
+
el.style.transform = 'translateY(12px)';
|
|
1287
|
+
el.style.transition = 'opacity 0.4s ease, transform 0.4s ease';
|
|
1288
|
+
fadeObserver.observe(el);
|
|
950
1289
|
});
|
|
951
1290
|
</script>
|
|
952
1291
|
</body>
|