mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-11 17:54:03 +01:00
Haunting, Normal and Crusade scale enemy hp and speed, the survivor's health, your income, and the length of the night. Normal is exactly 1.0 on every multiplier — it is the identity tier, which is what lets every existing raw-value assertion keep passing untouched. Enemy speed now derives from a single helper, so difficulty and frenzy compose in one place rather than fighting at three call sites. Also fixes a bug this surfaced: handleRestart ignored the selected tier, so restarting after choosing Crusade silently reverted to Normal. The react-hooks purity rule flagged Date.now() in the new handler, and extracting restartSeed() exposed the omission. Endless mode is deliberately left out — fmtTime(Infinity) renders Infinity:NaN, which would cost a guard plus tests for a mode whose only content is the same game but longer. README rewritten for all four features, including the reversal of its old placement promise. 160 tests, 100% coverage. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VFyXexNjMQG9V7K8de17fc
277 lines
5.3 KiB
CSS
277 lines
5.3 KiB
CSS
:root {
|
|
--void: #140b1c;
|
|
--panel: #1e1229;
|
|
--panel-edge: #34204a;
|
|
--bone: #e8dcc8;
|
|
--bone-dim: #9c8f7a;
|
|
--blood: #c94f7c;
|
|
--arcane: #b06ce8;
|
|
--holy: #7ce0c3;
|
|
--font-display: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
|
|
--font-data: ui-monospace, "Cascadia Mono", "JetBrains Mono", Menlo, monospace;
|
|
}
|
|
|
|
* { box-sizing: border-box; }
|
|
|
|
body {
|
|
margin: 0;
|
|
background:
|
|
radial-gradient(1200px 500px at 50% -10%, #241335 0%, var(--void) 60%);
|
|
color: var(--bone);
|
|
font-family: var(--font-data);
|
|
min-height: 100vh;
|
|
}
|
|
|
|
.frame {
|
|
max-width: 1280px;
|
|
margin: 0 auto;
|
|
padding: 16px 20px 28px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 14px;
|
|
}
|
|
|
|
.masthead {
|
|
display: flex;
|
|
align-items: baseline;
|
|
gap: 16px;
|
|
border-bottom: 1px solid var(--panel-edge);
|
|
padding-bottom: 10px;
|
|
}
|
|
|
|
.masthead h1 {
|
|
font-family: var(--font-display);
|
|
font-size: 1.7rem;
|
|
letter-spacing: 0.06em;
|
|
margin: 0;
|
|
color: var(--bone);
|
|
}
|
|
|
|
.tagline {
|
|
margin: 0;
|
|
color: var(--bone-dim);
|
|
font-size: 0.8rem;
|
|
flex: 1;
|
|
}
|
|
|
|
.clock {
|
|
margin: 0;
|
|
font-size: 1.1rem;
|
|
color: var(--arcane);
|
|
}
|
|
|
|
.board {
|
|
display: flex;
|
|
gap: 14px;
|
|
align-items: flex-start;
|
|
}
|
|
|
|
.stage {
|
|
border: 1px solid var(--panel-edge);
|
|
border-radius: 6px;
|
|
background: var(--void);
|
|
width: 100%;
|
|
max-width: 960px;
|
|
height: auto;
|
|
display: block;
|
|
}
|
|
|
|
.hud {
|
|
width: 270px;
|
|
min-width: 220px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 14px;
|
|
position: relative;
|
|
}
|
|
|
|
.hud-block {
|
|
background: var(--panel);
|
|
border: 1px solid var(--panel-edge);
|
|
border-radius: 6px;
|
|
padding: 12px 14px;
|
|
}
|
|
|
|
.hud-label {
|
|
font-family: var(--font-display);
|
|
font-size: 0.95rem;
|
|
letter-spacing: 0.12em;
|
|
text-transform: uppercase;
|
|
margin: 0 0 8px;
|
|
color: var(--bone-dim);
|
|
}
|
|
|
|
.hud-num { margin: 6px 0 0; font-size: 0.85rem; }
|
|
|
|
.phials { display: flex; gap: 5px; }
|
|
|
|
.phial {
|
|
width: 18px;
|
|
height: 26px;
|
|
border: 1px solid var(--panel-edge);
|
|
border-radius: 3px 3px 8px 8px;
|
|
background: transparent;
|
|
}
|
|
|
|
.phial-full {
|
|
background: linear-gradient(180deg, var(--arcane), #6d3aa8);
|
|
border-color: var(--arcane);
|
|
box-shadow: 0 0 8px rgba(176, 108, 232, 0.45);
|
|
}
|
|
|
|
.hpbar {
|
|
height: 10px;
|
|
border: 1px solid var(--panel-edge);
|
|
border-radius: 5px;
|
|
overflow: hidden;
|
|
background: #120b18;
|
|
}
|
|
|
|
.hpbar-fill {
|
|
height: 100%;
|
|
background: linear-gradient(90deg, #2e5c50, var(--holy));
|
|
transition: width 120ms linear;
|
|
}
|
|
|
|
.feed {
|
|
list-style: none;
|
|
margin: 8px 0 0;
|
|
padding: 0;
|
|
font-size: 0.75rem;
|
|
color: var(--holy);
|
|
}
|
|
|
|
.feed li::before { content: "▲ "; color: var(--bone-dim); }
|
|
|
|
.status-chips {
|
|
list-style: none;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 6px;
|
|
margin: 8px 0 0;
|
|
padding: 0;
|
|
}
|
|
|
|
.chip {
|
|
font-family: var(--font-data);
|
|
font-size: 0.68rem;
|
|
letter-spacing: 0.04em;
|
|
padding: 2px 7px;
|
|
border-radius: 999px;
|
|
border: 1px solid currentcolor;
|
|
opacity: 0.85;
|
|
}
|
|
|
|
.chip-slow { color: var(--arcane); }
|
|
.chip-suppress { color: var(--blood); }
|
|
.chip-bleed { color: var(--bone-dim); }
|
|
|
|
.spawnbar {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 10px;
|
|
}
|
|
|
|
.card {
|
|
font-family: var(--font-data);
|
|
background: var(--panel);
|
|
color: var(--bone);
|
|
border: 1px solid var(--panel-edge);
|
|
border-radius: 6px;
|
|
padding: 10px 14px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 3px;
|
|
cursor: pointer;
|
|
min-width: 118px;
|
|
text-align: left;
|
|
}
|
|
|
|
.card:hover:not(:disabled) {
|
|
border-color: var(--blood);
|
|
box-shadow: 0 0 10px rgba(201, 79, 124, 0.35);
|
|
}
|
|
|
|
.card:focus-visible {
|
|
outline: 2px solid var(--arcane);
|
|
outline-offset: 2px;
|
|
}
|
|
|
|
.card:disabled { opacity: 0.42; cursor: not-allowed; }
|
|
|
|
.card-name { font-family: var(--font-display); letter-spacing: 0.05em; }
|
|
|
|
.card-cost { font-size: 0.72rem; color: var(--blood); }
|
|
|
|
.card-boss { border-color: #5c2440; }
|
|
|
|
.card-wave { border-color: #3d2f63; }
|
|
|
|
.overlay {
|
|
background: var(--panel);
|
|
border-radius: 6px;
|
|
padding: 16px;
|
|
text-align: center;
|
|
}
|
|
|
|
.overlay h2 { font-family: var(--font-display); margin: 0 0 6px; }
|
|
|
|
.overlay p { margin: 0 0 12px; font-size: 0.8rem; color: var(--bone-dim); }
|
|
|
|
.overlay-win { border: 1px solid var(--blood); }
|
|
|
|
.overlay-loss { border: 1px solid var(--holy); }
|
|
|
|
.overlay button {
|
|
font-family: var(--font-display);
|
|
background: var(--blood);
|
|
color: var(--void);
|
|
border: none;
|
|
border-radius: 5px;
|
|
padding: 9px 16px;
|
|
cursor: pointer;
|
|
letter-spacing: 0.04em;
|
|
}
|
|
|
|
.overlay-loss button { background: var(--holy); }
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.hpbar-fill { transition: none; }
|
|
}
|
|
|
|
@media (max-width: 900px) {
|
|
.board { flex-direction: column; }
|
|
.hud { width: 100%; }
|
|
}
|
|
|
|
.card-power { border-color: var(--arcane); }
|
|
.card-rift { border-color: var(--bone-dim); }
|
|
.card-rift-active { border-color: var(--holy); color: var(--holy); }
|
|
|
|
.frenzy-banner {
|
|
margin: 10px 0 0;
|
|
padding: 5px 9px;
|
|
border: 1px solid var(--blood);
|
|
border-radius: 4px;
|
|
color: var(--blood);
|
|
font-family: var(--font-data);
|
|
font-size: 0.72rem;
|
|
letter-spacing: 0.06em;
|
|
text-align: center;
|
|
}
|
|
|
|
.difficulty { display: flex; gap: 6px; justify-content: center; margin-top: 6px; }
|
|
|
|
.diff {
|
|
background: none;
|
|
border: 1px solid var(--panel-edge);
|
|
border-radius: 4px;
|
|
color: var(--bone-dim);
|
|
cursor: pointer;
|
|
font-family: var(--font-data);
|
|
font-size: 0.7rem;
|
|
padding: 3px 10px;
|
|
}
|
|
|
|
.diff-on { border-color: var(--holy); color: var(--holy); }
|