world-simulator / frontend /src /styles.css
DeltaZN
feat: simple reasoning integration
c10fe82
Raw
History Blame Contribute Delete
20.9 kB
:root {
color: #f5f7f0;
background: #0e1813;
font-family:
Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
font-synthesis: none;
text-rendering: optimizeLegibility;
}
* {
box-sizing: border-box;
}
html,
body,
#root {
width: 100%;
height: 100%;
margin: 0;
overflow: hidden;
}
button {
font: inherit;
}
.shell {
position: relative;
width: 100vw;
height: 100svh;
overflow: hidden;
}
.worldCanvas {
position: absolute !important;
inset: 0;
z-index: 0;
width: 100% !important;
height: 100% !important;
}
/* ---------------------------------------------------------------- panels */
.scoreboard,
.eventFeed,
.controls,
.agentPanel,
.errorToast,
.busyToast {
border: 1px solid rgb(255 255 255 / 18%);
background: rgb(18 28 23 / 80%);
box-shadow: 0 18px 60px rgb(0 0 0 / 22%);
backdrop-filter: blur(14px);
}
/* ------------------------------------------------------------ scoreboard */
.scoreboard {
position: absolute;
top: 14px;
left: 50%;
z-index: 60;
width: min(460px, calc(100vw - 28px));
display: grid;
gap: 8px;
padding: 10px 14px 12px;
border-radius: 10px;
transform: translateX(-50%);
}
.scoreDuel {
display: grid;
grid-template-columns: 1fr auto 1fr;
align-items: center;
gap: 10px;
}
.scoreSide {
display: flex;
align-items: baseline;
gap: 10px;
}
.scoreName {
font-size: 13px;
font-weight: 800;
letter-spacing: 0.06em;
}
.scoreValue {
font-size: 24px;
font-weight: 800;
line-height: 1;
}
.scoreVs {
color: rgb(245 247 240 / 55%);
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
}
.scoreMeta {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 10px;
color: rgb(245 247 240 / 78%);
font-size: 12px;
}
.scoreActivity {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: #c7e6bd;
}
.famineBadge {
padding: 2px 8px;
border: 1px solid rgb(240 195 78 / 50%);
border-radius: 5px;
background: rgb(240 195 78 / 14%);
color: #ffeebc;
font-size: 11px;
font-weight: 800;
letter-spacing: 0.04em;
animation: faminePulse 1.6s ease-in-out infinite;
}
.countryGrid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 8px;
}
.countryCard {
display: grid;
gap: 5px;
min-width: 0;
padding: 8px 9px;
border: 1px solid rgb(255 255 255 / 22%);
border-radius: 8px;
background: rgb(255 255 255 / 7%);
}
.countryCardEmpty {
grid-column: 1 / -1;
color: rgb(245 247 240 / 60%);
font-size: 12px;
}
.countryHead {
display: grid;
grid-template-columns: auto minmax(0, 1fr) auto;
align-items: center;
gap: 6px;
font-size: 11px;
}
.countryHead strong {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.countryHead span:last-child {
color: rgb(245 247 240 / 58%);
font-size: 10px;
}
.countryBadge,
.npcCountryBadge {
display: inline-grid;
place-items: center;
width: 18px;
height: 18px;
border-radius: 5px;
color: #101813;
font-size: 11px;
font-weight: 900;
line-height: 1;
}
.countryPolicy {
margin: 0;
min-height: 2.5em;
color: rgb(245 247 240 / 82%);
font-size: 11px;
line-height: 1.25;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.countryFacts {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 3px 8px;
color: rgb(245 247 240 / 62%);
font-size: 10px;
}
.countryFacts span {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
@keyframes faminePulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.55;
}
}
.winProgress {
display: grid;
gap: 5px;
}
.winRow {
display: grid;
grid-template-columns: 158px 1fr;
align-items: center;
gap: 8px;
}
.winLabel {
font-size: 11px;
color: rgb(245 247 240 / 82%);
white-space: nowrap;
}
.winBar {
height: 8px;
border-radius: 5px;
background: rgb(255 255 255 / 12%);
overflow: hidden;
}
.winFill {
display: block;
height: 100%;
border-radius: 5px;
transition: width 320ms ease;
}
.winFillPopulation {
background: linear-gradient(90deg, #6fd96a, #b8f08a);
}
.winFillSurvival {
background: linear-gradient(90deg, #5b96f0, #9fd1ff);
}
.modelPills {
display: flex;
gap: 6px;
justify-content: center;
}
.modelPill {
padding: 4px 8px;
border-radius: 5px;
background: rgb(255 255 255 / 9%);
font-size: 10px;
}
.modelStatusReady {
color: #d9f4cf;
}
.modelStatusWarmup,
.modelStatusUnknown {
color: #fff3a1;
}
.modelStatusError {
color: #ffd3c8;
}
.scoreboard .tooltipAnchor[data-tooltip]::before {
top: calc(100% + 2px);
bottom: auto;
border-top-color: transparent;
border-bottom-color: rgb(10 17 14 / 96%);
}
.scoreboard .tooltipAnchor[data-tooltip]::after {
top: calc(100% + 14px);
bottom: auto;
}
/* ------------------------------------------------------------ side panels */
.sidePanelHeader {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
padding: 11px 12px 9px;
border-bottom: 1px solid rgb(255 255 255 / 14%);
}
.sidePanelTitle {
font-size: 13px;
font-weight: 800;
color: #fffce9;
}
.sidePanelHint {
font-size: 11px;
color: rgb(245 247 240 / 55%);
}
.eventEmpty {
margin: 0;
padding: 12px;
color: rgb(245 247 240 / 55%);
font-size: 12px;
}
/* ------------------------------------------------------------- event feed */
.eventFeed {
position: absolute;
top: 14px;
right: 14px;
bottom: 84px;
z-index: 30;
width: min(316px, calc(100vw - 28px));
display: flex;
flex-direction: column;
border-radius: 10px;
overflow: hidden;
}
.eventList {
flex: 1;
min-height: 0;
overflow-y: auto;
padding: 6px 8px 10px;
display: grid;
gap: 2px;
align-content: start;
scrollbar-width: thin;
}
.eventLine {
display: grid;
grid-template-columns: 34px 20px 1fr;
gap: 6px;
align-items: baseline;
padding: 4px 6px;
border-left: 3px solid transparent;
border-radius: 4px;
font-size: 12px;
line-height: 1.3;
}
.eventTick {
color: rgb(245 247 240 / 45%);
font-size: 10px;
font-variant-numeric: tabular-nums;
text-align: right;
}
.eventIcon {
text-align: center;
}
.eventText {
color: rgb(245 247 240 / 88%);
overflow-wrap: anywhere;
}
.severityGood {
border-left-color: #6fd96a;
background: rgb(111 217 106 / 8%);
}
.severityGood .eventText {
color: #d6f5cf;
}
.severityWarning {
border-left-color: #f0c34e;
background: rgb(240 195 78 / 8%);
}
.severityWarning .eventText {
color: #ffeebc;
}
.severityDanger {
border-left-color: #f06a4e;
background: rgb(240 106 78 / 10%);
}
.severityDanger .eventText {
color: #ffd3c8;
}
.severityNeutral {
border-left-color: rgb(255 255 255 / 18%);
}
.directiveTarget {
flex-shrink: 0;
color: #9fd1ff;
font-weight: 700;
font-family: ui-monospace, monospace;
font-size: 10px;
}
.directiveText {
color: rgb(245 247 240 / 82%);
}
.directiveBadge {
flex-shrink: 0;
padding: 1px 5px;
border-radius: 4px;
background: rgb(240 195 78 / 18%);
color: #ffeebc;
font-size: 9px;
font-weight: 700;
}
/* --------------------------------------------------------------- controls */
.controls {
position: absolute;
right: 14px;
bottom: 18px;
z-index: 30;
display: flex;
gap: 8px;
padding: 8px;
border-radius: 8px;
}
.controls button {
width: 42px;
height: 42px;
display: grid;
place-items: center;
border: 0;
border-radius: 7px;
color: #f7f5dd;
background: rgb(255 255 255 / 12%);
cursor: pointer;
}
.controls button:disabled {
cursor: wait;
opacity: 0.88;
}
.controls button:hover {
background: rgb(255 255 255 / 20%);
}
.controls button.isActive {
color: #142018;
background: #f8df6b;
}
.controls button.isActive:hover {
background: #ffe983;
}
.controls button:focus-visible,
.npcLabel button:focus-visible {
outline: 2px solid #f8df6b;
outline-offset: 2px;
}
/* -------------------------------------------------------------- agent panel */
.agentPanel {
position: absolute;
left: 14px;
bottom: 18px;
z-index: 30;
width: min(316px, calc(100vw - 108px));
border-radius: 8px;
overflow: visible;
}
.panelHeader {
display: flex;
justify-content: space-between;
gap: 12px;
padding: 13px 14px 10px;
border-bottom: 1px solid rgb(255 255 255 / 14%);
}
.panelTitle {
min-width: 0;
color: #fffce9;
font-size: 15px;
font-weight: 750;
}
.panelRole {
color: #c7e6bd;
font-size: 12px;
text-transform: uppercase;
}
.agentReadout {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 1px;
background: rgb(255 255 255 / 10%);
}
.readoutCell {
min-width: 0;
padding: 11px 8px;
background: rgb(18 28 23 / 68%);
color: rgb(245 247 240 / 82%);
font-size: 12px;
text-align: center;
}
.healthCell {
color: #fff3a1;
font-weight: 750;
}
.modelControl {
display: grid;
grid-template-columns: auto minmax(0, 1fr);
align-items: center;
gap: 8px;
padding: 8px 10px;
border-top: 1px solid rgb(255 255 255 / 10%);
background: rgb(255 255 255 / 5%);
}
.modelControl span {
color: #c7e6bd;
font-size: 10px;
font-weight: 750;
letter-spacing: 0.07em;
text-transform: uppercase;
}
.modelControl select {
min-width: 0;
height: 30px;
border: 1px solid rgb(255 255 255 / 18%);
border-radius: 6px;
background: rgb(18 28 23 / 88%);
color: #fffce9;
font-size: 11px;
}
.modelControl select:disabled {
opacity: 0.65;
}
.directiveBanner {
display: grid;
gap: 4px;
padding: 10px 12px;
border-top: 1px solid rgb(255 255 255 / 10%);
background: rgb(248 223 107 / 9%);
}
.directiveBanner span {
color: #fff3a1;
font-size: 11px;
font-weight: 750;
line-height: 1.1;
text-transform: uppercase;
}
.directiveBanner p {
margin: 0;
color: rgb(245 247 240 / 86%);
font-size: 12px;
line-height: 1.35;
}
.relationshipStrip {
display: flex;
flex-wrap: wrap;
gap: 6px;
padding: 9px 10px 0;
}
.relationshipPill {
max-width: 96px;
padding: 6px 8px;
border-radius: 6px;
background: rgb(255 255 255 / 9%);
color: rgb(245 247 240 / 82%);
font-size: 11px;
line-height: 1;
}
.houseResidents {
display: grid;
gap: 2px;
padding: 9px 0 0;
}
.houseResidents:last-child {
padding-bottom: 10px;
}
.houseResidentsLabel {
padding: 0 10px;
color: #c7e6bd;
font-size: 10px;
font-weight: 750;
letter-spacing: 0.07em;
text-transform: uppercase;
}
.houseResidentStrip {
padding-top: 4px;
}
button.houseResidentPill {
border: none;
font: inherit;
font-size: 11px;
cursor: pointer;
}
button.houseResidentPill:hover {
background: rgb(255 255 255 / 18%);
color: #fffce9;
}
.memoryList {
max-height: 148px;
overflow-y: auto;
padding: 9px 10px 10px;
}
.memorySummary,
.memoryItem {
display: grid;
gap: 4px;
padding: 9px 0;
border-bottom: 1px solid rgb(255 255 255 / 10%);
}
.memorySummary {
padding-top: 0;
}
.memoryItem:last-child {
border-bottom: 0;
}
.memoryTick {
color: #c7e6bd;
font-size: 11px;
line-height: 1.1;
}
.memorySummary p,
.memoryItem p {
position: relative;
margin: 0;
color: rgb(245 247 240 / 84%);
font-size: 12px;
line-height: 1.35;
}
.memorySummary p {
color: rgb(245 247 240 / 72%);
}
.thinkingBlock {
display: grid;
gap: 4px;
margin: 8px 10px 0;
padding: 9px 10px;
max-height: 140px;
overflow-y: auto;
border: 1px solid rgb(160 180 255 / 22%);
border-radius: 8px;
background: rgb(120 140 255 / 8%);
}
.thinkingLabel {
color: #b9c4ff;
font-size: 11px;
line-height: 1.1;
letter-spacing: 0.02em;
}
.thinkingText {
margin: 0;
color: rgb(232 236 255 / 86%);
font-size: 12px;
font-style: italic;
line-height: 1.4;
white-space: pre-wrap;
}
/* ----------------------------------------------------------------- tooltips */
.tooltipAnchor {
position: relative;
min-width: 0;
overflow: visible;
}
.tooltipAnchor:focus-visible {
outline: 2px solid #f8df6b;
outline-offset: 2px;
}
.truncateText {
display: block;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.tooltipMeasure {
position: absolute;
width: max-content;
height: 0;
overflow: hidden;
pointer-events: none;
visibility: hidden;
white-space: nowrap;
}
.tooltipAnchor[data-tooltip]::before,
.tooltipAnchor[data-tooltip]::after,
.memoryItem p[data-tooltip]::before,
.memoryItem p[data-tooltip]::after {
position: absolute;
left: 50%;
z-index: 80;
opacity: 0;
pointer-events: none;
transition:
opacity 120ms ease,
transform 120ms ease,
visibility 120ms ease;
visibility: hidden;
}
.tooltipAnchor[data-tooltip]::before,
.memoryItem p[data-tooltip]::before {
content: "";
border: 6px solid transparent;
}
.tooltipAnchor[data-tooltip]::after,
.memoryItem p[data-tooltip]::after {
content: attr(data-tooltip);
width: max-content;
max-width: min(320px, calc(100vw - 28px));
padding: 8px 10px;
border: 1px solid rgb(255 255 255 / 18%);
border-radius: 6px;
background: rgb(10 17 14 / 96%);
box-shadow: 0 14px 42px rgb(0 0 0 / 28%);
color: #fffce9;
font-size: 12px;
font-weight: 600;
line-height: 1.3;
overflow-wrap: anywhere;
text-align: left;
text-transform: none;
white-space: normal;
}
.tooltipAnchor[data-tooltip]:hover::before,
.tooltipAnchor[data-tooltip]:hover::after,
.tooltipAnchor[data-tooltip]:focus-visible::before,
.tooltipAnchor[data-tooltip]:focus-visible::after,
.memoryItem p[data-tooltip]:hover::before,
.memoryItem p[data-tooltip]:hover::after {
opacity: 1;
visibility: visible;
}
.tooltipAnchor[data-tooltip]::before,
.memoryItem p[data-tooltip]::before {
bottom: calc(100% + 2px);
border-top-color: rgb(10 17 14 / 96%);
transform: translate(-50%, 4px);
}
.tooltipAnchor[data-tooltip]::after,
.memoryItem p[data-tooltip]::after {
bottom: calc(100% + 14px);
transform: translate(-50%, 4px);
}
.tooltipAnchor[data-tooltip]:hover::before,
.tooltipAnchor[data-tooltip]:hover::after,
.tooltipAnchor[data-tooltip]:focus-visible::before,
.tooltipAnchor[data-tooltip]:focus-visible::after,
.memoryItem p[data-tooltip]:hover::before,
.memoryItem p[data-tooltip]:hover::after {
transform: translate(-50%, 0);
}
/* ------------------------------------------------------------------ toasts */
.errorToast {
position: absolute;
top: 142px;
left: 50%;
z-index: 70;
max-width: min(560px, calc(100vw - 28px));
padding: 11px 14px;
border-color: rgb(255 120 94 / 54%);
border-radius: 8px;
color: #ffd3c8;
font-size: 13px;
transform: translateX(-50%);
}
.busyToast {
position: absolute;
top: 142px;
left: 50%;
z-index: 65;
display: inline-flex;
align-items: center;
gap: 8px;
max-width: min(560px, calc(100vw - 28px));
padding: 11px 14px;
border-radius: 8px;
color: #fffce9;
font-size: 13px;
transform: translateX(-50%);
}
.spinIcon {
animation: spin 0.9s linear infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
/* ------------------------------------------------------------ scene labels */
.npcLabel {
pointer-events: auto;
}
/* Lift the character/beast badges up off the actor's head. */
.npcLabel > button {
transform: translateY(-16px);
}
.npcCard {
min-width: 96px;
max-width: 136px;
display: grid;
gap: 3px;
padding: 6px 8px 7px;
border: 1.5px solid rgb(255 255 255 / 22%);
border-radius: 8px;
color: #fffce9;
background: rgb(15 24 20 / 82%);
box-shadow: 0 10px 28px rgb(0 0 0 / 24%);
cursor: pointer;
text-align: left;
}
.npcCard:hover {
background: rgb(18 30 24 / 92%);
box-shadow: 0 12px 30px rgb(0 0 0 / 28%);
}
.npcCardDead {
opacity: 0.62;
filter: grayscale(0.7);
}
.npcCardName {
display: flex;
align-items: center;
gap: 5px;
min-width: 0;
}
.npcCardName strong {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 12px;
line-height: 1.1;
}
.npcCardIcon {
font-size: 11px;
line-height: 1;
}
.npcCountryBadge {
width: 16px;
height: 16px;
background: #f7d96c;
font-size: 10px;
}
.npcCardRole {
font-size: 9px;
font-weight: 700;
letter-spacing: 0.07em;
line-height: 1;
text-transform: uppercase;
}
.npcBar {
display: block;
width: 100%;
height: 5px;
border-radius: 3px;
background: rgb(255 255 255 / 14%);
overflow: hidden;
}
.npcBarFill {
display: block;
height: 100%;
border-radius: 3px;
transition: width 280ms ease;
}
.npcAgeBar {
height: 3px;
}
.npcAgeFill {
background: #d9b35a;
}
.houseTag,
.beastTag,
.resourceTag {
pointer-events: none;
display: grid;
gap: 3px;
padding: 5px 8px;
border: 1px solid rgb(255 255 255 / 20%);
border-radius: 7px;
background: rgb(15 24 20 / 80%);
color: #fffce9;
white-space: nowrap;
}
.houseTag {
min-width: 88px;
}
/* The house tag is a button so the home can be selected from the label. */
button.houseTag {
pointer-events: auto;
font: inherit;
text-align: left;
cursor: pointer;
}
button.houseTag:hover {
background: rgb(18 30 24 / 92%);
box-shadow: 0 10px 26px rgb(0 0 0 / 26%);
}
.houseTagBuilding {
border-color: rgb(255 208 122 / 50%);
}
.houseTagDestroyed {
border-color: rgb(240 106 78 / 55%);
opacity: 0.85;
}
.houseTagSelected {
border-color: rgb(159 216 255 / 85%);
box-shadow: 0 0 0 1px rgb(159 216 255 / 45%);
}
.houseTagTitle,
.beastTagTitle {
font-size: 11px;
font-weight: 700;
line-height: 1.1;
}
.houseHpBar,
.beastHpBar {
height: 4px;
}
.beastTag {
min-width: 80px;
border-color: rgb(240 106 78 / 50%);
}
.beastTagTitle {
color: #ffd3c8;
}
.resourceTag {
padding: 3px 7px;
font-size: 11px;
font-weight: 700;
}
.treasuryTag,
.cannonTag {
border-color: rgb(244 211 106 / 45%);
background: rgb(15 24 20 / 88%);
text-align: center;
}
/* -------------------------------------------------------- game over overlay */
.gameOverOverlay {
position: absolute;
inset: 0;
z-index: 100;
display: grid;
place-items: center;
padding: 20px;
background: rgb(8 13 10 / 78%);
backdrop-filter: blur(6px);
animation: overlayIn 400ms ease;
}
@keyframes overlayIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.gameOverCard {
width: min(620px, calc(100vw - 40px));
max-height: calc(100svh - 60px);
overflow-y: auto;
display: grid;
gap: 14px;
padding: 26px 28px;
border: 1px solid rgb(255 255 255 / 22%);
border-radius: 14px;
background: rgb(18 28 23 / 96%);
box-shadow: 0 30px 90px rgb(0 0 0 / 50%);
text-align: center;
}
.gameOver-win .gameOverCard {
border-color: rgb(111 217 106 / 45%);
}
.gameOver-lose .gameOverCard {
border-color: rgb(240 106 78 / 45%);
}
.gameOverCard h1 {
margin: 0;
font-size: 26px;
letter-spacing: 0.04em;
}
.gameOver-win .gameOverCard h1 {
color: #d6f5cf;
}
.gameOver-lose .gameOverCard h1 {
color: #ffd3c8;
}
.gameOverSubtitle {
margin: 0;
color: rgb(245 247 240 / 78%);
font-size: 14px;
}
.gameOverScore {
display: flex;
justify-content: center;
gap: 12px;
font-size: 17px;
font-weight: 800;
}
.scoreDivider {
color: rgb(245 247 240 / 40%);
}
.gameOverStats {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
}
.gameOverStat {
display: grid;
gap: 3px;
padding: 10px 6px;
border-radius: 8px;
background: rgb(255 255 255 / 7%);
}
.gameOverStatValue {
font-size: 17px;
font-weight: 800;
}
.gameOverStatLabel {
color: rgb(245 247 240 / 62%);
font-size: 11px;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.gameOverCauses {
margin: 0;
color: rgb(245 247 240 / 68%);
font-size: 12px;
}
.gameOverStory {
display: grid;
gap: 7px;
text-align: left;
}
.gameOverStory h2 {
margin: 0;
font-size: 13px;
color: rgb(245 247 240 / 80%);
text-transform: uppercase;
letter-spacing: 0.06em;
}
.gameOverStoryList {
display: grid;
gap: 2px;
max-height: 220px;
overflow-y: auto;
padding: 6px;
border-radius: 8px;
background: rgb(0 0 0 / 22%);
scrollbar-width: thin;
}
.gameOverDismiss {
justify-self: center;
padding: 10px 22px;
border: 1px solid rgb(255 255 255 / 26%);
border-radius: 8px;
background: rgb(255 255 255 / 10%);
color: #fffce9;
font-size: 13px;
font-weight: 700;
cursor: pointer;
}
.gameOverDismiss:hover {
background: rgb(255 255 255 / 18%);
}
/* ---------------------------------------------------------------- responsive */
@media (max-width: 1180px) {
.eventFeed {
width: min(262px, calc(100vw - 28px));
}
}
@media (max-width: 860px) {
.scoreboard {
top: 8px;
width: min(400px, calc(100vw - 16px));
}
.eventFeed {
top: auto;
bottom: 200px;
max-height: 32svh;
}
.agentPanel {
display: none;
}
.controls {
right: 8px;
bottom: 200px;
}
}