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