shell-mirror 1.5.131 → 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/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
- <title>Shell Mirror - Mirror your Mac terminal to your phone</title>
7
- <meta name="description" content="Mirror your Mac terminal to your phone. Continue your Claude Code or Gemini CLI session on your phone or iPad while on the go.">
8
- <meta name="keywords" content="mobile coding, remote shell, Claude Code mobile, Gemini CLI phone, Mac shell browser, secure shell sharing">
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="Shell Mirror - Mirror your Mac terminal to your phone">
13
- <meta property="og:description" content="Mirror your Mac terminal to your phone. Continue your Claude Code or Gemini CLI session on your phone or iPad while on the go.">
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="Shell Mirror - Mirror your Mac terminal to your phone">
19
- <meta property="twitter:description" content="Mirror your Mac terminal to your phone. Continue your Claude Code or Gemini CLI session on your phone or iPad while on the go.">
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
- console.log('✅ Google Analytics script loaded successfully');
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: #0a0b0d;
58
- --bg-secondary: #141519;
59
- --bg-tertiary: #1a1b20;
60
- --bg-hover: #22232a;
61
- --text-primary: #ffffff;
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: #5d5fef;
65
- --accent-hover: #4a4cd6;
62
+ --accent: #7c4dff;
63
+ --accent-light: #cdbdff;
64
+ --accent-hover: #6833ea;
66
65
  --success: #00c853;
67
- --border: #2a2b30;
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 20px;
88
+ padding: 0 32px;
88
89
  }
89
90
 
