evaldoc 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/.env.staging.example +19 -0
  2. package/.firebaserc +6 -0
  3. package/.github/workflows/auto-merge-to-main.yml +28 -0
  4. package/.github/workflows/ci.yml +27 -0
  5. package/.github/workflows/npxhub-publish.yml +170 -0
  6. package/.prettierignore +4 -0
  7. package/.prettierrc.json +7 -0
  8. package/README.md +142 -0
  9. package/SRS.md +448 -0
  10. package/apphosting.staging.yaml +48 -0
  11. package/apphosting.yaml +50 -0
  12. package/bin/evaldoc.cjs +105 -0
  13. package/cors.json +8 -0
  14. package/docs/ARCHITECTURE.md +769 -0
  15. package/docs/ARCHITECTURE_SUMMARY.md +323 -0
  16. package/docs/DEPLOYMENT.md +86 -0
  17. package/docs/DEPLOYMENT_STEPS.md +373 -0
  18. package/docs/DEPLOY_FIRESTORE_RULES.md +239 -0
  19. package/docs/DEPLOY_STORAGE_RULES.md +82 -0
  20. package/docs/DOCTOR_TUTORIAL.md +467 -0
  21. package/docs/FIREBASE_STORAGE_CORS_FIX.md +131 -0
  22. package/docs/FIXES_APPLIED.md +128 -0
  23. package/docs/IMPLEMENTATION.md +498 -0
  24. package/docs/IMPLEMENTATION_COMPLETE.md +317 -0
  25. package/docs/LLM-SETUP.md +216 -0
  26. package/docs/MANUAL_TEST_GUIDE.md +327 -0
  27. package/docs/PATIENT_GUIDE.md +451 -0
  28. package/docs/PLATFORM_OVERVIEW.md +194 -0
  29. package/docs/QUICKSTART.md +252 -0
  30. package/docs/QUICK_REFERENCE.md +222 -0
  31. package/docs/READY_TO_TEST.md +383 -0
  32. package/docs/RUN.md +237 -0
  33. package/docs/START_TESTING.md +130 -0
  34. package/docs/STRIPE_CONNECT_SETUP.md +454 -0
  35. package/docs/SYSTEM_READY.md +345 -0
  36. package/docs/THREADS_IMPLEMENTATION_COMPLETE.md +431 -0
  37. package/docs/THREAD_IMPLEMENTATION_GUIDE.md +345 -0
  38. package/docs/firebasefiles.md +21 -0
  39. package/docs/homepage.md +1208 -0
  40. package/docs/payments.md +159 -0
  41. package/eslint.config.js +76 -0
  42. package/firebase.json +27 -0
  43. package/firestore.indexes.json +88 -0
  44. package/firestore.rules +125 -0
  45. package/functions/package-lock.json +2884 -0
  46. package/functions/package.json +20 -0
  47. package/functions/src/analytics.js +101 -0
  48. package/functions/src/audit.js +28 -0
  49. package/functions/src/auth.js +19 -0
  50. package/functions/src/drafts.js +128 -0
  51. package/functions/src/feedback.js +164 -0
  52. package/functions/src/firebase-init.js +29 -0
  53. package/functions/src/i18n.js +134 -0
  54. package/functions/src/limits.js +27 -0
  55. package/functions/src/llm.js +271 -0
  56. package/functions/src/ner.js +162 -0
  57. package/functions/src/notifications.js +273 -0
  58. package/functions/src/orgs.js +127 -0
  59. package/functions/src/patient-api.js +545 -0
  60. package/functions/src/payment.js +830 -0
  61. package/functions/src/safety.js +188 -0
  62. package/functions/src/stripe-config.js +33 -0
  63. package/functions/src/topics.js +94 -0
  64. package/functions/src/triage.js +191 -0
  65. package/functions/src/utils.js +28 -0
  66. package/functions/src/validate.js +177 -0
  67. package/functions/test-firebase.js +36 -0
  68. package/jest.config.js +18 -0
  69. package/package.json +52 -0
  70. package/public/404.html +93 -0
  71. package/public/app/analytics.html +336 -0
  72. package/public/app/analytics.js +177 -0
  73. package/public/app/app.css +1400 -0
  74. package/public/app/app.js +1754 -0
  75. package/public/app/config.js +14 -0
  76. package/public/app/inbox-threads.js +843 -0
  77. package/public/app/inbox.html +598 -0
  78. package/public/app/inbox.js +397 -0
  79. package/public/app/index.html +612 -0
  80. package/public/assets/logo.jpg +0 -0
  81. package/public/chat.html +137 -0
  82. package/public/css/chat.css +870 -0
  83. package/public/css/landing-enhance.css +298 -0
  84. package/public/css/styles.css +1198 -0
  85. package/public/favicon.svg +5 -0
  86. package/public/find-doctor.html +220 -0
  87. package/public/index.html +399 -0
  88. package/public/js/chat-threads.js +513 -0
  89. package/public/js/chat.js +832 -0
  90. package/public/js/search.js +41 -0
  91. package/public/privacy.html +101 -0
  92. package/public/robots.txt +6 -0
  93. package/public/site.webmanifest +12 -0
  94. package/public/terms.html +110 -0
  95. package/scripts/create-test-provider.js +55 -0
  96. package/scripts/deploy-staging.sh +51 -0
  97. package/scripts/fix-provider.js +39 -0
  98. package/scripts/quick-test.sh +37 -0
  99. package/scripts/test-chat.sh +54 -0
  100. package/scripts/test-multi-turn.js +137 -0
  101. package/scripts/test-ner-simple.js +28 -0
  102. package/scripts/test-ner.js +60 -0
  103. package/scripts/test-stripe-connect.js +304 -0
  104. package/scripts/test-webhook-secret.sh +24 -0
  105. package/server.js +3864 -0
  106. package/storage.rules +22 -0
  107. package/test-api.json +1 -0
  108. package/tests/emulator/README.md +38 -0
  109. package/tests/emulator/counters.emulator.test.js +81 -0
  110. package/tests/integration/api-account-selfserve.test.js +312 -0
  111. package/tests/integration/api-admin-digest.test.js +202 -0
  112. package/tests/integration/api-chat-satisfaction.test.js +259 -0
  113. package/tests/integration/api-doctor-drafts.test.js +236 -0
  114. package/tests/integration/api-doctor-inbox.test.js +401 -0
  115. package/tests/integration/api-org.test.js +328 -0
  116. package/tests/integration/api-payment.test.js +664 -0
  117. package/tests/integration/api-provider-settings.test.js +475 -0
  118. package/tests/integration/api-qr.test.js +121 -0
  119. package/tests/integration/api-security.test.js +241 -0
  120. package/tests/integration/api-stripe-search.test.js +303 -0
  121. package/tests/integration/api-webhook-deletion.test.js +231 -0
  122. package/tests/mocks/firebase-admin.js +220 -0
  123. package/tests/unit/analytics.test.js +151 -0
  124. package/tests/unit/audit-bugs.test.js +203 -0
  125. package/tests/unit/chat-ui-logic.test.js +283 -0
  126. package/tests/unit/drafts.test.js +104 -0
  127. package/tests/unit/feedback.test.js +148 -0
  128. package/tests/unit/i18n.test.js +229 -0
  129. package/tests/unit/llm-retry.test.js +122 -0
  130. package/tests/unit/notifications.test.js +155 -0
  131. package/tests/unit/orgs.test.js +328 -0
  132. package/tests/unit/payment.test.js +889 -0
  133. package/tests/unit/safety-edge-cases.test.js +509 -0
  134. package/tests/unit/safety-srs-compliance.test.js +252 -0
  135. package/tests/unit/safety.test.js +291 -0
  136. package/tests/unit/server-helpers.test.js +774 -0
  137. package/tests/unit/topics-limits.test.js +158 -0
  138. package/tests/unit/triage.test.js +152 -0
  139. package/tests/unit/validate.test.js +408 -0
