@mcptoolshop/sovereign 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/CHANGELOG.md +126 -0
  2. package/LICENSE +21 -0
  3. package/README.es.md +158 -0
  4. package/README.fr.md +158 -0
  5. package/README.hi.md +158 -0
  6. package/README.it.md +158 -0
  7. package/README.ja.md +158 -0
  8. package/README.md +158 -0
  9. package/README.pt-BR.md +158 -0
  10. package/README.zh.md +158 -0
  11. package/SECURITY.md +61 -0
  12. package/bin/sovereign.js +167 -0
  13. package/package.json +56 -0
  14. package/release/00-START-HERE.html +333 -0
  15. package/release/CHANGELOG.md +126 -0
  16. package/release/README.txt +144 -0
  17. package/release/balance-evidence/README.txt +81 -0
  18. package/release/balance-evidence/raw-data/sovereign-batch-v0.10-canonical-400.json +72134 -0
  19. package/release/balance-evidence/raw-data/sovereign-batch-v0.10-canonical-slot-swap.json +18137 -0
  20. package/release/balance-evidence/raw-data/sovereign-batch-v0.10-canonical.json +18137 -0
  21. package/release/balance-evidence/raw-data/sovereign-batch-v0.10-mc-mirror.json +18089 -0
  22. package/release/balance-evidence/raw-data/sovereign-batch-v0.10-mfg-mirror.json +18089 -0
  23. package/release/balance-evidence/raw-data/sovereign-batch-v0.10-tf-mirror.json +18089 -0
  24. package/release/balance-evidence/sovereign-batch-v0.10-canonical-400.html +1 -0
  25. package/release/balance-evidence/sovereign-batch-v0.10-canonical-slot-swap.html +1 -0
  26. package/release/balance-evidence/sovereign-batch-v0.10-canonical.html +1 -0
  27. package/release/balance-evidence/sovereign-batch-v0.10-mc-mirror.html +1 -0
  28. package/release/balance-evidence/sovereign-batch-v0.10-mfg-mirror.html +1 -0
  29. package/release/balance-evidence/sovereign-batch-v0.10-summary.html +2 -0
  30. package/release/balance-evidence/sovereign-batch-v0.10-tf-mirror.html +1 -0
  31. package/release/board-game/README.txt +48 -0
  32. package/release/board-game/sovereign-economy-audit.html +501 -0
  33. package/release/board-game/sovereign-print-audit.html +479 -0
  34. package/release/board-game/sovereign-prototype.html +1939 -0
  35. package/release/design-history/01-phase1-concept.html +632 -0
  36. package/release/design-history/02-phase2-prototype.html +1026 -0
  37. package/release/design-history/03-phase3-audit.html +268 -0
  38. package/release/design-history/04-phase4-audit.html +274 -0
  39. package/release/design-history/05-phase5-audit.html +305 -0
  40. package/release/design-history/README.txt +66 -0
  41. package/release/digital-mode/README.txt +89 -0
  42. package/release/digital-mode/sovereign-solo.html +3884 -0
  43. package/release/digital-mode/sovereign-v0.10-freeze-audit.html +67 -0