90
- /* Header */
91
+ /* ========== Header ========== */
91
92
  header {
92
- padding: 16px 0;
93
- position: relative;
93
+ position: fixed;
94
+ top: 0;
95
+ width: 100%;
94
96
  z-index: 100;
95
- background: var(--bg-secondary);
96
- border-bottom: 1px solid var(--border);
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
- nav {
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.2rem;
107
- font-weight: 600;
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 20px;
145
+ padding: 10px 22px;
115
146
  text-decoration: none;
116
- border-radius: 6px;
117
- font-weight: 500;
147
+ border-radius: 8px;
148
+ font-weight: 600;
118
149
  border: none;
119
- transition: all 0.15s ease;
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 Section */
161
+ /* ========== Hero ========== */
127
162
  .hero {
128
163
  text-align: center;
129
- padding: 60px 0 80px;
130
- color: var(--text-primary);
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(2rem, 4vw, 3rem);
135
- font-weight: 600;
136
- margin-bottom: 16px;
137
- line-height: 1.2;
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 p {
141
- font-size: clamp(1rem, 1.5vw, 1.1rem);
142
- margin-bottom: 40px;
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: 60px;
219
+ margin-bottom: 80px;
155
220
  }
156
221
 
157
222
  .btn-primary {
158
- background: var(--accent);
159
- color: white;
160
- padding: 14px 28px;
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: 6px;
163
- font-weight: 500;
227
+ border-radius: 8px;
228
+ font-weight: 700;
164
229
  font-size: 1rem;
165
- transition: all 0.15s ease;
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
- background: var(--accent-hover);
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: transparent;
243
+ background: var(--bg-tertiary);
175
244
  color: var(--text-primary);
176
- padding: 14px 28px;
245
+ padding: 16px 36px;
177
246
  text-decoration: none;
178
- border-radius: 6px;
179
- font-weight: 500;
247
+ border-radius: 8px;
248
+ font-weight: 600;
180
249
  font-size: 1rem;
181
- border: 1px solid var(--border);
182
- transition: all 0.15s ease;
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
- /* Setup Steps */
191
- .setup-steps {
192
- margin: 40px auto;
193
- max-width: 600px;
194
- display: flex;
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
- .setup-step {
200
- display: flex;
201
- align-items: center;
202
- gap: 16px;
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
- .step-number {
206
- font-size: 1rem;
207
- font-weight: 600;
208
- color: var(--text-muted);
209
- min-width: 32px;
210
- height: 32px;
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
- /* Installation Code */
219
- .install-code {
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
- height: 56px;
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
- .install-code pre {
232
- color: var(--success);
233
- font-family: 'Monaco', 'Menlo', monospace;
234
- font-size: 0.95rem;
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
- .copy-btn {
241
- position: absolute;
242
- right: 12px;
243
- top: 50%;
244
- transform: translateY(-50%);
245
- background: var(--bg-hover);
246
- border: 1px solid var(--border);
247
- border-radius: 4px;
248
- padding: 6px 10px;
249
- color: var(--text-secondary);
250
- cursor: pointer;
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
- .copy-btn:hover {
256
- background: var(--accent);
257
- border-color: var(--accent);
258
- color: white;
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
- .copy-btn:active {
262
- transform: translateY(-50%) scale(0.95);
344
+ @keyframes blink {
345
+ 50% { opacity: 0; }
263
346
  }
264
347
 
265
- .copy-btn svg {
266
- display: block;
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
- /* Google Login Button */
270
- .btn-google {
271
- background: white;
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
- gap: 10px;
282
- transition: all 0.15s ease;
283
- cursor: pointer;
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
- height: 56px;
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
- .btn-google:hover {
289
- background: #f0f0f0;
402
+ /* ========== Clarifying line (inside terminal visual) ========== */
403
+ .clarifying-line {
404
+ text-align: center;
405
+ padding: 20px 32px 0;
290
406
  }
291
407
 
292
- .btn-google:active {
293
- transform: scale(0.98);
408
+ .clarifying-line p {
409
+ color: var(--text-muted);
410
+ font-size: 0.85rem;
411
+ font-style: italic;
294
412
  }
295
413
 
296
- /* Installation Modal */
297
- .install-modal {
298
- display: none;
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
- .install-modal.show {
311
- display: flex;
419
+ .benefit-grid {
420
+ display: grid;
421
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
422
+ gap: 24px;
312
423
  }
313
424
 
314
- .install-modal-content {
315
- background: var(--bg-secondary);
316
- padding: 24px;
317
- border-radius: 8px;
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
- max-width: 500px;
320
- margin: 20px;
321
- text-align: center;
322
- position: relative;
430
+ border-radius: 16px;
323
431
  }
324
432
 
325
- .install-modal-content h3 {
326
- color: var(--text-primary);
327
- margin-bottom: 16px;
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
- .install-modal-content p {
331
- color: var(--text-secondary);
332
- margin-bottom: 16px;
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
- .install-modal-content .install-code {
336
- background: var(--bg-tertiary);
337
- margin: 16px 0;
455
+ .benefit-block:hover {
456
+ transform: translateY(-6px);
338
457
  }
339
458
 
340
- .install-modal-content .install-code pre {
341
- color: var(--success);
459
+ .benefit-block h3,
460
+ .benefit-block p {
461
+ position: relative;
462
+ z-index: 1;
342
463
  }
343
464
 
344
- .close-modal {
345
- position: absolute;
346
- top: 10px;
347
- right: 15px;
348
- background: none;
349
- border: none;
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
- .close-modal:hover {
356
- color: var(--text-primary);
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
- /* How It Works */
360
- .how-it-works {
361
- background: var(--bg-secondary);
362
- padding: 80px 0;
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.75rem;
368
- font-weight: 600;
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
- .steps {
374
- display: grid;
375
- grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
376
- gap: 32px;
377
- margin-bottom: 48px;
495
+ .why-content {
496
+ max-width: 680px;
497
+ margin: 0 auto;
378
498
  }
379
499
 
380
- .step {
381
- text-align: center;
382
- padding: 24px 16px;
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
- .step-icon {
386
- width: 56px;
387
- height: 56px;
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
- margin: 0 auto 16px;
395
- font-size: 1.25rem;
396
- font-weight: 600;
397
- color: var(--text-secondary);
546
+ flex-shrink: 0;
398
547
  }
399
548
 
400
- .step h3 {
401
- font-size: 1.1rem;
402
- font-weight: 600;
403
- margin-bottom: 12px;
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
- .step p {
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
- line-height: 1.6;
410
- font-size: 0.95rem;
574
+ font-size: 1.05rem;
575
+ line-height: 1.8;
576
+ margin-bottom: 20px;
411
577
  }
412
578
 
413
- /* Security Section */
414
- .security {
415
- background: var(--bg-tertiary);
416
- padding: 80px 0;
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
- .security-flow {
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
- gap: 24px;
424
- flex-wrap: wrap;
425
- margin: 40px 0;
613
+ margin: 0 auto 24px;
614
+ position: relative;
615
+ transition: border-color 0.4s ease;
426
616
  }
427
617
 
428
- .security-step {
429
- background: var(--bg-secondary);
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
- .security-step h4 {
438
- color: var(--accent);
439
- margin-bottom: 8px;
440
- font-size: 0.95rem;
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
- .security-step p {
655
+ .step p {
444
656
  color: var(--text-secondary);
445
- font-size: 0.85rem;
657
+ line-height: 1.6;
658
+ font-size: 0.9rem;
446
659
  }
447
660
 
448
- .arrow {
449
- font-size: 1.5rem;
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
- /* Use Cases */
454
- .use-cases {
455
- padding: 80px 0;
668
+ /* ========== Comparison ========== */
669
+ .comparison {
670
+ padding: 120px 0;
456
671
  background: var(--bg-secondary);
457
672
  }
458
673
 
459
- .use-case-grid {
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: repeat(auto-fit, minmax(300px, 1fr));
462
- gap: 24px;
703
+ grid-template-columns: 1fr 1fr;
704
+ gap: 20px 48px;
705
+ position: relative;
463
706
  }
464
707
 
465
- .use-case {
466
- background: var(--bg-tertiary);
467
- padding: 24px;
468
- border-radius: 6px;
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
- .use-case h3 {
473
- color: var(--text-primary);
474
- margin-bottom: 12px;
475
- font-size: 1rem;
476
- font-weight: 600;
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
- .use-case p {
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
- /* Footer CTA */
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
- background: var(--bg-primary);
487
- border-top: 1px solid var(--border);
488
- padding: 60px 0;
737
+ padding: 120px 0;
489
738
  text-align: center;
490
- color: var(--text-primary);
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: 1.75rem;
495
- font-weight: 600;
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: 32px;
763
+ font-size: 1.1rem;
764
+ margin-bottom: 40px;
502
765
  color: var(--text-secondary);
766
+ position: relative;
503
767
  }
504
768
 
505
- /* Responsive Design */
506
- @media (max-width: 768px) {
507
- .setup-steps {
508
- max-width: 95%;
509
- gap: 12px;
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
- .setup-step {
513
- gap: 12px;
514
- }
776
+ .footer-inner {
777
+ display: flex;
778
+ justify-content: space-between;
779
+ align-items: center;
780
+ }
515
781
 
516
- .step-number {
517
- min-width: 28px;
518
- height: 28px;
519
- font-size: 0.85rem;
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
- .install-code {
523
- height: 48px;
524
- padding: 12px 16px;
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
- .install-code pre {
528
- font-size: 0.85rem;
824
+ @media (max-width: 768px) {
825
+ .container { padding: 0 20px; }
826
+
827
+ .hero {
828
+ padding: 120px 0 30px;
529
829
  }
530
830
 
531
- .btn-google {
532
- height: 48px;
533
- padding: 12px 16px;
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: 240px;
842
+ .btn-primary, .btn-secondary {
843
+ width: 260px;
844
+ text-align: center;
544
845
  }
545
846
 
546
- .security-flow {
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
- .arrow {
551
- transform: rotate(90deg);
856
+ .mock-phone {
857
+ width: 180px;
858
+ min-height: 300px;
859
+ align-self: center;
552
860
  }
553
861
 
554
- .steps {
555
- grid-template-columns: 1fr;
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
- .hero h1 {
563
- font-size: 1.75rem;
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
- /* Subtle animations */
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.4s ease-out;
911
+ animation: fadeIn 0.5s ease-out;
575
912
  }
576
913
  </style>
577
914
  </head>
578
915
  <body>
579
916
  <header>
580
- <nav class="container">
581
- <div class="logo">Shell Mirror</div>
582
- <a href="/app" class="cta-button">Launch App</a>
583
- </nav>
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 Section -->
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>Mirror your Mac terminal<br>to your phone</h1>
591
- <p>Continue your Claude Code or Gemini CLI session on your phone or iPad while on the go.</p>
592
-
593
- <p style="text-align: center; color: var(--text-muted); font-size: 0.9rem; margin: 40px 0 24px; font-weight: 500; text-transform: uppercase; letter-spacing: 0.5px;">
594
- Quick Setup
595
- </p>
596
-
597
- <div class="setup-steps">
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
- <div class="setup-step">
612
- <div class="step-number">2</div>
613
- <div class="install-code">
614
- <pre>shell-mirror</pre>
615
- <button class="copy-btn" onclick="copyToClipboard('shell-mirror', this)" title="Copy to clipboard">
616
- <svg width="16" height="16" fill="white" viewBox="0 0 16 16">
617
- <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"/>
618
- <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"/>
619
- </svg>
620
- </button>
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">&nbsp;&nbsp;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
- <div class="setup-step">
625
- <div class="step-number">3</div>
626
- <button class="btn-google" onclick="handleGoogleLogin()">
627
- <svg width="20" height="20" viewBox="0 0 24 24">
628
- <path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/>
629
- <path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/>
630
- <path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
631
- <path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/>
632
- </svg>
633
- Login with Google
634
- </button>
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">&nbsp;&nbsp;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
- <!-- How It Works -->
645
- <section class="how-it-works" id="how-it-works">
989
+ <!-- Benefits -->
990
+ <section class="benefits" data-section="benefits">
646
991
  <div class="container">
647
- <h2 class="section-title">How Shell Mirror Works</h2>
648
-
649
- <div class="steps">
650
- <div class="step">
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
- <div class="step">
657
- <div class="step-icon">2</div>
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
- <div class="step">
663
- <div class="step-icon">3</div>
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
- <!-- Security -->
672
- <section class="security" id="security">
1009
+ <!-- Why This Exists -->
1010
+ <section class="why-section" data-section="why">
673
1011
  <div class="container">
674
- <h2 class="section-title">Secure & Reliable</h2>
675
- <p style="text-align: center; margin-bottom: 40px; color: var(--text-secondary); font-size: 0.95rem;">
676
- Enterprise-grade security with Google OAuth authentication.
677
- </p>
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" id="use-cases">
1021
+ <section class="use-cases" data-section="use_cases">
709
1022
  <div class="container">
710
- <h2 class="section-title">Use Cases</h2>
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
- <h3>Claude Code CLI</h3>
715
- <p>Use Claude Code CLI from your phone. Run AI-powered coding commands using your own Claude API account.</p>
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
- <div class="use-case">
719
- <h3>Gemini CLI</h3>
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
- <div class="use-case">
724
- <h3>Standard Tools</h3>
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
- <div class="use-case">
729
- <h3>Quick Fixes</h3>
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
- <div class="use-case">
734
- <h3>Mobile Development</h3>
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
- <div class="use-case">
739
- <h3>Personal Projects</h3>
740
- <p>Work on personal projects from anywhere. Your own computer, your own accounts, your own code.</p>
741
- </div>
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
- <!-- Footer CTA -->
747
- <section class="footer-cta" id="get-started">
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>Get Started</h2>
750
- <p>Access your terminal from anywhere</p>
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
- <div style="margin-top: 32px; display: flex; gap: 16px; justify-content: center; flex-wrap: wrap;">
753
- <button class="btn-primary" onclick="handleGoogleLogin()" style="padding: 16px 32px;">Start Now</button>
754
- <a href="https://github.com/karmalsky/shell-mirror" class="btn-secondary">View on GitHub</a>
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
- <!-- Version Footer -->
760
- <footer style="background: var(--bg-secondary); color: var(--text-muted); text-align: center; padding: 16px 0; font-size: 0.75rem; border-top: 1px solid var(--border);">
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
- <p id="version-info">Shell Mirror</p>
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
- // Copy to clipboard function
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
- console.log('🔍 [DEBUG] Dashboard button clicked');
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 versionElement = document.getElementById('version-info');
834
-
835
- if (versionElement && buildInfo) {
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
- // Google Analytics helper function
1180
+ // ========== Analytics helpers ==========
845
1181
  function sendGAEvent(eventName, eventParams) {
846
- if (typeof gtag === 'function') {
847
- console.log('📊 [GA] Sending event:', eventName, eventParams);
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
- // Initialize page on load
857
- document.addEventListener('DOMContentLoaded', async () => {
858
- // Wait a moment for GA script to load
859
- setTimeout(() => {
860
- console.log('🔍 [DEBUG] Checking Google Analytics setup...');
861
- console.log('🔍 [DEBUG] gtag function type:', typeof gtag);
862
- console.log('🔍 [DEBUG] dataLayer exists:', typeof window.dataLayer !== 'undefined');
863
- console.log('🔍 [DEBUG] gtagLoaded flag:', window.gtagLoaded);
864
-
865
- // Send test event
866
- sendGAEvent('page_view', {
867
- page_title: 'Shell Mirror Landing',
868
- page_location: window.location.href
869
- });
870
- }, 1000);
871
-
872
- await updateHeaderAndCTA();
873
- loadVersionInfo();
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
- // Update header and CTA based on auth status
1225
+ // ========== Auth-aware header ==========
877
1226
  async function updateHeaderAndCTA() {
878
1227
  const authStatus = await checkAuthStatus();
879
-
880
- // Update header navigation
881
- const headerNav = document.querySelector('nav');
1228
+ const headerCta = document.getElementById('header-cta');
1229
+
882
1230
  if (authStatus.isAuthenticated) {
883
- // Show user info + dashboard link
884
- headerNav.innerHTML = `
885
- <div class="logo">Shell Mirror</div>
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
- // Update main CTA buttons
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')).scrollIntoView({
927
- behavior: 'smooth'
928
- });
1269
+ const target = document.querySelector(this.getAttribute('href'));
1270
+ if (target) target.scrollIntoView({ behavior: 'smooth' });
929
1271
  });
930
1272
  });
931
1273
 
932
- // Subtle fade-in for sections
933
- const observerOptions = {
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
- }, observerOptions);
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.transition = 'opacity 0.3s ease';
949
- observer.observe(el);
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>