paracosm 0.9.1021 → 0.9.1024

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 (38) hide show
  1. package/README.md +12 -11
  2. package/assets/landing.css +1 -533
  3. package/dist/dashboard/dist/assets/{index-YkbFYo4m.js → index-Da6eIzNW.js} +2 -2
  4. package/dist/dashboard/dist/assets/{pdf-D0rlhCn8.js → pdf-CdfMQ2jQ.js} +1 -1
  5. package/dist/dashboard/dist/index.html +1 -1
  6. package/dist/dashboard/dist/llms-full.txt +5 -7
  7. package/dist/dashboard/dist/llms.txt +2 -0
  8. package/dist/dashboard/dist/sitemap.xml +7 -27
  9. package/dist/dashboard/landing.html +35 -292
  10. package/dist/server/rate-limiter.d.ts +0 -9
  11. package/dist/server/rate-limiter.d.ts.map +1 -1
  12. package/dist/server/rate-limiter.js +0 -36
  13. package/dist/server/rate-limiter.js.map +1 -1
  14. package/dist/server/routes/waitlist.d.ts +15 -19
  15. package/dist/server/routes/waitlist.d.ts.map +1 -1
  16. package/dist/server/routes/waitlist.js +5 -107
  17. package/dist/server/routes/waitlist.js.map +1 -1
  18. package/dist/server/server-app.d.ts +1 -1
  19. package/dist/server/server-app.d.ts.map +1 -1
  20. package/dist/server/server-app.js +28 -27
  21. package/dist/server/server-app.js.map +1 -1
  22. package/dist/server/services/email-templates.d.ts +4 -11
  23. package/dist/server/services/email-templates.d.ts.map +1 -1
  24. package/dist/server/services/email-templates.js +4 -70
  25. package/dist/server/services/email-templates.js.map +1 -1
  26. package/dist/server/stores/session.d.ts +6 -4
  27. package/dist/server/stores/session.d.ts.map +1 -1
  28. package/dist/server/stores/session.js +5 -3
  29. package/dist/server/stores/session.js.map +1 -1
  30. package/dist/server/stores/sqlite-run-history.d.ts +8 -12
  31. package/dist/server/stores/sqlite-run-history.d.ts.map +1 -1
  32. package/dist/server/stores/sqlite-run-history.js +6 -6
  33. package/dist/server/stores/sqlite-run-history.js.map +1 -1
  34. package/dist/server/stores/waitlist.d.ts +9 -6
  35. package/dist/server/stores/waitlist.d.ts.map +1 -1
  36. package/dist/server/stores/waitlist.js +8 -5
  37. package/dist/server/stores/waitlist.js.map +1 -1
  38. package/package.json +2 -1
