-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathengineering-release.html
More file actions
1103 lines (1003 loc) · 142 KB
/
Copy pathengineering-release.html
File metadata and controls
1103 lines (1003 loc) · 142 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="light">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="generator" content="dossier/1.0">
<title>Release Readiness: 0.5.5</title>
<style>
:root{
color-scheme:light dark;
--ds-bg:#fbfbfc; --ds-bg-2:#f5f4f8; --ds-bg-3:#edebf1;
--ds-line:#e8e6ee; --ds-line-2:#dcd9e4; --ds-line-strong:#c7c2d3;
--ds-ink:#1a1822; --ds-ink-2:#56525f; --ds-ink-3:#8b8698;
--ds-accent:#c81e4a; --ds-accent-2:#a8183d; --ds-accent-tint:rgba(200,30,74,.08);
--ds-ok:#0f7a52; --ds-warn:#9a5b00; --ds-danger:#c0263b;
--ds-ok-tint:rgba(15,122,82,.1); --ds-warn-tint:rgba(154,91,0,.12); --ds-danger-tint:rgba(192,38,59,.1);
--ds-frame:1180px; --ds-rail:212px;
--ds-font:Inter,ui-sans-serif,system-ui,-apple-system,"Segoe UI",sans-serif;
--ds-serif:Charter,"Bitstream Charter","Iowan Old Style","Palatino Linotype",Georgia,serif;
--ds-mono:"Geist Mono",ui-monospace,"SF Mono",SFMono-Regular,Menlo,monospace;
--ds-ease:cubic-bezier(.2,0,0,1);
}
[data-theme="dark"]{
--ds-bg:#0e0d13; --ds-bg-2:#16141d; --ds-bg-3:#1e1b27;
--ds-line:#2c2937; --ds-line-2:#3b3749; --ds-line-strong:#524c63;
--ds-ink:#eceaf1; --ds-ink-2:#a8a3b6; --ds-ink-3:#7b7689;
--ds-accent:#ff6b88; --ds-accent-2:#ff8aa0; --ds-accent-tint:rgba(255,107,136,.12);
--ds-ok:#34d399; --ds-warn:#fbbf24; --ds-danger:#fb7185;
--ds-ok-tint:rgba(52,211,153,.12); --ds-warn-tint:rgba(251,191,36,.12); --ds-danger-tint:rgba(251,113,133,.12);
}
*{box-sizing:border-box}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%;scroll-padding-top:66px}
body{margin:0;background:var(--ds-bg);color:var(--ds-ink);font-family:var(--ds-font);font-size:16px;line-height:1.55;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;overflow-x:hidden;-webkit-tap-highlight-color:transparent}
::selection{background:var(--ds-accent-tint)}
a{color:var(--ds-accent);text-decoration:none}
a:hover{text-decoration:underline;text-underline-offset:2px}
button,input,select,textarea{font:inherit;color:inherit}
:focus-visible{outline:2px solid var(--ds-accent);outline-offset:2px;border-radius:5px}
.ds-tabbar,.ds-tablewrap,pre,.ds-diff-lines,.ds-diff-empty,.ds-math{scrollbar-width:none}
.ds-tabbar::-webkit-scrollbar,.ds-tablewrap::-webkit-scrollbar,pre::-webkit-scrollbar,.ds-diff-lines::-webkit-scrollbar,.ds-diff-empty::-webkit-scrollbar,.ds-math::-webkit-scrollbar{display:none}
h1,h2,h3,h4{font-weight:640;letter-spacing:-.014em;scroll-margin-top:66px}
h1{font-size:30px;line-height:1.18;letter-spacing:-.02em}
h2{font-size:22px;line-height:1.24;letter-spacing:-.015em;margin:0 0 5px}
h3{font-size:17.5px;line-height:1.3;letter-spacing:-.006em;margin:0 0 4px}
h4{font-size:15px;margin:0 0 3px}
p{margin:0 0 13px}
ul,ol{margin:0 0 13px;padding-left:21px}
li{margin:5px 0}
strong{font-weight:640}
code{font-family:var(--ds-mono);font-size:.86em;background:var(--ds-bg-2);border:1px solid var(--ds-line);border-radius:5px;padding:.5px 5px;color:var(--ds-ink)}
.ds-prose p:last-child,.ds-prose-list:last-child{margin-bottom:0}
.ds-prose-list{color:var(--ds-ink-2)}
.ds-prose-list strong{color:var(--ds-ink)}
.ds-muted{color:var(--ds-ink-2)}
@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important;scroll-behavior:auto!important}}
.ds-progress{position:fixed;inset:0 0 auto 0;height:2px;z-index:60}
.ds-progress-bar{height:100%;width:0;background:linear-gradient(90deg,var(--ds-accent),var(--ds-accent-2))}
.ds-skip{position:fixed;left:14px;top:10px;z-index:100;transform:translateY(-140%);background:var(--ds-ink);color:var(--ds-bg);border-radius:8px;padding:8px 12px;font-size:13px;font-weight:650;box-shadow:0 10px 30px rgba(20,16,40,.18)}
.ds-skip:focus{transform:none;text-decoration:none}
.ds-shell{width:min(var(--ds-frame),calc(100% - 48px));margin:0 auto;padding-left:env(safe-area-inset-left);padding-right:env(safe-area-inset-right)}
/* top bar */
.ds-topbar{position:sticky;top:0;z-index:40;display:flex;align-items:center;justify-content:space-between;gap:14px;height:54px;background:var(--ds-bg);border-bottom:1px solid var(--ds-line)}
.ds-brand{display:flex;align-items:center;gap:10px;min-width:0;flex:1}
.ds-mark{width:9px;height:9px;border-radius:50%;background:var(--ds-accent);box-shadow:0 0 0 4px var(--ds-accent-tint);flex:none}
.ds-crumbs{color:var(--ds-ink);font-size:14.5px;font-weight:580;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ds-tools{display:flex;align-items:center;gap:8px;flex:none}
.ds-btn{display:inline-flex;align-items:center;gap:7px;height:34px;padding:0 11px;border:0;background:transparent;color:var(--ds-ink-2);font-size:13px;font-weight:560;border-radius:9px;cursor:pointer;transition:background .12s var(--ds-ease),color .12s var(--ds-ease),border-color .12s var(--ds-ease),transform .1s var(--ds-ease)}
.ds-btn:hover{background:var(--ds-bg-2);color:var(--ds-ink)}
.ds-btn .ds-i{flex:none;display:flex}
.ds-btn kbd{font-family:var(--ds-mono);font-size:11px;color:var(--ds-ink-3);border:1px solid var(--ds-line-2);border-radius:5px;padding:1px 5px}
.ds-search-btn{border:1px solid var(--ds-line-2);background:var(--ds-bg-2);min-width:172px;justify-content:flex-start;color:var(--ds-ink-3)}
.ds-search-btn .ds-search-label{margin-right:auto}
.ds-search-btn:hover{border-color:var(--ds-line-strong);background:var(--ds-bg-2);color:var(--ds-ink-2)}
.ds-btn[data-theme-toggle]{width:40px;height:40px;padding:0;justify-content:center;font-size:20px;line-height:1;color:var(--ds-ink-2)}
.ds-btn[data-theme-toggle]:hover{background:transparent;color:var(--ds-accent)}
.ds-menu{position:relative}
.ds-menu>summary{list-style:none;display:inline-flex;align-items:center;gap:7px;height:34px;padding:0 13px;border:1px solid var(--ds-line-2);background:var(--ds-bg-2);color:var(--ds-ink);font-size:13px;font-weight:580;border-radius:9px;cursor:pointer}
.ds-menu>summary::-webkit-details-marker{display:none}
.ds-menu>summary::after{content:"▾";font-size:11px;color:var(--ds-ink-3)}
.ds-menu>summary:hover{border-color:var(--ds-line-strong);background:var(--ds-bg-3)}
.ds-menu-list{position:absolute;right:0;top:42px;min-width:206px;display:grid;padding:6px;background:var(--ds-bg);border:1px solid var(--ds-line-2);border-radius:12px;box-shadow:0 14px 38px rgba(20,16,40,.14);z-index:50}
.ds-menu-list button{justify-content:flex-start;width:100%;height:36px;padding:0 11px;color:var(--ds-ink);font-weight:520}
.ds-dirty-status{display:inline-flex;align-items:center;height:26px;padding:0 9px;border-radius:999px;background:var(--ds-accent-tint);color:var(--ds-accent);font-size:11.5px;font-weight:680;font-variant-numeric:tabular-nums;white-space:nowrap}
.ds-dirty-status[hidden]{display:none}
.ds-tool-modal{position:fixed;inset:0;z-index:85;display:flex;align-items:center;justify-content:center;padding:22px;background:rgba(15,14,20,.38)}
.ds-tool-modal[hidden]{display:none}
.ds-tool-card{width:min(760px,100%);max-height:88vh;display:grid;gap:14px;overflow:auto;background:var(--ds-bg);border:1px solid var(--ds-line-2);border-radius:14px;box-shadow:0 24px 80px rgba(0,0,0,.22);padding:16px}
.ds-tool-wide{width:min(1040px,100%)}
.ds-tool-head{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;padding-bottom:12px;border-bottom:1px solid var(--ds-line)}
.ds-tool-head strong{display:block;font-size:15px}
.ds-tool-head p,.ds-tool-note{margin:4px 0 0;color:var(--ds-ink-3);font-size:12.5px}
.ds-export-grid{display:flex;flex-wrap:wrap;gap:8px}
.ds-export-grid .ds-btn,.ds-tool-actions .ds-btn{justify-content:center;border:1px solid var(--ds-line-2);background:var(--ds-bg);color:var(--ds-ink-2)}
.ds-export-grid .ds-btn:not(.ds-btn-line),.ds-tool-actions .ds-btn:not(.ds-btn-line){background:var(--ds-bg-2);color:var(--ds-ink)}
.ds-export-grid .ds-btn:hover,.ds-tool-actions .ds-btn:hover{border-color:var(--ds-line-strong);background:var(--ds-bg-3);color:var(--ds-ink)}
.ds-export-preview-head{display:flex;align-items:center;justify-content:space-between;color:var(--ds-ink-2);font-size:12px}
.ds-export-preview{width:100%;min-height:220px;border:1px solid var(--ds-line-2);border-radius:10px;background:var(--ds-bg-2);color:var(--ds-ink);font:12px/1.55 var(--ds-mono);padding:12px;resize:vertical}
.ds-revision-result{min-height:96px}
.ds-file-btn{display:inline-flex;align-items:center;height:36px;padding:0 11px;border:1px solid var(--ds-line-2);border-radius:9px;background:var(--ds-bg);color:var(--ds-ink-2);font-size:13px;font-weight:560;cursor:pointer}
.ds-file-btn:focus-visible{outline:2px solid var(--ds-accent);outline-offset:2px;border-color:var(--ds-line-strong)}
.ds-file-btn input{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
.ds-blockedit-list{display:grid;gap:8px}
.ds-blockedit-row{display:grid;grid-template-columns:minmax(0,1fr) auto auto auto;gap:8px;align-items:center;border:1px solid var(--ds-line-2);border-radius:10px;background:var(--ds-bg-2);padding:8px}
.ds-blockedit-row b{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px}
.ds-blockedit-row .ds-btn{height:30px}
.ds-tool-row{display:grid;grid-template-columns:160px minmax(0,1fr) auto;gap:8px;align-items:center}
.ds-tool-row input,.ds-tool-row select,.ds-field-grid input,.ds-field-grid select,.ds-field-grid textarea{width:100%;border:1px solid var(--ds-line-2);border-radius:8px;background:var(--ds-bg);color:var(--ds-ink);padding:8px 9px;font:13px var(--ds-font)}
.ds-field-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
.ds-field-grid label{display:grid;gap:5px;color:var(--ds-ink-3);font-size:12px;font-weight:650}
.ds-field-grid .wide{grid-column:1/-1}
.ds-field-grid textarea{min-height:110px;resize:vertical;line-height:1.45}
.ds-tool-actions{display:flex;justify-content:flex-end}
.ds-lifecycle{display:inline-flex;align-items:center;gap:9px;margin:22px 0 0;padding:6px 13px;background:var(--ds-bg-2);border:1px solid var(--ds-line);border-radius:999px;color:var(--ds-ink-2);font-size:12.5px}
.ds-lifecycle b{display:inline-flex;align-items:center;gap:7px;color:var(--ds-ink);font-weight:600;text-transform:capitalize}
.ds-lifecycle b::before{content:"";width:7px;height:7px;border-radius:50%;background:var(--ds-warn);box-shadow:0 0 0 3px var(--ds-warn-tint)}
.ds-lifecycle.stage-durable b::before{background:var(--ds-ok);box-shadow:0 0 0 3px var(--ds-ok-tint)}
.ds-lifecycle.stage-review b::before{background:var(--ds-accent);box-shadow:0 0 0 3px var(--ds-accent-tint)}
/* layout */
.ds-layout{display:grid;grid-template-columns:minmax(0,1fr) var(--ds-rail);gap:56px;padding:10px 0 96px;align-items:start}
.ds-layout.no-toc{grid-template-columns:1fr}
.ds-content{min-width:0;grid-column:1;counter-reset:sec}
.ds-toc{grid-column:2;position:sticky;top:74px;display:grid;gap:0;font-size:12.5px;align-self:start}
.ds-toc .ds-search{margin:0 0 14px}
.ds-toc .ds-search input{width:100%;height:34px;border:1px solid var(--ds-line-2);border-radius:9px;background:var(--ds-bg-2);padding:0 11px;font-size:13px;outline:0}
.ds-toc .ds-search input:focus{border-color:var(--ds-line-strong);background:var(--ds-bg)}
.ds-toc-head{color:var(--ds-ink-3);font-size:11px;font-weight:680;letter-spacing:.07em;text-transform:uppercase;margin-bottom:10px}
.ds-toc-link{display:block;padding:4px 0 4px 14px;color:var(--ds-ink-3);border-left:1.5px solid var(--ds-line);font-weight:520;transition:color .12s var(--ds-ease),border-color .12s var(--ds-ease)}
.ds-toc-link.lvl-2{padding-left:25px}
.ds-toc-link:hover{color:var(--ds-ink)}
.ds-toc-link.active{color:var(--ds-accent);border-left-color:var(--ds-accent)}
.ds-block{position:relative;min-width:0}
.ds-content>.ds-block+.ds-block{margin-top:34px}
.ds-content>.ds-block+.ds-section{margin-top:50px}
.ds-content>.ds-section{counter-increment:sec}
.ds-copy{position:absolute;top:8px;right:8px;z-index:2;display:inline-flex;align-items:center;justify-content:center;width:27px;height:27px;opacity:0;border:1px solid var(--ds-line);border-radius:8px;background:var(--ds-bg);color:var(--ds-ink-3);cursor:pointer;box-shadow:0 1px 2px rgba(20,16,40,.04);transition:opacity .12s var(--ds-ease),color .12s,background .12s,border-color .12s}
.ds-block:hover>.ds-copy{opacity:1}
.ds-copy:hover{color:var(--ds-ink);background:var(--ds-bg-2);border-color:var(--ds-line-strong)}
.ds-copy svg{display:block}
.ds-block[data-block="code"]>.ds-copy,.ds-block[data-block="diagram"]>.ds-copy{display:none}
/* in-place edit mode */
html.ds-editing .ds-btn[data-edit-toggle]{background:var(--ds-accent-tint);color:var(--ds-accent)}
.ds-editing [data-edit]{outline:1px dashed var(--ds-line-strong);outline-offset:3px;border-radius:4px;cursor:text}
.ds-editing [data-edit]:hover{outline-color:var(--ds-accent)}
.ds-editing [data-edit]:focus{outline:2px solid var(--ds-accent);outline-offset:3px}
/* theme studio */
.ds-swatch{width:34px;padding:0;justify-content:center}
.ds-swatch span{width:14px;height:14px;border-radius:50%;background:var(--ds-accent);box-shadow:0 0 0 1px var(--ds-line-2)}
.ds-studio{position:fixed;right:18px;top:62px;z-index:70;width:min(330px,calc(100vw - 28px));background:var(--ds-bg);border:1px solid var(--ds-line-2);border-radius:14px;box-shadow:0 18px 44px rgba(20,16,40,.18);padding:14px;display:grid;gap:10px}
.ds-studio[hidden]{display:none}
.ds-studio-head{display:flex;justify-content:space-between;align-items:center;font-size:13px}
.ds-studio-row{display:flex;justify-content:space-between;align-items:center;font-size:13px;font-weight:560;color:var(--ds-ink-2)}
.ds-studio-row input[type=color]{width:46px;height:28px;border:1px solid var(--ds-line-2);border-radius:7px;background:none;cursor:pointer;padding:2px}
.ds-studio-row input[type=text],.ds-studio-select,.ds-studio-json{border:1px solid var(--ds-line-2);border-radius:8px;background:var(--ds-bg-2);color:var(--ds-ink);font:12.5px var(--ds-mono);outline:0}
.ds-studio-row input[type=text]{width:92px;padding:6px 8px;text-align:right}
.ds-studio-presets{display:flex;flex-wrap:wrap;gap:8px}
.ds-studio-sw{width:26px;height:26px;border-radius:50%;border:1px solid var(--ds-line-2);cursor:pointer;padding:0;transition:transform .1s var(--ds-ease)}
.ds-studio-sw:hover{transform:scale(1.1)}
.ds-studio-select{width:100%;padding:7px 8px;font-family:inherit}
.ds-studio-json{width:100%;min-height:108px;resize:vertical;padding:9px;line-height:1.4}
.ds-studio-actions{display:grid;grid-template-columns:1fr 1fr;gap:7px}
.ds-studio-actions [data-studio-reset]{grid-column:1/-1}
.ds-studio-actions .ds-btn-line{justify-content:center}
mark{background:var(--ds-accent-tint);color:inherit;border-radius:3px;padding:0 2px}
/* hero, no background wash */
.ds-hero{padding:34px 0 4px}
.ds-eyebrow{display:inline-flex;align-items:center;margin:0 0 15px;padding:5px 12px;background:var(--ds-accent-tint);color:var(--ds-accent);font-size:12px;font-weight:600;letter-spacing:.02em;border-radius:999px}
.ds-hero h1{font-family:var(--ds-serif);font-weight:400;font-size:clamp(30px,4.2vw,44px);line-height:1.08;letter-spacing:-.022em;margin:0;max-width:20ch}
.ds-lede{max-width:62ch;margin:18px 0 0;color:var(--ds-ink-2);font-size:18px;line-height:1.5}
.ds-pillrow{display:flex;flex-wrap:wrap;gap:0;margin-top:20px;color:var(--ds-ink-3);font-size:12.5px;font-weight:520}
.ds-pill{position:relative;padding:0 14px}
.ds-pill:first-child{padding-left:0}
.ds-pill+.ds-pill::before{content:"";position:absolute;left:0;top:50%;width:3px;height:3px;border-radius:50%;background:var(--ds-line-strong);transform:translateY(-50%)}
.ds-meta{display:flex;flex-wrap:wrap;gap:30px;margin-top:24px;padding-top:20px;border-top:1px solid var(--ds-line)}
.ds-meta-item{display:grid;gap:3px}
.ds-meta-item .ds-label{color:var(--ds-ink-3);font-size:11px;font-weight:680;letter-spacing:.06em;text-transform:uppercase}
.ds-meta-item .ds-val{color:var(--ds-ink);font-size:14.5px;font-weight:560}
/* section */
.ds-section{padding-top:32px;border-top:1px solid var(--ds-line-2)}
.ds-section.unframed{border-top:0;padding-top:0}
.ds-section-head{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:18px}
.ds-section-titles{flex:1;min-width:0}
.ds-content>.ds-section .ds-section-titles h2::before{content:"§ " counter(sec,decimal-leading-zero);display:flex;align-items:center;width:fit-content;background:var(--ds-accent-tint);color:var(--ds-accent);font-family:var(--ds-mono);font-size:11.5px;font-weight:600;letter-spacing:.07em;padding:4px 10px;border-radius:999px;margin-bottom:12px}
.ds-section-titles .ds-muted{margin:7px 0 0;font-size:15px}
.ds-toggle{flex:none;display:inline-flex;align-items:center;justify-content:center;border:0;background:transparent;color:var(--ds-ink-3);width:28px;height:28px;border-radius:8px;cursor:pointer;transition:background .12s,color .12s}
.ds-toggle:hover{background:var(--ds-bg-2);color:var(--ds-ink)}
.ds-toggle svg{transition:transform .2s var(--ds-ease)}
.ds-section[data-collapsed="1"] .ds-toggle svg{transform:rotate(-90deg)}
.ds-section-body{display:grid;gap:18px}
.ds-section-body>*{min-width:0}
.ds-section[data-collapsed="1"] .ds-section-body{display:none}
.ds-twocol{display:grid;grid-template-columns:1fr 1fr;gap:28px}
/* outlined cards (equal-size) */
.ds-cardgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:14px}
.ds-card{padding:17px 19px;border:1px solid var(--ds-line-2);border-radius:13px;background:var(--ds-bg);transition:border-color .14s var(--ds-ease),transform .14s var(--ds-ease)}
.ds-card h3{font-size:15.5px;margin:0 0 7px}
.ds-card p{margin:0;color:var(--ds-ink-2);font-size:14.5px}
.ds-statgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px}
.ds-stat{padding:16px 18px;border:1px solid var(--ds-line-2);border-radius:13px;background:var(--ds-bg)}
.ds-stat strong{display:block;font-size:30px;font-weight:600;letter-spacing:-.022em;line-height:1;font-variant-numeric:tabular-nums}
.ds-stat span{display:block;margin-top:8px;color:var(--ds-ink-2);font-size:13px}
.ds-stat-delta{display:block;margin-top:10px;color:var(--ds-ink-3);font-size:12px;font-weight:620;font-variant-numeric:tabular-nums}
.ds-stat-delta span{display:inline;margin:0;color:inherit;font-size:inherit}
.ds-stat-delta.tone-up,.ds-stat-delta.tone-positive,.ds-stat-delta.tone-good{color:var(--ds-ok)}
.ds-stat-delta.tone-down,.ds-stat-delta.tone-negative,.ds-stat-delta.tone-bad{color:var(--ds-danger)}
.ds-stat-delta.tone-warn,.ds-stat-delta.tone-warning{color:var(--ds-warn)}
/* flow */
.ds-flow{position:relative;display:grid;counter-reset:flow}
.ds-flow::before{content:"";position:absolute;left:15px;top:24px;bottom:24px;width:1px;background:var(--ds-line)}
.ds-flowstep{position:relative;display:grid;grid-template-columns:32px 1fr;gap:18px;padding:15px 0;border-top:1px solid var(--ds-line);align-items:start}
.ds-flowstep:first-child{border-top:0}
.ds-flowstep::before{position:relative;z-index:1;counter-increment:flow;content:counter(flow,decimal-leading-zero);display:inline-flex;align-items:center;justify-content:center;width:32px;height:24px;background:var(--ds-bg);font-family:var(--ds-mono);font-size:12.5px;color:var(--ds-accent);padding-top:3px}
.ds-flowstep-body strong{display:block;margin-bottom:3px;font-size:15.5px}
.ds-flowstep-body span{color:var(--ds-ink-2);font-size:15px}
/* timeline */
.ds-timeline{position:relative;display:grid}
.ds-timeline::before{content:"";position:absolute;left:131px;top:24px;bottom:24px;width:1px;background:var(--ds-line)}
.ds-phase{position:relative;display:grid;grid-template-columns:120px 1fr;gap:24px;padding:15px 0;border-top:1px solid var(--ds-line)}
.ds-phase:first-child{border-top:0}
.ds-phase::before{content:"";position:absolute;left:124px;top:24px;width:15px;height:15px;border-radius:50%;background:var(--ds-bg);border:1px solid var(--ds-line-strong)}
.ds-phase-id{display:flex;flex-direction:column;gap:7px;color:var(--ds-ink);font-weight:600;font-size:14.5px;align-items:flex-start}
.ds-date{color:var(--ds-ink-3);font-size:12px;font-weight:500}
.ds-phase>div:last-child{color:var(--ds-ink-2)}
/* tables (pan on narrow screens without exposing nested scroll chrome) */
.ds-tablewrap{overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch}
table{width:100%;border-collapse:collapse;font-size:14.5px;margin:0}
th,td{text-align:left;padding:10px 16px 10px 0;border-bottom:1px solid var(--ds-line);vertical-align:top}
th{color:var(--ds-ink-3);font-size:11px;font-weight:680;letter-spacing:.05em;text-transform:uppercase;border-bottom-color:var(--ds-line-2);white-space:nowrap}
td{color:var(--ds-ink-2)}
td strong{color:var(--ds-ink)}
tr.ds-rec td{color:var(--ds-ink)}
/* chips */
.ds-status,.ds-lvl,.ds-akind,.ds-astatus,.ds-badge{display:inline-block;font-size:11px;font-weight:620;letter-spacing:.02em}
.ds-status{padding:2px 9px;border-radius:999px;background:var(--ds-bg-3);color:var(--ds-ink-2);text-transform:capitalize}
.s-done,.s-shipped{color:var(--ds-ok);background:var(--ds-ok-tint)} .s-in-progress,.s-doing{color:var(--ds-accent);background:var(--ds-accent-tint)} .s-blocked{color:var(--ds-danger);background:var(--ds-danger-tint)}
.ds-lvl{text-transform:capitalize}
.ds-lvl.l-high{color:var(--ds-danger)} .ds-lvl.l-medium{color:var(--ds-warn)} .ds-lvl.l-low{color:var(--ds-ok)}
/* callout */
.ds-callout{border-left:2px solid var(--ds-line-strong);padding:2px 0 2px 18px;color:var(--ds-ink-2)}
.ds-callout strong{color:var(--ds-ink)}
.ds-callout.tone-tip{border-left-color:var(--ds-accent)}
.ds-callout.tone-ok{border-left-color:var(--ds-ok)}
.ds-callout.tone-warn{border-left-color:var(--ds-warn)}
.ds-callout.tone-danger{border-left-color:var(--ds-danger)}
/* code */
.ds-code,.ds-diagram{border:1px solid var(--ds-line);border-radius:11px;overflow:hidden;background:var(--ds-bg-2)}
.ds-code-bar{display:flex;justify-content:space-between;align-items:center;gap:12px;padding:8px 14px;font-family:var(--ds-mono);font-size:12px;color:var(--ds-ink-3);border-bottom:1px solid var(--ds-line)}
.ds-code-bar .ds-lang{color:var(--ds-accent);letter-spacing:.02em}
.ds-code-copy{border:1px solid var(--ds-line-2);background:var(--ds-bg);color:var(--ds-ink-3);font-family:var(--ds-font);font-size:11.5px;font-weight:560;border-radius:7px;padding:3px 10px;cursor:pointer;transition:color .12s,border-color .12s,transform .1s}
.ds-code-copy:hover{color:var(--ds-ink);border-color:var(--ds-line-strong)}
pre{margin:0;overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;padding:15px;font-family:var(--ds-mono);font-size:13px;line-height:1.6;color:var(--ds-ink)}
pre code{background:transparent;border:0;padding:0;font-size:inherit}
/* Shiki dual-theme highlighting (build-time, no client JS) */
.ds-code .shiki{background:transparent!important;margin:0}
.ds-code .shiki,.ds-code .shiki span{color:var(--shiki-light)}
[data-theme="dark"] .ds-code .shiki,[data-theme="dark"] .ds-code .shiki span{color:var(--shiki-dark)}
/* Graphviz diagram, baked to inline SVG */
.ds-diagram-svg{display:flex;justify-content:center;padding:18px;background:#fff;border:0}
.ds-diagram-svg svg{max-width:100%;height:auto}
/* code editor */
.ds-codeedit{border:1px solid var(--ds-line-2);border-radius:12px;background:var(--ds-bg);overflow:hidden;margin-top:12px}
.ds-codeedit.dirty{border-color:var(--ds-accent)}
.ds-codeedit-bar{display:flex;justify-content:space-between;gap:12px;align-items:center;padding:9px 14px;border-bottom:1px solid var(--ds-line);background:var(--ds-bg-2);font-family:var(--ds-mono);font-size:12px;color:var(--ds-ink-3)}
.ds-codeedit-bar .ds-lang{color:var(--ds-accent)}
.ds-codeedit-bar .ds-lang,.ds-code-bar .ds-lang{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ds-codeedit-meta{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:8px;font-family:var(--ds-font);min-width:0}
.ds-codeedit-meta span{border:1px solid var(--ds-line-2);border-radius:999px;padding:2px 8px;background:var(--ds-bg);font-size:11.5px;color:var(--ds-ink-2)}
.ds-codeedit-area{display:block;width:100%;min-height:220px;border:0;border-radius:0;background:var(--ds-bg);color:var(--ds-ink);font-family:var(--ds-mono);font-size:13px;line-height:1.55;padding:14px 16px;resize:vertical;tab-size:2;overflow:hidden}
.ds-codeedit-area:focus{outline:2px solid var(--ds-accent-tint);outline-offset:-2px}
.ds-codeedit-actions{display:flex;flex-wrap:wrap;gap:8px;align-items:center;justify-content:flex-end;padding:10px 12px;border-top:1px solid var(--ds-line);background:var(--ds-bg-2)}
.ds-codeedit-state{margin-right:auto;color:var(--ds-ink-3);font-size:12px;font-weight:680;letter-spacing:.04em;text-transform:uppercase}
.ds-codeedit.dirty .ds-codeedit-state{color:var(--ds-accent)}
/* process block family */
.ds-process-list{display:grid;gap:10px;margin-top:14px;min-width:0}
.ds-process-card{border:1px solid var(--ds-line-2);border-radius:12px;background:var(--ds-bg);padding:14px 16px;min-width:0;overflow-wrap:anywhere}
.ds-process-card-head{display:flex;justify-content:space-between;gap:14px;align-items:flex-start}
.ds-process-card h4{margin:0 0 4px;font-size:15.5px}
.ds-gate{border:1px solid var(--ds-line-2);border-radius:12px;background:var(--ds-bg);padding:14px 16px;margin-top:12px}
.ds-comments{margin:10px 0 0;padding-left:20px;color:var(--ds-ink-2)}
.ds-comments li+li{margin-top:8px}
.ds-comments p{margin:4px 0 0}
.ds-release-list{display:grid;gap:10px}
.ds-release-gate{display:grid;gap:8px}
.ds-release-gate textarea{min-height:58px}
.ds-finding .ds-chip{border-color:rgba(214,48,49,.26)}
.ds-vrun .ds-chip{border-color:rgba(18,161,104,.26)}
.ds-trust-sources{margin-top:14px}
.ds-trust-sources h4{margin:0 0 8px;color:var(--ds-ink)}
.ds-trust-sources table{font-size:13.5px}
.ds-trust-claims{margin-top:14px}
.ds-trust-claim{border-left:3px solid var(--ds-line-strong)}
.ds-trust-claim.status-verified,.ds-trust-claim.status-accepted{border-left-color:var(--ds-ok)}
.ds-trust-claim.status-disputed,.ds-trust-claim.status-rejected{border-left-color:var(--ds-danger)}
.ds-trust-claim.status-partial,.ds-trust-claim.status-unverified{border-left-color:var(--ds-warn)}
.ds-trust-refs{display:flex;flex-wrap:wrap;gap:7px;margin-top:10px;padding-top:10px;border-top:1px solid var(--ds-line)}
.ds-trust-link{text-decoration:none}
.ds-trust-missing{color:var(--ds-danger);border-color:rgba(214,48,49,.3)}
/* patch and diff blocks */
.ds-patchlist{display:grid;gap:12px;margin-top:14px}
.ds-patch{border:1px solid var(--ds-line-2);border-radius:12px;background:var(--ds-bg);padding:15px 17px}
.ds-patch-head{display:flex;justify-content:space-between;gap:16px;align-items:flex-start}
.ds-patch h4{margin:0 0 4px;font-size:15.5px}
.ds-patch .ds-detailgrid{margin-top:12px}
.ds-patch-review,.ds-diff-review{display:grid;gap:9px;margin-top:12px}
.ds-patch-review label,.ds-diff-review label,.ds-hunk-head label{display:grid;gap:4px;color:var(--ds-ink-3);font-size:12px;font-weight:650}
.ds-patch-review select,.ds-diff-review select,.ds-hunk-head select{border:1px solid var(--ds-line-2);border-radius:7px;background:var(--ds-bg);color:var(--ds-ink);padding:5px 7px;font:12px var(--ds-font)}
.ds-patch-review textarea,.ds-diff-review textarea,.ds-diff-comment{width:100%;min-height:54px;border:1px solid var(--ds-line-2);border-radius:8px;background:var(--ds-bg);color:var(--ds-ink);padding:8px 9px;font:13px/1.45 var(--ds-font);resize:vertical}
.ds-diffview{margin-top:15px}
.ds-diffview.nested{border-top:1px solid var(--ds-line);padding-top:14px}
.ds-diff-summary{display:flex;flex-wrap:wrap;gap:8px;margin:10px 0;color:var(--ds-ink-2);font-size:12.5px;font-weight:650;font-variant-numeric:tabular-nums}
.ds-diff-summary span{border:1px solid var(--ds-line-2);border-radius:999px;padding:3px 9px;background:var(--ds-bg)}
.ds-diff-summary .add{color:var(--ds-ok);border-color:rgba(18,161,104,.3)}
.ds-diff-summary .del{color:var(--ds-danger);border-color:rgba(214,48,49,.3)}
.ds-diff-files{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 12px}
.ds-diff-filelink{display:inline-flex;gap:8px;align-items:center;max-width:100%;border:1px solid var(--ds-line-2);border-radius:8px;padding:6px 9px;color:var(--ds-ink-2);font-size:12px;text-decoration:none}
.ds-diff-filelink span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:280px}
.ds-diff-filelink b{color:var(--ds-ink-3);font-weight:650;font-variant-numeric:tabular-nums}
.ds-diff-file{border:1px solid var(--ds-line-2);border-radius:12px;background:var(--ds-bg);overflow:hidden;margin-top:10px}
.ds-diff-file summary{display:flex;justify-content:space-between;gap:12px;align-items:center;padding:11px 14px;cursor:pointer;background:var(--ds-bg-2);font-weight:650}
.ds-diff-path{font-family:var(--ds-mono);font-size:12.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ds-diff-stat{font-size:12px;color:var(--ds-ink-3);font-variant-numeric:tabular-nums}
.ds-diff-meta-lines{display:grid;gap:2px;padding:9px 14px;border-top:1px solid var(--ds-line);font-family:var(--ds-mono);font-size:12px;color:var(--ds-ink-3);background:var(--ds-bg)}
.ds-hunk{border-top:1px solid var(--ds-line)}
.ds-hunk-head{display:flex;justify-content:space-between;gap:12px;align-items:center;padding:7px 14px;background:var(--ds-accent-tint);color:var(--ds-accent);font-family:var(--ds-mono);font-size:12px;font-weight:650}
.ds-hunk-head label{min-width:138px;color:var(--ds-ink-2);font-family:var(--ds-font)}
.ds-diff-comment{border-radius:0;border-left:0;border-right:0;border-top:0}
.ds-diff-lines{margin:0;overflow-x:auto;overflow-y:hidden;background:var(--ds-bg);font-family:var(--ds-mono);font-size:12.5px;line-height:1.5}
.ds-diff-line{display:grid;grid-template-columns:46px 46px 22px minmax(0,1fr);min-width:min(520px,100%)}
.ds-diff-line span{padding:0 7px}
.ds-diff-num{color:var(--ds-ink-3);text-align:right;border-right:1px solid var(--ds-line);user-select:none}
.ds-diff-mark{color:var(--ds-ink-3);text-align:center;user-select:none}
.ds-diff-code{white-space:pre}
.ds-diff-line.add{background:rgba(18,161,104,.1)}
.ds-diff-line.add .ds-diff-mark,.ds-diff-line.add .ds-diff-code{color:var(--ds-ok)}
.ds-diff-line.del{background:rgba(214,48,49,.09)}
.ds-diff-line.del .ds-diff-mark,.ds-diff-line.del .ds-diff-code{color:var(--ds-danger)}
.ds-diff-line.meta{color:var(--ds-ink-3);background:var(--ds-bg-2)}
.ds-diff-empty{padding:14px;overflow-x:auto;overflow-y:hidden;border:1px solid var(--ds-line-2);border-radius:12px;background:var(--ds-bg);font-family:var(--ds-mono)}
/* figure */
.ds-figure{margin:0;display:grid;gap:9px}
.ds-figure img{display:block;max-width:100%;height:auto;border:1px solid var(--ds-line);border-radius:12px}
.ds-figure figcaption{color:var(--ds-ink-3);font-size:13px;text-align:center}
/* math (KaTeX MathML, native render) */
.ds-math{overflow-x:auto;overflow-y:hidden;text-align:center;font-size:1.05em;line-height:1.45;padding:6px 2px 8px}
.ds-math.inline{display:inline-block;text-align:left}
.ds-math math{font-size:1.15em}
/* footnotes */
.ds-fnref{font-size:.72em;line-height:0}
.ds-fnref a{padding:0 1px}
.ds-citeref{font-size:.72em;line-height:0}
.ds-citeref a{padding:0 2px;text-decoration:none}
.ds-footnotes{margin:0;padding-left:22px;color:var(--ds-ink-2);font-size:14.5px}
.ds-footnotes li{margin:6px 0}
.ds-footnotes li:target{background:var(--ds-accent-tint);border-radius:6px}
.ds-citations{margin:0;padding-left:24px;color:var(--ds-ink-2);font-size:14.5px}
.ds-citations li{margin:10px 0;padding-left:4px}
.ds-citations li:target{background:var(--ds-accent-tint);border-radius:6px}
.ds-cite-main{font-weight:750;color:var(--ds-ink)}
.ds-cite-meta{margin-top:2px;color:var(--ds-ink-3);font-size:13px}
.ds-citations blockquote{margin:8px 0 0;padding:6px 10px;border-left:2px solid var(--ds-line-strong);background:var(--ds-bg-2);border-radius:6px}
.ds-fnback{margin-left:4px;text-decoration:none}
/* charts (inline SVG) */
.ds-chart{border:1px solid var(--ds-line);border-radius:12px;background:var(--ds-bg);padding:14px 12px}
.ds-chart-svg{display:block;width:100%;height:auto}
.ds-chart-label,.ds-chart-tick,.ds-chart-value{font-family:var(--ds-font);font-size:11px}
.ds-chart-label,.ds-chart-tick{fill:var(--ds-ink-3)}
.ds-chart-value{fill:var(--ds-ink-2);font-weight:650;font-variant-numeric:tabular-nums}
.ds-chart-grid{stroke:var(--ds-line);stroke-width:1;stroke-dasharray:2 4}
.ds-chart-axis{stroke:var(--ds-line-2);stroke-width:1.2}
.ds-chart-zero{stroke:var(--ds-line-strong);stroke-width:1.2}
/* provenance receipt */
.ds-receipt{border:1px solid var(--ds-line-2);border-radius:12px;background:var(--ds-bg-2);padding:16px 18px;font-size:14px}
.ds-receipt-head{font-weight:680;font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--ds-ink-3);margin-bottom:12px}
.ds-receipt .ds-detail{grid-template-columns:120px 1fr}
.ds-receipt-sources{margin-top:12px;padding-top:12px;border-top:1px solid var(--ds-line)}
.ds-receipt-sources ul{margin:6px 0 0;padding-left:20px;color:var(--ds-ink-2)}
/* plugin block fallback (Node string renderer injected into the React port) */
.ds-content>.ds-pluginblock{margin-top:34px}
.ds-content>.ds-pluginblock:first-child{margin-top:0}
/* tabs */
.ds-tabbar{display:flex;gap:22px;border-bottom:1px solid var(--ds-line);margin-bottom:20px;overflow-x:auto;overflow-y:hidden;padding-bottom:1px}
.ds-tab{border:0;background:transparent;padding:0 0 11px;color:var(--ds-ink-3);font-size:14px;font-weight:560;border-bottom:1.5px solid transparent;margin-bottom:-1px;cursor:pointer;white-space:nowrap}
.ds-tab.active{color:var(--ds-ink);border-bottom-color:var(--ds-accent)}
.ds-pane{display:none}
.ds-pane.active{display:grid;gap:20px}
/* faq */
details.ds-faq{border-bottom:1px solid var(--ds-line);padding:14px 0}
details.ds-faq summary{cursor:pointer;font-weight:560;list-style:none;display:flex;justify-content:space-between;align-items:center;gap:16px}
details.ds-faq summary::-webkit-details-marker{display:none}
details.ds-faq summary::after{content:"+";color:var(--ds-ink-3);font-size:18px;flex:none}
details.ds-faq[open] summary::after{content:"-"}
details.ds-faq p{margin:12px 0 2px;color:var(--ds-ink-2)}
/* action items */
.ds-actions{list-style:none;padding:0;margin:0;display:grid}
.ds-action{display:flex;align-items:center;justify-content:space-between;gap:14px;padding:13px 0;border-top:1px solid var(--ds-line)}
.ds-action:first-child{border-top:0}
.ds-action label{display:flex;align-items:center;gap:12px;cursor:pointer;flex:1;min-width:0}
.ds-action input{width:17px;height:17px;accent-color:var(--ds-accent);flex:none}
.ds-action.done .ds-action-title{text-decoration:line-through;color:var(--ds-ink-3)}
.ds-action-meta{display:flex;gap:12px;align-items:center;flex:none}
.ds-owner{font-size:12.5px;color:var(--ds-ink-3)}
/* assumptions */
.ds-assumptions{list-style:none;padding:0;margin:0;display:grid}
.ds-assumption{display:grid;grid-template-columns:auto 1fr auto;gap:14px;align-items:baseline;padding:12px 0;border-top:1px solid var(--ds-line)}
.ds-assumption:first-child{border-top:0}
.ds-akind{font-size:11px;text-transform:uppercase;letter-spacing:.05em;color:var(--ds-ink-3)}
.ds-astatus{color:var(--ds-ink-3)}
.ds-assumption.a-verified .ds-astatus{color:var(--ds-ok)}
.ds-assumption.a-rejected .ds-astatus{color:var(--ds-danger)}
/* glossary */
.ds-glossary{display:grid;margin:0}
.ds-gterm{display:grid;grid-template-columns:200px 1fr;gap:24px;padding:13px 0;border-top:1px solid var(--ds-line)}
.ds-gterm:first-child{border-top:0}
.ds-gterm dt{font-weight:560}
.ds-gterm dd{margin:0;color:var(--ds-ink-2)}
.ds-term{border-bottom:1px dotted var(--ds-ink-3);cursor:help}
.ds-xlink{color:var(--ds-accent)}
/* review / triage list */
.ds-reviewboard .ds-review-bar{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin:16px 0 13px}
.ds-review-search{flex:1 1 170px;height:36px;border:1px solid var(--ds-line-2);border-radius:9px;background:var(--ds-bg-2);padding:0 12px;font-size:13.5px;outline:0}
.ds-review-search:focus{border-color:var(--ds-line-strong);background:var(--ds-bg)}
.ds-review-only{display:inline-flex;align-items:center;gap:8px;color:var(--ds-ink-2);font-size:13.5px;font-weight:520;cursor:pointer}
.ds-review-only input{width:16px;height:16px;accent-color:var(--ds-accent)}
.ds-review-count{color:var(--ds-ink-2);font-size:13.5px;font-weight:560;font-variant-numeric:tabular-nums}
.ds-btn-line{border:1px solid var(--ds-line-2);background:var(--ds-bg);color:var(--ds-ink-2);height:36px}
.ds-btn-line:hover{border-color:var(--ds-line-strong);background:var(--ds-bg-2);color:var(--ds-ink)}
.ds-rlist{display:grid;gap:9px}
.ds-ritem{border:1px solid var(--ds-line-2);border-radius:12px;background:var(--ds-bg);overflow:hidden;transition:border-color .14s var(--ds-ease)}
.ds-ritem:hover{border-color:var(--ds-line-strong)}
.ds-ritem.selected{border-color:var(--ds-accent)}
.ds-ritem.selected .ds-ritem-head{background:var(--ds-accent-tint)}
.ds-ritem-head{display:grid;grid-template-columns:auto 1fr auto;gap:14px;align-items:start;padding:15px 17px;cursor:pointer}
.ds-ritem-check{display:flex;align-items:center;padding-top:1px}
.ds-ritem-check input{width:18px;height:18px;accent-color:var(--ds-accent);cursor:pointer}
.ds-ritem-titles{min-width:0}
.ds-row-anchor{display:inline-flex;width:max-content;margin:0 0 5px;padding:2px 7px;border:1px solid var(--ds-line);border-radius:999px;background:var(--ds-bg-2);color:var(--ds-ink-3);font-family:var(--ds-mono);font-size:10.5px;font-weight:650;letter-spacing:.04em;text-decoration:none}
.ds-row-anchor:hover{border-color:var(--ds-line-strong);color:var(--ds-accent);text-decoration:none}
.ds-ritem:target{border-color:var(--ds-accent);box-shadow:0 0 0 3px var(--ds-accent-tint)}
.ds-ritem-titles h4{font-size:15.5px;margin:0 0 3px}
.ds-ritem-titles .ds-muted{margin:0;font-size:14px}
.ds-ritem-aside{display:flex;align-items:center;gap:11px;white-space:nowrap}
.ds-chev{color:var(--ds-ink-3);font-size:12px;transition:transform .22s var(--ds-ease)}
.ds-ritem.open .ds-chev{transform:rotate(180deg)}
.ds-chips{display:flex;flex-wrap:wrap;gap:7px;margin-top:10px}
.ds-chip{padding:3px 10px;border:1px solid var(--ds-line-2);border-radius:999px;color:var(--ds-ink-2);font-size:11px;font-weight:560}
.ds-ritem-wrap{display:grid;grid-template-rows:0fr;transition:grid-template-rows .26s var(--ds-ease)}
.ds-ritem.open .ds-ritem-wrap{grid-template-rows:1fr}
.ds-ritem-body{overflow:hidden;min-height:0;padding:0 17px}
.ds-ref{padding-top:6px;border-top:1px solid var(--ds-line)}
.ds-ref>*{margin-top:15px}
.ds-notes{display:grid;gap:7px;padding:15px 0 17px}
.ds-notes span{color:var(--ds-ink-3);font-size:11.5px;font-weight:680;letter-spacing:.05em;text-transform:uppercase}
.ds-detailgrid{display:grid;margin:0}
.ds-detail{display:grid;grid-template-columns:120px 1fr;gap:16px;padding:8px 0;border-top:1px solid var(--ds-line)}
.ds-detail dt{color:var(--ds-ink-3);font-size:12px;text-transform:uppercase;letter-spacing:.04em}
.ds-detail dd{margin:0;color:var(--ds-ink-2);min-width:0;overflow-wrap:anywhere}
textarea{width:100%;min-height:80px;resize:vertical;border:1px solid var(--ds-line-2);border-radius:9px;background:var(--ds-bg);padding:10px 11px;font-size:14px;line-height:1.5;outline:0;overflow:hidden}
textarea:focus{border-color:var(--ds-line-strong)}
/* process boards */
.ds-pitem .ds-ritem-head{grid-template-columns:1fr auto}
.ds-pitem.verdict-approve{border-color:var(--ds-ok)}
.ds-pitem.verdict-approve .ds-ritem-head{background:rgba(18,161,104,.08)}
.ds-pitem.verdict-block{border-color:var(--ds-danger)}
.ds-pitem.verdict-block .ds-ritem-head{background:rgba(214,48,49,.08)}
.ds-pitem.verdict-revise,.ds-pitem.verdict-retry{border-color:var(--ds-warn)}
.ds-pitem.verdict-revise .ds-ritem-head,.ds-pitem.verdict-retry .ds-ritem-head{background:rgba(245,158,11,.09)}
.ds-process-verdict-wrap{display:flex;align-items:center;gap:7px;color:var(--ds-ink-3);font-size:11px;font-weight:680;letter-spacing:.04em;text-transform:uppercase;cursor:default}
.ds-process-verdict{height:32px;border:1px solid var(--ds-line-2);border-radius:8px;background:var(--ds-bg);color:var(--ds-ink);font:inherit;font-size:12px;font-weight:620;letter-spacing:0;text-transform:none;padding:0 26px 0 9px;cursor:pointer}
.ds-process-verdict:focus{outline:2px solid var(--ds-accent-tint);border-color:var(--ds-line-strong)}
.ds-footer{padding:24px 0 calc(24px + env(safe-area-inset-bottom));border-top:1px solid var(--ds-line);color:var(--ds-ink-3);font-size:12.5px}
/* palette + modals */
.ds-palette{position:fixed;inset:0;z-index:70;background:rgba(14,11,22,.42);display:flex;align-items:flex-start;justify-content:center;padding:13vh 16px 16px}
.ds-palette[hidden]{display:none}
.ds-palette-box{width:min(620px,100%);background:var(--ds-bg);border:1px solid var(--ds-line-2);border-radius:16px;box-shadow:0 30px 70px rgba(14,11,22,.3);overflow:hidden}
.ds-palette-input{width:100%;border:0;border-bottom:1px solid var(--ds-line);padding:18px 20px;font-size:16px;background:transparent;outline:0}
.ds-palette-list{max-height:52vh;overflow:auto;-webkit-overflow-scrolling:touch;padding:8px}
.ds-palette-item{display:flex;justify-content:space-between;gap:10px;padding:12px 14px;border-radius:10px;cursor:pointer;font-weight:520;font-size:14.5px}
.ds-palette-item.active{background:var(--ds-bg-2)}
.ds-palette-item small{color:var(--ds-ink-3)}
.ds-modal{position:fixed;inset:0;z-index:70;background:rgba(14,11,22,.42);display:flex;align-items:center;justify-content:center;padding:18px}
.ds-modal[hidden]{display:none}
.ds-modal-box{width:min(820px,100%);max-height:84vh;display:flex;flex-direction:column;background:var(--ds-bg);border:1px solid var(--ds-line-2);border-radius:16px;overflow:hidden;box-shadow:0 30px 70px rgba(14,11,22,.3)}
.ds-modal-head{display:flex;justify-content:space-between;align-items:center;padding:14px 16px;border-bottom:1px solid var(--ds-line)}
.ds-modal-box textarea{flex:1;min-height:54vh;border:0;border-radius:0;font-family:var(--ds-mono);font-size:13px}
.ds-shortcuts-box{width:min(520px,100%)}
.ds-shortcuts{display:grid;gap:8px;margin:0;padding:16px}
.ds-shortcuts div{display:grid;grid-template-columns:92px minmax(0,1fr);align-items:center;gap:12px;border:1px solid var(--ds-line);border-radius:10px;background:var(--ds-bg-2);padding:10px 12px}
.ds-shortcuts dt{display:flex;gap:4px;margin:0}
.ds-shortcuts dd{margin:0;color:var(--ds-ink-2);font-size:13.5px}
.ds-toast{position:fixed;right:18px;bottom:calc(18px + env(safe-area-inset-bottom));z-index:80;background:var(--ds-ink);color:var(--ds-bg);border-radius:11px;padding:11px 16px;font-size:13.5px;font-weight:560;box-shadow:0 16px 38px rgba(14,11,22,.32);opacity:0;transform:translateY(8px);transition:.18s var(--ds-ease);pointer-events:none}
.ds-toast.show{opacity:1;transform:none}
/* back to top */
.ds-totop{position:fixed;left:18px;bottom:calc(18px + env(safe-area-inset-bottom));z-index:50;display:flex;align-items:center;justify-content:center;width:42px;height:42px;border-radius:50%;border:1px solid var(--ds-line-2);background:var(--ds-bg);color:var(--ds-ink-2);font-size:17px;cursor:pointer;box-shadow:0 10px 28px rgba(20,16,40,.14);opacity:0;transform:translateY(10px) scale(.92);transition:.2s var(--ds-ease);pointer-events:none}
.ds-totop.show{opacity:1;transform:none;pointer-events:auto}
.ds-totop:hover{color:var(--ds-accent);border-color:var(--ds-line-strong)}
/* entrance reveal, JS-added, so no-JS markup stays visible */
.ds-reveal{opacity:0;transform:translateY(12px);transition:opacity .55s var(--ds-ease),transform .55s var(--ds-ease)}
.ds-reveal.in{opacity:1;transform:none}
/* hover lift + link underline + press feedback (pointer devices) */
@media (hover:hover){
.ds-card,.ds-stat{transition:border-color .14s var(--ds-ease),transform .14s var(--ds-ease)}
.ds-card:hover,.ds-stat:hover{transform:translateY(-2px);border-color:var(--ds-line-strong)}
.ds-content a:not(.ds-anchor){background:linear-gradient(currentColor 0 0) 0 100% / 0 1.5px no-repeat;transition:background-size .18s var(--ds-ease)}
.ds-content a:not(.ds-anchor):hover{background-size:100% 1.5px;text-decoration:none}
}
.ds-btn:active,.ds-menu>summary:active,.ds-toggle:active,.ds-totop:active,.ds-code-copy:active{transform:scale(.96)}
@media (prefers-contrast:more){
:root{--ds-line:#c5c0d0;--ds-line-2:#aaa3ba;--ds-line-strong:#7d738f;--ds-ink-3:#595164}
[data-theme="dark"]{--ds-line:#4f475f;--ds-line-2:#665d78;--ds-line-strong:#8c82a0;--ds-ink-3:#cac4d6}
}
/* heading anchors */
.ds-content h2,.ds-content h3{position:relative}
.ds-anchor{margin-left:9px;color:var(--ds-ink-3);font-weight:400;opacity:0;text-decoration:none;transition:opacity .12s var(--ds-ease),color .12s var(--ds-ease)}
.ds-content h2:hover .ds-anchor,.ds-content h3:hover .ds-anchor,.ds-anchor:focus-visible{opacity:1}
.ds-anchor:hover{color:var(--ds-accent)}
tbody tr{transition:color .12s var(--ds-ease)}
tbody tr:hover td{color:var(--ds-ink)}
.ds-action:hover .ds-action-title{color:var(--ds-ink)}
/* ============ responsive ============ */
@media (max-width:1040px){
.ds-shell{width:calc(100% - 40px)}
.ds-layout{grid-template-columns:1fr;gap:0;padding-bottom:80px}
.ds-toc{display:none}
}
@media (max-width:720px){
.ds-shell{width:calc(100% - 32px)}
.ds-topbar{height:52px;gap:10px}
.ds-tools{gap:6px;max-width:calc(100vw - 96px);overflow-x:auto;overscroll-behavior-x:contain;padding-bottom:2px;scrollbar-width:none}
.ds-tools::-webkit-scrollbar{display:none}
.ds-search-btn{min-width:0;width:40px;padding:0;justify-content:center}
.ds-search-btn .ds-search-label,.ds-search-btn kbd{display:none}
.ds-btn[data-theme-toggle]{width:38px;height:38px}
.ds-menu-list{right:0;min-width:220px}
.ds-tool-modal{align-items:flex-start;padding:12px}
.ds-tool-card{max-height:calc(100vh - 24px);border-radius:12px;padding:14px}
.ds-studio{right:12px;top:58px;max-height:calc(100vh - 76px);overflow:auto}
.ds-tool-head{align-items:flex-start;gap:10px}
.ds-export-grid{display:grid;grid-template-columns:1fr 1fr}
.ds-export-grid .ds-btn,.ds-file-btn{width:100%;justify-content:center}
.ds-tool-row,.ds-field-grid{grid-template-columns:1fr}
.ds-field-grid .wide{grid-column:auto}
.ds-hero{padding:24px 0 2px}
.ds-lede{font-size:16.5px;margin-top:15px}
.ds-meta{gap:20px}
.ds-content>.ds-block+.ds-block{margin-top:28px}
.ds-content>.ds-block+.ds-section{margin-top:40px}
.ds-section{padding-top:26px}
.ds-section-body{gap:16px}
h2{font-size:20px}
.ds-twocol{grid-template-columns:1fr;gap:18px}
.ds-phase,.ds-gterm,.ds-detail{grid-template-columns:1fr;gap:5px}
.ds-timeline::before,.ds-phase::before{display:none}
.ds-patch-head,.ds-process-card-head,.ds-hunk-head,.ds-diff-file summary{align-items:flex-start;flex-wrap:wrap}
.ds-ritem-head,.ds-pitem .ds-ritem-head{grid-template-columns:1fr}
.ds-ritem-aside{white-space:normal;flex-wrap:wrap}
.ds-codeedit-bar{align-items:flex-start;flex-direction:column}
.ds-codeedit-meta{justify-content:flex-start}
.ds-review-search{flex-basis:100%}
.ds-tablewrap{overflow:visible}
.ds-tablewrap table{min-width:0;table-layout:auto}
th,td{padding-right:10px;overflow-wrap:anywhere}
pre{white-space:pre-wrap;overflow-wrap:anywhere}
.ds-diff-line{grid-template-columns:28px 28px 16px minmax(0,1fr);min-width:0}
.ds-diff-line span{padding:0 4px}
.ds-diff-code{white-space:pre-wrap;overflow-wrap:anywhere}
.ds-copy{display:none}
}
@media (max-width:480px){
.ds-shell{width:calc(100% - 24px)}
.ds-crumbs{font-size:13.5px}
.ds-hero h1{font-size:27px}
.ds-lede{font-size:16px}
.ds-statgrid{grid-template-columns:1fr 1fr}
.ds-stat strong{font-size:26px}
.ds-ritem-head{padding:13px 14px;gap:11px}
.ds-ritem-body{padding:0 14px}
.ds-palette{padding-top:9vh}
.ds-shortcuts div{grid-template-columns:1fr;gap:6px}
.ds-export-grid{grid-template-columns:1fr}
.ds-blockedit-row{grid-template-columns:1fr 1fr 1fr}
.ds-blockedit-row b{grid-column:1/-1}
.ds-flowstep{grid-template-columns:26px 1fr;gap:13px}
.ds-flow::before{left:12px}
.ds-flowstep::before{width:26px}
}
/* print / PDF */
@media print{
@page{size:A4;margin:20mm 14mm 18mm}
:root{--ds-bg:#fff;--ds-bg-2:#fff;--ds-ink:#111;--ds-ink-2:#333;--ds-ink-3:#666;--ds-line:#ddd;--ds-line-2:#ccc}
*{-webkit-print-color-adjust:exact;print-color-adjust:exact}
html{font-size:11pt}
body{background:#fff!important;color:#111!important}
.ds-topbar,.ds-toc,.ds-totop,.ds-palette,.ds-modal,.ds-tool-modal,.ds-toast,.ds-studio,.ds-progress,.ds-skip,.ds-copy,.ds-review-bar,.ds-ritem-check,.ds-notes,.ds-toggle,.ds-code-copy,.ds-codeedit-actions,.ds-diff-files,.ds-process-verdict-wrap,.ds-release-gate textarea{display:none!important}
.ds-layout{display:block}
.ds-content{max-width:none}
.ds-shell{width:100%;background:#fff;box-shadow:none}
.ds-section[data-collapsed="1"] .ds-section-body{display:grid!important}
.ds-ritem-wrap{grid-template-rows:1fr!important}
.ds-section,.ds-block,.ds-hero,.ds-ritem,.ds-card,.ds-stat,.ds-chart,.ds-figure,.ds-codeedit,.ds-patch,.ds-diff-file,.ds-hunk,table,pre{break-inside:avoid-page;box-shadow:none}
.ds-section,.ds-block{border-color:#ddd}
.ds-block{margin-block:12pt}
.ds-hero{padding-top:0}
.ds-reveal{opacity:1!important;transform:none!important}
h1,h2,h3,h4{break-after:avoid;orphans:3;widows:3}
p,li,blockquote{orphans:3;widows:3}
pre,.ds-diff-line{white-space:pre-wrap;overflow:visible}
.ds-tablewrap{overflow:visible}
table{width:100%;page-break-inside:auto}
tr{break-inside:avoid-page}
img,svg,.ds-chart-svg{max-width:100%!important;height:auto}
a{color:inherit;text-decoration:none}
.ds-content a[href^="http"]::after{content:" (" attr(href) ")";font-size:.86em;color:#666;overflow-wrap:anywhere}
.ds-content .ds-citeref a::after,.ds-content .ds-fnref a::after{content:""}
}
:root{--ds-accent: #15803d;--ds-accent-2: #166534;--ds-accent-tint: rgba(21,128,61,.1);}[data-theme="dark"]{--ds-accent: #15803d;--ds-accent-2: #166534;--ds-accent-tint: rgba(21,128,61,.1);}</style>
</head>
<body>
<a class="ds-skip" href="#main">Skip to content</a>
<div class="ds-progress"><div class="ds-progress-bar"></div></div>
<div class="ds-shell">
<header class="ds-topbar">
<div class="ds-brand"><span class="ds-mark"></span><span class="ds-crumbs">Examples / Engineering release</span></div>
<div class="ds-tools">
<button class="ds-btn ds-search-btn" type="button" data-palette-open><span class="ds-i"><svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><circle cx="11" cy="11" r="7"></circle><path d="m20 20-3.4-3.4"></path></svg></span><span class="ds-search-label">Search</span><kbd>⌘K</kbd></button>
<span class="ds-dirty-status" data-dirty-status hidden>state</span>
<button class="ds-btn" type="button" data-edit-toggle title="Edit text in place">Edit</button>
<button class="ds-btn" type="button" data-block-editor-open title="Edit block structure">Blocks</button>
<button class="ds-btn" type="button" data-evidence-open title="Attach evidence">Evidence</button>
<button class="ds-btn ds-swatch" type="button" data-studio-open title="Theme studio"><span></span></button>
<button class="ds-btn" type="button" data-theme-toggle aria-label="Toggle theme">◐</button>
<details class="ds-menu"><summary>Export</summary><div class="ds-menu-list">
<button class="ds-btn" type="button" data-action="open-export-center">Open Export Center</button>
<button class="ds-btn" type="button" data-action="copy-md">Copy Markdown</button>
<button class="ds-btn" type="button" data-action="copy-digest">Copy for AI (digest)</button>
<button class="ds-btn" type="button" data-action="download-md">Download Markdown</button>
<button class="ds-btn" type="button" data-action="download-json">Download source JSON</button>
<button class="ds-btn" type="button" data-action="download-state-json">Download state packet</button>
<button class="ds-btn" type="button" data-action="download-merged-json">Download merged JSON</button>
<button class="ds-btn" type="button" data-action="download-handoff-json">Download agent handoff</button>
<button class="ds-btn" type="button" data-action="copy-prompt">Copy AI prompt</button>
<button class="ds-btn" type="button" data-action="print-pdf">Print / save PDF</button>
<button class="ds-btn" type="button" data-action="view-source">View source</button>
</div></details>
</div>
</header>
<div class="ds-lifecycle stage-review"><b>review</b> A release gate and QA control room.</div>
<div class="ds-layout">
<main class="ds-content" id="main" tabindex="-1">
<section class="ds-hero ds-block" data-block="hero" data-id="a-release-page-that-keeps-gates-evidence-and-claims-together-0"><p class="ds-eyebrow">Release control room</p><h1 id="a-release-page-that-keeps-gates-evidence-and-claims-together-0" data-edit="a-release-page-that-keeps-gates-evidence-and-claims-together-0:title">A release page that keeps gates, evidence, and claims together</h1><p class="ds-lede" data-edit="a-release-page-that-keeps-gates-evidence-and-claims-together-0:lede">Use this shape when a team needs public QA readiness, release notes, command receipts, and a durable closeout packet for agents.</p><div class="ds-pillrow"><span class="ds-pill">Release gates</span><span class="ds-pill">Verification</span><span class="ds-pill">Manual QA</span><span class="ds-pill">Closeout</span></div><div class="ds-meta"><div class="ds-meta-item"><span class="ds-label">Release</span><span class="ds-val">0.5.5</span></div><div class="ds-meta-item"><span class="ds-label">Required gates</span><span class="ds-val">6</span></div><div class="ds-meta-item"><span class="ds-label">State</span><span class="ds-val">Manual QA</span></div></div></section>
<section class="ds-block" data-block="release-checklist" data-id="release-gates-1"><button class="ds-copy" type="button" data-copy aria-label="Copy block" title="Copy"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button><h3 id="release-gates-1">Release gates</h3><ul class="ds-actions ds-release-list"><li class="ds-action ds-release-gate" data-release-row="tests"><label><input type="checkbox" data-release-gate="tests" data-release-title="Automated tests pass" data-release-required="1" checked><span class="ds-action-title">Automated tests pass</span></label><span class="ds-action-meta"><span class="ds-chip">required</span><span class="ds-status s-passed">passed</span></span><textarea data-release-notes="tests" placeholder="Evidence, approver, blocker">npm test</textarea></li><li class="ds-action ds-release-gate" data-release-row="react"><label><input type="checkbox" data-release-gate="react" data-release-title="React renderer typecheck passes" data-release-required="1" checked><span class="ds-action-title">React renderer typecheck passes</span></label><span class="ds-action-meta"><span class="ds-chip">required</span><span class="ds-status s-passed">passed</span></span><textarea data-release-notes="react" placeholder="Evidence, approver, blocker">cd react && npx tsc --noEmit</textarea></li><li class="ds-action ds-release-gate" data-release-row="docs"><label><input type="checkbox" data-release-gate="docs" data-release-title="README and examples regenerated" data-release-required="1" checked><span class="ds-action-title">README and examples regenerated</span></label><span class="ds-action-meta"><span class="ds-chip">required</span><span class="ds-status s-passed">passed</span></span><textarea data-release-notes="docs" placeholder="Evidence, approver, blocker">node bin/dossier.mjs build examples/*.dossier.json</textarea></li><li class="ds-action ds-release-gate" data-release-row="live-editor"><label><input type="checkbox" data-release-gate="live-editor" data-release-title="Live CodeMirror editor smoke passes" data-release-required="1" checked><span class="ds-action-title">Live CodeMirror editor smoke passes</span></label><span class="ds-action-meta"><span class="ds-chip">required</span><span class="ds-status s-passed">passed</span></span><textarea data-release-notes="live-editor" placeholder="Evidence, approver, blocker">Playwright smoke edited a CodeMirror-backed code-editor and saved back to source JSON</textarea></li><li class="ds-action ds-release-gate" data-release-row="manual"><label><input type="checkbox" data-release-gate="manual" data-release-title="Manual browser pass complete" data-release-required="1" ><span class="ds-action-title">Manual browser pass complete</span></label><span class="ds-action-meta"><span class="ds-chip">required</span><span class="ds-status s-todo">todo</span></span><textarea data-release-notes="manual" placeholder="Evidence, approver, blocker">Run docs/product/public-manual-qa.md</textarea></li><li class="ds-action ds-release-gate" data-release-row="npm"><label><input type="checkbox" data-release-gate="npm" data-release-title="npm publish credential available" data-release-required="0" ><span class="ds-action-title">npm publish credential available</span></label><span class="ds-action-meta"><span class="ds-status s-blocked">blocked</span></span><textarea data-release-notes="npm" placeholder="Evidence, approver, blocker">npm whoami if publishing to registry</textarea></li></ul><div class="ds-codeedit-actions"><button class="ds-btn ds-btn-line" type="button" data-export-release>Export release packet</button><button class="ds-btn ds-btn-line" type="button" data-import-release>Import</button></div></section>
<section class="ds-block" data-block="verification-run" data-id="command-receipts-2"><button class="ds-copy" type="button" data-copy aria-label="Copy block" title="Copy"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button><h3 id="command-receipts-2">Command receipts</h3><div class="ds-process-list"><article class="ds-process-card ds-vrun"><div class="ds-process-card-head"><div><h4>Unit tests</h4></div><div class="ds-chips"><span class="ds-chip">status · passed</span><span class="ds-chip">kind · passed</span></div></div><dl class="ds-detailgrid"><div class="ds-detail"><dt>command</dt><dd>npm test</dd></div><div class="ds-detail"><dt>expected</dt><dd>All node tests pass.</dd></div><div class="ds-detail"><dt>actual</dt><dd>Process, trust, export, and render tests passed.</dd></div></dl></article><article class="ds-process-card ds-vrun"><div class="ds-process-card-head"><div><h4>Example build</h4></div><div class="ds-chips"><span class="ds-chip">status · passed</span><span class="ds-chip">kind · passed</span></div></div><dl class="ds-detailgrid"><div class="ds-detail"><dt>command</dt><dd>node bin/dossier.mjs build examples/*.dossier.json</dd></div><div class="ds-detail"><dt>expected</dt><dd>Every example emits HTML and Markdown.</dd></div><div class="ds-detail"><dt>actual</dt><dd>Generated showcase, overview, and focused example pages.</dd></div></dl></article><article class="ds-process-card ds-vrun"><div class="ds-process-card-head"><div><h4>Live editor smoke</h4></div><div class="ds-chips"><span class="ds-chip">status · passed</span><span class="ds-chip">kind · passed</span></div></div><dl class="ds-detailgrid"><div class="ds-detail"><dt>command</dt><dd>dossier serve examples/implementation-packet.dossier.json</dd></div><div class="ds-detail"><dt>expected</dt><dd>CodeMirror mounts, edits sync, and save-back writes the source model.</dd></div><div class="ds-detail"><dt>actual</dt><dd>Playwright verified desktop and mobile CodeMirror mounting, textarea sync, and save-back.</dd></div></dl></article></div></section>
<section class="ds-block" data-block="table" data-id="release-assets-3"><button class="ds-copy" type="button" data-copy aria-label="Copy block" title="Copy"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button><h3 id="release-assets-3">Release assets</h3><div class="ds-tablewrap"><table><thead><tr><th>Asset</th><th>Audience</th><th>Use</th></tr></thead><tbody><tr><td>README.md</td><td>New users</td><td>Install, choose examples, learn block and packet model.</td></tr><tr><td>examples/showcase.html</td><td>Evaluators</td><td>Inspect the full block catalog.</td></tr><tr><td>docs/product/public-manual-qa.md</td><td>Release reviewer</td><td>Run browser, live serve, MCP, and export checks.</td></tr><tr><td>schema/packets/trust.schema.json</td><td>Agents</td><td>Validate trust packets and recorded claims.</td></tr></tbody></table></div></section>
<section class="ds-block" data-block="trust-report" data-id="release-confidence-4"><button class="ds-copy" type="button" data-copy aria-label="Copy block" title="Copy"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button><h3 id="release-confidence-4">Release confidence</h3><div class="ds-trust-sources"><h4>Sources</h4><div class="ds-tablewrap"><table><thead><tr><th>Source</th><th>Kind</th><th>Trust</th><th>License</th><th>Summary</th></tr></thead><tbody><tr id="release-confidence-4-tests" data-trust-source="tests"><td>Automated tests</td><td>command</td><td>high</td><td></td><td>Narrow verification for render, schema, MCP, and packets.</td></tr><tr id="release-confidence-4-manual" data-trust-source="manual"><td>Manual QA guide</td><td>checklist</td><td>medium</td><td></td><td>Human browser pass still required before broad announcement.</td></tr></tbody></table></div></div><div class="ds-process-list ds-trust-claims"><article class="ds-process-card ds-trust-claim status-verified" data-trust-claim="ready-for-manual-qa"><div class="ds-process-card-head"><div><h4>Release is ready for public manual QA.</h4></div><div class="ds-chips"><span class="ds-chip">status · verified</span><span class="ds-chip">confidence · high</span></div></div><div class="ds-trust-refs"><a class="ds-chip ds-trust-link" href="#release-confidence-4-tests">Automated tests</a><a class="ds-chip ds-trust-link" href="#release-confidence-4-manual">Manual QA guide</a><span class="ds-chip">unit-tests</span><span class="ds-chip">example-build</span></div></article><article class="ds-process-card ds-trust-claim status-external" data-trust-claim="registry-publish"><div class="ds-process-card-head"><div><h4>Registry publishing requires npm credentials.</h4></div><div class="ds-chips"><span class="ds-chip">status · external</span><span class="ds-chip">confidence · high</span></div></div><div class="ds-trust-refs"><a class="ds-chip ds-trust-link" href="#release-confidence-4-manual">Manual QA guide</a></div></article></div></section>
<section class="ds-block" data-block="process-receipt" data-id="release-receipt-5"><button class="ds-copy" type="button" data-copy aria-label="Copy block" title="Copy"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg></button><aside class="ds-receipt ds-process-receipt"><div class="ds-receipt-head">Release receipt</div><dl class="ds-detailgrid"><div class="ds-detail"><dt>outcome</dt><dd>Ready for public manual QA</dd></div><div class="ds-detail"><dt>owner</dt><dd>Release captain</dd></div><div class="ds-detail"><dt>date</dt><dd>2026-06-29</dd></div><div class="ds-detail"><dt>commands</dt><dd>npm test, node bin/dossier.mjs build examples/*.dossier.json, dossier serve CodeMirror smoke</dd></div><div class="ds-detail"><dt>risks</dt><dd>Manual QA is not a substitute for production telemetry., Registry publishing depends on credentials.</dd></div><div class="ds-detail"><dt>follow ups</dt><dd>Run public manual QA guide., Confirm Pages deployment after push.</dd></div></dl></aside></section>
</main>
<aside class="ds-toc"><div class="ds-search"><input type="search" placeholder="Search…" data-search></div><div class="ds-toc-head">On this page</div><a class="ds-toc-link lvl-1" href="#a-release-page-that-keeps-gates-evidence-and-claims-together-0" data-toc="a-release-page-that-keeps-gates-evidence-and-claims-together-0">A release page that keeps gates, evidence, and claims together</a><a class="ds-toc-link lvl-2" href="#release-gates-1" data-toc="release-gates-1">Release gates</a><a class="ds-toc-link lvl-2" href="#command-receipts-2" data-toc="command-receipts-2">Command receipts</a><a class="ds-toc-link lvl-2" href="#release-confidence-4" data-toc="release-confidence-4">Release confidence</a><a class="ds-toc-link lvl-2" href="#release-receipt-5" data-toc="release-receipt-5">Release receipt</a></aside>
</div>
<footer class="ds-footer">2 min read · 386 words · Generated with Dossier · 2026-06-29</footer>
</div>
<button class="ds-totop" type="button" data-totop aria-label="Back to top">↑</button>
<div class="ds-palette" data-palette hidden><div class="ds-palette-box" role="dialog" aria-label="Command palette"><input type="text" placeholder="Jump to or run an action…" data-palette-input><div class="ds-palette-list" data-palette-list></div></div></div>
<div class="ds-modal" data-source-modal hidden><div class="ds-modal-box" role="dialog" aria-modal="true" aria-label="Markdown source"><div class="ds-modal-head"><strong>Markdown source</strong><button class="ds-btn" type="button" data-source-close>Close</button></div><textarea readonly data-source-text></textarea></div></div>
<div class="ds-modal" data-shortcuts-modal hidden><div class="ds-modal-box ds-shortcuts-box" role="dialog" aria-modal="true" aria-label="Keyboard shortcuts"><div class="ds-modal-head"><strong>Keyboard shortcuts</strong><button class="ds-btn" type="button" data-shortcuts-close>Close</button></div><dl class="ds-shortcuts"><div><dt><kbd>⌘K</kbd></dt><dd>Open command palette</dd></div><div><dt><kbd>/</kbd></dt><dd>Focus document search</dd></div><div><dt><kbd>?</kbd></dt><dd>Open shortcuts</dd></div><div><dt><kbd>T</kbd></dt><dd>Toggle theme</dd></div><div><dt><kbd>Esc</kbd></dt><dd>Close active panel</dd></div></dl></div></div>
<div class="ds-tool-modal" data-export-modal hidden><div class="ds-tool-card ds-tool-wide" role="dialog" aria-modal="true" aria-label="Export Center"><div class="ds-tool-head"><div><strong>Export Center</strong><p data-export-summary>Choose exactly what should leave this artifact.</p></div><button class="ds-btn ds-btn-line" type="button" data-tool-close>Close</button></div><div class="ds-export-grid"><button class="ds-btn ds-btn-line" type="button" data-export-kind="source">Preview source JSON</button><button class="ds-btn ds-btn-line" type="button" data-export-kind="state">Preview state packet</button><button class="ds-btn ds-btn-line" type="button" data-export-kind="merged">Preview merged JSON</button><button class="ds-btn ds-btn-line" type="button" data-export-kind="handoff">Preview agent handoff</button><button class="ds-btn ds-btn-line" type="button" data-export-kind="prompt">Preview AI prompt</button><label class="ds-file-btn" role="button" tabindex="0">Import state packet<input type="file" accept="application/json" data-state-file></label><label class="ds-file-btn" role="button" tabindex="0">Compare revision<input type="file" accept="application/json" data-revision-file></label></div><div class="ds-export-grid"><button class="ds-btn" type="button" data-export-download="source">Download source JSON</button><button class="ds-btn" type="button" data-export-download="state">Download state packet</button><button class="ds-btn" type="button" data-export-download="merged">Download merged JSON</button><button class="ds-btn" type="button" data-export-download="handoff">Download handoff</button><button class="ds-btn" type="button" data-export-download="prompt">Download prompt</button><button class="ds-btn ds-btn-line" type="button" data-action="print-pdf">Print / save PDF</button><button class="ds-btn ds-btn-line" type="button" data-export-copy>Copy preview</button></div><div class="ds-export-preview-head"><strong data-export-preview-title>Current state packet</strong></div><textarea class="ds-export-preview" readonly data-export-preview></textarea><textarea class="ds-export-preview ds-revision-result" readonly data-revision-result placeholder="Revision diff appears here after comparing another dossier JSON."></textarea></div></div>
<div class="ds-tool-modal" data-block-editor-modal hidden><div class="ds-tool-card" role="dialog" aria-modal="true" aria-label="Block editor"><div class="ds-tool-head"><div><strong>Block editor</strong><p>Reorder, delete, or add top-level blocks, then download merged JSON and rebuild.</p></div><button class="ds-btn ds-btn-line" type="button" data-tool-close>Close</button></div><div class="ds-blockedit-list" data-block-editor-list></div><div class="ds-tool-row"><select data-block-editor-type><option>prose</option><option>section</option><option>callout</option><option>table</option><option>code-editor</option><option>process-board</option><option>patch-set</option><option>verification-run</option><option>release-checklist</option></select><input type="text" data-block-editor-title placeholder="New block title"><button class="ds-btn" type="button" data-block-editor-add>Add block</button></div><p class="ds-tool-note" data-block-editor-status></p></div></div>
<div class="ds-tool-modal" data-evidence-modal hidden><div class="ds-tool-card" role="dialog" aria-modal="true" aria-label="Attach evidence"><div class="ds-tool-head"><div><strong>Attach evidence</strong><p>Add source material to the state packet and merged dossier.</p></div><button class="ds-btn ds-btn-line" type="button" data-tool-close>Close</button></div><div class="ds-field-grid"><label>Id<input type="text" data-evidence-id placeholder="auto-from-title"></label><label>Title<input type="text" data-evidence-title placeholder="Browser smoke"></label><label>Kind<input type="text" data-evidence-kind placeholder="manual"></label><label>Trust<select data-evidence-trust><option>medium</option><option>high</option><option>low</option></select></label><label class="wide">Source<input type="text" data-evidence-source placeholder="command, URL, person, file"></label><label class="wide">Body<textarea data-evidence-body placeholder="What was observed?"></textarea></label></div><div class="ds-tool-actions"><button class="ds-btn" type="button" data-evidence-add>Add evidence</button></div></div></div>
<div class="ds-toast" data-toast role="status" aria-live="polite"></div>
<div class="ds-studio" data-studio hidden role="dialog" aria-label="Theme studio">
<div class="ds-studio-head"><strong>Theme studio</strong><button class="ds-btn" type="button" data-studio-close>Close</button></div>
<label class="ds-studio-row">Accent <input type="color" data-studio-token="accent" data-studio-accent></label>
<label class="ds-studio-row">Canvas <input type="color" data-studio-token="bg"></label>
<label class="ds-studio-row">Surface <input type="color" data-studio-token="bg-2"></label>
<label class="ds-studio-row">Ink <input type="color" data-studio-token="ink"></label>
<label class="ds-studio-row">Frame <input type="text" data-studio-token="frame" placeholder="1120px"></label>
<div class="ds-studio-presets"><button class="ds-studio-sw" type="button" data-studio-preset="berry" title="berry" style="background:#c81e4a"></button><button class="ds-studio-sw" type="button" data-studio-preset="slate" title="slate" style="background:#4f5b6b"></button><button class="ds-studio-sw" type="button" data-studio-preset="forest" title="forest" style="background:#2f7d55"></button><button class="ds-studio-sw" type="button" data-studio-preset="ocean" title="ocean" style="background:#1f7a98"></button><button class="ds-studio-sw" type="button" data-studio-preset="midnight" title="midnight" style="background:#5b6ef5"></button><button class="ds-studio-sw" type="button" data-studio-preset="amber" title="amber" style="background:#c2790c"></button><button class="ds-studio-sw" type="button" data-studio-preset="plum" title="plum" style="background:#8a3ffc"></button></div>
<select class="ds-studio-select" data-studio-saved><option value="">Saved presets</option></select>
<textarea class="ds-studio-json" data-studio-json spellcheck="false"></textarea>
<div class="ds-studio-actions"><button class="ds-btn ds-btn-line" type="button" data-studio-copy>Copy JSON</button><button class="ds-btn ds-btn-line" type="button" data-studio-import>Import JSON</button><button class="ds-btn ds-btn-line" type="button" data-studio-save>Save preset</button><button class="ds-btn ds-btn-line" type="button" data-studio-download>Download theme</button><button class="ds-btn ds-btn-line" type="button" data-studio-reset>Reset</button></div>
</div>
<script type="application/json" id="ds-themes">{"default":{},"berry":{"accent":"#c81e4a","accent-2":"#a8183d","accent-tint":"rgba(200,30,74,.08)"},"slate":{"accent":"#4f5b6b","accent-2":"#3a4452","accent-tint":"rgba(79,91,107,.1)"},"forest":{"accent":"#2f7d55","accent-2":"#246342","accent-tint":"rgba(47,125,85,.1)"},"ocean":{"accent":"#1f7a98","accent-2":"#185f76","accent-tint":"rgba(31,122,152,.1)"},"midnight":{"accent":"#5b6ef5","accent-2":"#4654d4","accent-tint":"rgba(91,110,245,.12)"},"amber":{"accent":"#c2790c","accent-2":"#a06409","accent-tint":"rgba(194,121,12,.12)"},"plum":{"accent":"#8a3ffc","accent-2":"#722fd1","accent-tint":"rgba(138,63,252,.1)"}}</script>
<script type="application/json" id="dossier-model">{"$schema":"https://raw.githubusercontent.com/kylebegeman/dossier/next/schema/dossier.schema.json","dossierVersion":"1.0","kind":"release","meta":{"title":"Release Readiness: 0.5.5","slug":"engineering-release","eyebrow":"Release example","crumbs":["Examples","Engineering release"],"status":"review","owner":"Release captain","updated":"2026-06-29","tags":["example","release","qa"],"theme":{"accent":"#15803d","accent-2":"#166534","accent-tint":"rgba(21,128,61,.1)"},"lifecycle":{"stage":"review","note":"A release gate and QA control room."}},"blocks":[{"type":"hero","eyebrow":"Release control room","title":"A release page that keeps gates, evidence, and claims together","lede":"Use this shape when a team needs public QA readiness, release notes, command receipts, and a durable closeout packet for agents.","pills":["Release gates","Verification","Manual QA","Closeout"],"sideCards":[{"label":"Release","value":"0.5.5"},{"label":"Required gates","value":"6"},{"label":"State","value":"Manual QA"}],"id":"a-release-page-that-keeps-gates-evidence-and-claims-together-0"},{"type":"release-checklist","title":"Release gates","gates":[{"id":"tests","title":"Automated tests pass","status":"passed","required":true,"evidence":"npm test"},{"id":"react","title":"React renderer typecheck passes","status":"passed","required":true,"evidence":"cd react && npx tsc --noEmit"},{"id":"docs","title":"README and examples regenerated","status":"passed","required":true,"evidence":"node bin/dossier.mjs build examples/*.dossier.json"},{"id":"live-editor","title":"Live CodeMirror editor smoke passes","status":"passed","required":true,"evidence":"Playwright smoke edited a CodeMirror-backed code-editor and saved back to source JSON"},{"id":"manual","title":"Manual browser pass complete","status":"todo","required":true,"evidence":"Run docs/product/public-manual-qa.md"},{"id":"npm","title":"npm publish credential available","status":"blocked","required":false,"evidence":"npm whoami if publishing to registry"}],"id":"release-gates-1"},{"type":"verification-run","title":"Command receipts","runs":[{"id":"unit-tests","title":"Unit tests","command":"npm test","status":"passed","expected":"All node tests pass.","actual":"Process, trust, export, and render tests passed."},{"id":"example-build","title":"Example build","command":"node bin/dossier.mjs build examples/*.dossier.json","status":"passed","expected":"Every example emits HTML and Markdown.","actual":"Generated showcase, overview, and focused example pages."},{"id":"codemirror-smoke","title":"Live editor smoke","command":"dossier serve examples/implementation-packet.dossier.json","status":"passed","expected":"CodeMirror mounts, edits sync, and save-back writes the source model.","actual":"Playwright verified desktop and mobile CodeMirror mounting, textarea sync, and save-back."}],"id":"command-receipts-2"},{"type":"table","title":"Release assets","columns":["Asset","Audience","Use"],"rows":[["README.md","New users","Install, choose examples, learn block and packet model."],["examples/showcase.html","Evaluators","Inspect the full block catalog."],["docs/product/public-manual-qa.md","Release reviewer","Run browser, live serve, MCP, and export checks."],["schema/packets/trust.schema.json","Agents","Validate trust packets and recorded claims."]],"id":"release-assets-3"},{"type":"trust-report","title":"Release confidence","sources":[{"id":"tests","label":"Automated tests","kind":"command","trust":"high","summary":"Narrow verification for render, schema, MCP, and packets."},{"id":"manual","label":"Manual QA guide","kind":"checklist","trust":"medium","summary":"Human browser pass still required before broad announcement."}],"claims":[{"id":"ready-for-manual-qa","claim":"Release is ready for public manual QA.","status":"verified","confidence":"high","sources":["tests","manual"],"evidence":["unit-tests","example-build"]},{"id":"registry-publish","claim":"Registry publishing requires npm credentials.","status":"external","confidence":"high","sources":["manual"]}],"id":"release-confidence-4"},{"type":"process-receipt","title":"Release receipt","outcome":"Ready for public manual QA","owner":"Release captain","date":"2026-06-29","commands":["npm test","node bin/dossier.mjs build examples/*.dossier.json","dossier serve CodeMirror smoke"],"risks":["Manual QA is not a substitute for production telemetry.","Registry publishing depends on credentials."],"followUps":["Run public manual QA guide.","Confirm Pages deployment after push."],"id":"release-receipt-5"}]}</script>
<script type="text/markdown" id="dossier-markdown">---
title: "Release Readiness: 0.5.5"
slug: "engineering-release"
status: "review"
updated: "2026-06-29"
---
# A release page that keeps gates, evidence, and claims together
Use this shape when a team needs public QA readiness, release notes, command receipts, and a durable closeout packet for agents.
## Release gates
- [x] Automated tests pass (required), npm test
- [x] React renderer typecheck passes (required), cd react && npx tsc --noEmit
- [x] README and examples regenerated (required), node bin/dossier.mjs build examples/*.dossier.json
- [x] Live CodeMirror editor smoke passes (required), Playwright smoke edited a CodeMirror-backed code-editor and saved back to source JSON
- [ ] Manual browser pass complete (required), Run docs/product/public-manual-qa.md
- [ ] npm publish credential available, npm whoami if publishing to registry
## Command receipts
### Unit tests (passed)
```sh
npm test
```
- **Expected:** All node tests pass.
- **Actual:** Process, trust, export, and render tests passed.
### Example build (passed)
```sh
node bin/dossier.mjs build examples/*.dossier.json
```
- **Expected:** Every example emits HTML and Markdown.
- **Actual:** Generated showcase, overview, and focused example pages.
### Live editor smoke (passed)
```sh
dossier serve examples/implementation-packet.dossier.json
```
- **Expected:** CodeMirror mounts, edits sync, and save-back writes the source model.
- **Actual:** Playwright verified desktop and mobile CodeMirror mounting, textarea sync, and save-back.
### Release assets
| Asset | Audience | Use |
| --- | --- | --- |
| README.md | New users | Install, choose examples, learn block and packet model. |
| examples/showcase.html | Evaluators | Inspect the full block catalog. |
| docs/product/public-manual-qa.md | Release reviewer | Run browser, live serve, MCP, and export checks. |
| schema/packets/trust.schema.json | Agents | Validate trust packets and recorded claims. |
## Release confidence
### Sources
- **tests:** Automated tests (high)
Narrow verification for render, schema, MCP, and packets.
- **manual:** Manual QA guide (medium)
Human browser pass still required before broad announcement.
### Claims
- **Release is ready for public manual QA.** (verified), confidence: high
- Sources: tests, manual
- Evidence: unit-tests, example-build
- **Registry publishing requires npm credentials.** (external), confidence: high
- Sources: manual
## Release receipt
- **outcome:** Ready for public manual QA
- **owner:** Release captain
- **date:** 2026-06-29
- **Commands:** npm test, node bin/dossier.mjs build examples/*.dossier.json, dossier serve CodeMirror smoke
- **Follow-ups:** Run public manual QA guide., Confirm Pages deployment after push.
</script>
<script type="text/plain" id="dossier-digest"># Release Readiness: 0.5.5 [review]
SUMMARY: Use this shape when a team needs public QA readiness, release notes, command receipts, and a durable closeout packet for agents.
- release-checklist: Release gates
- verification-run: Command receipts
- table: Release assets
- trust-report: Release confidence
- process-receipt: Release receipt</script>
<script>
(function(){
var $=function(s,r){return (r||document).querySelector(s)};
var $$=function(s,r){return Array.prototype.slice.call((r||document).querySelectorAll(s))};
var model={},mdSrc="",digestSrc="",slug="dossier";
try{model=JSON.parse($("#dossier-model").textContent);}catch(e){}
window.__DOSSIER_MODEL__=model;
mdSrc=(($("#dossier-markdown")||{}).textContent||"");
digestSrc=(($("#dossier-digest")||{}).textContent||"");
slug=(model.meta&&model.meta.slug)||"dossier";
var store="ds:"+slug;
var dirty=false;
function toast(msg){var t=$("[data-toast]");if(!t)return;t.textContent=msg;t.classList.add("show");setTimeout(function(){t.classList.remove("show")},1600);}
function copy(text,msg){if(navigator.clipboard){navigator.clipboard.writeText(text).then(function(){toast(msg||"Copied")});}else{var ta=document.createElement("textarea");ta.value=text;document.body.appendChild(ta);ta.select();try{document.execCommand("copy")}catch(e){}ta.remove();toast(msg||"Copied");}}
function download(name,text,type){var b=new Blob([text],{type:type||"text/plain"});var u=URL.createObjectURL(b);var a=document.createElement("a");a.href=u;a.download=name;a.click();URL.revokeObjectURL(u);}
function slugifyClient(s){return String(s||"").toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,64)||"item";}
function clone(o){return JSON.parse(JSON.stringify(o||{}));}
function nowIso(){try{return new Date().toISOString();}catch(e){return "";}}
function countMap(m){return Object.keys(m||{}).length;}
function markDirty(){dirty=true;document.documentElement.classList.add("ds-dirty");updateDirtyStatus();}
function updateDirtyStatus(){var el=$("[data-dirty-status]");if(!el)return;var edits=state.editors||{},diff=state.diffReview||{files:{},hunks:{}};var n=countMap(state.actions)+countMap(state.decisions)+countMap(state.process)+Object.keys(edits).filter(function(id){return edits[id]&&edits[id].dirty!==false}).length+countMap(state.verdicts)+countMap(state.release)+countMap(state.patchReview)+countMap(diff.files)+countMap(diff.hunks)+countMap(state.evidence);el.hidden=!dirty&&!n;el.textContent=n?("state "+n):"edited";}
function walkBlocks(blocks,fn){(blocks||[]).forEach(function(b){if(!b||typeof b!=="object")return;fn(b);if(b.blocks)walkBlocks(b.blocks,fn);if(b.left)walkBlocks(b.left,fn);if(b.right)walkBlocks(b.right,fn);if(b.tabs)b.tabs.forEach(function(t){walkBlocks(t.blocks,fn)});if(b.candidates)b.candidates.forEach(function(c){walkBlocks(c.blocks,fn)});if(b.items)b.items.forEach(function(it){walkBlocks(it.blocks,fn)});});}
function applyById(items,map,fn){(items||[]).forEach(function(it,i){var id=it.id||String(i),u=map[id];if(u)fn(it,u);});}
function statefulJson(m){return JSON.stringify(m,null,2);}
function sourceModelJson(){return statefulJson(model);}
function collectActions(){var out={};$$(".ds-action").forEach(function(li){var id=li.getAttribute("data-action"),cb=$("[data-action-check]",li);if(id&&cb)out[id]=!!cb.checked;});state.actions=out;return out;}
function collectDecisions(){var out={};$$("[data-select]").forEach(function(cb){var id=cb.getAttribute("data-select");var ta=byAttr("[data-notes]","data-notes",id);out[id]={selected:!!cb.checked,notes:ta?ta.value:""};});state.decisions=out;return out;}
function collectEditorsMap(){var edits={};$$("[data-code-editor]").forEach(function(ta){var id=ta.getAttribute("data-code-editor");edits[id]={text:ta.value,lang:ta.getAttribute("data-editor-lang")||"",filename:ta.getAttribute("data-editor-filename")||"",targetPath:ta.getAttribute("data-editor-target")||"",title:ta.getAttribute("data-editor-title")||"",dirty:ta.value!==ta.__original};});state.editors=edits;return edits;}
function collectEvidence(){state.evidence=state.evidence||{};return state.evidence;}
function collectStatePacket(persist){if(persist!==false&&typeof save==="function")save();var packets={actions:collectActions(),decisions:collectDecisions(),process:typeof collectProcess==="function"?collectProcess():(state.process||{}),edits:collectEditorsMap(),verdicts:typeof collectVerdicts==="function"?collectVerdicts():(state.verdicts||{}),release:typeof collectRelease==="function"?collectRelease():(state.release||{}),patchReview:typeof collectPatchReview==="function"?collectPatchReview():(state.patchReview||{}),diffReview:typeof collectDiffReview==="function"?collectDiffReview():(state.diffReview||{files:{},hunks:{}}),evidence:collectEvidence()};return {schema:"dossier.state/v1",slug:slug,updatedAt:nowIso(),packets:packets};}
function mergeCurrentState(){var next=clone(model),packet=collectStatePacket(),p=packet.packets;walkBlocks(next.blocks||[],function(b){if(b.type==="action-items"){(b.items||[]).forEach(function(it,i){var id=b.id+":"+i;if(p.actions[id]!==undefined)it.status=p.actions[id]?"done":"todo";});}if(b.type==="review-board")applyById(b.candidates,p.decisions,function(it,u){it.selected=!!u.selected;if(u.notes!=null)it.notes=u.notes;});if(b.type==="process-board")applyById(b.items,p.process,function(it,u){if(u.verdict!=null)it.verdict=u.verdict;if(u.notes!=null)it.notes=u.notes;});if(b.type==="code-editor"){var id=b.id||slugifyClient(b.title||b.filename||b.targetPath||"code-editor"),u=p.edits[id];if(!u)Object.keys(p.edits).some(function(k){var e=p.edits[k];if(e&&((e.targetPath&&e.targetPath===b.targetPath)||(e.filename&&e.filename===b.filename)||(e.title&&e.title===b.title))){u=e;return true;}return false;});if(u&&u.text!=null)b.code=String(u.text);}if(b.type==="verdict-gate"){var gid=b.gateId||b.id||slugifyClient(b.title||"verdict-gate"),vu=p.verdicts[gid];if(vu){if(vu.verdict!=null)b.verdict=vu.verdict;if(vu.notes!=null)b.notes=vu.notes;}}if(b.type==="release-checklist")applyById(b.gates,p.release,function(g,u){if(u.done!=null)g.status=u.done?"done":"todo";if(u.notes!=null)g.evidence=u.notes;});if(b.type==="patch-set")applyById(b.patches,p.patchReview,function(pa,u){if(u.verdict!=null){pa.review=u.verdict;if(u.verdict==="approve")pa.status=pa.status==="applied"?"applied":"accepted";else if(u.verdict==="revise")pa.status="needs-revision";else if(u.verdict==="skip")pa.status="skipped";}if(u.notes!=null)pa.notes=u.notes;});if(b.type==="diff-view"&&(Object.keys(p.diffReview.files||{}).length||Object.keys(p.diffReview.hunks||{}).length))b.review=p.diffReview;});var evidence=Object.keys(p.evidence||{}).map(function(id){var e=p.evidence[id]||{};e.id=id;return e;});if(evidence.length){var log=null;walkBlocks(next.blocks||[],function(b){if(!log&&b.type==="evidence-log")log=b;});if(!log){log={type:"evidence-log",id:"state-evidence",title:"Attached evidence",items:[]};next.blocks=next.blocks||[];next.blocks.push(log);}var seen={};(log.items||[]).forEach(function(e){seen[e.id]=true;});log.items=(log.items||[]).concat(evidence.filter(function(e){return !seen[e.id];}));}next.meta=next.meta||{};next.meta.stateExportedAt=packet.updatedAt;return next;}
function handoffPacket(){var packet=collectStatePacket(),p=packet.packets;var dirtyEdits=Object.keys(p.edits).filter(function(id){return p.edits[id]&&p.edits[id].dirty!==false;}).map(function(id){var e=p.edits[id];return {id:id,targetPath:e.targetPath||e.filename||"",title:e.title||"",dirty:e.dirty!==false};});var release=Object.keys(p.release).map(function(id){var g=p.release[id]||{};g.id=id;return g;});return {schema:"dossier.handoff/v1",slug:slug,title:(model.meta&&model.meta.title)||"Dossier",kind:model.kind||"dossier",generatedAt:packet.updatedAt,totals:{decisions:Object.keys(p.decisions).length,selectedDecisions:Object.keys(p.decisions).filter(function(id){return p.decisions[id]&&p.decisions[id].selected;}).length,processItems:Object.keys(p.process).length,dirtyEdits:dirtyEdits.length,releaseGates:release.length,unresolvedReleaseGates:release.filter(function(g){return g.required&&!g.done;}).length,patchReviews:Object.keys(p.patchReview).length,diffFileReviews:Object.keys(p.diffReview.files||{}).length,diffHunkReviews:Object.keys(p.diffReview.hunks||{}).length,evidence:Object.keys(p.evidence).length},decisions:p.decisions,process:p.process,edits:dirtyEdits,release:{gates:release,unresolved:release.filter(function(g){return g.required&&!g.done;})},patchReview:p.patchReview,diffReview:p.diffReview,evidence:p.evidence,nextAgentInstruction:"Use selected and approved items first. Treat notes as constraints. Apply dirty edits only when target paths are unambiguous. Resolve release and trust gaps before closeout."};}
function promptText(){var h=handoffPacket();return "Create or update a Dossier JSON model for \""+h.title+"\".\n\nRequirements:\n- Use dossierVersion \"1.0\" and stable kebab-case ids for every block and nested packet item.\n- Kind should be \""+h.kind+"\". Use process blocks when work must round-trip to an agent.\n- Include a hero first, then sectioned blocks with concise titles and source-backed claims.\n- For implementation or review work, include process-board, patch-set or diff-view, verification-run, trust-report, and process-receipt blocks when relevant.\n- Add targetPath on every code-editor that should be applied back to files.\n- Keep export semantics clear: source JSON is the authored model; state packets are human changes; merged JSON applies state back into the model.\n\nCurrent handoff summary: "+JSON.stringify(h.totals);}
function diffModelsClient(a,z){var aa=(a.blocks||[]),zz=(z.blocks||[]),am={},zm={},added=[],removed=[],changed=[];aa.forEach(function(b,i){am[b.id||("index-"+i)]=b;});zz.forEach(function(b,i){zm[b.id||("index-"+i)]=b;});Object.keys(zm).forEach(function(id){if(!am[id])added.push(id);else if(JSON.stringify(zm[id])!==JSON.stringify(am[id]))changed.push(id);});Object.keys(am).forEach(function(id){if(!zm[id])removed.push(id);});return {schema:"dossier.diff/v1",slug:slug,added:added,removed:removed,changed:changed,metaChanged:JSON.stringify(a.meta||{})!==JSON.stringify(z.meta||{})};}
function validatePacket(d,name){var expect={process:"dossier.process/v1",edits:"dossier.edits/v1",verdicts:"dossier.verdicts/v1",release:"dossier.release/v1",patch:"dossier.patch-review/v1",diff:"dossier.diff-review/v1",state:"dossier.state/v1"}[name];if(expect&&d&&d.schema&&d.schema!==expect)throw new Error("expected "+expect);return d;}
function downloadState(){download(slug+".state.json",statefulJson(collectStatePacket()),"application/json");}
function downloadMerged(){download(slug+".merged.dossier.json",statefulJson(mergeCurrentState()),"application/json");}
function downloadHandoff(){download(slug+".handoff.json",statefulJson(handoffPacket()),"application/json");}
function printCurrent(){toast(dirty?"Print uses current visible state":"Opening print preview");setTimeout(function(){window.print();},60);}
var savedTheme=localStorage.getItem("ds:theme");
if(savedTheme)document.documentElement.setAttribute("data-theme",savedTheme);
var tt=$("[data-theme-toggle]");
function themeGlyph(){return document.documentElement.getAttribute("data-theme")==="dark"?"☀":"☾";}
function toggleTheme(){var cur=document.documentElement.getAttribute("data-theme")==="dark"?"light":"dark";document.documentElement.setAttribute("data-theme",cur);localStorage.setItem("ds:theme",cur);if(tt)tt.textContent=themeGlyph();}
if(tt){tt.textContent=themeGlyph();tt.addEventListener("click",toggleTheme);}
var bar=$(".ds-progress-bar");
function prog(){if(!bar)return;var h=document.documentElement.scrollHeight-window.innerHeight;bar.style.width=(h>0?(window.scrollY/h*100):0)+"%";}
window.addEventListener("scroll",prog,{passive:true});prog();
var links={};$$(".ds-toc-link").forEach(function(l){links[l.getAttribute("data-toc")]=l;});
if(window.IntersectionObserver){
var io=new IntersectionObserver(function(ents){ents.forEach(function(en){if(en.isIntersecting){var id=en.target.id;if(links[id]){Object.keys(links).forEach(function(k){links[k].classList.toggle("active",k===id);});}}});},{rootMargin:"-8% 0px -82% 0px"});
Object.keys(links).forEach(function(id){var el=document.getElementById(id);if(el)io.observe(el);});
}
$$("[data-copy]").forEach(function(btn){btn.addEventListener("click",function(e){e.stopPropagation();var blk=btn.closest(".ds-block");var txt=blk?blk.innerText.replace(/^Copy\s*/,""):"";copy(txt,"Block copied");});});
$$("[data-toggle]").forEach(function(btn){btn.addEventListener("click",function(){var sec=btn.closest(".ds-section");var c=sec.getAttribute("data-collapsed")==="1";sec.setAttribute("data-collapsed",c?"0":"1");});});
$$(".ds-tabs").forEach(function(w){var tabs=$$(".ds-tab",w),panes=$$(".ds-pane",w);tabs.forEach(function(tb){tb.addEventListener("click",function(){var i=tb.getAttribute("data-tab");tabs.forEach(function(x){x.classList.toggle("active",x===tb)});panes.forEach(function(p){p.classList.toggle("active",p.getAttribute("data-pane")===i)});});});});
var search=$("[data-search]");
if(search){search.addEventListener("input",function(){var q=search.value.trim().toLowerCase();$$(".ds-content > .ds-block").forEach(function(blk){var hit=!q||blk.innerText.toLowerCase().indexOf(q)>=0;blk.style.display=hit?"":"none";});});}
var focusableSel='a[href],button:not([disabled]),input:not([disabled]):not([type="file"]),select:not([disabled]),textarea:not([disabled]),[role="button"],[tabindex]:not([tabindex="-1"])';
function focusableIn(root){return $$(focusableSel,root).filter(function(el){return !el.closest("[hidden]")&&el.tabIndex!==-1;});}
function showLayer(m,focusEl){if(!m)return;m.__lastFocus=document.activeElement;m.hidden=false;var f=focusEl||focusableIn(m)[0];if(f&&f.focus)f.focus();}
function hideLayer(m){if(!m||m.hidden)return;m.hidden=true;var f=m.__lastFocus;if(f&&document.contains(f)&&f.focus)f.focus();}
function topLayer(){var open=$$(".ds-palette:not([hidden]),.ds-modal:not([hidden]),.ds-tool-modal:not([hidden]),.ds-studio:not([hidden])");return open.length?open[open.length-1]:null;}
function closeTopLayer(){var m=topLayer();if(!m)return false;hideLayer(m);return true;}
function trapFocus(e){if(e.key!=="Tab")return;var m=topLayer();if(!m)return;var list=focusableIn(m);if(!list.length){e.preventDefault();return;}var first=list[0],last=list[list.length-1];if(e.shiftKey&&document.activeElement===first){last.focus();e.preventDefault();}else if(!e.shiftKey&&document.activeElement===last){first.focus();e.preventDefault();}}
document.addEventListener("keydown",trapFocus,true);
function viewSource(){var m=$("[data-source-modal]");if(!m)return;$("[data-source-text]").value=mdSrc;showLayer(m,$("[data-source-close]",m));}
function openShortcuts(){var m=$("[data-shortcuts-modal]");if(m)showLayer(m,$("[data-shortcuts-close]",m));}
$$("[data-action]").forEach(function(b){b.addEventListener("click",function(){var a=b.getAttribute("data-action");if(a==="open-export-center")openExportCenter();else if(a==="copy-md")copy(mdSrc,"Markdown copied");else if(a==="copy-digest")copy(digestSrc,"Agent digest copied");else if(a==="copy-prompt")copy(promptText(),"Prompt copied");else if(a==="download-md")download(slug+".md",mdSrc,"text/markdown");else if(a==="download-json")download(slug+".source.dossier.json",sourceModelJson(),"application/json");else if(a==="download-state-json")downloadState();else if(a==="download-merged-json")downloadMerged();else if(a==="download-handoff-json")downloadHandoff();else if(a==="print-pdf")printCurrent();else if(a==="view-source")viewSource();});});
var sc=$("[data-source-close]");if(sc)sc.addEventListener("click",function(){hideLayer($("[data-source-modal]"));});
var shc=$("[data-shortcuts-close]");if(shc)shc.addEventListener("click",function(){hideLayer($("[data-shortcuts-modal]"));});
var pal=$("[data-palette]"),palIn=$("[data-palette-input]"),palList=$("[data-palette-list]");
var cmds=[];
$$(".ds-toc-link").forEach(function(l){cmds.push({label:l.textContent,hint:"Section",act:function(){location.hash="#"+l.getAttribute("data-toc");}});});
cmds.push({label:"Toggle theme",hint:"Action",act:toggleTheme});
cmds.push({label:"Copy Markdown",hint:"Action",act:function(){copy(mdSrc,"Markdown copied");}});
cmds.push({label:"Open Export Center",hint:"Action",act:openExportCenter});
cmds.push({label:"Download source JSON",hint:"Action",act:function(){download(slug+".source.dossier.json",sourceModelJson(),"application/json");}});
cmds.push({label:"Download merged JSON",hint:"Action",act:downloadMerged});
cmds.push({label:"Download agent handoff",hint:"Action",act:downloadHandoff});
cmds.push({label:"View Markdown source",hint:"Action",act:viewSource});
cmds.push({label:"Keyboard shortcuts",hint:"Action",act:openShortcuts});
var palIdx=0,palFiltered=cmds;
function renderPal(){if(!palList)return;palList.innerHTML="";palFiltered.forEach(function(c,i){var d=document.createElement("div");d.className="ds-palette-item"+(i===palIdx?" active":"");var s1=document.createElement("span");s1.textContent=c.label;var s2=document.createElement("small");s2.textContent=c.hint;d.appendChild(s1);d.appendChild(s2);d.addEventListener("click",function(){closePal();c.act();});palList.appendChild(d);});}
function openPal(){if(!pal)return;palIn.value="";palFiltered=cmds;palIdx=0;renderPal();showLayer(pal,palIn);}
function closePal(){if(pal)hideLayer(pal);}
function filterPal(){var q=palIn.value.toLowerCase();palFiltered=cmds.filter(function(c){return c.label.toLowerCase().indexOf(q)>=0;});palIdx=0;renderPal();}
var po=$("[data-palette-open]");if(po)po.addEventListener("click",openPal);
if(palIn){palIn.addEventListener("input",filterPal);palIn.addEventListener("keydown",function(e){if(e.key==="ArrowDown"){palIdx=Math.min(palIdx+1,palFiltered.length-1);renderPal();e.preventDefault();}else if(e.key==="ArrowUp"){palIdx=Math.max(palIdx-1,0);renderPal();e.preventDefault();}else if(e.key==="Enter"){if(palFiltered[palIdx]){var c=palFiltered[palIdx];closePal();c.act();}}else if(e.key==="Escape"){closePal();}});}
document.addEventListener("keydown",function(e){if((e.metaKey||e.ctrlKey)&&e.key.toLowerCase()==="k"){e.preventDefault();openPal();}});
if(pal)pal.addEventListener("click",function(e){if(e.target===pal)closePal();});
var state={};try{state=JSON.parse(localStorage.getItem(store)||"{}");}catch(e){}
function save(){localStorage.setItem(store,JSON.stringify(state));}
function byAttr(sel,attr,val,root){var s=String(val);var nodes=$$(sel,root);for(var i=0;i<nodes.length;i++){if(nodes[i].getAttribute(attr)===s)return nodes[i];}return null;}
function packetMap(packet,primary,alternate){var src=(packet&&packet[primary])||(packet&&alternate&&packet[alternate])||packet||{};if(Array.isArray(src)){var out={};src.forEach(function(entry,i){if(entry&&typeof entry==="object")out[entry.id||String(i)]=entry;});return out;}return src&&typeof src==="object"?src:{};}
function normalizeStatePacket(d){d=validatePacket(d,"state");var p=(d&&d.packets)||d||{};var dr=p.diffReview||{};return {actions:packetMap(p.actions||p.actionItems||{},"actions","items"),decisions:packetMap(p.decisions||{},"decisions","items"),process:packetMap(p.process||{},"process","items"),edits:packetMap(p.edits||p.editors||{},"edits","items"),verdicts:packetMap(p.verdicts||{},"verdicts","items"),release:packetMap(p.release||{},"release","gates"),patchReview:packetMap(p.patchReview||p.patches||{},"patches","items"),diffReview:{files:packetMap(dr.files||p.files||{},"files"),hunks:packetMap(dr.hunks||p.hunks||{},"hunks")},evidence:packetMap(p.evidence||{},"evidence","items")};}
function applyStatePacket(d){var p=normalizeStatePacket(d),applied=0;state.actions=p.actions;Object.keys(p.actions).forEach(function(id){var li=byAttr(".ds-action","data-action",id),cb=li?$("[data-action-check]",li):null;if(cb){cb.checked=!!p.actions[id];li.classList.toggle("done",cb.checked);applied++;}});state.decisions=p.decisions;Object.keys(p.decisions).forEach(function(id){var entry=p.decisions[id]||{},cb=byAttr("[data-select]","data-select",id),ta=byAttr("[data-notes]","data-notes",id);if(cb){cb.checked=!!entry.selected;var row=cb.closest(".ds-ritem");if(row)row.classList.toggle("selected",cb.checked);applied++;}if(ta&&entry.notes!=null)ta.value=entry.notes;});state.process=p.process;Object.keys(p.process).forEach(function(id){var entry=p.process[id]||{},sel=byAttr("[data-process-verdict]","data-process-verdict",id),ta=byAttr("[data-process-notes]","data-process-notes",id);if(sel&&entry.verdict){sel.value=entry.verdict;processVerdictClass(sel.closest(".ds-pitem"),sel.value);applied++;}if(ta&&entry.notes!=null)ta.value=entry.notes;});state.editors=p.edits;Object.keys(p.edits).forEach(function(id){var entry=p.edits[id]||{},ta=byAttr("[data-code-editor]","data-code-editor",id);if(ta&&entry.text!=null){ta.value=entry.text;editorMark(id,ta.value!==ta.__original);sizeEditor(ta);applied++;}});state.verdicts=p.verdicts;Object.keys(p.verdicts).forEach(function(id){var entry=p.verdicts[id]||{},sel=byAttr("[data-verdict-gate]","data-verdict-gate",id),ta=byAttr("[data-verdict-notes]","data-verdict-notes",id);if(sel&&entry.verdict){sel.value=entry.verdict;applied++;}if(ta&&entry.notes!=null)ta.value=entry.notes;});state.release=p.release;Object.keys(p.release).forEach(function(id){var entry=p.release[id]||{},cb=byAttr("[data-release-gate]","data-release-gate",id),ta=byAttr("[data-release-notes]","data-release-notes",id);if(cb&&entry.done!=null){cb.checked=!!entry.done;applied++;}if(ta&&entry.notes!=null)ta.value=entry.notes;});state.patchReview=p.patchReview;Object.keys(p.patchReview).forEach(function(id){var entry=p.patchReview[id]||{},sel=byAttr("[data-patch-verdict]","data-patch-verdict",id),ta=byAttr("[data-patch-notes]","data-patch-notes",id);if(sel&&entry.verdict){sel.value=entry.verdict;applied++;}if(ta&&entry.notes!=null)ta.value=entry.notes;});state.diffReview=p.diffReview;Object.keys(p.diffReview.files||{}).forEach(function(id){var entry=p.diffReview.files[id]||{},sel=byAttr("[data-diff-file-verdict]","data-diff-file-verdict",id),ta=byAttr("[data-diff-file-comment]","data-diff-file-comment",id);if(sel&&entry.verdict){sel.value=entry.verdict;applied++;}if(ta&&entry.comment!=null)ta.value=entry.comment;});Object.keys(p.diffReview.hunks||{}).forEach(function(id){var entry=p.diffReview.hunks[id]||{},sel=byAttr("[data-diff-hunk-verdict]","data-diff-hunk-verdict",id),ta=byAttr("[data-diff-hunk-comment]","data-diff-hunk-comment",id);if(sel&&entry.verdict){sel.value=entry.verdict;applied++;}if(ta&&entry.comment!=null)ta.value=entry.comment;});state.evidence=p.evidence;save();markDirty();if(typeof reviewCount==="function")reviewCount();if(typeof reviewFilter==="function")reviewFilter();if(typeof processCount==="function")processCount();if(typeof processFilter==="function")processFilter();setPreview("Imported state packet",statefulJson({schema:"dossier.state/v1",slug:slug,updatedAt:(d&&d.updatedAt)||nowIso(),packets:p}));toast("Imported state packet"+(applied?": "+applied+" controls":""));}
function setPreview(title,text){var head=$("[data-export-preview-title]"),ta=$("[data-export-preview]");if(head)head.textContent=title;if(ta)ta.value=text;}
function openExportCenter(){var m=$("[data-export-modal]");if(!m)return;var packet=collectStatePacket();setPreview("Current state packet",statefulJson(packet));var summary=$("[data-export-summary]");if(summary){var p=packet.packets;summary.textContent="State: "+Object.keys(p.decisions).length+" decisions, "+Object.keys(p.process).length+" process items, "+Object.keys(p.edits).length+" edits, "+Object.keys(p.evidence).length+" evidence records.";}showLayer(m,$("[data-export-kind]",m));}
function closeToolModal(sel){hideLayer($(sel));}
function emptyBlock(type,title){var b={type:type,title:title||type};if(type==="prose"){delete b.title;b.markdown=title||"New prose block.";}else if(type==="section"){b.blocks=[];}else if(type==="callout"){b.body=title||"New callout.";}else if(type==="table"){b.columns=["Column"];b.rows=[["Value"]];}else if(type==="code-editor"){b.code="";b.lang="text";}else if(type==="process-board"){b.items=[{id:"new-work-item",title:title||"New work item"}];}else if(type==="patch-set"){b.patches=[{id:"new-patch",title:title||"New patch"}];}else if(type==="verification-run"){b.runs=[{id:"new-run",title:title||"New run"}];}else if(type==="release-checklist"){b.gates=[{id:"new-gate",title:title||"New gate",required:true,status:"todo"}];}return b;}
function renderStaticBlockEditor(){var list=$("[data-block-editor-list]");if(!list)return;list.innerHTML="";(model.blocks||[]).forEach(function(b,i){var row=document.createElement("div");row.className="ds-blockedit-row";var label=document.createElement("b");label.textContent=(b.title||b.heading||b.type||"block")+" · "+(b.id||("index "+i));var up=document.createElement("button"),down=document.createElement("button"),del=document.createElement("button");[up,down,del].forEach(function(btn){btn.className="ds-btn ds-btn-line";btn.type="button";});up.textContent="Up";down.textContent="Down";del.textContent="Delete";up.disabled=i===0;down.disabled=i===(model.blocks||[]).length-1;row.appendChild(label);row.appendChild(up);row.appendChild(down);row.appendChild(del);up.addEventListener("click",function(){var x=model.blocks[i-1];model.blocks[i-1]=model.blocks[i];model.blocks[i]=x;markDirty();renderStaticBlockEditor();});down.addEventListener("click",function(){var x=model.blocks[i+1];model.blocks[i+1]=model.blocks[i];model.blocks[i]=x;markDirty();renderStaticBlockEditor();});del.addEventListener("click",function(){model.blocks.splice(i,1);markDirty();renderStaticBlockEditor();});list.appendChild(row);});var note=$("[data-block-editor-status]");if(note)note.textContent="Download merged JSON to persist structural changes, then rebuild.";window.__DOSSIER_MODEL__=model;}
function openBlockEditor(){var m=$("[data-block-editor-modal]");if(!m)return;renderStaticBlockEditor();showLayer(m,$("[data-tool-close]",m));}
function openEvidencePanel(){var m=$("[data-evidence-modal]");if(!m)return;showLayer(m,$("[data-evidence-title]",m));}
function addEvidenceFromForm(){state.evidence=state.evidence||{};var title=($("[data-evidence-title]")||{}).value||"Evidence";var id=slugifyClient(($("[data-evidence-id]")||{}).value||title);state.evidence[id]={title:title,kind:($("[data-evidence-kind]")||{}).value||"note",source:($("[data-evidence-source]")||{}).value||"",trust:($("[data-evidence-trust]")||{}).value||"medium",body:($("[data-evidence-body]")||{}).value||"",created:nowIso()};save();markDirty();toast("Evidence attached");closeToolModal("[data-evidence-modal]");}
function compareRevisionFile(file){var r=new FileReader();r.onload=function(){try{var other=JSON.parse(r.result),diff=diffModelsClient(other,mergeCurrentState());var out=$("[data-revision-result]");if(out)out.value=statefulJson(diff);setPreview("Revision diff",statefulJson(diff));toast("Revision compared");}catch(e){toast("Compare failed");}};r.readAsText(file);}
function importStateFile(file){var r=new FileReader();r.onload=function(){try{applyStatePacket(JSON.parse(r.result));}catch(e){toast("State import failed");}};r.readAsText(file);}
$$("[data-export-kind]").forEach(function(btn){btn.addEventListener("click",function(){var k=btn.getAttribute("data-export-kind");if(k==="source")setPreview("Source JSON",sourceModelJson());else if(k==="state")setPreview("Current state packet",statefulJson(collectStatePacket()));else if(k==="merged")setPreview("Merged Dossier JSON",statefulJson(mergeCurrentState()));else if(k==="handoff")setPreview("Agent handoff packet",statefulJson(handoffPacket()));else if(k==="prompt")setPreview("AI authoring prompt",promptText());});});
$$("[data-export-download]").forEach(function(btn){btn.addEventListener("click",function(){var k=btn.getAttribute("data-export-download");if(k==="source")download(slug+".source.dossier.json",sourceModelJson(),"application/json");else if(k==="state")downloadState();else if(k==="merged")downloadMerged();else if(k==="handoff")downloadHandoff();else if(k==="prompt")download(slug+".prompt.txt",promptText(),"text/plain");});});
var expCopy=$("[data-export-copy]");if(expCopy)expCopy.addEventListener("click",function(){var ta=$("[data-export-preview]");copy(ta?ta.value:"","Export copied");});
$$("[data-tool-close]").forEach(function(btn){btn.addEventListener("click",function(){hideLayer(btn.closest(".ds-tool-modal,.ds-modal"));});});
$$(".ds-modal,.ds-tool-modal").forEach(function(m){m.addEventListener("click",function(e){if(e.target===m)hideLayer(m);});});
$$(".ds-file-btn").forEach(function(btn){btn.addEventListener("keydown",function(e){if(e.key==="Enter"||e.key===" "){e.preventDefault();var inp=$('input[type="file"]',btn);if(inp)inp.click();}});});
var blockOpen=$("[data-block-editor-open]");if(blockOpen)blockOpen.addEventListener("click",openBlockEditor);
var blockAdd=$("[data-block-editor-add]");if(blockAdd)blockAdd.addEventListener("click",function(){model.blocks=Array.isArray(model.blocks)?model.blocks:[];model.blocks.push(emptyBlock(($("[data-block-editor-type]")||{}).value||"prose",($("[data-block-editor-title]")||{}).value||""));markDirty();renderStaticBlockEditor();});
var evidenceOpen=$("[data-evidence-open]");if(evidenceOpen)evidenceOpen.addEventListener("click",openEvidencePanel);
var evidenceAdd=$("[data-evidence-add]");if(evidenceAdd)evidenceAdd.addEventListener("click",addEvidenceFromForm);
var rev=$("[data-revision-file]");if(rev)rev.addEventListener("change",function(){if(rev.files&&rev.files[0])compareRevisionFile(rev.files[0]);});
var sf=$("[data-state-file]");if(sf)sf.addEventListener("change",function(){if(sf.files&&sf.files[0])importStateFile(sf.files[0]);});
document.addEventListener("input",function(e){if(e.target&&e.target.matches("[data-notes],[data-process-notes],[data-code-editor],[data-verdict-notes],[data-release-notes],[data-patch-notes],[data-diff-file-comment],[data-diff-hunk-comment],[data-edit]"))markDirty();},true);
document.addEventListener("change",function(e){if(e.target&&e.target.matches("[data-action-check],[data-select],[data-process-verdict],[data-verdict-gate],[data-release-gate],[data-patch-verdict],[data-diff-file-verdict],[data-diff-hunk-verdict]"))markDirty();},true);
state.actions=state.actions||{};
$$(".ds-action").forEach(function(li){var key=li.getAttribute("data-action");var cb=$("[data-action-check]",li);if(!cb)return;if(state.actions[key])cb.checked=true;function sync(){li.classList.toggle("done",cb.checked);state.actions[key]=cb.checked;save();}cb.addEventListener("change",sync);li.classList.toggle("done",cb.checked);});
function reviewCount(){$$("[data-review-count]").forEach(function(c){var root=c.closest('[data-block="review-board"]')||document;var n=$$("[data-select]:checked",root).length;c.textContent=n+" selected";});}
state.decisions=state.decisions||{};
$$("[data-select]").forEach(function(cb){var id=cb.getAttribute("data-select");if(state.decisions[id]&&state.decisions[id].selected){cb.checked=true;cb.closest(".ds-ritem").classList.add("selected");}cb.addEventListener("change",function(){cb.closest(".ds-ritem").classList.toggle("selected",cb.checked);state.decisions[id]=state.decisions[id]||{};state.decisions[id].selected=cb.checked;save();reviewCount();});});
$$("[data-notes]").forEach(function(ta){var id=ta.getAttribute("data-notes");if(state.decisions[id]&&state.decisions[id].notes)ta.value=state.decisions[id].notes;ta.addEventListener("input",function(){state.decisions[id]=state.decisions[id]||{};state.decisions[id].notes=ta.value;save();});});
reviewCount();
var ed=$("[data-export-decisions]");if(ed)ed.addEventListener("click",function(){download(slug+".decisions.json",JSON.stringify({slug:slug,decisions:state.decisions},null,2),"application/json");});
var im=$("[data-import-decisions]");if(im)im.addEventListener("click",function(){var inp=document.createElement("input");inp.type="file";inp.accept="application/json";inp.onchange=function(){var f=inp.files[0];if(!f)return;var r=new FileReader();r.onload=function(){try{var d=JSON.parse(r.result);var dec=packetMap(d,"decisions");Object.keys(dec).forEach(function(id){state.decisions[id]=dec[id];var cb=byAttr("[data-select]","data-select",id);if(cb){cb.checked=!!dec[id].selected;cb.closest(".ds-ritem").classList.toggle("selected",cb.checked);}var ta=byAttr("[data-notes]","data-notes",id);if(ta&&dec[id].notes!=null)ta.value=dec[id].notes;});save();markDirty();reviewCount();toast("Imported decisions");}catch(e){toast("Import failed");}};r.readAsText(f);};inp.click();});
// expandable triage rows: header toggles open, checkbox does not
$$(".ds-ritem").forEach(function(item){var head=item.querySelector("[data-rtoggle]");if(head)head.addEventListener("click",function(e){if(e.target.closest("[data-stop]"))return;item.classList.toggle("open");});var stop=item.querySelector("[data-stop]");if(stop)stop.addEventListener("click",function(e){e.stopPropagation();});});
function reviewFilter(){$$('[data-block="review-board"]').forEach(function(root){var rsearch=$("[data-review-search]",root),ronly=$("[data-review-only]",root);var q=((rsearch&&rsearch.value)||"").trim().toLowerCase();var only=ronly&&ronly.checked;$$(".ds-ritem",root).forEach(function(i){var txt=i.getAttribute("data-text")||"";var cb=i.querySelector("[data-select]");var sel=cb&&cb.checked;i.style.display=((!q||txt.indexOf(q)>=0)&&(!only||sel))?"":"none";});});}
$$('[data-block="review-board"]').forEach(function(root){var rsearch=$("[data-review-search]",root),ronly=$("[data-review-only]",root),rexpand=$("[data-review-expand]",root);if(rsearch)rsearch.addEventListener("input",reviewFilter);if(ronly)ronly.addEventListener("change",reviewFilter);if(rexpand)rexpand.addEventListener("click",function(){var items=$$(".ds-ritem",root);var anyClosed=items.some(function(i){return !i.classList.contains("open");});items.forEach(function(i){i.classList.toggle("open",anyClosed);});rexpand.textContent=anyClosed?"Collapse all":"Expand all";});});
$$("[data-select]").forEach(function(cb){cb.addEventListener("change",reviewFilter);});
function processVerdictClass(item,verdict){if(!item)return;["undecided","approve","revise","skip","defer","split","retry","block"].forEach(function(v){item.classList.remove("verdict-"+v);});item.classList.add("verdict-"+(verdict||"undecided"));}
function processCount(){$$("[data-process-count]").forEach(function(c){var root=c.closest('[data-block="process-board"]')||document;var n=$$("[data-process-verdict]",root).filter(function(s){return s.value&&s.value!=="undecided";}).length;c.textContent=n+" verdict"+(n===1?"":"s");});}
state.process=state.process||{};
$$("[data-process-verdict]").forEach(function(sel){var id=sel.getAttribute("data-process-verdict");if(state.process[id]&&state.process[id].verdict)sel.value=state.process[id].verdict;function sync(){state.process[id]=state.process[id]||{};state.process[id].verdict=sel.value;processVerdictClass(sel.closest(".ds-pitem"),sel.value);save();processCount();processFilter();}sel.addEventListener("change",sync);processVerdictClass(sel.closest(".ds-pitem"),sel.value);});
$$("[data-process-notes]").forEach(function(ta){var id=ta.getAttribute("data-process-notes");if(state.process[id]&&state.process[id].notes)ta.value=state.process[id].notes;ta.addEventListener("input",function(){state.process[id]=state.process[id]||{};state.process[id].notes=ta.value;save();});});
processCount();
function collectProcess(){var out={};$$("[data-process-verdict]").forEach(function(sel){var id=sel.getAttribute("data-process-verdict");var ta=byAttr("[data-process-notes]","data-process-notes",id);var item=sel.closest(".ds-pitem");var title=item&&item.querySelector("h4")?item.querySelector("h4").textContent:"";out[id]={verdict:sel.value||"undecided",notes:ta?ta.value:"",title:title};});state.process=out;save();return out;}
var ep=$("[data-export-process]");if(ep)ep.addEventListener("click",function(){download(slug+".process.json",JSON.stringify({schema:"dossier.process/v1",slug:slug,process:collectProcess()},null,2),"application/json");});
var ip=$("[data-import-process]");if(ip)ip.addEventListener("click",function(){var inp=document.createElement("input");inp.type="file";inp.accept="application/json";inp.onchange=function(){var f=inp.files[0];if(!f)return;var r=new FileReader();r.onload=function(){try{var d=validatePacket(JSON.parse(r.result),"process");var proc=packetMap(d,"process","items");Object.keys(proc).forEach(function(id){state.process[id]=proc[id];var sel=byAttr("[data-process-verdict]","data-process-verdict",id);if(sel&&proc[id].verdict){sel.value=proc[id].verdict;processVerdictClass(sel.closest(".ds-pitem"),sel.value);}var ta=byAttr("[data-process-notes]","data-process-notes",id);if(ta&&proc[id].notes!=null)ta.value=proc[id].notes;});save();markDirty();processCount();processFilter();toast("Imported process state");}catch(e){toast("Import failed");}};r.readAsText(f);};inp.click();});
$$(".ds-pitem").forEach(function(item){var head=item.querySelector("[data-ptoggle]");if(head)head.addEventListener("click",function(e){if(e.target.closest("[data-stop]"))return;item.classList.toggle("open");});var stop=item.querySelector("[data-stop]");if(stop)stop.addEventListener("click",function(e){e.stopPropagation();});});
function processFilter(){$$('[data-block="process-board"]').forEach(function(root){var psearch=$("[data-process-search]",root),ponly=$("[data-process-only]",root);var q=((psearch&&psearch.value)||"").trim().toLowerCase();var only=ponly&&ponly.checked;$$(".ds-pitem",root).forEach(function(i){var txt=i.getAttribute("data-text")||"";var sel=i.querySelector("[data-process-verdict]");var has=sel&&sel.value&&sel.value!=="undecided";i.style.display=((!q||txt.indexOf(q)>=0)&&(!only||has))?"":"none";});});}
$$('[data-block="process-board"]').forEach(function(root){var psearch=$("[data-process-search]",root),ponly=$("[data-process-only]",root),pexpand=$("[data-process-expand]",root);if(psearch)psearch.addEventListener("input",processFilter);if(ponly)ponly.addEventListener("change",processFilter);if(pexpand)pexpand.addEventListener("click",function(){var items=$$(".ds-pitem",root);var anyClosed=items.some(function(i){return !i.classList.contains("open");});items.forEach(function(i){i.classList.toggle("open",anyClosed);});pexpand.textContent=anyClosed?"Collapse all":"Expand all";});});
function editorMark(id,dirty){var shell=byAttr("[data-editor-shell]","data-editor-shell",id),label=byAttr("[data-editor-state]","data-editor-state",id);if(shell)shell.classList.toggle("dirty",!!dirty);if(label)label.textContent=dirty?"dirty":"clean";}
function sizeEditor(ta){ta.style.height="auto";ta.style.height=Math.max(220,ta.scrollHeight+2)+"px";}
state.editors=state.editors||{};
$$("[data-code-editor]").forEach(function(ta){var id=ta.getAttribute("data-code-editor");var saved=state.editors[id];ta.__original=ta.value;if(saved&&saved.text!=null)ta.value=saved.text;sizeEditor(ta);function sync(){var dirty=ta.value!==ta.__original;state.editors[id]={text:ta.value,lang:ta.getAttribute("data-editor-lang")||"",filename:ta.getAttribute("data-editor-filename")||"",targetPath:ta.getAttribute("data-editor-target")||"",title:ta.getAttribute("data-editor-title")||"",dirty:dirty};editorMark(id,dirty);sizeEditor(ta);save();}ta.addEventListener("input",sync);editorMark(id,ta.value!==ta.__original);var reset=byAttr("[data-editor-reset]","data-editor-reset",id);if(reset)reset.addEventListener("click",function(){ta.value=ta.__original;sync();});if(typeof window.DossierEditorEnhancer==="function"){try{window.DossierEditorEnhancer({id:id,textarea:ta,language:ta.getAttribute("data-editor-lang")||"",filename:ta.getAttribute("data-editor-filename")||"",targetPath:ta.getAttribute("data-editor-target")||"",title:ta.getAttribute("data-editor-title")||""});}catch(e){}}});
function exportEditors(){var edits={};$$("[data-code-editor]").forEach(function(ta){var id=ta.getAttribute("data-code-editor");edits[id]={text:ta.value,lang:ta.getAttribute("data-editor-lang")||"",filename:ta.getAttribute("data-editor-filename")||"",targetPath:ta.getAttribute("data-editor-target")||"",title:ta.getAttribute("data-editor-title")||"",dirty:ta.value!==ta.__original};});download(slug+".edits.json",JSON.stringify({schema:"dossier.edits/v1",slug:slug,edits:edits},null,2),"application/json");}
function importEditors(){var inp=document.createElement("input");inp.type="file";inp.accept="application/json";inp.onchange=function(){var f=inp.files[0];if(!f)return;var r=new FileReader();r.onload=function(){try{var d=validatePacket(JSON.parse(r.result),"edits");var edits=packetMap(d,"edits","items");Object.keys(edits).forEach(function(id){var entry=edits[id];if(!entry||entry.text==null)return;state.editors[id]=entry;var ta=byAttr("[data-code-editor]","data-code-editor",id);if(ta){ta.value=entry.text;editorMark(id,ta.value!==ta.__original);sizeEditor(ta);}});save();markDirty();toast("Imported editor edits");}catch(e){toast("Import failed");}};r.readAsText(f);};inp.click();}
$$("[data-export-editors]").forEach(function(b){b.addEventListener("click",exportEditors);});
$$("[data-import-editors]").forEach(function(b){b.addEventListener("click",importEditors);});
$$("main textarea:not(.ds-codeedit-area)").forEach(function(ta){function fit(){ta.style.height="auto";ta.style.height=Math.max(80,ta.scrollHeight+2)+"px";}fit();ta.addEventListener("input",fit);});
state.verdicts=state.verdicts||{};
$$("[data-verdict-gate]").forEach(function(sel){var id=sel.getAttribute("data-verdict-gate");if(state.verdicts[id]&&state.verdicts[id].verdict)sel.value=state.verdicts[id].verdict;function sync(){state.verdicts[id]=state.verdicts[id]||{};state.verdicts[id].verdict=sel.value;save();}sel.addEventListener("change",sync);});
$$("[data-verdict-notes]").forEach(function(ta){var id=ta.getAttribute("data-verdict-notes");if(state.verdicts[id]&&state.verdicts[id].notes)ta.value=state.verdicts[id].notes;ta.addEventListener("input",function(){state.verdicts[id]=state.verdicts[id]||{};state.verdicts[id].notes=ta.value;save();});});
function collectVerdicts(){var out={};$$("[data-verdict-gate]").forEach(function(sel){var id=sel.getAttribute("data-verdict-gate");var ta=byAttr("[data-verdict-notes]","data-verdict-notes",id);out[id]={verdict:sel.value||"undecided",notes:ta?ta.value:"",title:sel.getAttribute("data-verdict-title")||""};});state.verdicts=out;save();return out;}
function exportVerdicts(){download(slug+".verdicts.json",JSON.stringify({schema:"dossier.verdicts/v1",slug:slug,verdicts:collectVerdicts()},null,2),"application/json");}
function importVerdicts(){var inp=document.createElement("input");inp.type="file";inp.accept="application/json";inp.onchange=function(){var f=inp.files[0];if(!f)return;var r=new FileReader();r.onload=function(){try{var d=validatePacket(JSON.parse(r.result),"verdicts");var verdicts=packetMap(d,"verdicts","items");Object.keys(verdicts).forEach(function(id){state.verdicts[id]=verdicts[id];var sel=byAttr("[data-verdict-gate]","data-verdict-gate",id);if(sel&&verdicts[id].verdict)sel.value=verdicts[id].verdict;var ta=byAttr("[data-verdict-notes]","data-verdict-notes",id);if(ta&&verdicts[id].notes!=null)ta.value=verdicts[id].notes;});save();markDirty();toast("Imported verdicts");}catch(e){toast("Import failed");}};r.readAsText(f);};inp.click();}
$$("[data-export-verdicts]").forEach(function(b){b.addEventListener("click",exportVerdicts);});
$$("[data-import-verdicts]").forEach(function(b){b.addEventListener("click",importVerdicts);});
state.release=state.release||{};