@@ -0,0 +1,1939 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <title>Sovereign · The Hamilton System Board Game · v0.2</title>
6
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
7
+ <style>
8
+ /* =====================================================================
9
+ SOVEREIGN — THE HAMILTON SYSTEM BOARD GAME
10
+ Founding Credit: Fund the debt. Build the bank. Industrialize the republic.
11
+ Self-contained · US Letter · digital-review-friendly · prototype pack.
12
+ ===================================================================== */
13
+ :root {
14
+ --revolutionary-debt: #6E1F1E;
15
+ --state-debt: #4A6B8A;
16
+ --revenue-system: #C28A28;
17
+ --commercial-infrastructure: #2E7A6B;
18
+ --national-finance: #1F2D52;
19
+ --internal-improvements: #B85A28;
20
+ --manufactures: #8C8A2E;
21
+ --strategic-industry: #3A3A3A;
22
+ --parchment: #F0E6CD;
23
+ --ink: #1A1612;
24
+ --highlight: #C8392E;
25
+ --parchment-2: #E6DABC;
26
+ --rule: rgba(26,22,18,0.55);
27
+ --rule-soft: rgba(26,22,18,0.22);
28
+ --display: "Baskerville","Big Caslon","Hoefler Text","Garamond","Times New Roman",serif;
29
+ --body: "Iowan Old Style","Georgia","Cambria","Times New Roman",serif;
30
+ --ui: -apple-system,"Segoe UI","Helvetica Neue","Arial",system-ui,sans-serif;
31
+ --mono: "SF Mono","Menlo","Consolas","Courier New",monospace;
32
+ --board-size: 17in;
33
+ --corner-size: 1.5in;
34
+ --space-depth: 1.5in;
35
+ --space-len: calc((var(--board-size) - 2 * var(--corner-size)) / 9);
36
+ }
37
+
38
+ @page { size: 8.5in 11in; margin: 0.25in; }
39
+ @page tile { size: 8.5in 11in; margin: 0; }
40
+ * { box-sizing: border-box; }
41
+ html, body {
42
+ margin: 0; padding: 0; font-family: var(--body); color: var(--ink);
43
+ background: #2A2622;
44
+ -webkit-print-color-adjust: exact; print-color-adjust: exact;
45
+ }
46
+ .viewport { display: flex; flex-direction: column; align-items: center; gap: 28px; padding: 32px 16px 96px; }
47
+ .page {
48
+ width: 8.5in; min-height: 11in; background: var(--parchment); color: var(--ink); position: relative;
49
+ box-shadow: 0 10px 40px rgba(0,0,0,.55), 0 2px 4px rgba(0,0,0,.4);
50
+ padding: 0.25in;
51
+ }
52
+ .page-tile { padding: 0; page: tile; }
53
+
54
+ /* Card-grid sheets (9-up at 2.5 × 3.5 in) pack tightly — pull padding and
55
+ header margin in just enough that the 3-row grid sits inside the page. */
56
+ .page:has(.grid) { padding: 0.12in 0.25in; }
57
+ .page:has(.grid) .sheet-head { margin-bottom: 0.04in; }
58
+ @media print {
59
+ html, body { background: #fff !important; margin: 0 !important; }
60
+ .viewport { padding: 0 !important; gap: 0 !important; }
61
+ .page {
62
+ box-shadow: none !important;
63
+ page-break-after: always;
64
+ break-after: page;
65
+ page-break-inside: avoid;
66
+ break-inside: avoid;
67
+ margin: 0 auto !important;
68
+ width: 8.5in !important;
69
+ }
70
+ .page:last-child { page-break-after: auto; break-after: auto; }
71
+ .toolbar, .digital-nav { display: none !important; }
72
+ /* Belt-and-braces: hide all <a> tag chrome on links inside the digital nav (already removed via display:none above) */
73
+ a { color: inherit; text-decoration: none; }
74
+ }
75
+ .toolbar { position: fixed; top: 16px; right: 16px; z-index: 30; }
76
+ .toolbar button {
77
+ background: var(--parchment); color: var(--ink);
78
+ border: 1px solid var(--ink); padding: 8px 14px;
79
+ font-family: var(--ui); font-size: 12px;
80
+ letter-spacing: .08em; text-transform: uppercase; cursor: pointer;
81
+ }
82
+ .toolbar button:hover { background: var(--parchment-2); }
83
+
84
+ .sheet-head {
85
+ display: flex; justify-content: space-between; align-items: baseline;
86
+ padding-bottom: 6px; border-bottom: 1px solid var(--ink);
87
+ font-family: var(--ui); font-size: 9.5px; letter-spacing: .22em; text-transform: uppercase;
88
+ margin-bottom: 0.18in;
89
+ }
90
+ .sheet-head .brand-mark { font-family: var(--ui); font-weight: 700; letter-spacing: .32em; font-size: 9.5px; }
91
+ .sheet-head .sigil { font-family: var(--display); font-style: italic; letter-spacing: 0; text-transform: none; font-size: 12px; }
92
+
93
+ .crop-mark { position: absolute; width: 12px; height: 12px; pointer-events: none; }
94
+ .crop-mark::before, .crop-mark::after { content: ""; position: absolute; background: var(--ink); }
95
+ .crop-mark::before { left: 0; right: 0; height: 0.5px; top: 50%; }
96
+ .crop-mark::after { top: 0; bottom: 0; width: 0.5px; left: 50%; }
97
+
98
+ /* ===== BOARD ======================================================== */
99
+ .board {
100
+ position: relative; width: var(--board-size); height: var(--board-size);
101
+ background: var(--parchment); border: 3px solid var(--ink);
102
+ box-shadow: inset 0 0 0 1px var(--parchment), inset 0 0 0 6px var(--ink), inset 0 0 0 7px var(--parchment);
103
+ color: var(--ink); font-family: var(--ui);
104
+ }
105
+ .edge { position: absolute; display: flex; }
106
+ .edge-bottom { left: var(--corner-size); right: var(--corner-size); bottom: 0; height: var(--space-depth); flex-direction: row-reverse; }
107
+ .edge-top { left: var(--corner-size); right: var(--corner-size); top: 0; height: var(--space-depth); flex-direction: row; }
108
+ .edge-left { top: var(--corner-size); bottom: var(--corner-size); left: 0; width: var(--space-depth); flex-direction: column-reverse; }
109
+ .edge-right { top: var(--corner-size); bottom: var(--corner-size); right: 0; width: var(--space-depth); flex-direction: column; }
110
+ .corner { position: absolute; width: var(--corner-size); height: var(--corner-size); border: 1px solid var(--ink); background: var(--parchment); overflow: hidden; }
111
+ .corner-br { right: 0; bottom: 0; } .corner-bl { left: 0; bottom: 0; }
112
+ .corner-tl { left: 0; top: 0; } .corner-tr { right: 0; top: 0; }
113
+ .space {
114
+ position: relative; border: 1px solid var(--ink); background: var(--parchment);
115
+ overflow: hidden; flex-shrink: 0;
116
+ }
117
+ .edge-bottom .space, .edge-top .space { width: var(--space-len); height: var(--space-depth); }
118
+ .edge-left .space, .edge-right .space { width: var(--space-depth); height: var(--space-len); }
119
+ .space .content { position: absolute; width: var(--space-len); height: var(--space-depth); display: grid; grid-template-rows: 28px 1fr 24px; color: var(--ink); }
120
+ .edge-bottom .space .content { top: 0; left: 0; }
121
+ .edge-top .space .content { top: 50%; left: 50%; transform: translate(-50%,-50%) rotate(180deg); transform-origin: center; }
122
+ .edge-left .space .content { top: 50%; left: 50%; transform: translate(-50%,-50%) rotate(-90deg); transform-origin: center; }
123
+ .edge-right .space .content { top: 50%; left: 50%; transform: translate(-50%,-50%) rotate(90deg); transform-origin: center; }
124
+ .space .band {
125
+ display: flex; align-items: center; justify-content: space-between; padding: 0 6px;
126
+ color: #fff; border-bottom: 1px solid var(--ink);
127
+ font-family: var(--ui); font-size: 8px; letter-spacing: .14em; text-transform: uppercase; font-weight: 700;
128
+ }
129
+ .space .band .num { font-family: var(--mono); font-size: 9px; background: rgba(0,0,0,0.18); border: 1px solid rgba(255,255,255,0.55); padding: 1px 4px; }
130
+ .space .band .band-label { font-family: var(--ui); font-size: 7.5px; letter-spacing: .18em; }
131
+ .space .body { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; padding: 4px 5px; text-align: center; }
132
+ .space .body svg.glyph { width: 30px; height: 30px; color: var(--ink); }
133
+ .space .body .name { font-family: var(--display); font-size: 11.5px; line-height: 1.05; max-width: 100%; text-wrap: balance; }
134
+ .space .foot { border-top: 1px solid var(--ink); display: flex; align-items: center; justify-content: space-between; padding: 0 6px; font-family: var(--mono); font-size: 10px; }
135
+ .space .foot .price { font-family: var(--display); font-size: 13px; }
136
+ .space .foot .kind { font-family: var(--ui); font-size: 7.5px; letter-spacing: .14em; text-transform: uppercase; font-weight: 700; }
137
+
138
+ .p-horizontal { background-image: repeating-linear-gradient(0deg, rgba(255,255,255,0) 0 3px, rgba(255,255,255,.34) 3px 4px); }
139
+ .p-vertical { background-image: repeating-linear-gradient(90deg, rgba(255,255,255,0) 0 3px, rgba(255,255,255,.34) 3px 4px); }
140
+ .p-diag-up { background-image: repeating-linear-gradient(45deg, rgba(255,255,255,0) 0 3px, rgba(255,255,255,.34) 3px 4px); }
141
+ .p-wave { background-image: radial-gradient(circle at 50% 100%, rgba(255,255,255,.34) 1.5px, transparent 2px), radial-gradient(circle at 0% 100%, rgba(255,255,255,.34) 1.5px, transparent 2px), radial-gradient(circle at 100% 100%, rgba(255,255,255,.34) 1.5px, transparent 2px); background-size: 8px 4px; }
142
+ .p-dots { background-image: radial-gradient(rgba(255,255,255,.42) 0.8px, transparent 1.4px); background-size: 5px 5px; }
143
+ .p-diag-down { background-image: repeating-linear-gradient(-45deg, rgba(255,255,255,0) 0 3px, rgba(255,255,255,.34) 3px 4px); }
144
+ .p-cross { background-image: repeating-linear-gradient(45deg, rgba(255,255,255,0) 0 3px, rgba(255,255,255,.28) 3px 4px), repeating-linear-gradient(-45deg, rgba(255,255,255,0) 0 3px, rgba(255,255,255,.28) 3px 4px); }
145
+ .p-chevron { background-image: linear-gradient(135deg, rgba(255,255,255,.32) 25%, transparent 25%), linear-gradient(225deg, rgba(255,255,255,.32) 25%, transparent 25%); background-size: 8px 8px; }
146
+
147
+ .sys-revolutionary-debt .band { background: var(--revolutionary-debt); }
148
+ .sys-state-debt .band { background: var(--state-debt); }
149
+ .sys-revenue-system .band { background: var(--revenue-system); }
150
+ .sys-commercial-infrastructure .band { background: var(--commercial-infrastructure); }
151
+ .sys-national-finance .band { background: var(--national-finance); }
152
+ .sys-internal-improvements .band { background: var(--internal-improvements); }
153
+ .sys-manufactures .band { background: var(--manufactures); }
154
+ .sys-strategic-industry .band { background: var(--strategic-industry); }
155
+ .route .band { background: var(--ink); background-image: repeating-linear-gradient(90deg, transparent 0 10px, rgba(255,255,255,.5) 10px 11px, transparent 11px 21px, rgba(255,255,255,.5) 21px 22px); }
156
+ .institution .band { background: var(--ink); background-image: radial-gradient(circle, rgba(255,255,255,.5) 1px, transparent 1.5px); background-size: 6px 6px; }
157
+ .institution .body svg.glyph { width: 38px; height: 38px; }
158
+ .institution .body .name { font-size: 12px; }
159
+ .tax .band { background: var(--highlight); }
160
+ .tax .body svg.glyph { color: var(--highlight); }
161
+ .tax .foot .price { color: var(--highlight); }
162
+ .card-space .band { background: var(--ink); background-image: repeating-linear-gradient(45deg, transparent 0 4px, rgba(255,255,255,.28) 4px 5px); }
163
+ .card-space .body svg.glyph { width: 36px; height: 36px; }
164
+ .card-debate .body svg.glyph { color: var(--state-debt); }
165
+ .card-shock .body svg.glyph { color: var(--highlight); }
166
+ .card-space .foot .kind { font-weight: 700; }
167
+ .card-debate .foot .kind { color: var(--state-debt); }
168
+ .card-shock .foot .kind { color: var(--highlight); }
169
+
170
+ .corner .content { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; padding: 8px; text-align: center; }
171
+ .corner-br .content { transform: rotate(-45deg); } .corner-bl .content { transform: rotate(45deg); }
172
+ .corner-tl .content { transform: rotate(135deg); } .corner-tr .content { transform: rotate(-135deg); }
173
+ .corner .head { font-family: var(--ui); font-size: 9px; font-weight: 700; letter-spacing: .22em; text-transform: uppercase; border-bottom: 1px solid var(--ink); padding-bottom: 3px; min-width: 110px; }
174
+ .corner .glyph-ring { width: 56px; height: 56px; border: 1px solid var(--ink); border-radius: 50%; display: flex; align-items: center; justify-content: center; position: relative; background: var(--parchment); }
175
+ .corner .glyph-ring::before { content: ""; position: absolute; inset: 4px; border: 1px solid var(--rule-soft); border-radius: 50%; }
176
+ .corner .glyph-ring svg { width: 30px; height: 30px; color: var(--ink); }
177
+ .corner .sub { font-family: var(--body); font-size: 9px; line-height: 1.3; font-style: italic; max-width: 130px; }
178
+ .corner.start .head { color: var(--national-finance); border-color: var(--national-finance); }
179
+ .corner.crisis .head { color: var(--highlight); border-color: var(--highlight); } .corner.crisis .glyph-ring svg { color: var(--highlight); }
180
+ .corner.safe .head { color: var(--commercial-infrastructure); border-color: var(--commercial-infrastructure); }
181
+ .corner.send .head { color: var(--highlight); border-color: var(--highlight); } .corner.send .glyph-ring svg { color: var(--highlight); }
182
+
183
+ .center { position: absolute; top: var(--corner-size); left: var(--corner-size); right: var(--corner-size); bottom: var(--corner-size); padding: 0.45in 0.55in; display: grid; grid-template-rows: auto 1fr auto; gap: 14px; background: var(--parchment); }
184
+ .center::before, .center::after { content: ""; position: absolute; left: 14px; right: 14px; height: 1px; background: var(--ink); opacity: .35; }
185
+ .center::before { top: 14px; } .center::after { bottom: 14px; }
186
+ .c-head { text-align: center; padding-top: 8px; }
187
+ .c-head .lead-rule { display: flex; justify-content: center; align-items: center; gap: 10px; font-family: var(--ui); font-size: 11px; letter-spacing: .32em; text-transform: uppercase; margin-bottom: 12px; }
188
+ .c-head .lead-rule::before, .c-head .lead-rule::after { content: ""; height: 1px; background: var(--ink); flex: 1; max-width: 80px; }
189
+ .c-head h1 { font-family: var(--display); font-weight: 400; font-size: 80px; line-height: 0.95; margin: 0; letter-spacing: -.01em; }
190
+ .c-head .subtitle { font-family: var(--display); font-style: italic; font-size: 18px; margin-top: 10px; }
191
+ .c-mid { display: grid; grid-template-columns: 1.35fr 1fr; gap: 28px; align-items: start; padding: 0 10px; }
192
+ .tracks { display: flex; flex-direction: column; gap: 14px; }
193
+ .tracks .panel-head { display: flex; justify-content: space-between; align-items: baseline; border-bottom: 1px solid var(--ink); padding-bottom: 4px; margin-bottom: 4px; }
194
+ .tracks .panel-head h3 { font-family: var(--ui); font-size: 12px; font-weight: 700; letter-spacing: .26em; text-transform: uppercase; margin: 0; }
195
+ .tracks .panel-head .note { font-family: var(--display); font-style: italic; font-size: 11px; }
196
+ .track { display: grid; grid-template-columns: 140px 1fr 64px; align-items: center; gap: 12px; }
197
+ .track .label { display: flex; align-items: center; gap: 6px; font-family: var(--ui); font-weight: 700; font-size: 11px; letter-spacing: .14em; text-transform: uppercase; }
198
+ .track .label svg { width: 16px; height: 16px; }
199
+ .track .scale { position: relative; height: 26px; border: 1px solid var(--ink); background: var(--parchment); display: grid; grid-template-columns: repeat(13, 1fr); }
200
+ .track .scale .tick { border-right: 1px solid var(--rule-soft); display: flex; align-items: center; justify-content: center; font-family: var(--mono); font-size: 8.5px; position: relative; }
201
+ .track .scale .tick:last-child { border-right: 0; }
202
+ .track .scale .tick.major { background: rgba(26,22,18,0.05); }
203
+ .track .scale .pip { position: absolute; left: 0; right: 0; bottom: -10px; text-align: center; font-family: var(--ui); font-size: 8px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; pointer-events: none; }
204
+ .track .scale .pip::before { content: ""; display: block; margin: 0 auto 1px; width: 12px; height: 12px; border: 1.5px solid var(--ink); border-radius: 50%; background: currentColor; }
205
+ .track.t-credit .scale .pip { color: var(--national-finance); }
206
+ .track.t-resist .scale .pip { color: var(--highlight); }
207
+ .track.t-indust .scale .pip { color: var(--manufactures); }
208
+ .track .cap-note { font-family: var(--mono); font-size: 9px; text-align: right; line-height: 1.2; opacity: .8; }
209
+ .acts-list { border: 1.5px solid var(--ink); padding: 12px 14px; }
210
+ .acts-list h3 { font-family: var(--ui); font-size: 12px; font-weight: 700; letter-spacing: .26em; text-transform: uppercase; text-align: center; border-bottom: 1px solid var(--ink); padding-bottom: 4px; margin: 4px 0 8px; }
211
+ .acts-list ol { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 5px; }
212
+ .acts-list li { display: grid; grid-template-columns: 22px 22px 1fr; align-items: center; gap: 8px; font-family: var(--body); font-size: 11.5px; }
213
+ .acts-list li .n { font-family: var(--mono); font-size: 10px; background: var(--ink); color: var(--parchment); width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; }
214
+ .acts-list li svg { width: 18px; height: 18px; color: var(--ink); }
215
+ .acts-list li .name { font-family: var(--display); font-size: 13px; }
216
+ .c-foot { display: grid; grid-template-columns: 1fr 1fr; align-items: center; gap: 16px; padding: 0 10px; }
217
+ .laps { display: flex; flex-direction: column; gap: 4px; }
218
+ .laps h3 { font-family: var(--ui); font-size: 11px; font-weight: 700; letter-spacing: .26em; text-transform: uppercase; margin-bottom: 4px; }
219
+ .laps .row { display: flex; gap: 6px; }
220
+ .laps .cell { width: 36px; height: 36px; border: 1.5px solid var(--ink); background: var(--parchment); display: flex; align-items: center; justify-content: center; font-family: var(--display); font-size: 18px; position: relative; }
221
+ .laps .cell::after { content: ""; position: absolute; inset: 3px; border: 1px solid var(--rule-soft); }
222
+ .laps .cell .small { position: absolute; top: 2px; left: 4px; font-family: var(--mono); font-size: 7px; letter-spacing: .08em; opacity: .65; }
223
+ .mechanics { text-align: right; border: 1px solid var(--ink); padding: 10px 12px; background: var(--parchment-2); }
224
+ .mechanics .label { font-family: var(--ui); font-size: 9px; letter-spacing: .22em; text-transform: uppercase; opacity: .75; margin-bottom: 4px; }
225
+ .mechanics .line { font-family: var(--display); font-size: 14px; line-height: 1.3; }
226
+ .mechanics .sub { font-family: var(--mono); font-size: 9px; margin-top: 4px; letter-spacing: .04em; opacity: .85; }
227
+
228
+ /* Tile pages */
229
+ .tile-strip { height: 2in; padding: 0.3in 0.4in 0.2in; border-bottom: 1px solid var(--ink); display: grid; grid-template-columns: 1fr auto; align-items: end; gap: 18px; }
230
+ .tile-strip .legend { font-family: var(--ui); font-size: 9.5px; letter-spacing: .14em; }
231
+ .tile-strip h2 { font-family: var(--display); font-size: 36px; margin: 0; line-height: 0.95; }
232
+ .tile-strip .sub { font-family: var(--display); font-style: italic; font-size: 14px; margin-top: 4px; }
233
+ .tile-strip .quad-id { font-family: var(--mono); font-size: 11px; letter-spacing: .12em; border: 1px solid var(--ink); padding: 8px 12px; }
234
+ .tile-window { position: relative; width: 8.5in; height: 9in; overflow: hidden; }
235
+ .tile-window .board { position: absolute; width: 17in; height: 17in; border-width: 3px; }
236
+ .tile-window[data-quad="tl"] .board { top: 0; left: 0; }
237
+ .tile-window[data-quad="tr"] .board { top: 0; right: 0; }
238
+ .tile-window[data-quad="bl"] .board { bottom: 0; left: 0; }
239
+ .tile-window[data-quad="br"] .board { bottom: 0; right: 0; }
240
+ .tile-window .crop { position: absolute; width: 14px; height: 14px; pointer-events: none; }
241
+ .tile-window .crop::before, .tile-window .crop::after { content: ""; position: absolute; background: var(--ink); }
242
+ .tile-window .crop::before { left: 0; right: 0; height: 1px; top: 50%; }
243
+ .tile-window .crop::after { top: 0; bottom: 0; width: 1px; left: 50%; }
244
+ .tile-window .crop.tl { top: -1px; left: -1px; transform: translate(-50%,-50%); }
245
+ .tile-window .crop.tr { top: -1px; right: -1px; transform: translate(50%,-50%); }
246
+ .tile-window .crop.bl { bottom: -1px; left: -1px; transform: translate(-50%,50%); }
247
+ .tile-window .crop.br { bottom: -1px; right: -1px; transform: translate(50%,50%); }
248
+ .align-mark { position: absolute; font-family: var(--mono); font-size: 9px; letter-spacing: .1em; background: var(--parchment); padding: 2px 6px; border: 1px solid var(--ink); }
249
+ .align-mark.tm { top: 0.5in; left: 50%; transform: translateX(-50%); }
250
+ .align-mark.bm { bottom: 0.5in; left: 50%; transform: translateX(-50%); }
251
+ .align-mark.lm { left: 0.25in; top: 50%; transform: translateY(-50%); writing-mode: vertical-rl; }
252
+ .align-mark.rm { right: 0.25in; top: 50%; transform: translateY(-50%); writing-mode: vertical-rl; }
253
+
254
+ /* ===== PROPERTY CARD ================================================ */
255
+ .grid { display: grid; grid-template-columns: repeat(3, 2.5in); grid-template-rows: repeat(3, 3.5in); gap: 0; justify-content: center; position: relative; }
256
+ .card { width: 2.5in; height: 3.5in; background: var(--parchment); color: var(--ink); border: 1.5px solid var(--ink); display: grid; grid-template-rows: 30px 50px 60px 50px 1fr 32px; position: relative; overflow: hidden; font-family: var(--ui); }
257
+ .card::before { content: ""; position: absolute; inset: 4px; border: 0.5px solid var(--rule-soft); pointer-events: none; }
258
+ .card .band { position: relative; color: #fff; display: flex; align-items: center; justify-content: space-between; padding: 0 10px; font-family: var(--ui); font-size: 8.5px; letter-spacing: .2em; text-transform: uppercase; font-weight: 700; border-bottom: 1px solid var(--ink); }
259
+ .card .band .num { font-family: var(--mono); font-size: 9.5px; background: rgba(0,0,0,0.2); border: 1px solid rgba(255,255,255,0.55); padding: 1px 5px; }
260
+ .card .title { padding: 8px 12px 4px; border-bottom: 1px solid var(--rule-soft); text-align: center; }
261
+ .card .title .name { font-family: var(--display); font-size: 16px; line-height: 1.0; margin: 0; text-wrap: balance; }
262
+ .card .title .subkind { font-family: var(--ui); font-size: 7.5px; letter-spacing: .22em; text-transform: uppercase; margin-top: 4px; opacity: .85; }
263
+ .card .glyph { display: flex; align-items: center; justify-content: center; }
264
+ .card .glyph .icon-ring { width: 52px; height: 52px; border: 1px solid var(--ink); border-radius: 50%; display: flex; align-items: center; justify-content: center; background: var(--parchment); position: relative; }
265
+ .card .glyph .icon-ring::after { content: ""; position: absolute; inset: 3px; border: 0.5px solid var(--rule-soft); border-radius: 50%; }
266
+ .card .glyph .icon-ring svg { width: 28px; height: 28px; color: var(--ink); }
267
+ .card .flavor { padding: 0 14px; display: flex; align-items: center; justify-content: center; font-family: var(--display); font-style: italic; font-size: 9.5px; line-height: 1.32; text-align: center; text-wrap: pretty; }
268
+ .card .pay { margin: 0 8px; border: 1px solid var(--ink); border-top-width: 1.5px; background: var(--parchment-2); display: grid; grid-template-rows: 18px 1fr; overflow: hidden; }
269
+ .card .pay .pay-head { background: var(--ink); color: var(--parchment); display: flex; align-items: center; justify-content: space-between; padding: 0 8px; font-family: var(--ui); font-size: 7.5px; letter-spacing: .22em; text-transform: uppercase; }
270
+ .card .pay .pay-head .legend { font-family: var(--mono); font-size: 7px; opacity: .85; }
271
+ .card .pay table { width: 100%; border-collapse: collapse; font-family: var(--ui); font-size: 9px; letter-spacing: .08em; }
272
+ .card .pay td { padding: 1.5px 8px; border-bottom: 0.5px solid var(--rule-soft); vertical-align: middle; line-height: 1.2; }
273
+ .card .pay tr:last-child td { border-bottom: 0; }
274
+ .card .pay td.tier { text-transform: uppercase; font-weight: 700; font-size: 8.5px; }
275
+ .card .pay td.sub { font-family: var(--mono); font-size: 7.5px; opacity: .7; text-align: right; padding-right: 3px; }
276
+ .card .pay td.val { font-family: var(--display); font-size: 12px; text-align: right; padding-right: 8px; font-variant-numeric: tabular-nums; }
277
+ .card .pay tr.base td { background: rgba(26,22,18,0.04); }
278
+ .card .pay tr.fullset td { font-style: italic; }
279
+ .card .pay .rules-list { display: flex; flex-direction: column; padding: 4px 8px; gap: 4px; height: 100%; justify-content: space-around; }
280
+ .card .pay .rules-list .row { display: grid; grid-template-columns: 1fr auto; align-items: center; font-family: var(--ui); font-size: 8.5px; line-height: 1.18; gap: 6px; }
281
+ .card .pay .rules-list .row .cond { font-family: var(--body); font-size: 9px; line-height: 1.18; letter-spacing: 0; }
282
+ .card .pay .rules-list .row .val { font-family: var(--display); font-size: 12px; white-space: nowrap; }
283
+ .card .pay .rules-list .row .cond strong { font-family: var(--ui); font-size: 7.5px; letter-spacing: .14em; text-transform: uppercase; font-weight: 700; display: block; margin-bottom: 1px; }
284
+ .card .pay .rules-list .row.alt { background: rgba(26,22,18,0.04); padding: 2px 4px; }
285
+ .card .foot { border-top: 1px solid var(--ink); display: grid; align-items: center; font-family: var(--ui); font-size: 7px; letter-spacing: .18em; text-transform: uppercase; }
286
+ .card.has-mortgage .foot { grid-template-columns: 1fr 1fr 1fr; }
287
+ .card.no-mortgage .foot { grid-template-columns: 1fr 2fr; }
288
+ .card .foot .cell { display: flex; flex-direction: column; align-items: center; border-right: 1px solid var(--rule-soft); padding: 2px; line-height: 1.05; }
289
+ .card .foot .cell:last-child { border-right: 0; }
290
+ .card .foot .cell .lbl { font-weight: 700; font-size: 6.8px; opacity: .8; }
291
+ .card .foot .cell .v { font-family: var(--display); font-size: 13px; }
292
+ .card .foot .note { font-family: var(--ui); font-size: 7px; letter-spacing: .14em; text-transform: uppercase; text-align: center; padding: 2px 4px; }
293
+ .card .foot .note span { font-family: var(--display); font-style: italic; font-size: 9px; letter-spacing: 0; text-transform: none; display: block; margin-top: 1px; }
294
+
295
+ .card.sys-revolutionary-debt .band { background: var(--revolutionary-debt); background-image: repeating-linear-gradient(0deg, rgba(255,255,255,0) 0 3px, rgba(255,255,255,.32) 3px 4px); }
296
+ .card.sys-state-debt .band { background: var(--state-debt); background-image: repeating-linear-gradient(90deg, rgba(255,255,255,0) 0 3px, rgba(255,255,255,.32) 3px 4px); }
297
+ .card.sys-revenue-system .band { background: var(--revenue-system); background-image: repeating-linear-gradient(45deg, rgba(255,255,255,0) 0 3px, rgba(255,255,255,.32) 3px 4px); }
298
+ .card.sys-commercial-infrastructure .band { background: var(--commercial-infrastructure); background-image: radial-gradient(circle at 50% 100%, rgba(255,255,255,.34) 1.5px, transparent 2px), radial-gradient(circle at 0% 100%, rgba(255,255,255,.34) 1.5px, transparent 2px), radial-gradient(circle at 100% 100%, rgba(255,255,255,.34) 1.5px, transparent 2px); background-size: 8px 4px; }
299
+ .card.sys-national-finance .band { background: var(--national-finance); background-image: radial-gradient(rgba(255,255,255,.42) 0.8px, transparent 1.4px); background-size: 5px 5px; }
300
+ .card.sys-internal-improvements .band { background: var(--internal-improvements); background-image: repeating-linear-gradient(-45deg, rgba(255,255,255,0) 0 3px, rgba(255,255,255,.32) 3px 4px); }
301
+ .card.sys-manufactures .band { background: var(--manufactures); background-image: repeating-linear-gradient(45deg, rgba(255,255,255,0) 0 3px, rgba(255,255,255,.28) 3px 4px), repeating-linear-gradient(-45deg, rgba(255,255,255,0) 0 3px, rgba(255,255,255,.28) 3px 4px); }
302
+ .card.sys-strategic-industry .band { background: var(--strategic-industry); background-image: linear-gradient(135deg, rgba(255,255,255,.32) 25%, transparent 25%), linear-gradient(225deg, rgba(255,255,255,.32) 25%, transparent 25%); background-size: 8px 8px; }
303
+ .card.kind-route .band { background: var(--ink); background-image: repeating-linear-gradient(90deg, transparent 0 10px, rgba(255,255,255,.5) 10px 11px, transparent 11px 21px, rgba(255,255,255,.5) 21px 22px); }
304
+ .card.kind-institution .band { background: var(--ink); background-image: radial-gradient(circle, rgba(255,255,255,.5) 1px, transparent 1.5px); background-size: 6px 6px; }
305
+
306
+ /* Route + Institution cards — looser layout, bigger payment values */
307
+ .card.kind-route .pay .rules-list .row .cond,
308
+ .card.kind-institution .pay .rules-list .row .cond {
309
+ font-family: var(--body); font-size: 10px; line-height: 1.2;
310
+ }
311
+ .card.kind-route .pay .rules-list .row .cond strong,
312
+ .card.kind-institution .pay .rules-list .row .cond strong {
313
+ font-family: var(--ui); font-size: 7.5px; letter-spacing: .14em; text-transform: uppercase; font-weight: 700; display: block; margin-bottom: 1px;
314
+ }
315
+ .card.kind-route .pay .rules-list .row .val,
316
+ .card.kind-institution .pay .rules-list .row .val {
317
+ font-family: var(--display); font-size: 16px; line-height: 1; font-variant-numeric: tabular-nums; white-space: nowrap; font-weight: 700;
318
+ }
319
+ .card.kind-route .pay .rules-list,
320
+ .card.kind-institution .pay .rules-list {
321
+ padding: 6px 10px; gap: 6px;
322
+ }
323
+ .card.kind-institution .pay .rules-list .row .val.muted {
324
+ font-style: italic;
325
+ opacity: 0.65;
326
+ font-weight: 400;
327
+ }
328
+
329
+ /* ===== DIGITAL BOARD OVERVIEW (screen-only) ======================== */
330
+ .board-overview { display: none; }
331
+ @media screen {
332
+ .board-overview {
333
+ display: block;
334
+ width: min(100%, 1100px);
335
+ margin: 4px auto 8px;
336
+ padding: 18px 20px;
337
+ background: var(--parchment); color: var(--ink);
338
+ border: 1.5px solid var(--ink);
339
+ box-shadow: 0 10px 40px rgba(0,0,0,.45);
340
+ position: relative;
341
+ font-family: var(--ui);
342
+ }
343
+ .board-overview .bo-head { display: flex; justify-content: space-between; align-items: baseline; border-bottom: 1px solid var(--ink); padding-bottom: 8px; margin-bottom: 12px; }
344
+ .board-overview .bo-eyebrow { font-family: var(--ui); font-size: 9.5px; font-weight: 700; letter-spacing: .32em; text-transform: uppercase; }
345
+ .board-overview .bo-sub { font-family: var(--display); font-style: italic; font-size: 13px; }
346
+ .board-overview .bo-stage { position: relative; width: 100%; aspect-ratio: 1; overflow: hidden; border: 1px solid var(--rule-soft); }
347
+ .board-overview .bo-stage .board { position: absolute; top: 0; left: 0; transform-origin: top left; }
348
+ .board-overview .bo-note { font-family: var(--ui); font-size: 9px; letter-spacing: .18em; text-transform: uppercase; opacity: .75; margin-top: 10px; display: flex; justify-content: space-between; }
349
+ }
350
+ @media print { .board-overview { display: none !important; } }
351
+ .ecard { width: 2.5in; height: 3.5in; background: var(--parchment); color: var(--ink); border: 1.5px solid var(--ink); display: grid; grid-template-rows: 28px 18px 54px 28px 1fr 32px 22px; position: relative; overflow: hidden; font-family: var(--body); }
352
+ .ecard::before { content: ""; position: absolute; inset: 4px; border: 0.5px solid var(--rule-soft); pointer-events: none; z-index: 1; }
353
+ .ecard .band { position: relative; color: #fff; display: flex; align-items: center; justify-content: space-between; padding: 0 10px; font-family: var(--ui); font-size: 9px; letter-spacing: .26em; text-transform: uppercase; font-weight: 700; border-bottom: 1px solid var(--ink); z-index: 2; }
354
+ .ecard .band .num { font-family: var(--mono); font-size: 9.5px; background: rgba(0,0,0,0.2); border: 1px solid rgba(255,255,255,0.55); padding: 1px 5px; }
355
+ .ecard .alert { position: relative; display: flex; align-items: center; justify-content: center; font-family: var(--ui); font-size: 7.5px; font-weight: 700; letter-spacing: .32em; text-transform: uppercase; z-index: 2; }
356
+ .ecard .title { padding: 8px 12px 0; text-align: center; display: flex; flex-direction: column; align-items: center; justify-content: center; z-index: 2; }
357
+ .ecard .title .name { font-family: var(--display); font-size: 17px; line-height: 1.0; text-wrap: balance; }
358
+ .ecard .affects { display: flex; align-items: center; justify-content: center; gap: 6px; padding: 0 10px; z-index: 2; }
359
+ .ecard .affects .aff { width: 18px; height: 18px; border: 1px solid var(--ink); background: var(--parchment); display: flex; align-items: center; justify-content: center; }
360
+ .ecard .affects .aff svg { width: 11px; height: 11px; color: var(--ink); }
361
+ .ecard .affects .tag { font-family: var(--ui); font-size: 7.5px; letter-spacing: .14em; text-transform: uppercase; font-weight: 700; padding: 1px 5px; border: 1px solid var(--rule-soft); background: var(--parchment-2); }
362
+ .ecard .effect { padding: 6px 14px 4px; display: flex; align-items: center; justify-content: center; font-family: var(--body); font-size: 10.5px; line-height: 1.42; text-align: center; text-wrap: pretty; z-index: 2; }
363
+ .ecard .effect p { margin: 0; }
364
+ .ecard .effect p + p { margin-top: 5px; }
365
+ .ecard .effect strong { font-family: var(--display); font-weight: 700; }
366
+ .ecard .effect var { font-family: var(--display); font-style: italic; }
367
+ .ecard .effect em { font-style: italic; opacity: .8; }
368
+ .ecard .effect .sys { font-family: var(--ui); font-size: 9.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; }
369
+ .ecard .outcomes { display: flex; align-items: center; justify-content: center; gap: 4px; padding: 0 8px; z-index: 2; }
370
+ .ecard .outcomes:empty { display: none; }
371
+ .ecard .chip { display: inline-flex; align-items: center; gap: 3px; padding: 2px 5px; font-family: var(--ui); font-size: 7.5px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; line-height: 1; border: 1px solid var(--ink); white-space: nowrap; }
372
+ .ecard .chip .delta { font-family: var(--mono); font-size: 8.5px; letter-spacing: 0; }
373
+ .ecard .chip.t-credit { background: var(--national-finance); color: #fff; }
374
+ .ecard .chip.t-resist { background: var(--highlight); color: #fff; }
375
+ .ecard .chip.t-indust { background: var(--manufactures); color: #fff; }
376
+ .ecard .foot { border-top: 1px solid var(--ink); display: flex; align-items: center; justify-content: space-between; padding: 0 10px; font-family: var(--ui); font-size: 7.5px; letter-spacing: .18em; text-transform: uppercase; z-index: 2; }
377
+ .ecard .foot .code { font-family: var(--mono); letter-spacing: .08em; }
378
+ .ecard .foot .deck-mark { display: flex; align-items: center; gap: 5px; }
379
+ .ecard .foot .deck-mark svg { width: 12px; height: 12px; color: var(--ink); }
380
+
381
+ .ecard.deck-shock .band { background: var(--ink); background-image: linear-gradient(180deg, var(--highlight) 0, var(--highlight) 3px, var(--ink) 3px); }
382
+ .ecard.deck-shock .alert { background: var(--parchment-2); color: var(--highlight); border-bottom: 0.5px solid var(--highlight); }
383
+ .ecard.deck-shock .alert::before, .ecard.deck-shock .alert::after { content: "❖"; color: var(--highlight); font-size: 7px; padding: 0 6px; font-family: var(--display); }
384
+ .ecard.deck-shock .effect strong { color: var(--highlight); }
385
+ .ecard.deck-shock .foot { border-top-color: var(--highlight); }
386
+ .ecard.deck-shock .foot .deck-mark svg { color: var(--highlight); }
387
+ .ecard.deck-shock::after { content: ""; position: absolute; top: 0; right: 0; width: 18px; height: 18px; background: var(--highlight); clip-path: polygon(100% 0, 100% 100%, 0 0); z-index: 3; }
388
+
389
+ .ecard.deck-debate .band { background: var(--national-finance); background-image: repeating-linear-gradient(90deg, rgba(255,255,255,0) 0 3px, rgba(255,255,255,.32) 3px 4px); }
390
+ .ecard.deck-debate .alert { background: var(--parchment-2); color: var(--national-finance); font-style: italic; letter-spacing: .22em; border-bottom: 0.5px solid var(--national-finance); font-family: var(--display); font-size: 9px; font-weight: 400; text-transform: none; }
391
+ .ecard.deck-debate .alert::before, .ecard.deck-debate .alert::after { content: "✦"; color: var(--national-finance); font-size: 8px; padding: 0 8px; font-style: normal; }
392
+ .ecard.deck-debate .title::after { content: "* * *"; font-family: var(--display); font-size: 9px; letter-spacing: .4em; color: var(--national-finance); opacity: .8; margin-top: 6px; display: block; }
393
+ .ecard.deck-debate .effect strong { color: var(--national-finance); }
394
+ .ecard.deck-debate .foot { border-top-color: var(--national-finance); }
395
+ .ecard.deck-debate .foot .deck-mark svg { color: var(--national-finance); }
396
+ .ecard.deck-debate::after { content: ""; position: absolute; top: 6px; right: 6px; width: 16px; height: 16px; border: 1px solid var(--national-finance); background: linear-gradient(45deg, transparent 46%, var(--national-finance) 46% 54%, transparent 54%), linear-gradient(-45deg, transparent 46%, var(--national-finance) 46% 54%, transparent 54%); z-index: 3; }
397
+
398
+ /* ===== ACT CARD ===================================================== */
399
+ .grid-acts { display: grid; grid-template-columns: repeat(2, 3.5in); grid-template-rows: repeat(2, 5in); justify-content: center; gap: 0; position: relative; }
400
+ .act { width: 3.5in; height: 5in; background: var(--parchment); color: var(--ink); border: 2px solid var(--ink); display: grid; grid-template-rows: 38px 1fr 96px 32px; position: relative; overflow: hidden; font-family: var(--body); }
401
+ .act::before { content: ""; position: absolute; inset: 5px; border: 0.5px solid var(--rule-soft); pointer-events: none; }
402
+ .act .head { background: var(--ink); color: var(--parchment); display: flex; align-items: center; justify-content: space-between; padding: 0 14px; font-family: var(--ui); font-size: 10px; letter-spacing: .26em; text-transform: uppercase; font-weight: 700; z-index: 2; }
403
+ .act .head .lap { font-family: var(--mono); font-size: 10px; background: var(--parchment); color: var(--ink); padding: 2px 8px; letter-spacing: .14em; }
404
+ .act .body { padding: 14px 18px 8px; display: grid; grid-template-rows: auto auto 1fr; gap: 8px; z-index: 2; }
405
+ .act .body .lap-mark { display: flex; align-items: center; gap: 10px; font-family: var(--ui); font-size: 10px; letter-spacing: .26em; text-transform: uppercase; }
406
+ .act .body .lap-mark .roman { font-family: var(--display); font-size: 22px; border: 1.5px solid var(--ink); padding: 0 10px; background: var(--parchment); }
407
+ .act .body .name { font-family: var(--display); font-size: 28px; line-height: 1.0; letter-spacing: -.01em; text-wrap: balance; }
408
+ .act .body .effect { font-family: var(--body); font-size: 12px; line-height: 1.45; margin-top: 4px; }
409
+ .act .body .effect p { margin: 0 0 6px; }
410
+ .act .body .effect strong { font-family: var(--display); font-weight: 700; }
411
+ .act .body .effect var { font-family: var(--display); font-style: italic; }
412
+ .act .body .effect .sys { font-family: var(--ui); font-size: 10.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; }
413
+ .act .vote { margin: 0 14px 8px; border: 1.5px solid var(--ink); padding: 8px 12px; display: grid; grid-template-columns: 72px 1fr; gap: 12px; align-items: center; background: var(--parchment-2); z-index: 2; }
414
+ .act .vote .stamp { font-family: var(--display); font-size: 20px; line-height: 1; text-align: center; letter-spacing: .04em; border: 1.5px solid var(--ink); padding: 6px 4px 4px; background: var(--parchment); }
415
+ .act .vote .stamp .sub { font-family: var(--ui); font-size: 6.5px; letter-spacing: .22em; text-transform: uppercase; display: block; margin-top: 3px; line-height: 1; }
416
+ .act .vote .text { font-family: var(--body); font-size: 10.5px; line-height: 1.35; }
417
+ .act .vote .text .key { font-family: var(--ui); font-size: 9px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; display: block; margin-bottom: 2px; }
418
+ .act .foot { border-top: 1px solid var(--ink); display: flex; align-items: center; justify-content: space-between; padding: 0 14px; font-family: var(--ui); font-size: 8px; letter-spacing: .16em; text-transform: uppercase; z-index: 2; }
419
+ .act .foot .code { font-family: var(--mono); }
420
+ .act .foot .icon { display: flex; align-items: center; gap: 6px; }
421
+ .act .foot .icon svg { width: 14px; height: 14px; color: var(--ink); }
422
+ .act.voting .vote { display: none; }
423
+ .act.voting .body { grid-template-rows: auto auto 1fr; }
424
+
425
+ /* ===== ROLE CARD ==================================================== */
426
+ .role { width: 3.5in; height: 5in; background: var(--parchment); color: var(--ink); border: 2px solid var(--ink); display: grid; grid-template-rows: 36px 110px 1fr 96px 28px; position: relative; overflow: hidden; font-family: var(--body); }
427
+ .role::before { content: ""; position: absolute; inset: 5px; border: 0.5px solid var(--rule-soft); pointer-events: none; }
428
+ .role .head { background: var(--national-finance); color: #fff; background-image: repeating-linear-gradient(90deg, rgba(255,255,255,0) 0 3px, rgba(255,255,255,.28) 3px 4px); display: flex; align-items: center; justify-content: space-between; padding: 0 14px; font-family: var(--ui); font-size: 10px; letter-spacing: .26em; text-transform: uppercase; font-weight: 700; z-index: 2; }
429
+ .role .head .num { font-family: var(--mono); font-size: 10px; background: rgba(0,0,0,.22); padding: 2px 8px; border: 1px solid rgba(255,255,255,.6); }
430
+ .role .title { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 8px 14px 0; text-align: center; z-index: 2; }
431
+ .role .title .name { font-family: var(--display); font-size: 30px; line-height: 1.0; text-wrap: balance; }
432
+ .role .title .crest { margin-top: 6px; width: 36px; height: 36px; border: 1px solid var(--ink); border-radius: 50%; display: flex; align-items: center; justify-content: center; background: var(--parchment); position: relative; }
433
+ .role .title .crest::after { content: ""; position: absolute; inset: 3px; border: 0.5px solid var(--rule-soft); border-radius: 50%; }
434
+ .role .title .crest svg { width: 22px; height: 22px; color: var(--ink); }
435
+ .role .body { padding: 8px 18px 10px; display: grid; grid-template-rows: auto 1fr; gap: 8px; text-align: center; z-index: 2; }
436
+ .role .body .specialty-label { font-family: var(--ui); font-size: 9px; letter-spacing: .32em; text-transform: uppercase; color: var(--national-finance); border-top: 1px solid var(--ink); border-bottom: 1px solid var(--ink); padding: 4px 0; margin: 0 auto; min-width: 100px; }
437
+ .role .body .ability { font-family: var(--body); font-size: 13px; line-height: 1.4; align-self: center; padding: 0 6px; }
438
+ .role .body .ability strong { font-family: var(--display); font-weight: 700; }
439
+ .role .reminders { margin: 0 14px 6px; border: 1px solid var(--ink); background: var(--parchment-2); padding: 8px 12px; z-index: 2; }
440
+ .role .reminders h3 { font-family: var(--ui); font-size: 8.5px; letter-spacing: .22em; text-transform: uppercase; margin: 0 0 4px; font-weight: 700; }
441
+ .role .reminders ul { margin: 0; padding-left: 14px; }
442
+ .role .reminders li { font-family: var(--body); font-size: 9.5px; line-height: 1.35; margin: 0 0 1px; }
443
+ .role .foot { border-top: 1px solid var(--ink); display: flex; align-items: center; justify-content: space-between; padding: 0 14px; font-family: var(--ui); font-size: 8px; letter-spacing: .18em; text-transform: uppercase; z-index: 2; }
444
+ .role .foot .code { font-family: var(--mono); }
445
+
446
+ /* ===== TRACKER ====================================================== */
447
+ .tracker { width: 100%; border: 2px solid var(--ink); background: var(--parchment); padding: 18px 22px 16px; position: relative; }
448
+ .tracker::before { content: ""; position: absolute; inset: 6px; border: 0.5px solid var(--rule-soft); pointer-events: none; }
449
+ .tracker .tk-head { display: flex; justify-content: space-between; align-items: baseline; border-bottom: 1px solid var(--ink); padding-bottom: 8px; }
450
+ .tracker .tk-head h2 { font-family: var(--display); font-size: 30px; margin: 0; line-height: 1; }
451
+ .tracker .tk-head .sigil { font-family: var(--display); font-style: italic; font-size: 13px; }
452
+ .tracker .tk-intro { font-family: var(--body); font-size: 11px; line-height: 1.4; max-width: 70ch; margin: 8px 0 14px; }
453
+ .tk-row { display: grid; grid-template-columns: 160px 1fr 220px; gap: 14px; padding: 12px 0; border-top: 1px solid var(--rule-soft); align-items: center; }
454
+ .tk-row:first-of-type { border-top: 1.5px solid var(--ink); }
455
+ .tk-row .label { display: flex; flex-direction: column; gap: 4px; }
456
+ .tk-row .label .name { font-family: var(--display); font-size: 18px; line-height: 1; }
457
+ .tk-row .label .tag { font-family: var(--ui); font-size: 8.5px; font-weight: 700; letter-spacing: .22em; text-transform: uppercase; }
458
+ .tk-row .label .starts { font-family: var(--mono); font-size: 9px; margin-top: 2px; opacity: .85; }
459
+ .tk-row .scale { position: relative; border: 1px solid var(--ink); background: var(--parchment); display: grid; grid-template-columns: repeat(13, 1fr); height: 44px; overflow: visible; }
460
+ .tk-row .scale .tick { border-right: 0.5px solid var(--rule-soft); display: flex; align-items: center; justify-content: center; font-family: var(--mono); font-size: 11px; position: relative; }
461
+ .tk-row .scale .tick:last-child { border-right: 0; }
462
+ .tk-row .scale .tick.major { background: rgba(26,22,18,0.05); }
463
+ .tk-row .scale .tick.start { background: rgba(26,22,18,0.15); }
464
+ .tk-row .scale .threshold { position: absolute; bottom: -22px; left: 0; right: 0; text-align: center; font-family: var(--ui); font-size: 7.5px; letter-spacing: .14em; text-transform: uppercase; font-weight: 700; white-space: nowrap; }
465
+ .tk-row .scale .threshold::before { content: "▲"; display: block; font-size: 7px; margin-bottom: -2px; }
466
+ .tk-row .scale .start-pip { position: absolute; top: -22px; left: 0; right: 0; text-align: center; font-family: var(--ui); font-size: 7.5px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; }
467
+ .tk-row .scale .start-pip::after { content: "●"; display: block; font-size: 12px; margin-top: -2px; }
468
+ .tk-row .effects { font-family: var(--body); font-size: 10px; line-height: 1.4; }
469
+ .tk-row .effects ul { padding-left: 14px; margin: 0; }
470
+ .tk-row .effects strong { font-family: var(--display); font-weight: 700; }
471
+ .tk-row.credit .label .name, .tk-row.credit .scale .start-pip, .tk-row.credit .scale .threshold { color: var(--national-finance); }
472
+ .tk-row.resist .label .name, .tk-row.resist .scale .start-pip, .tk-row.resist .scale .threshold { color: var(--highlight); }
473
+ .tk-row.indust .label .name, .tk-row.indust .scale .start-pip, .tk-row.indust .scale .threshold { color: var(--manufactures); }
474
+ .tracker .marker-set { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--ink); display: grid; grid-template-columns: 1fr auto; gap: 18px; align-items: center; }
475
+ .tracker .marker-set h3 { font-family: var(--ui); font-size: 9.5px; letter-spacing: .22em; text-transform: uppercase; margin: 0 0 4px; font-weight: 700; }
476
+ .tracker .marker-set p { font-family: var(--body); font-size: 10.5px; line-height: 1.4; margin: 0; }
477
+ .tracker .marker-row { display: flex; gap: 12px; }
478
+ .tracker .marker { width: 32px; height: 32px; border: 1.5px solid var(--ink); border-radius: 50%; display: flex; align-items: center; justify-content: center; font-family: var(--ui); font-size: 8.5px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; text-align: center; line-height: 1; padding: 2px; }
479
+ .tracker .marker.credit { background: var(--national-finance); color: #fff; }
480
+ .tracker .marker.resist { background: var(--highlight); color: #fff; }
481
+ .tracker .marker.indust { background: var(--manufactures); color: #fff; }
482
+
483
+ /* ===== PASSED ACTS TRAY ============================================= */
484
+ .passed-acts-tray { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--ink); }
485
+ .passed-acts-tray .tray-head { display: flex; align-items: baseline; gap: 12px; margin-bottom: 6px; }
486
+ .passed-acts-tray .tray-eyebrow { font-family: var(--ui); font-size: 9px; letter-spacing: .26em; text-transform: uppercase; font-weight: 700; color: var(--national-finance); border: 1px solid var(--national-finance); padding: 2px 8px; }
487
+ .passed-acts-tray .tray-title { font-family: var(--display); font-style: italic; font-size: 13px; }
488
+ .passed-acts-tray .tray-row { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
489
+ .passed-acts-tray .tray-slot { border: 1px dashed var(--ink); background: var(--parchment); padding: 8px 4px; text-align: center; height: 56px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; }
490
+ .passed-acts-tray .tray-slot .slot-roman { font-family: var(--display); font-size: 18px; line-height: 1; }
491
+ .passed-acts-tray .tray-slot .slot-name { font-family: var(--ui); font-size: 8px; letter-spacing: .14em; text-transform: uppercase; font-weight: 700; opacity: .8; }
492
+
493
+ /* ===== TREASURY NOTES =============================================== */
494
+ .grid-notes { display: grid; grid-template-columns: repeat(3, 2.625in); grid-template-rows: repeat(7, 1.375in); justify-content: center; gap: 0; position: relative; }
495
+ .note { width: 2.625in; height: 1.375in; background: var(--parchment); color: var(--ink); border: 1.5px solid var(--ink); display: grid; grid-template-columns: 70px 1fr 56px; position: relative; overflow: hidden; font-family: var(--ui); }
496
+ .note::before { content: ""; position: absolute; inset: 3px; border: 0.5px solid var(--rule-soft); pointer-events: none; }
497
+ .note .lh { border-right: 1px solid var(--ink); display: flex; flex-direction: column; align-items: center; justify-content: center; position: relative; }
498
+ .note .lh .denom { font-family: var(--display); font-size: 28px; line-height: 0.9; letter-spacing: -.02em; }
499
+ .note .lh .unit { font-family: var(--ui); font-size: 7.5px; letter-spacing: .26em; text-transform: uppercase; margin-top: 2px; }
500
+ .note .body { padding: 4px 8px; display: grid; grid-template-rows: auto 1fr auto auto; align-items: center; text-align: center; }
501
+ .note .body .brand { font-family: var(--ui); font-size: 7.5px; font-weight: 700; letter-spacing: .32em; text-transform: uppercase; }
502
+ .note .body .title-row { font-family: var(--display); font-size: 11.5px; line-height: 1.1; display: flex; flex-direction: column; align-items: center; gap: 1px; }
503
+ .note .body .title-row .play { font-family: var(--ui); font-style: normal; font-size: 7px; letter-spacing: .24em; text-transform: uppercase; font-weight: 700; border: 0.5px solid var(--ink); padding: 1px 5px; margin-top: 2px; }
504
+ .note .body .disclaimer { font-family: var(--ui); font-size: 6.5px; letter-spacing: .14em; text-transform: uppercase; opacity: .8; }
505
+ .note .body .serial { font-family: var(--mono); font-size: 7px; letter-spacing: .1em; }
506
+ .note .rh { border-left: 1px solid var(--ink); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; padding: 2px; }
507
+ .note .rh .seal { width: 30px; height: 30px; border: 1px solid var(--ink); border-radius: 50%; display: flex; align-items: center; justify-content: center; position: relative; }
508
+ .note .rh .seal::after { content: ""; position: absolute; inset: 2px; border: 0.5px solid var(--rule-soft); border-radius: 50%; }
509
+ .note .rh .seal svg { width: 16px; height: 16px; }
510
+ .note .rh .echo { font-family: var(--display); font-size: 14px; line-height: 1; }
511
+ .note .rh .echo-unit { font-family: var(--ui); font-size: 6px; letter-spacing: .18em; text-transform: uppercase; }
512
+ .note.d-1 { --denom-color: var(--strategic-industry); }
513
+ .note.d-5 { --denom-color: var(--state-debt); }
514
+ .note.d-10 { --denom-color: var(--commercial-infrastructure); }
515
+ .note.d-50 { --denom-color: var(--revenue-system); }
516
+ .note.d-100 { --denom-color: var(--national-finance); }
517
+ .note.d-500 { --denom-color: var(--revolutionary-debt); }
518
+ .note .lh { background: var(--denom-color); color: #fff; }
519
+ .note .rh { background: var(--parchment-2); color: var(--denom-color); }
520
+ .note .rh .seal { border-color: var(--denom-color); }
521
+ .note .rh .seal svg { color: var(--denom-color); }
522
+ .note .body .brand { color: var(--denom-color); }
523
+ .note.d-1 .lh { background-image: linear-gradient(135deg, rgba(255,255,255,.32) 25%, transparent 25%), linear-gradient(225deg, rgba(255,255,255,.32) 25%, transparent 25%); background-size: 8px 8px; }
524
+ .note.d-5 .lh { background-image: repeating-linear-gradient(90deg, rgba(255,255,255,0) 0 3px, rgba(255,255,255,.32) 3px 4px); }
525
+ .note.d-10 .lh { background-image: radial-gradient(circle at 50% 100%, rgba(255,255,255,.32) 1.5px, transparent 2px), radial-gradient(circle at 0% 100%, rgba(255,255,255,.32) 1.5px, transparent 2px), radial-gradient(circle at 100% 100%, rgba(255,255,255,.32) 1.5px, transparent 2px); background-size: 8px 4px; }
526
+ .note.d-50 .lh { background-image: repeating-linear-gradient(45deg, rgba(255,255,255,0) 0 3px, rgba(255,255,255,.32) 3px 4px); }
527
+ .note.d-100 .lh { background-image: radial-gradient(rgba(255,255,255,.42) 0.8px, transparent 1.4px); background-size: 5px 5px; }
528
+ .note.d-500 .lh { background-image: repeating-linear-gradient(0deg, rgba(255,255,255,0) 0 3px, rgba(255,255,255,.32) 3px 4px); }
529
+
530
+ /* ===== UPGRADE / INFLUENCE TOKENS ================================== */
531
+ .grid-upgrade { display: grid; grid-template-columns: repeat(5, 1.25in); grid-template-rows: repeat(5, 1.25in); justify-content: center; gap: 0; position: relative; }
532
+ .tok-up { width: 1.25in; height: 1.25in; background: var(--parchment); color: var(--ink); border: 1.5px solid var(--ink); position: relative; overflow: hidden; display: grid; grid-template-rows: auto 1fr auto; text-align: center; font-family: var(--ui); padding: 4px; }
533
+ .tok-up::before { content: ""; position: absolute; inset: 3px; border: 0.5px solid var(--rule-soft); pointer-events: none; }
534
+ .tok-up .label { font-family: var(--ui); font-size: 7.5px; font-weight: 700; letter-spacing: .26em; text-transform: uppercase; padding-top: 3px; position: relative; z-index: 2; }
535
+ .tok-up .roman { font-family: var(--display); font-size: 44px; line-height: 1; align-self: center; position: relative; z-index: 2; }
536
+ .tok-up .roman .ord { font-family: var(--ui); font-size: 8.5px; font-weight: 700; letter-spacing: .2em; text-transform: uppercase; display: block; margin-top: 2px; }
537
+ .tok-up .brand { font-family: var(--ui); font-size: 5.5px; letter-spacing: .22em; text-transform: uppercase; padding-bottom: 3px; opacity: .8; position: relative; z-index: 2; }
538
+ .tok-up.t1 { border-color: var(--state-debt); } .tok-up.t1 .label, .tok-up.t1 .roman { color: var(--state-debt); }
539
+ .tok-up.t2 { border-color: var(--manufactures); border-width: 2px; } .tok-up.t2 .label, .tok-up.t2 .roman { color: var(--manufactures); }
540
+ .tok-up.t3 { border-color: var(--revolutionary-debt); border-width: 2.5px; } .tok-up.t3 .label, .tok-up.t3 .roman { color: var(--revolutionary-debt); }
541
+
542
+ .grid-influence { display: grid; grid-template-columns: repeat(8, 1in); grid-template-rows: repeat(5, 1in); justify-content: center; gap: 0; position: relative; }
543
+ .tok-inf { width: 1in; height: 1in; background: var(--parchment); color: var(--ink); border: 1.5px solid var(--ink); position: relative; overflow: hidden; display: grid; grid-template-rows: auto auto auto; align-items: center; justify-content: center; text-align: center; padding: 4px; gap: 1px; }
544
+ .tok-inf::before { content: ""; position: absolute; inset: 3px; border: 0.5px solid var(--rule-soft); border-radius: 50%; pointer-events: none; }
545
+ .tok-inf .seal { width: 26px; height: 26px; border: 1px solid var(--ink); border-radius: 50%; display: flex; align-items: center; justify-content: center; background: var(--parchment); margin: 4px auto 0; position: relative; z-index: 2; }
546
+ .tok-inf .seal::after { content: ""; position: absolute; inset: 2px; border: 0.5px solid var(--rule-soft); border-radius: 50%; }
547
+ .tok-inf .seal svg { width: 14px; height: 14px; color: var(--ink); }
548
+ .tok-inf .name { font-family: var(--ui); font-size: 7.5px; font-weight: 700; letter-spacing: .24em; text-transform: uppercase; z-index: 2; }
549
+ .tok-inf .val { font-family: var(--display); font-size: 16px; line-height: 1; margin-top: 2px; z-index: 2; }
550
+ .tok-inf .val .x { font-family: var(--ui); font-size: 6.5px; letter-spacing: .2em; text-transform: uppercase; display: block; margin-top: 1px; font-weight: 700; }
551
+
552
+ /* ===== CARD BACK ==================================================== */
553
+ .cardback { width: 2.5in; height: 3.5in; background: var(--parchment); border: 1.5px solid var(--ink); position: relative; overflow: hidden; display: flex; flex-direction: column; align-items: center; justify-content: space-between; padding: 18px 14px 14px; text-align: center; }
554
+ .cardback::before { content: ""; position: absolute; inset: 6px; border: 1px solid var(--ink); pointer-events: none; }
555
+ .cardback::after { content: ""; position: absolute; inset: 10px; border: 0.5px solid var(--rule-soft); pointer-events: none; }
556
+ .cardback .cb-eyebrow { font-family: var(--ui); font-size: 7px; letter-spacing: .32em; text-transform: uppercase; opacity: .8; z-index: 2; }
557
+ .cardback .cb-head { font-family: var(--ui); font-size: 9px; letter-spacing: .32em; text-transform: uppercase; z-index: 2; margin-top: 2px; }
558
+ .cardback .cb-title { font-family: var(--display); font-size: 28px; line-height: 0.92; margin-top: 4px; z-index: 2; letter-spacing: -.005em; }
559
+ .cardback .cb-seal { width: 84px; height: 84px; margin: 4px auto; z-index: 2; display: flex; align-items: center; justify-content: center; }
560
+ .cardback .cb-seal svg { width: 100%; height: 100%; color: var(--ink); }
561
+ .cardback .cb-sub { font-family: var(--display); font-style: italic; font-size: 10px; line-height: 1.3; padding: 0 6px; z-index: 2; }
562
+ .cardback .cb-foot { font-family: var(--ui); font-size: 6.8px; letter-spacing: .26em; text-transform: uppercase; z-index: 2; }
563
+
564
+ /* Deck-specific back variants — distinct in grayscale via border weight, ornament, layout */
565
+ .cardback.cb-charter::before { border-color: var(--ink); border-width: 1.5px; }
566
+ .cardback.cb-charter .cb-head { color: var(--national-finance); }
567
+ .cardback.cb-charter .cb-title { color: var(--ink); }
568
+ .cardback.cb-charter .corner-orn { position: absolute; width: 14px; height: 14px; border: 1px solid var(--national-finance); z-index: 2; }
569
+ .cardback.cb-charter .corner-orn.tl { top: 14px; left: 14px; border-right: 0; border-bottom: 0; }
570
+ .cardback.cb-charter .corner-orn.tr { top: 14px; right: 14px; border-left: 0; border-bottom: 0; }
571
+ .cardback.cb-charter .corner-orn.bl { bottom: 14px; left: 14px; border-right: 0; border-top: 0; }
572
+ .cardback.cb-charter .corner-orn.br { bottom: 14px; right: 14px; border-left: 0; border-top: 0; }
573
+
574
+ .cardback.cb-shock { background-image: repeating-linear-gradient(135deg, transparent 0 8px, rgba(200,57,46,0.05) 8px 9px); }
575
+ .cardback.cb-shock::before { border-color: var(--highlight); border-width: 1.5px; }
576
+ .cardback.cb-shock .cb-head, .cardback.cb-shock .cb-foot { color: var(--highlight); }
577
+ .cardback.cb-shock .cb-seal svg { color: var(--highlight); }
578
+ .cardback.cb-shock .corner-wedge { position: absolute; top: 0; right: 0; width: 22px; height: 22px; background: var(--highlight); clip-path: polygon(100% 0, 100% 100%, 0 0); z-index: 3; }
579
+ .cardback.cb-shock .corner-wedge.bl { top: auto; right: auto; bottom: 0; left: 0; clip-path: polygon(0 0, 0 100%, 100% 100%); }
580
+
581
+ .cardback.cb-debate { background-image: repeating-linear-gradient(90deg, transparent 0 6px, rgba(31,45,82,0.04) 6px 7px); }
582
+ .cardback.cb-debate::before { border-color: var(--national-finance); border-width: 1.5px; }
583
+ .cardback.cb-debate .cb-head, .cardback.cb-debate .cb-foot { color: var(--national-finance); }
584
+ .cardback.cb-debate .cb-seal svg { color: var(--national-finance); }
585
+ .cardback.cb-debate .asterism { font-family: var(--display); color: var(--national-finance); letter-spacing: .4em; font-size: 10px; z-index: 2; }
586
+ .cardback.cb-debate .corner-diamond { position: absolute; width: 14px; height: 14px; border: 1px solid var(--national-finance); z-index: 2; background: linear-gradient(45deg, transparent 46%, var(--national-finance) 46% 54%, transparent 54%), linear-gradient(-45deg, transparent 46%, var(--national-finance) 46% 54%, transparent 54%); }
587
+ .cardback.cb-debate .corner-diamond.tl { top: 14px; left: 14px; }
588
+ .cardback.cb-debate .corner-diamond.tr { top: 14px; right: 14px; }
589
+ .cardback.cb-debate .corner-diamond.bl { bottom: 14px; left: 14px; }
590
+ .cardback.cb-debate .corner-diamond.br { bottom: 14px; right: 14px; }
591
+
592
+ .cardback.cb-act { background:
593
+ radial-gradient(ellipse at center, transparent 55%, rgba(26,22,18,0.04) 100%),
594
+ var(--parchment); }
595
+ .cardback.cb-act::before { border-width: 2.5px; }
596
+ .cardback.cb-act::after { inset: 14px; border-width: 1px; }
597
+ .cardback.cb-act .cb-head { color: var(--ink); font-weight: 700; }
598
+ .cardback.cb-act .cb-seal { width: 96px; height: 96px; }
599
+ .cardback.cb-act .ribbon { position: absolute; top: 6px; left: 50%; transform: translateX(-50%); padding: 2px 14px; background: var(--ink); color: var(--parchment); font-family: var(--ui); font-size: 7px; letter-spacing: .26em; text-transform: uppercase; z-index: 3; }
600
+
601
+ .cardback.cb-role { background-image:
602
+ linear-gradient(180deg, var(--parchment-2) 0%, var(--parchment-2) 48%, var(--parchment) 48%, var(--parchment) 100%); }
603
+ .cardback.cb-role::before { border-color: var(--national-finance); border-width: 1.5px; }
604
+ .cardback.cb-role .cb-head { color: var(--national-finance); }
605
+ .cardback.cb-role .cb-title { color: var(--national-finance); }
606
+ .cardback.cb-role .portrait-frame { width: 80px; height: 80px; border: 1.5px solid var(--national-finance); border-radius: 50%; background: var(--parchment); display: flex; align-items: center; justify-content: center; position: relative; margin: 4px auto; z-index: 2; }
607
+ .cardback.cb-role .portrait-frame::after { content: ""; position: absolute; inset: 4px; border: 0.5px solid var(--rule-soft); border-radius: 50%; }
608
+ .cardback.cb-role .portrait-frame svg { width: 38px; height: 38px; color: var(--national-finance); }
609
+ .cardback.cb-role .silhouette { width: 32px; height: 32px; border-radius: 50%; background: var(--national-finance); position: relative; }
610
+ .cardback.cb-role .silhouette::after { content: ""; position: absolute; bottom: -10px; left: 50%; transform: translateX(-50%); width: 48px; height: 24px; background: var(--national-finance); border-radius: 24px 24px 0 0; }
611
+
612
+ /* ===== DIGITAL REVIEW MODE (screen-only) ============================ */
613
+ .digital-nav {
614
+ width: 8.5in; max-width: 100%;
615
+ background: var(--parchment);
616
+ border: 1.5px solid var(--ink);
617
+ padding: 18px 22px 16px;
618
+ margin-bottom: 4px;
619
+ font-family: var(--ui);
620
+ box-shadow: 0 10px 40px rgba(0,0,0,.45);
621
+ position: relative;
622
+ }
623
+ .digital-nav::before { content: ""; position: absolute; inset: 6px; border: 0.5px solid var(--rule-soft); pointer-events: none; }
624
+ .digital-nav .dn-head { border-bottom: 1px solid var(--ink); padding-bottom: 8px; margin-bottom: 12px; text-align: left; }
625
+ .digital-nav .dn-eyebrow { font-family: var(--ui); font-size: 9px; letter-spacing: .32em; text-transform: uppercase; color: var(--national-finance); }
626
+ .digital-nav .dn-title { font-family: var(--display); font-size: 32px; line-height: 1; letter-spacing: -.01em; margin-top: 4px; }
627
+ .digital-nav .dn-sub { font-family: var(--display); font-style: italic; font-size: 13px; margin-top: 2px; }
628
+ .digital-nav .dn-links { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
629
+ .digital-nav .dn-links a {
630
+ display: flex; flex-direction: column;
631
+ border: 1px solid var(--ink);
632
+ background: var(--parchment-2);
633
+ padding: 8px 10px;
634
+ text-decoration: none; color: var(--ink);
635
+ transition: background 80ms ease;
636
+ }
637
+ .digital-nav .dn-links a:hover { background: var(--ink); color: var(--parchment); }
638
+ .digital-nav .dn-links a:hover .dn-sheets { color: var(--parchment-2); }
639
+ .digital-nav .dn-label { font-family: var(--ui); font-weight: 700; font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; }
640
+ .digital-nav .dn-sheets { font-family: var(--mono); font-size: 9px; letter-spacing: .08em; opacity: .75; margin-top: 2px; }
641
+ .digital-nav .dn-foot { margin-top: 10px; padding-top: 6px; border-top: 0.5px solid var(--rule-soft); display: flex; justify-content: space-between; font-family: var(--ui); font-size: 9px; letter-spacing: .14em; text-transform: uppercase; opacity: .7; }
642
+
643
+ @media print { .digital-nav { display: none !important; } }
644
+
645
+ /* ===== COVER LOCKUP ================================================= */
646
+ .cover-lockup { margin-bottom: 6px; }
647
+ .cover-eyebrow { font-family: var(--ui); font-size: 11px; letter-spacing: .32em; text-transform: uppercase; color: var(--national-finance); margin-bottom: 4px; }
648
+ .cover-tag { font-family: var(--display); font-size: 16px; line-height: 1.35; margin-top: 6px; }
649
+ .cover-tag em { font-style: italic; }
650
+
651
+ /* ===== COVER + RULES + PRIMER ====================================== */
652
+ .cover-title { font-family: var(--display); font-size: 72px; line-height: 0.95; letter-spacing: -.01em; margin: 0 0 6px; }
653
+ .cover-sub { font-family: var(--display); font-style: italic; font-size: 16px; line-height: 1.4; max-width: 66ch; margin: 0 0 18px; }
654
+ .cover-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; }
655
+ .cover-cols h3 { font-family: var(--ui); font-size: 11px; font-weight: 700; letter-spacing: .18em; text-transform: uppercase; margin: 0 0 6px; }
656
+ .cover-cols ul, .cover-cols ol { padding-left: 18px; margin: 0 0 8px; }
657
+ .cover-cols li { font-family: var(--body); font-size: 11.5px; line-height: 1.5; }
658
+ .contents { border: 1px solid var(--ink); padding: 12px; background: var(--parchment-2); margin-top: 14px; }
659
+ .contents table { width: 100%; border-collapse: collapse; }
660
+ .contents td { padding: 3px 8px; font-family: var(--body); font-size: 10px; line-height: 1.3; border-bottom: 0.5px solid var(--rule-soft); }
661
+ .contents td:first-child { font-family: var(--ui); font-weight: 700; letter-spacing: .12em; text-transform: uppercase; font-size: 9px; width: 100px; }
662
+ .contents td:last-child { text-align: right; font-family: var(--mono); font-size: 9.5px; width: 110px; }
663
+
664
+ .rules-header .rh-eyebrow { font-family: var(--ui); font-size: 10px; letter-spacing: .32em; text-transform: uppercase; color: var(--national-finance); margin-bottom: 4px; display: block; }
665
+ .rules-header h1 { font-family: var(--display); font-size: 38px; margin: 0 0 2px; line-height: 1; letter-spacing: -.01em; }
666
+ .rules-header .rh-system { font-family: var(--ui); font-size: 10px; letter-spacing: .26em; text-transform: uppercase; margin-bottom: 4px; display: block; }
667
+ .rules-header .rh-tag { font-family: var(--display); font-style: italic; font-size: 13px; line-height: 1.35; margin: 0 0 4px; display: block; max-width: 60ch; }
668
+ .rules-header .rh-sub { font-family: var(--display); font-style: italic; font-size: 14px; margin-bottom: 14px; display: block; }
669
+ .rules-cols { columns: 2; column-gap: 24px; column-rule: 0.5px solid var(--rule-soft); }
670
+ .rules-cols section { break-inside: avoid; margin-bottom: 12px; }
671
+ .rules-cols h3 { font-family: var(--ui); font-size: 9.5px; font-weight: 700; letter-spacing: .22em; text-transform: uppercase; color: var(--national-finance); margin: 0 0 4px; border-bottom: 0.5px solid var(--ink); padding-bottom: 2px; }
672
+ .rules-cols h3 .num { font-family: var(--mono); font-size: 9px; margin-right: 8px; opacity: .8; }
673
+ .rules-cols p, .rules-cols ul, .rules-cols ol { font-family: var(--body); font-size: 10.5px; line-height: 1.45; margin: 0 0 4px; }
674
+ .rules-cols ul, .rules-cols ol { padding-left: 16px; }
675
+ .rules-cols li { margin-bottom: 2px; }
676
+ .rules-cols strong { font-family: var(--display); font-weight: 700; }
677
+ .rules-cols .callout { border-left: 2px solid var(--highlight); padding: 4px 8px; background: rgba(200,57,46,0.05); font-size: 10px; }
678
+ .rules-cols .callout strong { color: var(--highlight); }
679
+
680
+ .primer-header .ph-eyebrow { font-family: var(--ui); font-size: 10px; letter-spacing: .32em; text-transform: uppercase; color: var(--national-finance); margin-bottom: 4px; display: block; }
681
+ .primer-header h1 { font-family: var(--display); font-size: 42px; margin: 0 0 2px; line-height: 1; letter-spacing: -.01em; }
682
+ .primer-header .ph-system { font-family: var(--ui); font-size: 10px; letter-spacing: .26em; text-transform: uppercase; margin-bottom: 4px; display: block; }
683
+ .primer-header .ph-tag { font-family: var(--display); font-style: italic; font-size: 13px; line-height: 1.35; margin: 0 0 6px; display: block; max-width: 60ch; }
684
+ .primer-header .ph-sub { font-family: var(--display); font-style: italic; font-size: 14px; margin-bottom: 14px; display: block; }
685
+ .primer-body { columns: 2; column-gap: 26px; column-rule: 0.5px solid var(--rule-soft); }
686
+ .primer-body p { font-family: var(--body); font-size: 11.5px; line-height: 1.5; margin: 0 0 8px; text-indent: 0; }
687
+ .primer-body p:first-of-type::first-letter { font-family: var(--display); font-size: 42px; float: left; line-height: 0.9; margin: 4px 6px 0 0; color: var(--national-finance); }
688
+ .primer-body h3 { font-family: var(--ui); font-size: 10px; font-weight: 700; letter-spacing: .22em; text-transform: uppercase; color: var(--revolutionary-debt); margin: 4px 0 4px; break-after: avoid; }
689
+ .primer-pillars { margin-top: 12px; display: grid; grid-template-columns: repeat(2, 1fr); gap: 6px 12px; break-inside: avoid; }
690
+ .primer-pillars .pillar { display: grid; grid-template-columns: 22px 1fr; gap: 8px; align-items: start; }
691
+ .primer-pillars svg { width: 18px; height: 18px; color: var(--ink); margin-top: 1px; }
692
+ .primer-pillars .pillar .nm { font-family: var(--display); font-weight: 700; font-size: 11px; line-height: 1.1; }
693
+ .primer-pillars .pillar .dc { font-family: var(--body); font-size: 9.5px; line-height: 1.3; }
694
+ .primer-foot { margin-top: 14px; padding-top: 10px; border-top: 1px solid var(--ink); font-family: var(--ui); font-size: 9.5px; letter-spacing: .12em; text-transform: uppercase; display: flex; justify-content: space-between; }
695
+
696
+ .legend-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 6px; margin-top: 6px; }
697
+ .legend-row { display: grid; grid-template-columns: 18px 18px 1fr; align-items: center; gap: 8px; font-family: var(--ui); font-size: 9.5px; letter-spacing: .04em; }
698
+ .legend-row .sw { width: 14px; height: 14px; border: 1px solid var(--ink); }
699
+ .legend-row .ic svg { width: 16px; height: 16px; }
700
+ </style>
701
+ </head>
702
+ <body>
703
+
704
+ <svg aria-hidden="true" style="position:absolute;width:0;height:0;overflow:hidden" xmlns="http://www.w3.org/2000/svg"><defs>
705
+ <symbol id="icon-debt-certificate" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 3h11l3 3v15H5z"/><path d="M16 3v3h3"/><line x1="7.5" y1="9" x2="14.5" y2="9"/><line x1="7.5" y1="11.5" x2="16" y2="11.5"/><line x1="7.5" y1="14" x2="13" y2="14"/><circle cx="16.5" cy="17.5" r="2.2" fill="currentColor" stroke="none"/><path d="M15.2 19.4l-1 2.4M17.8 19.4l1 2.4"/></symbol>
706
+ <symbol id="icon-state-ledger" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 5.5c3-1 6-1 9 .5 3-1.5 6-1.5 9-.5v13c-3-1-6-1-9 .5-3-1.5-6-1.5-9-.5z"/><line x1="12" y1="6" x2="12" y2="19"/><line x1="6" y1="9" x2="10" y2="9"/><line x1="6" y1="12" x2="10" y2="12"/><line x1="6" y1="15" x2="10" y2="15"/><line x1="14" y1="9" x2="18" y2="9"/><line x1="14" y1="12" x2="18" y2="12"/><line x1="14" y1="15" x2="18" y2="15"/></symbol>
707
+ <symbol id="icon-customs-house" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><line x1="12" y1="2.5" x2="12" y2="5"/><path d="M12 2.5l3 1.2-3 1.2z" fill="currentColor"/><path d="M3.5 9L12 5.5 20.5 9"/><line x1="3" y1="9.5" x2="21" y2="9.5"/><line x1="6" y1="10" x2="6" y2="17"/><line x1="9.5" y1="10" x2="9.5" y2="17"/><line x1="14.5" y1="10" x2="14.5" y2="17"/><line x1="18" y1="10" x2="18" y2="17"/><line x1="3" y1="17.5" x2="21" y2="17.5"/><line x1="2.5" y1="20.5" x2="21.5" y2="20.5"/></symbol>
708
+ <symbol id="icon-harbor" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="5.5" r="1.7"/><line x1="12" y1="7.2" x2="12" y2="17"/><line x1="9.5" y1="9" x2="14.5" y2="9"/><path d="M6 14c0 3.3 2.7 5 6 5s6-1.7 6-5"/><line x1="6" y1="14" x2="4.5" y2="14"/><line x1="18" y1="14" x2="19.5" y2="14"/><path d="M2.5 21c1.2-.8 2.4-.8 3.6 0s2.4.8 3.6 0 2.4-.8 3.6 0 2.4.8 3.6 0 2.4-.8 3.6 0"/></symbol>
709
+ <symbol id="icon-bank" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 8L12 3.5 21 8"/><line x1="3" y1="8.5" x2="21" y2="8.5"/><line x1="5.5" y1="9" x2="5.5" y2="17"/><line x1="9" y1="9" x2="9" y2="17"/><line x1="15" y1="9" x2="15" y2="17"/><line x1="18.5" y1="9" x2="18.5" y2="17"/><line x1="3" y1="17.5" x2="21" y2="17.5"/><line x1="2" y1="20.5" x2="22" y2="20.5"/><circle cx="12" cy="13" r="2.2"/><line x1="12" y1="11.2" x2="12" y2="14.8"/></symbol>
710
+ <symbol id="icon-route" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19 Q8 11 12 11 T20 5"/><line x1="6.2" y1="15.5" x2="7.6" y2="13.5"/><line x1="10" y1="11.3" x2="12" y2="11"/><line x1="15" y1="9" x2="17" y2="7.5"/><path d="M3 21c1.2-.6 2.4-.6 3.6 0s2.4.6 3.6 0 2.4-.6 3.6 0 2.4.6 3.6 0 2.4-.6 3.6 0"/><rect x="18.5" y="2.5" width="3" height="4"/><line x1="20" y1="6.5" x2="20" y2="8"/></symbol>
711
+ <symbol id="icon-manufactory" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 20V11l5 3V11l5 3V8h3l1-4h1l1 4v12z"/><line x1="3" y1="20.2" x2="21" y2="20.2"/><rect x="5" y="15.5" width="1.5" height="2.5"/><rect x="10" y="15.5" width="1.5" height="2.5"/><rect x="15" y="14" width="1.5" height="2.5"/><rect x="15" y="18" width="1.5" height="2"/></symbol>
712
+ <symbol id="icon-armory-shipyard" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 4h14v8c0 5-4 8-7 9-3-1-7-4-7-9z"/><line x1="7.5" y1="7" x2="16.5" y2="16"/><line x1="16.5" y1="7" x2="7.5" y2="16"/><circle cx="12" cy="11.5" r="0.8" fill="currentColor"/></symbol>
713
+ <symbol id="icon-market-shock" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16"/><line x1="3" y1="16" x2="21" y2="16"/><polyline points="4.5,14 7,12 9,15 11,8 13,17 15,5 17,13 19.5,11"/><polyline points="13,2 11,7 14,7 12,12" fill="currentColor" stroke="none"/></symbol>
714
+ <symbol id="icon-republic-debate" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 8h6l-1 11H4z"/><path d="M21 8h-6l1 11h4z"/><line x1="9" y1="11.5" x2="15" y2="11.5"/><circle cx="6" cy="5" r="1.6"/><circle cx="18" cy="5" r="1.6"/><line x1="6" y1="6.6" x2="6" y2="8"/><line x1="18" y1="6.6" x2="18" y2="8"/></symbol>
715
+ <symbol id="icon-act-of-congress" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 4h12a2 2 0 0 1 2 2v0a2 2 0 0 1-2 2H7"/><path d="M7 8v10a2 2 0 0 1-2 2v0a2 2 0 0 1-2-2v-2h4"/><path d="M17 4a2 2 0 0 1 2 2v14H7"/><line x1="9.5" y1="11.5" x2="16" y2="11.5"/><line x1="9.5" y1="14" x2="14" y2="14"/><circle cx="17" cy="17" r="1.5" fill="currentColor" stroke="none"/><path d="M16 18.2l-.6 2.4M18 18.2l.6 2.4"/></symbol>
716
+ <symbol id="icon-treasury-start" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 5v14M9 8h4.5a2 2 0 0 1 0 4H9M9 12h4.5a2 2 0 0 1 0 4H9"/></symbol>
717
+ <symbol id="icon-crisis" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 5l6 6-6 6"/><path d="M19 5l-6 6 6 6"/><line x1="3" y1="12" x2="6" y2="12"/><line x1="18" y1="12" x2="21" y2="12"/></symbol>
718
+ <symbol id="icon-dividend" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="6.5"/><path d="M5 17c2 1.5 4.5 2 7 2s5-.5 7-2"/><path d="M5 7c2-1.5 4.5-2 7-2s5 .5 7 2"/><line x1="12" y1="9.2" x2="12" y2="14.8"/><line x1="9.8" y1="12" x2="14.2" y2="12"/></symbol>
719
+ <symbol id="icon-send-crisis" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M19 5 L9 15"/><path d="M9 15 L5 19"/><polygon points="4,20 9,15 9,20" fill="currentColor" stroke="none"/><circle cx="19" cy="5" r="2" fill="currentColor" stroke="none"/></symbol>
720
+ <symbol id="icon-influence" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3l2.4 5.6L20 9.5l-4 4 1 5.7L12 16.5 7 19.2l1-5.7-4-4 5.6-.9z"/></symbol>
721
+ <symbol id="seal-mark" viewBox="0 0 200 200" fill="none" stroke="currentColor" stroke-width="1" stroke-linecap="round" stroke-linejoin="round"><circle cx="100" cy="100" r="92"/><circle cx="100" cy="100" r="85"/><circle cx="100" cy="100" r="62"/><g transform="translate(100 100)"><line x1="0" y1="-38" x2="0" y2="18"/><line x1="-30" y1="-30" x2="30" y2="-30"/><path d="M-40 -22 L-20 -22 L-30 -8 Z"/><path d="M20 -22 L40 -22 L30 -8 Z"/><path d="M-10 18 H10 V24 H-10 Z" fill="currentColor" stroke="none"/></g></symbol>
722
+ </defs></svg>
723
+
724
+ <div class="toolbar"><button onclick="window.print()">Print / Save PDF</button></div>
725
+
726
+ <div class="viewport" id="viewport">
727
+ <!-- All sheets are inserted by script.js below. -->
728
+ </div>
729
+
730
+ <script id="content-script">
731
+ window.__RULES_1 = `
732
+ <div class="rules-header">
733
+ <span class="rh-eyebrow">Sovereign</span>
734
+ <h1>Rules of Play</h1>
735
+ <span class="rh-system">The Hamilton System Board Game</span>
736
+ <span class="rh-tag"><em>Founding Credit: Fund the debt. Build the bank. Industrialize the republic.</em></span>
737
+ <span class="rh-sub">A Hamiltonian economic strategy game · v 1 · 3 – 4 players</span>
738
+ </div>
739
+ <div class="rules-cols">
740
+
741
+ <section>
742
+ <h3><span class="num">01</span>The Premise</h3>
743
+ <p>It is the early 1790s. The federal Treasury has just opened. Players act as financiers, brokers, and industrialists racing to plant their flag in the new national economy — and to take credit for building it. The player with the most <strong>Influence</strong> at game end wins.</p>
744
+ </section>
745
+
746
+ <section>
747
+ <h3><span class="num">02</span>Setup</h3>
748
+ <ul>
749
+ <li>Assemble the 17 × 17 in board from the four tiled sheets.</li>
750
+ <li>Each player picks a <strong>Role</strong> card and takes <strong>1 500 TN</strong>.</li>
751
+ <li>Place track markers: Credit at <strong>5</strong>, Resistance at <strong>2</strong>, Industrial Capacity at <strong>1</strong>.</li>
752
+ <li>Shuffle the Market Shock and Republic Debate decks; place face-down beside the board.</li>
753
+ <li>Stack the seven <strong>Acts of Congress</strong> face-down in lap order, Funding Act on top.</li>
754
+ <li>All players begin on <strong>Treasury Opens</strong>.</li>
755
+ </ul>
756
+ </section>
757
+
758
+ <section>
759
+ <h3><span class="num">03</span>A Turn</h3>
760
+ <ol>
761
+ <li>Roll two dice and move clockwise that many spaces.</li>
762
+ <li>Resolve the space you land on (see right).</li>
763
+ <li>Pay any obligations that come due, then end the turn.</li>
764
+ </ol>
765
+ <p>Passing <strong>Treasury Opens</strong>: collect <strong>200 TN</strong>. Landing exactly on Treasury Opens: collect <strong>400 TN</strong>.</p>
766
+ </section>
767
+
768
+ <section>
769
+ <h3><span class="num">04</span>Buying Property</h3>
770
+ <p>Land on an unowned Property, Route, or Institution: you may buy it from the bank at the printed Cost. If you decline, the asset is <strong>auctioned</strong>.</p>
771
+ <p>An auction opens at <strong>10 TN</strong>; all players (including the active player) may bid in any increment. Highest bid pays the bank and takes the card. If no one bids, the asset remains unowned.</p>
772
+ </section>
773
+
774
+ <section>
775
+ <h3><span class="num">05</span>Payments</h3>
776
+ <p>When an opponent lands on your Property, they pay you the printed amount. The card's payment table is canonical:</p>
777
+ <ul>
778
+ <li><strong>Base</strong> — the standard payment.</li>
779
+ <li><strong>Full Set</strong> — once you own every property of a color/system, the payment <strong>doubles</strong>.</li>
780
+ <li><strong>Tier I</strong> = <strong>5 ×</strong> base · <strong>Tier II</strong> = <strong>15 ×</strong> · <strong>Tier III</strong> = <strong>30 ×</strong> base.</li>
781
+ </ul>
782
+ <p>Upgrades may only be built on properties in a full set you own. Each upgrade costs the card's Upgrade value.</p>
783
+ <p>Routes pay by the number of routes you own: <strong>25 · 50 · 100 · 200 TN</strong> for 1 / 2 / 3 / 4 routes. Routes pay when an opponent <em>lands on the route</em>; the payment scales with the number of routes the owner currently holds.</p>
784
+ <p>Institutions pay by dice roll — see each institution's card for its multiplier and any condition (e.g. Bank Charter).</p>
785
+ </section>
786
+
787
+ <section>
788
+ <h3><span class="num">06</span>Mortgages</h3>
789
+ <p>If a Property card prints a Mortgage value, you may mortgage that property: collect the mortgage value from the bank. The property pays nothing while mortgaged. To unmortgage, pay the mortgage value <strong>+ 10 %</strong>. Routes and Institutions have no mortgage in v1.</p>
790
+ </section>
791
+
792
+ <section>
793
+ <h3><span class="num">07</span>Corner Spaces</h3>
794
+ <ul>
795
+ <li><strong>Treasury Opens</strong> — start space. See §03.</li>
796
+ <li><strong>Constitutional Crisis</strong> — politically blocked. To leave: pay <strong>50 TN</strong> at start of turn · roll doubles · or skip one full turn and leave on the following turn.</li>
797
+ <li><strong>National Dividend</strong> — safe space. No payment in v1.</li>
798
+ <li><strong>Go to Crisis</strong> — move directly to Constitutional Crisis.</li>
799
+ </ul>
800
+ </section>
801
+
802
+ <section>
803
+ <h3><span class="num">07a</span>Tax Spaces</h3>
804
+ <p>Tax spaces: pay the amount shown to the bank. <strong>Federal Excise</strong> costs 200 TN. <strong>Speculation Scandal</strong> costs 100 TN <em>and</em> moves Public Resistance <strong>+1</strong>.</p>
805
+ </section>
806
+
807
+ <section>
808
+ <h3><span class="num">08</span>Event Spaces</h3>
809
+ <p>Landing on <strong>Market Shock</strong> or <strong>Republic Debate</strong>: draw the top card of the matching deck, read it aloud, and resolve. Discard face-up unless the card says "Keep."</p>
810
+ </section>
811
+
812
+ <section>
813
+ <h3><span class="num">09</span>Acts of Congress</h3>
814
+ <p>At the start of each lap, reveal the top Act of Congress card and call a vote. <strong>All players vote.</strong> Majority <strong>passes</strong>. Ties <strong>fail</strong>. Resolve the Act's effect if it passes; otherwise place it on the bottom of the Act sequence — the same Act will re-trigger one lap later.</p>
815
+ <p><strong>Passed Acts are placed face-up beside the Track Board.</strong> Their effects remain in force until game end.</p>
816
+ <div class="callout"><strong>Bank Charter</strong> (Lap III) is the decisive Act: Bank of the United States payments rise from 4 × dice to 10 × dice, and the Mint can compound to 20 × dice when the same player owns both Institutions.</div>
817
+ </section>
818
+
819
+ <section>
820
+ <h3><span class="num">10</span>Shared Tracks</h3>
821
+ <p>The three tracks affect every player at the table. Move the marker by ± steps as cards and Acts direct. Caps at <strong>12</strong>; further increases ignored.</p>
822
+ <ul>
823
+ <li><strong>Public Credit</strong> (starts 5). If Credit ≤ 2, foreign loans fail; routes pay half. <strong>Default</strong> fires at 0: every player loses 50 % cash + 1 random upgrade. Credit resets to 3.</li>
824
+ <li><strong>Public Resistance</strong> (starts 2). At 8, the Whiskey Rebellion card becomes live. <strong>Rebellion</strong> fires at 12: all Revenue System upgrades destroyed, Whiskey Excise owner goes to Crisis, Resistance resets to 6.</li>
825
+ <li><strong>Industrial Capacity</strong> (starts 1). At ≥ 6, Manufactures and Strategic payments +25 %. At ≥ 8, those owners gain bonus Influence at game end.</li>
826
+ </ul>
827
+ </section>
828
+
829
+ <section style="break-inside:avoid;padding:8px 12px;border:1px dashed var(--ink);background:rgba(26,22,18,0.03);font-size:9.5px;font-family:var(--ui);letter-spacing:.04em"><strong style="font-family:var(--display)">v0.2 balance candidate</strong> &mdash; route ladder, Coinage Act, Industrial Capacity thresholds, and Revolutionary Debt bases adjusted after corrected economy audit FC-EM-002. Sheet count, mechanics, prices, role abilities, card backs, and visual system preserved from v0.1.</section>
830
+
831
+ </div>`;
832
+
833
+ window.__RULES_2 = `
834
+ <div class="rules-header">
835
+ <span class="rh-eyebrow">Sovereign</span>
836
+ <h1>Rules of Play · 2 / 2</h1>
837
+ <span class="rh-system">The Hamilton System Board Game</span>
838
+ <span class="rh-tag"><em>Founding Credit: Fund the debt. Build the bank. Industrialize the republic.</em></span>
839
+ <span class="rh-sub">Influence scoring, end-of-game procedure, tiebreakers</span>
840
+ </div>
841
+ <div class="rules-cols">
842
+
843
+ <section>
844
+ <h3><span class="num">11</span>Game End</h3>
845
+ <p>The game lasts <strong>7 laps</strong>. After every player has completed lap 7, finish the round so each player has had an equal number of turns. Then score Influence.</p>
846
+ </section>
847
+
848
+ <section>
849
+ <h3><span class="num">12</span>Influence Scoring</h3>
850
+ <p>Total every player's Influence Points from the following sources. Highest score wins.</p>
851
+ <ul>
852
+ <li><strong>+1 Influence</strong> per <strong>200 TN</strong> cash held (round down).</li>
853
+ <li><strong>+1 Influence</strong> per property owned.</li>
854
+ <li><strong>+2 Influence</strong> per <em>upgraded</em> property (any tier).</li>
855
+ <li><strong>+3 Influence</strong> per complete color/system set.</li>
856
+ <li><strong>+1 Influence</strong> per <em>route</em> owned.</li>
857
+ <li><strong>+2 Influence</strong> per <em>institution</em> owned.</li>
858
+ <li><strong>+1 Influence</strong> for each "You Are Hamilton" card kept.</li>
859
+ <li><strong>− 1 Influence</strong> per lap spent <em>bankrupt</em> (zero cash at start of lap).</li>
860
+ </ul>
861
+ </section>
862
+
863
+ <section>
864
+ <h3><span class="num">13</span>End-Game Bonuses</h3>
865
+ <ul>
866
+ <li>If <strong>Public Credit ≥ 8</strong> at game end, each player who owns at least one <strong>National Finance</strong> property gains <strong>⌊ 5 / N ⌋ Influence</strong>, where <em>N</em> is the number of players who own at least one National Finance property (round down each share).</li>
867
+ <li>If <strong>Industrial Capacity ≥ 8</strong>, each Manufactures and Strategic Industry owner gains <strong>+ 2 Influence</strong>.</li>
868
+ </ul>
869
+ </section>
870
+
871
+ <section>
872
+ <h3><span class="num">14</span>Tiebreakers</h3>
873
+ <p>If two or more players tie on total Influence, the tie is broken by strongest contribution to <strong>Public Credit</strong>, in this order:</p>
874
+ <ol>
875
+ <li>Number of times the <strong>Treasury Architect</strong> ability raised Credit during the game.</li>
876
+ <li>Number of times the player voted <em>in favor</em> of the <strong>Funding</strong> or <strong>Assumption</strong> Acts.</li>
877
+ <li>Coin flip.</li>
878
+ </ol>
879
+ </section>
880
+
881
+ <section>
882
+ <h3><span class="num">15</span>Rebellion &amp; Default</h3>
883
+ <p>These two large events are how the game punishes runaway tracks.</p>
884
+ <ul>
885
+ <li><strong>Default</strong> (Credit = 0): every player loses 50 % cash (round down) and 1 random upgrade chosen by die. Credit resets to 3.</li>
886
+ <li><strong>Rebellion</strong> (Resistance = 12): all Revenue System upgrades destroyed; Whiskey Excise owner moves to Constitutional Crisis; Resistance resets to 6.</li>
887
+ </ul>
888
+ <p><strong>Precedence.</strong> If Default fires on a player with no upgrades, the cash penalty applies alone. If a player would be bankrupted by Default, resolve Default first, then bankruptcy.</p>
889
+ <div class="callout"><strong>Design note.</strong> Defaults and Rebellions are public catastrophes. Industrial Capacity is the only track without a punitive trigger — it is pure reward.</div>
890
+ </section>
891
+
892
+ <section>
893
+ <h3><span class="num">16</span>Trading</h3>
894
+ <p>Players may negotiate trades at any time when it is not someone else's roll. A trade may include cash, properties (un-mortgaged or mortgaged), Influence Points already earned, and "kept" event cards. Mortgaged properties transfer with their mortgage liability; the new owner must unmortgage by paying mortgage + 10 %.</p>
895
+ </section>
896
+ <section>
897
+ <h3><span class="num">17</span>Bankruptcy</h3>
898
+ <p>If you cannot pay an obligation, you may mortgage properties, sell upgrades back to the bank at half their cost, or accept Crisis. If you still cannot pay, you are <strong>bankrupt</strong> — your assets return to the bank, you lose all upgrades, and you continue playing with 0 TN until you collect another 200 TN at Treasury Opens. Each <em>lap</em> you remain bankrupt costs <strong>− 1 Influence</strong> at scoring.</p>
899
+ </section>
900
+
901
+ <section>
902
+ <h3><span class="num">18</span>What Wins</h3>
903
+ <p>In playtest, winning lines run through <strong>full sets early</strong>, <strong>Bank Charter</strong> (and the Mint stack), and a Credit reading of <strong>8 or above</strong> at game end. Hoarding cash without owning property is a losing strategy: at 200 TN per Influence, cash converts at the worst exchange rate on the board.</p>
904
+ </section>
905
+
906
+ </div>`;
907
+
908
+ window.__PRIMER = `
909
+ <div class="primer-header">
910
+ <span class="ph-eyebrow">Sovereign</span>
911
+ <h1>Hamilton's System</h1>
912
+ <span class="ph-system">The Hamilton System Board Game</span>
913
+ <span class="ph-tag"><em>Founding Credit: Fund the debt. Build the bank. Industrialize the republic.</em></span>
914
+ <span class="ph-sub">A historical primer · the system Hamilton actually built</span>
915
+ </div>
916
+ <div class="primer-body">
917
+ <p>In 1789 the United States owed more than $54 million it could not pay. Continental Congress had printed paper money to fund the Revolution; the new Constitution had given the federal government taxing authority but no working revenue system; thirteen states each carried their own war debts on terms ranging from generous to ruinous. Foreign lenders treated American securities as scrap. A single sentence circulated in London counting-houses: <em>"the American funds are not worth a continental."</em></p>
918
+
919
+ <p>Alexander Hamilton was thirty-four when George Washington made him the first Secretary of the Treasury. He had two years to invent a federal economy from scratch, and he did it in six interlocking reports.</p>
920
+
921
+ <h3>Six Reports, One Machine</h3>
922
+ <p>The <strong>First Report on the Public Credit</strong> (1790) proposed that the federal government honor every continental certificate at full face value — and <em>assume</em> the war debts of each state. Pay them at par, fund them with steady federal revenue, and the dead paper would become live, traded collateral. Speculators bought the certificates from desperate farmers; reformers cried foul; the bill passed anyway, in the famous compromise that moved the capital to the Potomac.</p>
923
+
924
+ <p>The <strong>Second Report</strong> proposed a <strong>Bank of the United States</strong> — federally chartered, partly federally owned, but operated like a commercial bank. It would hold Treasury deposits, discount merchant bills, and issue banknotes redeemable in specie. Jefferson and Madison argued the Constitution did not authorize it. Hamilton wrote the doctrine of <em>implied powers</em> in reply. Washington signed the charter in 1791. Subscriptions sold out within hours.</p>
925
+
926
+ <p>The <strong>Tariff and Excise schedules</strong> filled the federal coffers. A duty on every imported barrel, every yard of British cloth, every cask of West India rum. An excise on domestic distilled spirits — which provoked the Whiskey Rebellion in western Pennsylvania, the first serious test of federal enforcement. Hamilton himself rode west with the militia.</p>
927
+
928
+ <p>The <strong>Coinage Act</strong> of 1792 founded the U.S. Mint and ended a chaotic situation in which Spanish dollars, Mexican reales, and clipped foreign silver all circulated at uncertain rates. The <strong>Report on Manufactures</strong> argued for an industrial policy: bounties, tariff protection, and federal support for nascent textile, iron, and arms manufactories. Congress shelved most of it — but the framework outlived him.</p>
929
+
930
+ <p>Underneath these reports ran one idea: <em>public credit is the lifeblood of the modern state.</em> Pay your debts at par. Tax steadily. Bank centrally. Build infrastructure with chartered companies. Defend the industries that defend the country. Hamilton's system was not free trade and not state socialism — it was a deliberate alliance of federal authority and private capital, designed to crowd in investment instead of crowding it out.</p>
931
+
932
+ <h3>Why a Game</h3>
933
+ <p>Most of <em>Sovereign</em>'s mechanics map onto something Hamilton actually did. Continental Certificates and State Debt cards represent the assumption fight. The Bank of the United States and U.S. Mint are the institutional levers. Revenue System properties are the tariff and excise stream. Routes and Internal Improvements echo the federal post roads and chartered turnpikes. Manufactures and Strategic Industry trace the <em>Report on Manufactures</em>. Public Credit, Public Resistance, and Industrial Capacity are the three numbers Hamilton kept in his head.</p>
934
+
935
+ <p>Play it once and you'll feel the bargain the Federalists were trying to make: <em>concentrate financial power, distribute industrial gain, and ride out the political backlash.</em> Sometimes the backlash wins. The Whiskey Rebellion fires. The Bank's charter is allowed to expire. Then the next administration starts the cycle again.</p>
936
+
937
+ <div class="primer-pillars">
938
+ <div class="pillar"><svg viewBox="0 0 24 24"><use href="#icon-debt-certificate"/></svg><div><div class="nm">Fund the debt</div><div class="dc">Pay continental and state debts at par.</div></div></div>
939
+ <div class="pillar"><svg viewBox="0 0 24 24"><use href="#icon-bank"/></svg><div><div class="nm">Build the bank</div><div class="dc">A chartered national bank to discount and lend.</div></div></div>
940
+ <div class="pillar"><svg viewBox="0 0 24 24"><use href="#icon-customs-house"/></svg><div><div class="nm">Tax steadily</div><div class="dc">Tariffs and excise — the federal revenue stream.</div></div></div>
941
+ <div class="pillar"><svg viewBox="0 0 24 24"><use href="#icon-route"/></svg><div><div class="nm">Move the goods</div><div class="dc">Post roads, turnpikes, canals, coastwise shipping.</div></div></div>
942
+ <div class="pillar"><svg viewBox="0 0 24 24"><use href="#icon-manufactory"/></svg><div><div class="nm">Industrialize</div><div class="dc">Bounties and protection for nascent manufactures.</div></div></div>
943
+ <div class="pillar"><svg viewBox="0 0 24 24"><use href="#icon-armory-shipyard"/></svg><div><div class="nm">Defend the state</div><div class="dc">Armories, shipyards, and the means of force.</div></div></div>
944
+ </div>
945
+ </div>
946
+ <div class="primer-foot">
947
+ <span>Sovereign · The Hamilton System Board Game · <em>Founding Credit</em></span>
948
+ <span>v 1 · 2026</span>
949
+ </div>`;
950
+ </script>
951
+
952
+ <script id="data-script">
953
+ /* =====================================================================
954
+ DATA — shared constants
955
+ ===================================================================== */
956
+ const SYS = {
957
+ 'revolutionary-debt': { label:'Revolutionary Debt', short:'Rev. Debt', icon:'icon-debt-certificate', subkind:'Federal Bond · Continental Era', pattern:'p-horizontal' },
958
+ 'state-debt': { label:'State Debt', short:'State Debt', icon:'icon-state-ledger', subkind:'State Bond · Assumption Track', pattern:'p-vertical' },
959
+ 'revenue-system': { label:'Revenue System', short:'Revenue', icon:'icon-customs-house', subkind:'Federal Tariff · Customs', pattern:'p-diag-up' },
960
+ 'commercial-infrastructure': { label:'Commercial Infrastructure', short:'Commerce', icon:'icon-harbor', subkind:'Commercial Asset · Port System', pattern:'p-wave' },
961
+ 'national-finance': { label:'National Finance', short:'Finance', icon:'icon-bank', subkind:'Federal Instrument · Treasury', pattern:'p-dots' },
962
+ 'internal-improvements': { label:'Internal Improvements', short:'Improv.', icon:'icon-route', subkind:'Infrastructure Grant · Toll Asset', pattern:'p-diag-down' },
963
+ 'manufactures': { label:'Manufactures', short:'Mfg.', icon:'icon-manufactory', subkind:'Manufacturing Asset · Industrial', pattern:'p-cross' },
964
+ 'strategic-industry': { label:'Strategic Industry', short:'Strategic', icon:'icon-armory-shipyard', subkind:'Strategic Asset · National Power', pattern:'p-chevron' },
965
+ };
966
+
967
+ const TRACK_DEFS = {
968
+ credit: { start: 5, thresholds: [ { tick: 2, label: '≤ 2 · loans fail' }, { tick: 0, label: '0 · Default' } ] },
969
+ resist: { start: 2, thresholds: [ { tick: 8, label: '≥ 8 · Rebellion live' }, { tick: 12, label: '12 · Rebellion fires' } ] },
970
+ indust: { start: 1, thresholds: [ { tick: 6, label: '≥ 6 · +25 %' }, { tick: 8, label: '≥ 8 · +2 Inf' } ] },
971
+ };
972
+
973
+ /* ===== Board spaces (40) ===== */
974
+ const SPACES = [
975
+ { num:0, pos:'corner', side:'br', kind:'start', title:'Treasury Opens', sub:'Pass +200 TN · Land +400 TN', icon:'icon-treasury-start' },
976
+ { num:1, pos:'edge', side:'bottom', kind:'system', sys:'revolutionary-debt', icon:'icon-debt-certificate', name:'Continental Certificates', price:'$60' },
977
+ { num:2, pos:'edge', side:'bottom', kind:'card-debate', icon:'icon-republic-debate', name:'Republic Debate', kindLabel:'Draw 1' },
978
+ { num:3, pos:'edge', side:'bottom', kind:'system', sys:'revolutionary-debt', icon:'icon-debt-certificate', name:'Soldier Pay Notes', price:'$60' },
979
+ { num:4, pos:'edge', side:'bottom', kind:'tax', icon:'icon-customs-house', name:'Federal Excise', price:'Pay 200', kindLabel:'Tax' },
980
+ { num:5, pos:'edge', side:'bottom', kind:'route', icon:'icon-route', name:'Northern Post Road', price:'$200', kindLabel:'Route' },
981
+ { num:6, pos:'edge', side:'bottom', kind:'system', sys:'state-debt', icon:'icon-state-ledger', name:'Massachusetts Debt', price:'$100' },
982
+ { num:7, pos:'edge', side:'bottom', kind:'card-shock', icon:'icon-market-shock', name:'Market Shock', kindLabel:'Draw 1' },
983
+ { num:8, pos:'edge', side:'bottom', kind:'system', sys:'state-debt', icon:'icon-state-ledger', name:'South Carolina Debt', price:'$100' },
984
+ { num:9, pos:'edge', side:'bottom', kind:'system', sys:'state-debt', icon:'icon-state-ledger', name:'Virginia Debt', price:'$120' },
985
+ { num:10, pos:'corner', side:'bl', kind:'crisis', title:'Constitutional Crisis', sub:'Pay 50 · Roll doubles · Skip turn', icon:'icon-crisis' },
986
+ { num:11, pos:'edge', side:'left', kind:'system', sys:'revenue-system', icon:'icon-customs-house', name:'Customs House', price:'$140' },
987
+ { num:12, pos:'edge', side:'left', kind:'institution', icon:'icon-bank', name:'Bank of the United States', price:'$150', kindLabel:'Institution' },
988
+ { num:13, pos:'edge', side:'left', kind:'system', sys:'revenue-system', icon:'icon-customs-house', name:'Import Duties', price:'$140' },
989
+ { num:14, pos:'edge', side:'left', kind:'system', sys:'revenue-system', icon:'icon-customs-house', name:'Whiskey Excise', price:'$160' },
990
+ { num:15, pos:'edge', side:'left', kind:'route', icon:'icon-route', name:'Western Turnpike', price:'$200', kindLabel:'Route' },
991
+ { num:16, pos:'edge', side:'left', kind:'system', sys:'commercial-infrastructure', icon:'icon-harbor', name:'New York Harbor', price:'$180' },
992
+ { num:17, pos:'edge', side:'left', kind:'card-debate', icon:'icon-republic-debate', name:'Republic Debate', kindLabel:'Draw 1' },
993
+ { num:18, pos:'edge', side:'left', kind:'system', sys:'commercial-infrastructure', icon:'icon-harbor', name:'Philadelphia Exchange', price:'$180' },
994
+ { num:19, pos:'edge', side:'left', kind:'system', sys:'commercial-infrastructure', icon:'icon-harbor', name:'Coastal Shipping', price:'$200' },
995
+ { num:20, pos:'corner', side:'tl', kind:'safe', title:'National Dividend', sub:'Safe space', icon:'icon-dividend' },
996
+ { num:21, pos:'edge', side:'top', kind:'system', sys:'national-finance', icon:'icon-bank', name:'Treasury Securities', price:'$220' },
997
+ { num:22, pos:'edge', side:'top', kind:'card-shock', icon:'icon-market-shock', name:'Market Shock', kindLabel:'Draw 1' },
998
+ { num:23, pos:'edge', side:'top', kind:'system', sys:'national-finance', icon:'icon-bank', name:'Bank Subscription', price:'$220' },
999
+ { num:24, pos:'edge', side:'top', kind:'system', sys:'national-finance', icon:'icon-bank', name:'Federal Deposits', price:'$240' },
1000
+ { num:25, pos:'edge', side:'top', kind:'route', icon:'icon-route', name:'Potomac Canal', price:'$200', kindLabel:'Route' },
1001
+ { num:26, pos:'edge', side:'top', kind:'system', sys:'internal-improvements', icon:'icon-route', name:'Turnpike Charter', price:'$260' },
1002
+ { num:27, pos:'edge', side:'top', kind:'system', sys:'internal-improvements', icon:'icon-route', name:'Canal Company', price:'$260' },
1003
+ { num:28, pos:'edge', side:'top', kind:'institution', icon:'icon-act-of-congress', name:'United States Mint', price:'$150', kindLabel:'Institution' },
1004
+ { num:29, pos:'edge', side:'top', kind:'system', sys:'internal-improvements', icon:'icon-route', name:'Postal Road Network', price:'$280' },
1005
+ { num:30, pos:'corner', side:'tr', kind:'send', title:'Go to Crisis', sub:'Move directly to space 10', icon:'icon-send-crisis' },
1006
+ { num:31, pos:'edge', side:'right', kind:'system', sys:'manufactures', icon:'icon-manufactory', name:'Textile Works', price:'$300' },
1007
+ { num:32, pos:'edge', side:'right', kind:'system', sys:'manufactures', icon:'icon-manufactory', name:'Iron Foundry', price:'$300' },
1008
+ { num:33, pos:'edge', side:'right', kind:'card-debate', icon:'icon-republic-debate', name:'Republic Debate', kindLabel:'Draw 1' },
1009
+ { num:34, pos:'edge', side:'right', kind:'system', sys:'manufactures', icon:'icon-manufactory', name:'Glassworks', price:'$320' },
1010
+ { num:35, pos:'edge', side:'right', kind:'route', icon:'icon-route', name:'Atlantic Port Chain', price:'$200', kindLabel:'Route' },
1011
+ { num:36, pos:'edge', side:'right', kind:'card-shock', icon:'icon-market-shock', name:'Market Shock', kindLabel:'Draw 1' },
1012
+ { num:37, pos:'edge', side:'right', kind:'system', sys:'strategic-industry', icon:'icon-armory-shipyard', name:'Armory Works', price:'$350' },
1013
+ { num:38, pos:'edge', side:'right', kind:'tax', icon:'icon-armory-shipyard', name:'Speculation Scandal', price:'Pay 100', kindLabel:'Tax · +1 Resist.' },
1014
+ { num:39, pos:'edge', side:'right', kind:'system', sys:'strategic-industry', icon:'icon-armory-shipyard', name:'Shipbuilding Yard', price:'$400' },
1015
+ ];
1016
+
1017
+ const PROPS = [
1018
+ { id:1, name:'Continental Certificates', sys:'revolutionary-debt', cost:60, base:4, up:30, mort:30, flavor:'Paper notes issued to fund the Revolution. Worth pennies on the dollar — until Hamilton fixed them at par.' },
1019
+ { id:2, name:'Soldier Pay Notes', sys:'revolutionary-debt', cost:60, base:6, up:30, mort:30, flavor:'Promises of back pay handed to veterans who returned to debt-ridden farms and rebellious neighbors.' },
1020
+ { id:3, name:'Massachusetts Debt', sys:'state-debt', cost:100, base:6, up:50, mort:50, flavor:"Bay-State war obligations heavy enough to spark Shays's revolt before the federal Treasury took them on." },
1021
+ { id:4, name:'South Carolina Debt', sys:'state-debt', cost:100, base:6, up:50, mort:50, flavor:'Coastal war debts whose assumption swung Southern votes to the new federal bargain.' },
1022
+ { id:5, name:'Virginia Debt', sys:'state-debt', cost:120, base:8, up:50, mort:60, flavor:'Old Dominion debt — small in dollars, large in politics. Madison fought every step of its assumption.' },
1023
+ { id:6, name:'Customs House', sys:'revenue-system', cost:140, base:10, up:75, mort:70, flavor:'Tidewater offices where federal revenue first enters the Treasury, one bonded crate at a time.' },
1024
+ { id:7, name:'Import Duties', sys:'revenue-system', cost:140, base:10, up:75, mort:70, flavor:"Tariffs on European goods — the federal government's first dependable stream of cash." },
1025
+ { id:8, name:'Whiskey Excise', sys:'revenue-system', cost:160, base:12, up:75, mort:80, flavor:'An excise on distilled spirits. Lucrative on paper, riot-inducing on the Pennsylvania frontier.' },
1026
+ { id:9, name:'New York Harbor', sys:'commercial-infrastructure', cost:180, base:14, up:100, mort:90, flavor:"The continent's busiest deep-water port and the engine of the federal customs revenue." },
1027
+ { id:10, name:'Philadelphia Exchange', sys:'commercial-infrastructure', cost:180, base:14, up:100, mort:90, flavor:"Merchant bills, marine insurance, securities — quoted daily at the country's first public exchange." },
1028
+ { id:11, name:'Coastal Shipping', sys:'commercial-infrastructure', cost:200, base:16, up:100, mort:100, flavor:'Cabotage routes linking New England carpentry, mid-Atlantic flour, and Carolina rice into one market.' },
1029
+ { id:12, name:'Treasury Securities', sys:'national-finance', cost:220, base:18, up:125, mort:110, flavor:"Federal bonds at six percent — the bedrock collateral of the new nation's credit." },
1030
+ { id:13, name:'Bank Subscription', sys:'national-finance', cost:220, base:18, up:125, mort:110, flavor:'Shares in the Bank of the United States. Subscriptions oversold within an hour of opening.' },
1031
+ { id:14, name:'Federal Deposits', sys:'national-finance', cost:240, base:20, up:125, mort:120, flavor:'Customs receipts deposited with the Bank, leveraged into loans that ran the young economy.' },
1032
+ { id:15, name:'Turnpike Charter', sys:'internal-improvements', cost:260, base:22, up:150, mort:130, flavor:'A toll road granted by the legislature to private investors willing to gravel and grade it.' },
1033
+ { id:16, name:'Canal Company', sys:'internal-improvements', cost:260, base:22, up:150, mort:130, flavor:'Stockholders dig the ditch, the state grants the right of way, the country gains a corridor.' },
1034
+ { id:17, name:'Postal Road Network', sys:'internal-improvements', cost:280, base:24, up:150, mort:140, flavor:'Federal post roads carried newspapers cheap and bound thirteen states into one polity.' },
1035
+ { id:18, name:'Textile Works', sys:'manufactures', cost:300, base:26, up:200, mort:150, flavor:'Water-powered carding and spinning. The pioneers smuggled British plans out under their hats.' },
1036
+ { id:19, name:'Iron Foundry', sys:'manufactures', cost:300, base:26, up:200, mort:150, flavor:'Charcoal-fired furnaces casting kettles, plows, and — when needed — cannon for the young republic.' },
1037
+ { id:20, name:'Glassworks', sys:'manufactures', cost:320, base:28, up:200, mort:160, flavor:'Sand, ash, and labor — bottle glass for apothecaries and window panes for the Atlantic seaboard.' },
1038
+ { id:21, name:'Armory Works', sys:'strategic-industry', cost:350, base:35, up:200, mort:175, flavor:'Federal arsenals stockpiling muskets so the next mobilization need not depend on French gunsmiths.' },
1039
+ { id:22, name:'Shipbuilding Yard', sys:'strategic-industry', cost:400, base:50, up:200, mort:200, flavor:'Live-oak frigates and merchant sloops — the timber, tar, and copper of national reach.' },
1040
+ ];
1041
+
1042
+ const ROUTES = [
1043
+ { id:23, name:'Northern Post Road', flavor:'Rider relay binding Boston to Philadelphia.' },
1044
+ { id:24, name:'Western Turnpike', flavor:'Macadamized stone hauling Ohio grain east.' },
1045
+ { id:25, name:'Potomac Canal', flavor:'Locks around the Great Falls of the Tidewater.' },
1046
+ { id:26, name:'Atlantic Port Chain',flavor:'Coastwise packet boats linking the seaboard.' },
1047
+ ];
1048
+
1049
+ const INSTS = [
1050
+ { id:27, name:'Bank of the United States', icon:'icon-bank', cost:150,
1051
+ flavor:'Federal deposits, merchant discounts, banknotes at par.',
1052
+ subkind:'Federal Institution · Banking',
1053
+ rules:[ { cond:'Before Bank Charter passes', val:'4 × dice' }, { cond:'After Bank Charter passes', val:'10 × dice' } ] },
1054
+ { id:28, name:'United States Mint', icon:'icon-act-of-congress', cost:150,
1055
+ flavor:'Federal gold and silver coinage struck at par.',
1056
+ subkind:'Federal Institution · Coinage',
1057
+ rules:[
1058
+ { cond:'Mint alone (no Bank)', val:'no payment', muted:true },
1059
+ { cond:'Owner holds BOTH institutions', val:'10 × dice' },
1060
+ { cond:'Owner holds BOTH institutions and Bank Charter has passed', val:'20 × dice' }
1061
+ ] },
1062
+ ];
1063
+
1064
+ const ROUTE_LADDER = [
1065
+ { cond:'1 route owned', val:'$25' },
1066
+ { cond:'2 routes owned', val:'$50' },
1067
+ { cond:'3 routes owned', val:'$100' },
1068
+ { cond:'4 routes owned', val:'$150' },
1069
+ ];
1070
+
1071
+ const MARKET_SHOCK = [
1072
+ { id:1, name:'Panic in the Market', tags:['Conditional','Payment'], affects:[],
1073
+ effect:`<p>If <var>Public Credit &lt; 5</var>, pay <strong>50&nbsp;TN</strong> to the bank.</p><p>If <var>Credit ≥ 8</var>, <strong>collect 50&nbsp;TN</strong> instead.</p>` },
1074
+ { id:2, name:'Foreign Demand Rises', tags:['System','Payout'], affects:['manufactures'],
1075
+ effect:`<p>All <span class="sys">Manufactures</span> owners collect <strong>40&nbsp;TN</strong> from the bank.</p>` },
1076
+ { id:3, name:'Speculation Fever', tags:['Auction','Track'], affects:['revolutionary-debt','state-debt'], tracks:{resist:1},
1077
+ effect:`<p>Choose <strong>one unowned</strong> <span class="sys">Revolutionary Debt</span> or <span class="sys">State Debt</span> property.</p><p>Auction it immediately.</p>` },
1078
+ { id:4, name:'Shipping Disruption', tags:['Suspension','System'], affects:['commercial-infrastructure'],
1079
+ effect:`<p><span class="sys">Commercial Infrastructure</span> and <span class="sys">Route</span> payments are <strong>suspended</strong> until your next turn.</p>` },
1080
+ { id:5, name:'Gold and Silver Inflow', tags:['Owner','Track'], affects:[], tracks:{credit:1},
1081
+ effect:`<p><span class="sys">Mint</span> owner collects <strong>50&nbsp;TN</strong> from each player.</p>` },
1082
+ { id:6, name:'Foreign Loan Secured', tags:['Payment','Track'], affects:[], tracks:{credit:1},
1083
+ effect:`<p>You receive <strong>100&nbsp;TN</strong> from the bank.</p>` },
1084
+ { id:7, name:'British Trade Embargo', tags:['System','Track'], affects:['revenue-system'], tracks:{indust:1},
1085
+ effect:`<p><span class="sys">Revenue System</span> payments are <strong>halved</strong> this round.</p>` },
1086
+ { id:8, name:'Yellow Fever Outbreak', tags:['Movement'], affects:['commercial-infrastructure'],
1087
+ effect:`<p>Move to the <strong>nearest</strong> <span class="sys">Commercial Infrastructure</span> property: New York Harbor, Philadelphia Exchange, or Coastal Shipping.</p><p><em>Pay nothing if you own it.</em></p>` },
1088
+ { id:9, name:'Successful Bond Auction', tags:['Payout','Multi-system'], affects:['revolutionary-debt','national-finance'],
1089
+ effect:`<p>All <span class="sys">Revolutionary Debt</span> and <span class="sys">National Finance</span> owners collect <strong>30&nbsp;TN</strong> <em>per property</em>.</p>` },
1090
+ { id:10, name:'Bank Run', tags:['Conditional','Track'], affects:['national-finance'], tracks:{indust:-1},
1091
+ effect:`<p>If <var>Bank Charter</var> has passed, all <span class="sys">National Finance</span> owners <strong>lose 1 upgrade</strong>.</p>` },
1092
+ { id:11, name:'Cotton Gin Patented', tags:['System','Track'], affects:['manufactures'], tracks:{indust:1},
1093
+ effect:`<p><span class="sys">Textile Works</span> payment is <strong>doubled</strong> this round.</p>` },
1094
+ { id:12, name:'Treaty Renegotiation', tags:['Multi-system','Track'], affects:['revolutionary-debt','state-debt'], tracks:{credit:2},
1095
+ effect:`<p><span class="sys">Revolutionary Debt</span> and <span class="sys">State Debt</span> payments are <strong>doubled</strong> this round.</p>` },
1096
+ ];
1097
+
1098
+ const REPUBLIC_DEBATE = [
1099
+ { id:1, name:'Strict Construction Objection', tags:['Choice','Crisis'], affects:[],
1100
+ effect:`<p>Move to <span class="sys">Constitutional Crisis</span> &mdash; <em>OR</em> &mdash;</p><p>Pay <strong>50&nbsp;TN</strong> to lobby and remain in place.</p>` },
1101
+ { id:2, name:'Jeffersonian Opposition', tags:['Owner','Track'], affects:[], tracks:{resist:1},
1102
+ effect:`<p><span class="sys">Bank of the United States</span> owner pays <strong>100&nbsp;TN</strong> to the bank.</p>` },
1103
+ { id:3, name:'Credit Restored', tags:['Multi-system','Track'], affects:['revolutionary-debt','state-debt','national-finance'], tracks:{credit:1},
1104
+ effect:`<p>Bond owners — <span class="sys">Revolutionary Debt</span>, <span class="sys">State Debt</span>, or <span class="sys">National Finance</span> — each collect <strong>50&nbsp;TN</strong>.</p>` },
1105
+ { id:4, name:'Whiskey Rebellion', tags:['Conditional','Crisis'], affects:['revenue-system'],
1106
+ effect:`<p>If <var>Public Resistance ≥ 8</var>, <span class="sys">Whiskey Excise</span> owner loses <strong>1 upgrade</strong> and goes to <span class="sys">Constitutional Crisis</span>.</p>` },
1107
+ { id:5, name:'Cabinet Bargain', tags:['Trade','Track'], affects:[], tracks:{resist:-1},
1108
+ effect:`<p>Trade <strong>one card or property</strong> with another player. Both sides gain <strong>1 Influence</strong>.</p><p><em>If no trade within 30 sec: only the active player gains 1 Influence.</em></p>` },
1109
+ { id:6, name:'Newspaper Smear', tags:['Influence','Payment'], affects:[],
1110
+ effect:`<p>Pay <strong>25&nbsp;TN</strong> <em>per Influence Point</em> you currently hold.</p>` },
1111
+ { id:7, name:'Federalist Victory', tags:['Conditional','Track'], affects:['national-finance'], tracks:{credit:1},
1112
+ effect:`<p>If you hold any <span class="sys">National Finance</span> property, collect <strong>100&nbsp;TN</strong>.</p>` },
1113
+ { id:8, name:'Anti-Federalist Pamphlet', tags:['System','Track'], affects:['revenue-system'], tracks:{resist:1},
1114
+ effect:`<p>All <span class="sys">Revenue System</span> owners pay <strong>30&nbsp;TN</strong> to the bank.</p>` },
1115
+ { id:9, name:'Funding Plan Advances', tags:['Vote'], affects:[],
1116
+ effect:`<p>Force the <strong>next Act vote</strong> immediately, ahead of its lap order.</p>` },
1117
+ { id:10, name:'State Convention Calls', tags:['System','Option'], affects:['state-debt'],
1118
+ effect:`<p>Each <span class="sys">State Debt</span> owner may sell <strong>one</strong> State Debt property back to the bank at <em>full purchase price</em>.</p>` },
1119
+ { id:11, name:'National Lottery', tags:['Payout','All Players'], affects:[],
1120
+ effect:`<p>All players collect <strong>10&nbsp;TN</strong> <em>per property owned</em>.</p>` },
1121
+ { id:12, name:'You Are Hamilton', tags:['Keepable','Influence'], affects:[], tracks:{credit:1},
1122
+ effect:`<p>Collect <strong>200&nbsp;TN</strong>. Gain <strong>1 Influence</strong>.</p><p><em>Keep this card for one "skip Crisis" use.</em></p>` },
1123
+ ];
1124
+
1125
+ const ACTS = [
1126
+ { id:1, lap:1, roman:'I', name:'Funding Act', icon:'icon-debt-certificate',
1127
+ effect:`<p>All <span class="sys">Revolutionary Debt</span> payments <strong>+50 %</strong> permanently.</p><p><strong>Public Credit +2.</strong></p>` },
1128
+ { id:2, lap:2, roman:'II', name:'Assumption Act', icon:'icon-state-ledger',
1129
+ effect:`<p><span class="sys">State Debt</span> payments <strong>+100 %</strong> permanently.</p><p><strong>Public Credit +2.</strong> <strong>Public Resistance +1.</strong></p>` },
1130
+ { id:3, lap:3, roman:'III', name:'Bank Charter', icon:'icon-bank',
1131
+ effect:`<p><span class="sys">Bank of the United States</span> activates lending and <strong>enhanced institution payments</strong>.</p><p><em>Bank now pays 10 × dice instead of 4 × dice.</em></p>` },
1132
+ { id:4, lap:4, roman:'IV', name:'Tariff Schedule', icon:'icon-customs-house',
1133
+ effect:`<p><span class="sys">Revenue System</span> payments <strong>+50 %</strong> permanently.</p><p><strong>Public Resistance +1.</strong></p>` },
1134
+ { id:5, lap:5, roman:'V', name:'Coinage Act', icon:'icon-act-of-congress',
1135
+ effect:`<p><span class="sys">Mint</span> owner collects <strong>50&nbsp;TN</strong> from each <em>other</em> player.</p><p><strong>Public Credit +1.</strong> <strong>Industrial Capacity +1.</strong></p>` },
1136
+ { id:6, lap:6, roman:'VI', name:'Report on Manufactures',icon:'icon-manufactory',
1137
+ effect:`<p><span class="sys">Manufactures</span> upgrade costs are <strong>halved</strong> for one full lap.</p><p><strong>Industrial Capacity +2.</strong></p>` },
1138
+ { id:7, lap:7, roman:'VII', name:'Excise Enforcement', icon:'icon-armory-shipyard',
1139
+ effect:`<p><span class="sys">Whiskey Excise</span> pays <strong>2×</strong> this round.</p><p><strong>Public Resistance +2.</strong> <em>If Resistance reaches 12 → Rebellion fires.</em></p>` },
1140
+ ];
1141
+
1142
+ const VOTING_REF = { id:'V', lap:null, roman:'§', name:'Voting Reference', icon:'icon-republic-debate',
1143
+ voting:true,
1144
+ effect:`<p><strong>All players vote</strong> on every Act of Congress.</p><p><strong>Majority passes.</strong> <strong>Ties fail.</strong></p><p>Failed Acts return to the <em>bottom of the Act sequence</em> and re-trigger one lap later. The vote then repeats with the same rules.</p><p><em>Pass / fail is determined the moment each Act is revealed; no abstentions.</em></p>` };
1145
+
1146
+ const ROLES = [
1147
+ { id:1, name:'Treasury Architect', icon:'icon-act-of-congress', specialty:'Credit Lever',
1148
+ ability:`Once per round, <strong>pay 50 TN</strong> to the bank to raise <strong>Public Credit by 1</strong>.` },
1149
+ { id:2, name:'State Broker', icon:'icon-state-ledger', specialty:'Assumption Windfall',
1150
+ ability:`When the <strong>Assumption Act</strong> passes, collect <strong>100 TN per State Debt property</strong> you own.` },
1151
+ { id:3, name:'Merchant Financier', icon:'icon-harbor', specialty:'Commercial Edge',
1152
+ ability:`<strong>+25 % payment</strong> on every <strong>Commercial Infrastructure</strong> property. <strong>+1 vote</strong> on the Tariff Schedule.` },
1153
+ { id:4, name:'Manufacturer', icon:'icon-manufactory', specialty:'Industrial Discount',
1154
+ ability:`Pay <strong>50 % less</strong> for every <strong>Manufactures</strong> and <strong>Strategic Industry</strong> upgrade.` },
1155
+ ];
1156
+
1157
+ const REMINDERS = [
1158
+ 'Starts with 1 500 TN · 3 – 4 players',
1159
+ 'Lasts 7 laps, then score Influence',
1160
+ 'Tracks affect everyone, not just you',
1161
+ ];
1162
+
1163
+ const NOTES = [
1164
+ { val:1, words:'One', color:'strategic-industry' },
1165
+ { val:5, words:'Five', color:'state-debt' },
1166
+ { val:10, words:'Ten', color:'commercial-infrastructure' },
1167
+ { val:50, words:'Fifty', color:'revenue-system' },
1168
+ { val:100, words:'One Hundred', color:'national-finance' },
1169
+ { val:500, words:'Five Hundred', color:'revolutionary-debt' },
1170
+ ];
1171
+
1172
+ const TIERS = [
1173
+ { id:1, roman:'I', ord:'First', cls:'t1' },
1174
+ { id:2, roman:'II', ord:'Second', cls:'t2' },
1175
+ { id:3, roman:'III', ord:'Third', cls:'t3' },
1176
+ ];
1177
+
1178
+ /* =====================================================================
1179
+ HELPERS
1180
+ ===================================================================== */
1181
+ function el(tag, cls, html) { const e = document.createElement(tag); if (cls) e.className = cls; if (html !== undefined) e.innerHTML = html; return e; }
1182
+ function svgUse(id) { return `<svg viewBox="0 0 24 24"><use href="#${id}"/></svg>`; }
1183
+ function svgUseRaw(id) { return `<svg viewBox="0 0 200 200"><use href="#${id}"/></svg>`; }
1184
+ function pad(n) { return String(n).padStart(2,'0'); }
1185
+ function fmt$(n) { return '$' + n.toLocaleString('en-US'); }
1186
+ function fmtDelta(n) { return n > 0 ? '+' + n : String(n); }
1187
+
1188
+ /* =====================================================================
1189
+ BOARD render
1190
+ ===================================================================== */
1191
+ function renderSpace(s) {
1192
+ const klass = ['space'];
1193
+ if (s.kind === 'system') klass.push('sys-' + s.sys);
1194
+ if (s.kind === 'route') klass.push('route');
1195
+ if (s.kind === 'institution') klass.push('institution');
1196
+ if (s.kind === 'tax') klass.push('tax');
1197
+ if (s.kind === 'card-debate') klass.push('card-space','card-debate');
1198
+ if (s.kind === 'card-shock') klass.push('card-space','card-shock');
1199
+ const sp = el('div', klass.join(' '));
1200
+ sp.dataset.num = s.num; sp.dataset.side = s.side;
1201
+ const c = el('div', 'content');
1202
+ const band = el('div', 'band');
1203
+ if (s.kind === 'system') band.classList.add(SYS[s.sys].pattern);
1204
+ const bandLabel = s.kind === 'system' ? SYS[s.sys].short
1205
+ : s.kind === 'route' ? 'Route'
1206
+ : s.kind === 'institution' ? 'Institution'
1207
+ : s.kind === 'tax' ? 'Tax'
1208
+ : s.kind === 'card-debate' ? 'Debate'
1209
+ : s.kind === 'card-shock' ? 'Shock' : '';
1210
+ band.innerHTML = `<span class="band-label">${bandLabel}</span><span class="num">${pad(s.num)}</span>`;
1211
+ c.appendChild(band);
1212
+ const body = el('div', 'body');
1213
+ body.innerHTML = svgUse(s.icon).replace('<svg ', '<svg class="glyph" ') + `<div class="name">${s.name}</div>`;
1214
+ c.appendChild(body);
1215
+ const foot = el('div', 'foot');
1216
+ if (s.kind === 'system' || s.kind === 'route' || s.kind === 'institution') {
1217
+ foot.innerHTML = `<span class="kind">${s.kindLabel || ''}</span><span class="price">${s.price}</span>`;
1218
+ } else if (s.kind === 'tax') {
1219
+ foot.innerHTML = `<span class="kind">${s.kindLabel}</span><span class="price">${s.price}</span>`;
1220
+ } else {
1221
+ foot.innerHTML = `<span class="kind">${s.kindLabel}</span><span class="price" style="opacity:.6">card</span>`;
1222
+ }
1223
+ c.appendChild(foot);
1224
+ sp.appendChild(c);
1225
+ return sp;
1226
+ }
1227
+ function renderCorner(s) {
1228
+ const c = el('div', `corner corner-${s.side} ${s.kind}`);
1229
+ c.dataset.num = s.num;
1230
+ const content = el('div', 'content');
1231
+ content.innerHTML = `<div class="head">${s.title}</div><div class="glyph-ring">${svgUse(s.icon)}</div><div class="sub">${s.sub}</div><div class="mono" style="font-family:var(--mono);font-size:8px;letter-spacing:.14em;opacity:.65;margin-top:2px">SPACE ${pad(s.num)}</div>`;
1232
+ c.appendChild(content);
1233
+ return c;
1234
+ }
1235
+ function renderCenter() {
1236
+ const center = el('div', 'center');
1237
+ const head = el('div', 'c-head');
1238
+ head.innerHTML = `<div class="lead-rule">The Hamilton System Board Game</div><h1>Sovereign</h1><div class="subtitle">The Hamilton System Board Game</div>`;
1239
+ center.appendChild(head);
1240
+ const mid = el('div', 'c-mid');
1241
+ const tracks = el('div', 'tracks');
1242
+ tracks.innerHTML = `<div class="panel-head"><h3>Shared Tracks</h3><span class="note">cap 12 · tracks affect everyone</span></div>`;
1243
+ function trackEl(klass, labelText, iconId, start) {
1244
+ const t = el('div', 'track ' + klass);
1245
+ const scale = el('div', 'scale');
1246
+ let ticks = '';
1247
+ for (let i = 0; i <= 12; i++) {
1248
+ const major = (i % 3 === 0);
1249
+ ticks += `<div class="tick${major?' major':''}">${i}${i === start ? '<span class="pip">start</span>' : ''}</div>`;
1250
+ }
1251
+ scale.innerHTML = ticks;
1252
+ t.innerHTML = `<div class="label">${svgUse(iconId)} ${labelText}</div>`;
1253
+ t.appendChild(scale);
1254
+ t.appendChild(el('div', 'cap-note', `starts<br/>at ${start}`));
1255
+ return t;
1256
+ }
1257
+ tracks.appendChild(trackEl('t-credit', 'Public Credit', 'icon-bank', 5));
1258
+ tracks.appendChild(trackEl('t-resist', 'Public Resistance', 'icon-republic-debate', 2));
1259
+ tracks.appendChild(trackEl('t-indust', 'Industrial Capacity', 'icon-manufactory', 1));
1260
+ mid.appendChild(tracks);
1261
+ const acts = el('div', 'acts-list');
1262
+ let actsHTML = `<h3>Acts of Congress · Lap Order</h3><ol>`;
1263
+ ACTS.forEach((a, i) => { actsHTML += `<li><span class="n">${i+1}</span>${svgUse(a.icon)}<span class="name">${a.name}</span></li>`; });
1264
+ actsHTML += `</ol>`;
1265
+ acts.innerHTML = actsHTML;
1266
+ mid.appendChild(acts);
1267
+ center.appendChild(mid);
1268
+ const foot = el('div', 'c-foot');
1269
+ const laps = el('div', 'laps');
1270
+ let lapHTML = `<h3>Lap Tracker</h3><div class="row">`;
1271
+ for (let i = 1; i <= 7; i++) lapHTML += `<div class="cell"><span class="small">L</span>${i}</div>`;
1272
+ lapHTML += `</div>`;
1273
+ laps.innerHTML = lapHTML;
1274
+ foot.appendChild(laps);
1275
+ const mech = el('div', 'mechanics');
1276
+ mech.innerHTML = `<div class="label">Quick reference</div><div class="line">3 – 4 players &nbsp;·&nbsp; 7 laps<br/>Influence scoring</div><div class="sub">Tracks affect everyone &nbsp;·&nbsp; Cash starts 1 500 TN</div>`;
1277
+ foot.appendChild(mech);
1278
+ center.appendChild(foot);
1279
+ return center;
1280
+ }
1281
+ function renderBoardInto(container) {
1282
+ SPACES.filter(s => s.pos === 'corner').forEach(s => container.appendChild(renderCorner(s)));
1283
+ const sides = { bottom:[], left:[], top:[], right:[] };
1284
+ SPACES.filter(s => s.pos === 'edge').forEach(s => sides[s.side].push(s));
1285
+ Object.entries(sides).forEach(([side, list]) => {
1286
+ const strip = el('div', 'edge edge-' + side);
1287
+ list.sort((a,b) => a.num - b.num).forEach(s => strip.appendChild(renderSpace(s)));
1288
+ container.appendChild(strip);
1289
+ });
1290
+ container.appendChild(renderCenter());
1291
+ }
1292
+
1293
+ /* =====================================================================
1294
+ PROPERTY / ROUTE / INSTITUTION cards
1295
+ ===================================================================== */
1296
+ function renderProperty(p) {
1297
+ const sys = SYS[p.sys];
1298
+ const c = el('div', `card sys-${p.sys} kind-property has-mortgage`);
1299
+ const base = p.base, full = base*2, t1 = base*5, t2 = base*15, t3 = base*30;
1300
+ c.innerHTML = `
1301
+ <div class="band"><span>${sys.label}</span><span class="num">${pad(p.id)}</span></div>
1302
+ <div class="title"><div class="name">${p.name}</div><div class="subkind">${sys.subkind}</div></div>
1303
+ <div class="glyph"><div class="icon-ring">${svgUse(sys.icon)}</div></div>
1304
+ <div class="flavor">${p.flavor}</div>
1305
+ <div class="pay">
1306
+ <div class="pay-head"><span>Payment</span><span class="legend">TN per landing</span></div>
1307
+ <table>
1308
+ <tr class="base"><td class="tier">Base</td><td class="val">${fmt$(base)}</td></tr>
1309
+ <tr class="fullset"><td class="tier">Full Set <span class="sub">×2</span></td><td class="val">${fmt$(full)}</td></tr>
1310
+ <tr><td class="tier">Tier I <span class="sub">+${fmt$(p.up)}</span></td><td class="val">${fmt$(t1)}</td></tr>
1311
+ <tr><td class="tier">Tier II <span class="sub">+${fmt$(p.up)}</span></td><td class="val">${fmt$(t2)}</td></tr>
1312
+ <tr><td class="tier">Tier III <span class="sub">+${fmt$(p.up)}</span></td><td class="val">${fmt$(t3)}</td></tr>
1313
+ </table>
1314
+ </div>
1315
+ <div class="foot">
1316
+ <div class="cell"><span class="lbl">Cost</span><span class="v">${fmt$(p.cost)}</span></div>
1317
+ <div class="cell"><span class="lbl">Upgrade</span><span class="v">${fmt$(p.up)}</span></div>
1318
+ <div class="cell"><span class="lbl">Mortgage</span><span class="v">${fmt$(p.mort)}</span></div>
1319
+ </div>`;
1320
+ return c;
1321
+ }
1322
+ function renderRoute(r) {
1323
+ const c = el('div', 'card kind-route no-mortgage');
1324
+ const rows = ROUTE_LADDER.map((rl,i) => `<div class="row ${i%2?'alt':''}"><span class="cond">${rl.cond}</span><span class="val">${rl.val}</span></div>`).join('');
1325
+ c.innerHTML = `
1326
+ <div class="band"><span>Route</span><span class="num">${pad(r.id)}</span></div>
1327
+ <div class="title"><div class="name">${r.name}</div><div class="subkind">Infrastructure Corridor</div></div>
1328
+ <div class="glyph"><div class="icon-ring">${svgUse('icon-route')}</div></div>
1329
+ <div class="flavor">${r.flavor}</div>
1330
+ <div class="pay"><div class="pay-head"><span>Payment · by routes owned</span><span class="legend">TN</span></div><div class="rules-list">${rows}</div></div>
1331
+ <div class="foot"><div class="cell"><span class="lbl">Cost</span><span class="v">${fmt$(200)}</span></div><div class="cell note">Payment scales<br/><span>with routes you own</span></div></div>`;
1332
+ return c;
1333
+ }
1334
+ function renderInstitution(i) {
1335
+ const c = el('div', 'card kind-institution no-mortgage');
1336
+ const rows = i.rules.map((rule, k) => `<div class="row ${k%2?'alt':''}"><span class="cond"><strong>Condition ${k+1}</strong>${rule.cond}</span><span class="val${rule.muted ? ' muted' : ''}">${rule.val}</span></div>`).join('');
1337
+ c.innerHTML = `
1338
+ <div class="band"><span>Institution</span><span class="num">${pad(i.id)}</span></div>
1339
+ <div class="title"><div class="name">${i.name}</div><div class="subkind">${i.subkind}</div></div>
1340
+ <div class="glyph"><div class="icon-ring">${svgUse(i.icon)}</div></div>
1341
+ <div class="flavor">${i.flavor}</div>
1342
+ <div class="pay"><div class="pay-head"><span>Payment Conditions</span><span class="legend">multiplier · dice roll</span></div><div class="rules-list">${rows}</div></div>
1343
+ <div class="foot"><div class="cell"><span class="lbl">Cost</span><span class="v">${fmt$(i.cost)}</span></div><div class="cell note">Chartered<br/><span>federal institution</span></div></div>`;
1344
+ return c;
1345
+ }
1346
+ function renderReference(sysKey) {
1347
+ const sys = SYS[sysKey];
1348
+ const c = el('div', `card sys-${sysKey} kind-reference no-mortgage`);
1349
+ c.innerHTML = `
1350
+ <div class="band"><span>${sys.label}</span><span class="num">REF</span></div>
1351
+ <div class="title"><div class="name">${sys.label}</div><div class="subkind">${sys.subkind}</div></div>
1352
+ <div class="glyph"><div class="icon-ring">${svgUse(sys.icon)}</div></div>
1353
+ <div class="flavor">Reference card — not a playable asset. Properties of this system carry the band, pattern, and icon shown above.</div>
1354
+ <div class="pay"><div class="pay-head"><span>System Identity</span><span class="legend">color · icon · label</span></div><div class="rules-list">
1355
+ <div class="row"><span class="cond"><strong>Band color</strong>see top of this card</span></div>
1356
+ <div class="row alt"><span class="cond"><strong>Pattern fallback</strong>visible in grayscale</span></div>
1357
+ <div class="row"><span class="cond"><strong>Icon</strong>${sys.icon.replace('icon-','')}</span></div>
1358
+ </div></div>
1359
+ <div class="foot"><div class="cell"><span class="lbl">Reference</span><span class="v" style="font-size:11px">${sys.label}</span></div><div class="cell note">Non-playable<br/><span>for assembly only</span></div></div>`;
1360
+ return c;
1361
+ }
1362
+ function renderCharterBack() {
1363
+ const c = el('div', 'cardback cb-charter');
1364
+ c.innerHTML = `
1365
+ <div class="corner-orn tl"></div><div class="corner-orn tr"></div>
1366
+ <div class="corner-orn bl"></div><div class="corner-orn br"></div>
1367
+ <div class="cb-eyebrow">Sovereign</div>
1368
+ <div class="cb-head">Charter &amp; Asset</div>
1369
+ <div class="cb-title">Treasury<span class="amp" style="font-family:var(--display);font-style:italic">.</span></div>
1370
+ <div class="cb-seal">${svgUseRaw('seal-mark')}</div>
1371
+ <div class="cb-sub">The Hamilton System Board Game<br/>Property · Route · Institution</div>
1372
+ <div class="cb-foot">Draw · Hold · Build</div>`;
1373
+ return c;
1374
+ }
1375
+ function renderShockBack() {
1376
+ const c = el('div', 'cardback cb-shock');
1377
+ c.innerHTML = `
1378
+ <div class="corner-wedge"></div>
1379
+ <div class="corner-wedge bl"></div>
1380
+ <div class="cb-eyebrow">Sovereign</div>
1381
+ <div class="cb-head">Market Shock</div>
1382
+ <div class="cb-title">Volatility<span class="amp" style="font-family:var(--display);font-style:italic">.</span></div>
1383
+ <div class="cb-seal">${svgUse('icon-market-shock')}</div>
1384
+ <div class="cb-sub">The Hamilton System Board Game<br/>Panic, embargo, demand.</div>
1385
+ <div class="cb-foot">Draw · Read · Resolve</div>`;
1386
+ return c;
1387
+ }
1388
+ function renderDebateBack() {
1389
+ const c = el('div', 'cardback cb-debate');
1390
+ c.innerHTML = `
1391
+ <div class="corner-diamond tl"></div><div class="corner-diamond tr"></div>
1392
+ <div class="corner-diamond bl"></div><div class="corner-diamond br"></div>
1393
+ <div class="cb-eyebrow">Sovereign</div>
1394
+ <div class="cb-head">Republic Debate</div>
1395
+ <div class="cb-title">Broadside<span class="amp" style="font-family:var(--display);font-style:italic">.</span></div>
1396
+ <div class="asterism">✦ ✦ ✦</div>
1397
+ <div class="cb-seal">${svgUse('icon-republic-debate')}</div>
1398
+ <div class="cb-sub">The Hamilton System Board Game<br/>Faction, bargain, dispute.</div>
1399
+ <div class="cb-foot">Draw · Read · Resolve</div>`;
1400
+ return c;
1401
+ }
1402
+ function renderActBack() {
1403
+ const c = el('div', 'cardback cb-act');
1404
+ c.innerHTML = `
1405
+ <div class="ribbon">Federal Statute</div>
1406
+ <div class="cb-eyebrow" style="margin-top:14px">Sovereign</div>
1407
+ <div class="cb-head">Act of Congress</div>
1408
+ <div class="cb-seal">${svgUseRaw('seal-mark')}</div>
1409
+ <div class="cb-sub">The Hamilton System Board Game<br/>A vote of the Congress.</div>
1410
+ <div class="cb-foot">Reveal at lap start</div>`;
1411
+ return c;
1412
+ }
1413
+ function renderRoleBack() {
1414
+ const c = el('div', 'cardback cb-role');
1415
+ c.innerHTML = `
1416
+ <div class="cb-eyebrow">Sovereign</div>
1417
+ <div class="cb-head">Founder Role</div>
1418
+ <div class="cb-title">Office<span class="amp" style="font-family:var(--display);font-style:italic">.</span></div>
1419
+ <div class="portrait-frame"><div class="silhouette"></div></div>
1420
+ <div class="cb-sub">The Hamilton System Board Game<br/>One office per player.</div>
1421
+ <div class="cb-foot">Faction · Office · Influence</div>`;
1422
+ return c;
1423
+ }
1424
+
1425
+ /* =====================================================================
1426
+ EVENT CARDS
1427
+ ===================================================================== */
1428
+ const SYS_ICON_MAP = Object.fromEntries(Object.entries(SYS).map(([k, v]) => [k, v.icon]));
1429
+ function renderEventCard(card, deck) {
1430
+ const c = el('div', `ecard deck-${deck}`);
1431
+ const deckLabel = deck === 'shock' ? 'Market Shock' : 'Republic Debate';
1432
+ const deckCode = deck === 'shock' ? 'MS' : 'RD';
1433
+ const alertText = deck === 'shock' ? 'Urgent · Market Notice' : 'Broadside · Political Debate';
1434
+ const deckIcon = deck === 'shock' ? 'icon-market-shock' : 'icon-republic-debate';
1435
+ let affectsHTML = '';
1436
+ if (card.affects && card.affects.length) {
1437
+ affectsHTML = card.affects.map(s => `<span class="aff" title="${s.replace(/-/g,' ')}">${svgUse(SYS_ICON_MAP[s])}</span>`).join('');
1438
+ }
1439
+ const tagsHTML = (card.tags || []).slice(0,2).map(t => `<span class="tag">${t}</span>`).join('');
1440
+ let outcomesHTML = '';
1441
+ if (card.tracks) {
1442
+ if (card.tracks.credit != null) outcomesHTML += `<span class="chip t-credit">Credit <span class="delta">${fmtDelta(card.tracks.credit)}</span></span>`;
1443
+ if (card.tracks.resist != null) outcomesHTML += `<span class="chip t-resist">Resist <span class="delta">${fmtDelta(card.tracks.resist)}</span></span>`;
1444
+ if (card.tracks.indust != null) outcomesHTML += `<span class="chip t-indust">Indust <span class="delta">${fmtDelta(card.tracks.indust)}</span></span>`;
1445
+ }
1446
+ c.innerHTML = `
1447
+ <div class="band"><span>${deckLabel}</span><span class="num">№ ${pad(card.id)}</span></div>
1448
+ <div class="alert">${alertText}</div>
1449
+ <div class="title"><div class="name">${card.name}</div></div>
1450
+ <div class="affects">${affectsHTML}${tagsHTML}</div>
1451
+ <div class="effect"><div>${card.effect}</div></div>
1452
+ <div class="outcomes">${outcomesHTML}</div>
1453
+ <div class="foot"><span class="code">${deckCode}-${pad(card.id)}</span><span class="deck-mark">${svgUse(deckIcon)}<span>${deckCode}</span></span></div>`;
1454
+ return c;
1455
+ }
1456
+
1457
+ /* =====================================================================
1458
+ ACTS + ROLES
1459
+ ===================================================================== */
1460
+ function renderAct(a) {
1461
+ const c = el('div', `act ${a.voting ? 'voting' : ''}`);
1462
+ const lapText = a.voting ? 'Voting · §' : `Lap ${a.lap}`;
1463
+ const code = a.voting ? 'AC-VOTE' : `AC-${pad(a.id)}`;
1464
+ c.innerHTML = `
1465
+ <div class="head"><span>Act of Congress</span><span class="lap">${lapText}</span></div>
1466
+ <div class="body">
1467
+ <div class="lap-mark"><span class="roman">${a.roman}</span><span>${a.voting ? 'Procedure' : 'Lap ' + a.lap + ' · Federal Act'}</span></div>
1468
+ <div class="name">${a.name}</div>
1469
+ <div class="effect">${a.effect}</div>
1470
+ </div>
1471
+ ${a.voting ? '' : `<div class="vote"><div class="stamp">VOTE<span class="sub">Majority</span></div><div class="text"><span class="key">All players vote</span><span>Majority passes · ties fail · failed Acts return one lap later.</span></div></div>`}
1472
+ <div class="foot"><span class="code">${code}</span><span class="icon">${svgUse(a.icon)}<span>${a.voting ? 'Procedure' : 'Federal Act'}</span></span></div>`;
1473
+ return c;
1474
+ }
1475
+ function renderRole(r) {
1476
+ const c = el('div', 'role');
1477
+ c.innerHTML = `
1478
+ <div class="head"><span>Role</span><span class="num">No. ${pad(r.id)}</span></div>
1479
+ <div class="title"><div class="name">${r.name}</div><div class="crest">${svgUse(r.icon)}</div></div>
1480
+ <div class="body"><span class="specialty-label">${r.specialty}</span><p class="ability">${r.ability}</p></div>
1481
+ <div class="reminders"><h3>Universal</h3><ul>${REMINDERS.map(t=>`<li>${t}</li>`).join('')}</ul></div>
1482
+ <div class="foot"><span class="code">RL-${pad(r.id)}</span><span>Sovereign · The Hamilton System</span></div>`;
1483
+ return c;
1484
+ }
1485
+
1486
+ /* =====================================================================
1487
+ NOTES / TOKENS / TRACKER
1488
+ ===================================================================== */
1489
+ let SERIAL = 1000;
1490
+ function nextSerial() { SERIAL += 7; return 'FC' + String(SERIAL).padStart(6, '0'); }
1491
+ function renderNote(n) {
1492
+ const c = el('div', `note d-${n.val}`);
1493
+ c.innerHTML = `
1494
+ <div class="lh"><span class="denom">${n.val}</span><span class="unit">TN</span></div>
1495
+ <div class="body">
1496
+ <span class="brand">Sovereign · The Hamilton System</span>
1497
+ <div class="title-row"><span>Treasury Note</span><span class="play">Play Money</span></div>
1498
+ <span class="serial">№ ${nextSerial()}</span>
1499
+ <span class="disclaimer">${n.words} · No Legal Value</span>
1500
+ </div>
1501
+ <div class="rh"><div class="seal">${svgUseRaw('seal-mark')}</div><span class="echo">${n.val}</span><span class="echo-unit">TN</span></div>`;
1502
+ return c;
1503
+ }
1504
+ function renderUpgrade(t) {
1505
+ const c = el('div', `tok-up ${t.cls}`);
1506
+ c.innerHTML = `<span class="label">Upgrade</span><span class="roman">${t.roman}<span class="ord">Tier ${t.roman}</span></span><span class="brand">Sovereign · The Hamilton System</span>`;
1507
+ return c;
1508
+ }
1509
+ function renderInfluence() {
1510
+ const c = el('div', 'tok-inf');
1511
+ c.innerHTML = `<div class="seal">${svgUse('icon-influence')}</div><span class="name">Influence</span><span class="val">1<span class="x">point</span></span>`;
1512
+ return c;
1513
+ }
1514
+ function renderTrackScale(scaleEl, key) {
1515
+ const def = TRACK_DEFS[key];
1516
+ for (let i = 0; i <= 12; i++) {
1517
+ const major = (i % 3 === 0);
1518
+ const isStart = (i === def.start);
1519
+ const tick = el('div', `tick${major?' major':''}${isStart?' start':''}`);
1520
+ tick.textContent = i;
1521
+ if (isStart) {
1522
+ const pip = el('div', 'start-pip');
1523
+ pip.textContent = 'start';
1524
+ tick.appendChild(pip);
1525
+ }
1526
+ const thr = def.thresholds.find(t => t.tick === i);
1527
+ if (thr) {
1528
+ const th = el('div', 'threshold');
1529
+ th.textContent = thr.label;
1530
+ tick.appendChild(th);
1531
+ }
1532
+ scaleEl.appendChild(tick);
1533
+ }
1534
+ }
1535
+
1536
+ /* =====================================================================
1537
+ SHEET HELPERS
1538
+ ===================================================================== */
1539
+ function addCropMarks(grid, cols, rows, cellW, cellH) {
1540
+ for (let r = 0; r <= rows; r++) {
1541
+ for (let c = 0; c <= cols; c++) {
1542
+ const m = el('div', 'crop-mark');
1543
+ m.style.left = `${c * cellW}in`;
1544
+ m.style.top = `${r * cellH}in`;
1545
+ m.style.transform = 'translate(-50%, -50%)';
1546
+ grid.appendChild(m);
1547
+ }
1548
+ }
1549
+ }
1550
+ function sheet(klass, html) {
1551
+ const s = el('section', 'page ' + (klass || ''));
1552
+ s.innerHTML = html;
1553
+ return s;
1554
+ }
1555
+ function head(left, sigil, right) {
1556
+ return `<div class="sheet-head"><span class="brand-mark">SOVEREIGN</span><span class="sigil">${left}${sigil ? ' · ' + sigil : ''}</span><span>${right}</span></div>`;
1557
+ }
1558
+
1559
+ /* =====================================================================
1560
+ SHEET BUILDERS
1561
+ ===================================================================== */
1562
+ const TOTAL_SHEETS = 34;
1563
+
1564
+ function sheetCover() {
1565
+ const s = sheet('', head('Sovereign · The Hamilton System Board Game', 'Series of MMXXVI · prototype master', '1 / ' + TOTAL_SHEETS));
1566
+ s.innerHTML += `
1567
+ <div class="cover-lockup">
1568
+ <div class="cover-eyebrow">The Hamilton System Board Game</div>
1569
+ <h1 class="cover-title">Sovereign</h1>
1570
+ <div class="cover-tag">Founding Credit: <em>Fund the debt. Build the bank. Industrialize the republic.</em></div>
1571
+ <div class="cover-eyebrow" style="font-size:9px;letter-spacing:.22em;margin-top:8px;opacity:.75">v0.2 balance candidate · derived from corrected economy audit FC-EM-002</div>
1572
+ </div>
1573
+ <p class="cover-sub">A prototype pack for the browser and the printer. Twenty-eight <strong>asset cards</strong> — 22 Property cards, 4 Routes, 2 Institutions — plus two event decks, seven Acts of Congress, four player roles, three shared tracks, six denominations of play money, and the tokens that knit them together. Thirty-four US Letter sheets.</p>
1574
+ <div class="cover-cols">
1575
+ <div>
1576
+ <h3>Print when you want it · digital when you don't</h3>
1577
+ <ul>
1578
+ <li>Paper: <strong>US Letter</strong>, 60 lb cardstock when printing.</li>
1579
+ <li>Scale: <strong>100 %</strong>. Margins: minimum.</li>
1580
+ <li>Board prints across 4 tiled sheets (A – D).</li>
1581
+ <li>Card sheets are 9-up; Acts &amp; Roles are 4-up.</li>
1582
+ <li>Grayscale-safe: every system has a unique pattern.</li>
1583
+ <li>Card backs are <strong>optional</strong> — sheets 30 – 34, one design per deck.</li>
1584
+ </ul>
1585
+ <h3 style="margin-top:14px">Bill of materials</h3>
1586
+ <ul>
1587
+ <li><strong>1 board</strong> · 17 in × 17 in (4 tiles, plus digital overview)</li>
1588
+ <li><strong>22 Property cards</strong> · <strong>4 Routes</strong> · <strong>2 Institutions</strong> — 28 total asset cards · plus 8 system reference cards</li>
1589
+ <li><strong>24 event cards</strong> · 12 Market Shock · 12 Republic Debate</li>
1590
+ <li><strong>7 Acts</strong> + 1 voting reference · <strong>4 Roles</strong></li>
1591
+ <li><strong>1 track board</strong> · 3 marker discs to cut</li>
1592
+ <li><strong>126 Treasury Notes</strong> (21 of each denomination)</li>
1593
+ <li><strong>75 Upgrade tokens</strong> · <strong>40 Influence tokens</strong></li>
1594
+ </ul>
1595
+ </div>
1596
+ <div>
1597
+ <h3>System legend</h3>
1598
+ <div class="legend-grid" id="cover-legend"></div>
1599
+ <p style="font-family:var(--mono);font-size:9px;opacity:.8;margin-top:6px">Routes &amp; Institutions share an ink-on-parchment band — the icon does the categorical work.</p>
1600
+ <h3 style="margin-top:14px">Setup at a glance</h3>
1601
+ <ul>
1602
+ <li>Deal <strong>1 500 TN</strong> to each of <strong>3 – 4 players</strong>.</li>
1603
+ <li>Place Credit at <strong>5</strong>, Resistance at <strong>2</strong>, Capacity at <strong>1</strong>.</li>
1604
+ <li>Shuffle each event deck; place Act stack in lap order.</li>
1605
+ <li>Each player chooses a <strong>Role</strong>. Start on Treasury Opens.</li>
1606
+ </ul>
1607
+ </div>
1608
+ </div>
1609
+ <div class="contents"><table id="cover-toc"></table></div>`;
1610
+ return s;
1611
+ }
1612
+
1613
+ function sheetBoardTile(quad, sheetNo, label, sideTxt) {
1614
+ const s = sheet('page-tile', '');
1615
+ s.innerHTML = `
1616
+ <div class="tile-strip">
1617
+ <div>
1618
+ <div class="legend">Sovereign · Tiled Board · sheet ${sheetNo} of ${TOTAL_SHEETS} · print tile — assemble with A/B/C/D · use Digital Board Overview for full-board inspection</div>
1619
+ <h2>${label}</h2>
1620
+ <div class="sub">${sideTxt}</div>
1621
+ </div>
1622
+ <div class="quad-id">QUAD ${quad.toUpperCase()}</div>
1623
+ </div>
1624
+ <div class="tile-window" data-quad="${quad}">
1625
+ <div class="board"></div>
1626
+ <div class="crop tl"></div><div class="crop tr"></div>
1627
+ <div class="crop bl"></div><div class="crop br"></div>
1628
+ </div>`;
1629
+ renderBoardInto(s.querySelector('.board'));
1630
+ return s;
1631
+ }
1632
+
1633
+ function sheetPropertyCards(label, sheetNo, picker) {
1634
+ const s = sheet('', head(label, 'Trim along crop marks · 2½ × 3½ in', `${sheetNo} / ${TOTAL_SHEETS}`));
1635
+ const g = el('div', 'grid');
1636
+ picker(g);
1637
+ addCropMarks(g, 3, 3, 2.5, 3.5);
1638
+ s.appendChild(g);
1639
+ return s;
1640
+ }
1641
+
1642
+ function sheetBackPage(label, sigil, sheetNo, builder) {
1643
+ const s = sheet('', head(label, sigil, `${sheetNo} / ${TOTAL_SHEETS}`));
1644
+ const g = el('div', 'grid');
1645
+ for (let i = 0; i < 9; i++) g.appendChild(builder());
1646
+ addCropMarks(g, 3, 3, 2.5, 3.5);
1647
+ s.appendChild(g);
1648
+ return s;
1649
+ }
1650
+
1651
+ function sheetEventCards(label, sheetNo, picker) {
1652
+ const s = sheet('', head(label, 'Event card sheet', `${sheetNo} / ${TOTAL_SHEETS}`));
1653
+ const g = el('div', 'grid');
1654
+ picker(g);
1655
+ addCropMarks(g, 3, 3, 2.5, 3.5);
1656
+ s.appendChild(g);
1657
+ return s;
1658
+ }
1659
+
1660
+ function sheetActs(label, sheetNo, picker) {
1661
+ const s = sheet('', head(label, 'Acts of Congress · flipped in lap order', `${sheetNo} / ${TOTAL_SHEETS}`));
1662
+ const g = el('div', 'grid-acts');
1663
+ picker(g);
1664
+ addCropMarks(g, 2, 2, 3.5, 5);
1665
+ s.appendChild(g);
1666
+ return s;
1667
+ }
1668
+
1669
+ function sheetRoles(sheetNo) {
1670
+ const s = sheet('', head('Role Cards · 1 – 4', 'Choose one per player', `${sheetNo} / ${TOTAL_SHEETS}`));
1671
+ const g = el('div', 'grid-acts');
1672
+ ROLES.forEach(r => g.appendChild(renderRole(r)));
1673
+ addCropMarks(g, 2, 2, 3.5, 5);
1674
+ s.appendChild(g);
1675
+ return s;
1676
+ }
1677
+
1678
+ function sheetTracker(sheetNo) {
1679
+ const s = sheet('', head('Shared Track Board', 'Tracks affect everyone · caps at 12', `${sheetNo} / ${TOTAL_SHEETS}`));
1680
+ s.innerHTML += `
1681
+ <div class="tracker">
1682
+ <div class="tk-head"><h2>Shared Tracks</h2><div class="sigil">Public Credit · Public Resistance · Industrial Capacity</div></div>
1683
+ <p class="tk-intro">Three numeric tracks the whole table watches. Move the matching marker by ± steps as cards and Acts direct. Each track has thresholds that change the rules of the game while the marker sits at or past them.</p>
1684
+ <div class="tk-row credit">
1685
+ <div class="label"><span class="tag">Track I</span><span class="name">Public Credit</span><span class="starts">starts at 5 · cap 12</span></div>
1686
+ <div class="scale" data-track="credit"></div>
1687
+ <div class="effects"><ul><li><strong>Credit ≤ 2</strong> · foreign loans stop paying. Routes pay half.</li><li><strong>Credit = 0</strong> · <em>Default</em>. Every player loses 50 % cash + 1 random upgrade. Credit resets to 3.</li></ul></div>
1688
+ </div>
1689
+ <div class="tk-row resist">
1690
+ <div class="label"><span class="tag">Track II</span><span class="name">Public Resistance</span><span class="starts">starts at 2 · cap 12</span></div>
1691
+ <div class="scale" data-track="resist"></div>
1692
+ <div class="effects"><ul><li><strong>Resist ≥ 8</strong> · Whiskey Rebellion card becomes live.</li><li><strong>Resist = 12</strong> · <em>Rebellion</em>. All Revenue upgrades destroyed. Whiskey Excise owner → Crisis. Resets to 6.</li></ul></div>
1693
+ </div>
1694
+ <div class="tk-row indust">
1695
+ <div class="label"><span class="tag">Track III</span><span class="name">Industrial Capacity</span><span class="starts">starts at 1 · cap 12</span></div>
1696
+ <div class="scale" data-track="indust"></div>
1697
+ <div class="effects"><ul><li><strong>Capacity ≥ 6</strong> &middot; Manufactures &amp; Strategic payments +25 %.</li><li><strong>Capacity ≥ 8</strong> &middot; those owners each gain +2 Influence at game end.</li></ul></div>
1698
+ </div>
1699
+ <div class="marker-set">
1700
+ <div><h3>How to use this board</h3><p>Cut out the three marker discs at right. Place each on its starting tick. Move along the scale as effects fire. The marker is the canonical record of each track's current value.</p></div>
1701
+ <div class="marker-row"><div class="marker credit">Credit</div><div class="marker resist">Resist</div><div class="marker indust">Indust</div></div>
1702
+ </div>
1703
+ <div class="passed-acts-tray">
1704
+ <div class="tray-head"><span class="tray-eyebrow">Tray</span><span class="tray-title">Passed Acts — place face-up here</span></div>
1705
+ <div class="tray-row">
1706
+ <div class="tray-slot"><span class="slot-roman">I</span><span class="slot-name">Funding</span></div>
1707
+ <div class="tray-slot"><span class="slot-roman">II</span><span class="slot-name">Assumption</span></div>
1708
+ <div class="tray-slot"><span class="slot-roman">III</span><span class="slot-name">Bank Charter</span></div>
1709
+ <div class="tray-slot"><span class="slot-roman">IV</span><span class="slot-name">Tariff</span></div>
1710
+ <div class="tray-slot"><span class="slot-roman">V</span><span class="slot-name">Coinage</span></div>
1711
+ <div class="tray-slot"><span class="slot-roman">VI</span><span class="slot-name">Manufactures</span></div>
1712
+ <div class="tray-slot"><span class="slot-roman">VII</span><span class="slot-name">Excise</span></div>
1713
+ </div>
1714
+ </div>
1715
+ </div>`;
1716
+ s.querySelectorAll('[data-track]').forEach(scaleEl => renderTrackScale(scaleEl, scaleEl.dataset.track));
1717
+ return s;
1718
+ }
1719
+
1720
+ function sheetNote(denom, sheetNo) {
1721
+ const note = NOTES.find(n => n.val === denom);
1722
+ const s = sheet('', head(`Treasury Notes · ${denom} TN`, '21 notes per sheet · trim along borders', `${sheetNo} / ${TOTAL_SHEETS}`));
1723
+ const g = el('div', 'grid-notes');
1724
+ for (let i = 0; i < 21; i++) g.appendChild(renderNote(note));
1725
+ addCropMarks(g, 3, 7, 2.625, 1.375);
1726
+ s.appendChild(g);
1727
+ return s;
1728
+ }
1729
+
1730
+ function sheetUpgrade(tier, sheetNo) {
1731
+ const s = sheet('', head(`Upgrade Tokens · Tier ${tier.roman}`, '25 tokens per sheet · trim along borders', `${sheetNo} / ${TOTAL_SHEETS}`));
1732
+ const g = el('div', 'grid-upgrade');
1733
+ for (let i = 0; i < 25; i++) g.appendChild(renderUpgrade(tier));
1734
+ addCropMarks(g, 5, 5, 1.25, 1.25);
1735
+ s.appendChild(g);
1736
+ return s;
1737
+ }
1738
+
1739
+ function sheetInfluence(sheetNo) {
1740
+ const s = sheet('', head('Influence Tokens', '40 tokens · scored at game end', `${sheetNo} / ${TOTAL_SHEETS}`));
1741
+ const g = el('div', 'grid-influence');
1742
+ for (let i = 0; i < 40; i++) g.appendChild(renderInfluence());
1743
+ addCropMarks(g, 8, 5, 1, 1);
1744
+ s.appendChild(g);
1745
+ return s;
1746
+ }
1747
+
1748
+ /* =====================================================================
1749
+ RULES + PRIMER — placeholder, filled by separate inline script
1750
+ ===================================================================== */
1751
+ function sheetRules1(sheetNo) {
1752
+ const s = sheet('', head('Rules of Play · 1 / 2', 'Read this side before your first game', `${sheetNo} / ${TOTAL_SHEETS}`));
1753
+ s.innerHTML += window.__RULES_1 || '';
1754
+ return s;
1755
+ }
1756
+ function sheetRules2(sheetNo) {
1757
+ const s = sheet('', head('Rules of Play · 2 / 2', 'Influence scoring · end conditions', `${sheetNo} / ${TOTAL_SHEETS}`));
1758
+ s.innerHTML += window.__RULES_2 || '';
1759
+ return s;
1760
+ }
1761
+ function sheetPrimer(sheetNo) {
1762
+ const s = sheet('', head('Historical Primer', 'How Hamilton actually built the system', `${sheetNo} / ${TOTAL_SHEETS}`));
1763
+ s.innerHTML += window.__PRIMER || '';
1764
+ return s;
1765
+ }
1766
+
1767
+ /* =====================================================================
1768
+ ASSEMBLE
1769
+ ===================================================================== */
1770
+ const vp = document.getElementById('viewport');
1771
+
1772
+ const SHEETS = [
1773
+ sheetCover,
1774
+ () => sheetBoardTile('br', 2, 'Board Tile A', 'Bottom-Right · Side I (War Debt) · Treasury Opens'),
1775
+ () => sheetBoardTile('bl', 3, 'Board Tile B', 'Bottom-Left · Side I + corner 10 · Constitutional Crisis'),
1776
+ () => sheetBoardTile('tl', 4, 'Board Tile C', 'Top-Left · Side II + corner 20 · National Dividend'),
1777
+ () => sheetBoardTile('tr', 5, 'Board Tile D', 'Top-Right · Side III + corner 30 · Go to Crisis'),
1778
+ () => sheetPropertyCards('Property Cards · 1 / 4', 6, g => { for (let i=1;i<=9;i++) g.appendChild(renderProperty(PROPS[i-1])); }),
1779
+ () => sheetPropertyCards('Property Cards · 2 / 4', 7, g => { for (let i=10;i<=18;i++) g.appendChild(renderProperty(PROPS[i-1])); }),
1780
+ () => sheetPropertyCards('Property Cards · 3 / 4', 8, g => {
1781
+ for (let i=19;i<=22;i++) g.appendChild(renderProperty(PROPS[i-1]));
1782
+ ROUTES.forEach(r => g.appendChild(renderRoute(r)));
1783
+ g.appendChild(renderInstitution(INSTS[0]));
1784
+ }),
1785
+ () => sheetPropertyCards('Property Cards · 4 / 4', 9, g => {
1786
+ g.appendChild(renderInstitution(INSTS[1]));
1787
+ Object.keys(SYS).forEach(k => g.appendChild(renderReference(k)));
1788
+ }),
1789
+ () => sheetEventCards('Event Cards · 1 / 3 · Market Shock 01–09', 10, g => MARKET_SHOCK.slice(0,9).forEach(c => g.appendChild(renderEventCard(c,'shock')))),
1790
+ () => sheetEventCards('Event Cards · 2 / 3 · Market 10–12 + Debate 01–06', 11, g => {
1791
+ MARKET_SHOCK.slice(9).forEach(c => g.appendChild(renderEventCard(c,'shock')));
1792
+ REPUBLIC_DEBATE.slice(0,6).forEach(c => g.appendChild(renderEventCard(c,'debate')));
1793
+ }),
1794
+ () => sheetEventCards('Event Cards · 3 / 3 · Republic Debate 07–12', 12, g => REPUBLIC_DEBATE.slice(6).forEach(c => g.appendChild(renderEventCard(c,'debate')))),
1795
+ () => sheetActs('Acts of Congress · 1 / 2', 13, g => ACTS.slice(0,4).forEach(a => g.appendChild(renderAct(a)))),
1796
+ () => sheetActs('Acts of Congress · 2 / 2 + Voting Reference', 14, g => { ACTS.slice(4).forEach(a => g.appendChild(renderAct(a))); g.appendChild(renderAct(VOTING_REF)); }),
1797
+ () => sheetRoles(15),
1798
+ () => sheetTracker(16),
1799
+ () => sheetNote(1, 17),
1800
+ () => sheetNote(5, 18),
1801
+ () => sheetNote(10, 19),
1802
+ () => sheetNote(50, 20),
1803
+ () => sheetNote(100, 21),
1804
+ () => sheetNote(500, 22),
1805
+ () => sheetUpgrade(TIERS[0], 23),
1806
+ () => sheetUpgrade(TIERS[1], 24),
1807
+ () => sheetUpgrade(TIERS[2], 25),
1808
+ () => sheetInfluence(26),
1809
+ () => sheetRules1(27),
1810
+ () => sheetRules2(28),
1811
+ () => sheetPrimer(29),
1812
+ /* === OPTIONAL CARD BACKS — separate sheets, single-sided play still works === */
1813
+ () => sheetBackPage('Card Backs · 1 / 5 · Charter & Asset', 'For Property / Route / Institution cards (sheets 6 – 9) — print ~4 copies for full coverage', 30, renderCharterBack),
1814
+ () => sheetBackPage('Card Backs · 2 / 5 · Market Shock', 'For Market Shock cards (sheets 10 – 11) — print ~2 copies for full coverage', 31, renderShockBack),
1815
+ () => sheetBackPage('Card Backs · 3 / 5 · Republic Debate','For Republic Debate cards (sheets 11 – 12) — print ~2 copies for full coverage', 32, renderDebateBack),
1816
+ () => sheetBackPage('Card Backs · 4 / 5 · Acts of Congress','For Acts cards (sheets 13 – 14) — print 1 copy', 33, renderActBack),
1817
+ () => sheetBackPage('Card Backs · 5 / 5 · Founder Role', 'For Role cards (sheet 15) — print 1 copy', 34, renderRoleBack),
1818
+ ];
1819
+
1820
+ SHEETS.forEach(fn => vp.appendChild(fn()));
1821
+
1822
+ /* Cover legend + TOC */
1823
+ const legend = document.getElementById('cover-legend');
1824
+ if (legend) {
1825
+ Object.entries(SYS).forEach(([k, sys]) => {
1826
+ const cnt = PROPS.filter(p => p.sys === k).length;
1827
+ const row = el('div', 'legend-row');
1828
+ row.innerHTML = `<div class="sw" style="background: var(--${k})"></div><div class="ic">${svgUse(sys.icon)}</div><div class="nm">${sys.label} <span style="font-family:var(--mono);font-size:9px;opacity:.7">${cnt} card${cnt!==1?'s':''}</span></div>`;
1829
+ legend.appendChild(row);
1830
+ });
1831
+ }
1832
+ const toc = document.getElementById('cover-toc');
1833
+ if (toc) {
1834
+ const rows = [
1835
+ ['Sheet 1','Cover · system legend · setup · digital map','this page'],
1836
+ ['Sheets 2 – 5','Board · 4 tiled US Letter quadrants','17 × 17 in board'],
1837
+ ['Sheets 6 – 9','Property · Route · Institution cards','28 asset · 9-up'],
1838
+ ['Sheets 10 – 12','Event decks · Market Shock + Republic Debate','24 cards'],
1839
+ ['Sheets 13 – 14','Acts of Congress · 7 + voting reference','8 cards'],
1840
+ ['Sheet 15','Founder Role cards','4 cards'],
1841
+ ['Sheet 16','Shared Track Board','3 tracks + markers'],
1842
+ ['Sheets 17 – 22','Treasury Notes · 1/5/10/50/100/500 TN','126 notes'],
1843
+ ['Sheets 23 – 25','Upgrade tokens · Tier I/II/III','75 tokens'],
1844
+ ['Sheet 26','Influence tokens','40 tokens'],
1845
+ ['Sheets 27 – 28','Rules of Play','2 pages'],
1846
+ ['Sheet 29','Historical primer','1 page'],
1847
+ ['Sheets 30 – 34','Optional card backs · 5 distinct designs','print as needed'],
1848
+ ];
1849
+ toc.innerHTML = rows.map(r => `<tr><td>${r[0]}</td><td>${r[1]}</td><td>${r[2]}</td></tr>`).join('');
1850
+ }
1851
+
1852
+ /* =====================================================================
1853
+ DIGITAL REVIEW MODE — screen-only nav, jump links, section dividers
1854
+ ===================================================================== */
1855
+ (function buildDigitalReview() {
1856
+ const SECTIONS = [
1857
+ { id:'sec-cover', label:'Cover', sheets:'1', page: 0 },
1858
+ { id:'sec-board', label:'Board Tiles', sheets:'2 – 5', page: 1 },
1859
+ { id:'sec-prop', label:'Asset Cards', sheets:'6 – 9', page: 5 },
1860
+ { id:'sec-event', label:'Event Cards', sheets:'10 – 12', page: 9 },
1861
+ { id:'sec-acts', label:'Acts of Congress', sheets:'13 – 14', page: 12 },
1862
+ { id:'sec-roles', label:'Roles', sheets:'15', page: 14 },
1863
+ { id:'sec-tracks', label:'Track Board', sheets:'16', page: 15 },
1864
+ { id:'sec-money', label:'Treasury Notes', sheets:'17 – 22', page: 16 },
1865
+ { id:'sec-tokens', label:'Tokens', sheets:'23 – 26', page: 22 },
1866
+ { id:'sec-rules', label:'Rules', sheets:'27 – 28', page: 26 },
1867
+ { id:'sec-primer', label:'Historical Primer', sheets:'29', page: 28 },
1868
+ { id:'sec-backs', label:'Card Backs', sheets:'30 – 34', page: 29 },
1869
+ ];
1870
+ const pages = vp.querySelectorAll('.page');
1871
+ SECTIONS.forEach(sec => { if (pages[sec.page]) pages[sec.page].id = sec.id; });
1872
+
1873
+ const nav = document.createElement('nav');
1874
+ nav.className = 'digital-nav';
1875
+ nav.innerHTML = `
1876
+ <div class="dn-head">
1877
+ <div class="dn-eyebrow">Digital Review Mode</div>
1878
+ <div class="dn-title">Sovereign</div>
1879
+ <div class="dn-sub">The Hamilton System Board Game · prototype pack</div>
1880
+ </div>
1881
+ <div class="dn-links">
1882
+ ${SECTIONS.map(s => `<a href="#${s.id}"><span class="dn-label">${s.label}</span><span class="dn-sheets">${s.sheets}</span></a>`).join('')}
1883
+ </div>
1884
+ <div class="dn-foot">
1885
+ <span>Click any link to jump to that section.</span>
1886
+ <span>This nav hides automatically on print.</span>
1887
+ </div>`;
1888
+ vp.insertBefore(nav, vp.firstChild);
1889
+
1890
+ /* ----- Digital Board Overview (screen-only) ----- */
1891
+ const SECTIONS_NAV = [
1892
+ { id:'sec-cover', label:'Cover', sheets:'1' },
1893
+ { id:'sec-overview', label:'Board Overview', sheets:'digital-only' },
1894
+ { id:'sec-board', label:'Board Tiles', sheets:'2 – 5' },
1895
+ { id:'sec-prop', label:'Asset Cards', sheets:'6 – 9' },
1896
+ { id:'sec-event', label:'Event Cards', sheets:'10 – 12' },
1897
+ { id:'sec-acts', label:'Acts of Congress', sheets:'13 – 14' },
1898
+ { id:'sec-roles', label:'Roles', sheets:'15' },
1899
+ { id:'sec-tracks', label:'Track Board', sheets:'16' },
1900
+ { id:'sec-money', label:'Treasury Notes', sheets:'17 – 22' },
1901
+ { id:'sec-tokens', label:'Tokens', sheets:'23 – 26' },
1902
+ { id:'sec-rules', label:'Rules', sheets:'27 – 28' },
1903
+ { id:'sec-primer', label:'Historical Primer', sheets:'29' },
1904
+ { id:'sec-backs', label:'Card Backs', sheets:'30 – 34' },
1905
+ ];
1906
+ const linksRoot = nav.querySelector('.dn-links');
1907
+ linksRoot.innerHTML = SECTIONS_NAV.map(s => `<a href="#${s.id}"><span class="dn-label">${s.label}</span><span class="dn-sheets">${s.sheets}</span></a>`).join('');
1908
+
1909
+ const overview = document.createElement('section');
1910
+ overview.className = 'board-overview';
1911
+ overview.id = 'sec-overview';
1912
+ overview.innerHTML = `
1913
+ <div class="bo-head">
1914
+ <div>
1915
+ <div class="bo-eyebrow">Digital Board Overview</div>
1916
+ <div class="bo-sub">The assembled 17 × 17 in board, screen-only · print sheets 2 – 5 for the physical playing surface.</div>
1917
+ </div>
1918
+ <div class="bo-eyebrow" style="opacity:.65">Digital-only</div>
1919
+ </div>
1920
+ <div class="bo-stage"><div class="board"></div></div>
1921
+ <div class="bo-note"><span>Tiles A / B / C / D → sheets 2 – 5</span><span>Same render pipeline as print</span></div>`;
1922
+ const coverPage = pages[0];
1923
+ coverPage.parentNode.insertBefore(overview, coverPage.nextSibling);
1924
+ renderBoardInto(overview.querySelector('.bo-stage .board'));
1925
+
1926
+ const applyBoardScale = () => {
1927
+ const stage = overview.querySelector('.bo-stage');
1928
+ const boardEl = stage.querySelector('.board');
1929
+ if (!stage || !boardEl) return;
1930
+ const scale = stage.offsetWidth / (17 * 96);
1931
+ boardEl.style.transform = `scale(${scale})`;
1932
+ };
1933
+ applyBoardScale();
1934
+ window.addEventListener('resize', applyBoardScale);
1935
+ })();
1936
+ </script>
1937
+
1938
+ </body>
1939
+ </html>