package/README.md CHANGED
@@ -459,7 +459,7 @@ Programmatic surfaces: `paracosm` root (`run`, `runMany`, `WorldModel`, `compile
459
459
 
460
460
  For non-SSE consumers there's `POST /simulate` (gated on `PARACOSM_ENABLE_SIMULATE_ENDPOINT=true`) and nine read-and-replay routes under `/api/v1/*`. Wire-level details: [`docs/HTTP_API.md`](docs/HTTP_API.md).
461
461
 
462
- Storage: SQLite by default, Postgres / sql.js / IndexedDB via `STORAGE_ADAPTER=` env. Run history (Library) and session blobs (Load menu) share the same schema. Admin write routes (`/admin/sessions/save`, `/admin/data/wipe`) require both `ADMIN_WRITE=true` and an `ADMIN_TOKEN` bearer; off by default.
462
+ Storage: SQLite through `@framers/sql-storage-adapter` (better-sqlite3, or sql.js when the native module cannot load). Run history (Library) lives in `data/runs.db` under `APP_DIR`, the working directory when unset (`PARACOSM_RUN_HISTORY_DB_PATH` moves it), and saved sessions (Load menu) in `data/sessions.db`; `STORAGE_ADAPTER` and `DATABASE_URL` have no effect on either. Admin write routes (`/admin/sessions/save`, `/admin/data/wipe`) require both `ADMIN_WRITE=true` and an `ADMIN_TOKEN` bearer; off by default.
463
463
 
464
464
  ---
465
465
 
@@ -512,18 +512,17 @@ Paracosm uses [AgentOS](https://agentos.sh/en) for agent orchestration, LLM disp
512
512
 
513
513
  ---
514
514
 
515
- ## Open source vs hosted
515
+ ## Hosted demo or your own install
516
516
 
517
- | | Open source (Apache-2.0) | Hosted (planned) |
518
- |------------------|--------------------------------------------------------------------|------------------------------------------------------------------------|
519
- | Actors | Unlimited via API. Dashboard renders the full cohort side-by-side, constellation view past 50. | Fleet management UI on top. |
520
- | Simulations | In-process parallelism via the bounded worker pool. | Distributed parallelization across worker nodes. |
521
- | Scenarios | JSON + compiler, unlimited. | Visual scenario editor, team sharing, version control. |
522
- | Agent chat | Available after the first turn completes. | Persistent agents with durable memory across sessions. |
523
- | Cost | Free forever. The user supplies LLM API keys. | Tiered pricing for teams, organizations, and government agencies. |
524
- | Support | Community via Discord and GitHub. | SLA, dedicated support, private deployment. |
517
+ | | Hosted demo | Your own install (Apache-2.0) |
518
+ |---|---|---|
519
+ | Where | [paracosm.agentos.sh/sim](https://paracosm.agentos.sh/sim), in the browser, without an account. | Your machine or server: `npm install paracosm` for the SDK and the CLI, `paracosm dashboard` for the same dashboard at `http://localhost:3456`. |
520
+ | Model keys | The host's keys, or your own OpenAI or Anthropic key entered in Settings. | Your own keys, from the environment or a `.env` file. |
521
+ | Limits | Runs on the host's keys are capped in turns, population and departments, and each IP address has a daily run limit. Your own key lifts both. | No hosted quotas: the SDK and `paracosm run` cap no turns, population, departments or daily runs. The API has its own bounds: `runMany()` and `WorldModel.quickstart()` take 2 to 6 actors and throw outside that range, `run()` runs two and returns the first, and a dashboard run takes 2 to 300 actors (a fork takes 1). The dashboard server limits runs on its own keys to `RATE_LIMIT` per IP address per day (1 when unset); `RATE_LIMIT=0` turns the limit off. |
522
+ | Cost | Free to try. | Free. You pay your model provider for the runs you make. |
523
+ | Support | Community via Discord and GitHub. | Community via Discord and GitHub. |
525
524
 
526
- The open-source engine is the permanent foundation. The hosted product targets organizations that need to run dozens or hundreds of simulations in parallel: defense agencies stress-testing doctrine, corporations modeling leadership scenarios, game studios generating divergent NPC civilizations at scale. Contact [team@frame.dev](mailto:team@frame.dev) for early access.
525
+ Commercial, partnership and sponsorship inquiries go to [team@frame.dev](mailto:team@frame.dev).
527
526
 
528
527
  ---
529
528
 
@@ -534,6 +533,8 @@ The open-source engine is the permanent foundation. The hosted product targets o
534
533
  | Live demo | [paracosm.agentos.sh/sim](https://paracosm.agentos.sh/sim) |
535
534
  | Landing page | [paracosm.agentos.sh](https://paracosm.agentos.sh) |
536
535
  | API docs | [paracosm.agentos.sh/docs](https://paracosm.agentos.sh/docs) |
536
+ | HTTP API | [docs/HTTP_API.md](https://github.com/framerslab/paracosm/blob/master/docs/HTTP_API.md) |
537
+ | Cookbook | [docs/COOKBOOK.md](https://github.com/framerslab/paracosm/blob/master/docs/COOKBOOK.md) |
537
538
  | npm | [npmjs.com/package/paracosm](https://www.npmjs.com/package/paracosm) |
538
539
  | AgentOS | [agentos.sh](https://agentos.sh/en) |
539
540
  | Discord | [wilds.ai/discord](https://wilds.ai/discord) |
@@ -780,50 +780,6 @@ a:hover { text-decoration: underline; }
780
780
  .feat p { font-size: var(--font-md); color: var(--t2); line-height: 1.7; }
781
781
  .feat-ref { font-size: var(--font-2xs); color: var(--t4); margin-top: 10px; font-family: var(--mono); border-top: 1px solid var(--border); padding-top: 8px; }
782
782
 
783
- /* ── Flow Diagram ─────────────────────────────────────────────────────────── */
784
-
785
- .flow-wrap { position: relative; margin: 48px 0; padding: 40px 0; }
786
-
787
- /* Pin the connector to the vertical center of the icon-ring row.
788
- padding-top (40px) + half the ring height (64 / 2 = 32px) = 72px.
789
- Was `top: 50%`, which scaled with the tallest node's paragraph and
790
- started cutting through the title/description text as soon as the
791
- copy got long enough. */
792
- .flow-line { position: absolute; top: 72px; left: 60px; right: 60px; height: 2px; background: var(--border); z-index: 0; }
793
- .flow-line-fill { height: 100%; width: 0; background: var(--grad); transition: width 1.5s ease; }
794
- .flow-line-fill.active { width: 100%; }
795
-
796
- .flow { display: flex; justify-content: space-between; position: relative; z-index: 1; }
797
-
798
- .flow-node { display: flex; flex-direction: column; align-items: center; text-align: center; width: 22%; position: relative; }
799
-
800
- .flow-ring {
801
- width: 64px; height: 64px;
802
- border-radius: 50%;
803
- border: 2px solid var(--border);
804
- display: flex; align-items: center; justify-content: center;
805
- background: var(--bg);
806
- transition: all .5s;
807
- margin-bottom: 14px;
808
- }
809
-
810
- .flow-ring svg { width: 28px; height: 28px; opacity: .7; transition: opacity .3s; }
811
- .flow-ring.active { border-color: var(--amber); }
812
- .flow-ring.active svg { opacity: 1; }
813
-
814
- .flow-num { font-family: var(--mono); font-size: var(--font-2xs); font-weight: 700; color: var(--t4); letter-spacing: 1px; margin-bottom: 4px; }
815
- .flow-node h3 { font-family: var(--mono); font-size: var(--font-md); font-weight: 700; color: var(--t1); margin-bottom: 4px; }
816
- .flow-node p { font-size: var(--font-xs); color: var(--t3); line-height: 1.5; max-width: 180px; }
817
-
818
- /* ── Divergence Visualization ─────────────────────────────────────────────── */
819
-
820
- .diverge { display: flex; gap: 20px; margin-top: 48px; }
821
- .diverge-side { flex: 1; border-radius: 8px; padding: 24px; border: 1px solid var(--border); background: var(--bg3); transition: all .3s; }
822
- .diverge-side:hover { border-color: var(--border-hl); }
823
- .diverge-side h3 { font-family: var(--mono); font-size: var(--font-lg); font-weight: 700; margin-bottom: 8px; }
824
- .diverge-bar { height: 6px; border-radius: 3px; margin: 6px 0; overflow: hidden; background: var(--border); }
825
- .diverge-fill { height: 100%; border-radius: 3px; transition: width 1s ease; }
826
-
827
783
  /* ── Scenarios ────────────────────────────────────────────────────────────── */
828
784
 
829
785
  .scenarios { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
@@ -979,199 +935,6 @@ section p a,
979
935
 
980
936
  /* ── CTA Banner ───────────────────────────────────────────────────────────── */
981
937
 
982
- /* ── Whitepaper "coming soon" CTA ───────────────────────────────────────── */
983
-
984
- .whitepaper-sec { padding: 80px 24px; }
985
- .whitepaper-inner { max-width: 1040px; margin: 0 auto; }
986
-
987
- .whitepaper-card {
988
- position: relative;
989
- border-radius: 24px;
990
- border: 1px solid var(--border);
991
- background:
992
- linear-gradient(135deg, color-mix(in oklab, var(--bg2) 92%, transparent) 0%, color-mix(in oklab, var(--bg3) 88%, transparent) 100%);
993
- padding: 48px 40px;
994
- overflow: hidden;
995
- isolation: isolate;
996
- }
997
-
998
- .whitepaper-card::before {
999
- /* Subtle hex-grid texture overlay matching the agentos.sh whitepaper card */
1000
- content: '';
1001
- position: absolute;
1002
- inset: 0;
1003
- pointer-events: none;
1004
- opacity: 0.05;
1005
- background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='60' height='52' viewBox='0 0 60 52'><path d='M 30 0 L 60 17 L 60 35 L 30 52 L 0 35 L 0 17 Z' fill='none' stroke='%23e8b44a' stroke-width='0.6' /></svg>");
1006
- background-repeat: repeat;
1007
- z-index: 0;
1008
- }
1009
-
1010
- .whitepaper-card::after {
1011
- /* Bottom gradient hairline accent */
1012
- content: '';
1013
- position: absolute;
1014
- inset: auto 0 0 0;
1015
- height: 3px;
1016
- background: linear-gradient(90deg, var(--rust) 0%, var(--amber) 50%, var(--teal) 100%);
1017
- z-index: 0;
1018
- }
1019
-
1020
- .whitepaper-card > * { position: relative; z-index: 1; }
1021
-
1022
- .whitepaper-pill {
1023
- display: inline-flex;
1024
- align-items: center;
1025
- gap: 8px;
1026
- padding: 6px 14px;
1027
- border-radius: 999px;
1028
- border: 1px solid color-mix(in oklab, var(--amber) 50%, transparent);
1029
- background: color-mix(in oklab, var(--amber) 10%, transparent);
1030
- color: var(--amber);
1031
- font-family: var(--mono);
1032
- font-size: var(--font-2xs);
1033
- font-weight: 700;
1034
- letter-spacing: 0.2em;
1035
- margin-bottom: 20px;
1036
- }
1037
-
1038
- .whitepaper-pill-icon {
1039
- width: 14px;
1040
- height: 14px;
1041
- }
1042
-
1043
- .whitepaper-title {
1044
- margin: 0 0 16px;
1045
- font-family: var(--mono);
1046
- font-size: clamp(28px, 4.2vw, 40px);
1047
- font-weight: 800;
1048
- line-height: 1.15;
1049
- background: linear-gradient(135deg, var(--rust) 0%, var(--amber) 50%, var(--teal) 100%);
1050
- -webkit-background-clip: text;
1051
- background-clip: text;
1052
- -webkit-text-fill-color: transparent;
1053
- color: transparent;
1054
- }
1055
-
1056
- .whitepaper-dek {
1057
- margin: 0 0 32px;
1058
- max-width: 640px;
1059
- font-size: var(--font-lg);
1060
- line-height: 1.7;
1061
- color: var(--t2);
1062
- }
1063
-
1064
- .whitepaper-dek code {
1065
- font-family: var(--mono);
1066
- font-size: 0.9em;
1067
- padding: 0.1em 0.35em;
1068
- border-radius: 3px;
1069
- background: color-mix(in oklab, var(--bg) 60%, transparent);
1070
- border: 1px solid var(--border);
1071
- }
1072
-
1073
- .whitepaper-grid {
1074
- display: grid;
1075
- grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
1076
- gap: 16px;
1077
- margin-bottom: 36px;
1078
- }
1079
-
1080
- .whitepaper-grid-item {
1081
- border-radius: 14px;
1082
- border: 1px solid var(--border);
1083
- background: color-mix(in oklab, var(--bg) 50%, transparent);
1084
- padding: 18px 20px;
1085
- }
1086
-
1087
- .whitepaper-grid-label {
1088
- font-family: var(--mono);
1089
- font-size: var(--font-2xs);
1090
- font-weight: 700;
1091
- letter-spacing: 0.18em;
1092
- text-transform: uppercase;
1093
- color: var(--amber);
1094
- margin-bottom: 8px;
1095
- }
1096
-
1097
- .whitepaper-grid-body {
1098
- font-size: var(--font-md);
1099
- line-height: 1.6;
1100
- color: var(--t2);
1101
- }
1102
-
1103
- .whitepaper-cta-row {
1104
- display: flex;
1105
- flex-wrap: wrap;
1106
- gap: 12px;
1107
- align-items: center;
1108
- }
1109
-
1110
- .whitepaper-cta-disabled {
1111
- display: inline-flex;
1112
- align-items: center;
1113
- gap: 8px;
1114
- padding: 12px 22px;
1115
- border-radius: 999px;
1116
- border: 1px solid color-mix(in oklab, var(--amber) 60%, transparent);
1117
- background: color-mix(in oklab, var(--amber) 18%, transparent);
1118
- color: var(--amber);
1119
- font-family: var(--mono);
1120
- font-size: var(--font-md);
1121
- font-weight: 700;
1122
- letter-spacing: 0.06em;
1123
- cursor: not-allowed;
1124
- opacity: 0.85;
1125
- position: relative;
1126
- }
1127
-
1128
- .whitepaper-cta-disabled::after {
1129
- content: '';
1130
- position: absolute;
1131
- inset: -2px;
1132
- border-radius: inherit;
1133
- border: 1px dashed color-mix(in oklab, var(--amber) 35%, transparent);
1134
- pointer-events: none;
1135
- }
1136
-
1137
- .whitepaper-cta-notify {
1138
- display: inline-flex;
1139
- align-items: center;
1140
- gap: 8px;
1141
- padding: 12px 22px;
1142
- border-radius: 999px;
1143
- background: var(--rust);
1144
- color: #fff;
1145
- font-family: var(--mono);
1146
- font-size: var(--font-md);
1147
- font-weight: 700;
1148
- text-decoration: none;
1149
- transition: background 0.2s ease, transform 0.2s ease;
1150
- }
1151
-
1152
- .whitepaper-cta-notify:hover {
1153
- background: color-mix(in oklab, var(--rust) 80%, var(--amber));
1154
- transform: translateY(-1px);
1155
- }
1156
-
1157
- .whitepaper-cta-secondary {
1158
- display: inline-flex;
1159
- align-items: center;
1160
- gap: 6px;
1161
- padding: 12px 18px;
1162
- border-radius: 999px;
1163
- border: 1px solid var(--border);
1164
- color: var(--t2);
1165
- font-size: var(--font-md);
1166
- text-decoration: none;
1167
- transition: border-color 0.2s ease, color 0.2s ease;
1168
- }
1169
-
1170
- .whitepaper-cta-secondary:hover {
1171
- border-color: var(--amber);
1172
- color: var(--t1);
1173
- }
1174
-
1175
938
  .banner { text-align: center; padding: 100px 24px; position: relative; }
1176
939
  .banner::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 1px; background: var(--grad); opacity: .3; }
1177
940
  .banner h2 { font-family: var(--mono); font-size: clamp(22px, 4vw, 32px); font-weight: 800; margin-bottom: 14px; }
@@ -1456,16 +1219,6 @@ html:not(.js) .rv {
1456
1219
  * step instead of staggering across a 20px window (.arch used to
1457
1220
  * collapse at 880, .scenarios at 900 — visible double reflow). */
1458
1221
  .arch { grid-template-columns: 1fr; }
1459
- .flow { flex-direction: column; align-items: stretch; gap: 28px; }
1460
- .flow-line { display: none; }
1461
- /* Desktop keeps each node at width:22% so four fit across the row. On
1462
- mobile the flex direction flips to column, but without widening the
1463
- node the 22% cap turns every stacked block into a narrow centered
1464
- strip with huge empty gutters. Let each node take the full column
1465
- width and the description paragraph read at a natural line length. */
1466
- .flow-node { width: 100%; max-width: 520px; margin: 0 auto; }
1467
- .flow-node p { max-width: none; font-size: var(--font-md); line-height: 1.6; }
1468
- .diverge { flex-direction: column; }
1469
1222
  .contact-grid { grid-template-columns: 1fr; }
1470
1223
  .hero-chips { gap: 6px; }
1471
1224
  .pricing-tiers { flex-direction: column; align-items: center; }
@@ -1477,17 +1230,6 @@ html:not(.js) .rv {
1477
1230
  .sec { padding: 64px 16px; }
1478
1231
  .hero { padding: 80px 16px 56px; }
1479
1232
  .arch-row { padding: 18px 18px; }
1480
- /* Whitepaper card: shrinks horizontal padding and stacks the CTA row
1481
- so each pill button fills the card width instead of wrapping into
1482
- an awkward 2/3-column hybrid on phones. */
1483
- .whitepaper-sec { padding: 56px 16px; }
1484
- .whitepaper-card { padding: 32px 22px; border-radius: 18px; }
1485
- .whitepaper-grid { grid-template-columns: 1fr; gap: 12px; margin-bottom: 28px; }
1486
- .whitepaper-grid-item { padding: 16px 18px; }
1487
- .whitepaper-cta-row { flex-direction: column; align-items: stretch; gap: 10px; }
1488
- .whitepaper-cta-disabled,
1489
- .whitepaper-cta-notify,
1490
- .whitepaper-cta-secondary { justify-content: center; padding: 12px 18px; }
1491
1233
  /* Banner: mobile users were seeing 100px of empty padding above and
1492
1234
  below the headline, pushing the CTA below the fold on most phones. */
1493
1235
  .banner { padding: 64px 16px; }
@@ -1521,8 +1263,6 @@ html:not(.js) .rv {
1521
1263
  }
1522
1264
 
1523
1265
  .light .arch-row { background: rgba(248, 242, 228, .7); border-color: var(--border); box-shadow: 0 2px 8px rgba(60, 40, 10, .06); }
1524
- .light .flow-ring { background: var(--bg); border-color: var(--border); }
1525
- .light .diverge-side { background: var(--bg3); border-color: var(--border); }
1526
1266
  .light .pricing-banner { background: var(--bg3); border-color: var(--border); }
1527
1267
  .light .contact-card { background: var(--bg3); border-color: var(--border); }
1528
1268
  .light .faq-item { border-bottom-color: var(--border); }
@@ -1659,277 +1399,6 @@ html:not(.js) .rv {
1659
1399
  background: rgba(232, 180, 74, 0.08) !important;
1660
1400
  }
1661
1401
 
1662
- /* ═══════════════════════════════════════════════════════════════════════════
1663
- Waitlist section
1664
- ═══════════════════════════════════════════════════════════════════════════ */
1665
- .waitlist-section {
1666
- position: relative;
1667
- padding: 96px 24px 72px;
1668
- border-top: 1px solid rgba(232, 180, 74, 0.12);
1669
- background:
1670
- radial-gradient(ellipse at 20% 0%, rgba(224, 101, 48, 0.10) 0%, transparent 55%),
1671
- radial-gradient(ellipse at 80% 100%, rgba(76, 168, 168, 0.08) 0%, transparent 55%),
1672
- linear-gradient(180deg, rgba(232, 180, 74, 0.04) 0%, transparent 60%);
1673
- scroll-margin-top: 80px;
1674
- overflow: hidden;
1675
- }
1676
- /* Subtle paracosm orbit-line accent — top hairline, gradient amber→rust→teal */
1677
- .waitlist-section::before {
1678
- content: '';
1679
- position: absolute;
1680
- top: 0;
1681
- left: 50%;
1682
- transform: translateX(-50%);
1683
- width: min(80%, 480px);
1684
- height: 1px;
1685
- background: linear-gradient(90deg,
1686
- transparent 0%,
1687
- var(--rust) 25%,
1688
- var(--amber) 50%,
1689
- var(--teal) 75%,
1690
- transparent 100%);
1691
- opacity: 0.5;
1692
- }
1693
- .waitlist-inner {
1694
- position: relative;
1695
- max-width: 640px;
1696
- margin: 0 auto;
1697
- text-align: center;
1698
- }
1699
- .waitlist-eyebrow {
1700
- display: inline-block;
1701
- font-family: var(--mono);
1702
- font-size: var(--font-xs);
1703
- font-weight: 700;
1704
- letter-spacing: 2px;
1705
- color: var(--rust);
1706
- text-transform: uppercase;
1707
- margin-bottom: 18px;
1708
- padding: 6px 14px;
1709
- border: 1px solid rgba(224, 101, 48, 0.3);
1710
- border-radius: 999px;
1711
- background: rgba(224, 101, 48, 0.06);
1712
- }
1713
- .waitlist-heading {
1714
- font-size: clamp(32px, 5vw, 48px);
1715
- font-weight: 800;
1716
- margin: 0 0 14px;
1717
- color: var(--t1);
1718
- letter-spacing: -0.02em;
1719
- line-height: 1.1;
1720
- }
1721
- .waitlist-heading-accent {
1722
- background: linear-gradient(135deg, var(--rust), var(--amber));
1723
- -webkit-background-clip: text;
1724
- background-clip: text;
1725
- -webkit-text-fill-color: transparent;
1726
- color: transparent;
1727
- }
1728
- .waitlist-sub {
1729
- font-size: 17px;
1730
- line-height: 1.6;
1731
- color: var(--t2);
1732
- margin: 0 auto 36px;
1733
- max-width: 520px;
1734
- }
1735
- .waitlist-form {
1736
- display: flex;
1737
- flex-direction: column;
1738
- gap: 16px;
1739
- text-align: left;
1740
- }
1741
- .waitlist-field {
1742
- display: flex;
1743
- flex-direction: column;
1744
- gap: 6px;
1745
- }
1746
- .waitlist-field > span {
1747
- font-family: var(--mono);
1748
- font-size: 12px;
1749
- letter-spacing: 1px;
1750
- color: var(--t3);
1751
- text-transform: uppercase;
1752
- }
1753
- .waitlist-required {
1754
- color: var(--rust);
1755
- }
1756
- .waitlist-field input,
1757
- .waitlist-field textarea,
1758
- .waitlist-field select {
1759
- background: var(--waitlist-input-bg, rgba(0, 0, 0, 0.28));
1760
- border: 1px solid var(--border);
1761
- border-radius: 8px;
1762
- padding: 13px 16px;
1763
- font-size: 15px;
1764
- color: var(--t1);
1765
- font-family: inherit;
1766
- transition: border-color 120ms ease, box-shadow 120ms ease, background 120ms ease;
1767
- resize: vertical;
1768
- }
1769
- /* Light mode: input fields go to a clean off-white card-style background
1770
- so they don't blend into the sepia section bg the way the dark-mode
1771
- "blackish overlay" does. */
1772
- html.light .waitlist-field input,
1773
- html.light .waitlist-field textarea,
1774
- html.light .waitlist-field select {
1775
- background: #fbf7ee;
1776
- box-shadow: 0 1px 0 rgba(60, 40, 10, 0.04) inset;
1777
- }
1778
- html.light .waitlist-field input:hover,
1779
- html.light .waitlist-field textarea:hover,
1780
- html.light .waitlist-field select:hover {
1781
- background: #fff;
1782
- }
1783
- html.light .waitlist-field input:focus,
1784
- html.light .waitlist-field textarea:focus,
1785
- html.light .waitlist-field select:focus {
1786
- background: #fff;
1787
- box-shadow: 0 0 0 3px rgba(142, 44, 12, 0.12);
1788
- }
1789
- .waitlist-field input::placeholder,
1790
- .waitlist-field textarea::placeholder {
1791
- color: var(--t3);
1792
- opacity: 0.7;
1793
- }
1794
- .waitlist-field input:hover,
1795
- .waitlist-field textarea:hover,
1796
- .waitlist-field select:hover {
1797
- border-color: var(--border-hl);
1798
- }
1799
- .waitlist-field input:focus,
1800
- .waitlist-field textarea:focus,
1801
- .waitlist-field select:focus {
1802
- outline: none;
1803
- border-color: var(--amber);
1804
- box-shadow: 0 0 0 3px rgba(232, 180, 74, 0.15);
1805
- background: rgba(0, 0, 0, 0.18);
1806
- }
1807
- .waitlist-field select {
1808
- appearance: none;
1809
- -webkit-appearance: none;
1810
- background-image:
1811
- linear-gradient(45deg, transparent 50%, var(--t3) 50%),
1812
- linear-gradient(135deg, var(--t3) 50%, transparent 50%);
1813
- background-position: calc(100% - 18px) 50%, calc(100% - 13px) 50%;
1814
- background-size: 5px 5px, 5px 5px;
1815
- background-repeat: no-repeat;
1816
- padding-right: 36px;
1817
- cursor: pointer;
1818
- }
1819
- .waitlist-submit {
1820
- background: linear-gradient(135deg, var(--rust), var(--amber));
1821
- color: #0a0806;
1822
- border: none;
1823
- border-radius: 6px;
1824
- padding: 14px 20px;
1825
- font-size: 15px;
1826
- font-weight: 700;
1827
- letter-spacing: 0.5px;
1828
- cursor: pointer;
1829
- display: inline-flex;
1830
- align-items: center;
1831
- justify-content: center;
1832
- gap: 8px;
1833
- transition: transform 80ms ease, opacity 120ms ease;
1834
- margin-top: 4px;
1835
- }
1836
- .waitlist-submit:hover { transform: translateY(-1px); }
1837
- .waitlist-submit:disabled { opacity: 0.6; cursor: wait; transform: none; }
1838
- .waitlist-submit svg { width: 14px; height: 14px; }
1839
- .waitlist-fineprint {
1840
- font-size: 12px;
1841
- color: var(--t3);
1842
- margin: 4px 0 0;
1843
- text-align: center;
1844
- }
1845
- .waitlist-fineprint code {
1846
- background: rgba(232, 180, 74, 0.08);
1847
- padding: 1px 5px;
1848
- border-radius: 3px;
1849
- font-size: 11px;
1850
- color: var(--amber);
1851
- }
1852
- /* Real-time field validation (the JS sets data-validity="ok|err|empty"
1853
- on each .waitlist-field element on input/blur). The static :invalid
1854
- pseudo-class fires too eagerly — it lights up empty required inputs
1855
- on first paint, which looks broken to first-time visitors. The
1856
- data-attribute lets us only show error state AFTER the user has
1857
- actually typed something. */
1858
- .waitlist-field[data-validity="ok"] input,
1859
- .waitlist-field[data-validity="ok"] textarea,
1860
- .waitlist-field[data-validity="ok"] select {
1861
- border-color: var(--green, #305a10);
1862
- padding-right: 38px;
1863
- }
1864
- .waitlist-field[data-validity="ok"] {
1865
- position: relative;
1866
- }
1867
- .waitlist-field[data-validity="ok"]::after {
1868
- content: '✓';
1869
- position: absolute;
1870
- right: 14px;
1871
- bottom: 14px;
1872
- color: var(--green, #5a8a30);
1873
- font-weight: 700;
1874
- font-size: 14px;
1875
- pointer-events: none;
1876
- }
1877
- .waitlist-field[data-validity="err"] input,
1878
- .waitlist-field[data-validity="err"] textarea {
1879
- border-color: var(--rust);
1880
- background: rgba(196, 106, 58, 0.05);
1881
- }
1882
- .waitlist-field-hint {
1883
- font-size: 11.5px;
1884
- color: var(--t3);
1885
- margin: 4px 2px 0;
1886
- font-family: var(--mono);
1887
- letter-spacing: 0.3px;
1888
- min-height: 14px;
1889
- transition: color 120ms ease;
1890
- }
1891
- .waitlist-field[data-validity="err"] .waitlist-field-hint {
1892
- color: var(--rust);
1893
- }
1894
- .waitlist-success {
1895
- text-align: center;
1896
- padding: 32px 16px;
1897
- }
1898
- .waitlist-success-icon {
1899
- width: 56px;
1900
- height: 56px;
1901
- border-radius: 50%;
1902
- background: linear-gradient(135deg, var(--rust), var(--amber));
1903
- color: #0a0806;
1904
- display: flex;
1905
- align-items: center;
1906
- justify-content: center;
1907
- font-size: 28px;
1908
- font-weight: 700;
1909
- margin: 0 auto 16px;
1910
- }
1911
- .waitlist-success h3 {
1912
- font-size: 22px;
1913
- margin: 0 0 8px;
1914
- color: var(--t1);
1915
- }
1916
- .waitlist-success p {
1917
- margin: 0;
1918
- color: var(--t2);
1919
- font-size: 15px;
1920
- line-height: 1.5;
1921
- }
1922
- .waitlist-error {
1923
- margin-top: 12px;
1924
- padding: 12px 14px;
1925
- background: rgba(224, 101, 48, 0.12);
1926
- border: 1px solid rgba(224, 101, 48, 0.4);
1927
- border-radius: 6px;
1928
- color: var(--t1);
1929
- font-size: 14px;
1930
- }
1931
- .waitlist-error strong { color: var(--rust); margin-right: 6px; }
1932
-
1933
1402
  /* Mobile: stack hero CTAs vertically below 640px */
1934
1403
  @media (max-width: 640px) {
1935
1404
  .hero-ctas {
@@ -1940,12 +1409,11 @@ html.light .waitlist-field select:focus {
1940
1409
  width: 100%;
1941
1410
  justify-content: center;
1942
1411
  }
1943
- .waitlist-section { padding: 64px 20px 40px; }
1944
1412
  }
1945
1413
 
1946
1414
  /* Mobile hero trim — page is 27k+ px tall on phones because the hero
1947
1415
  stacks logo + tagline + 3 CTAs + 5 prompt chips + demo video + sub-
1948
- paragraph + waitlist before the visitor reaches the explainer. The
1416
+ paragraph before the visitor reaches the explainer. The
1949
1417
  demo video + redundant sub-paragraph collectively eat ~700-900px of
1950
1418
  vertical real estate on a 375px-wide phone for content that's also
1951
1419
  covered by the prompts and the page below. Show a tappable "Watch