@@ -0,0 +1,1198 @@
1
+ /* EvalDoc Homepage - YC Style Medical Design */
2
+ /* Feyti Medical Group Colors: Deep clinical blues, clean whites, subtle teals */
3
+
4
+ :root {
5
+ /* Feyti Medical Group Brand Colors */
6
+ --primary: #297B56;
7
+ --primary-dark: #1e5c40;
8
+ --primary-light: #3a9d6f;
9
+ --accent: #297B56;
10
+ --background: #FBFBFB;
11
+
12
+ /* Neutral Colors */
13
+ --gray-50: #F9FAFB;
14
+ --gray-100: #F3F4F6;
15
+ --gray-200: #E5E7EB;
16
+ --gray-400: #9CA3AF;
17
+ --gray-600: #4B5563;
18
+ --gray-800: #1F2937;
19
+ --gray-900: #111827;
20
+ --white: #FFFFFF;
21
+
22
+ /* Status Colors */
23
+ --danger: #DC2626;
24
+ --success: #297B56;
25
+ --warning: #F59E0B;
26
+
27
+ --radius: 12px;
28
+ --radius-sm: 8px;
29
+ --radius-lg: 16px;
30
+ --transition: all 0.2s ease;
31
+ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
32
+ --shadow: 0 4px 6px rgba(0, 0, 0, 0.07);
33
+ --shadow-lg: 0 10px 25px rgba(0, 0, 0, 0.1);
34
+ }
35
+
36
+ * {
37
+ margin: 0;
38
+ padding: 0;
39
+ box-sizing: border-box;
40
+ }
41
+
42
+ body {
43
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
44
+ color: var(--gray-900);
45
+ line-height: 1.6;
46
+ background: var(--background);
47
+ -webkit-font-smoothing: antialiased;
48
+ -moz-osx-font-smoothing: grayscale;
49
+ }
50
+
51
+ /* Navigation */
52
+ .navbar {
53
+ position: sticky;
54
+ top: 0;
55
+ background: rgba(255, 255, 255, 0.98);
56
+ backdrop-filter: blur(10px);
57
+ border-bottom: 1px solid var(--gray-200);
58
+ z-index: 1000;
59
+ padding: 1rem 0;
60
+ }
61
+
62
+ .nav-container {
63
+ max-width: 1280px;
64
+ margin: 0 auto;
65
+ padding: 0 2rem;
66
+ display: flex;
67
+ justify-content: space-between;
68
+ align-items: center;
69
+ }
70
+
71
+ .logo {
72
+ display: flex;
73
+ align-items: center;
74
+ gap: 0.75rem;
75
+ text-decoration: none;
76
+ color: var(--primary);
77
+ font-weight: 700;
78
+ font-size: 1.25rem;
79
+ }
80
+
81
+ .logo-icon {
82
+ width: 40px;
83
+ height: 40px;
84
+ background: var(--primary);
85
+ border-radius: 10px;
86
+ display: flex;
87
+ align-items: center;
88
+ justify-content: center;
89
+ font-size: 1.25rem;
90
+ }
91
+
92
+ .logo-img-nav {
93
+ height: 40px;
94
+ width: auto;
95
+ object-fit: contain;
96
+ border-radius: 8px;
97
+ }
98
+
99
+ .nav-links {
100
+ display: flex;
101
+ gap: 2rem;
102
+ align-items: center;
103
+ }
104
+
105
+ .nav-links a {
106
+ color: var(--gray-600);
107
+ text-decoration: none;
108
+ font-weight: 500;
109
+ font-size: 0.95rem;
110
+ transition: var(--transition);
111
+ }
112
+
113
+ .nav-links a:hover {
114
+ color: var(--primary);
115
+ }
116
+
117
+ .nav-links .nav-cta {
118
+ background: var(--primary);
119
+ color: white;
120
+ padding: 0.625rem 1.25rem;
121
+ border-radius: var(--radius-sm);
122
+ font-weight: 600;
123
+ }
124
+
125
+ .nav-links .nav-cta:hover {
126
+ background: var(--primary-dark);
127
+ transform: translateY(-1px);
128
+ }
129
+
130
+ /* Hero Section */
131
+ .hero {
132
+ padding: 5rem 0 6rem;
133
+ background: linear-gradient(180deg, var(--gray-50) 0%, var(--white) 100%);
134
+ }
135
+
136
+ .hero-container {
137
+ max-width: 1280px;
138
+ margin: 0 auto;
139
+ padding: 0 2rem;
140
+ display: grid;
141
+ grid-template-columns: 1.1fr 0.9fr;
142
+ gap: 4rem;
143
+ align-items: center;
144
+ }
145
+
146
+ .hero-content {
147
+ display: flex;
148
+ flex-direction: column;
149
+ gap: 1.5rem;
150
+ }
151
+
152
+ .hero-badge {
153
+ display: inline-block;
154
+ background: var(--gray-100);
155
+ color: var(--gray-700);
156
+ padding: 0.5rem 1rem;
157
+ border-radius: 50px;
158
+ font-size: 0.875rem;
159
+ font-weight: 500;
160
+ align-self: flex-start;
161
+ border: 1px solid var(--gray-200);
162
+ }
163
+
164
+ .hero-content h1 {
165
+ font-size: 3.5rem;
166
+ font-weight: 700;
167
+ line-height: 1.1;
168
+ color: var(--primary);
169
+ letter-spacing: -0.02em;
170
+ }
171
+
172
+ .hero-subtitle {
173
+ font-size: 1.25rem;
174
+ color: var(--gray-600);
175
+ line-height: 1.6;
176
+ max-width: 600px;
177
+ }
178
+
179
+ .hero-trust-line {
180
+ font-size: 1rem;
181
+ color: var(--gray-500);
182
+ font-style: italic;
183
+ margin-top: 1rem;
184
+ }
185
+
186
+ /* Search Box Hero */
187
+ .search-box-hero {
188
+ background: var(--white);
189
+ border: 2px solid var(--gray-200);
190
+ border-radius: var(--radius-lg);
191
+ padding: 2rem;
192
+ box-shadow: var(--shadow-lg);
193
+ margin-top: 1rem;
194
+ }
195
+
196
+ .search-box-hero h3 {
197
+ font-size: 1.125rem;
198
+ margin-bottom: 1rem;
199
+ color: var(--gray-900);
200
+ font-weight: 600;
201
+ }
202
+
203
+ .search-form {
204
+ display: flex;
205
+ gap: 0.5rem;
206
+ margin-bottom: 0.75rem;
207
+ }
208
+
209
+ .search-form input {
210
+ flex: 1;
211
+ padding: 0.875rem 1.25rem;
212
+ border: 2px solid var(--gray-200);
213
+ border-radius: var(--radius);
214
+ font-size: 1rem;
215
+ font-family: inherit;
216
+ transition: var(--transition);
217
+ background: var(--white);
218
+ }
219
+
220
+ .search-form input:focus {
221
+ outline: none;
222
+ border-color: var(--primary);
223
+ box-shadow: 0 0 0 3px rgba(41, 123, 86, 0.1);
224
+ }
225
+
226
+ .search-form button {
227
+ padding: 0.875rem 2rem;
228
+ background: var(--primary);
229
+ color: white;
230
+ border: none;
231
+ border-radius: var(--radius);
232
+ font-size: 1rem;
233
+ font-weight: 600;
234
+ cursor: pointer;
235
+ transition: var(--transition);
236
+ font-family: inherit;
237
+ }
238
+
239
+ .search-form button:hover {
240
+ background: var(--primary-dark);
241
+ transform: translateY(-1px);
242
+ }
243
+
244
+ .search-hint {
245
+ font-size: 0.875rem;
246
+ color: var(--gray-500);
247
+ }
248
+
249
+ /* Quick Results */
250
+ .quick-results {
251
+ display: none;
252
+ margin-top: 1rem;
253
+ border-top: 1px solid var(--gray-200);
254
+ padding-top: 1rem;
255
+ max-height: 300px;
256
+ overflow-y: auto;
257
+ }
258
+
259
+ .search-result {
260
+ display: flex;
261
+ justify-content: space-between;
262
+ align-items: center;
263
+ padding: 1rem;
264
+ border-radius: var(--radius-sm);
265
+ cursor: pointer;
266
+ transition: var(--transition);
267
+ margin-bottom: 0.5rem;
268
+ }
269
+
270
+ .search-result:hover {
271
+ background: var(--gray-50);
272
+ }
273
+
274
+ .provider-info {
275
+ flex: 1;
276
+ }
277
+
278
+ .provider-name {
279
+ font-weight: 600;
280
+ color: var(--gray-900);
281
+ margin-bottom: 0.25rem;
282
+ }
283
+
284
+ .provider-specialty {
285
+ font-size: 0.875rem;
286
+ color: var(--gray-600);
287
+ }
288
+
289
+ .chat-arrow {
290
+ font-size: 1.5rem;
291
+ color: var(--primary);
292
+ }
293
+
294
+ .search-loading,
295
+ .search-error,
296
+ .no-results {
297
+ padding: 1rem;
298
+ text-align: center;
299
+ color: var(--gray-500);
300
+ font-size: 0.875rem;
301
+ }
302
+
303
+ .search-error {
304
+ color: var(--danger);
305
+ }
306
+
307
+ /* Hero Visual */
308
+ .hero-visual {
309
+ display: flex;
310
+ justify-content: center;
311
+ align-items: center;
312
+ }
313
+
314
+ .visual-card {
315
+ background: var(--white);
316
+ border: 2px solid var(--gray-200);
317
+ border-radius: var(--radius-lg);
318
+ padding: 1.5rem;
319
+ box-shadow: var(--shadow-lg);
320
+ width: 100%;
321
+ max-width: 450px;
322
+ }
323
+
324
+ .visual-header {
325
+ display: flex;
326
+ align-items: center;
327
+ gap: 1rem;
328
+ margin-bottom: 1.5rem;
329
+ padding-bottom: 1rem;
330
+ border-bottom: 1px solid var(--gray-200);
331
+ }
332
+
333
+ .visual-avatar-container {
334
+ display: flex;
335
+ align-items: center;
336
+ gap: 0.75rem;
337
+ }
338
+
339
+ .visual-logo {
340
+ height: 36px;
341
+ width: auto;
342
+ object-fit: contain;
343
+ border-radius: 6px;
344
+ }
345
+
346
+ .visual-avatar {
347
+ font-weight: 600;
348
+ font-size: 1rem;
349
+ color: var(--gray-900);
350
+ }
351
+
352
+ .visual-status {
353
+ flex: 1;
354
+ }
355
+
356
+ .status-text {
357
+ font-weight: 600;
358
+ color: var(--gray-900);
359
+ font-size: 0.95rem;
360
+ }
361
+
362
+ .status-indicator {
363
+ font-size: 0.875rem;
364
+ color: var(--success);
365
+ }
366
+
367
+ .chat-demo {
368
+ display: flex;
369
+ flex-direction: column;
370
+ gap: 1rem;
371
+ }
372
+
373
+ .chat-bubble {
374
+ padding: 0.875rem 1.125rem;
375
+ border-radius: 12px;
376
+ max-width: 85%;
377
+ font-size: 0.9rem;
378
+ line-height: 1.5;
379
+ }
380
+
381
+ .chat-bubble.patient {
382
+ background: var(--gray-100);
383
+ color: var(--gray-900);
384
+ align-self: flex-start;
385
+ border-bottom-left-radius: 4px;
386
+ }
387
+
388
+ .chat-bubble.ai {
389
+ background: var(--primary);
390
+ color: white;
391
+ align-self: flex-end;
392
+ border-bottom-right-radius: 4px;
393
+ }
394
+
395
+ .chat-bubble p {
396
+ margin: 0;
397
+ }
398
+
399
+ /* Context Strip */
400
+ .context-strip {
401
+ background: var(--primary);
402
+ color: white;
403
+ padding: 3rem 0;
404
+ text-align: center;
405
+ }
406
+
407
+ .context-container {
408
+ max-width: 1280px;
409
+ margin: 0 auto;
410
+ padding: 0 2rem;
411
+ }
412
+
413
+ .context-headline {
414
+ font-size: 1.5rem;
415
+ font-weight: 600;
416
+ margin-bottom: 1rem;
417
+ }
418
+
419
+ .context-flags {
420
+ font-size: 2rem;
421
+ margin: 1.5rem 0;
422
+ }
423
+
424
+ .context-stats {
425
+ font-size: 1.125rem;
426
+ opacity: 0.9;
427
+ }
428
+
429
+ /* Sections */
430
+ .section {
431
+ padding: 5rem 0;
432
+ max-width: 1280px;
433
+ margin: 0 auto;
434
+ padding-left: 2rem;
435
+ padding-right: 2rem;
436
+ }
437
+
438
+ .section h2 {
439
+ font-size: 2.75rem;
440
+ text-align: center;
441
+ margin-bottom: 3rem;
442
+ font-weight: 700;
443
+ color: var(--gray-900);
444
+ letter-spacing: -0.02em;
445
+ }
446
+
447
+ .section-light {
448
+ background: var(--gray-50);
449
+ max-width: 100%;
450
+ margin: 0;
451
+ }
452
+
453
+ .section-dark {
454
+ background: var(--gray-900);
455
+ color: white;
456
+ max-width: 100%;
457
+ margin: 0;
458
+ }
459
+
460
+ .section-dark h2 {
461
+ color: white;
462
+ }
463
+
464
+ /* Problem Section */
465
+ .problem-grid {
466
+ display: grid;
467
+ grid-template-columns: repeat(2, 1fr);
468
+ gap: 3rem;
469
+ margin-bottom: 3rem;
470
+ max-width: 1000px;
471
+ margin-left: auto;
472
+ margin-right: auto;
473
+ }
474
+
475
+ .problem-col h3 {
476
+ font-size: 1.5rem;
477
+ margin-bottom: 1.5rem;
478
+ color: var(--gray-900);
479
+ }
480
+
481
+ .problem-list {
482
+ list-style: none;
483
+ padding: 0;
484
+ }
485
+
486
+ .problem-list li {
487
+ padding: 0.75rem 0;
488
+ padding-left: 1.5rem;
489
+ position: relative;
490
+ color: var(--gray-700);
491
+ font-size: 1.05rem;
492
+ line-height: 1.6;
493
+ }
494
+
495
+ .problem-list li::before {
496
+ content: "•";
497
+ position: absolute;
498
+ left: 0;
499
+ color: var(--primary);
500
+ font-size: 1.5rem;
501
+ line-height: 1.4;
502
+ }
503
+
504
+ .problem-bold {
505
+ text-align: center;
506
+ font-size: 1.5rem;
507
+ font-weight: 600;
508
+ color: var(--primary);
509
+ max-width: 700px;
510
+ margin: 0 auto;
511
+ line-height: 1.4;
512
+ }
513
+
514
+ /* Solution Section */
515
+ .solution-intro {
516
+ text-align: center;
517
+ font-size: 1.25rem;
518
+ color: var(--gray-700);
519
+ max-width: 800px;
520
+ margin: 0 auto 3rem;
521
+ line-height: 1.7;
522
+ }
523
+
524
+ .features-grid {
525
+ display: grid;
526
+ grid-template-columns: repeat(3, 1fr);
527
+ gap: 2rem;
528
+ max-width: 1100px;
529
+ margin: 0 auto;
530
+ }
531
+
532
+ .feature-card {
533
+ background: var(--white);
534
+ border: 2px solid var(--gray-200);
535
+ border-radius: var(--radius-lg);
536
+ padding: 2.5rem 2rem;
537
+ text-align: center;
538
+ transition: var(--transition);
539
+ }
540
+
541
+ .feature-card:hover {
542
+ border-color: var(--primary);
543
+ transform: translateY(-4px);
544
+ box-shadow: var(--shadow-lg);
545
+ }
546
+
547
+ .feature-icon-large {
548
+ font-size: 3rem;
549
+ margin-bottom: 1.5rem;
550
+ }
551
+
552
+ .feature-card h3 {
553
+ font-size: 1.5rem;
554
+ margin-bottom: 1rem;
555
+ color: var(--gray-900);
556
+ }
557
+
558
+ .feature-card p {
559
+ color: var(--gray-600);
560
+ font-size: 1.05rem;
561
+ line-height: 1.6;
562
+ }
563
+
564
+ /* Flow Diagram */
565
+ .flow-diagram {
566
+ display: flex;
567
+ justify-content: center;
568
+ align-items: center;
569
+ gap: 1.5rem;
570
+ max-width: 1200px;
571
+ margin: 0 auto 2rem;
572
+ flex-wrap: wrap;
573
+ }
574
+
575
+ .flow-step {
576
+ flex: 1;
577
+ min-width: 180px;
578
+ text-align: center;
579
+ }
580
+
581
+ .flow-number {
582
+ width: 60px;
583
+ height: 60px;
584
+ background: var(--primary);
585
+ color: white;
586
+ border-radius: 50%;
587
+ display: flex;
588
+ align-items: center;
589
+ justify-content: center;
590
+ font-size: 1.75rem;
591
+ font-weight: 700;
592
+ margin: 0 auto 1rem;
593
+ }
594
+
595
+ .flow-step h4 {
596
+ font-size: 1.125rem;
597
+ margin-bottom: 0.5rem;
598
+ color: var(--gray-900);
599
+ font-weight: 600;
600
+ }
601
+
602
+ .flow-step p {
603
+ font-size: 0.95rem;
604
+ color: var(--gray-600);
605
+ }
606
+
607
+ .flow-arrow {
608
+ font-size: 2rem;
609
+ color: var(--gray-400);
610
+ flex-shrink: 0;
611
+ }
612
+
613
+ .flow-caption {
614
+ text-align: center;
615
+ font-size: 1.125rem;
616
+ color: var(--gray-600);
617
+ font-style: italic;
618
+ }
619
+
620
+ /* Platform Section */
621
+ .platform-grid {
622
+ display: grid;
623
+ grid-template-columns: repeat(4, 1fr);
624
+ gap: 2rem;
625
+ max-width: 1100px;
626
+ margin: 0 auto 2rem;
627
+ }
628
+
629
+ .platform-feature {
630
+ text-align: center;
631
+ }
632
+
633
+ .platform-icon {
634
+ font-size: 2.5rem;
635
+ margin-bottom: 1rem;
636
+ }
637
+
638
+ .platform-feature h3 {
639
+ font-size: 1.25rem;
640
+ margin-bottom: 0.75rem;
641
+ color: white;
642
+ }
643
+
644
+ .platform-feature p {
645
+ color: rgba(255, 255, 255, 0.8);
646
+ font-size: 0.95rem;
647
+ }
648
+
649
+ .platform-tagline {
650
+ text-align: center;
651
+ font-size: 1.375rem;
652
+ font-weight: 600;
653
+ color: white;
654
+ margin-top: 2rem;
655
+ }
656
+
657
+ /* Safety Checklist */
658
+ .safety-checklist {
659
+ max-width: 800px;
660
+ margin: 0 auto 2rem;
661
+ display: flex;
662
+ flex-direction: column;
663
+ gap: 1.25rem;
664
+ }
665
+
666
+ .safety-item {
667
+ display: flex;
668
+ align-items: flex-start;
669
+ gap: 1rem;
670
+ padding: 1.25rem;
671
+ background: var(--gray-50);
672
+ border-radius: var(--radius);
673
+ border: 2px solid var(--gray-200);
674
+ }
675
+
676
+ .safety-icon {
677
+ font-size: 1.5rem;
678
+ flex-shrink: 0;
679
+ }
680
+
681
+ .safety-text {
682
+ font-size: 1.05rem;
683
+ color: var(--gray-700);
684
+ line-height: 1.6;
685
+ }
686
+
687
+ .safety-disclaimer {
688
+ text-align: center;
689
+ font-size: 1.125rem;
690
+ color: var(--gray-600);
691
+ font-style: italic;
692
+ margin-top: 2rem;
693
+ }
694
+
695
+ /* Who Section */
696
+ .who-grid {
697
+ display: grid;
698
+ grid-template-columns: repeat(2, 1fr);
699
+ gap: 3rem;
700
+ max-width: 1000px;
701
+ margin: 0 auto;
702
+ }
703
+
704
+ .who-card {
705
+ background: var(--white);
706
+ border: 2px solid var(--gray-200);
707
+ border-radius: var(--radius-lg);
708
+ padding: 2.5rem;
709
+ }
710
+
711
+ .who-card h3 {
712
+ font-size: 1.5rem;
713
+ margin-bottom: 1.5rem;
714
+ color: var(--gray-900);
715
+ }
716
+
717
+ .who-list {
718
+ list-style: none;
719
+ padding: 0;
720
+ margin-bottom: 2rem;
721
+ }
722
+
723
+ .who-list li {
724
+ padding: 0.75rem 0;
725
+ padding-left: 1.5rem;
726
+ position: relative;
727
+ color: var(--gray-700);
728
+ font-size: 1.05rem;
729
+ line-height: 1.6;
730
+ }
731
+
732
+ .who-list li::before {
733
+ content: "✓";
734
+ position: absolute;
735
+ left: 0;
736
+ color: var(--primary);
737
+ font-weight: 700;
738
+ }
739
+
740
+ /* Model Section */
741
+ .model-cards {
742
+ display: grid;
743
+ grid-template-columns: repeat(3, 1fr);
744
+ gap: 2rem;
745
+ max-width: 1000px;
746
+ margin: 0 auto 2rem;
747
+ }
748
+
749
+ .model-card {
750
+ text-align: center;
751
+ padding: 2rem 1.5rem;
752
+ background: var(--gray-50);
753
+ border-radius: var(--radius-lg);
754
+ border: 2px solid var(--gray-200);
755
+ }
756
+
757
+ .model-icon {
758
+ font-size: 2.5rem;
759
+ margin-bottom: 1rem;
760
+ }
761
+
762
+ .model-card h4 {
763
+ font-size: 1.25rem;
764
+ margin-bottom: 0.75rem;
765
+ color: var(--gray-900);
766
+ font-weight: 600;
767
+ }
768
+
769
+ .model-card p {
770
+ color: var(--gray-600);
771
+ font-size: 0.95rem;
772
+ }
773
+
774
+ .model-principles {
775
+ text-align: center;
776
+ margin-top: 2rem;
777
+ }
778
+
779
+ .model-principles p {
780
+ font-size: 1.25rem;
781
+ color: var(--primary);
782
+ }
783
+
784
+ /* Feyti Strip */
785
+ .feyti-strip {
786
+ background: linear-gradient(135deg, var(--primary), var(--primary-dark));
787
+ color: white;
788
+ padding: 2.5rem 0;
789
+ text-align: center;
790
+ }
791
+
792
+ .feyti-container {
793
+ max-width: 1280px;
794
+ margin: 0 auto;
795
+ padding: 0 2rem;
796
+ display: flex;
797
+ align-items: center;
798
+ justify-content: center;
799
+ gap: 1.5rem;
800
+ }
801
+
802
+ .feyti-logo {
803
+ height: 60px;
804
+ width: auto;
805
+ object-fit: contain;
806
+ border-radius: 8px;
807
+ }
808
+
809
+ .feyti-text-container {
810
+ text-align: center;
811
+ }
812
+
813
+ .feyti-text {
814
+ font-size: 1.25rem;
815
+ margin-bottom: 0.5rem;
816
+ }
817
+
818
+ .feyti-tagline {
819
+ font-size: 1rem;
820
+ opacity: 0.9;
821
+ }
822
+
823
+ /* Final CTA */
824
+ .final-cta {
825
+ padding: 6rem 0;
826
+ background: linear-gradient(180deg, var(--white) 0%, var(--gray-50) 100%);
827
+ }
828
+
829
+ .final-cta-container {
830
+ max-width: 900px;
831
+ margin: 0 auto;
832
+ padding: 0 2rem;
833
+ text-align: center;
834
+ }
835
+
836
+ .final-cta-container h2 {
837
+ font-size: 3rem;
838
+ margin-bottom: 1.5rem;
839
+ color: var(--primary);
840
+ font-weight: 700;
841
+ letter-spacing: -0.02em;
842
+ }
843
+
844
+ .final-cta-container > p {
845
+ font-size: 1.25rem;
846
+ color: var(--gray-600);
847
+ margin-bottom: 2.5rem;
848
+ line-height: 1.6;
849
+ }
850
+
851
+ .final-cta-buttons {
852
+ display: flex;
853
+ gap: 1rem;
854
+ justify-content: center;
855
+ margin-bottom: 1.5rem;
856
+ flex-wrap: wrap;
857
+ }
858
+
859
+ .btn-large-primary {
860
+ display: inline-block;
861
+ padding: 1.125rem 2.5rem;
862
+ background: var(--primary);
863
+ color: white;
864
+ text-decoration: none;
865
+ border-radius: var(--radius);
866
+ font-weight: 600;
867
+ font-size: 1.125rem;
868
+ transition: var(--transition);
869
+ border: 2px solid var(--primary);
870
+ }
871
+
872
+ .btn-large-primary:hover {
873
+ background: var(--primary-dark);
874
+ border-color: var(--primary-dark);
875
+ transform: translateY(-2px);
876
+ box-shadow: var(--shadow-lg);
877
+ }
878
+
879
+ .btn-large-secondary {
880
+ display: inline-block;
881
+ padding: 1.125rem 2.5rem;
882
+ background: white;
883
+ color: var(--primary);
884
+ text-decoration: none;
885
+ border-radius: var(--radius);
886
+ font-weight: 600;
887
+ font-size: 1.125rem;
888
+ transition: var(--transition);
889
+ border: 2px solid var(--primary);
890
+ }
891
+
892
+ .btn-large-secondary:hover {
893
+ background: var(--gray-50);
894
+ transform: translateY(-2px);
895
+ box-shadow: var(--shadow);
896
+ }
897
+
898
+ .btn-secondary {
899
+ display: inline-block;
900
+ padding: 0.875rem 2rem;
901
+ background: var(--primary);
902
+ color: white;
903
+ text-decoration: none;
904
+ border-radius: var(--radius);
905
+ font-weight: 600;
906
+ font-size: 1rem;
907
+ transition: var(--transition);
908
+ border: 2px solid var(--primary);
909
+ }
910
+
911
+ .btn-secondary:hover {
912
+ background: var(--primary-dark);
913
+ transform: translateY(-2px);
914
+ box-shadow: var(--shadow);
915
+ }
916
+
917
+ .final-cta-footer {
918
+ font-size: 1.125rem;
919
+ color: var(--gray-600);
920
+ font-style: italic;
921
+ }
922
+
923
+ /* Footer */
924
+ .footer {
925
+ background: var(--gray-900);
926
+ color: white;
927
+ padding: 4rem 0 2rem;
928
+ }
929
+
930
+ .footer-container {
931
+ max-width: 1280px;
932
+ margin: 0 auto;
933
+ padding: 0 2rem 3rem;
934
+ display: grid;
935
+ grid-template-columns: repeat(3, 1fr);
936
+ gap: 3rem;
937
+ }
938
+
939
+ .footer-section h4 {
940
+ font-size: 1.25rem;
941
+ margin-bottom: 1.25rem;
942
+ font-weight: 600;
943
+ }
944
+
945
+ .footer-section p {
946
+ color: rgba(255, 255, 255, 0.7);
947
+ font-size: 0.95rem;
948
+ line-height: 1.6;
949
+ margin-bottom: 0.75rem;
950
+ }
951
+
952
+ .footer-brand {
953
+ color: rgba(255, 255, 255, 0.5);
954
+ font-size: 0.875rem;
955
+ font-style: italic;
956
+ margin-top: 1rem;
957
+ }
958
+
959
+ .footer-address {
960
+ color: rgba(255, 255, 255, 0.5);
961
+ font-size: 0.85rem;
962
+ line-height: 1.6;
963
+ margin-top: 0.75rem;
964
+ }
965
+
966
+ .footer-section a {
967
+ display: block;
968
+ color: rgba(255, 255, 255, 0.7);
969
+ text-decoration: none;
970
+ margin-bottom: 0.75rem;
971
+ transition: var(--transition);
972
+ font-size: 0.95rem;
973
+ }
974
+
975
+ .footer-section a:hover {
976
+ color: white;
977
+ padding-left: 4px;
978
+ }
979
+
980
+ .footer-bottom {
981
+ max-width: 1280px;
982
+ margin: 0 auto;
983
+ padding: 2rem 2rem 0;
984
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
985
+ text-align: center;
986
+ }
987
+
988
+ .footer-bottom p {
989
+ color: rgba(255, 255, 255, 0.6);
990
+ font-size: 0.875rem;
991
+ margin-bottom: 0.5rem;
992
+ }
993
+
994
+ .footer-disclaimer {
995
+ color: rgba(255, 255, 255, 0.4);
996
+ font-size: 0.8rem;
997
+ font-style: italic;
998
+ max-width: 800px;
999
+ margin: 1rem auto 0;
1000
+ line-height: 1.5;
1001
+ }
1002
+
1003
+ /* Responsive Design */
1004
+ @media (max-width: 1024px) {
1005
+ .hero-container {
1006
+ grid-template-columns: 1fr;
1007
+ gap: 3rem;
1008
+ }
1009
+
1010
+ .hero-content h1 {
1011
+ font-size: 2.75rem;
1012
+ }
1013
+
1014
+ .features-grid {
1015
+ grid-template-columns: 1fr;
1016
+ }
1017
+
1018
+ .platform-grid {
1019
+ grid-template-columns: repeat(2, 1fr);
1020
+ }
1021
+
1022
+ .model-cards {
1023
+ grid-template-columns: 1fr;
1024
+ }
1025
+
1026
+ .flow-diagram {
1027
+ flex-direction: column;
1028
+ }
1029
+
1030
+ .flow-arrow {
1031
+ transform: rotate(90deg);
1032
+ }
1033
+ }
1034
+
1035
+ @media (max-width: 768px) {
1036
+ .hero-content h1 {
1037
+ font-size: 2.25rem;
1038
+ }
1039
+
1040
+ .section h2 {
1041
+ font-size: 2rem;
1042
+ }
1043
+
1044
+ .problem-grid {
1045
+ grid-template-columns: 1fr;
1046
+ gap: 2rem;
1047
+ }
1048
+
1049
+ .who-grid {
1050
+ grid-template-columns: 1fr;
1051
+ }
1052
+
1053
+ .footer-container {
1054
+ grid-template-columns: 1fr;
1055
+ gap: 2rem;
1056
+ }
1057
+
1058
+ .final-cta-container h2 {
1059
+ font-size: 2rem;
1060
+ }
1061
+
1062
+ .final-cta-buttons {
1063
+ flex-direction: column;
1064
+ }
1065
+
1066
+ .nav-links {
1067
+ gap: 1rem;
1068
+ font-size: 0.875rem;
1069
+ }
1070
+
1071
+ .search-form {
1072
+ flex-direction: column;
1073
+ }
1074
+
1075
+ .search-form button {
1076
+ width: 100%;
1077
+ }
1078
+ }
1079
+
1080
+ @media (max-width: 640px) {
1081
+ .hero-content h1 {
1082
+ font-size: 1.875rem;
1083
+ }
1084
+
1085
+ .section {
1086
+ padding: 3rem 1rem;
1087
+ }
1088
+
1089
+ .section h2 {
1090
+ font-size: 1.75rem;
1091
+ }
1092
+
1093
+ .nav-container {
1094
+ padding: 0 1rem;
1095
+ }
1096
+
1097
+ .nav-links a:not(.nav-cta) {
1098
+ display: none;
1099
+ }
1100
+
1101
+ .context-headline {
1102
+ font-size: 1.25rem;
1103
+ }
1104
+
1105
+ .context-flags {
1106
+ font-size: 1.5rem;
1107
+ }
1108
+
1109
+ .platform-grid {
1110
+ grid-template-columns: 1fr;
1111
+ }
1112
+ }
1113
+
1114
+ /* ── Waitlist form (landing page) ─────────────────────────── */
1115
+ .waitlist-launch-badge {
1116
+ display: inline-block;
1117
+ background: linear-gradient(135deg, #4fb3a4, #3a8a7e);
1118
+ color: #fff;
1119
+ font-size: 0.875rem;
1120
+ font-weight: 600;
1121
+ padding: 0.4rem 1rem;
1122
+ border-radius: 999px;
1123
+ margin-bottom: 1.5rem;
1124
+ letter-spacing: 0.03em;
1125
+ }
1126
+
1127
+ .waitlist-form {
1128
+ max-width: 540px;
1129
+ margin: 0 auto 1.5rem;
1130
+ }
1131
+
1132
+ .waitlist-fields {
1133
+ display: flex;
1134
+ flex-direction: column;
1135
+ gap: 0.75rem;
1136
+ }
1137
+
1138
+ .waitlist-fields input {
1139
+ width: 100%;
1140
+ padding: 0.875rem 1rem;
1141
+ border: 1.5px solid #d1d5db;
1142
+ border-radius: 8px;
1143
+ font-size: 1rem;
1144
+ font-family: inherit;
1145
+ outline: none;
1146
+ transition: border-color 0.2s;
1147
+ box-sizing: border-box;
1148
+ }
1149
+
1150
+ .waitlist-fields input:focus {
1151
+ border-color: #4fb3a4;
1152
+ }
1153
+
1154
+ .waitlist-form-msg {
1155
+ margin-top: 0.75rem;
1156
+ font-size: 0.9rem;
1157
+ min-height: 1.25rem;
1158
+ color: #6b7280;
1159
+ }
1160
+
1161
+ .waitlist-form-msg.success { color: #059669; font-weight: 500; }
1162
+ .waitlist-form-msg.error { color: #dc2626; }
1163
+
1164
+ /* Small phone fixes */
1165
+ @media (max-width: 480px) {
1166
+ .search-form input {
1167
+ font-size: 16px;
1168
+ min-height: 44px;
1169
+ }
1170
+ .search-form button {
1171
+ min-height: 44px;
1172
+ min-width: 44px;
1173
+ padding: 0.75rem 1rem;
1174
+ }
1175
+ .hero-content h1 {
1176
+ font-size: 1.5rem;
1177
+ }
1178
+ .hero-subtitle {
1179
+ font-size: 0.95rem;
1180
+ }
1181
+ .problem-grid {
1182
+ grid-template-columns: 1fr;
1183
+ gap: 1.5rem;
1184
+ }
1185
+ .footer-container {
1186
+ grid-template-columns: 1fr;
1187
+ }
1188
+ }
1189
+
1190
+ /* Focus visible for accessibility */
1191
+ a:focus-visible,
1192
+ button:focus-visible,
1193
+ input:focus-visible,
1194
+ select:focus-visible,
1195
+ textarea:focus-visible {
1196
+ outline: 2px solid var(--primary);
1197
+ outline-offset: 2px;
1198
+ }