Clicking a resident (or aiming the walk/fly crosshair at one and pressing E) selects them: they stop walking, glow pink with a wider halo, get a name tag above their head, and the sidebar shows a resident ID card instead of code. The card has a drawn head-and-shoulders portrait (eyes and hair in their colours), name, sex, age, occupation and employer, eye colour, hair colour, blood type, where they were last seen, an ID number and a barcode. people.js generates identities deterministically from the repository name and resident index using nymshift's England/Wales names and taxonomy tables, so the same resident is always the same person. Picking projects each figure to the screen and ignores residents hidden behind buildings. Tested for stability, table membership and sex/first-name consistency.
411 lines
40 KiB
CSS
411 lines
40 KiB
CSS
/* CodeNavigator: a hand-cut dev zine. Flat ink, hard edges, stickers, a little chaos. */
|
|
@font-face { font-family: "Archivo Black"; font-weight: 400; font-display: swap; src: url("./fonts/archivo-black.woff2") format("woff2"); }
|
|
@font-face { font-family: "Atkinson Hyperlegible"; font-weight: 400; font-display: swap; src: url("./fonts/atkinson-400.woff2") format("woff2"); }
|
|
@font-face { font-family: "Atkinson Hyperlegible"; font-weight: 700; font-display: swap; src: url("./fonts/atkinson-700.woff2") format("woff2"); }
|
|
@font-face { font-family: "Space Mono"; font-weight: 400; font-display: swap; src: url("./fonts/space-mono-400.woff2") format("woff2"); }
|
|
@font-face { font-family: "Space Mono"; font-weight: 700; font-display: swap; src: url("./fonts/space-mono-700.woff2") format("woff2"); }
|
|
|
|
:root {
|
|
color-scheme: dark;
|
|
--ink: #15130f;
|
|
--ink-2: #1e1b16;
|
|
--ink-3: #2a261f;
|
|
--black: #000;
|
|
--paper: #f3ecdc;
|
|
--muted: #bdb39d;
|
|
--dim: #867c67;
|
|
--line: #3b352b;
|
|
--lime: #c8f135;
|
|
--pink: #ff5ea8;
|
|
--sky: #5cc8ff;
|
|
--tang: #ff9a1f;
|
|
--red: #ff4d3d;
|
|
--yellow: #ffd23f;
|
|
--danger: #ff4d3d;
|
|
--hard: 3px 3px 0 var(--black);
|
|
--hard-lg: 5px 5px 0 var(--black);
|
|
--display: "Archivo Black", Impact, "Arial Black", sans-serif;
|
|
--body: "Atkinson Hyperlegible", system-ui, sans-serif;
|
|
--mono: "Space Mono", ui-monospace, Consolas, monospace;
|
|
--panel-width: 310px;
|
|
--toolbar-height: 56px;
|
|
}
|
|
|
|
* { box-sizing: border-box; }
|
|
[hidden] { display: none !important; }
|
|
html, body, #app { width: 100%; height: 100%; overflow: hidden; }
|
|
body { margin: 0; background: var(--ink); color: var(--paper); font: 13px/1.5 var(--body); -webkit-font-smoothing: antialiased; }
|
|
button, input, select { font: inherit; }
|
|
button { color: inherit; }
|
|
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
|
|
::selection { background: var(--pink); color: var(--black); }
|
|
* { scrollbar-width: thin; scrollbar-color: var(--line) transparent; }
|
|
kbd { display: inline-block; min-width: 18px; padding: 0 4px; border: 2px solid var(--black); border-bottom-width: 3px; border-radius: 4px; background: var(--paper); color: var(--black); font: 700 10px/1.4 var(--mono); text-align: center; }
|
|
|
|
@keyframes wiggle { 25% { transform: rotate(-9deg); } 75% { transform: rotate(7deg); } }
|
|
@keyframes blink { 50% { opacity: .35; } }
|
|
@keyframes barber { from { transform: translateX(-28px); } to { transform: translateX(0); } }
|
|
@keyframes plonk { from { opacity: 0; transform: translateY(-10px) rotate(-3deg); } }
|
|
@keyframes bob { 50% { transform: rotate(4deg) translateY(-4px); } }
|
|
|
|
/* ---- Toolbar ---- */
|
|
.toolbar { position: relative; z-index: 5; height: var(--toolbar-height); padding: 0 14px; display: flex; align-items: center; gap: 10px; background: var(--ink-2); border-bottom: 2px solid var(--black); }
|
|
.toolbar::after { content: ""; position: absolute; left: 0; right: 0; bottom: -6px; height: 4px; background: repeating-linear-gradient(90deg, var(--lime) 0 38px, var(--pink) 38px 61px, var(--sky) 61px 87px, var(--tang) 87px 101px); }
|
|
.brand { display: flex; gap: 9px; align-items: center; padding-right: 14px; border-right: 2px dashed var(--line); }
|
|
.brand svg { width: 28px; height: 28px; transform: rotate(-6deg); }
|
|
.brand-name { display: flex; align-items: center; gap: 4px; font: 400 15px/1 var(--display); color: var(--paper); }
|
|
.brand-name em { font-style: normal; padding: 3px 6px 2px; border: 2px solid var(--black); border-radius: 4px; background: var(--lime); color: var(--black); box-shadow: 2px 2px 0 var(--black); transform: rotate(-3deg); }
|
|
|
|
/* Toolbar buttons are labelled chips: icon + word, same height everywhere. */
|
|
.tool-group { display: flex; align-items: center; gap: 4px; padding: 3px; border: 2px solid var(--black); border-radius: 10px; background: var(--ink); }
|
|
.tool, .metric { height: 32px; display: inline-flex; align-items: center; justify-content: center; gap: 6px; padding: 0 10px; border: 2px solid transparent; border-radius: 7px; background: transparent; color: var(--muted); font: 700 11px var(--mono); text-transform: uppercase; letter-spacing: .03em; white-space: nowrap; cursor: pointer; transition: background-color .12s, color .12s, transform .12s, box-shadow .12s; }
|
|
.tool.icon-only { width: 36px; padding: 0; }
|
|
.tool svg { width: 16px; height: 16px; flex-shrink: 0; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
|
|
.tool:hover svg { animation: wiggle .35s ease-in-out; }
|
|
.metric b { font: 700 13px/1 var(--mono); }
|
|
.tool:hover, .metric:hover { color: var(--paper); background: var(--ink-3); }
|
|
.tool.active, .metric.active { color: var(--black); border-color: var(--black); background: var(--lime); box-shadow: 2px 2px 0 var(--black); }
|
|
.metric.active { background: var(--pink); }
|
|
.tool.primary { color: var(--black); border-color: var(--black); background: var(--tang); box-shadow: 3px 3px 0 var(--black); transform: rotate(-2deg); }
|
|
.tool.primary:hover { background: var(--yellow); transform: rotate(1deg) translate(-1px, -1px); box-shadow: 4px 4px 0 var(--black); }
|
|
.toolbar-spacer { flex: 1; }
|
|
.scene-stats { white-space: nowrap; text-align: right; line-height: 1.3; font: 700 11px var(--mono); color: var(--paper); font-variant-numeric: tabular-nums; }
|
|
.scene-stats small { display: block; color: var(--dim); font-weight: 400; }
|
|
.filter-wrap { position: relative; flex-shrink: 0; width: clamp(200px, 18vw, 270px); }
|
|
.filter-wrap::before { content: "?"; position: absolute; left: 9px; top: 50%; width: 18px; height: 18px; display: grid; place-items: center; border: 2px solid var(--black); border-radius: 50%; background: var(--sky); color: var(--black); font: 700 10px/1 var(--mono); transform: translateY(-50%) rotate(-10deg); pointer-events: none; }
|
|
.filter-wrap input { width: 100%; height: 38px; padding: 0 36px 0 36px; border: 2px solid var(--black); border-radius: 8px; outline: none; background: var(--ink); color: var(--paper); box-shadow: var(--hard); transition: border-color .12s, box-shadow .12s; }
|
|
.filter-wrap input::placeholder { color: var(--dim); font-style: italic; }
|
|
.filter-wrap input:focus { border-color: var(--pink); box-shadow: 3px 3px 0 var(--pink); }
|
|
.filter-wrap kbd { position: absolute; right: 9px; top: 50%; transform: translateY(-50%) rotate(4deg); }
|
|
.live-dot { flex-shrink: 0; width: 12px; height: 12px; border: 2px solid var(--black); border-radius: 50%; background: var(--dim); }
|
|
.live-dot.connected { background: var(--lime); animation: blink 1.6s steps(2, jump-none) infinite; }
|
|
|
|
/* ---- Workspace ---- */
|
|
.workspace { position: absolute; inset: calc(var(--toolbar-height) + 4px) 0 0; display: grid; grid-template-columns: minmax(0,1fr) var(--panel-width); transition: grid-template-columns .22s ease; }
|
|
.workspace.inspector-hidden { grid-template-columns: minmax(0,1fr) 0px; }
|
|
.workspace.inspector-hidden .inspector { border-left: 0; }
|
|
.viewport { position: relative; min-width: 0; overflow: hidden; touch-action: none; user-select: none; cursor: grab; background: radial-gradient(circle at 1px 1px, rgba(243,236,220,.07) 1.2px, transparent 0) 0 0 / 24px 24px, var(--ink); }
|
|
.viewport.dragging { cursor: grabbing; }
|
|
.viewport.panning { cursor: move; }
|
|
#glCanvas, #overlayCanvas { position: absolute; inset: 0; width: 100%; height: 100%; }
|
|
#overlayCanvas { pointer-events: none; }
|
|
|
|
/* A tab stuck to the sidebar's left edge, half way down, that folds the sidebar away. */
|
|
.inspector-toggle { position: absolute; z-index: 6; top: 50%; right: var(--panel-width); width: 22px; height: 64px; margin-right: -1px; display: grid; place-items: center; padding: 0; border: 2px solid var(--black); border-right: 0; border-radius: 10px 0 0 10px; background: var(--lime); color: var(--black); box-shadow: -3px 3px 0 var(--black); transform: translateY(-50%); transition: right .22s ease, background-color .12s, width .12s; cursor: pointer; }
|
|
.inspector-toggle:hover { width: 28px; background: var(--yellow); }
|
|
.inspector-toggle svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; transition: transform .22s; }
|
|
.workspace.inspector-hidden .inspector-toggle { right: 0; }
|
|
.workspace.inspector-hidden .inspector-toggle svg { transform: rotate(180deg); }
|
|
|
|
/* Floating things on the map are stickers: flat, black-edged, hard shadow, never quite square. */
|
|
.breadcrumb, .canvas-controls, .camera-help, .legend, .tooltip, .progress-card, .city-hud, .city-target, .city-address, .minimap, .tour-caption { border: 2px solid var(--black); background: var(--ink-2); box-shadow: var(--hard); }
|
|
|
|
/* ---- Welcome ---- */
|
|
.welcome { position: absolute; inset: 0; z-index: 1; display: grid; place-content: center; justify-items: start; max-width: 780px; margin: 0 auto; padding: 32px; cursor: default; }
|
|
.welcome .eyebrow { display: inline-flex; align-items: center; gap: 8px; padding: 5px 11px; border: 2px solid var(--black); border-radius: 4px; background: var(--pink); color: var(--black); box-shadow: 2px 2px 0 var(--black); font: 700 11px var(--mono); text-transform: uppercase; letter-spacing: .06em; transform: rotate(-3deg); }
|
|
.welcome .eyebrow i { width: 8px; height: 8px; border-radius: 50%; background: var(--black); animation: blink 1s steps(2, jump-none) infinite; }
|
|
.welcome h1 { position: relative; margin: 22px 0 0; font: 400 clamp(38px, 6vw, 72px)/.98 var(--display); color: var(--paper); }
|
|
.welcome h1 span { display: inline-block; margin-top: 8px; padding: .02em .16em .1em; border: 3px solid var(--black); border-radius: 6px; background: var(--lime); color: var(--black); box-shadow: 5px 5px 0 var(--black); transform: rotate(-2deg); }
|
|
.welcome p { max-width: 540px; margin: 20px 0 0; color: var(--muted); font-size: 16px; line-height: 1.6; }
|
|
.welcome p b { color: var(--paper); }
|
|
.welcome-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; margin-top: 30px; color: var(--dim); font: 11px var(--mono); }
|
|
.welcome-features { display: flex; flex-wrap: wrap; gap: 9px; margin-top: 38px; }
|
|
.welcome-features span { padding: 5px 10px; border: 2px solid var(--line); border-radius: 999px; color: var(--muted); font: 700 11px var(--mono); }
|
|
.welcome-features span:nth-child(4n+1) { border-color: var(--lime); transform: rotate(-2deg); }
|
|
.welcome-features span:nth-child(4n+2) { border-color: var(--sky); transform: rotate(1.5deg); }
|
|
.welcome-features span:nth-child(4n+3) { border-color: var(--pink); transform: rotate(-1deg); }
|
|
.welcome-features span:nth-child(4n) { border-color: var(--tang); transform: rotate(2.5deg); }
|
|
.welcome-sticker { position: absolute; right: 0; top: 16%; width: 100px; height: 100px; display: grid; place-content: center; border: 2px solid var(--black); border-radius: 50%; background: var(--tang); color: var(--black); box-shadow: var(--hard); text-align: center; font: 400 13px/1.05 var(--display); text-transform: uppercase; transform: rotate(12deg); animation: bob 3.2s ease-in-out infinite; }
|
|
.welcome-sticker small { display: block; margin-top: 2px; font: 700 9px var(--mono); text-transform: none; }
|
|
|
|
.button-primary, .dialog-button, .github-row button { height: 42px; padding: 0 20px; border: 2px solid var(--black); border-radius: 8px; background: var(--lime); color: var(--black); box-shadow: 4px 4px 0 var(--black); font: 400 14px var(--display); cursor: pointer; transition: transform .1s, box-shadow .1s, background-color .1s; }
|
|
.button-primary:hover, .dialog-button:hover, .github-row button:hover { background: var(--yellow); box-shadow: 6px 6px 0 var(--black); transform: translate(-2px, -2px) rotate(-1deg); }
|
|
.button-primary:active, .dialog-button:active, .github-row button:active { box-shadow: 1px 1px 0 var(--black); transform: translate(3px, 3px); }
|
|
|
|
/* ---- Inspector ---- */
|
|
.inspector { min-width: 0; overflow: hidden; background: var(--ink-2); border-left: 2px solid var(--black); }
|
|
.inspector > * { min-width: calc(var(--panel-width) - 2px); }
|
|
.tabs { height: 52px; display: flex; align-items: center; gap: 6px; margin: 0 12px; border-bottom: 2px dashed var(--line); }
|
|
.tab { height: 30px; padding: 0 11px; border: 2px solid transparent; border-radius: 6px; background: transparent; color: var(--dim); font: 700 11px var(--mono); text-transform: uppercase; letter-spacing: .05em; cursor: pointer; }
|
|
.tab:hover { color: var(--paper); }
|
|
.tab.active { color: var(--black); border-color: var(--black); background: var(--sky); box-shadow: 2px 2px 0 var(--black); transform: rotate(-2deg); }
|
|
.tab:nth-child(2).active { background: var(--tang); transform: rotate(1.5deg); }
|
|
.tab:nth-child(3).active { background: var(--pink); transform: rotate(-1deg); }
|
|
#resultBadge:not(:empty) { margin-left: 5px; padding: 0 5px; border-radius: 3px; background: var(--black); color: var(--lime); font-size: 10px; }
|
|
.panel { display: none; height: calc(100% - 52px); overflow: auto; padding: 16px 14px 26px; }
|
|
.panel.active { display: block; }
|
|
.panel-hint, .result-summary { margin: 0 0 14px; color: var(--muted); line-height: 1.6; }
|
|
.entity-title { margin-bottom: 14px; }
|
|
.entity-title small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dim); font: 11px var(--mono); }
|
|
.entity-title h2 { margin: 6px 0 0; font: 400 21px/1.1 var(--display); color: var(--paper); overflow-wrap: anywhere; }
|
|
.meta-grid { display: grid; grid-template-columns: 1fr auto; gap: 0 12px; padding: 4px 12px; border: 2px solid var(--black); border-radius: 8px; background: var(--ink); box-shadow: var(--hard); font-variant-numeric: tabular-nums; }
|
|
.meta-grid span, .meta-grid b { padding: 7px 0; border-bottom: 1px dashed var(--line); }
|
|
.meta-grid span:nth-last-of-type(1), .meta-grid b:nth-last-of-type(1) { border-bottom: 0; }
|
|
.meta-grid span { color: var(--muted); }
|
|
.meta-grid b { color: var(--paper); font: 700 12px var(--mono); text-align: right; }
|
|
.section-title { display: flex; align-items: center; gap: 8px; margin: 22px 0 9px; color: var(--paper); font: 700 11px var(--mono); text-transform: uppercase; letter-spacing: .07em; }
|
|
.section-title::before { content: ""; width: 9px; height: 9px; flex-shrink: 0; border: 2px solid var(--black); background: var(--pink); transform: rotate(45deg); }
|
|
.relation { display: flex; gap: 9px; align-items: center; margin: 0 -8px; padding: 6px 8px; border-radius: 6px; cursor: pointer; }
|
|
.relation:hover { background: var(--ink-3); }
|
|
.relation i { width: 7px; height: 7px; border-radius: 50%; background: var(--lime); }
|
|
.relation span { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--paper); }
|
|
.relation small { color: var(--dim); font: 10px var(--mono); }
|
|
.alert-row { display: grid; grid-template-columns: auto minmax(0,1fr); gap: 10px; align-items: center; margin: 0 -8px; padding: 7px 8px; border-radius: 6px; color: inherit; text-decoration: none; }
|
|
.alert-row:hover { background: var(--ink-3); }
|
|
.alert-row em { padding: 1px 7px; border: 2px solid var(--black); border-radius: 4px; font: 700 9.5px var(--mono); font-style: normal; text-transform: uppercase; }
|
|
.alert-row strong, .alert-row small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.alert-row strong { color: var(--paper); }
|
|
.alert-row small { color: var(--dim); font: 10px var(--mono); }
|
|
.severity-critical { color: var(--paper); background: var(--red); }
|
|
.severity-high { color: var(--black); background: var(--tang); }
|
|
.severity-medium { color: var(--black); background: var(--yellow); }
|
|
.severity-low { color: var(--black); background: var(--muted); }
|
|
/* Resident ID card: laminated cream card, lime header, holographic sheen, barcode. */
|
|
.id-card { position: relative; overflow: hidden; margin: 4px 2px 0; border: 2px solid var(--black); border-radius: 12px; background: #f3ecdc; color: #15130f; box-shadow: 5px 5px 0 var(--black); transform: rotate(-1.2deg); animation: plonk .25s ease-out; }
|
|
.id-card::after { content: ""; position: absolute; inset: 0; pointer-events: none; background: linear-gradient(115deg, transparent 30%, rgba(92,200,255,.18) 42%, rgba(255,94,168,.18) 50%, rgba(200,241,53,.18) 58%, transparent 70%); }
|
|
.id-card small { display: block; color: #6b6352; font: 700 8.5px var(--mono); text-transform: uppercase; letter-spacing: .08em; }
|
|
.id-card-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; padding: 7px 12px; border-bottom: 2px solid var(--black); background: var(--lime); }
|
|
.id-card-head span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: 700 10px var(--mono); text-transform: uppercase; }
|
|
.id-card-head b { flex-shrink: 0; font: 400 13px var(--display); }
|
|
.id-card-body { display: grid; grid-template-columns: 96px minmax(0,1fr); gap: 12px; padding: 12px; }
|
|
.id-card-portrait { width: 96px; height: 116px; border: 2px solid var(--black); border-radius: 6px; box-shadow: 2px 2px 0 var(--black); }
|
|
.id-card-fields strong { display: block; margin: 1px 0 8px; font: 400 17px/1.1 var(--display); overflow-wrap: anywhere; }
|
|
.id-card-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px 10px; }
|
|
.id-card-grid span { font: 700 12px var(--mono); }
|
|
.id-card-grid .wide { grid-column: 1 / -1; }
|
|
.id-card-job { margin: 0 12px; padding: 8px 10px; border: 2px dashed #b9ae95; border-radius: 6px; }
|
|
.id-card-job strong { display: block; font: 700 14px var(--body); }
|
|
.id-card-job span { color: #4a4436; font-size: 12px; }
|
|
.id-card-foot { display: flex; align-items: end; justify-content: space-between; gap: 10px; padding: 10px 12px 4px; font: 700 11px var(--mono); }
|
|
.id-card-foot > span:first-child { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.id-card-number { flex-shrink: 0; padding: 1px 6px; border-radius: 3px; background: #15130f; color: var(--lime); }
|
|
.id-card-barcode { display: flex; gap: 2px; height: 26px; margin: 6px 12px 12px; overflow: hidden; }
|
|
.id-card-barcode i { flex-shrink: 0; height: 100%; background: #15130f; }
|
|
.id-card-note { margin-top: 14px; font: italic 11px var(--mono); text-align: center; }
|
|
.coverage-title, .coverage-list-head, .source-title { display: flex; align-items: center; justify-content: flex-start; }
|
|
.coverage-title small, .coverage-list-head small, .source-title small { margin-left: auto; }
|
|
.coverage-title small, .coverage-list-head small, .source-title small { color: var(--dim); font: 10px var(--mono); text-transform: none; letter-spacing: 0; }
|
|
.coverage-menu { display: grid; gap: 3px; }
|
|
.coverage-row { width: 100%; min-height: 34px; display: grid; grid-template-columns: 10px 1fr auto 14px; gap: 10px; align-items: center; padding: 5px 9px; border: 2px solid transparent; border-radius: 7px; background: transparent; color: var(--paper); text-align: left; cursor: pointer; }
|
|
.coverage-row:hover { background: var(--ink-3); }
|
|
.coverage-row.active { color: var(--black); border-color: var(--black); background: var(--lime); box-shadow: 2px 2px 0 var(--black); }
|
|
.coverage-row i { width: 10px; height: 10px; border: 2px solid var(--black); border-radius: 2px; }
|
|
.coverage-row span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.coverage-row small { color: inherit; opacity: .7; font: 11px var(--mono); }
|
|
.coverage-row b { font: 700 14px var(--mono); text-align: center; }
|
|
.coverage-list-head { margin: 18px 0 8px; color: var(--paper); font: 700 12px var(--mono); }
|
|
.coverage-file-list { position: relative; height: min(39vh, 350px); min-height: 150px; overflow: auto; border: 2px solid var(--black); border-radius: 8px; outline: none; background: var(--ink); }
|
|
.coverage-file-list:focus { border-color: var(--pink); }
|
|
.coverage-list-spacer { width: 1px; }
|
|
.coverage-list-window { position: absolute; inset: 0 0 auto; }
|
|
.coverage-file { width: 100%; height: 43px; display: grid; grid-template-columns: 4px minmax(0,1fr) auto; gap: 10px; align-items: stretch; padding: 5px 10px; border: 0; border-bottom: 1px dashed var(--line); background: transparent; color: inherit; text-align: left; cursor: pointer; }
|
|
.coverage-file:hover { background: var(--ink-3); }
|
|
.coverage-file.active { background: var(--ink-3); box-shadow: inset 4px 0 var(--pink); }
|
|
.coverage-file > i { border-radius: 1px; }
|
|
.coverage-file > span { min-width: 0; align-self: center; }
|
|
.coverage-file strong, .coverage-file small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.coverage-file strong { color: var(--paper); }
|
|
.coverage-file small { color: var(--dim); font: 10px var(--mono); }
|
|
.coverage-file em { align-self: center; color: var(--dim); font: 10px var(--mono); font-style: normal; }
|
|
.coverage-empty { padding: 18px 10px; color: var(--dim); text-align: center; }
|
|
.code-preview { position: relative; height: min(46vh, 430px); min-height: 220px; overflow: auto; border: 2px solid var(--black); border-radius: 8px; outline: none; background: #0e0c09; color: #d9d0bd; font: 11px/16px var(--mono); tab-size: 2; }
|
|
.code-preview:focus { border-color: var(--pink); }
|
|
.source-spacer { position: relative; min-width: 100%; }
|
|
.source-window { position: absolute; inset: 0 auto auto 0; min-width: 100%; margin: 0; padding: 6px 0 0; color: inherit; font: inherit; line-height: 16px; white-space: pre; }
|
|
.source-line { display: block; height: 16px; padding-right: 12px; }
|
|
.source-line::before { content: attr(data-line); position: sticky; left: 0; display: inline-block; width: 42px; margin-right: 12px; padding-right: 8px; border-right: 2px solid #26221b; background: #0e0c09; color: #5d5647; text-align: right; user-select: none; }
|
|
.tok-plain { color: #d9d0bd; }
|
|
.tok-comment { color: #7d745f; font-style: italic; }
|
|
.tok-string { color: #c8f135; }
|
|
.tok-number { color: #ff9a1f; }
|
|
.tok-keyword { color: #ff5ea8; }
|
|
.tok-type { color: #5cc8ff; }
|
|
.tok-function { color: #ffd23f; }
|
|
.tok-property { color: #9be7c4; }
|
|
.tok-operator { color: #a79d88; }
|
|
.tok-constant { color: #ff7a6b; }
|
|
.tok-tag { color: #5cc8ff; }
|
|
.result-row { display: grid; grid-template-columns: 4px minmax(0,1fr); gap: 10px; min-width: 0; margin: 0 -6px; padding: 8px; border-radius: 6px; cursor: pointer; }
|
|
.result-row:hover { background: var(--ink-3); }
|
|
.result-row i { border-radius: 1px; background: var(--tang); }
|
|
.result-row strong { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--paper); }
|
|
.result-row small { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dim); font: 10px var(--mono); }
|
|
|
|
/* ---- Floating canvas chrome ---- */
|
|
.breadcrumb { position: absolute; left: 16px; bottom: 16px; max-width: calc(100% - 200px); display: flex; align-items: center; gap: 10px; padding: 6px 13px 6px 6px; border-radius: 10px 4px 10px 4px; color: var(--muted); font: 11px var(--mono); }
|
|
#breadcrumbText { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
.breadcrumb button { width: 28px; height: 28px; display: grid; place-items: center; padding: 0; border: 2px solid var(--black); border-radius: 6px; background: var(--sky); color: var(--black); font-weight: 700; cursor: pointer; transition: transform .15s; }
|
|
.breadcrumb button:hover { transform: rotate(-12deg); }
|
|
.fps { position: absolute; right: 20px; bottom: 70px; padding: 2px 7px; border: 2px solid var(--black); border-radius: 4px; background: var(--black); color: var(--lime); font: 700 10px var(--mono); }
|
|
.canvas-controls { position: absolute; right: 16px; bottom: 16px; display: flex; gap: 3px; padding: 4px; border-radius: 4px 10px 4px 10px; }
|
|
.canvas-controls button { display: grid; place-items: center; width: 32px; height: 30px; border: 0; border-radius: 6px; background: transparent; color: var(--paper); font: 700 18px var(--mono); cursor: pointer; }
|
|
.canvas-controls button:hover { background: var(--lime); color: var(--black); }
|
|
.canvas-controls svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
|
|
.legend { position: absolute; right: 12px; top: 14px; display: none; width: 214px; padding: 6px; border-radius: 8px; transform: rotate(1deg); }
|
|
.legend.open { display: grid; gap: 2px; animation: plonk .18s ease-out; }
|
|
.legend button { width: 100%; display: flex; justify-content: space-between; gap: 12px; padding: 7px 8px; border: 0; border-radius: 5px; background: transparent; color: var(--paper); text-align: left; cursor: pointer; }
|
|
.legend button:hover { background: var(--ink-3); }
|
|
.legend button b { color: var(--dim); font: 11px var(--mono); }
|
|
.legend i { display: inline-block; width: 10px; height: 10px; margin-right: 8px; border: 2px solid var(--black); border-radius: 2px; }
|
|
.tooltip { position: absolute; z-index: 3; max-width: 320px; padding: 6px 10px; border-radius: 3px; background: var(--paper); color: var(--black); font-weight: 700; pointer-events: none; transform: rotate(-1deg); }
|
|
.tooltip small { display: block; margin-top: 1px; color: #5d5647; font: 400 10.5px var(--mono); }
|
|
.camera-help { position: absolute; z-index: 2; left: 16px; top: 18px; width: fit-content; max-width: calc(100% - 32px); display: flex; flex-wrap: wrap; gap: 12px; align-items: center; padding: 5px 12px 5px 5px; border-radius: 8px; color: var(--dim); font: 10.5px var(--mono); }
|
|
.camera-help button { height: 28px; padding: 0 10px; border: 2px solid var(--black); border-radius: 6px; background: var(--ink-3); color: var(--paper); font: 700 10.5px var(--mono); text-transform: uppercase; cursor: pointer; }
|
|
.camera-help button:hover { background: var(--sky); color: var(--black); }
|
|
.camera-help b { color: var(--paper); }
|
|
|
|
/* City bar: one row of identical chips (views, then actions), help text underneath. */
|
|
.city-hud { position: absolute; z-index: 2; left: 16px; top: 18px; max-width: calc(100% - 290px); display: grid; gap: 6px; padding: 5px; border-radius: 10px 4px 10px 4px; }
|
|
.city-row { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }
|
|
.city-row .divider { width: 2px; height: 22px; margin: 0 4px; background: repeating-linear-gradient(var(--line) 0 4px, transparent 4px 7px); }
|
|
.chip { height: 32px; display: inline-flex; align-items: center; gap: 7px; padding: 0 11px 0 7px; border: 2px solid transparent; border-radius: 7px; background: transparent; color: var(--muted); font: 700 11px var(--mono); text-transform: uppercase; letter-spacing: .03em; white-space: nowrap; cursor: pointer; transition: background-color .12s, color .12s, transform .12s; }
|
|
.chip svg { width: 16px; height: 16px; flex-shrink: 0; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
|
|
.chip kbd { margin-left: 1px; }
|
|
.chip:hover { color: var(--paper); background: var(--ink-3); }
|
|
.chip:hover svg { animation: wiggle .35s ease-in-out; }
|
|
.chip.active { color: var(--black); border-color: var(--black); background: var(--lime); box-shadow: 2px 2px 0 var(--black); }
|
|
#tourButton.active { background: var(--pink); }
|
|
#shareButton.done { color: var(--black); border-color: var(--black); background: var(--sky); }
|
|
.city-help { padding: 0 6px 2px; color: var(--dim); font: 10.5px var(--mono); }
|
|
.city-help b { color: var(--paper); }
|
|
.tour-caption { position: absolute; z-index: 2; left: 50%; bottom: 84px; display: grid; justify-items: center; gap: 2px; padding: 12px 22px; border-radius: 10px; text-align: center; pointer-events: none; transform: translateX(-50%) rotate(-1.5deg); animation: plonk .3s ease-out; }
|
|
.tour-caption small { padding: 0 6px; background: var(--pink); color: var(--black); font: 700 10px var(--mono); letter-spacing: .1em; }
|
|
.tour-caption strong { color: var(--paper); font: 400 26px var(--display); }
|
|
.tour-caption span { color: var(--muted); font: 11px var(--mono); }
|
|
.joystick { position: absolute; z-index: 3; width: 112px; height: 112px; margin: -56px 0 0 -56px; border: 2px dashed var(--paper); border-radius: 50%; background: rgba(21,19,15,.5); pointer-events: none; }
|
|
.joystick i { position: absolute; left: 34px; top: 34px; width: 40px; height: 40px; border: 2px solid var(--black); border-radius: 50%; background: var(--lime); }
|
|
.crosshair { position: absolute; z-index: 2; left: 50%; top: 50%; width: 18px; height: 18px; margin: -9px 0 0 -9px; pointer-events: none; }
|
|
.crosshair::before, .crosshair::after { content: ""; position: absolute; background: var(--paper); box-shadow: 0 0 0 1px var(--black); }
|
|
.crosshair::before { left: 8px; top: 0; width: 2px; height: 18px; }
|
|
.crosshair::after { left: 0; top: 8px; width: 18px; height: 2px; }
|
|
.city-target { position: absolute; z-index: 2; left: 50%; top: calc(50% + 22px); padding: 5px 11px; border-radius: 4px; background: var(--paper); color: var(--black); font-weight: 700; white-space: nowrap; text-align: center; pointer-events: none; transform: translateX(-50%) rotate(-1deg); }
|
|
.city-target small { display: block; color: #5d5647; font: 400 10.5px var(--mono); }
|
|
.city-target kbd { margin-left: 6px; background: var(--lime); }
|
|
.city-address { position: absolute; z-index: 2; right: 16px; top: 18px; max-width: 260px; padding: 4px 10px; border-radius: 4px; background: var(--black); color: var(--lime); font: 700 11px var(--mono); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; pointer-events: none; }
|
|
.minimap { position: absolute; z-index: 2; right: 16px; bottom: 62px; width: 220px; height: 150px; border-radius: 6px; cursor: crosshair; transform: rotate(-1deg); }
|
|
|
|
.progress-card { position: absolute; z-index: 4; left: 50%; top: 22px; width: min(460px, calc(100% - 30px)); padding: 16px 44px 15px 16px; border-radius: 10px 4px 10px 4px; box-shadow: var(--hard-lg); transform: translateX(-50%) rotate(-.6deg); animation: plonk .22s ease-out; }
|
|
.progress-copy { display: flex; flex-direction: column; gap: 3px; }
|
|
.progress-copy strong { color: var(--paper); font: 400 15px var(--display); }
|
|
.progress-copy span, .progress-count { color: var(--muted); }
|
|
#progressMessage { max-height: 100px; overflow: auto; overflow-wrap: anywhere; font: 11px var(--mono); }
|
|
.progress-track { position: relative; height: 12px; margin: 12px 0 7px; overflow: hidden; border: 2px solid var(--black); border-radius: 3px; background: var(--ink); }
|
|
.progress-track i { position: relative; display: block; height: 100%; width: 5%; overflow: hidden; background: var(--lime); transition: width .25s ease; }
|
|
/* Barber pole: 45deg stripes whose horizontal period is exactly 28px (stripe spacing 28/sqrt 2), painted
|
|
once on a layer 28px wider than the bar and slid one period, so the loop has no seam or jump. */
|
|
.progress-track i::before { content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: calc(100% + 28px); background: repeating-linear-gradient(-45deg, var(--lime) 0 calc(14px / 1.41421356), var(--black) 0 calc(28px / 1.41421356)); animation: barber .6s linear infinite; will-change: transform; }
|
|
.progress-track i[data-tone="error"] { background: var(--danger); }
|
|
.progress-track i[data-tone="warn"] { background: var(--yellow); }
|
|
.progress-track i[data-tone]::before { display: none; }
|
|
.progress-count { font: 10.5px var(--mono); }
|
|
.progress-dismiss { position: absolute; right: 8px; top: 8px; }
|
|
.progress-action { display: inline-grid; place-items: center; width: fit-content; margin-top: 14px; text-decoration: none; }
|
|
.empty-state { position: absolute; inset: 0; display: grid; place-content: center; gap: 4px; text-align: center; color: var(--paper); }
|
|
.empty-state strong { font: 400 20px var(--display); }
|
|
.empty-state span { color: var(--muted); }
|
|
|
|
/* ---- Dialogs ---- */
|
|
dialog { width: min(580px, calc(100vw - 30px)); max-height: calc(100dvh - 32px); padding: 0; border: 2px solid var(--black); border-radius: 16px 6px 16px 6px; background: var(--ink-2); color: var(--paper); box-shadow: 8px 8px 0 var(--black); }
|
|
dialog[open] { animation: plonk .2s ease-out; transform: rotate(-.4deg); }
|
|
dialog::backdrop { background: rgba(10, 8, 5, .78); }
|
|
.dialog-shell { padding: 28px; }
|
|
.dialog-head { display: flex; align-items: start; justify-content: space-between; margin-bottom: 18px; }
|
|
.dialog-head small { display: inline-block; padding: 2px 7px; background: var(--pink); color: var(--black); font: 700 10px var(--mono); letter-spacing: .12em; transform: rotate(-2deg); }
|
|
.dialog-head h1 { margin: 10px 0 0; font: 400 30px/1.05 var(--display); color: var(--paper); }
|
|
.dialog-description { margin: 8px 0 2px; color: var(--muted); font-size: 14px; }
|
|
.close-button { width: 34px; height: 34px; flex-shrink: 0; display: grid; place-items: center; padding: 0; border: 2px solid var(--black); border-radius: 8px; background: var(--ink-3); color: var(--paper); cursor: pointer; transition: transform .2s, background-color .12s; }
|
|
.close-button svg { display: block; width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; }
|
|
.close-button:hover { background: var(--red); color: var(--black); transform: rotate(90deg); }
|
|
.source-card { width: 100%; margin-top: 14px; padding: 16px; border: 2px solid var(--black); border-radius: 10px; background: var(--ink); color: inherit; text-align: left; transition: transform .12s, box-shadow .12s; }
|
|
button.source-card { display: flex; align-items: center; gap: 14px; cursor: pointer; }
|
|
button.source-card:hover { box-shadow: 5px 5px 0 var(--sky); transform: translate(-2px, -2px); }
|
|
.github-card:focus-within { box-shadow: 5px 5px 0 var(--lime); }
|
|
.source-card > b { margin-left: auto; color: var(--dim); font: 700 20px var(--mono); transition: transform .12s, color .12s; }
|
|
button.source-card:hover > b { color: var(--sky); transform: translateX(4px); }
|
|
.source-icon { width: 42px; height: 42px; display: grid; place-items: center; border: 2px solid var(--black); border-radius: 8px; background: var(--sky); color: var(--black); transform: rotate(-5deg); }
|
|
.github-card .source-icon { background: var(--lime); transform: rotate(4deg); }
|
|
.source-icon svg { width: 21px; height: 21px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
|
|
.source-card strong, .source-card small { display: block; }
|
|
.source-card strong { font: 400 15px var(--display); color: var(--paper); }
|
|
.source-card small { margin-top: 2px; color: var(--muted); }
|
|
.github-card { display: grid; grid-template-columns: 42px 1fr; gap: 0 14px; align-items: center; }
|
|
.github-row { grid-column: 1 / -1; display: flex; gap: 10px; margin-top: 14px; }
|
|
.github-row input { flex: 1; min-width: 0; height: 42px; padding: 0 12px; border: 2px solid var(--black); border-radius: 8px; outline: none; background: var(--ink-2); color: var(--paper); font: 12px var(--mono); }
|
|
.github-row input::placeholder { color: var(--dim); }
|
|
.github-row input:focus { border-color: var(--lime); }
|
|
.github-account { grid-column: 1 / -1; margin: 10px 0 0; color: var(--muted); font-size: 12.5px; }
|
|
.github-account a, .github-account button { padding: 0 2px; border: 0; background: linear-gradient(transparent 60%, rgba(255,94,168,.45) 60%); color: var(--paper); font: inherit; font-weight: 700; text-decoration: none; cursor: pointer; }
|
|
.github-account a:hover, .github-account button:hover { background: var(--pink); color: var(--black); }
|
|
.github-notice { margin: 0 0 4px; padding: 9px 12px; border: 2px solid var(--black); border-left-width: 8px; border-radius: 6px; background: var(--ink); color: var(--paper); font-weight: 700; transform: rotate(-.5deg); }
|
|
.github-notice[data-tone="ok"] { border-left-color: var(--lime); }
|
|
.github-notice[data-tone="warn"] { border-left-color: var(--yellow); }
|
|
.github-notice[data-tone="error"] { border-left-color: var(--red); }
|
|
.form-error { grid-column: 1 / -1; min-height: 16px; margin: 6px 0 -6px; color: var(--red); font: 700 11px var(--mono); }
|
|
.dialog-foot { display: flex; gap: 8px; align-items: center; margin: 16px 2px 0; color: var(--dim); font: 11px/1.6 var(--mono); }
|
|
.dialog-foot::before { content: "!"; flex-shrink: 0; width: 16px; height: 16px; display: grid; place-items: center; border-radius: 50%; background: var(--yellow); color: var(--black); font-weight: 700; }
|
|
.settings-dialog { width: min(480px, calc(100vw - 30px)); }
|
|
.settings-dialog[open] { transform: rotate(.5deg); }
|
|
.settings-shell { padding: 26px; }
|
|
.settings-status { display: flex; align-items: center; justify-content: space-between; margin: -2px 0 8px; padding: 8px 12px; border: 2px dashed var(--line); border-radius: 8px; }
|
|
.settings-status span { display: flex; align-items: center; gap: 8px; color: var(--paper); font-weight: 700; }
|
|
.settings-status i { width: 9px; height: 9px; border: 2px solid var(--black); border-radius: 50%; background: var(--lime); }
|
|
.settings-status small { color: var(--dim); font: 700 10px var(--mono); letter-spacing: .08em; }
|
|
.preference-row { display: flex; gap: 16px; justify-content: space-between; align-items: center; padding: 15px 0; border-bottom: 1px dashed var(--line); }
|
|
.preference-row label { color: var(--paper); font-weight: 700; }
|
|
.preference-row small { display: block; margin-top: 3px; color: var(--muted); font-size: 11.5px; font-weight: 400; }
|
|
.preference-row select { padding: 7px 10px; border: 2px solid var(--black); border-radius: 7px; background: var(--ink); color: var(--paper); font: 12px var(--mono); }
|
|
.switch { appearance: none; flex-shrink: 0; width: 44px; height: 24px; margin: 0; padding: 2px; border: 2px solid var(--black); border-radius: 999px; background: var(--ink-3); cursor: pointer; transition: background .15s; }
|
|
.switch::before { content: ""; display: block; width: 16px; height: 16px; border: 2px solid var(--black); border-radius: 50%; background: var(--muted); transition: transform .2s cubic-bezier(.3,1.6,.5,1), background .15s; }
|
|
.switch:checked { background: var(--lime); }
|
|
.switch:checked::before { background: var(--paper); transform: translateX(20px); }
|
|
.shortcut-guide { margin-top: 18px; color: var(--muted); font: 11px var(--mono); }
|
|
.shortcut-guide > span { display: block; margin-bottom: 10px; }
|
|
.shortcut-guide div { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; }
|
|
.settings-note { display: grid; grid-template-columns: 36px 1fr; gap: 12px; align-items: start; margin-top: 16px; padding: 12px; border: 2px solid var(--black); border-radius: 10px; background: var(--ink); transform: rotate(-.7deg); }
|
|
.settings-note-icon { width: 36px; height: 36px; display: grid; place-items: center; border: 2px solid var(--black); border-radius: 8px; background: var(--tang); color: var(--black); font-size: 18px; transform: rotate(8deg); }
|
|
.settings-note p { margin: 0; }
|
|
.settings-note strong, .settings-note small { display: block; }
|
|
.settings-note strong { color: var(--paper); }
|
|
.settings-note small { margin-top: 3px; color: var(--muted); line-height: 1.5; }
|
|
.settings-actions { display: flex; justify-content: flex-end; margin-top: 20px; }
|
|
.dialog-button { min-width: 96px; }
|
|
|
|
button:focus-visible, a:focus-visible, input:focus-visible, select:focus-visible, [role="tab"]:focus-visible { outline: 2px dashed var(--pink); outline-offset: 3px; }
|
|
html[data-input-method="pointer"] button:focus { outline: none; }
|
|
|
|
@media (max-width: 1500px) { .scene-stats { display: none; } }
|
|
@media (max-width: 1150px) {
|
|
.tool .label, .metric span, .brand-name { display: none; }
|
|
.tool:not(.icon-only) { padding: 0 8px; }
|
|
.brand { padding-right: 10px; }
|
|
.welcome-sticker { display: none; }
|
|
}
|
|
@media (max-width: 900px) {
|
|
:root { --panel-width: 260px; }
|
|
.filter-wrap { width: 160px; }
|
|
.toolbar { gap: 6px; padding: 0 10px; }
|
|
.chip .label { display: none; }
|
|
.city-hud { max-width: calc(100% - 32px); }
|
|
.city-address { display: none; }
|
|
}
|
|
@media (max-width: 670px) {
|
|
:root { --panel-width: 0px; }
|
|
.workspace { grid-template-columns: 1fr; grid-template-rows: minmax(160px,1fr) minmax(150px,30%); }
|
|
.inspector { display: block; border-left: 0; border-top: 2px solid var(--black); }
|
|
.inspector > * { min-width: 0; }
|
|
.inspector-toggle { display: none; }
|
|
.tabs { height: 44px; }
|
|
.panel { height: calc(100% - 44px); padding: 10px 12px; }
|
|
#layersButton, #codeButton, #paletteButton, .brand, .metric-switch, #mapButton, .toolbar-spacer { display: none; }
|
|
.filter-wrap { flex: 1; width: auto; min-width: 65px; }
|
|
.dialog-shell { padding: 20px; }
|
|
.welcome { padding: 20px; }
|
|
.welcome-features { display: none; }
|
|
.camera-help { left: 10px; top: 10px; gap: 8px; font-size: 9.5px; }
|
|
.city-hud { left: 10px; top: 10px; }
|
|
.city-help, .minimap { display: none; }
|
|
.breadcrumb { left: 10px; bottom: 10px; }
|
|
.canvas-controls { right: 10px; bottom: 10px; }
|
|
}
|
|
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; animation-iteration-count: 1 !important; } }
|