Skip to main content

max / alloy_tui

47.8 KB · 1241 lines History Blame Raw
1 <!doctype html>
2 <html lang="en">
3 <head>
4 <meta charset="utf-8">
5 <title>Alloy — UX mockup</title>
6 <meta name="viewport" content="width=device-width, initial-scale=1">
7 <style>
8 /* ------- Fonts ------- */
9 @font-face {
10 font-family: "Departure Mono";
11 src: url("fonts/DepartureMonoNerdFontMono-Regular.otf") format("opentype");
12 font-weight: 400;
13 font-display: block;
14 }
15 @font-face {
16 font-family: "Iosevka";
17 src: url("https://cdn.jsdelivr.net/npm/@fontsource/iosevka@5.2.6/files/iosevka-latin-400-normal.woff2") format("woff2");
18 font-weight: 400;
19 font-style: normal;
20 font-display: swap;
21 }
22 @font-face {
23 font-family: "Iosevka";
24 src: url("https://cdn.jsdelivr.net/npm/@fontsource/iosevka@5.2.6/files/iosevka-latin-600-normal.woff2") format("woff2");
25 font-weight: 600;
26 font-style: normal;
27 font-display: swap;
28 }
29
30 /* ------- Tokens (light mode canonical) ------- */
31 :root {
32 /* Ramp — H=80, C=0.012 throughout */
33 --surface-sunken: oklch(92% 0.012 80);
34 --surface: oklch(96% 0.012 80);
35 --surface-raised: oklch(98% 0.012 80);
36 --surface-overlay: oklch(99.5% 0.012 80);
37 --border-subtle: oklch(88% 0.012 80);
38 --border: oklch(80% 0.012 80);
39 --border-strong: oklch(65% 0.012 80);
40 --text-muted: oklch(55% 0.012 80);
41 --text-secondary: oklch(38% 0.012 80);
42 --text-primary: oklch(18% 0.012 80);
43
44 /* Accents (mode-invariant) */
45 --accent-error: oklch(55% 0.18 25);
46 --accent-warn: oklch(70% 0.15 85);
47 --accent-healthy: oklch(62% 0.16 145);
48 --accent-info: oklch(60% 0.16 240);
49 --accent-syntax: oklch(55% 0.18 310);
50
51 /* Typography */
52 --font-mono-working: "Iosevka", ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace;
53 --font-mono-display: "Departure Mono", "Iosevka", ui-monospace, monospace;
54 --size-caption: 12px;
55 --size-body: 14px;
56 --size-section-header: 16px;
57 --size-title: 20px;
58 --size-readout-sm: 16px;
59 --size-readout-md: 24px;
60 --size-readout-lg: 48px;
61 --size-readout-xl: 72px;
62 --weight-body: 400;
63 --weight-emphasis: 600;
64 --tracking-body: 0;
65 --tracking-display: 0.04em;
66 --tracking-display-caps: 0.08em;
67 --line-height-body: 1.4;
68 --line-height-tabular: 1.3;
69 --line-height-display: 1.0;
70
71 /* Geometry */
72 --space-xs: 2px;
73 --space-sm: 4px;
74 --space-md: 8px;
75 --space-lg: 16px;
76 --space-xl: 24px;
77 --radius-control: 4px;
78 --radius-overlay: 6px;
79 --radius-data: 0;
80 --border-width-default: 1px;
81 --border-width-focus: 2px;
82 --focus-ring-offset: 1px;
83 }
84
85 /* Dark-mode polarity flip — same H/C, repositioned L stops per TOKENS.md */
86 body[data-mode="dark"] {
87 --surface-sunken: oklch(8% 0.012 80);
88 --surface: oklch(12% 0.012 80);
89 --surface-raised: oklch(15% 0.012 80);
90 --surface-overlay: oklch(19% 0.012 80);
91 --border-subtle: oklch(22% 0.012 80);
92 --border: oklch(30% 0.012 80);
93 --border-strong: oklch(48% 0.012 80);
94 --text-muted: oklch(60% 0.012 80);
95 --text-secondary: oklch(78% 0.012 80);
96 --text-primary: oklch(94% 0.012 80);
97 }
98
99 /* ------- Base ------- */
100 * { box-sizing: border-box; }
101 html, body {
102 margin: 0;
103 padding: 0;
104 background: var(--surface);
105 color: var(--text-primary);
106 font-family: var(--font-mono-working);
107 font-size: var(--size-body);
108 line-height: var(--line-height-body);
109 font-weight: var(--weight-body);
110 }
111
112 main {
113 max-width: 1100px;
114 margin: 0 auto;
115 padding: var(--space-xl);
116 }
117
118 /* ------- Header strip ------- */
119 .head {
120 display: flex;
121 align-items: baseline;
122 justify-content: space-between;
123 border-bottom: var(--border-width-default) solid var(--border);
124 padding-bottom: var(--space-lg);
125 margin-bottom: var(--space-xl);
126 }
127 .head h1 {
128 font-family: var(--font-mono-display);
129 font-size: var(--size-readout-md);
130 font-weight: 400;
131 letter-spacing: var(--tracking-display-caps);
132 margin: 0;
133 text-transform: uppercase;
134 }
135 .head .meta {
136 font-size: var(--size-caption);
137 color: var(--text-muted);
138 }
139 .head .meta strong { color: var(--text-secondary); font-weight: var(--weight-emphasis); }
140
141 .mode-toggle {
142 font-family: var(--font-mono-working);
143 font-size: var(--size-caption);
144 text-transform: uppercase;
145 letter-spacing: var(--tracking-display-caps);
146 background: var(--surface-raised);
147 border: var(--border-width-default) solid var(--border);
148 border-radius: var(--radius-control);
149 padding: var(--space-sm) var(--space-md);
150 color: var(--text-primary);
151 cursor: pointer;
152 }
153 .mode-toggle:hover { background: var(--surface-overlay); }
154 .mode-toggle:active { background: var(--surface); }
155 .mode-toggle:focus-visible {
156 outline: var(--border-width-focus) solid var(--border-strong);
157 outline-offset: var(--focus-ring-offset);
158 }
159
160 /* ------- Section pattern ------- */
161 section {
162 margin-bottom: var(--space-xl);
163 padding-bottom: var(--space-xl);
164 border-bottom: var(--border-width-default) solid var(--border-subtle);
165 }
166 section:last-child { border-bottom: none; }
167 section > h2 {
168 font-family: var(--font-mono-working);
169 font-size: var(--size-section-header);
170 font-weight: var(--weight-emphasis);
171 margin: 0 0 var(--space-md);
172 color: var(--text-primary);
173 }
174 section > .desc {
175 color: var(--text-secondary);
176 margin: 0 0 var(--space-lg);
177 font-size: var(--size-body);
178 }
179 section > .desc code {
180 background: var(--surface-sunken);
181 padding: 0 var(--space-xs);
182 border-radius: var(--radius-control);
183 font-size: 13px;
184 }
185
186 /* ------- Ramp swatches ------- */
187 .ramps { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-lg); }
188 .ramp-block {
189 background: var(--surface-raised);
190 border: var(--border-width-default) solid var(--border);
191 border-radius: var(--radius-control);
192 padding: var(--space-md);
193 }
194 .ramp-block h3 {
195 font-family: var(--font-mono-display);
196 font-size: var(--size-readout-sm);
197 letter-spacing: var(--tracking-display-caps);
198 text-transform: uppercase;
199 font-weight: 400;
200 margin: 0 0 var(--space-md);
201 color: var(--text-secondary);
202 }
203 .swatch {
204 display: grid;
205 grid-template-columns: 28px 1fr auto;
206 align-items: center;
207 gap: var(--space-md);
208 padding: var(--space-xs) 0;
209 font-size: var(--size-caption);
210 }
211 .swatch .chip {
212 width: 28px;
213 height: 28px;
214 border: var(--border-width-default) solid var(--border);
215 border-radius: var(--radius-data);
216 }
217 .swatch .name { font-weight: var(--weight-emphasis); }
218 .swatch .val { color: var(--text-muted); font-size: var(--size-caption); }
219
220 /* ------- Accents ------- */
221 .accents { display: flex; gap: var(--space-md); flex-wrap: wrap; }
222 .accent-card {
223 flex: 1 1 180px;
224 border: var(--border-width-default) solid var(--border);
225 border-radius: var(--radius-control);
226 background: var(--surface-raised);
227 padding: var(--space-md);
228 }
229 .accent-card .dot {
230 width: 14px; height: 14px;
231 border-radius: 50%;
232 display: inline-block;
233 vertical-align: middle;
234 margin-right: var(--space-sm);
235 }
236 .accent-card .lbl {
237 text-transform: uppercase;
238 letter-spacing: var(--tracking-display-caps);
239 font-size: var(--size-caption);
240 color: var(--text-secondary);
241 }
242 .accent-card .val {
243 display: block;
244 margin-top: var(--space-sm);
245 color: var(--text-muted);
246 font-size: var(--size-caption);
247 }
248
249 /* ------- Typography samples ------- */
250 .type-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-lg); }
251 .type-block {
252 border: var(--border-width-default) solid var(--border);
253 background: var(--surface-raised);
254 padding: var(--space-lg);
255 border-radius: var(--radius-control);
256 }
257 .type-block .role {
258 font-size: var(--size-caption);
259 text-transform: uppercase;
260 letter-spacing: var(--tracking-display-caps);
261 color: var(--text-muted);
262 margin-bottom: var(--space-md);
263 }
264 .type-block .working-line {
265 font-family: var(--font-mono-working);
266 margin: var(--space-xs) 0;
267 }
268 .type-block .display-line {
269 font-family: var(--font-mono-display);
270 margin: var(--space-xs) 0;
271 letter-spacing: var(--tracking-display);
272 line-height: var(--line-height-display);
273 }
274 .type-block .anno {
275 display: inline-block;
276 min-width: 7em;
277 color: var(--text-muted);
278 font-size: var(--size-caption);
279 }
280
281 /* ------- Button states grid ------- */
282 .states-grid {
283 display: grid;
284 grid-template-columns: 7em repeat(5, 1fr);
285 align-items: center;
286 gap: var(--space-md);
287 background: var(--surface-raised);
288 padding: var(--space-lg);
289 border: var(--border-width-default) solid var(--border);
290 border-radius: var(--radius-control);
291 }
292 .states-grid > .col-head {
293 font-size: var(--size-caption);
294 text-transform: uppercase;
295 letter-spacing: var(--tracking-display-caps);
296 color: var(--text-muted);
297 text-align: center;
298 }
299 .states-grid > .row-head {
300 font-size: var(--size-caption);
301 text-transform: uppercase;
302 letter-spacing: var(--tracking-display-caps);
303 color: var(--text-muted);
304 }
305
306 /* Button — base + states (statics; we render each forced state explicitly) */
307 .btn {
308 font-family: var(--font-mono-working);
309 font-size: var(--size-body);
310 font-weight: var(--weight-emphasis);
311 border-radius: var(--radius-control);
312 padding: var(--space-sm) var(--space-md);
313 border: var(--border-width-default) solid var(--border);
314 background: var(--surface-raised);
315 color: var(--text-primary);
316 cursor: pointer;
317 text-align: center;
318 display: inline-block;
319 width: 100%;
320 }
321 .btn.state-hover { background: var(--surface-overlay); }
322 .btn.state-pressed { background: var(--surface); }
323 .btn.state-focused { outline: var(--border-width-focus) solid var(--border-strong); outline-offset: var(--focus-ring-offset); }
324 .btn.state-disabled { background: var(--surface-raised); color: var(--text-muted); border-color: var(--border-subtle); cursor: not-allowed; }
325
326 /* ------- Form elements ------- */
327 .form-grid {
328 display: grid;
329 grid-template-columns: 1fr 1fr;
330 gap: var(--space-lg);
331 background: var(--surface-raised);
332 padding: var(--space-lg);
333 border: var(--border-width-default) solid var(--border);
334 border-radius: var(--radius-control);
335 }
336 .field { display: block; }
337 .field > label {
338 display: block;
339 font-size: var(--size-caption);
340 text-transform: uppercase;
341 letter-spacing: var(--tracking-display-caps);
342 color: var(--text-muted);
343 margin-bottom: var(--space-sm);
344 }
345 .field > input[type="text"],
346 .field > select {
347 width: 100%;
348 font-family: var(--font-mono-working);
349 font-size: var(--size-body);
350 background: var(--surface-sunken);
351 color: var(--text-primary);
352 border: var(--border-width-default) solid var(--border);
353 border-radius: var(--radius-control);
354 padding: var(--space-sm) var(--space-md);
355 }
356 .field > input[type="text"]:focus,
357 .field > select:focus {
358 outline: var(--border-width-focus) solid var(--border-strong);
359 outline-offset: var(--focus-ring-offset);
360 }
361
362 /* Custom checkbox */
363 .check {
364 display: inline-flex;
365 align-items: center;
366 gap: var(--space-md);
367 cursor: pointer;
368 user-select: none;
369 }
370 .check input { position: absolute; opacity: 0; pointer-events: none; }
371 .check .box {
372 width: 18px; height: 18px;
373 border: var(--border-width-default) solid var(--border);
374 background: var(--surface-sunken);
375 border-radius: var(--radius-control);
376 display: inline-flex;
377 align-items: center;
378 justify-content: center;
379 }
380 .check input:checked + .box::after {
381 content: "";
382 width: 10px; height: 10px;
383 background: var(--text-primary);
384 border-radius: 1px;
385 }
386 .check input:focus-visible + .box {
387 outline: var(--border-width-focus) solid var(--border-strong);
388 outline-offset: var(--focus-ring-offset);
389 }
390
391 /* Custom switch */
392 .switch {
393 display: inline-flex;
394 align-items: center;
395 gap: var(--space-md);
396 cursor: pointer;
397 user-select: none;
398 }
399 .switch input { position: absolute; opacity: 0; pointer-events: none; }
400 .switch .track {
401 width: 36px; height: 20px;
402 background: var(--surface-sunken);
403 border: var(--border-width-default) solid var(--border);
404 border-radius: 10px;
405 position: relative;
406 transition: background 0.08s linear;
407 }
408 .switch .track::after {
409 content: "";
410 position: absolute;
411 top: 2px; left: 2px;
412 width: 14px; height: 14px;
413 background: var(--text-secondary);
414 border-radius: 50%;
415 transition: transform 0.08s linear, background 0.08s linear;
416 }
417 .switch input:checked + .track { background: var(--border-strong); }
418 .switch input:checked + .track::after { transform: translateX(16px); background: var(--surface-raised); }
419 .switch input:focus-visible + .track {
420 outline: var(--border-width-focus) solid var(--border-strong);
421 outline-offset: var(--focus-ring-offset);
422 }
423
424 /* ------- Status readout panel (Departure showcase) ------- */
425 .status {
426 background: var(--surface-raised);
427 border: var(--border-width-default) solid var(--border);
428 border-radius: var(--radius-control);
429 padding: var(--space-lg);
430 display: grid;
431 grid-template-columns: 1fr 1fr;
432 gap: var(--space-lg);
433 }
434 .readout {
435 display: flex;
436 flex-direction: column;
437 gap: var(--space-xs);
438 border-left: var(--border-width-default) solid var(--border-subtle);
439 padding-left: var(--space-md);
440 }
441 .readout .lbl {
442 font-family: var(--font-mono-display);
443 font-size: var(--size-caption);
444 text-transform: uppercase;
445 letter-spacing: var(--tracking-display-caps);
446 color: var(--text-muted);
447 }
448 .readout .val {
449 font-family: var(--font-mono-display);
450 font-size: var(--size-readout-lg);
451 line-height: var(--line-height-display);
452 letter-spacing: var(--tracking-display);
453 color: var(--text-primary);
454 font-variant-numeric: tabular-nums;
455 }
456 .readout .val .unit {
457 font-size: var(--size-readout-md);
458 color: var(--text-muted);
459 }
460 .readout .sub {
461 font-family: var(--font-mono-working);
462 font-size: var(--size-caption);
463 color: var(--text-muted);
464 }
465 .bigclock {
466 grid-column: span 2;
467 text-align: center;
468 border-left: none;
469 border-bottom: var(--border-width-default) solid var(--border-subtle);
470 padding-bottom: var(--space-lg);
471 padding-left: 0;
472 }
473 .bigclock .val {
474 font-size: var(--size-readout-xl);
475 letter-spacing: var(--tracking-display);
476 }
477
478 /* ------- Settings row pattern (composed example) ------- */
479 .window {
480 background: var(--surface-raised);
481 border: var(--border-width-default) solid var(--border);
482 border-radius: var(--radius-control);
483 overflow: hidden;
484 }
485 .window > .titlebar {
486 display: flex;
487 align-items: center;
488 justify-content: space-between;
489 padding: var(--space-md) var(--space-lg);
490 background: var(--surface-overlay);
491 border-bottom: var(--border-width-default) solid var(--border-subtle);
492 }
493 .window > .titlebar .title {
494 font-size: var(--size-caption);
495 text-transform: uppercase;
496 letter-spacing: var(--tracking-display-caps);
497 color: var(--text-secondary);
498 }
499 .window > .body {
500 display: grid;
501 grid-template-columns: 200px 1fr;
502 }
503 .sidebar {
504 background: var(--surface);
505 border-right: var(--border-width-default) solid var(--border-subtle);
506 padding: var(--space-md) 0;
507 }
508 .sidebar a {
509 display: flex;
510 align-items: center;
511 gap: var(--space-md);
512 padding: var(--space-sm) var(--space-lg);
513 color: var(--text-secondary);
514 text-decoration: none;
515 font-size: var(--size-body);
516 }
517 .sidebar a:hover { background: var(--surface-overlay); color: var(--text-primary); }
518 .sidebar a.current {
519 background: var(--surface-raised);
520 color: var(--text-primary);
521 font-weight: var(--weight-emphasis);
522 border-left: 2px solid var(--border-strong);
523 padding-left: calc(var(--space-lg) - 2px);
524 }
525 .panel {
526 padding: var(--space-xl);
527 }
528 .panel-header {
529 display: flex;
530 align-items: center;
531 gap: var(--space-lg);
532 margin-bottom: var(--space-xl);
533 padding-bottom: var(--space-lg);
534 border-bottom: var(--border-width-default) solid var(--border-subtle);
535 }
536 .panel-header .hero { flex-shrink: 0; }
537 .panel-header .titleblock h3 {
538 font-family: var(--font-mono-display);
539 text-transform: uppercase;
540 letter-spacing: var(--tracking-display-caps);
541 font-size: var(--size-section-header);
542 font-weight: 400;
543 margin: 0 0 var(--space-sm);
544 color: var(--text-primary);
545 }
546 .panel-header .titleblock .sub {
547 color: var(--text-muted);
548 font-size: var(--size-caption);
549 }
550 .row {
551 display: grid;
552 grid-template-columns: 1fr auto;
553 align-items: center;
554 gap: var(--space-lg);
555 padding: var(--space-md) 0;
556 border-bottom: var(--border-width-default) solid var(--border-subtle);
557 }
558 .row:last-child { border-bottom: none; }
559 .row .key { display: flex; flex-direction: column; gap: var(--space-xs); }
560 .row .key .name { color: var(--text-primary); }
561 .row .key .hint { color: var(--text-muted); font-size: var(--size-caption); }
562
563 /* ------- Messages with accents (color-as-information) ------- */
564 .msg {
565 display: flex;
566 align-items: flex-start;
567 gap: var(--space-md);
568 padding: var(--space-md);
569 border-left: 3px solid var(--border);
570 background: var(--surface-raised);
571 border-radius: 0 var(--radius-control) var(--radius-control) 0;
572 margin: var(--space-sm) 0;
573 }
574 .msg .glyph {
575 width: 18px; height: 18px;
576 display: inline-flex;
577 align-items: center;
578 justify-content: center;
579 font-weight: var(--weight-emphasis);
580 flex-shrink: 0;
581 }
582 .msg.error { border-left-color: var(--accent-error); }
583 .msg.error .glyph { color: var(--accent-error); }
584 .msg.warn { border-left-color: var(--accent-warn); }
585 .msg.warn .glyph { color: var(--accent-warn); }
586 .msg.healthy { border-left-color: var(--accent-healthy); }
587 .msg.healthy .glyph { color: var(--accent-healthy); }
588 .msg.info { border-left-color: var(--accent-info); }
589 .msg.info .glyph { color: var(--accent-info); }
590
591 /* ------- Iso illustration block ------- */
592 .hero-grid {
593 display: grid;
594 grid-template-columns: repeat(4, 1fr);
595 gap: var(--space-lg);
596 }
597 .hero-tile {
598 background: var(--surface-raised);
599 border: var(--border-width-default) solid var(--border);
600 border-radius: var(--radius-control);
601 padding: var(--space-lg);
602 display: flex;
603 flex-direction: column;
604 align-items: center;
605 gap: var(--space-md);
606 }
607 .hero-tile svg { display: block; }
608 .hero-tile .lbl {
609 font-family: var(--font-mono-display);
610 font-size: var(--size-caption);
611 letter-spacing: var(--tracking-display-caps);
612 text-transform: uppercase;
613 color: var(--text-secondary);
614 }
615
616 /* color inheritance for SVG strokes/patterns */
617 .iso { color: var(--border-strong); }
618 .iso path, .iso line, .iso polyline, .iso polygon, .iso ellipse, .iso circle, .iso rect {
619 stroke: currentColor;
620 fill: none;
621 stroke-width: 1.5;
622 stroke-linecap: round;
623 stroke-linejoin: round;
624 }
625 .iso .hatch { stroke-width: 1; }
626 .iso .dim { stroke: var(--text-muted); stroke-width: 0.75; stroke-dasharray: 2 2; }
627 .iso .callout { fill: var(--text-muted); font: 9px var(--font-mono-display); letter-spacing: 0.05em; }
628 .iso .leader { stroke: var(--text-muted); stroke-width: 0.5; }
629
630 /* ------- App icon strip (dock pretend) ------- */
631 .dock {
632 display: flex;
633 gap: var(--space-md);
634 background: var(--surface-overlay);
635 border: var(--border-width-default) solid var(--border);
636 border-radius: var(--radius-overlay);
637 padding: var(--space-md);
638 width: fit-content;
639 margin: 0 auto;
640 }
641 .dock .app {
642 width: 96px; height: 96px;
643 background: var(--surface-raised);
644 border: var(--border-width-default) solid var(--border-subtle);
645 border-radius: var(--radius-control);
646 display: flex;
647 flex-direction: column;
648 align-items: center;
649 justify-content: center;
650 gap: var(--space-xs);
651 cursor: pointer;
652 }
653 .dock .app:hover { background: var(--surface-overlay); border-color: var(--border); }
654 .dock .app .lbl {
655 font-size: 10px;
656 text-transform: uppercase;
657 letter-spacing: var(--tracking-display-caps);
658 color: var(--text-muted);
659 }
660
661 /* Footer */
662 footer {
663 margin-top: var(--space-xl);
664 padding-top: var(--space-lg);
665 border-top: var(--border-width-default) solid var(--border);
666 font-size: var(--size-caption);
667 color: var(--text-muted);
668 }
669 footer a { color: var(--text-secondary); }
670 </style>
671 </head>
672 <body data-mode="light">
673 <main>
674
675 <div class="head">
676 <h1>Alloy &middot; UX mockup</h1>
677 <div style="display:flex; align-items:center; gap: var(--space-lg);">
678 <div class="meta">
679 tokens: <strong>TOKENS.md</strong> &middot;
680 icons: <strong>ICONOGRAPHY.md</strong> &middot;
681 mode: <strong id="mode-readout">light</strong>
682 </div>
683 <button class="mode-toggle" id="mode-toggle">flip polarity</button>
684 </div>
685 </div>
686
687 <!-- ============================================================== -->
688 <section>
689 <h2>1. Ramp</h2>
690 <p class="desc">Ten L-stops at hue 80, chroma 0.012. Dark mode preserves H/C and inverts polarity while keeping elevation ordering (raised reads lighter than base in both modes).</p>
691 <div class="ramps">
692 <div class="ramp-block">
693 <h3>Active mode</h3>
694 <div class="swatch"><div class="chip" style="background: var(--surface-sunken)"></div><span class="name">surface-sunken</span><span class="val">L 92 / 8</span></div>
695 <div class="swatch"><div class="chip" style="background: var(--surface)"></div><span class="name">surface</span><span class="val">L 96 / 12</span></div>
696 <div class="swatch"><div class="chip" style="background: var(--surface-raised)"></div><span class="name">surface-raised</span><span class="val">L 98 / 15</span></div>
697 <div class="swatch"><div class="chip" style="background: var(--surface-overlay)"></div><span class="name">surface-overlay</span><span class="val">L 99.5 / 19</span></div>
698 <div class="swatch"><div class="chip" style="background: var(--border-subtle)"></div><span class="name">border-subtle</span><span class="val">L 88 / 22</span></div>
699 <div class="swatch"><div class="chip" style="background: var(--border)"></div><span class="name">border</span><span class="val">L 80 / 30</span></div>
700 <div class="swatch"><div class="chip" style="background: var(--border-strong)"></div><span class="name">border-strong</span><span class="val">L 65 / 48</span></div>
701 <div class="swatch"><div class="chip" style="background: var(--text-muted)"></div><span class="name">text-muted</span><span class="val">L 55 / 60</span></div>
702 <div class="swatch"><div class="chip" style="background: var(--text-secondary)"></div><span class="name">text-secondary</span><span class="val">L 38 / 78</span></div>
703 <div class="swatch"><div class="chip" style="background: var(--text-primary)"></div><span class="name">text-primary</span><span class="val">L 18 / 94</span></div>
704 </div>
705 <div class="ramp-block">
706 <h3>Accents — same both modes</h3>
707 <div class="swatch"><div class="chip" style="background: var(--accent-error)"></div><span class="name">accent-error</span><span class="val">25°</span></div>
708 <div class="swatch"><div class="chip" style="background: var(--accent-warn)"></div><span class="name">accent-warn</span><span class="val">85°</span></div>
709 <div class="swatch"><div class="chip" style="background: var(--accent-healthy)"></div><span class="name">accent-healthy</span><span class="val">145°</span></div>
710 <div class="swatch"><div class="chip" style="background: var(--accent-info)"></div><span class="name">accent-info</span><span class="val">240°</span></div>
711 <div class="swatch"><div class="chip" style="background: var(--accent-syntax)"></div><span class="name">accent-syntax</span><span class="val">310°</span></div>
712
713 <div style="margin-top: var(--space-lg)">
714 <div class="msg error"><div class="glyph">!</div><div><strong>Disk write failed.</strong> Bay 03 reports a hardware fault. Action required.</div></div>
715 <div class="msg warn"><div class="glyph">&#9888;</div><div><strong>Battery at 18%.</strong> Plug in or close non-essential applications.</div></div>
716 <div class="msg healthy"><div class="glyph">&#10003;</div><div><strong>Backup complete.</strong> 24,108 files written to archive volume.</div></div>
717 <div class="msg info"><div class="glyph">i</div><div><strong>Update available.</strong> alloy-system 0.4.1 is ready to install.</div></div>
718 </div>
719 </div>
720 </div>
721 </section>
722
723 <!-- ============================================================== -->
724 <section>
725 <h2>2. Typography &mdash; two fonts, two roles</h2>
726 <p class="desc">Iosevka for anything authored or read. Departure Mono for anything <em>displayed as a readout</em>. The seam between them is where the mil-spec register lives.</p>
727 <div class="type-grid">
728 <div class="type-block">
729 <div class="role">Working &mdash; Iosevka</div>
730 <div class="working-line" style="font-size: 20px; font-weight: 600"><span class="anno">title 20/600</span>Schedule a maintenance window</div>
731 <div class="working-line" style="font-size: 16px; font-weight: 600"><span class="anno">header 16/600</span>Connected interfaces</div>
732 <div class="working-line" style="font-size: 14px; font-weight: 400"><span class="anno">body 14/400</span>The relay station reports nominal voltage across all three phases.</div>
733 <div class="working-line" style="font-size: 14px; font-weight: 600"><span class="anno">strong 14/600</span>Operator override is in effect.</div>
734 <div class="working-line" style="font-size: 12px; font-weight: 400; color: var(--text-muted)"><span class="anno">caption 12/400</span>Last polled 14:22:08 &middot; jitter 1.4ms</div>
735 </div>
736 <div class="type-block">
737 <div class="role">Display &mdash; Departure</div>
738 <div class="display-line" style="font-size: 48px"><span class="anno" style="color: var(--text-muted); font-family: var(--font-mono-working)">readout 48</span>14:22:08</div>
739 <div class="display-line" style="font-size: 24px"><span class="anno" style="color: var(--text-muted); font-family: var(--font-mono-working)">readout 24</span>CPU 12% &middot; 36C</div>
740 <div class="display-line" style="font-size: 16px; text-transform: uppercase; letter-spacing: var(--tracking-display-caps)"><span class="anno" style="color: var(--text-muted); font-family: var(--font-mono-working)">caps 16/.08</span>Generator A nominal</div>
741 <div class="display-line" style="font-size: 12px; text-transform: uppercase; letter-spacing: var(--tracking-display-caps); color: var(--text-muted)"><span class="anno" style="color: var(--text-muted); font-family: var(--font-mono-working)">caps 12/.08</span>Bay 03 // FAULT</div>
742 </div>
743 </div>
744 </section>
745
746 <!-- ============================================================== -->
747 <section>
748 <h2>3. Control states</h2>
749 <p class="desc">Every interactive surface defines five states. Hover steps toward the eye (lighter in both modes). Pressed steps away. Focus is <code>border-strong</code> at 2px, never an accent color.</p>
750 <div class="states-grid">
751 <div></div>
752 <div class="col-head">default</div>
753 <div class="col-head">hover</div>
754 <div class="col-head">pressed</div>
755 <div class="col-head">focused</div>
756 <div class="col-head">disabled</div>
757
758 <div class="row-head">Button</div>
759 <button class="btn">Apply</button>
760 <button class="btn state-hover">Apply</button>
761 <button class="btn state-pressed">Apply</button>
762 <button class="btn state-focused">Apply</button>
763 <button class="btn state-disabled" disabled>Apply</button>
764 </div>
765 </section>
766
767 <!-- ============================================================== -->
768 <section>
769 <h2>4. Form elements</h2>
770 <p class="desc">Inputs sit on <code>surface-sunken</code> &mdash; recessed, signaling editability. Switches use ramp-only color; the "on" state shifts to <code>border-strong</code>, not an accent.</p>
771 <div class="form-grid">
772 <div class="field">
773 <label>Station identifier</label>
774 <input type="text" value="RS-04 // Bell Hollow">
775 </div>
776 <div class="field">
777 <label>Polling interval</label>
778 <select>
779 <option>250 ms</option>
780 <option selected>500 ms</option>
781 <option>1 s</option>
782 <option>5 s</option>
783 </select>
784 </div>
785 <div class="field">
786 <label>Toggles</label>
787 <div style="display: flex; flex-direction: column; gap: var(--space-md);">
788 <label class="switch"><input type="checkbox" checked><span class="track"></span><span>Annunciator audible</span></label>
789 <label class="switch"><input type="checkbox"><span class="track"></span><span>Auto-reset on fault clear</span></label>
790 <label class="switch"><input type="checkbox" checked><span class="track"></span><span>Log to archive volume</span></label>
791 </div>
792 </div>
793 <div class="field">
794 <label>Channels</label>
795 <div style="display: flex; flex-direction: column; gap: var(--space-md);">
796 <label class="check"><input type="checkbox" checked><span class="box"></span><span>Generator A</span></label>
797 <label class="check"><input type="checkbox" checked><span class="box"></span><span>Generator B</span></label>
798 <label class="check"><input type="checkbox"><span class="box"></span><span>Generator C (offline)</span></label>
799 <label class="check"><input type="checkbox" checked><span class="box"></span><span>Microwave relay 04-N</span></label>
800 </div>
801 </div>
802 </div>
803 </section>
804
805 <!-- ============================================================== -->
806 <section>
807 <h2>5. Status readouts &mdash; Departure in its role</h2>
808 <p class="desc">The display font earning its rent. Tabular numerics, fixed weight, UPPERCASE labels with tracking. This is what makes Alloy look like an instrument rather than a productivity app.</p>
809 <div class="status">
810 <div class="readout bigclock">
811 <span class="lbl">Local time &middot; UTC&minus;06</span>
812 <span class="val">14:22:08</span>
813 <span class="sub">Drift 0.4 ms over last 24h</span>
814 </div>
815 <div class="readout">
816 <span class="lbl">CPU load</span>
817 <span class="val">12<span class="unit">%</span></span>
818 <span class="sub">8 cores nominal &middot; 36&deg;C</span>
819 </div>
820 <div class="readout">
821 <span class="lbl">Memory</span>
822 <span class="val">9.4<span class="unit">G</span></span>
823 <span class="sub">of 32G &middot; 28% utilized</span>
824 </div>
825 <div class="readout">
826 <span class="lbl">Net &uarr;</span>
827 <span class="val">1.4<span class="unit">M</span></span>
828 <span class="sub">wlp1s0 &middot; jitter 1.2 ms</span>
829 </div>
830 <div class="readout">
831 <span class="lbl">Net &darr;</span>
832 <span class="val">12.8<span class="unit">M</span></span>
833 <span class="sub">peak 28.4M / 10s</span>
834 </div>
835 </div>
836 </section>
837
838 <!-- ============================================================== -->
839 <section>
840 <h2>6. Hero iconography &mdash; relay station theme</h2>
841 <p class="desc">Placeholders, drawn in inline SVG to demonstrate the style rules from <code>ICONOGRAPHY.md</code>. True isometric, 1.5px line on <code>border-strong</code>, mandatory hatching, no fills. Real illustrations get drawn for v1.</p>
842 <div class="hero-grid">
843 <div class="hero-tile">
844 <!-- Microwave relay tower -->
845 <svg class="iso" viewBox="0 0 120 160" width="100" height="140" aria-label="Microwave relay tower">
846 <defs>
847 <pattern id="metal-tower" patternUnits="userSpaceOnUse" width="6" height="6" patternTransform="rotate(45)">
848 <line class="hatch" x1="0" y1="0" x2="0" y2="6"/>
849 </pattern>
850 </defs>
851 <!-- ground line -->
852 <line x1="20" y1="140" x2="100" y2="140"/>
853 <line class="hatch" x1="22" y1="143" x2="98" y2="143"/>
854 <line class="hatch" x1="26" y1="146" x2="94" y2="146"/>
855 <line class="hatch" x1="30" y1="149" x2="90" y2="149"/>
856 <!-- concrete pad -->
857 <polygon points="40,140 80,140 84,135 44,135"/>
858 <!-- mast vertical lines (iso vertical) -->
859 <line x1="58" y1="135" x2="58" y2="40"/>
860 <line x1="66" y1="135" x2="66" y2="40"/>
861 <!-- mast crossbracing (X pattern) -->
862 <line x1="58" y1="125" x2="66" y2="115"/>
863 <line x1="66" y1="125" x2="58" y2="115"/>
864 <line x1="58" y1="115" x2="66" y2="105"/>
865 <line x1="66" y1="115" x2="58" y2="105"/>
866 <line x1="58" y1="105" x2="66" y2="95"/>
867 <line x1="66" y1="105" x2="58" y2="95"/>
868 <line x1="58" y1="95" x2="66" y2="85"/>
869 <line x1="66" y1="95" x2="58" y2="85"/>
870 <line x1="58" y1="85" x2="66" y2="75"/>
871 <line x1="66" y1="85" x2="58" y2="75"/>
872 <line x1="58" y1="75" x2="66" y2="65"/>
873 <line x1="66" y1="75" x2="58" y2="65"/>
874 <line x1="58" y1="65" x2="66" y2="55"/>
875 <line x1="66" y1="65" x2="58" y2="55"/>
876 <line x1="58" y1="55" x2="66" y2="45"/>
877 <line x1="66" y1="55" x2="58" y2="45"/>
878 <!-- horn antennas at top -->
879 <path d="M 50 50 L 58 50 L 58 42 L 50 42 Z"/>
880 <path d="M 50 50 L 46 54 L 46 46 L 50 42"/>
881 <path d="M 66 50 L 74 50 L 74 42 L 66 42 Z"/>
882 <path d="M 74 50 L 78 54 L 78 46 L 74 42"/>
883 <!-- top cap -->
884 <line x1="58" y1="40" x2="66" y2="40"/>
885 <circle cx="62" cy="36" r="2"/>
886 </svg>
887 <div class="lbl">Network</div>
888 </div>
889
890 <div class="hero-tile">
891 <!-- Generator + transformer -->
892 <svg class="iso" viewBox="0 0 160 160" width="120" height="120" aria-label="Generator and transformer">
893 <defs>
894 <pattern id="metal-gen" patternUnits="userSpaceOnUse" width="5" height="5" patternTransform="rotate(45)">
895 <line class="hatch" x1="0" y1="0" x2="0" y2="5"/>
896 </pattern>
897 </defs>
898 <!-- ground line -->
899 <line x1="10" y1="140" x2="150" y2="140"/>
900 <line class="hatch" x1="14" y1="144" x2="148" y2="144"/>
901 <line class="hatch" x1="20" y1="148" x2="142" y2="148"/>
902 <!-- concrete plinth (iso box) -->
903 <polygon points="20,140 80,140 90,130 30,130"/>
904 <polygon points="80,140 80,135 90,125 90,130"/>
905 <line x1="20" y1="140" x2="20" y2="138"/>
906 <!-- generator cylinder horizontal (iso) -->
907 <!-- left ellipse -->
908 <ellipse cx="35" cy="110" rx="6" ry="14" transform="rotate(-30 35 110)"/>
909 <!-- right ellipse -->
910 <ellipse cx="80" cy="110" rx="6" ry="14" transform="rotate(-30 80 110)"/>
911 <!-- top connecting line -->
912 <line x1="32" y1="98" x2="77" y2="98"/>
913 <!-- bottom connecting line -->
914 <line x1="38" y1="122" x2="83" y2="122"/>
915 <!-- bands across cylinder -->
916 <line x1="48" y1="100" x2="51" y2="124"/>
917 <line x1="65" y1="100" x2="68" y2="124"/>
918 <!-- junction box on top -->
919 <polygon points="48,90 62,90 66,86 52,86"/>
920 <polygon points="62,90 62,98 66,94 66,86"/>
921 <polygon points="48,90 48,98 62,98 62,90"/>
922 <!-- output conduit going right to transformer -->
923 <line x1="64" y1="88" x2="100" y2="78"/>
924 <!-- transformer (iso box on plinth) -->
925 <polygon points="105,120 140,120 148,114 113,114"/>
926 <polygon points="140,120 140,80 148,74 148,114"/>
927 <polygon points="105,120 105,80 140,80 140,120"/>
928 <!-- transformer cooling fins -->
929 <line x1="142" y1="115" x2="142" y2="80"/>
930 <line x1="144" y1="113" x2="144" y2="78"/>
931 <line x1="146" y1="111" x2="146" y2="76"/>
932 <!-- bushings on top -->
933 <ellipse cx="115" cy="78" rx="2" ry="1"/>
934 <line x1="115" y1="78" x2="115" y2="70"/>
935 <ellipse cx="125" cy="76" rx="2" ry="1"/>
936 <line x1="125" y1="76" x2="125" y2="68"/>
937 <ellipse cx="135" cy="74" rx="2" ry="1"/>
938 <line x1="135" y1="74" x2="135" y2="66"/>
939 </svg>
940 <div class="lbl">Power</div>
941 </div>
942
943 <div class="hero-tile">
944 <!-- Annunciator panel -->
945 <svg class="iso" viewBox="0 0 160 160" width="120" height="120" aria-label="Annunciator panel">
946 <!-- floor line -->
947 <line x1="20" y1="145" x2="140" y2="145"/>
948 <line class="hatch" x1="24" y1="148" x2="138" y2="148"/>
949 <line class="hatch" x1="30" y1="151" x2="132" y2="151"/>
950 <!-- base plinth -->
951 <polygon points="50,145 110,145 120,138 60,138"/>
952 <polygon points="110,145 110,142 120,135 120,138"/>
953 <!-- panel face (iso vertical face) -->
954 <polygon points="50,138 110,138 110,40 50,40"/>
955 <!-- panel top (iso top face) -->
956 <polygon points="50,40 110,40 120,32 60,32"/>
957 <!-- panel side -->
958 <polygon points="110,40 110,138 120,130 120,32"/>
959 <!-- lamp grid 3x4 on front face -->
960 <g>
961 <rect x="55" y="48" width="12" height="10"/>
962 <rect x="72" y="48" width="12" height="10"/>
963 <rect x="89" y="48" width="12" height="10"/>
964 <rect x="55" y="63" width="12" height="10"/>
965 <rect x="72" y="63" width="12" height="10"/>
966 <rect x="89" y="63" width="12" height="10"/>
967 <rect x="55" y="78" width="12" height="10"/>
968 <rect x="72" y="78" width="12" height="10"/>
969 <rect x="89" y="78" width="12" height="10"/>
970 <rect x="55" y="93" width="12" height="10"/>
971 <rect x="72" y="93" width="12" height="10"/>
972 <rect x="89" y="93" width="12" height="10"/>
973 </g>
974 <!-- label strip -->
975 <line x1="55" y1="112" x2="101" y2="112"/>
976 <line x1="55" y1="120" x2="101" y2="120"/>
977 <!-- label hatching (parallel lines = label text placeholder) -->
978 <line class="hatch" x1="57" y1="115" x2="98" y2="115"/>
979 <line class="hatch" x1="57" y1="117" x2="98" y2="117"/>
980 <!-- reset button bottom right -->
981 <ellipse cx="98" cy="130" rx="3" ry="2"/>
982 </svg>
983 <div class="lbl">Notifications</div>
984 </div>
985
986 <div class="hero-tile">
987 <!-- Parts crate on pallet -->
988 <svg class="iso" viewBox="0 0 160 160" width="120" height="120" aria-label="Parts bay crate">
989 <!-- floor -->
990 <line x1="10" y1="145" x2="150" y2="145"/>
991 <line class="hatch" x1="14" y1="148" x2="148" y2="148"/>
992 <line class="hatch" x1="20" y1="151" x2="142" y2="151"/>
993 <!-- pallet slats (iso) -->
994 <polygon points="30,140 110,140 130,128 50,128"/>
995 <polygon points="110,140 110,135 130,123 130,128"/>
996 <line x1="30" y1="140" x2="30" y2="135"/>
997 <line x1="30" y1="135" x2="110" y2="135"/>
998 <!-- pallet gap lines -->
999 <line x1="55" y1="138" x2="75" y2="126"/>
1000 <line x1="85" y1="138" x2="105" y2="126"/>
1001 <!-- crate body -->
1002 <polygon points="40,128 100,128 120,116 60,116"/>
1003 <polygon points="100,128 100,60 120,48 120,116"/>
1004 <polygon points="40,128 40,60 100,60 100,128"/>
1005 <!-- crate bracing X on front -->
1006 <line x1="40" y1="128" x2="100" y2="60"/>
1007 <line x1="100" y1="128" x2="40" y2="60"/>
1008 <!-- crate bracing on side -->
1009 <line x1="100" y1="128" x2="120" y2="48"/>
1010 <line x1="100" y1="60" x2="120" y2="116"/>
1011 <!-- top slats -->
1012 <line x1="50" y1="60" x2="70" y2="48"/>
1013 <line x1="60" y1="60" x2="80" y2="48"/>
1014 <line x1="70" y1="60" x2="90" y2="48"/>
1015 <line x1="80" y1="60" x2="100" y2="48"/>
1016 <line x1="90" y1="60" x2="110" y2="48"/>
1017 <!-- stencil label on front -->
1018 <line x1="55" y1="100" x2="85" y2="100"/>
1019 <line x1="55" y1="105" x2="85" y2="105"/>
1020 <line class="hatch" x1="58" y1="102" x2="82" y2="102"/>
1021 </svg>
1022 <div class="lbl">Packages</div>
1023 </div>
1024 </div>
1025 </section>
1026
1027 <!-- ============================================================== -->
1028 <section>
1029 <h2>7. Authored app icons &mdash; dock</h2>
1030 <p class="desc">Each marquee Alloy app gets a piece of facility equipment as its identity. Drawn against the chrome ramp, no color.</p>
1031 <div class="dock">
1032 <div class="app">
1033 <svg class="iso" viewBox="0 0 60 60" width="56" height="56" aria-label="Lockscreen">
1034 <line x1="6" y1="52" x2="54" y2="52"/>
1035 <line class="hatch" x1="10" y1="55" x2="50" y2="55"/>
1036 <polygon points="18,52 42,52 48,46 24,46"/>
1037 <polygon points="42,52 42,20 48,14 48,46"/>
1038 <polygon points="18,52 18,20 42,20 42,52"/>
1039 <circle cx="30" cy="36" r="4"/>
1040 <line x1="30" y1="40" x2="30" y2="46"/>
1041 </svg>
1042 <span class="lbl">Lock</span>
1043 </div>
1044 <div class="app">
1045 <svg class="iso" viewBox="0 0 60 60" width="56" height="56" aria-label="Packages">
1046 <line x1="6" y1="52" x2="54" y2="52"/>
1047 <line class="hatch" x1="10" y1="55" x2="50" y2="55"/>
1048 <polygon points="15,48 40,48 48,40 23,40"/>
1049 <polygon points="40,48 40,22 48,14 48,40"/>
1050 <polygon points="15,48 15,22 40,22 40,48"/>
1051 <line x1="15" y1="48" x2="40" y2="22"/>
1052 <line x1="40" y1="48" x2="15" y2="22"/>
1053 </svg>
1054 <span class="lbl">Packages</span>
1055 </div>
1056 <div class="app">
1057 <svg class="iso" viewBox="0 0 60 60" width="56" height="56" aria-label="Settings">
1058 <line x1="6" y1="52" x2="54" y2="52"/>
1059 <line class="hatch" x1="10" y1="55" x2="50" y2="55"/>
1060 <polygon points="20,50 40,50 46,44 26,44"/>
1061 <polygon points="20,44 40,44 40,16 20,16"/>
1062 <polygon points="40,44 40,16 46,10 46,38"/>
1063 <polygon points="20,16 40,16 46,10 26,10"/>
1064 <!-- knobs grid -->
1065 <circle cx="25" cy="24" r="2"/>
1066 <circle cx="32" cy="24" r="2"/>
1067 <circle cx="25" cy="32" r="2"/>
1068 <circle cx="32" cy="32" r="2"/>
1069 </svg>
1070 <span class="lbl">Settings</span>
1071 </div>
1072 <div class="app">
1073 <svg class="iso" viewBox="0 0 60 60" width="56" height="56" aria-label="Terminal">
1074 <line x1="6" y1="52" x2="54" y2="52"/>
1075 <line class="hatch" x1="10" y1="55" x2="50" y2="55"/>
1076 <polygon points="14,50 42,50 48,44 20,44"/>
1077 <polygon points="42,50 42,18 48,12 48,44"/>
1078 <polygon points="14,50 14,18 42,18 42,50"/>
1079 <line x1="18" y1="26" x2="22" y2="30"/>
1080 <line x1="22" y1="30" x2="18" y2="34"/>
1081 <line x1="24" y1="36" x2="32" y2="36"/>
1082 </svg>
1083 <span class="lbl">Terminal</span>
1084 </div>
1085 <div class="app">
1086 <svg class="iso" viewBox="0 0 60 60" width="56" height="56" aria-label="Files">
1087 <line x1="6" y1="52" x2="54" y2="52"/>
1088 <line class="hatch" x1="10" y1="55" x2="50" y2="55"/>
1089 <polygon points="14,46 36,46 42,40 20,40"/>
1090 <polygon points="14,46 14,28 36,28 36,46"/>
1091 <polygon points="36,46 36,28 42,22 42,40"/>
1092 <polygon points="14,28 36,28 42,22 20,22"/>
1093 <line x1="18" y1="34" x2="32" y2="34"/>
1094 <line x1="18" y1="40" x2="32" y2="40"/>
1095 </svg>
1096 <span class="lbl">Files</span>
1097 </div>
1098 </div>
1099 </section>
1100
1101 <!-- ============================================================== -->
1102 <section>
1103 <h2>8. Composed window &mdash; settings panel</h2>
1104 <p class="desc">Putting everything together. A typical chrome surface: titlebar, sidebar navigation, panel header with hero illustration, settings rows with the working-font/display-font split.</p>
1105 <div class="window">
1106 <div class="titlebar">
1107 <div class="title">Alloy &middot; Settings &middot; Network</div>
1108 <div class="title" style="color: var(--text-muted)">RS-04 // BELL HOLLOW</div>
1109 </div>
1110 <div class="body">
1111 <nav class="sidebar">
1112 <a href="#">Display</a>
1113 <a href="#" class="current">Network</a>
1114 <a href="#">Sound</a>
1115 <a href="#">Power</a>
1116 <a href="#">Storage</a>
1117 <a href="#">Updates</a>
1118 <a href="#">Privacy</a>
1119 </nav>
1120 <div class="panel">
1121 <div class="panel-header">
1122 <div class="hero">
1123 <svg class="iso" viewBox="0 0 120 160" width="80" height="110" aria-label="Microwave relay">
1124 <line x1="20" y1="140" x2="100" y2="140"/>
1125 <line class="hatch" x1="22" y1="143" x2="98" y2="143"/>
1126 <line class="hatch" x1="26" y1="146" x2="94" y2="146"/>
1127 <polygon points="40,140 80,140 84,135 44,135"/>
1128 <line x1="58" y1="135" x2="58" y2="40"/>
1129 <line x1="66" y1="135" x2="66" y2="40"/>
1130 <line x1="58" y1="125" x2="66" y2="115"/>
1131 <line x1="66" y1="125" x2="58" y2="115"/>
1132 <line x1="58" y1="105" x2="66" y2="95"/>
1133 <line x1="66" y1="105" x2="58" y2="95"/>
1134 <line x1="58" y1="85" x2="66" y2="75"/>
1135 <line x1="66" y1="85" x2="58" y2="75"/>
1136 <line x1="58" y1="65" x2="66" y2="55"/>
1137 <line x1="66" y1="65" x2="58" y2="55"/>
1138 <path d="M 50 50 L 58 50 L 58 42 L 50 42 Z"/>
1139 <path d="M 50 50 L 46 54 L 46 46 L 50 42"/>
1140 <path d="M 66 50 L 74 50 L 74 42 L 66 42 Z"/>
1141 <path d="M 74 50 L 78 54 L 78 46 L 74 42"/>
1142 </svg>
1143 </div>
1144 <div class="titleblock">
1145 <h3>Network &middot; transmission</h3>
1146 <div class="sub">wlp1s0 &middot; en0 &middot; relay 04-N &middot; auto-failover engaged</div>
1147 </div>
1148 </div>
1149
1150 <div class="row">
1151 <div class="key">
1152 <span class="name">Primary interface</span>
1153 <span class="hint">Used for outbound traffic unless overridden</span>
1154 </div>
1155 <div>
1156 <select style="width: 180px">
1157 <option>wlp1s0 (wifi)</option>
1158 <option selected>en0 (ethernet)</option>
1159 </select>
1160 </div>
1161 </div>
1162
1163 <div class="row">
1164 <div class="key">
1165 <span class="name">Connect on boot</span>
1166 <span class="hint">Restore last-known interface state at session start</span>
1167 </div>
1168 <label class="switch"><input type="checkbox" checked><span class="track"></span></label>
1169 </div>
1170
1171 <div class="row">
1172 <div class="key">
1173 <span class="name">DNS over HTTPS</span>
1174 <span class="hint">Resolve via Cloudflare 1.1.1.1, fall back to ISP</span>
1175 </div>
1176 <label class="switch"><input type="checkbox"><span class="track"></span></label>
1177 </div>
1178
1179 <div class="row">
1180 <div class="key">
1181 <span class="name">Polling interval</span>
1182 <span class="hint">How often link status and throughput are sampled</span>
1183 </div>
1184 <select style="width: 140px">
1185 <option>250 ms</option>
1186 <option selected>500 ms</option>
1187 <option>1 s</option>
1188 </select>
1189 </div>
1190
1191 <div class="row" style="border-bottom: none; padding-top: var(--space-lg)">
1192 <div class="key">
1193 <span class="name">Live readout</span>
1194 <span class="hint">Real-time throughput on the active interface</span>
1195 </div>
1196 <div style="display: flex; gap: var(--space-lg); font-family: var(--font-mono-display); font-variant-numeric: tabular-nums;">
1197 <div style="text-align: right">
1198 <div style="font-size: var(--size-caption); letter-spacing: var(--tracking-display-caps); text-transform: uppercase; color: var(--text-muted)">UP</div>
1199 <div style="font-size: var(--size-readout-md)">1.4M</div>
1200 </div>
1201 <div style="text-align: right">
1202 <div style="font-size: var(--size-caption); letter-spacing: var(--tracking-display-caps); text-transform: uppercase; color: var(--text-muted)">DOWN</div>
1203 <div style="font-size: var(--size-readout-md)">12.8M</div>
1204 </div>
1205 <div style="text-align: right">
1206 <div style="font-size: var(--size-caption); letter-spacing: var(--tracking-display-caps); text-transform: uppercase; color: var(--text-muted)">PING</div>
1207 <div style="font-size: var(--size-readout-md)">8<span style="color: var(--text-muted)">ms</span></div>
1208 </div>
1209 </div>
1210 </div>
1211
1212 <div style="display: flex; justify-content: flex-end; gap: var(--space-md); margin-top: var(--space-xl); padding-top: var(--space-lg); border-top: var(--border-width-default) solid var(--border-subtle)">
1213 <button class="btn state-disabled" style="width: auto" disabled>Revert</button>
1214 <button class="btn" style="width: auto; background: var(--surface); border-color: var(--border)">Cancel</button>
1215 <button class="btn" style="width: auto; background: var(--text-primary); color: var(--surface-raised); border-color: var(--text-primary)">Apply</button>
1216 </div>
1217 </div>
1218 </div>
1219 </div>
1220 </section>
1221
1222 <footer>
1223 Alloy &middot; mockup &middot; tokens locked in <a href="../TOKENS.md">TOKENS.md</a> &middot; iconography in <a href="../ICONOGRAPHY.md">ICONOGRAPHY.md</a>.
1224 Iso illustrations are rough SVG placeholders &mdash; the real ones get drawn for v1.
1225 </footer>
1226
1227 </main>
1228
1229 <script>
1230 const toggle = document.getElementById('mode-toggle');
1231 const readout = document.getElementById('mode-readout');
1232 toggle.addEventListener('click', () => {
1233 const cur = document.body.dataset.mode;
1234 const next = cur === 'dark' ? 'light' : 'dark';
1235 document.body.dataset.mode = next;
1236 readout.textContent = next;
1237 });
1238 </script>
1239 </body>
1240 </html>
1241