mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-25 17:45:53 +01:00
1147 lines
52 KiB
HTML
1147 lines
52 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<meta name="color-scheme" content="dark" />
|
||
<title>Document highlight exploration</title>
|
||
<style>
|
||
@font-face {
|
||
font-family: "InterVariable";
|
||
src: url("/fonts/InterVariable.woff2") format("woff2");
|
||
font-style: normal;
|
||
font-weight: 100 900;
|
||
font-display: swap;
|
||
}
|
||
|
||
:root {
|
||
--background: oklch(0.145 0 0);
|
||
--foreground: oklch(0.985 0 0);
|
||
--muted-foreground: oklch(0.708 0 0);
|
||
--border: oklch(1 0 0 / 10%);
|
||
--subtle: oklch(1 0 0 / 6%);
|
||
--subtle-hover: oklch(1 0 0 / 9%);
|
||
--focus: oklch(0.72 0.15 282);
|
||
--reading-width: 32rem;
|
||
}
|
||
|
||
* { box-sizing: border-box; }
|
||
|
||
html {
|
||
background: var(--background);
|
||
color: var(--foreground);
|
||
font-family: InterVariable, Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
|
||
-webkit-font-smoothing: antialiased;
|
||
text-rendering: optimizeLegibility;
|
||
}
|
||
|
||
body {
|
||
margin: 0;
|
||
min-width: 20rem;
|
||
background: var(--background);
|
||
color: var(--foreground);
|
||
}
|
||
|
||
button { font: inherit; }
|
||
|
||
.page {
|
||
width: min(100%, 90rem);
|
||
margin: 0 auto;
|
||
padding: 3rem clamp(1.25rem, 4vw, 4rem) 6rem;
|
||
}
|
||
|
||
.eyebrow {
|
||
margin: 0 0 0.75rem;
|
||
color: var(--muted-foreground);
|
||
font-size: 0.75rem;
|
||
font-weight: 600;
|
||
letter-spacing: 0.08em;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.hero {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) minmax(18rem, 26rem);
|
||
gap: 3rem;
|
||
align-items: end;
|
||
padding-bottom: 2rem;
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
|
||
.hero h1 {
|
||
max-width: 46rem;
|
||
margin: 0;
|
||
font-size: clamp(2rem, 4vw, 3.5rem);
|
||
font-weight: 600;
|
||
letter-spacing: -0.035em;
|
||
line-height: 1.05;
|
||
}
|
||
|
||
.hero p {
|
||
max-width: 43rem;
|
||
margin: 1.25rem 0 0;
|
||
color: var(--muted-foreground);
|
||
font-size: 0.9375rem;
|
||
line-height: 1.5rem;
|
||
}
|
||
|
||
.fixed-tokens {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
gap: 0.75rem;
|
||
margin: 0;
|
||
}
|
||
|
||
.fixed-tokens div {
|
||
min-width: 0;
|
||
padding: 0.75rem 0.875rem;
|
||
border: 1px solid var(--border);
|
||
border-radius: 0.5rem;
|
||
background: var(--subtle);
|
||
}
|
||
|
||
.fixed-tokens dt {
|
||
margin: 0 0 0.25rem;
|
||
color: var(--muted-foreground);
|
||
font-size: 0.6875rem;
|
||
font-weight: 600;
|
||
letter-spacing: 0.05em;
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.fixed-tokens dd {
|
||
margin: 0;
|
||
overflow: hidden;
|
||
font-size: 0.8125rem;
|
||
line-height: 1.125rem;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.toolbar {
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 10;
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 1rem;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin: 0 -0.75rem;
|
||
padding: 1rem 0.75rem;
|
||
border-bottom: 1px solid var(--border);
|
||
background: color-mix(in oklab, var(--background) 94%, transparent);
|
||
-webkit-backdrop-filter: blur(14px);
|
||
backdrop-filter: blur(14px);
|
||
}
|
||
|
||
.toolbar-group {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 0.5rem;
|
||
align-items: center;
|
||
}
|
||
|
||
.toolbar-label,
|
||
.shortlist {
|
||
color: var(--muted-foreground);
|
||
font-size: 0.75rem;
|
||
line-height: 1rem;
|
||
}
|
||
|
||
.segment {
|
||
display: inline-flex;
|
||
gap: 0.1875rem;
|
||
padding: 0.1875rem;
|
||
border: 1px solid var(--border);
|
||
border-radius: 0.5rem;
|
||
background: var(--subtle);
|
||
}
|
||
|
||
.segment button,
|
||
.copy-button,
|
||
.pick {
|
||
border: 0;
|
||
color: var(--muted-foreground);
|
||
background: transparent;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.segment button {
|
||
min-height: 1.75rem;
|
||
padding: 0.25rem 0.625rem;
|
||
border-radius: 0.3125rem;
|
||
font-size: 0.75rem;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.segment button:hover,
|
||
.copy-button:hover,
|
||
.pick:hover { color: var(--foreground); background: var(--subtle-hover); }
|
||
|
||
.segment button[aria-pressed="true"] {
|
||
color: var(--foreground);
|
||
background: oklch(1 0 0 / 11%);
|
||
box-shadow: 0 1px 0 oklch(0 0 0 / 28%);
|
||
}
|
||
|
||
.copy-button {
|
||
min-height: 1.75rem;
|
||
padding: 0.25rem 0.625rem;
|
||
border: 1px solid var(--border);
|
||
border-radius: 0.375rem;
|
||
font-size: 0.75rem;
|
||
}
|
||
|
||
.intro-note {
|
||
max-width: 56rem;
|
||
margin: 2.25rem 0 0;
|
||
color: var(--muted-foreground);
|
||
font-size: 0.8125rem;
|
||
line-height: 1.25rem;
|
||
}
|
||
|
||
.intro-note strong { color: var(--foreground); font-weight: 550; }
|
||
|
||
.grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
column-gap: clamp(2rem, 5vw, 5rem);
|
||
row-gap: 0;
|
||
margin-top: 1.25rem;
|
||
}
|
||
|
||
.page[data-width="wide"] .grid { grid-template-columns: 1fr; }
|
||
|
||
.specimen {
|
||
position: relative;
|
||
min-width: 0;
|
||
padding: 2.5rem 0 3rem;
|
||
border-bottom: 1px solid var(--border);
|
||
}
|
||
|
||
.specimen::before {
|
||
position: absolute;
|
||
inset: 1rem -1rem;
|
||
z-index: -1;
|
||
border: 1px solid transparent;
|
||
border-radius: 0.75rem;
|
||
content: "";
|
||
pointer-events: none;
|
||
transition: 120ms ease;
|
||
transition-property: background-color, border-color;
|
||
}
|
||
|
||
.specimen[data-selected="true"]::before {
|
||
border-color: color-mix(in oklab, var(--focus) 45%, transparent);
|
||
background: color-mix(in oklab, var(--focus) 4%, transparent);
|
||
}
|
||
|
||
.specimen-header {
|
||
display: grid;
|
||
grid-template-columns: 2rem minmax(0, 1fr) auto;
|
||
gap: 0.75rem;
|
||
align-items: start;
|
||
max-width: var(--reading-width);
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
|
||
.number {
|
||
color: var(--muted-foreground);
|
||
font-size: 0.75rem;
|
||
font-variant-numeric: tabular-nums;
|
||
line-height: 1.5rem;
|
||
}
|
||
|
||
.specimen h2 {
|
||
margin: 0;
|
||
font-size: 0.9375rem;
|
||
font-weight: 600;
|
||
letter-spacing: -0.01em;
|
||
line-height: 1.5rem;
|
||
}
|
||
|
||
.specimen-description {
|
||
margin: 0.125rem 0 0;
|
||
color: var(--muted-foreground);
|
||
font-size: 0.75rem;
|
||
line-height: 1.125rem;
|
||
}
|
||
|
||
.pick {
|
||
display: inline-flex;
|
||
gap: 0.375rem;
|
||
align-items: center;
|
||
min-height: 1.75rem;
|
||
padding: 0.25rem 0.5rem;
|
||
border: 1px solid var(--border);
|
||
border-radius: 0.375rem;
|
||
font-size: 0.6875rem;
|
||
line-height: 1rem;
|
||
}
|
||
|
||
.pick::before {
|
||
display: block;
|
||
width: 0.5rem;
|
||
height: 0.5rem;
|
||
border: 1px solid currentColor;
|
||
border-radius: 999px;
|
||
content: "";
|
||
}
|
||
|
||
.pick[aria-pressed="true"] { color: var(--foreground); }
|
||
.pick[aria-pressed="true"]::before { border-color: var(--focus); background: var(--focus); }
|
||
|
||
.document {
|
||
width: 100%;
|
||
max-width: var(--reading-width);
|
||
color: var(--foreground);
|
||
font-size: 0.9375rem;
|
||
font-weight: 400;
|
||
line-height: 1.5rem;
|
||
}
|
||
|
||
.document h3 {
|
||
margin: 0 0 0.75rem;
|
||
font-size: 1.25rem;
|
||
font-weight: 600;
|
||
letter-spacing: -0.01em;
|
||
line-height: 1.625rem;
|
||
}
|
||
|
||
.document p { margin: 0; }
|
||
|
||
.document code {
|
||
border-radius: 0.1875rem;
|
||
background: oklch(1 0 0 / 6%);
|
||
color: inherit;
|
||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
|
||
font-size: 0.9375rem;
|
||
font-weight: 500;
|
||
line-height: 1.5rem;
|
||
padding: 0.140625rem 0.328125rem;
|
||
}
|
||
|
||
mark {
|
||
color: inherit;
|
||
-webkit-box-decoration-break: clone;
|
||
box-decoration-break: clone;
|
||
}
|
||
|
||
/* 01 — the live dark-mode token, included as the control. */
|
||
.style-current mark {
|
||
background: #a16207;
|
||
box-shadow: 0 0.11em 0 #a16207, 0 -0.11em 0 #a16207;
|
||
}
|
||
|
||
/* 02 — asymmetric shadows create 4px x / 2px y visual padding without changing line metrics. */
|
||
.style-amber-halo mark {
|
||
--highlight: color-mix(in srgb, oklch(0.69 0.12 78) 28%, var(--background));
|
||
border-radius: 0.16rem;
|
||
background: var(--highlight);
|
||
box-shadow:
|
||
-0.12rem 0 0 0.12rem var(--highlight),
|
||
0.12rem 0 0 0.12rem var(--highlight);
|
||
}
|
||
|
||
/* 03 — low-chroma warmth, closer to paper than warning yellow. */
|
||
.style-sand mark {
|
||
border-radius: 0.1rem;
|
||
background: oklch(0.64 0.055 78 / 32%);
|
||
box-shadow: 0 0.05rem 0 0.07rem oklch(0.64 0.055 78 / 24%);
|
||
}
|
||
|
||
/* 04 — softer collaborative/comment color with a two-pixel visual outset. */
|
||
.style-lilac mark {
|
||
border-radius: 0.18rem;
|
||
background: oklch(0.66 0.15 300 / 25%);
|
||
box-shadow: 0 0 0 0.12rem oklch(0.66 0.15 300 / 25%);
|
||
}
|
||
|
||
/* 05 — cool utility color; reads as selection rather than status. */
|
||
.style-indigo mark {
|
||
border-radius: 0.18rem;
|
||
background: oklch(0.62 0.14 255 / 27%);
|
||
box-shadow: 0 0 0 0.1rem oklch(0.62 0.14 255 / 23%);
|
||
}
|
||
|
||
/* 06 — teal keeps contrast gentle against the warm black page. */
|
||
.style-teal mark {
|
||
border-radius: 0.16rem;
|
||
background: oklch(0.68 0.105 175 / 23%);
|
||
box-shadow: 0 0 0 0.1rem oklch(0.68 0.105 175 / 20%);
|
||
}
|
||
|
||
/* 07 — a restrained warm alternative that is visibly non-warning. */
|
||
.style-rose mark {
|
||
border-radius: 0.18rem;
|
||
background: oklch(0.68 0.14 18 / 23%);
|
||
box-shadow: 0 0 0 0.11rem oklch(0.68 0.14 18 / 20%);
|
||
}
|
||
|
||
/* 08 — no rectangle: an imperfect marker band through the lower glyph area. */
|
||
.style-marker mark {
|
||
background:
|
||
linear-gradient(
|
||
178deg,
|
||
transparent 18%,
|
||
oklch(0.78 0.12 90 / 15%) 18% 34%,
|
||
oklch(0.78 0.12 90 / 43%) 34% 84%,
|
||
transparent 84%
|
||
);
|
||
}
|
||
|
||
/* 09 — lightweight at rest, with a precise edge for range boundaries. */
|
||
.style-underline mark {
|
||
border-radius: 0.08rem;
|
||
background:
|
||
linear-gradient(
|
||
to top,
|
||
oklch(0.69 0.15 262 / 78%) 0 0.1rem,
|
||
oklch(0.69 0.15 262 / 13%) 0.1rem 100%
|
||
);
|
||
box-shadow: 0 0.08rem 0.28rem oklch(0.69 0.15 262 / 10%);
|
||
}
|
||
|
||
/* 10 — mostly neutral; the hairline outline carries the selection boundary. */
|
||
.style-glass mark {
|
||
border-radius: 0.18rem;
|
||
background: oklch(1 0 0 / 8%);
|
||
box-shadow:
|
||
0 0 0 0.11rem oklch(1 0 0 / 6%),
|
||
inset 0 0 0 0.055rem oklch(0.73 0.12 292 / 58%);
|
||
}
|
||
|
||
.round-heading {
|
||
display: grid;
|
||
grid-template-columns: 2rem minmax(0, 1fr);
|
||
gap: 0.75rem;
|
||
margin-top: 4.5rem;
|
||
padding-top: 2.5rem;
|
||
border-top: 1px solid var(--border);
|
||
}
|
||
|
||
.round-heading .round-number {
|
||
color: var(--muted-foreground);
|
||
font-size: 0.75rem;
|
||
font-variant-numeric: tabular-nums;
|
||
line-height: 1.5rem;
|
||
}
|
||
|
||
.round-heading h2 {
|
||
margin: 0;
|
||
font-size: clamp(1.5rem, 3vw, 2.25rem);
|
||
font-weight: 600;
|
||
letter-spacing: -0.025em;
|
||
line-height: 1.15;
|
||
}
|
||
|
||
.round-heading p {
|
||
max-width: 49rem;
|
||
margin: 0.75rem 0 0;
|
||
color: var(--muted-foreground);
|
||
font-size: 0.8125rem;
|
||
line-height: 1.25rem;
|
||
}
|
||
|
||
/* 11–20 — one geometry, ten stops around the yellow hue family. */
|
||
.style-yellow-halo mark {
|
||
--highlight: color-mix(in srgb, var(--highlight-color) 28%, var(--background));
|
||
border-radius: 0.16rem;
|
||
background: var(--highlight);
|
||
box-shadow:
|
||
-0.12rem 0 0 0.12rem var(--highlight),
|
||
0.12rem 0 0 0.12rem var(--highlight);
|
||
}
|
||
|
||
.tone-lemon { --highlight-color: oklch(0.84 0.13 102); }
|
||
.tone-citron { --highlight-color: oklch(0.81 0.16 108); }
|
||
.tone-canary { --highlight-color: oklch(0.82 0.15 96); }
|
||
.tone-sunflower { --highlight-color: oklch(0.78 0.16 89); }
|
||
.tone-marigold { --highlight-color: oklch(0.74 0.15 83); }
|
||
.tone-saffron { --highlight-color: oklch(0.72 0.16 76); }
|
||
.tone-honey { --highlight-color: oklch(0.68 0.12 72); }
|
||
.tone-wheat { --highlight-color: oklch(0.81 0.07 88); }
|
||
.tone-khaki { --highlight-color: oklch(0.68 0.08 103); }
|
||
.tone-antique-gold { --highlight-color: oklch(0.62 0.10 78); }
|
||
|
||
/* 21–30 — one balanced yellow pushed toward the WCAG AA contrast boundary. */
|
||
.style-brightness mark {
|
||
--highlight: color-mix(in srgb, oklch(0.78 0.16 89) var(--mix), var(--background));
|
||
border-radius: 0.16rem;
|
||
background: var(--highlight);
|
||
box-shadow:
|
||
-0.12rem 0 0 0.12rem var(--highlight),
|
||
0.12rem 0 0 0.12rem var(--highlight);
|
||
}
|
||
|
||
.brightness-25 { --mix: 25%; }
|
||
.brightness-30 { --mix: 30%; }
|
||
.brightness-35 { --mix: 35%; }
|
||
.brightness-40 { --mix: 40%; }
|
||
.brightness-45 { --mix: 45%; }
|
||
.brightness-50 { --mix: 50%; }
|
||
.brightness-55 { --mix: 55%; }
|
||
.brightness-58 { --mix: 58%; }
|
||
.brightness-60 { --mix: 60%; }
|
||
.brightness-62 { --mix: 62%; }
|
||
|
||
.mechanics {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 0.375rem;
|
||
max-width: var(--reading-width);
|
||
margin-top: 1.25rem;
|
||
}
|
||
|
||
.mechanics span {
|
||
padding: 0.1875rem 0.4375rem;
|
||
border: 1px solid var(--border);
|
||
border-radius: 999px;
|
||
color: var(--muted-foreground);
|
||
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
|
||
font-size: 0.625rem;
|
||
line-height: 0.875rem;
|
||
}
|
||
|
||
.footer {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 1rem 2rem;
|
||
justify-content: space-between;
|
||
padding-top: 2rem;
|
||
color: var(--muted-foreground);
|
||
font-size: 0.75rem;
|
||
line-height: 1.125rem;
|
||
}
|
||
|
||
.footer p { max-width: 44rem; margin: 0; }
|
||
.footer a { color: var(--foreground); text-underline-offset: 0.18em; }
|
||
|
||
.page[data-width="compact"] { --reading-width: 26rem; }
|
||
.page[data-width="panel"] { --reading-width: 32rem; }
|
||
.page[data-width="wide"] { --reading-width: 44rem; }
|
||
|
||
:focus-visible {
|
||
outline: 2px solid var(--focus);
|
||
outline-offset: 2px;
|
||
}
|
||
|
||
@media (max-width: 68rem) {
|
||
.hero { grid-template-columns: 1fr; gap: 2rem; }
|
||
.fixed-tokens { max-width: 36rem; }
|
||
.grid { grid-template-columns: 1fr; }
|
||
.document,
|
||
.specimen-header,
|
||
.mechanics { max-width: min(100%, var(--reading-width)); }
|
||
}
|
||
|
||
@media (max-width: 40rem) {
|
||
.page { padding-top: 2rem; }
|
||
.fixed-tokens { grid-template-columns: 1fr; }
|
||
.toolbar { position: static; }
|
||
.toolbar-group { width: 100%; }
|
||
.specimen-header { grid-template-columns: 1.75rem minmax(0, 1fr); }
|
||
.pick { grid-column: 2; justify-self: start; }
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
*, *::before, *::after { scroll-behavior: auto !important; transition-duration: 0.01ms !important; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<main class="page" data-width="panel">
|
||
<header class="hero">
|
||
<div>
|
||
<p class="eyebrow">Document annotations · visual study</p>
|
||
<h1>Ten shapes, ten yellows, one brightness limit</h1>
|
||
<p>The document surface is held constant so the highlight is the only moving part. Round two keeps option 02’s soft shape and moves through ten yellow-family colors; round three pushes one of them to the normal-text contrast boundary.</p>
|
||
</div>
|
||
|
||
<dl class="fixed-tokens" aria-label="Fixed document styles">
|
||
<div><dt>Typeface</dt><dd>Inter Variable</dd></div>
|
||
<div><dt>Body</dt><dd>15px / 24px</dd></div>
|
||
<div><dt>Background</dt><dd>oklch(0.145 0 0)</dd></div>
|
||
<div><dt>Foreground</dt><dd>oklch(0.985 0 0)</dd></div>
|
||
</dl>
|
||
</header>
|
||
|
||
<div class="toolbar" aria-label="Exploration controls">
|
||
<div class="toolbar-group">
|
||
<span class="toolbar-label">Reading width</span>
|
||
<div class="segment" role="group" aria-label="Reading width">
|
||
<button type="button" data-width-button="compact" aria-pressed="false">Compact</button>
|
||
<button type="button" data-width-button="panel" aria-pressed="true">Side panel</button>
|
||
<button type="button" data-width-button="wide" aria-pressed="false">Wide</button>
|
||
</div>
|
||
</div>
|
||
<div class="toolbar-group">
|
||
<span class="shortlist" aria-live="polite">Shortlist: none</span>
|
||
<button class="copy-button" type="button" disabled>Copy shortlist</button>
|
||
</div>
|
||
</div>
|
||
|
||
<p class="intro-note"><strong>The padding trick:</strong> options marked “visual outset” grow with paint (usually a shadow or an expanded overlay rectangle), not CSS padding. Option 02 and all of round two now use about 4px on the x-axis and 2px on the y-axis without changing line height or text wrapping.</p>
|
||
|
||
<div class="grid">
|
||
<section class="specimen style-current" data-option="01 Current solid ochre">
|
||
<div class="specimen-header">
|
||
<span class="number">01</span>
|
||
<div>
|
||
<h2>Current solid ochre</h2>
|
||
<p class="specimen-description">Control · high coverage, square fragments, warning-adjacent hue.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>solid fill</span><span>native ::highlight</span><span>0px radius</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-amber-halo" data-option="02 Soft amber halo">
|
||
<div class="specimen-header">
|
||
<span class="number">02</span>
|
||
<div>
|
||
<h2>Soft amber halo</h2>
|
||
<p class="specimen-description">Keeps the familiar hue, lowers the chroma, and softens every edge.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>28% fill</span><span>4px x / 2px y outset</span><span>3px radius</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-sand" data-option="03 Smoked sand">
|
||
<div class="specimen-header">
|
||
<span class="number">03</span>
|
||
<div>
|
||
<h2>Smoked sand</h2>
|
||
<p class="specimen-description">A low-saturation warm neutral that reads more like paper than status.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>low chroma</span><span>1px visual outset</span><span>2px radius</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-lilac" data-option="04 Lilac halo">
|
||
<div class="specimen-header">
|
||
<span class="number">04</span>
|
||
<div>
|
||
<h2>Lilac halo</h2>
|
||
<p class="specimen-description">A collaboration-like color that separates comments from warnings.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>25% fill</span><span>2px visual outset</span><span>3px radius</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-indigo" data-option="05 Indigo wash">
|
||
<div class="specimen-header">
|
||
<span class="number">05</span>
|
||
<div>
|
||
<h2>Indigo wash</h2>
|
||
<p class="specimen-description">Cool and workmanlike; reads as selected text instead of a warning.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>27% fill</span><span>2px visual outset</span><span>3px radius</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-teal" data-option="06 Teal wash">
|
||
<div class="specimen-header">
|
||
<span class="number">06</span>
|
||
<div>
|
||
<h2>Teal wash</h2>
|
||
<p class="specimen-description">Quiet on the warm-black surface while remaining easy to scan.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>23% fill</span><span>1.5px visual outset</span><span>3px radius</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-rose" data-option="07 Dusty rose">
|
||
<div class="specimen-header">
|
||
<span class="number">07</span>
|
||
<div>
|
||
<h2>Dusty rose</h2>
|
||
<p class="specimen-description">Still warm, but clearly distinct from amber warning and review states.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>23% fill</span><span>2px visual outset</span><span>3px radius</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-marker" data-option="08 Marker band">
|
||
<div class="specimen-header">
|
||
<span class="number">08</span>
|
||
<div>
|
||
<h2>Marker band</h2>
|
||
<p class="specimen-description">A translucent stroke across the lower glyph area instead of a box.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>gradient paint</span><span>no outset</span><span>native ::highlight*</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-underline" data-option="09 Underline and haze">
|
||
<div class="specimen-header">
|
||
<span class="number">09</span>
|
||
<div>
|
||
<h2>Underline + haze</h2>
|
||
<p class="specimen-description">The lightest block treatment; a precise edge anchors a faint wash.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>13% fill</span><span>2px underline</span><span>native-friendly</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-glass" data-option="10 Neutral glass outline">
|
||
<div class="specimen-header">
|
||
<span class="number">10</span>
|
||
<div>
|
||
<h2>Neutral glass outline</h2>
|
||
<p class="specimen-description">Almost colorless fill; a violet hairline defines the selected range.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>8% neutral fill</span><span>1px inset edge</span><span>2px visual outset</span></div>
|
||
</section>
|
||
</div>
|
||
|
||
<section class="round-heading" aria-labelledby="round-two-title">
|
||
<span class="round-number">02</span>
|
||
<div>
|
||
<h2 id="round-two-title">One shape, ten yellows</h2>
|
||
<p>Every sample below uses option 02’s translucent, rounded treatment with the wider 4px horizontal outset. Opacity and geometry stay fixed; only OKLCH lightness, chroma, and hue move.</p>
|
||
</div>
|
||
</section>
|
||
|
||
<div class="grid">
|
||
<section class="specimen style-yellow-halo tone-lemon" data-option="11 Pale lemon">
|
||
<div class="specimen-header">
|
||
<span class="number">11</span>
|
||
<div>
|
||
<h2>Pale lemon</h2>
|
||
<p class="specimen-description">The brightest, cleanest yellow in the set.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>L 84</span><span>C 13</span><span>H 102</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-yellow-halo tone-citron" data-option="12 Citron">
|
||
<div class="specimen-header">
|
||
<span class="number">12</span>
|
||
<div>
|
||
<h2>Citron</h2>
|
||
<p class="specimen-description">A sharper yellow with a slight greenward pull.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>L 81</span><span>C 16</span><span>H 108</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-yellow-halo tone-canary" data-option="13 Canary">
|
||
<div class="specimen-header">
|
||
<span class="number">13</span>
|
||
<div>
|
||
<h2>Canary</h2>
|
||
<p class="specimen-description">A familiar highlighter yellow without the solid-marker density.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>L 82</span><span>C 15</span><span>H 96</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-yellow-halo tone-sunflower" data-option="14 Sunflower">
|
||
<div class="specimen-header">
|
||
<span class="number">14</span>
|
||
<div>
|
||
<h2>Sunflower</h2>
|
||
<p class="specimen-description">Balanced yellow-gold with a little more body.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>L 78</span><span>C 16</span><span>H 89</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-yellow-halo tone-marigold" data-option="15 Marigold">
|
||
<div class="specimen-header">
|
||
<span class="number">15</span>
|
||
<div>
|
||
<h2>Marigold</h2>
|
||
<p class="specimen-description">Warmer and slightly deeper, without reaching orange.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>L 74</span><span>C 15</span><span>H 83</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-yellow-halo tone-saffron" data-option="16 Saffron">
|
||
<div class="specimen-header">
|
||
<span class="number">16</span>
|
||
<div>
|
||
<h2>Saffron</h2>
|
||
<p class="specimen-description">The warmest saturated option in this round.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>L 72</span><span>C 16</span><span>H 76</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-yellow-halo tone-honey" data-option="17 Honey">
|
||
<div class="specimen-header">
|
||
<span class="number">17</span>
|
||
<div>
|
||
<h2>Honey</h2>
|
||
<p class="specimen-description">A darker, quieter golden yellow for long selections.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>L 68</span><span>C 12</span><span>H 72</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-yellow-halo tone-wheat" data-option="18 Wheat">
|
||
<div class="specimen-header">
|
||
<span class="number">18</span>
|
||
<div>
|
||
<h2>Wheat</h2>
|
||
<p class="specimen-description">Pale and desaturated; closer to parchment than marker ink.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>L 81</span><span>C 07</span><span>H 88</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-yellow-halo tone-khaki" data-option="19 Khaki">
|
||
<div class="specimen-header">
|
||
<span class="number">19</span>
|
||
<div>
|
||
<h2>Khaki</h2>
|
||
<p class="specimen-description">A subdued, slightly olive yellow with low visual urgency.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>L 68</span><span>C 08</span><span>H 103</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-yellow-halo tone-antique-gold" data-option="20 Antique gold">
|
||
<div class="specimen-header">
|
||
<span class="number">20</span>
|
||
<div>
|
||
<h2>Antique gold</h2>
|
||
<p class="specimen-description">The deepest yellow; restrained but still clearly highlighted.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>L 62</span><span>C 10</span><span>H 78</span></div>
|
||
</section>
|
||
</div>
|
||
|
||
<section class="round-heading" aria-labelledby="round-three-title">
|
||
<span class="round-number">03</span>
|
||
<div>
|
||
<h2 id="round-three-title">How bright can it go?</h2>
|
||
<p>This ramp uses Sunflower (option 14), the unchanged white foreground, and the same borderless geometry. At 15px / 400 weight the text is “normal text,” so WCAG 2.2 AA requires at least 4.5:1 contrast. Sixty percent is the brightest practical stop here at 4.66:1; 62% falls below the requirement.</p>
|
||
</div>
|
||
</section>
|
||
|
||
<div class="grid">
|
||
<section class="specimen style-brightness brightness-25" data-option="21 Sunflower 25%">
|
||
<div class="specimen-header">
|
||
<span class="number">21</span>
|
||
<div>
|
||
<h2>Sunflower · 25%</h2>
|
||
<p class="specimen-description">Quiet baseline, slightly dimmer than the color round.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>25% blend</span><span>11.81:1</span><span>AAA pass</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-brightness brightness-30" data-option="22 Sunflower 30%">
|
||
<div class="specimen-header">
|
||
<span class="number">22</span>
|
||
<div>
|
||
<h2>Sunflower · 30%</h2>
|
||
<p class="specimen-description">Close to option 14, with a small brightness lift.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>30% blend</span><span>10.35:1</span><span>AAA pass</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-brightness brightness-35" data-option="23 Sunflower 35%">
|
||
<div class="specimen-header">
|
||
<span class="number">23</span>
|
||
<div>
|
||
<h2>Sunflower · 35%</h2>
|
||
<p class="specimen-description">Clearly highlighted, still soft across long ranges.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>35% blend</span><span>9.05:1</span><span>AAA pass</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-brightness brightness-40" data-option="24 Sunflower 40%">
|
||
<div class="specimen-header">
|
||
<span class="number">24</span>
|
||
<div>
|
||
<h2>Sunflower · 40%</h2>
|
||
<p class="specimen-description">A strong but comfortable mid-range treatment.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>40% blend</span><span>7.89:1</span><span>AAA pass</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-brightness brightness-45" data-option="25 Sunflower 45%">
|
||
<div class="specimen-header">
|
||
<span class="number">25</span>
|
||
<div>
|
||
<h2>Sunflower · 45%</h2>
|
||
<p class="specimen-description">Bright and unmistakable, just below enhanced contrast.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>45% blend</span><span>6.89:1</span><span>AA pass</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-brightness brightness-50" data-option="26 Sunflower 50%">
|
||
<div class="specimen-header">
|
||
<span class="number">26</span>
|
||
<div>
|
||
<h2>Sunflower · 50%</h2>
|
||
<p class="specimen-description">Halfway to the source yellow; intentionally prominent.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>50% blend</span><span>6.03:1</span><span>AA pass</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-brightness brightness-55" data-option="27 Sunflower 55%">
|
||
<div class="specimen-header">
|
||
<span class="number">27</span>
|
||
<div>
|
||
<h2>Sunflower · 55%</h2>
|
||
<p class="specimen-description">Very bright, with a modest accessibility buffer.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>55% blend</span><span>5.29:1</span><span>AA pass</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-brightness brightness-58" data-option="28 Sunflower 58%">
|
||
<div class="specimen-header">
|
||
<span class="number">28</span>
|
||
<div>
|
||
<h2>Sunflower · 58%</h2>
|
||
<p class="specimen-description">Near the limit, but retains a useful contrast margin.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>58% blend</span><span>4.90:1</span><span>AA pass</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-brightness brightness-60" data-option="29 Sunflower 60%">
|
||
<div class="specimen-header">
|
||
<span class="number">29</span>
|
||
<div>
|
||
<h2>Sunflower · 60%</h2>
|
||
<p class="specimen-description">Brightest recommended stop for this exact color and text.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>60% blend</span><span>4.66:1</span><span>AA pass</span></div>
|
||
</section>
|
||
|
||
<section class="specimen style-brightness brightness-62" data-option="30 Sunflower 62%">
|
||
<div class="specimen-header">
|
||
<span class="number">30</span>
|
||
<div>
|
||
<h2>Sunflower · 62%</h2>
|
||
<p class="specimen-description">Boundary proof: visibly brighter, but no longer compliant.</p>
|
||
</div>
|
||
<button class="pick" type="button" aria-pressed="false">Shortlist</button>
|
||
</div>
|
||
<div class="document">
|
||
<h3>Summary</h3>
|
||
<p>Build a TypeScript Node package that plugs into an existing Express application and serves a <mark>local, read-only traffic minimap</mark>. Each node represents a normalized <code>HTTP method + Express route</code>; the dashboard polls an in-memory snapshot and uses node size for request volume and color for latency/error health. <mark>The MVP is developer-only, single-process, ephemeral, and requires no database or authentication.</mark></p>
|
||
</div>
|
||
<div class="mechanics"><span>62% blend</span><span>4.43:1</span><span>AA fail</span></div>
|
||
</section>
|
||
</div>
|
||
|
||
<footer class="footer">
|
||
<p>* Contrast uses the page’s actual foreground and background with WCAG relative luminance. <a href="https://www.w3.org/WAI/WCAG22/Understanding/contrast-minimum.html" target="_blank" rel="noreferrer">WCAG 2.2 AA requires 4.5:1 for this 15px normal-weight text.</a></p>
|
||
<p>Click “Shortlist” on any option, then send the numbers back for a tighter second pass.</p>
|
||
</footer>
|
||
</main>
|
||
|
||
<script>
|
||
const page = document.querySelector(".page");
|
||
const widthButtons = Array.from(document.querySelectorAll("[data-width-button]"));
|
||
const shortlistLabel = document.querySelector(".shortlist");
|
||
const copyButton = document.querySelector(".copy-button");
|
||
const pickButtons = Array.from(document.querySelectorAll(".pick"));
|
||
|
||
widthButtons.forEach((button) => {
|
||
button.addEventListener("click", () => {
|
||
page.dataset.width = button.dataset.widthButton;
|
||
widthButtons.forEach((candidate) => {
|
||
candidate.setAttribute("aria-pressed", String(candidate === button));
|
||
});
|
||
});
|
||
});
|
||
|
||
function selectedOptions() {
|
||
return pickButtons
|
||
.filter((button) => button.getAttribute("aria-pressed") === "true")
|
||
.map((button) => button.closest(".specimen").dataset.option);
|
||
}
|
||
|
||
function renderShortlist() {
|
||
const selected = selectedOptions();
|
||
shortlistLabel.textContent = selected.length
|
||
? `Shortlist: ${selected.map((option) => option.slice(0, 2)).join(", ")}`
|
||
: "Shortlist: none";
|
||
copyButton.disabled = selected.length === 0;
|
||
copyButton.textContent = "Copy shortlist";
|
||
}
|
||
|
||
pickButtons.forEach((button) => {
|
||
button.addEventListener("click", () => {
|
||
const pressed = button.getAttribute("aria-pressed") === "true";
|
||
button.setAttribute("aria-pressed", String(!pressed));
|
||
button.closest(".specimen").dataset.selected = String(!pressed);
|
||
renderShortlist();
|
||
});
|
||
});
|
||
|
||
copyButton.addEventListener("click", async () => {
|
||
const text = `Document highlight shortlist: ${selectedOptions().join(", ")}`;
|
||
try {
|
||
await navigator.clipboard.writeText(text);
|
||
copyButton.textContent = "Copied";
|
||
} catch {
|
||
copyButton.textContent = "Copy failed";
|
||
}
|
||
});
|
||
</script>
|
||
</body>
|
||
</html>
|