kryptheon 0.1.21 → 0.1.23

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.
@@ -1,446 +1,378 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="utf-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1">
6
- <meta name="kryptheon-token" content="%%TOKEN%%">
7
- <title>Kryptheon</title>
8
- <link rel="icon" href="/logo.png">
9
- <style>
10
- /* Sunset: a warm white ground that turns to peach towards the bottom, soft
11
- raised surfaces with a warm shadow, and orange used for Kryptheon itself.
12
- Meaning has its own colours - ember for broken, amber for "look at this",
13
- leaf for held and fixed - so orange never has to mean "bad". Nothing is
14
- loaded from anywhere else; the logo is served by this same server. */
15
- :root {
16
- --paper: #fffaf5;
17
- --paper-2: #fcf1e7;
18
- --paper-3: #f7e4d4;
19
- --ink: #2d1e17;
20
- --muted: #8a6d5e;
21
- --faint: #b39889;
22
- --sun: #ec7433;
23
- --sun-soft: #f7a26c;
24
- --sun-deep: #c6571f;
25
- --gold: #d49b33;
26
- --ember: #c2412d;
27
- --amber: #a8720f;
28
- --leaf: #3b8657;
29
- --dusk: #6d4a7c;
30
- --raised: 10px 12px 28px rgba(199, 118, 66, 0.20), -8px -8px 20px rgba(255, 255, 255, 0.95);
31
- --raised-sm: 5px 6px 13px rgba(199, 118, 66, 0.20), -4px -4px 10px rgba(255, 255, 255, 0.9);
32
- --sunken: inset 3px 4px 9px rgba(199, 118, 66, 0.18), inset -3px -3px 8px rgba(255, 255, 255, 0.85);
33
- --display: "Baloo 2", "Nunito", ui-rounded, "Segoe UI Variable Display", "Segoe UI", system-ui, sans-serif;
34
- --serif: "Cormorant Garamond", "Cormorant", "Palatino Linotype", Palatino, Georgia, serif;
35
- --body: "Figtree", ui-sans-serif, "Segoe UI Variable Text", "Segoe UI", system-ui, sans-serif;
36
- --mono: ui-monospace, "Cascadia Code", Consolas, monospace;
37
- }
38
- * { box-sizing: border-box; }
39
- html { -webkit-text-size-adjust: 100%; }
40
- body {
41
- margin: 0; color: var(--ink); font: 14px/1.55 var(--body); min-height: 100vh;
42
- background: #fdf1e6 linear-gradient(170deg, #fffbf7 0%, #fff3e8 38%, #fde3cf 78%, #f9d2b8 100%) fixed;
43
- }
44
- button { font: inherit; color: inherit; }
45
- .shell { max-width: 1400px; margin: 0 auto; padding: 22px; display: grid; grid-template-columns: 250px minmax(0, 1fr); gap: 26px; align-items: start; }
46
- @media (max-width: 900px) { .shell { grid-template-columns: minmax(0, 1fr); padding: 16px; gap: 18px; } }
47
-
48
- /* Materials */
49
- .raised { background: var(--paper); border-radius: 24px; box-shadow: var(--raised); }
50
- .sunken { background: var(--paper-2); box-shadow: var(--sunken); }
51
-
52
- /* The marker: what matters most in a sentence gets a sunset highlight. */
53
- .hl { font-weight: 700; color: var(--ink); text-decoration: underline; text-decoration-color: rgba(236, 116, 51, 0.85); text-decoration-thickness: 3px; text-underline-offset: 4px; text-decoration-skip-ink: none; }
54
- .ul { text-decoration: underline; text-decoration-color: var(--sun); text-decoration-thickness: 2px; text-underline-offset: 4px; font-weight: 700; }
55
-
56
- /* Sidebar */
57
- .side { position: sticky; top: 22px; padding: 20px 14px; display: flex; flex-direction: column; gap: 16px; min-height: calc(100vh - 44px); border-radius: 26px; }
58
- @media (max-width: 900px) { .side { position: static; min-height: 0; } }
59
- .brand { display: flex; align-items: center; gap: 12px; padding: 0 6px; }
60
- .brand img { width: 50px; height: 50px; border-radius: 16px; background: #0b0b0b; box-shadow: 6px 7px 16px rgba(80, 40, 20, 0.35), -4px -4px 10px rgba(255, 255, 255, 0.9); flex: none; }
61
- .wordmark { font-family: var(--serif); font-weight: 600; font-size: 19px; letter-spacing: 0.1em; line-height: 1; min-width: 0; }
62
- .wordmark .dot { color: var(--gold); }
63
- .wordmark small { display: block; font-family: var(--body); font-weight: 500; font-size: 11px; letter-spacing: 0.02em; color: var(--muted); margin-top: 6px; }
64
- .nav-label { font-size: 10.5px; font-weight: 800; letter-spacing: 0.16em; color: var(--faint); padding: 0 12px; margin-bottom: 6px; }
65
- .nav { display: grid; gap: 3px; }
66
- .nav button { position: relative; display: flex; align-items: center; gap: 11px; width: 100%; border: 0; background: transparent; padding: 9px 12px; border-radius: 14px; cursor: pointer; font-weight: 600; color: var(--muted); text-align: left; transition: color 0.15s ease, background 0.15s ease; }
67
- .nav button:hover { color: var(--ink); background: rgba(247, 162, 108, 0.12); }
68
- .nav button.on { color: var(--sun-deep); background: var(--paper-2); box-shadow: var(--sunken); }
69
- .nav button.on::before { content: ""; position: absolute; left: -14px; top: 9px; bottom: 9px; width: 4px; border-radius: 0 4px 4px 0; background: var(--sun); }
70
- .nav .n-count { margin-left: auto; font-size: 11px; font-weight: 800; min-width: 22px; text-align: center; padding: 1px 7px; border-radius: 999px; background: var(--paper-3); color: var(--muted); }
71
- .nav .n-count.hot { background: var(--ember); color: #fff; }
72
- @media (max-width: 900px) { .nav { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); } .nav button.on::before { display: none; } }
73
- .built { margin-top: auto; padding: 14px; border-radius: 18px; }
74
- .built-top { display: flex; justify-content: space-between; font-size: 12px; font-weight: 600; color: var(--muted); }
75
- .built-top b { color: var(--ink); font-family: var(--display); font-size: 15px; }
76
- .meter { height: 11px; border-radius: 999px; margin-top: 10px; overflow: hidden; padding: 2px; }
77
- .meter i { display: block; height: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--gold), var(--sun)); }
78
- .built p { margin: 8px 0 0; font-size: 11.5px; color: var(--muted); }
79
- .account { display: flex; align-items: center; gap: 10px; padding: 10px; border-radius: 18px; }
80
- .avatar { width: 38px; height: 38px; flex: none; border-radius: 50%; display: grid; place-items: center; font-family: var(--display); font-weight: 800; background: linear-gradient(135deg, #ffd9b8, #f7a26c); color: #5a2a10; box-shadow: var(--raised-sm); }
81
- .account .a-name { font-weight: 700; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
82
- .account .a-sub { font-size: 11px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 160px; }
83
-
84
- /* Topbar */
85
- .top { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
86
- .top h1 { margin: 0; font-family: var(--display); font-weight: 800; font-size: 30px; line-height: 1.05; letter-spacing: -0.015em; }
87
- .top .sub { color: var(--muted); font-size: 13px; margin-top: 4px; display: flex; align-items: center; gap: 8px; }
88
- .live-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--leaf); box-shadow: 0 0 0 4px rgba(59, 134, 87, 0.15); }
89
- .top .grow { flex: 1; }
90
- .search { display: flex; align-items: center; gap: 8px; padding: 10px 16px; border-radius: 999px; min-width: 240px; color: var(--muted); }
91
- .search input { border: 0; background: transparent; outline: none; font: inherit; color: var(--ink); width: 100%; }
92
- @media (max-width: 700px) { .search { display: none; } }
93
- .bell { position: relative; width: 44px; height: 44px; border-radius: 50%; border: 0; display: grid; place-items: center; cursor: pointer; background: var(--paper); box-shadow: var(--raised-sm); color: var(--ink); }
94
- .bell .bdot { position: absolute; top: 10px; right: 11px; width: 9px; height: 9px; border-radius: 50%; background: var(--ember); border: 2px solid var(--paper); }
95
- .btn { display: inline-flex; align-items: center; gap: 8px; border: 0; border-radius: 999px; padding: 10px 18px; cursor: pointer; font-weight: 700; background: var(--paper); box-shadow: var(--raised-sm); transition: transform 0.12s ease, box-shadow 0.12s ease; white-space: nowrap; }
96
- .btn:hover:not(:disabled) { transform: translateY(-1px); }
97
- .btn:active:not(:disabled) { box-shadow: var(--sunken); transform: none; }
98
- .btn:disabled { opacity: 0.6; cursor: default; }
99
- .btn.sun { color: #fff; background: linear-gradient(135deg, #f6a064, #e5652b); box-shadow: 7px 8px 18px rgba(214, 96, 40, 0.38), -4px -4px 11px rgba(255, 255, 255, 0.85); }
100
- .btn.sm { padding: 7px 14px; font-size: 12.5px; }
101
- .spin { width: 13px; height: 13px; border-radius: 50%; border: 2px solid currentColor; border-right-color: transparent; animation: spin 0.8s linear infinite; }
102
- @keyframes spin { to { transform: rotate(360deg); } }
103
- @media (prefers-reduced-motion: reduce) { .spin { animation-duration: 3s; } .btn { transition: none; } }
104
- button:focus-visible, input:focus-visible { outline: 2px solid var(--sun); outline-offset: 3px; }
105
-
106
- /* Views: one section on screen at a time. */
107
- .view { margin-top: 22px; }
108
- .view[hidden] { display: none; }
109
- .when { display: flex; align-items: center; gap: 10px; padding: 12px 18px; border-radius: 16px; font-size: 13.5px; color: var(--muted); margin-bottom: 20px; }
110
- .when b.lbl { font-size: 10.5px; letter-spacing: 0.14em; color: var(--sun-deep); flex: none; }
111
-
112
- /* The sky: the headline card. Its sun sinks and reddens when something is broken. */
113
- .sky { position: relative; overflow: hidden; padding: 26px 28px; border-radius: 26px; display: flex; gap: 20px; align-items: center; flex-wrap: wrap; background: linear-gradient(115deg, #fffaf5 0%, #fff0e2 55%, #ffe0c8 100%); box-shadow: var(--raised); }
114
- .sky::before { content: ""; position: absolute; width: 260px; height: 260px; right: 40px; bottom: -150px; border-radius: 50%; background: radial-gradient(circle, #ffe2a8 0%, #f9b163 45%, rgba(249, 177, 99, 0) 70%); opacity: 0.9; pointer-events: none; }
115
- .sky::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 46px; background: repeating-linear-gradient(0deg, rgba(255, 250, 245, 0.75) 0 3px, transparent 3px 11px); pointer-events: none; }
116
- .sky.bad::before { background: radial-gradient(circle, #ffc38f 0%, #ef7a44 45%, rgba(214, 80, 45, 0) 72%); bottom: -170px; }
117
- .sky.ok::before { background: radial-gradient(circle, #fff1c4 0%, #ffd27a 45%, rgba(255, 210, 122, 0) 70%); bottom: -110px; }
118
- .sky > * { position: relative; z-index: 1; }
119
- .sky .s-chip { width: 58px; height: 58px; border-radius: 18px; display: grid; place-items: center; background: var(--paper); box-shadow: var(--raised-sm); flex: none; }
120
- .sky .s-text { flex: 1; min-width: 260px; }
121
- .sky .eyebrow { font-size: 11px; font-weight: 800; letter-spacing: 0.16em; color: var(--sun-deep); }
122
- .sky h2 { margin: 4px 0 0; font-family: var(--display); font-size: 28px; font-weight: 800; line-height: 1.1; }
123
- .sky p { margin: 6px 0 0; color: var(--muted); max-width: 640px; }
124
- .sky .s-actions { display: flex; gap: 10px; flex-wrap: wrap; }
125
-
126
- /* KPI tiles - each one opens the section it counts. */
127
- .kpis { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 18px; margin-top: 22px; }
128
- @media (max-width: 1100px) { .kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
129
- .kpi { padding: 18px; border-radius: 22px; border: 0; text-align: left; cursor: pointer; transition: transform 0.12s ease; width: 100%; }
130
- .kpi:hover { transform: translateY(-2px); }
131
- .kpi-top { display: flex; align-items: center; gap: 10px; }
132
- .ichip { width: 38px; height: 38px; border-radius: 50%; display: grid; place-items: center; flex: none; }
133
- .ichip.ember { background: rgba(194, 65, 45, 0.12); color: var(--ember); }
134
- .ichip.amber { background: rgba(212, 155, 51, 0.18); color: var(--amber); }
135
- .ichip.leaf { background: rgba(59, 134, 87, 0.13); color: var(--leaf); }
136
- .ichip.sun { background: rgba(236, 116, 51, 0.14); color: var(--sun-deep); }
137
- .kpi-label { font-size: 10.5px; font-weight: 800; letter-spacing: 0.13em; color: var(--muted); }
138
- .kpi-num { font-family: var(--display); font-weight: 800; font-size: 34px; line-height: 1.1; margin-top: 12px; font-variant-numeric: tabular-nums; }
139
- .kpi-foot { margin-top: 6px; min-height: 22px; display: flex; gap: 6px; flex-wrap: wrap; align-items: center; font-size: 12px; color: var(--muted); }
140
- .kpi-go { margin-top: 10px; font-size: 12px; font-weight: 700; color: var(--sun-deep); }
141
- .delta { display: inline-flex; align-items: center; gap: 4px; font-size: 11.5px; font-weight: 700; padding: 2px 9px; border-radius: 999px; background: var(--paper-2); box-shadow: var(--sunken); }
142
- .delta.up { color: var(--leaf); } .delta.down { color: var(--ember); } .delta.flat { color: var(--muted); }
143
-
144
- /* "Not sure where to look?" */
145
- .guide { padding: 22px; border-radius: 24px; margin-top: 22px; }
146
- .guide-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
147
- @media (max-width: 1000px) { .guide-list { grid-template-columns: minmax(0, 1fr); } }
148
- .g-row { display: grid; grid-template-columns: 12px minmax(0, 1fr) auto; gap: 12px; align-items: center; padding: 12px 14px; border: 0; border-radius: 16px; background: var(--paper-2); box-shadow: var(--sunken); cursor: pointer; text-align: left; font-size: 13.5px; color: var(--muted); }
149
- .g-row:hover { background: #fff5ec; }
150
- .g-row .g-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--faint); }
151
- .g-row .g-dot.hot { background: var(--ember); box-shadow: 0 0 0 4px rgba(194, 65, 45, 0.15); }
152
- .g-row .g-dot.warm { background: var(--gold); }
153
- .g-row .g-dot.cool { background: var(--leaf); }
154
- .g-row .g-to { display: flex; align-items: center; gap: 6px; font-weight: 800; color: var(--sun-deep); white-space: nowrap; font-size: 12.5px; }
155
- .g-row .g-state { display: block; font-size: 11.5px; color: var(--faint); margin-top: 2px; }
156
-
157
- /* Cards */
158
- .split { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 18px; margin-top: 22px; }
159
- @media (max-width: 1100px) { .split { grid-template-columns: minmax(0, 1fr); } }
160
- .card { padding: 22px; border-radius: 24px; min-width: 0; }
161
- .card + .card { margin-top: 18px; }
162
- .split .card + .card { margin-top: 0; }
163
- .card-head { display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap; margin-bottom: 16px; }
164
- .card-head h3 { margin: 0; font-family: var(--display); font-size: 20px; font-weight: 800; line-height: 1.15; }
165
- .card-head .c-sub { color: var(--muted); font-size: 12.5px; margin-top: 2px; }
166
- .card-head .grow { flex: 1; }
167
- .badge { font-size: 11.5px; font-weight: 800; padding: 3px 10px; border-radius: 999px; background: var(--paper-2); box-shadow: var(--sunken); color: var(--muted); }
168
- .seg { display: inline-flex; padding: 4px; border-radius: 999px; gap: 2px; }
169
- .seg button { border: 0; background: transparent; cursor: pointer; padding: 6px 14px; border-radius: 999px; font-size: 12.5px; font-weight: 700; color: var(--muted); }
170
- .seg button.on { color: #fff; background: linear-gradient(135deg, #f6a064, #e5652b); box-shadow: inset 2px 2px 5px rgba(120, 40, 0, 0.25); }
171
-
172
- /* Chart */
173
- .chart-wrap { position: relative; }
174
- .chart-wrap svg { display: block; width: 100%; height: 210px; overflow: visible; }
175
- .tip { position: absolute; transform: translate(-50%, -100%); pointer-events: none; padding: 8px 12px; border-radius: 14px; background: var(--paper); box-shadow: var(--raised-sm); white-space: nowrap; font-size: 12px; }
176
- .tip .t-date { color: var(--muted); font-weight: 600; font-size: 11px; }
177
- .tip .t-val { display: flex; align-items: center; gap: 6px; font-family: var(--display); font-weight: 800; font-size: 16px; }
178
- .tip .t-val i { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
179
- .stem { position: absolute; width: 1px; background: rgba(45, 30, 23, 0.3); transform: translateX(-50%); pointer-events: none; }
180
-
181
- /* Donut */
182
- .donut { display: grid; place-items: center; position: relative; margin: 0 0 14px; }
183
- .donut svg { width: 160px; height: 160px; }
184
- .donut .center { position: absolute; text-align: center; }
185
- .donut .center b { display: block; font-family: var(--display); font-size: 30px; font-weight: 800; line-height: 1; }
186
- .donut .center span { font-size: 12px; color: var(--muted); }
187
- .legend { display: grid; gap: 8px; }
188
- .legend .row { display: flex; align-items: center; gap: 10px; font-weight: 600; }
189
- .legend .row i { width: 11px; height: 11px; border-radius: 50%; display: inline-block; }
190
- .legend .row .v { margin-left: auto; font-family: var(--display); font-weight: 800; }
191
-
192
- /* Table */
193
- .table-scroll { overflow-x: auto; margin: 0 -6px; padding: 6px; }
194
- table { width: 100%; min-width: 880px; border-collapse: separate; border-spacing: 0 6px; font-size: 13px; }
195
- thead th { text-align: left; font-size: 10.5px; font-weight: 800; letter-spacing: 0.1em; color: var(--muted); padding: 11px 14px; background: var(--paper-2); box-shadow: var(--sunken); }
196
- thead th:first-child { border-radius: 999px 0 0 999px; }
197
- thead th:last-child { border-radius: 0 999px 999px 0; }
198
- tbody td { padding: 12px 14px; vertical-align: middle; }
199
- tbody tr.row td { background: var(--paper); cursor: pointer; }
200
- tbody tr.row td:first-child { border-radius: 16px 0 0 16px; }
201
- tbody tr.row td:last-child { border-radius: 0 16px 16px 0; }
202
- tbody tr.row.bad td:first-child { box-shadow: inset 4px 0 0 var(--ember); }
203
- tbody tr.row.warn td:first-child { box-shadow: inset 4px 0 0 var(--gold); }
204
- tbody tr.row:hover td { background: #fff3e8; }
205
- .f-title { font-weight: 700; max-width: 360px; }
206
- .f-id { font-family: var(--mono); font-size: 11px; color: var(--faint); }
207
- .tag { display: inline-flex; align-items: center; gap: 6px; font-size: 11.5px; font-weight: 700; padding: 3px 10px; border-radius: 999px; background: var(--paper); box-shadow: var(--raised-sm); white-space: nowrap; color: var(--muted); }
208
- .tag.ember { color: var(--ember); } .tag.amber { color: var(--amber); } .tag.leaf { color: var(--leaf); } .tag.sun { color: var(--sun-deep); } .tag.dusk { color: var(--dusk); }
209
- .tag .g-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
210
- .tag .g-half { width: 9px; height: 9px; border-radius: 50%; border: 2px solid currentColor; background: linear-gradient(90deg, currentColor 50%, transparent 50%); }
211
- .where { font-family: var(--mono); font-size: 11.5px; color: var(--muted); max-width: 240px; overflow-wrap: anywhere; }
212
- .conf { display: flex; align-items: center; gap: 8px; font-weight: 700; font-size: 12px; }
213
- .conf .meter { width: 64px; height: 9px; margin: 0; padding: 1.5px; }
214
- tr.detail td { padding: 4px 14px 16px; }
215
- .detail-box { border-radius: 18px; padding: 16px 18px; background: var(--paper-2); box-shadow: var(--sunken); }
216
- .detail-box .d-step { font-size: 11px; font-weight: 800; letter-spacing: 0.12em; color: var(--sun-deep); margin-top: 14px; }
217
- .detail-box .d-step:first-child { margin-top: 0; }
218
- .detail-box .d-text { color: var(--muted); font-size: 13px; overflow-wrap: anywhere; margin-top: 4px; }
219
- .detail-box pre { white-space: pre-wrap; overflow-wrap: anywhere; font: 12px/1.6 var(--mono); background: var(--paper); border-radius: 14px; padding: 14px; margin: 8px 0 0; box-shadow: var(--raised-sm); max-height: 340px; overflow: auto; }
220
- .d-actions { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 12px; }
221
- .attempts { margin-top: 10px; display: grid; gap: 6px; font-size: 12px; color: var(--muted); }
222
- .attempts div { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
223
- .empty { color: var(--muted); padding: 10px 4px; }
224
-
225
- /* What changed */
226
- .timeline { display: grid; gap: 0; max-width: 920px; }
227
- .tl { display: grid; grid-template-columns: 22px minmax(0, 1fr); gap: 14px; position: relative; padding-bottom: 18px; }
228
- .tl::before { content: ""; position: absolute; left: 10px; top: 20px; bottom: 0; width: 2px; background: var(--paper-3); }
229
- .tl:last-child::before { display: none; }
230
- .tl .knob { width: 22px; height: 22px; border-radius: 50%; margin-top: 1px; background: var(--faint); border: 5px solid var(--paper); box-shadow: var(--raised-sm); position: relative; z-index: 1; }
231
- .tl .knob.bad { background: var(--ember); } .tl .knob.ok { background: var(--leaf); } .tl .knob.mid { background: var(--gold); }
232
- .tl-head { font-weight: 700; }
233
- .tl-meta { font-size: 12px; color: var(--muted); }
234
- .tl-body { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
235
- .tl-files { margin-top: 8px; font-family: var(--mono); font-size: 11.5px; color: var(--muted); display: grid; gap: 2px; overflow-wrap: anywhere; }
236
- .more { margin-top: 4px; }
237
-
238
- /* Checks */
239
- .check-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
240
- @media (max-width: 1100px) { .check-grid { grid-template-columns: minmax(0, 1fr); } }
241
- .check { padding: 18px; border-radius: 20px; display: flex; flex-direction: column; gap: 8px; }
242
- .check .c-top { display: flex; align-items: center; gap: 12px; justify-content: space-between; }
243
- .check .c-name { font-weight: 800; font-size: 15px; }
244
- .check .c-what { font-size: 12.5px; color: var(--muted); }
245
- .check .c-foot { margin-top: auto; padding-top: 6px; }
246
- .na-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 10px; }
247
- .na { display: flex; align-items: center; gap: 12px; padding: 11px 14px; border-radius: 14px; font-weight: 700; color: var(--muted); font-size: 13px; min-width: 0; }
248
- .na .na-lock { display: block; font-size: 10px; font-weight: 800; letter-spacing: 0.1em; color: var(--faint); margin-top: 1px; }
249
- .na .switch { opacity: 0.55; }
250
- .switch { position: relative; width: 50px; height: 28px; flex: none; }
251
- .switch input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; z-index: 1; }
252
- .switch input:disabled { cursor: not-allowed; }
253
- .switch .track { position: absolute; inset: 0; border-radius: 999px; background: var(--paper-2); box-shadow: var(--sunken); transition: background 0.2s ease; }
254
- .switch .track::after { content: ""; position: absolute; width: 20px; height: 20px; left: 4px; top: 4px; border-radius: 50%; background: var(--paper); box-shadow: 2px 3px 6px rgba(160, 90, 50, 0.35), -2px -2px 5px rgba(255, 255, 255, 0.9); transition: transform 0.2s ease; }
255
- .switch input:checked + .track { background: linear-gradient(135deg, #f6a064, #e5652b); }
256
- .switch input:checked + .track::after { transform: translateX(22px); }
257
-
258
- /* Lists */
259
- .fix-row { display: flex; gap: 12px; align-items: center; padding: 12px 0; flex-wrap: wrap; }
260
- .fix-row + .fix-row { border-top: 1px solid rgba(138, 109, 94, 0.15); }
261
- .fix-row .fr-text { flex: 1; min-width: 200px; }
262
- .fix-row .fr-sub { font-size: 12px; color: var(--muted); font-family: var(--mono); overflow-wrap: anywhere; }
263
- .note { color: var(--muted); font-size: 13px; overflow-wrap: anywhere; max-width: 780px; }
264
- .path { font-family: var(--mono); font-size: 12.5px; padding: 12px 14px; border-radius: 14px; overflow-wrap: anywhere; margin-top: 10px; }
265
- .states { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 12px; margin-top: 16px; }
266
- .state-card { padding: 14px 16px; border-radius: 16px; }
267
- .state-card b { display: block; font-size: 13.5px; }
268
- .state-card span { font-size: 12px; color: var(--muted); }
269
- .files { display: grid; gap: 8px; margin-top: 14px; }
270
- .files div { display: grid; grid-template-columns: 170px minmax(0, 1fr); gap: 12px; font-size: 12.5px; }
271
- .files code { font-family: var(--mono); color: var(--ink); }
272
- .files span { color: var(--muted); }
273
- @media (max-width: 600px) { .files div { grid-template-columns: minmax(0, 1fr); gap: 0; } }
274
- .error { color: var(--ember); font-size: 12.5px; margin-top: 10px; }
275
- .toast { position: fixed; left: 50%; bottom: 22px; transform: translate(-50%, 24px); opacity: 0; padding: 12px 18px; border-radius: 16px; background: var(--paper); box-shadow: var(--raised); font-weight: 600; transition: all 0.25s ease; pointer-events: none; z-index: 10; max-width: calc(100vw - 32px); }
276
- .toast.show { opacity: 1; transform: translate(-50%, 0); }
277
- </style>
278
- </head>
279
- <body>
280
- <div class="shell">
281
- <aside class="side raised">
282
- <div class="brand">
283
- <img src="/logo.png" alt="Kryptheon logo" width="50" height="50">
284
- <div class="wordmark">KRYPTHEON<span class="dot">.</span><small>checks what your AI built</small></div>
285
- </div>
286
- <div>
287
- <div class="nav-label">OVERVIEW</div>
288
- <nav class="nav" id="navOverview"></nav>
289
- </div>
290
- <div>
291
- <div class="nav-label">WORKSPACE</div>
292
- <nav class="nav" id="navWorkspace"></nav>
293
- </div>
294
- <div class="built raised">
295
- <div class="built-top"><span>Checks built</span><b id="builtText">-</b></div>
296
- <div class="meter sunken"><i id="builtBar" style="width:0%"></i></div>
297
- <p id="builtNote"></p>
298
- </div>
299
- <div class="account sunken">
300
- <div class="avatar" id="avatar">K</div>
301
- <div style="min-width:0">
302
- <div class="a-name" id="projName">Project</div>
303
- <div class="a-sub" id="projPath"></div>
304
- </div>
305
- </div>
306
- </aside>
307
-
308
- <main>
309
- <div class="top">
310
- <div>
311
- <h1 id="viewTitle">Dashboard</h1>
312
- <div class="sub"><span class="live-dot"></span><span id="subline">Watching for changes</span></div>
313
- </div>
314
- <div class="grow"></div>
315
- <label class="search sunken">
316
- <span id="searchIcon"></span>
317
- <input id="search" type="search" placeholder="Search findings" aria-label="Search findings">
318
- </label>
319
- <button class="bell" id="bell" type="button" aria-label="What changed in the last look"></button>
320
- <button class="btn sun" id="runAll" type="button" data-action="run"></button>
321
- </div>
322
-
323
- <section class="view" id="view-dashboard">
324
- <div class="sky" id="sky">
325
- <div class="s-chip" id="skyIcon"></div>
326
- <div class="s-text">
327
- <div class="eyebrow" id="skyEyebrow">RIGHT NOW</div>
328
- <h2 id="skyTitle">Reading your project...</h2>
329
- <p id="skySub"></p>
330
- </div>
331
- <div class="s-actions" id="skyActions"></div>
332
- </div>
333
- <div class="kpis" id="kpis"></div>
334
- <div class="guide raised">
335
- <div class="card-head">
336
- <div>
337
- <h3>Not sure where to look?</h3>
338
- <div class="c-sub">Find your problem on the left - the section to open is on the right</div>
339
- </div>
340
- </div>
341
- <div class="guide-list" id="guide"></div>
342
- </div>
343
- <div class="split">
344
- <div class="card raised">
345
- <div class="card-head">
346
- <div>
347
- <h3>Recorded flows over time</h3>
348
- <div class="c-sub" id="chartSub">Each run: recordings that held</div>
349
- </div>
350
- <div class="grow"></div>
351
- <div class="seg sunken" id="range"></div>
352
- </div>
353
- <div class="chart-wrap" id="chart"></div>
354
- </div>
355
- <div class="card raised">
356
- <div class="card-head">
357
- <div>
358
- <h3>Open findings</h3>
359
- <div class="c-sub">By the check that found them</div>
360
- </div>
361
- </div>
362
- <div class="donut" id="donut"></div>
363
- <div class="legend" id="legend"></div>
364
- </div>
365
- </div>
366
- </section>
367
-
368
- <section class="view" id="view-findings" hidden>
369
- <div class="when sunken" id="when-findings"></div>
370
- <div class="card raised">
371
- <div class="card-head">
372
- <div>
373
- <h3>Findings</h3>
374
- <div class="c-sub">Click a row: what is wrong, the fix prompt, then Re-check</div>
375
- </div>
376
- <span class="badge" id="findingBadge">0</span>
377
- <div class="grow"></div>
378
- <div class="seg sunken" id="statusFilter"></div>
379
- </div>
380
- <div class="table-scroll">
381
- <table>
382
- <thead><tr><th>Finding</th><th>Check</th><th>Status</th><th>Severity</th><th>Where</th><th>Confidence</th></tr></thead>
383
- <tbody id="findingRows"></tbody>
384
- </table>
385
- </div>
386
- </div>
387
- </section>
388
-
389
- <section class="view" id="view-changes" hidden>
390
- <div class="when sunken" id="when-changes"></div>
391
- <div class="card raised">
392
- <div class="card-head"><div><h3>What changed</h3><div class="c-sub">Every look Kryptheon took, newest first</div></div><span class="badge" id="lookBadge">0</span></div>
393
- <div class="timeline" id="timeline"></div>
394
- </div>
395
- </section>
396
-
397
- <section class="view" id="view-fixes" hidden>
398
- <div class="when sunken" id="when-fixes"></div>
399
- <div class="card raised">
400
- <div class="card-head"><div><h3>Proven fixes</h3><div class="c-sub">Fixed only when a re-check said so</div></div><span class="badge" id="fixBadge">0</span></div>
401
- <div id="fixList"></div>
402
- </div>
403
- </section>
404
-
405
- <section class="view" id="view-checks" hidden>
406
- <div class="when sunken" id="when-checks"></div>
407
- <div class="check-grid" id="checkList"></div>
408
- <p class="error" id="checkError" hidden></p>
409
- <div class="card raised" style="margin-top:18px">
410
- <div class="card-head"><div><h3>Not built yet</h3><div class="c-sub">Listed so you know they exist - never shown as passed</div></div><span class="badge" id="naBadge">0</span></div>
411
- <div class="na-grid" id="naList"></div>
412
- </div>
413
- </section>
414
-
415
- <section class="view" id="view-runs" hidden>
416
- <div class="when sunken" id="when-runs"></div>
417
- <div class="card raised">
418
- <div class="card-head"><div><h3>Runs</h3><div class="c-sub">Your recorded flows, replayed against your app</div></div><span class="badge" id="runBadge">0</span></div>
419
- <div id="runList"></div>
420
- </div>
421
- </section>
422
-
423
- <section class="view" id="view-verification" hidden>
424
- <div class="when sunken" id="when-verification"></div>
425
- <div class="card raised">
426
- <div class="card-head"><div><h3>Kryptheon Verified</h3><div class="c-sub">A badge that stands for one version of your project</div></div><span class="badge" id="verifyBadge">not verified</span></div>
427
- <p class="note" id="verifyText"></p>
428
- <div class="states" id="verifyStates"></div>
429
- </div>
430
- </section>
431
-
432
- <section class="view" id="view-storage" hidden>
433
- <div class="when sunken" id="when-storage"></div>
434
- <div class="card raised">
435
- <div class="card-head"><div><h3>Where this lives</h3><div class="c-sub">On this machine, outside your project</div></div></div>
436
- <p class="note" id="storeNote"></p>
437
- <div class="path sunken" id="storePath"></div>
438
- <div class="files" id="storeFiles"></div>
439
- </div>
440
- </section>
441
- </main>
442
- </div>
443
- <div class="toast" id="toast" role="status" aria-live="polite"></div>
444
- <script src="/dashboard.js"></script>
445
- </body>
446
- </html>
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <meta name="kryptheon-token" content="%%TOKEN%%">
7
+ <title>Kryptheon</title>
8
+ <link rel="icon" href="/logo.png">
9
+ <style>
10
+ /* The grammar of kryptheon.tech: two grounds (ink and glacier), one orange,
11
+ type doing the work on a compressed width axis, hairlines for structure -
12
+ no cards, shadows or rounded corners. Orange means "act on this": a
13
+ confirmed problem, the one next thing, the button that does it. Everything
14
+ else is ink. The two fonts are the site's own, served by this server;
15
+ nothing is loaded from anywhere else. */
16
+ @font-face {
17
+ font-family: "Archivo";
18
+ font-style: normal;
19
+ font-weight: 100 900;
20
+ font-stretch: 62% 125%;
21
+ font-display: swap;
22
+ src: url("/fonts/archivo.woff2") format("woff2");
23
+ }
24
+ @font-face {
25
+ font-family: "Space Mono";
26
+ font-style: normal;
27
+ font-weight: 400;
28
+ font-display: swap;
29
+ src: url("/fonts/spacemono.woff2") format("woff2");
30
+ }
31
+ :root {
32
+ --ink: #0b0e14;
33
+ --ink-2: #141922;
34
+ --glacier: #f2f4f1;
35
+ --white: #fafbfa;
36
+ --orange: #ff4d00;
37
+ --orange-deep: #c23a00;
38
+ --on-dark: #e9edf2;
39
+ --on-light: #12161d;
40
+ --line: rgba(18, 22, 29, 0.16);
41
+ --line-dark: rgba(233, 237, 242, 0.14);
42
+ --muted: rgba(18, 22, 29, 0.62);
43
+ --display: "Archivo", "Bahnschrift", "Arial Narrow", "Helvetica Neue", Arial, sans-serif;
44
+ --mono: "Space Mono", ui-monospace, "Cascadia Code", Consolas, monospace;
45
+ --ease: cubic-bezier(0.16, 1, 0.3, 1);
46
+ --gutter: clamp(18px, 3.4vw, 44px);
47
+ }
48
+ * { box-sizing: border-box; }
49
+ html { -webkit-text-size-adjust: 100%; }
50
+ body { margin: 0; min-height: 100vh; color: var(--on-light); background: var(--glacier); font: 15px/1.6 var(--display); -webkit-font-smoothing: antialiased; }
51
+ button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
52
+ a { color: inherit; }
53
+ ::selection { color: var(--white); background: var(--orange); }
54
+ h1, h2, h3 { margin: 0; font-family: var(--display); font-weight: 900; font-stretch: 63%; letter-spacing: -0.015em; line-height: 0.95; text-transform: uppercase; }
55
+ button:focus-visible, input:focus-visible, a:focus-visible { outline: 2px solid var(--orange); outline-offset: 2px; }
56
+
57
+ /* The labels: Space Mono, small, spaced, upper case. */
58
+ .mono, .eyebrow, .c-sub, .badge, .tag, .n-count, .d-step, .tl-meta, .lr-sub, .na-lock, .step-num, .built-top, .btn, .seg button, .nav button, .site-link, .wordmark small, .top .sub {
59
+ font-family: var(--mono);
60
+ font-size: 11px;
61
+ font-weight: 400;
62
+ letter-spacing: 0.14em;
63
+ text-transform: uppercase;
64
+ }
65
+
66
+ .shell { display: grid; grid-template-columns: 250px minmax(0, 1fr); min-height: 100vh; }
67
+ @media (max-width: 900px) { .shell { grid-template-columns: minmax(0, 1fr); } }
68
+
69
+ /* --- ink: the sidebar --------------------------------------------------- */
70
+ .side { position: sticky; top: 0; height: 100vh; display: flex; flex-direction: column; gap: 26px; padding: 22px 18px 20px; color: var(--on-dark); background: var(--ink); overflow-y: auto; }
71
+ @media (max-width: 900px) { .side { position: static; height: auto; } }
72
+ .brand { display: flex; align-items: center; gap: 12px; }
73
+ .brand img { width: 40px; height: 40px; background: #000; flex: none; }
74
+ .wordmark { font-family: var(--display); font-weight: 900; font-stretch: 63%; font-size: 22px; letter-spacing: 0.02em; line-height: 1; text-transform: uppercase; color: var(--white); }
75
+ .wordmark .dot { color: var(--orange); }
76
+ .wordmark small { display: block; margin-top: 6px; font-size: 9.5px; letter-spacing: 0.14em; color: rgba(233, 237, 242, 0.5); }
77
+ .nav { display: grid; border-top: 1px solid var(--line-dark); }
78
+ .nav button { position: relative; display: flex; align-items: center; gap: 12px; width: 100%; padding: 13px 4px 13px 12px; text-align: left; color: rgba(233, 237, 242, 0.62); border-bottom: 1px solid var(--line-dark); transition: color 0.3s var(--ease), padding 0.3s var(--ease); }
79
+ .nav button svg { flex: none; opacity: 0.8; }
80
+ .nav button:hover { color: var(--white); }
81
+ .nav button.on { padding-left: 18px; color: var(--white); }
82
+ .nav button.on::before { content: ""; position: absolute; top: -1px; bottom: -1px; left: 0; width: 3px; background: var(--orange); }
83
+ .nav .n-count { margin-left: auto; font-size: 10px; letter-spacing: 0.06em; color: rgba(233, 237, 242, 0.55); }
84
+ .nav .n-count.hot { color: var(--orange); }
85
+ @media (max-width: 900px) { .nav { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); } }
86
+ .built { margin-top: auto; padding-top: 16px; border-top: 1px solid var(--line-dark); }
87
+ .built-top { display: flex; justify-content: space-between; align-items: baseline; font-size: 10px; color: rgba(233, 237, 242, 0.6); }
88
+ .built-top b { font-family: var(--display); font-weight: 900; font-stretch: 63%; font-size: 22px; letter-spacing: 0; color: var(--white); }
89
+ .meter { height: 2px; margin-top: 12px; background: var(--line-dark); }
90
+ .meter i { display: block; height: 100%; background: var(--orange); }
91
+ .built p { margin: 10px 0 0; font-size: 12px; line-height: 1.55; color: rgba(233, 237, 242, 0.5); }
92
+ .site-link { font-size: 10px; color: rgba(233, 237, 242, 0.6); text-decoration: none; transition: color 0.3s var(--ease); }
93
+ .site-link::after { content: " ↗"; }
94
+ .site-link:hover { color: var(--orange); }
95
+
96
+ /* --- glacier: the main side --------------------------------------------- */
97
+ main { min-width: 0; padding: 26px var(--gutter) 60px; }
98
+ .top { display: flex; align-items: flex-end; gap: 16px; flex-wrap: wrap; padding-bottom: 20px; border-bottom: 1px solid var(--line); }
99
+ .top h1 { font-size: clamp(2.4rem, 5vw, 3.8rem); }
100
+ .top .sub { display: flex; align-items: center; gap: 10px; margin-top: 10px; font-size: 10px; color: var(--muted); text-transform: none; letter-spacing: 0.06em; }
101
+ .live-dot { width: 7px; height: 7px; background: var(--orange); animation: pulse 2.4s var(--ease) infinite; }
102
+ @keyframes pulse { 50% { opacity: 0.25; } }
103
+ .top .grow { flex: 1; }
104
+
105
+ .btn { display: inline-flex; align-items: center; justify-content: center; gap: 9px; height: 42px; padding: 0 20px; border: 1px solid currentColor; white-space: nowrap; transition: background 0.3s var(--ease), color 0.3s var(--ease), border-color 0.3s var(--ease); }
106
+ .btn:hover:not(:disabled) { color: var(--orange); border-color: var(--orange); }
107
+ .btn:disabled { opacity: 0.5; cursor: default; }
108
+ .btn.sun { color: var(--white); background: var(--orange); border-color: var(--orange); }
109
+ .btn.sun:hover:not(:disabled) { color: var(--white); background: var(--orange-deep); border-color: var(--orange-deep); }
110
+ .btn.sm { height: 34px; padding: 0 14px; font-size: 10px; }
111
+ .spin { width: 12px; height: 12px; border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: spin 0.8s linear infinite; }
112
+ @keyframes spin { to { transform: rotate(360deg); } }
113
+
114
+ .view { margin-top: 28px; }
115
+ .view[hidden] { display: none; }
116
+ .card { min-width: 0; }
117
+ .card + .card, .view > .card.gap { margin-top: 44px; }
118
+ .card-head { display: flex; align-items: flex-end; gap: 14px; flex-wrap: wrap; padding-bottom: 14px; border-bottom: 1px solid var(--line); }
119
+ .card-head h3 { font-size: clamp(1.6rem, 2.8vw, 2.2rem); }
120
+ .card-head .c-sub { margin-top: 8px; font-size: 10px; color: var(--muted); }
121
+ .card-head .grow { flex: 1; }
122
+ .badge { font-size: 10px; color: var(--muted); }
123
+ .badge::before { content: "("; } .badge::after { content: ")"; }
124
+ .seg { display: inline-flex; border: 1px solid var(--line); }
125
+ .seg button { padding: 8px 14px; font-size: 10px; color: var(--muted); }
126
+ .seg button + button { border-left: 1px solid var(--line); }
127
+ .seg button.on { color: var(--white); background: var(--on-light); }
128
+
129
+ /* --- the one thing to do now: an ink band ------------------------------- */
130
+ .sky { position: relative; display: flex; align-items: center; gap: 22px; flex-wrap: wrap; padding: 34px 32px 36px; color: var(--on-dark); background: var(--ink); }
131
+ .sky::after { content: ""; position: absolute; left: 0; bottom: 0; width: 38%; height: 2px; background: var(--orange); }
132
+ .sky.bad { box-shadow: inset 4px 0 0 var(--orange); }
133
+ .sky.ok::after { background: rgba(233, 237, 242, 0.4); }
134
+ .sky .s-chip { display: grid; place-items: center; width: 54px; height: 54px; flex: none; border: 1px solid var(--line-dark); color: var(--orange) !important; }
135
+ .sky.ok .s-chip { color: var(--on-dark) !important; }
136
+ .sky .s-text { flex: 1; min-width: 240px; }
137
+ .sky .eyebrow { font-size: 10px; color: var(--orange); }
138
+ .sky h2 { margin-top: 10px; color: var(--white); font-size: clamp(2rem, 4.6vw, 3.6rem); }
139
+ .sky p { max-width: 62ch; margin: 12px 0 0; font-size: 14px; line-height: 1.65; color: rgba(233, 237, 242, 0.66); }
140
+ .sky .btn:not(.sun) { color: var(--on-dark); }
141
+
142
+ /* --- start here: the ladder --------------------------------------------- */
143
+ .steps { display: grid; }
144
+ .step { display: grid; grid-template-columns: 56px minmax(0, 1fr); gap: 8px; padding: 22px 0; border-bottom: 1px solid var(--line); }
145
+ .step-num { padding-top: 2px; font-size: 13px; letter-spacing: 0.04em; color: var(--orange); }
146
+ .step.done .step-num { color: var(--on-light); }
147
+ .step.off .step-num, .step.waiting .step-num { color: var(--muted); }
148
+ .step-num svg { width: 18px; height: 18px; }
149
+ .step-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
150
+ .step-title { font-weight: 800; font-stretch: 74%; font-size: clamp(1.1rem, 1.8vw, 1.45rem); letter-spacing: -0.01em; line-height: 1.05; text-transform: uppercase; }
151
+ .step.off .step-title, .step.off .step-why { opacity: 0.45; }
152
+ .step-why { max-width: 70ch; margin: 8px 0 0; font-size: 14px; line-height: 1.6; color: var(--muted); }
153
+ .step .btn { margin-top: 14px; }
154
+ .cmd { display: inline-flex; align-items: center; gap: 12px; max-width: 100%; margin-top: 14px; padding: 10px 10px 10px 16px; color: var(--on-dark); background: var(--ink); border-left: 2px solid var(--orange); }
155
+ .cmd code { font: 12.5px/1.5 var(--mono); overflow-wrap: anywhere; }
156
+ .cmd svg { flex: none; opacity: 0.6; }
157
+ .cmd-copy { display: grid; place-items: center; width: 30px; height: 30px; flex: none; border: 1px solid var(--line-dark); color: var(--on-dark); transition: color 0.3s var(--ease), border-color 0.3s var(--ease); }
158
+ .cmd-copy:hover { color: var(--orange); border-color: var(--orange); }
159
+
160
+ /* --- connect your AI tool: an index of tools, one tool's page ------------ */
161
+ .ai { display: grid; grid-template-columns: 220px minmax(0, 1fr); gap: 34px; padding-top: 18px; }
162
+ @media (max-width: 900px) { .ai { grid-template-columns: minmax(0, 1fr); gap: 18px; } }
163
+ .ai-tabs { display: flex; flex-direction: column; border-top: 1px solid var(--line); }
164
+ @media (max-width: 900px) { .ai-tabs { flex-direction: row; flex-wrap: wrap; } }
165
+ .ai-tab { position: relative; display: flex; align-items: baseline; gap: 10px; padding: 13px 8px 13px 14px; text-align: left; border-bottom: 1px solid var(--line); transition: color 0.3s var(--ease), padding 0.3s var(--ease); }
166
+ .ai-tab .ai-num { font: 10px var(--mono); color: var(--muted); }
167
+ .ai-tab .ai-name { font-weight: 800; font-stretch: 74%; text-transform: uppercase; }
168
+ .ai-tab .ai-tag { margin-left: auto; font: 9px var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); }
169
+ .ai-tab:hover, .ai-tab.on { color: var(--orange-deep); }
170
+ .ai-tab.on { padding-left: 20px; }
171
+ .ai-tab.on::before { content: ""; position: absolute; top: -1px; bottom: -1px; left: 0; width: 3px; background: var(--orange); }
172
+ .ai-panel h4 { margin: 10px 0 0; font-weight: 900; font-stretch: 63%; font-size: clamp(2rem, 4vw, 3rem); line-height: 0.95; text-transform: uppercase; }
173
+ .ai-badge { font: 10px var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); }
174
+ .ai-badge.tested { color: var(--orange-deep); }
175
+ .ai-steps { margin: 18px 0 0; padding: 0; list-style: none; border-top: 1px solid var(--line); }
176
+ .ai-steps li { display: grid; grid-template-columns: 40px minmax(0, 1fr); padding: 12px 0; font-size: 14px; line-height: 1.55; border-bottom: 1px solid var(--line); }
177
+ .ai-steps li span { font: 13px var(--mono); color: var(--orange); }
178
+ .ai-oneclick { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-top: 18px; }
179
+ .ai-oneclick small { font: 10px var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); }
180
+ .ai-plate { margin-top: 18px; color: var(--on-dark); background: var(--ink); }
181
+ .ai-plate-bar { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 14px; font: 10.5px var(--mono); border-bottom: 1px solid var(--line-dark); }
182
+ .ai-plate-bar span { opacity: 0.6; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
183
+ .ai-plate-bar button { flex: none; padding: 6px 12px; font: 10px var(--mono); letter-spacing: 0.14em; text-transform: uppercase; border: 1px solid var(--line-dark); transition: color 0.3s var(--ease), border-color 0.3s var(--ease); }
184
+ .ai-plate-bar button:hover { color: var(--orange); border-color: var(--orange); }
185
+ .ai-plate pre { margin: 0; padding: 16px 14px 18px; overflow-x: auto; font: 12.5px/1.7 var(--mono); white-space: pre; }
186
+ .ai-note { max-width: 66ch; margin: 14px 0 0; padding-left: 14px; font-size: 13.5px; line-height: 1.6; color: var(--muted); border-left: 2px solid var(--orange); }
187
+ .ai-then { margin-top: 20px; font-size: 14px; }
188
+ .ai-then b { font-weight: 900; font-stretch: 63%; font-size: 1.6rem; text-transform: uppercase; }
189
+
190
+ /* --- tags: orange acts, ink states --------------------------------------- */
191
+ .tag { display: inline-flex; align-items: center; gap: 6px; padding: 3px 8px; font-size: 9.5px; letter-spacing: 0.12em; white-space: nowrap; color: var(--muted); border: 1px solid var(--line); }
192
+ .tag.ember, .tag.sun { color: var(--orange-deep); border-color: var(--orange); }
193
+ .tag.amber { color: var(--on-light); border-style: dashed; border-color: rgba(18, 22, 29, 0.45); }
194
+ .tag.leaf { color: var(--on-light); border-color: var(--on-light); }
195
+ .tag.leaf::before { content: "✓"; }
196
+ .tag.dusk, .tag.muted { color: var(--muted); }
197
+ .tag .g-dot { width: 6px; height: 6px; background: currentColor; }
198
+ .tag .g-half { width: 7px; height: 7px; border: 1px solid currentColor; background: linear-gradient(90deg, currentColor 50%, transparent 50%); }
199
+ .step-head .tag { font-size: 9px; }
200
+
201
+ /* --- findings: one row each, a rule down the side ------------------------ */
202
+ .finding { border-bottom: 1px solid var(--line); }
203
+ .finding.bad { box-shadow: inset 3px 0 0 var(--orange); }
204
+ .finding.warn { box-shadow: inset 3px 0 0 rgba(18, 22, 29, 0.35); }
205
+ .finding-head { display: flex; align-items: center; gap: 14px; width: 100%; padding: 18px 8px 18px 20px; text-align: left; transition: background 0.3s var(--ease); }
206
+ .finding-head:hover { background: rgba(18, 22, 29, 0.035); }
207
+ .finding-head > svg { flex: none; color: var(--muted); }
208
+ .finding-left { flex: 1; min-width: 0; }
209
+ .f-title { font-weight: 800; font-stretch: 74%; font-size: clamp(1.05rem, 1.6vw, 1.3rem); letter-spacing: -0.01em; line-height: 1.1; text-transform: uppercase; }
210
+ .f-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
211
+ .f-where { font: 11px/1.4 var(--mono); color: var(--muted); overflow-wrap: anywhere; }
212
+ .detail-box { margin: 0 8px 22px 20px; padding: 18px 0 0; border-top: 1px dashed var(--line); }
213
+ .d-step { margin-top: 18px; font-size: 10px; color: var(--orange-deep); }
214
+ .d-step:first-child { margin-top: 0; }
215
+ .d-text { margin-top: 6px; font-size: 14px; line-height: 1.6; color: var(--muted); overflow-wrap: anywhere; }
216
+ .detail-box pre { max-height: 360px; margin: 10px 0 0; padding: 18px; overflow: auto; font: 12px/1.7 var(--mono); white-space: pre-wrap; overflow-wrap: anywhere; color: var(--on-dark); background: var(--ink); }
217
+ .d-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 14px; }
218
+ .attempts { display: grid; gap: 8px; margin-top: 14px; font-size: 13px; color: var(--muted); }
219
+ .attempts div { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
220
+ .empty { padding: 18px 0; font-size: 14px; color: var(--muted); }
221
+
222
+ /* --- what changed -------------------------------------------------------- */
223
+ .timeline { display: grid; }
224
+ .tl { display: grid; grid-template-columns: 18px minmax(0, 1fr); gap: 16px; padding: 20px 0; border-bottom: 1px solid var(--line); }
225
+ .tl .knob { width: 10px; height: 10px; margin-top: 7px; border: 1px solid var(--on-light); }
226
+ .tl .knob.bad { background: var(--orange); border-color: var(--orange); }
227
+ .tl .knob.ok { background: var(--on-light); }
228
+ .tl .knob.mid { border-style: dashed; }
229
+ .tl-head { font-weight: 800; font-stretch: 74%; font-size: 1.1rem; text-transform: uppercase; letter-spacing: -0.01em; }
230
+ .tl-meta { margin-top: 4px; font-size: 10px; color: var(--muted); }
231
+ .tl-body { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
232
+ .tl-files { display: grid; gap: 2px; margin-top: 10px; font: 11.5px/1.5 var(--mono); color: var(--muted); overflow-wrap: anywhere; }
233
+
234
+ /* --- checks -------------------------------------------------------------- */
235
+ .check-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1px; background: var(--line); border: 1px solid var(--line); }
236
+ @media (max-width: 1100px) { .check-grid { grid-template-columns: minmax(0, 1fr); } }
237
+ .check { display: flex; flex-direction: column; gap: 10px; padding: 22px 20px 24px; background: var(--glacier); }
238
+ .check .c-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
239
+ .check .c-name { font-weight: 800; font-stretch: 74%; font-size: 1.2rem; line-height: 1.05; text-transform: uppercase; }
240
+ .check .c-what { font-size: 13.5px; line-height: 1.6; color: var(--muted); }
241
+ .check .btn { align-self: flex-start; margin-top: auto; }
242
+ .na-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); border-top: 1px solid var(--line); }
243
+ .na { display: flex; align-items: center; gap: 12px; padding: 14px 4px; font-weight: 700; font-stretch: 74%; text-transform: uppercase; color: var(--muted); border-bottom: 1px solid var(--line); }
244
+ .na .na-lock { display: block; margin-top: 2px; font-size: 9px; font-weight: 400; color: rgba(18, 22, 29, 0.42); }
245
+ .na .switch { opacity: 0.45; }
246
+ .switch { position: relative; width: 42px; height: 22px; flex: none; }
247
+ .switch input { position: absolute; inset: 0; z-index: 1; margin: 0; opacity: 0; cursor: pointer; }
248
+ .switch input:disabled { cursor: not-allowed; }
249
+ .switch .track { position: absolute; inset: 0; border: 1px solid var(--on-light); transition: background 0.3s var(--ease), border-color 0.3s var(--ease); }
250
+ .switch .track::after { content: ""; position: absolute; top: 3px; left: 3px; width: 14px; height: 14px; background: var(--on-light); transition: transform 0.3s var(--ease), background 0.3s var(--ease); }
251
+ .switch input:checked + .track { background: var(--orange); border-color: var(--orange); }
252
+ .switch input:checked + .track::after { background: var(--white); transform: translateX(20px); }
253
+ .switch input:focus-visible + .track { outline: 2px solid var(--orange); outline-offset: 2px; }
254
+
255
+ /* --- simple lists -------------------------------------------------------- */
256
+ .line-row { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; padding: 16px 0; border-bottom: 1px solid var(--line); }
257
+ .lr-text { flex: 1; min-width: 200px; font-weight: 700; font-stretch: 80%; }
258
+ .lr-sub { margin-top: 3px; font-size: 10px; letter-spacing: 0.06em; text-transform: none; color: var(--muted); overflow-wrap: anywhere; }
259
+ .note { max-width: 70ch; margin: 18px 0 0; font-size: 14px; line-height: 1.65; color: var(--muted); overflow-wrap: anywhere; }
260
+ .path { margin-top: 14px; padding: 14px 16px; font: 12.5px/1.5 var(--mono); color: var(--on-dark); background: var(--ink); border-left: 2px solid var(--orange); overflow-wrap: anywhere; }
261
+ .files { display: grid; margin-top: 20px; border-top: 1px solid var(--line); }
262
+ .files div { display: grid; grid-template-columns: 190px minmax(0, 1fr); gap: 14px; padding: 10px 0; font-size: 13.5px; border-bottom: 1px solid var(--line); }
263
+ .files code { font: 12px/1.5 var(--mono); }
264
+ .files span { color: var(--muted); }
265
+ @media (max-width: 600px) { .files div { grid-template-columns: minmax(0, 1fr); gap: 2px; } }
266
+
267
+ .toast { position: fixed; left: 50%; bottom: 24px; z-index: 10; max-width: calc(100vw - 32px); padding: 14px 20px; font-size: 14px; color: var(--on-dark); background: var(--ink); border-left: 2px solid var(--orange); opacity: 0; transform: translate(-50%, 20px); transition: opacity 0.35s var(--ease), transform 0.35s var(--ease); pointer-events: none; }
268
+ .toast.show { opacity: 1; transform: translate(-50%, 0); }
269
+
270
+ @media (prefers-reduced-motion: reduce) {
271
+ *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; }
272
+ }
273
+ </style>
274
+ </head>
275
+ <body>
276
+ <div class="shell">
277
+ <aside class="side">
278
+ <div class="brand">
279
+ <img src="/logo.png" alt="Kryptheon logo" width="40" height="40">
280
+ <div class="wordmark">Kryptheon<span class="dot">.</span><small>checks what your AI built</small></div>
281
+ </div>
282
+ <nav class="nav" id="nav"></nav>
283
+ <div class="built">
284
+ <div class="built-top"><span>Checks built</span><b id="builtText">-</b></div>
285
+ <div class="meter"><i id="builtBar" style="width:0%"></i></div>
286
+ <p id="builtNote"></p>
287
+ </div>
288
+ <a class="site-link" href="https://kryptheon.tech" target="_blank" rel="noopener noreferrer">kryptheon.tech</a>
289
+ </aside>
290
+
291
+ <main>
292
+ <div class="top">
293
+ <div>
294
+ <h1 id="viewTitle">Dashboard</h1>
295
+ <div class="sub"><span class="live-dot"></span><span id="subline">Watching for changes</span></div>
296
+ </div>
297
+ <div class="grow"></div>
298
+ <button class="btn sun" id="runAll" type="button" data-action="run"></button>
299
+ </div>
300
+
301
+ <section class="view" id="view-dashboard">
302
+ <div class="sky" id="sky">
303
+ <div class="s-chip" id="skyIcon"></div>
304
+ <div class="s-text">
305
+ <div class="eyebrow" id="skyEyebrow">Do this next</div>
306
+ <h2 id="skyTitle">Reading your project...</h2>
307
+ <p id="skySub"></p>
308
+ </div>
309
+ <div id="skyActions"></div>
310
+ </div>
311
+ <div class="card gap">
312
+ <div class="card-head"><div><h3>Start here</h3><div class="c-sub">Do these in order. A step is done only once it has actually run.</div></div></div>
313
+ <div class="steps" id="steps"></div>
314
+ </div>
315
+ <div class="card gap">
316
+ <div class="card-head"><div><h3>Connect your AI tool</h3><div class="c-sub">Optional - your assistant then checks its own work, and does not call a change done until the check passes</div></div></div>
317
+ <div class="ai">
318
+ <div class="ai-tabs" id="aiTabs" role="tablist" aria-label="Your AI tool"></div>
319
+ <div class="ai-panel" id="aiPanel" role="tabpanel"></div>
320
+ </div>
321
+ </div>
322
+ </section>
323
+
324
+ <section class="view" id="view-findings" hidden>
325
+ <div class="card">
326
+ <div class="card-head">
327
+ <div><div class="c-sub">Open one: what is wrong, the fix prompt, then Re-check</div></div>
328
+ <span class="badge" id="findingBadge">0</span>
329
+ <div class="grow"></div>
330
+ <div class="seg" id="statusFilter"></div>
331
+ </div>
332
+ <div id="findingList"></div>
333
+ </div>
334
+ </section>
335
+
336
+ <section class="view" id="view-changes" hidden>
337
+ <div class="card">
338
+ <div class="card-head"><div><div class="c-sub">Every look Kryptheon took, newest first</div></div><span class="badge" id="lookBadge">0</span></div>
339
+ <div class="timeline" id="timeline"></div>
340
+ </div>
341
+ </section>
342
+
343
+ <section class="view" id="view-fixes" hidden>
344
+ <div class="card">
345
+ <div class="card-head"><div><div class="c-sub">Fixed only when a re-check said so</div></div><span class="badge" id="fixBadge">0</span></div>
346
+ <div id="fixList"></div>
347
+ </div>
348
+ </section>
349
+
350
+ <section class="view" id="view-checks" hidden>
351
+ <div class="check-grid" id="checkList"></div>
352
+ <div class="card gap">
353
+ <div class="card-head"><div><h3>Not built yet</h3><div class="c-sub">Listed so you know they exist - never shown as passed</div></div><span class="badge" id="naBadge">0</span></div>
354
+ <div class="na-grid" id="naList"></div>
355
+ </div>
356
+ </section>
357
+
358
+ <section class="view" id="view-runs" hidden>
359
+ <div class="card">
360
+ <div class="card-head"><div><div class="c-sub">Your recorded flows, replayed against your app</div></div><span class="badge" id="runBadge">0</span></div>
361
+ <div id="runList"></div>
362
+ </div>
363
+ </section>
364
+
365
+ <section class="view" id="view-storage" hidden>
366
+ <div class="card">
367
+ <div class="card-head"><div><div class="c-sub">On this machine, outside your project</div></div></div>
368
+ <p class="note" id="storeNote"></p>
369
+ <div class="path" id="storePath"></div>
370
+ <div class="files" id="storeFiles"></div>
371
+ </div>
372
+ </section>
373
+ </main>
374
+ </div>
375
+ <div class="toast" id="toast" role="status" aria-live="polite"></div>
376
+ <script src="/dashboard.js"></script>
377
+ </body>
378
+ </html>