feat(mystery): /mystery route + CRT bezel + theme scaffold

This commit is contained in:
2026-05-08 23:39:58 -05:00
parent 460626aad9
commit 96d3036c4d
3 changed files with 229 additions and 0 deletions
+171
View File
@@ -0,0 +1,171 @@
:root[data-mystery-theme='amber'] {
--m-bg: #1a0d00;
--m-fg: #ffb000;
--m-accent-1: #ffb000;
--m-accent-2: #ffb000;
--m-dim: rgba(255, 176, 0, 0.55);
--m-bezel: #0a0500;
--m-divider-style: dashed;
}
:root[data-mystery-theme='ansi'] {
--m-bg: #000080;
--m-fg: #ffffff;
--m-accent-1: #ffff55;
--m-accent-2: #55ffff;
--m-dim: #aaaaaa;
--m-bezel: #000040;
--m-divider-style: double;
}
.mystery-root {
position: fixed;
inset: 0;
background: var(--m-bezel);
color: var(--m-fg);
font-family: 'Courier New', 'Cascadia Mono', 'Consolas', monospace;
font-size: 14px;
line-height: 1.45;
letter-spacing: 0.02em;
display: flex;
flex-direction: column;
padding: 16px;
box-sizing: border-box;
text-shadow: 0 0 1.5px currentColor;
}
.mystery-bezel {
flex: 1;
background: var(--m-bg);
border-radius: 6px;
padding: 22px 26px 14px;
position: relative;
overflow: hidden;
display: flex;
flex-direction: column;
box-shadow: inset 0 0 60px rgba(0, 0, 0, 0.55);
}
.mystery-bezel::before {
/* scanlines overlay */
content: '';
position: absolute;
inset: 0;
pointer-events: none;
background: repeating-linear-gradient(
to bottom,
transparent 0,
transparent 2px,
rgba(0, 0, 0, 0.18) 2px,
rgba(0, 0, 0, 0.18) 3px
);
opacity: 0.6;
z-index: 1;
}
.mystery-theme-toggle {
position: absolute;
top: 8px;
right: 12px;
z-index: 3;
display: flex;
gap: 6px;
font-size: 11px;
}
.mystery-theme-toggle button {
background: transparent;
color: var(--m-dim);
border: 1px solid var(--m-dim);
border-radius: 2px;
padding: 2px 6px;
font: inherit;
cursor: pointer;
}
.mystery-theme-toggle button[aria-pressed='true'] {
color: var(--m-fg);
border-color: var(--m-fg);
}
.mystery-transcript {
flex: 1;
overflow-y: auto;
white-space: pre-wrap;
word-break: break-word;
position: relative;
z-index: 2;
padding-right: 6px;
}
.mystery-transcript .system {
color: var(--m-accent-1);
font-weight: bold;
margin-top: 0.6em;
}
.mystery-transcript .player {
color: var(--m-accent-2);
}
.mystery-transcript .player::before { content: '> '; }
.mystery-transcript .narration {
margin: 0.25em 0;
}
.mystery-input-row {
display: flex;
align-items: center;
gap: 6px;
margin-top: 10px;
position: relative;
z-index: 2;
}
.mystery-input-row::before {
content: '>';
color: var(--m-accent-2);
}
.mystery-input {
flex: 1;
background: transparent;
color: var(--m-fg);
border: none;
outline: none;
font: inherit;
text-shadow: inherit;
caret-color: var(--m-fg);
}
.mystery-chips {
display: none;
flex-wrap: wrap;
gap: 4px;
padding: 6px 0 4px;
position: relative;
z-index: 2;
border-top: 1px var(--m-divider-style) var(--m-dim);
margin-top: 8px;
}
.mystery-chip {
background: transparent;
color: var(--m-fg);
border: 1px solid var(--m-fg);
border-radius: 2px;
padding: 3px 7px;
font: inherit;
cursor: pointer;
font-size: 11px;
}
.mystery-chip[disabled] {
opacity: 0.35;
cursor: not-allowed;
}
@media (pointer: coarse) {
.mystery-chips { display: flex; }
}
+10
View File
@@ -0,0 +1,10 @@
// Stub. Replaced in Task 10 with the full terminal implementation.
console.info('[halfstreet] terminal placeholder loaded')
const transcript = document.querySelector<HTMLDivElement>('[data-mystery-transcript]')
if (transcript) {
const line = document.createElement('div')
line.className = 'narration'
line.textContent = 'Terminal scaffold loaded. Type wiring lands in the next task.'
transcript.appendChild(line)
}