-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
1121 lines (1057 loc) · 76 KB
/
Copy pathindex.html
File metadata and controls
1121 lines (1057 loc) · 76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>LOTI — Prove when it happened</title>
<meta name="description" content="A peer-to-peer network for provable time and order. Prove that any document, photo, message, or measurement existed within a narrow window — and prove which of two events came first — with no central authority, no blockchain, and no fees. Precision scales with clock rate and network density, down to sub-second.">
<meta property="og:title" content="LOTI — Prove when it happened">
<meta property="og:description" content="Provable time and event order, without a middleman. Get a portable proof anyone can verify offline — with precision that scales down to sub-second, unlike a blockchain.">
<meta property="og:type" content="website">
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Ccircle cx='16' cy='16' r='14' fill='%23e0a63a'/%3E%3Cpath d='M9 16.5l4.5 4.5L23 11' fill='none' stroke='%230b1322' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,500;0,6..72,600;1,6..72,400;1,6..72,500&family=IBM+Plex+Mono:wght@400;500&family=IBM+Plex+Sans:wght@400;500;600&display=swap" rel="stylesheet">
<script>
// Set theme before paint to avoid a flash.
(function () {
document.documentElement.classList.add('js');
try {
var saved = localStorage.getItem('loti-theme');
var t = saved || (matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark');
document.documentElement.setAttribute('data-theme', t);
} catch (e) {}
})();
</script>
<style>
:root {
--bg: #0b1322;
--bg-2: #0e1a2e;
--surface: #12213b;
--surface-2: #16294a;
--ink: #eaf0fb;
--ink-soft: #a6b4cd;
--ink-faint: #78889f;
--line: rgba(166, 184, 214, 0.14);
--line-2: rgba(166, 184, 214, 0.28);
--accent: #e0a63a;
--accent-2: #f2bd54;
--accent-ink:#0b1322;
--verified: #52c79c;
--shadow: 0 24px 60px -28px rgba(0,0,0,0.65);
--maxw: 1280px;
--f-display: "Newsreader", Georgia, "Times New Roman", serif;
--f-body: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
--f-mono: "IBM Plex Mono", ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
}
@media (prefers-color-scheme: light) {
:root {
--bg: #eaeff7;
--bg-2: #f3f6fb;
--surface: #ffffff;
--surface-2: #f6f8fc;
--ink: #0f1a2c;
--ink-soft: #43526c;
--ink-faint: #74839b;
--line: rgba(24, 46, 86, 0.12);
--line-2: rgba(24, 46, 86, 0.22);
--accent: #b17a17;
--accent-2: #d6971f;
--accent-ink:#1a1204;
--verified: #16855e;
--shadow: 0 22px 50px -30px rgba(20,40,80,0.45);
}
}
:root[data-theme="light"] {
--bg: #eaeff7;
--bg-2: #f3f6fb;
--surface: #ffffff;
--surface-2: #f6f8fc;
--ink: #0f1a2c;
--ink-soft: #43526c;
--ink-faint: #74839b;
--line: rgba(24, 46, 86, 0.12);
--line-2: rgba(24, 46, 86, 0.22);
--accent: #b17a17;
--accent-2: #d6971f;
--accent-ink:#1a1204;
--verified: #16855e;
--shadow: 0 22px 50px -30px rgba(20,40,80,0.45);
}
:root[data-theme="dark"] {
--bg: #0b1322;
--bg-2: #0e1a2e;
--surface: #12213b;
--surface-2: #16294a;
--ink: #eaf0fb;
--ink-soft: #a6b4cd;
--ink-faint: #78889f;
--line: rgba(166, 184, 214, 0.14);
--line-2: rgba(166, 184, 214, 0.28);
--accent: #e0a63a;
--accent-2: #f2bd54;
--accent-ink:#0b1322;
--verified: #52c79c;
--shadow: 0 24px 60px -28px rgba(0,0,0,0.65);
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
body {
margin: 0;
background: var(--bg);
color: var(--ink);
font-family: var(--f-body);
font-size: 1.0625rem;
line-height: 1.65;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
overflow-x: hidden;
}
h1, h2, h3 { font-family: var(--f-display); font-weight: 500; line-height: 1.08; text-wrap: balance; margin: 0; letter-spacing: -0.012em; }
p { margin: 0; }
a { color: inherit; }
::selection { background: var(--accent); color: var(--accent-ink); }
.wrap { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: clamp(1.15rem, 4vw, 2.5rem); }
.eyebrow {
font-family: var(--f-mono);
font-size: 0.72rem;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--accent);
margin: 0 0 1rem;
display: flex; align-items: center; gap: 0.7rem;
}
.eyebrow::before { content: ""; width: 26px; height: 1px; background: var(--accent); opacity: 0.7; }
/* ---------- buttons ---------- */
.btn {
display: inline-flex; align-items: center; gap: 0.55rem;
font-family: var(--f-body); font-weight: 600; font-size: 0.98rem;
padding: 0.8rem 1.35rem; border-radius: 2px;
border: 1px solid transparent; cursor: pointer; text-decoration: none;
transition: transform .16s ease, background .16s ease, border-color .16s ease, color .16s ease;
white-space: nowrap;
}
.btn svg { width: 18px; height: 18px; }
.btn-primary { background: var(--accent); color: var(--accent-ink); }
.btn-primary:hover { background: var(--accent-2); transform: translateY(-2px); }
.btn-ghost { border-color: var(--line-2); color: var(--ink); background: transparent; }
.btn-ghost:hover { border-color: var(--accent); color: var(--accent); transform: translateY(-2px); }
a:focus-visible, button:focus-visible, summary:focus-visible {
outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 2px;
}
/* ---------- header ---------- */
header {
position: sticky; top: 0; z-index: 40;
background: color-mix(in srgb, var(--bg) 82%, transparent);
backdrop-filter: blur(12px);
border-bottom: 1px solid var(--line);
}
.nav { display: flex; align-items: center; justify-content: space-between; height: 66px; }
.brand { display: flex; align-items: center; gap: 0.6rem; font-family: var(--f-mono); font-weight: 500; letter-spacing: 0.16em; text-transform: uppercase; font-size: 0.92rem; text-decoration: none; color: var(--ink); }
.brand .seal { width: 22px; height: 22px; flex: none; }
.nav-links { display: flex; align-items: center; gap: 1.9rem; }
.nav-links a { font-size: 0.92rem; text-decoration: none; color: var(--ink-soft); transition: color .15s ease; }
.nav-links a:hover { color: var(--ink); }
.nav-right { display: flex; align-items: center; gap: 1rem; }
.theme-toggle {
display: inline-grid; place-items: center; width: 38px; height: 38px;
border: 1px solid var(--line-2); border-radius: 2px; background: transparent; color: var(--ink-soft); cursor: pointer;
transition: color .15s ease, border-color .15s ease;
}
.theme-toggle:hover { color: var(--accent); border-color: var(--accent); }
.theme-toggle svg { width: 18px; height: 18px; }
:root[data-theme="dark"] .icon-sun { display: block; }
:root[data-theme="dark"] .icon-moon { display: none; }
:root[data-theme="light"] .icon-sun { display: none; }
:root[data-theme="light"] .icon-moon { display: block; }
@media (max-width: 860px) { .nav-links { display: none; } }
/* ---------- hero ---------- */
.hero { position: relative; overflow: hidden; border-bottom: 1px solid var(--line); }
#lattice { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; display: block; }
.hero-veil {
position: absolute; inset: 0; z-index: 1; pointer-events: none;
background:
radial-gradient(120% 90% at 78% 15%, transparent 40%, var(--bg) 100%),
linear-gradient(180deg, transparent 55%, var(--bg) 100%);
}
.hero-inner { position: relative; z-index: 2; display: grid; grid-template-columns: 1.15fr 0.85fr; gap: clamp(2rem, 5vw, 4rem); align-items: center; padding-block: clamp(4rem, 10vw, 7.5rem); }
.hero h1 { font-size: clamp(2.7rem, 6.2vw, 4.7rem); font-weight: 500; }
.hero h1 em { font-style: italic; color: var(--accent); }
.hero .lead { color: var(--ink-soft); font-size: clamp(1.1rem, 1.55vw, 1.32rem); line-height: 1.6; margin-top: 1.5rem; max-width: 40ch; }
.hero-cta { display: flex; flex-wrap: wrap; gap: 0.8rem; margin-top: 2.2rem; }
.trust-strip { display: flex; flex-wrap: wrap; gap: 0.5rem 1.4rem; margin-top: 2.2rem; font-family: var(--f-mono); font-size: 0.76rem; letter-spacing: 0.06em; color: var(--ink-faint); text-transform: uppercase; }
.trust-strip span { display: inline-flex; align-items: center; gap: 0.5rem; }
.trust-strip span::before { content: ""; width: 5px; height: 5px; background: var(--accent); border-radius: 50%; }
/* proof card device */
.proof {
background: color-mix(in srgb, var(--surface) 88%, transparent);
border: 1px solid var(--line-2);
border-radius: 6px; padding: 1.35rem 1.4rem 1.25rem;
box-shadow: var(--shadow);
font-family: var(--f-mono); font-size: 0.86rem;
backdrop-filter: blur(6px);
}
.proof-head { display: flex; align-items: center; justify-content: space-between; border-bottom: 1px solid var(--line); padding-bottom: 0.75rem; margin-bottom: 0.9rem; }
.proof-head .tag { letter-spacing: 0.18em; text-transform: uppercase; font-size: 0.7rem; color: var(--ink-faint); }
.proof-row { display: flex; justify-content: space-between; gap: 1rem; padding: 0.28rem 0; color: var(--ink-soft); }
.proof-row b { color: var(--ink); font-weight: 500; }
.proof-win { color: var(--accent); font-variant-numeric: tabular-nums; }
.proof-valid {
display: inline-flex; align-items: center; gap: 0.5rem; margin-top: 1rem;
color: var(--verified); border: 1px solid color-mix(in srgb, var(--verified) 45%, transparent);
background: color-mix(in srgb, var(--verified) 12%, transparent);
border-radius: 3px; padding: 0.4rem 0.7rem; font-size: 0.76rem; letter-spacing: 0.08em; text-transform: uppercase;
}
.proof-valid svg { width: 15px; height: 15px; }
@media (max-width: 900px) {
.hero-inner { grid-template-columns: 1fr; }
.proof { max-width: 420px; }
}
/* ---------- sections ---------- */
section { padding-block: clamp(4rem, 9vw, 7rem); }
.section-alt { background: var(--bg-2); border-block: 1px solid var(--line); }
.section-head { max-width: 92ch; margin-bottom: 3rem; }
.section-head h2 { font-size: clamp(1.95rem, 3.6vw, 2.9rem); }
.section-head p { color: var(--ink-soft); font-size: 1.12rem; margin-top: 1.1rem; }
.subhead { font-family: var(--f-display); font-weight: 500; letter-spacing: -0.012em; font-size: clamp(1.4rem, 2.4vw, 1.9rem); margin: 3.6rem 0 1.7rem; }
.fine { color: var(--ink-faint); font-size: 0.92rem; margin-top: 1.15rem; max-width: 96ch; }
.fine b { color: var(--accent); font-weight: 500; }
.lede { max-width: 92ch; }
.lede p + p { margin-top: 1.2rem; }
.lede .drop { color: var(--ink); font-family: var(--f-display); font-size: clamp(1.35rem, 2.3vw, 1.7rem); line-height: 1.5; }
.lede .drop b { color: var(--accent); font-weight: 500; font-style: italic; }
/* ---------- chain figure ---------- */
.chain-fig { margin-top: 2.6rem; }
.chain-fig .frame {
background: var(--surface); border: 1px solid var(--line);
border-radius: 10px; padding: 1.4rem 1.5rem 1rem; box-shadow: var(--shadow);
overflow-x: auto; max-width: 780px; margin-inline: auto;
}
.chain-svg { display: block; width: 100%; min-width: 560px; height: auto; }
.chain-fig figcaption {
margin-top: 1rem; color: var(--ink-soft); font-size: 0.95rem;
max-width: 62ch; margin-inline: auto; text-align: center;
}
.chain-fig figcaption b { color: var(--accent); font-weight: 500; }
/* svg element classes */
.cf-axis { stroke: var(--line-2); stroke-width: 1; fill: none; }
.cf-arrowhead { fill: var(--ink-faint); }
.cf-mesh { stroke: var(--line-2); stroke-width: 1; opacity: 0.55; }
.cf-chain { fill: none; stroke: var(--accent); stroke-width: 2.4; stroke-linejoin: round; stroke-linecap: round; }
.cf-box { fill: var(--surface-2); stroke: var(--line-2); stroke-width: 1; }
.cf-box-chain { fill: color-mix(in srgb, var(--accent) 16%, var(--surface)); stroke: var(--accent); stroke-width: 1.4; }
.cf-box-lbl { fill: var(--ink-soft); font-family: var(--f-mono); font-size: 12px; }
.cf-box-lbl-chain { fill: var(--ink); }
.cf-event { fill: var(--accent); stroke: var(--accent); }
.cf-event-lbl { fill: var(--accent-ink); font-family: var(--f-mono); font-size: 12px; font-weight: 500; }
.cf-nodelbl { fill: var(--ink-soft); font-family: var(--f-mono); font-size: 13px; }
.cf-annot { fill: var(--ink-faint); font-family: var(--f-mono); font-size: 11px; }
.cf-annot-event { fill: var(--accent); }
.cf-bound-drop { stroke: var(--accent); stroke-width: 1; stroke-dasharray: 3 3; opacity: 0.7; }
.cf-bound-lbl { fill: var(--accent); font-family: var(--f-mono); font-size: 10.5px; letter-spacing: 0.04em; }
/* grids */
.grid { display: grid; gap: 1.15rem; }
.g-3 { grid-template-columns: repeat(3, 1fr); }
.g-2 { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 900px) { .g-3 { grid-template-columns: 1fr 1fr; } }
@media (max-width: 620px) { .g-3, .g-2 { grid-template-columns: 1fr; } }
.card {
background: var(--surface); border: 1px solid var(--line);
border-radius: 8px; padding: 1.6rem 1.55rem;
transition: transform .18s ease, border-color .18s ease, background .18s ease;
}
.card:hover { transform: translateY(-3px); border-color: var(--line-2); }
.card .ico { width: 40px; height: 40px; display: grid; place-items: center; border: 1px solid var(--line-2); border-radius: 8px; color: var(--accent); margin-bottom: 1.15rem; }
.card .ico svg { width: 22px; height: 22px; }
.card h3 { font-size: 1.28rem; margin-bottom: 0.55rem; }
.card p { color: var(--ink-soft); font-size: 0.99rem; }
.fail .ico { color: var(--ink-soft); }
/* steps */
.steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.1rem; counter-reset: step; }
@media (max-width: 900px) { .steps { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .steps { grid-template-columns: 1fr; } }
.step { position: relative; padding: 1.6rem 1.4rem; background: var(--surface); border: 1px solid var(--line); border-radius: 8px; }
.step .num { font-family: var(--f-mono); font-size: 0.8rem; color: var(--accent); letter-spacing: 0.1em; margin-bottom: 0.9rem; }
.step h3 { font-size: 1.18rem; margin-bottom: 0.5rem; }
.step p { color: var(--ink-soft); font-size: 0.96rem; }
/* benefits */
.benefits { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.4rem 2.4rem; }
@media (max-width: 820px) { .benefits { grid-template-columns: 1fr 1fr; } }
@media (max-width: 520px) { .benefits { grid-template-columns: 1fr; } }
.benefit { display: flex; gap: 0.9rem; padding: 1.1rem 0; border-top: 1px solid var(--line); }
.benefit svg { width: 20px; height: 20px; color: var(--accent); flex: none; margin-top: 0.2rem; }
.benefit h3 { font-family: var(--f-body); font-weight: 600; font-size: 1.02rem; letter-spacing: 0; }
.benefit p { color: var(--ink-soft); font-size: 0.94rem; margin-top: 0.15rem; }
/* quickstart terminals */
.quickstart-grid { display: grid; grid-template-columns: 1.12fr 1fr; gap: 1.1rem; align-items: start; }
@media (max-width: 820px) { .quickstart-grid { grid-template-columns: 1fr; } }
.terminal { background: var(--surface); border: 1px solid var(--line); border-radius: 10px; overflow: hidden; box-shadow: var(--shadow); }
.term-head { display: flex; align-items: center; gap: 0.7rem; padding: 0.68rem 1rem; background: var(--surface-2); border-bottom: 1px solid var(--line); }
.term-dots { display: flex; gap: 0.4rem; }
.term-dots span { width: 11px; height: 11px; border-radius: 50%; background: var(--line-2); }
.term-label { font-family: var(--f-mono); font-size: 0.74rem; letter-spacing: 0.07em; text-transform: uppercase; color: var(--ink-faint); }
.term-body { margin: 0; padding: 1.15rem 1.2rem; overflow-x: auto; font-family: var(--f-mono); font-size: 0.8rem; line-height: 1.7; color: var(--ink); white-space: pre; }
.term-body .c { color: var(--ink-faint); }
.term-body .p { color: var(--accent); font-weight: 500; }
.term-body .o { color: var(--ink-soft); }
.term-body b { color: var(--verified); font-weight: 500; }
code { font-family: var(--f-mono); font-size: 0.88em; background: var(--surface-2); border: 1px solid var(--line); border-radius: 4px; padding: 0.08em 0.36em; color: var(--ink); }
/* comparison table */
.table-scroll { overflow-x: auto; border: 1px solid var(--line); border-radius: 8px; }
table { border-collapse: collapse; width: 100%; min-width: 620px; font-size: 0.98rem; }
th, td { text-align: left; padding: 1rem 1.15rem; border-bottom: 1px solid var(--line); }
thead th { font-family: var(--f-mono); font-size: 0.74rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-faint); font-weight: 500; }
tbody th { font-weight: 600; color: var(--ink); }
td { color: var(--ink-soft); }
.col-loti { background: color-mix(in srgb, var(--accent) 9%, transparent); color: var(--ink); font-weight: 500; }
thead .col-loti { color: var(--accent); }
tr:last-child td, tr:last-child th { border-bottom: none; }
/* costs / benefits two-up */
.ledger { display: grid; grid-template-columns: 1fr 1fr; gap: 1.15rem; }
@media (max-width: 720px) { .ledger { grid-template-columns: 1fr; } }
.ledger .panel { border: 1px solid var(--line); border-radius: 8px; padding: 1.7rem 1.6rem; background: var(--surface); }
.ledger h3 { font-family: var(--f-mono); font-weight: 500; text-transform: uppercase; letter-spacing: 0.14em; font-size: 0.78rem; margin-bottom: 1.2rem; color: var(--ink-faint); }
.ledger ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.85rem; }
.ledger li { display: flex; gap: 0.75rem; color: var(--ink-soft); font-size: 0.99rem; }
.ledger li svg { width: 18px; height: 18px; flex: none; margin-top: 0.25rem; }
.ledger .cost li svg { color: var(--ink-faint); }
.ledger .gain li svg { color: var(--accent); }
.ledger .gain { border-color: var(--line-2); }
/* CTA band */
.cta-band { text-align: center; }
.cta-band h2 { font-size: clamp(2rem, 4vw, 3rem); }
.cta-band p { color: var(--ink-soft); font-size: 1.14rem; margin: 1.1rem auto 2.2rem; max-width: 48ch; }
.cta-band .hero-cta { justify-content: center; }
/* FAQ */
.faq { max-width: none; }
details { border-bottom: 1px solid var(--line); }
summary { cursor: pointer; list-style: none; padding: 1.35rem 0; display: flex; justify-content: space-between; align-items: center; gap: 1.5rem; font-family: var(--f-display); font-size: 1.22rem; font-weight: 500; }
summary::-webkit-details-marker { display: none; }
summary .plus { flex: none; width: 22px; height: 22px; position: relative; transition: transform .22s ease; color: var(--accent); }
summary .plus::before, summary .plus::after { content: ""; position: absolute; background: currentColor; }
summary .plus::before { left: 0; right: 0; top: 10px; height: 2px; }
summary .plus::after { top: 0; bottom: 0; left: 10px; width: 2px; transition: transform .22s ease; }
details[open] summary .plus::after { transform: scaleY(0); }
details p { color: var(--ink-soft); padding: 0 0 1.4rem; max-width: 68ch; }
/* footer */
footer { border-top: 1px solid var(--line); background: var(--bg-2); padding-block: 3.5rem 2.5rem; }
.foot-top { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 2rem; }
.foot-brand { max-width: 34ch; }
.foot-brand .brand { margin-bottom: 0.9rem; }
.foot-brand p { color: var(--ink-soft); font-size: 0.96rem; }
.foot-links { display: flex; gap: 3.5rem; flex-wrap: wrap; }
.foot-col h4 { font-family: var(--f-mono); font-size: 0.72rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--ink-faint); font-weight: 500; margin: 0 0 0.9rem; }
.foot-col a { display: block; color: var(--ink-soft); text-decoration: none; font-size: 0.95rem; padding: 0.3rem 0; transition: color .15s ease; }
.foot-col a:hover { color: var(--accent); }
.foot-bottom { margin-top: 2.6rem; padding-top: 1.6rem; border-top: 1px solid var(--line); display: flex; flex-wrap: wrap; justify-content: space-between; gap: 1rem; color: var(--ink-faint); font-family: var(--f-mono); font-size: 0.78rem; }
/* reveal */
.js .reveal { opacity: 0; transform: translateY(18px); transition: opacity .7s ease, transform .7s ease; }
.js .reveal.is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
.js .reveal { opacity: 1; transform: none; transition: none; }
.btn:hover, .card:hover { transform: none; }
}
</style>
</head>
<body>
<header>
<div class="wrap nav">
<a class="brand" href="#top">
<svg class="seal" viewBox="0 0 32 32" aria-hidden="true"><circle cx="16" cy="16" r="13.5" fill="none" stroke="var(--accent)" stroke-width="2"/><path d="M9.5 16.5l4.4 4.4L22.7 12" fill="none" stroke="var(--accent)" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
LOTI
</a>
<nav class="nav-links" aria-label="Primary">
<a href="#problem">The problem</a>
<a href="#idea">The idea</a>
<a href="#proof">The proof</a>
<a href="#uses">Use cases</a>
<a href="#compare">Compare</a>
<a href="#quickstart">Quickstart</a>
<a href="#faq">FAQ</a>
</nav>
<div class="nav-right">
<button class="theme-toggle" id="themeToggle" type="button" aria-label="Toggle light and dark theme">
<svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" aria-hidden="true"><circle cx="12" cy="12" r="4.2"/><path d="M12 2.5v2.4M12 19.1v2.4M4.6 4.6l1.7 1.7M17.7 17.7l1.7 1.7M2.5 12h2.4M19.1 12h2.4M4.6 19.4l1.7-1.7M17.7 6.3l1.7-1.7"/></svg>
<svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20.5 14.2A8.2 8.2 0 1 1 10.4 3.9a6.6 6.6 0 0 0 10.1 10.3z"/></svg>
</button>
<a class="btn btn-ghost" href="https://github.com/levy/loti" target="_blank" rel="noopener">
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 1.7A10.3 10.3 0 0 0 8.7 21.8c.5.1.7-.2.7-.5v-1.8c-2.9.6-3.5-1.2-3.5-1.2-.5-1.2-1.1-1.5-1.1-1.5-.9-.6.1-.6.1-.6 1 .1 1.6 1 1.6 1 .9 1.6 2.4 1.1 3 .9.1-.7.4-1.1.6-1.4-2.3-.3-4.7-1.1-4.7-5 0-1.1.4-2 1-2.7-.1-.3-.5-1.3.1-2.7 0 0 .8-.3 2.7 1a9.4 9.4 0 0 1 5 0c1.9-1.3 2.7-1 2.7-1 .6 1.4.2 2.4.1 2.7.6.7 1 1.6 1 2.7 0 3.9-2.4 4.7-4.7 5 .4.3.7 1 .7 2v3c0 .3.2.6.7.5A10.3 10.3 0 0 0 12 1.7z"/></svg>
GitHub
</a>
</div>
</div>
</header>
<main id="top">
<!-- HERO -->
<section class="hero">
<canvas id="lattice" aria-hidden="true"></canvas>
<div class="hero-veil" aria-hidden="true"></div>
<div class="wrap hero-inner">
<div>
<p class="eyebrow">Proof of when · peer‑to‑peer · no middleman</p>
<h1>Prove <em>when</em> it happened.<br>To anyone. Without<br>trusting anyone.</h1>
<p class="lead">LOTI links every digital event into a shared, hash-linked record of time — so you can prove both <em>when</em> a document, photo, message, or measurement existed, to within a narrow window, and <em>which of two events came first</em>. Not just a timestamp: a verifiable ordering of events.</p>
<div class="hero-cta">
<a class="btn btn-primary" href="https://docs.google.com/document/d/1KmdknFYkGlxhLoKOQb9g14LW4Jg7zIReaa_GsB5aJio" target="_blank" rel="noopener">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 5.5A2.5 2.5 0 0 1 6.5 3H18a2 2 0 0 1 2 2v13.5"/><path d="M6.5 21A2.5 2.5 0 0 1 4 18.5v-13"/><path d="M6.5 21H20V5"/><path d="M8 8h8M8 12h6"/></svg>
Read the whitepaper
</a>
<a class="btn btn-ghost" href="https://github.com/levy/loti" target="_blank" rel="noopener">
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 1.7A10.3 10.3 0 0 0 8.7 21.8c.5.1.7-.2.7-.5v-1.8c-2.9.6-3.5-1.2-3.5-1.2-.5-1.2-1.1-1.5-1.1-1.5-.9-.6.1-.6.1-.6 1 .1 1.6 1 1.6 1 .9 1.6 2.4 1.1 3 .9.1-.7.4-1.1.6-1.4-2.3-.3-4.7-1.1-4.7-5 0-1.1.4-2 1-2.7-.1-.3-.5-1.3.1-2.7 0 0 .8-.3 2.7 1a9.4 9.4 0 0 1 5 0c1.9-1.3 2.7-1 2.7-1 .6 1.4.2 2.4.1 2.7.6.7 1 1.6 1 2.7 0 3.9-2.4 4.7-4.7 5 .4.3.7 1 .7 2v3c0 .3.2.6.7.5A10.3 10.3 0 0 0 12 1.7z"/></svg>
View the code
</a>
</div>
<div class="trust-strip">
<span>Permissionless</span><span>Trustless</span><span>Private</span><span>Practically free</span>
</div>
</div>
<div class="proof" role="img" aria-label="Example proof: event created between 10:31:02 and 10:31:39, verified valid.">
<div class="proof-head">
<span class="tag">Portable proof · time bounds</span>
<span style="color:var(--accent)">◷</span>
</div>
<div class="proof-row"><span>event</span><b>manuscript.pdf</b></div>
<div class="proof-row"><span>existed after</span><b class="proof-win">2026‑07‑17 10:31:02</b></div>
<div class="proof-row"><span>existed before</span><b class="proof-win">2026‑07‑17 10:31:39</b></div>
<div class="proof-row"><span>window</span><b>37 seconds</b></div>
<div class="proof-row"><span>reference clock</span><b>a notary you trust</b></div>
<div class="proof-valid">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 12.5l5 5L20 6.5"/></svg>
Valid · signature ok · verified offline
</div>
</div>
</div>
</section>
<!-- PROBLEM -->
<section id="problem" class="section-alt">
<div class="wrap">
<div class="section-head reveal">
<p class="eyebrow">The problem</p>
<h2>A digital timestamp is just a number. And numbers can be changed.</h2>
<p>When the timing truly matters — who invented it first, whether the contract was signed by the deadline, when the footage was really shot — we fall back on trusting <em>someone</em>: a platform, a server, a notary, a screenshot. Every one of those is a single point of trust, failure, and dispute.</p>
</div>
<div class="grid g-3">
<div class="card fail reveal">
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 20l4-1L19.5 7.5a2.1 2.1 0 0 0-3-3L5 16l-1 4z"/><path d="M13.5 6.5l3 3"/></svg></div>
<h3>Timestamps are editable</h3>
<p>The "date created" on a file, an email header, a post — all of them can be set to anything. Proof needs more than a claim.</p>
</div>
<div class="card fail reveal">
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l7 3v5c0 4.4-3 7.6-7 9-4-1.4-7-4.6-7-9V6l7-3z"/><path d="M9.5 12.5l-1.5 3 4-2"/></svg></div>
<h3>Authorities can fail</h3>
<p>A central timestamping service can go dark, be hacked, be pressured, or simply be disbelieved by the other side. Trust is a liability.</p>
</div>
<div class="card fail reveal">
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3c2.5 2.6 2.5 15.4 0 18M12 3c-2.5 2.6-2.5 15.4 0 18"/></svg></div>
<h3>Blockchains overshoot</h3>
<p>They can timestamp — but they're public, slow, and cost a fee every time. Overkill for something that should be quiet and free.</p>
</div>
</div>
</div>
</section>
<!-- IDEA -->
<section id="idea">
<div class="wrap">
<div class="section-head reveal">
<p class="eyebrow">The idea</p>
<h2>A clock nobody owns.</h2>
</div>
<div class="lede reveal">
<p class="drop">Instead of one clock everyone has to trust, LOTI has every node keep time together. About once a second each node emits a small signed record called a <b>clock event</b>, and each one embeds a few hashes: the node's own previous clock event, and the most recent clock events it has heard from its neighbors.</p>
<p>Those hashes are the links. Pointing back at its own previous clock event puts each node's ticks in order; referencing its neighbors' clock events stitches the separate timelines together. Taken as a whole, this is one ever-growing, hash-linked graph — a directed acyclic graph, or DAG — in which every link means "this record already existed when that one was made." Only the <em>hash</em> of each clock event goes on the wire, sent over UDP to a handful of direct neighbors, so almost nothing about your machine leaves it.</p>
<p>The graph only ever grows at the front, and that is what makes it tamper-evident. Change anything already inside it and every hash computed from it stops matching — on your machine and on every neighbor that kept a copy. Nobody has to enforce a rule; the hashes simply stop lining up. That is the concrete reason you can't forge the past and can't pre-compute the future.</p>
<p>There's no global vote and no single winner. Each node assembles its own view of the graph from what it hears, and any two views can be lined up wherever they overlap. Nodes never have to agree on one timeline — only, link by link, on what came before what. So two nodes can hold different views and still never prove a <em>contradiction</em>.</p>
<p><b>Two proofs from one graph.</b> LOTI is a timestamping network — and the same graph also proves <em>which event came before which</em>, a tamper-proof <em>happened-before</em> ordering. Often you don't even need a clock for that: two events can be ordered against each other even when neither carries a trusted timestamp. Attach a reference clock and the ordering reads out as a date; leave it off and the order still holds.</p>
</div>
</div>
</section>
<!-- PROOF -->
<section id="proof" class="section-alt">
<div class="wrap">
<div class="section-head reveal">
<p class="eyebrow">Anatomy of a proof</p>
<h2>A chain that begins and ends at your own clock.</h2>
</div>
<div class="lede reveal">
<p class="drop">A proof is a <b>chain</b> of those hash links. It sets out from a clock event of the reference you trust, threads through clock events of nodes across the network, reaches the event in question, and returns to a later clock event of that same reference — pinning the event between one tick that provably came <b>before</b> it and one that provably came <b>after</b>.</p>
<p>Publishing an event staples it into the graph. The event embeds the hash of a recent local clock event, which places it <em>after</em> that tick; the next clock events its node emits reference the event back, placing it <em>before</em> those. So moments after it is published, the event already sits bracketed by earlier and later clock events — each of which is, in turn, linked to its neighbors'.</p>
<p>To read that as a time, a node follows the links from one of <em>its own</em> clock events, hop by hop, out to the target event and back to a second clock event of its own. Because both ends are ticks of a clock it chose to measure against — its own, a lab's, a notary's — those two bracketing ticks are the lower and upper bound, and the reference clock is what turns them into a date you can read. Nothing in the chain is asserted after the fact; it is a record of links that already existed, in the only order their hashes allow, which is why it can't be re-told two ways.</p>
</div>
<figure class="chain-fig reveal">
<div class="frame">
<svg class="chain-svg" viewBox="0 0 760 340" role="img" aria-label="A proof chain: the event E1 of node N1 is bracketed between clock events C1 and C6 of node N3, threading through the network from N3 up to the event and back down to N3.">
<defs><marker id="cf-arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse"><path d="M0 0L10 5L0 10z" class="cf-arrowhead"/></marker></defs>
<line class="cf-axis" x1="58" y1="95" x2="702" y2="95" marker-end="url(#cf-arrow)"/>
<text class="cf-nodelbl" x="40" y="99" text-anchor="middle">N<tspan dy="3" font-size="0.7em">1</tspan></text>
<line class="cf-axis" x1="58" y1="180" x2="702" y2="180" marker-end="url(#cf-arrow)"/>
<text class="cf-nodelbl" x="40" y="184" text-anchor="middle">N<tspan dy="3" font-size="0.7em">2</tspan></text>
<line class="cf-axis" x1="58" y1="265" x2="702" y2="265" marker-end="url(#cf-arrow)"/>
<text class="cf-nodelbl" x="40" y="269" text-anchor="middle">N<tspan dy="3" font-size="0.7em">3</tspan></text>
<line class="cf-axis" x1="58" y1="300" x2="702" y2="300" marker-end="url(#cf-arrow)"/>
<text class="cf-annot" x="710" y="304" text-anchor="start">t</text>
<line class="cf-mesh" x1="108" y1="180" x2="150" y2="95"/>
<line class="cf-mesh" x1="225" y1="180" x2="150" y2="95"/>
<line class="cf-mesh" x1="315" y1="180" x2="300" y2="95"/>
<line class="cf-mesh" x1="315" y1="180" x2="380" y2="95"/>
<line class="cf-mesh" x1="405" y1="180" x2="380" y2="95"/>
<line class="cf-mesh" x1="405" y1="180" x2="470" y2="95"/>
<line class="cf-mesh" x1="495" y1="180" x2="470" y2="95"/>
<line class="cf-mesh" x1="560" y1="180" x2="470" y2="95"/>
<line class="cf-mesh" x1="560" y1="180" x2="650" y2="95"/>
<line class="cf-mesh" x1="665" y1="180" x2="650" y2="95"/>
<line class="cf-mesh" x1="92" y1="265" x2="108" y2="180"/>
<line class="cf-mesh" x1="92" y1="265" x2="225" y2="180"/>
<line class="cf-mesh" x1="205" y1="265" x2="225" y2="180"/>
<line class="cf-mesh" x1="205" y1="265" x2="315" y2="180"/>
<line class="cf-mesh" x1="320" y1="265" x2="315" y2="180"/>
<line class="cf-mesh" x1="320" y1="265" x2="405" y2="180"/>
<line class="cf-mesh" x1="430" y1="265" x2="405" y2="180"/>
<line class="cf-mesh" x1="430" y1="265" x2="495" y2="180"/>
<line class="cf-mesh" x1="520" y1="265" x2="495" y2="180"/>
<line class="cf-mesh" x1="520" y1="265" x2="560" y2="180"/>
<line class="cf-mesh" x1="632" y1="265" x2="560" y2="180"/>
<line class="cf-mesh" x1="632" y1="265" x2="665" y2="180"/>
<polyline class="cf-chain" points="92,265 225,180 315,180 380,95 425,35 470,95 560,180 632,265"/>
<line class="cf-bound-drop" x1="92" y1="276.0" x2="92" y2="300"/>
<text class="cf-bound-lbl" x="92" y="318" text-anchor="middle">lower bound</text>
<line class="cf-bound-drop" x1="632" y1="276.0" x2="632" y2="300"/>
<text class="cf-bound-lbl" x="632" y="318" text-anchor="middle">upper bound</text>
<rect class="cf-box" x="134.0" y="84.0" width="32" height="22" rx="4"/>
<text class="cf-box-lbl" x="150" y="99" text-anchor="middle">C<tspan dy="3" font-size="0.7em">1</tspan></text>
<rect class="cf-box" x="284.0" y="84.0" width="32" height="22" rx="4"/>
<text class="cf-box-lbl" x="300" y="99" text-anchor="middle">C<tspan dy="3" font-size="0.7em">2</tspan></text>
<rect class="cf-box cf-box-chain" x="364.0" y="84.0" width="32" height="22" rx="4"/>
<text class="cf-box-lbl cf-box-lbl-chain" x="380" y="99" text-anchor="middle">C<tspan dy="3" font-size="0.7em">3</tspan></text>
<rect class="cf-box cf-box-chain" x="454.0" y="84.0" width="32" height="22" rx="4"/>
<text class="cf-box-lbl cf-box-lbl-chain" x="470" y="99" text-anchor="middle">C<tspan dy="3" font-size="0.7em">4</tspan></text>
<rect class="cf-box" x="634.0" y="84.0" width="32" height="22" rx="4"/>
<text class="cf-box-lbl" x="650" y="99" text-anchor="middle">C<tspan dy="3" font-size="0.7em">5</tspan></text>
<rect class="cf-box" x="92.0" y="169.0" width="32" height="22" rx="4"/>
<text class="cf-box-lbl" x="108" y="184" text-anchor="middle">C<tspan dy="3" font-size="0.7em">1</tspan></text>
<rect class="cf-box cf-box-chain" x="209.0" y="169.0" width="32" height="22" rx="4"/>
<text class="cf-box-lbl cf-box-lbl-chain" x="225" y="184" text-anchor="middle">C<tspan dy="3" font-size="0.7em">2</tspan></text>
<rect class="cf-box cf-box-chain" x="299.0" y="169.0" width="32" height="22" rx="4"/>
<text class="cf-box-lbl cf-box-lbl-chain" x="315" y="184" text-anchor="middle">C<tspan dy="3" font-size="0.7em">3</tspan></text>
<rect class="cf-box" x="389.0" y="169.0" width="32" height="22" rx="4"/>
<text class="cf-box-lbl" x="405" y="184" text-anchor="middle">C<tspan dy="3" font-size="0.7em">4</tspan></text>
<rect class="cf-box" x="479.0" y="169.0" width="32" height="22" rx="4"/>
<text class="cf-box-lbl" x="495" y="184" text-anchor="middle">C<tspan dy="3" font-size="0.7em">5</tspan></text>
<rect class="cf-box cf-box-chain" x="544.0" y="169.0" width="32" height="22" rx="4"/>
<text class="cf-box-lbl cf-box-lbl-chain" x="560" y="184" text-anchor="middle">C<tspan dy="3" font-size="0.7em">6</tspan></text>
<rect class="cf-box" x="649.0" y="169.0" width="32" height="22" rx="4"/>
<text class="cf-box-lbl" x="665" y="184" text-anchor="middle">C<tspan dy="3" font-size="0.7em">7</tspan></text>
<rect class="cf-box cf-box-chain" x="76.0" y="254.0" width="32" height="22" rx="4"/>
<text class="cf-box-lbl cf-box-lbl-chain" x="92" y="269" text-anchor="middle">C<tspan dy="3" font-size="0.7em">1</tspan></text>
<rect class="cf-box" x="189.0" y="254.0" width="32" height="22" rx="4"/>
<text class="cf-box-lbl" x="205" y="269" text-anchor="middle">C<tspan dy="3" font-size="0.7em">2</tspan></text>
<rect class="cf-box" x="304.0" y="254.0" width="32" height="22" rx="4"/>
<text class="cf-box-lbl" x="320" y="269" text-anchor="middle">C<tspan dy="3" font-size="0.7em">3</tspan></text>
<rect class="cf-box" x="414.0" y="254.0" width="32" height="22" rx="4"/>
<text class="cf-box-lbl" x="430" y="269" text-anchor="middle">C<tspan dy="3" font-size="0.7em">4</tspan></text>
<rect class="cf-box" x="504.0" y="254.0" width="32" height="22" rx="4"/>
<text class="cf-box-lbl" x="520" y="269" text-anchor="middle">C<tspan dy="3" font-size="0.7em">5</tspan></text>
<rect class="cf-box cf-box-chain" x="616.0" y="254.0" width="32" height="22" rx="4"/>
<text class="cf-box-lbl cf-box-lbl-chain" x="632" y="269" text-anchor="middle">C<tspan dy="3" font-size="0.7em">6</tspan></text>
<rect class="cf-event" x="407.0" y="23.0" width="36" height="24" rx="4"/>
<text class="cf-event-lbl" x="425" y="39" text-anchor="middle">E<tspan dy="3" font-size="0.7em">1</tspan></text>
<text class="cf-annot cf-annot-event" x="425" y="17.0" text-anchor="middle">your event</text>
</svg>
</div>
<figcaption>The event <b>E₁</b> made by node N₁ is pinned between two ticks of <b>your clock</b> (N₃) — <b>C₁</b> just before it, <b>C₆</b> just after. The bold chain threads up through the network to the event and back down; every link is one clock event embedding the hash of an earlier one, which is what makes the bracket impossible to fake.</figcaption>
</figure>
<h3 class="subhead reveal">Finding the chain across the network</h3>
<div class="lede reveal">
<p>The links point backward — an event knows the clock event it came after, not the ones that will later enclose it — so a node usually can't assemble the whole chain from its own copy. It sends a <b>discovery</b> request toward the event's creator. Each node along the way contributes clock events from its own chain, extending the bracket a little further, and forwards the request on; the response then retraces the path home, and every hop fills in the forward links the requester was missing. The chain that comes back is short: roughly forty clock events for a hop out and back on both the lower and upper side — small enough to fit in a single UDP packet.</p>
<p>Where a node knows a route toward the creator, it forwards straight there. Where it doesn't, it falls back to a <em>bounded</em> search rather than flooding the whole network — a capped fan-out, a hop limit, and a visited set so a request can't loop. The search also aims at the network <em>as it was cross-linked around the event's own time</em>, not as it looks today, which is why peers joining and leaving later never invalidate a proof that was already found.</p>
<p>Routing is only ever a guess about where to look, never a claim about what is true. Every chain a discovery returns is re-checked link by link before it is trusted — hashes recomputed, each link confirmed, both ends confirmed to be the requester's own clock events. A wrong turn can only make a search come back empty, or with a looser bound; it can never make it return a false one. Two nodes may find different chains, but never contradictory ones.</p>
</div>
<div class="grid g-2 reveal" style="margin-top: 2.6rem;">
<div class="card">
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3.5 12a8.5 8.5 0 1 0 2.7-6.2"/><path d="M3 4.5V9h4.5"/><path d="M12 8v4.3l3 1.8"/></svg></div>
<h3>You can't forge the past</h3>
<p>The moment a clock event is broadcast, your neighbors have echoed it and stacked their own ticks on top. To move a past event you'd have to rewrite every link that followed — on every machine that already holds a copy. The graph has set, and validation rejects any chain whose hashes don't line up.</p>
</div>
<div class="card">
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="2.4"/><path d="M7 7a7 7 0 0 0 0 10M17 7a7 7 0 0 1 0 10M9.4 9.4a3.6 3.6 0 0 0 0 5.2M14.6 9.4a3.6 3.6 0 0 1 0 5.2"/></svg></div>
<h3>You can't pre-compute the future</h3>
<p>Say you fake a protest — photos and video generated by AI weeks ahead — then publish them on the day so they look live. To hold up, your event has to agree with everything else the network recorded at that instant: the shared graph acts like an oracle for reality. Did the weather station's proven readings match your footage? A camera down the street? Depending on precision, even a traffic light's timing can contradict your video. You can't prepare the present in advance — you'd have to forge it exactly as it unfolds, which is far harder.</p>
</div>
</div>
</div>
</section>
<!-- HOW -->
<section id="how" class="section-alt">
<div class="wrap">
<div class="section-head reveal">
<p class="eyebrow">How you use it</p>
<h2>Four steps, and no leap of faith at the end.</h2>
</div>
<div class="steps">
<div class="step reveal">
<div class="num">STEP 01</div>
<h3>Join the network</h3>
<p>Run a node, or rely on one run by someone you trust — your company, a lab, a city, a law firm, a public notary.</p>
</div>
<div class="step reveal">
<div class="num">STEP 02</div>
<h3>Stamp your moment</h3>
<p>Point LOTI at any file or sensor reading. Its hash is linked into the graph instantly — and for free.</p>
</div>
<div class="step reveal">
<div class="num">STEP 03</div>
<h3>Ask for proof</h3>
<p>Request "when did this happen?" or "which came first?" LOTI hands you a small, portable proof file.</p>
</div>
<div class="step reveal">
<div class="num">STEP 04</div>
<h3>Anyone verifies</h3>
<p>They check the proof themselves — offline, in seconds. No account, no network, no trusting you. It holds up, or it doesn't.</p>
</div>
</div>
</div>
</section>
<!-- USE CASES -->
<section id="uses">
<div class="wrap">
<div class="section-head reveal">
<p class="eyebrow">Use cases</p>
<h2>Wherever "when" and "who was first" carry consequences.</h2>
</div>
<div class="grid g-3">
<div class="card reveal">
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3v18M7 21h10M5 7h14M12 3l-7 4 2.5 5a3.5 3.5 0 0 1-5 0L12 3zm0 0l7 4-2.5 5a3.5 3.5 0 0 0 5 0L12 3z"/></svg></div>
<h3>Legal disputes</h3>
<p>Settle "when" and "who was first" with mathematics, not memory. Prove a notice, filing, or agreement existed before a deadline.</p>
</div>
<div class="card reveal">
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 3h8l4 4v14H6z"/><path d="M14 3v4h4"/><path d="M9 13h6M9 16.5h6"/></svg></div>
<h3>Document timestamping</h3>
<p>Notarize any file — a manuscript, a design, a will — so its existence by a date is provable forever, without a notary's fee.</p>
</div>
<div class="card reveal">
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M14.5 9.6a3.2 3.2 0 1 0 0 4.8"/></svg></div>
<h3>Copyright & priority</h3>
<p>Establish that you made a song, photo, dataset, or invention first. Portable prior-art you can show any court or client.</p>
</div>
<div class="card reveal">
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 13a8 8 0 0 1 8 8M3 17a4 4 0 0 1 4 4"/><circle cx="5" cy="19" r="1.4"/><path d="M14 4l6 6-4 4-6-6z"/><path d="M13 11l-3 3"/></svg></div>
<h3>Oracle for physical reality</h3>
<p>Sensors stamp their readings; independent sensors corroborate each other. A trustless bridge between what happened in the world and what you can prove — noise, seismic, or camera data lining up with a real event.</p>
</div>
<div class="card reveal">
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="5" width="18" height="14" rx="1.5"/><path d="M3 9h18M7 5v14M17 5v14"/><path d="M11 11l3 1.8-3 1.8z" fill="currentColor" stroke="none"/></svg></div>
<h3>Provenance vs. deepfakes</h3>
<p>Prove footage existed before — or couldn't have existed before — the event it claims to show. Time becomes part of authenticity.</p>
</div>
<div class="card reveal">
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 3h6M10 3v6l-4.5 8.5A2 2 0 0 0 7.3 21h9.4a2 2 0 0 0 1.8-3.5L14 9V3"/><path d="M8 14h8"/></svg></div>
<h3>Research integrity</h3>
<p>Prove when data was collected or a result reached. No backdating, no quiet revisions — a defensible record of scientific priority.</p>
</div>
</div>
</div>
</section>
<!-- BENEFITS -->
<section id="benefits" class="section-alt">
<div class="wrap">
<div class="section-head reveal">
<p class="eyebrow">Why it's different</p>
<h2>The strengths come from what LOTI refuses to do.</h2>
</div>
<div class="benefits reveal">
<div class="benefit"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 12.5l5 5L20 6.5"/></svg><div><h3>Trustless</h3><p>Proofs are checked with math, not middlemen.</p></div></div>
<div class="benefit"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="8" cy="8" r="4"/><path d="M11 11l8 8M16 19l3-3M14 16l3-3"/></svg><div><h3>Permissionless</h3><p>Anyone can join. No gatekeeper, no application.</p></div></div>
<div class="benefit"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="5" y="10" width="14" height="10" rx="2"/><path d="M8 10V7a4 4 0 0 1 8 0v3"/></svg><div><h3>Private by default</h3><p>Only fingerprints travel the network — your content stays with you.</p></div></div>
<div class="benefit"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M9.5 9.5a2.5 2.5 0 0 1 4.5 1.2c0 1.8-2.5 1.8-2.5 3.3M12 17h.01"/></svg><div><h3>Practically free</h3><p>No coins, no mining, no gas. Publishing costs nothing.</p></div></div>
<div class="benefit"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 3h8l4 4v14H5V3z"/><path d="M9 13.5l2 2 4-4"/></svg><div><h3>Portable proofs</h3><p>A single file, verifiable offline, for as long as it matters.</p></div></div>
<div class="benefit"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="6" cy="6" r="2.4"/><circle cx="18" cy="6" r="2.4"/><circle cx="12" cy="18" r="2.4"/><path d="M7.7 7.7L11 15M16.3 7.7L13 15M8 6h8"/></svg><div><h3>No single point of failure</h3><p>Decentralized and censorship-resistant by construction.</p></div></div>
</div>
</div>
</section>
<!-- COMPARE -->
<section id="compare">
<div class="wrap">
<div class="section-head reveal">
<p class="eyebrow">Compare</p>
<h2>Between a notary and a blockchain — the sweet spot.</h2>
</div>
<div class="table-scroll reveal">
<table>
<thead>
<tr>
<th scope="col"></th>
<th scope="col" class="col-loti">LOTI</th>
<th scope="col">Timestamp authority</th>
<th scope="col">Blockchain</th>
</tr>
</thead>
<tbody>
<tr><th scope="row">Who you trust</th><td class="col-loti">A reference you choose — or the math</td><td>The authority</td><td>The chain & its validators</td></tr>
<tr><th scope="row">Proves order?</th><td class="col-loti">Yes — a native happened-before ordering, clock or no clock</td><td>No — stamps each event alone</td><td>Not within a block — same-block events share one stamp (≈10 min, Bitcoin)</td></tr>
<tr><th scope="row">Time resolution</th><td class="col-loti">Tunable — sub-second if you push the clock and topology</td><td>The authority's clock</td><td>Capped by block time — seconds to minutes</td></tr>
<tr><th scope="row">Cost per proof</th><td class="col-loti">Effectively free</td><td>Per-stamp fees</td><td>Transaction / gas fees</td></tr>
<tr><th scope="row">Your content</th><td class="col-loti">Stays private</td><td>Shared with the authority</td><td>Public forever</td></tr>
<tr><th scope="row">Resilience</th><td class="col-loti">No single point of failure</td><td>Central</td><td>Robust, but heavy</td></tr>
<tr><th scope="row">Permission</th><td class="col-loti">Open to anyone</td><td>Gatekept</td><td>Open</td></tr>
<tr><th scope="row">Footprint</th><td class="col-loti">A light background service</td><td>—</td><td>Energy / capital intensive</td></tr>
</tbody>
</table>
</div>
</div>
</section>
<!-- COSTS -->
<section id="costs" class="section-alt">
<div class="wrap">
<div class="section-head reveal">
<p class="eyebrow">The honest ledger</p>
<h2>What it costs, and what you get.</h2>
<p>LOTI is a network — it grows stronger with every participant. Here's the trade, without the sales gloss.</p>
</div>
<div class="ledger reveal">
<div class="panel cost">
<h3>What it takes</h3>
<ul>
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><path d="M5 12h14"/></svg><span>A node needs a bit of bandwidth and a slice of storage — <strong>capped at a budget you pick and flat forever</strong>, so it never outgrows its disk. Like a modest background service.</span></li>
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><path d="M5 12h14"/></svg><span>Hardware is cheap: a node runs always-on, low-power, on a <strong>~$15 Raspberry Pi Zero</strong> — its memory stays bounded and its clock history is capped to a fixed budget, so a long-lived node keeps a small footprint. <a href="https://github.com/levy/loti/tree/master/doc/embedded.md" target="_blank" rel="noopener">Embedded guide →</a></span></li>
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><path d="M5 12h14"/></svg><span>Proofs pin an event to a <em>window</em> — think under a minute — not an exact instant.</span></li>
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><path d="M5 12h14"/></svg><span>It proves <em>time and order</em>. Pair it with a signature when you also need to prove <em>who</em>.</span></li>
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"><path d="M5 12h14"/></svg><span>Like any network, its reach depends on participation — the more nodes, the tighter and more trusted the proofs.</span></li>
</ul>
</div>
<div class="panel gain">
<h3>What you gain</h3>
<ul>
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12.5l5 5L20 6.5"/></svg><span>Mathematical proof of when an event happened, and which of two came first.</span></li>
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12.5l5 5L20 6.5"/></svg><span>Proofs a third party can verify offline — no account, no platform, no trust in you.</span></li>
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12.5l5 5L20 6.5"/></svg><span>Freedom from fees, gatekeepers, and single points of failure.</span></li>
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12.5l5 5L20 6.5"/></svg><span>Privacy — publish as much as you like; only fingerprints ever leave your machine.</span></li>
<li><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 12.5l5 5L20 6.5"/></svg><span>Proofs that last — on a fixed storage budget a node's reach stretches back years, and further as you add chains; recent events stay pinned to the second, older ones fade in precision, and any proof it makes is valid forever.</span></li>
</ul>
</div>
</div>
</div>
</section>
<!-- BACK OF THE ENVELOPE -->
<section id="numbers">
<div class="wrap">
<div class="section-head reveal">
<p class="eyebrow">Back of the envelope</p>
<h2>Pick a storage budget. Everything else follows.</h2>
<p>A node runs several clock chains at once — one fast, each of the rest a step slower — keeps a fixed number of ticks on every chain, and prunes the rest. Storage then stays flat forever: recent moments are pinned to the second, and older ones widen gently with age. Here is what a given budget buys, at a steady one tick per second.</p>
</div>
<div class="table-scroll reveal">
<table>
<thead>
<tr>
<th scope="col">Device</th>
<th scope="col">Storage budget</th>
<th scope="col">Pinned to the second</th>
<th scope="col">A 10-year-old event</th>
<th scope="col">Reach</th>
</tr>
</thead>
<tbody>
<tr><th scope="row">Raspberry Pi Zero</th><td>64 MB</td><td>events up to ~2 hours old</td><td>bracketed to ~33 hours</td><td>~210 years</td></tr>
<tr><th scope="row">Phone or laptop</th><td>1 GB</td><td>events up to ~1.5 days old</td><td>bracketed to ~52 minutes</td><td>~310 years</td></tr>
<tr><th scope="row">Small server</th><td>32 GB</td><td>events up to ~46 days old</td><td>bracketed to ~81 seconds</td><td>~280 years</td></tr>
</tbody>
</table>
</div>
<p class="fine reveal">Reach is nearly free — it costs chains, not storage — so almost the whole budget goes to precision. Worst case, an aged event is bracketed to a fraction of its age: <b>~0.09%</b> on a Pi, <b>~0.004%</b> on a phone, <b>~0.00008%</b> on a server. Push the tick faster than one per second — or lean on a denser, better-connected patch of the network — and even recent bounds drop well below a second, a resolution no block-time-bound chain can reach.</p>
<h3 class="subhead reveal">What it takes to build the graph</h3>
<div class="grid g-3 reveal">
<div class="card">
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><ellipse cx="12" cy="6" rx="7" ry="2.8"/><path d="M5 6v12c0 1.6 3.1 2.8 7 2.8s7-1.2 7-2.8V6"/><path d="M5 12c0 1.6 3.1 2.8 7 2.8s7-1.2 7-2.8"/></svg></div>
<h3>Storage</h3>
<p>Your chosen budget, flat forever. The graph is a fixed pile of clock ticks — about a million on a phone, roughly 1 KB each — and pruning holds it there however long the node runs.</p>
</div>
<div class="card">
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="6" cy="6" r="2.4"/><circle cx="18" cy="6" r="2.4"/><circle cx="12" cy="18" r="2.4"/><path d="M7.7 7.7L11 15M16.3 7.7L13 15M8 6h8"/></svg></div>
<h3>Network</h3>
<p>One small clock event a second, shared as a hash with your ~10 neighbors. A complete proof is roughly 40 hops — about 40 KB, a single UDP packet. Everything else on the wire is just chain tips, about 1.25× a single chain.</p>
</div>
<div class="card">
<div class="ico"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="7" y="7" width="10" height="10" rx="1.6"/><path d="M10 4v3M14 4v3M10 17v3M14 17v3M4 10h3M4 14h3M17 10h3M17 14h3"/></svg></div>
<h3>CPU</h3>
<p>A hash and a signature about once a second. Running eight clock chains at once adds only ~25% over running one. Light enough to stay always-on on a $15 Raspberry Pi Zero.</p>
</div>
</div>
</div>
</section>
<!-- QUICKSTART -->
<section id="quickstart" class="section-alt">
<div class="wrap">
<div class="section-head reveal">
<p class="eyebrow">Quickstart</p>
<h2>Three commands to publish. One to look it up.</h2>
<p>A node runs as a background daemon (<code>lotid</code>); the <code>loti</code> client drives it over a local socket. Here is a brand-new node publishing a document — and a neighbor discovering it across the network.</p>
</div>
<div class="quickstart-grid reveal">
<div class="terminal">
<div class="term-head"><span class="term-dots"><span></span><span></span><span></span></span><span class="term-label">you — a new node</span></div>
<pre class="term-body"><span class="c"># 1 · start your node</span>
<span class="p">$</span> loti init
<span class="o">node id: 0x00000000a11ce5d0</span>
<span class="o">start: lotid --key ~/.loti/key --port 7000 --control ~/.loti/control.sock</span>
<span class="p">$</span> lotid --key ~/.loti/key --port 7000 --control ~/.loti/control.sock &
<span class="o">[lotid] node 0x00000000a11ce5d0 listening on udp/7000 (signed)</span>
<span class="p">$</span> export LOTI_CONTROL=~/.loti/control.sock
<span class="c"># 2 · add a neighbor (id:ip:port)</span>
<span class="p">$</span> loti peer add 0x00000000b0b0cafe:203.0.113.9:7000
<span class="o">peer: 0x00000000b0b0cafe:203.0.113.9:7000</span>
<span class="c"># 3 · publish a document</span>
<span class="p">$</span> loti publish "hello from alice"
<span class="o">event: <b>2c7f9a4e8d…</b></span></pre>
</div>
<div class="terminal">
<div class="term-head"><span class="term-dots"><span></span><span></span><span></span></span><span class="term-label">a neighbor</span></div>
<pre class="term-body"><span class="c"># the neighbor's node is already running and peered
# back to alice. alice shares the event hash;
# the neighbor looks the document up over the network:</span>
<span class="p">$</span> loti chain 2c7f9a4e8d…
<span class="o">reference: 0x00000000b0b0cafe</span>
<span class="o">lower: creator=0x00000000b0b0cafe hash=7a10d2… ts=1752748262000000000</span>
<span class="o">event: 2c7f9a4e8d…</span>
<span class="o">content: <b>hello from alice</b></span>
<span class="o">upper: creator=0x00000000b0b0cafe hash=7a2f81… ts=1752748299000000000</span>
<span class="o">clockEvents: 2</span>
<span class="c"># → the document, bracketed between two of the
# neighbor's own clock ticks — provably.</span></pre>
</div>
</div>
</div>
</section>
<!-- CTA -->
<section id="start">
<div class="wrap cta-band reveal">
<p class="eyebrow" style="justify-content:center">Get started</p>
<h2>Run a node. Stamp a moment.<br>Prove it to the world.</h2>
<p>LOTI is open research and open source. Read the whitepaper for the whole idea, or dive into the code and documentation.</p>
<div class="hero-cta">
<a class="btn btn-primary" href="https://docs.google.com/document/d/1KmdknFYkGlxhLoKOQb9g14LW4Jg7zIReaa_GsB5aJio" target="_blank" rel="noopener">Read the whitepaper</a>
<a class="btn btn-ghost" href="https://github.com/levy/loti" target="_blank" rel="noopener">Explore on GitHub</a>
</div>
</div>
</section>
<!-- FAQ -->
<section id="faq" class="section-alt">
<div class="wrap">
<div class="section-head reveal">
<p class="eyebrow">Questions</p>
<h2>The things people ask first.</h2>
</div>
<div class="faq reveal">
<details>
<summary>Is this a blockchain?<span class="plus"></span></summary>
<p>No. There's no global ledger, no coin, and no mining. Everyone keeps their own local timeline and cross-checks their neighbors, which makes LOTI far lighter, private, and free compared with a blockchain.</p>
</details>
<details>
<summary>Is this just timestamping?<span class="plus"></span></summary>
<p>It's a timestamping network — and, at the same time, an event-<em>ordering</em> one. The same graph fixes which event happened before which, as a tamper-proof partial order, whether or not you ever attach a date. Two events can be conclusively ordered against each other even when neither carries a trusted timestamp. Pin that ordering to a reference clock and you get a readable date; leave the clock out and the order still holds.</p>
</details>
<details>
<summary>Does it cost money?<span class="plus"></span></summary>
<p>Publishing an event is effectively free. Running a node costs a bit of bandwidth and a fixed slice of storage — capped at a budget you choose and flat forever. There are no per-proof fees.</p>
</details>
<details>
<summary>Won't the storage grow forever?<span class="plus"></span></summary>
<p>No. Each node keeps its clock history at several resolutions at once — fine-grained for recent events, progressively coarser for older ones — and trims each down to a fixed size. The clock-event store is capped at a budget you set, from tens of megabytes on a Raspberry Pi to tens of gigabytes on a server, and stays flat (published-event content is separate and grows with what you publish). Within a node's reach an old event stays orderable — its time window just widens gently with age (recent events pinned to the second, older ones coarser) — and more chains push that reach back years and beyond; a proof, once made, is valid forever.</p>
</details>
<details>
<summary>How precise is a proof?<span class="plus"></span></summary>
<p>It depends on the network — and precision is a dial, not a fixed floor. How tight the window is comes down to two things you can scale: the tick interval of the nodes on the chain, and the topology around your event — a denser, better-connected, faster-ticking stretch of the network brackets it more tightly. Push the clock faster and gather a few close neighbors and the window drops well below a second; leave it at one slow tick a node and it widens toward a minute. That tunability is something Bitcoin or Ethereum stamping can't match: there, resolution is pinned to the block interval — minutes on Bitcoin, seconds on Ethereum — and can't go finer. Worse for ordering, every event that lands in the same block carries that block's one timestamp, so within a block — about ten minutes on Bitcoin — there is no way to say which of two events came first at all. LOTI's clock ticks continuously, so it keeps separating events right down to its resolution. Either way, a LOTI proof is a rigorous bound, never a claim of an exact instant.</p>
</details>
<details>
<summary>Is my content made public?<span class="plus"></span></summary>
<p>No. By default only fingerprints — not your actual files — travel across the network. Your documents, photos, and measurements stay on your own machine.</p>
</details>
<details>
<summary>Do I have to trust the other nodes?<span class="plus"></span></summary>
<p>No. A proof is checked with mathematics, so a dishonest node can't fabricate a valid one. The only thing you choose is <em>whose clock</em> the time is measured against — your own, or a reputable reference like a notary or a court.</p>
</details>
<details>
<summary>Who runs the network?<span class="plus"></span></summary>
<p>Anyone. People, companies, cities, courts, laboratories, even sensors and IoT devices. The more participants there are, the tighter and more widely trusted the proofs become.</p>
</details>
<details>
<summary>How robust is the network?<span class="plus"></span></summary>
<p>Every node keeps several neighbors, not just one, and each clock event is heard and echoed by many of them. That redundancy is built in from the start: links and routes overlap heavily, so nodes dropping offline — or whole regions falling quiet — leave the graph intact and existing proofs verifiable. The more densely the network is connected, the more resilient it becomes.</p>
</details>
<details>
<summary>Does it keep working as the network grows and changes?<span class="plus"></span></summary>
<p>A proof traces the network as it was when your event happened — not as it looks today — so peers coming and going never invalidates an old proof. To stay fast as the network grows, a lookup heads straight for its destination where the route is known and falls back to a bounded search where it isn't. However it's found, every proof is re-checked by the math, so a wrong turn can only make a lookup miss — never make it lie.</p>
</details>
</div>
</div>
</section>
</main>
<footer>
<div class="wrap">
<div class="foot-top">
<div class="foot-brand">
<a class="brand" href="#top">
<svg class="seal" viewBox="0 0 32 32" aria-hidden="true"><circle cx="16" cy="16" r="13.5" fill="none" stroke="var(--accent)" stroke-width="2"/><path d="M9.5 16.5l4.4 4.4L22.7 12" fill="none" stroke="var(--accent)" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
LOTI
</a>
<p>A peer-to-peer network for provable time and order — the trustless middle ground between a notary and a blockchain.</p>
</div>
<div class="foot-links">
<div class="foot-col">
<h4>Learn</h4>
<a href="https://docs.google.com/document/d/1KmdknFYkGlxhLoKOQb9g14LW4Jg7zIReaa_GsB5aJio" target="_blank" rel="noopener">Whitepaper</a>
<a href="doc/Peer-to-peer%20Non-Consensus%20Partial%20Event%20Ordering%20Network.pdf">Paper (PDF)</a>
<a href="https://github.com/levy/loti/tree/master/doc" target="_blank" rel="noopener">Documentation</a>
</div>
<div class="foot-col">
<h4>Build</h4>
<a href="https://github.com/levy/loti" target="_blank" rel="noopener">Source code</a>
<a href="https://github.com/levy/loti/tree/master/doc/cli.md" target="_blank" rel="noopener">The CLI</a>
<a href="https://github.com/levy/loti/tree/master/doc/architecture.md" target="_blank" rel="noopener">Architecture</a>
</div>
</div>
</div>
<div class="foot-bottom">
<span>Based on the paper by Levente Mészáros.</span>
<span>Free software · GPLv3</span>
</div>
</div>
</footer>
<script>
// Theme toggle
(function () {
var btn = document.getElementById('themeToggle');
btn.addEventListener('click', function () {
var next = document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', next);
try { localStorage.setItem('loti-theme', next); } catch (e) {}
});
})();
// Scroll reveal
(function () {
var els = document.querySelectorAll('.reveal');
if (!('IntersectionObserver' in window) || matchMedia('(prefers-reduced-motion: reduce)').matches) {
els.forEach(function (el) { el.classList.add('is-visible'); });
return;
}
var io = new IntersectionObserver(function (entries) {
entries.forEach(function (e) {
if (e.isIntersecting) { e.target.classList.add('is-visible'); io.unobserve(e.target); }
});
}, { threshold: 0.12, rootMargin: '0px 0px -8% 0px' });
els.forEach(function (el) { io.observe(el); });
})();
// Hero lattice — parallel timelines cross-linked into a fabric of before/after,
// with one event bracketed between two ticks. The subject's core image, rendered live.
(function () {
var canvas = document.getElementById('lattice');