같은 날 두 차례 플레이테스트에서 나온 이슈를 이어서 처리했다.
**의회 세부화**
- 유형 D(이득 규약) 5종 신설 — 토큰 지급/게이지 완화/지출 가산 완화/
주목도 한도 증가/실적 요구치 하향. 내부 명분("강제 상정")이 여태 불리한
유형 A만 올릴 수 있어 실속 없던 문제를 해결 — 상정 풀에 D가 포함되는 게
내부 명분이 존재하는 이유
- 13석 표결을 실제 표 수로 구현(tallyVotes, 최대잔여법 + 결정적 해시).
혼합 명분이 "직접 통과 지정" 자리표시자에서 §7.3 스펙대로 실제 1표
이동으로 교체 — 동점은 스윙 전 득표가 많던 쪽이 이겨 1표 차에서만 뒤집힘.
의회 화면에 후보별 예상 득표·표 차·뒤집기 가능 여부를 미리 노출
- 공보 축 오염 선택지 1→7개로 보강(서사 기준 6개 재배정), 축 분포 균형화
**툴팁 신설 (InfoTooltip·ProtocolChip)**
- 규약·징벌·명분을 클릭하면 정확히 무엇이 막혔는지 설명이 뜬다. 문구는
UI가 추측하지 않고 council.js의 protocolEffectDetail·justificationDetail이
카탈로그에서 생성. 모바일 대상이라 hover가 아닌 클릭으로 연다
**크리티컬 버그: 주목도 미초기화**
- 라운드 종료 후 한도 판정에 총 주목도(이월 포함)를 쓰고 있어, 2라운드가
시작하자마자 이미 한도를 넘어 버스트가 무한 반복되고 있었다. 한도 판정은
"이번 라운드에 받은 카드"만 세도록 분리(roundAttention), 게이지·토큰
가산은 기존대로 총계(이월 포함) 기준 유지
**밸런스 피드백 5건**
- 결재 카드가 고정으로 보인다는 지적 → 실제 버그였다. cardIndex를 그냥
+1씩 돌려 CSV 순서 그대로 결정론적으로 반복되고 있었다. Fisher–Yates
셔플 큐로 교체(큐 소진 시 재셔플)
- 위협 축도 거의 안 나온다 → 위 셔플 버그가 원인의 상당 부분. 명백한
오배정 1건도 발견해 수정(id11 "군사 개입 지시": 고대 신 소환 저지가
인사 축으로 잘못 들어가 있었음 → 위협 축)
- 게이지 상승이 너무 낮음 → 등급 합계(주목도) 단독 기준이 실제 카드
등급 분포(대부분 1~4급)와 맞지 않아 3~4장을 쌓아도 최하 구간을 못
벗어났다. 카드 장수를 1차 기준으로 되돌리고 등급 배율(평균등급/5)을
곱하는 방식으로 재설계 — 3~4장 구간에서 6배 점프(0.5%→3.0%)
- 좌우 모두 오염 없는 완전 무행동 카드 1건(id15) 수정 — 좌측에 대외/6급
부여(기존 tag_corruption과 정합)
- 오염 카드 한쪽만 있어 안전 선택 메리트가 없다는 지적은 카드 데이터가
아니라 게이지 곡선 문제로 판단, 위 재설계로 해결(카드 재배분 안 함)
**문서**
- 결정 노트 2건: 2026-09-17-주목도-라운드-분리,
2026-09-17-게이지상승-장수기준-복원(기각한 대안 포함)
- 기획서 §4.2-A/B, §7.3, §9.2, §17 갱신. DEVLOG 2건 기록
Playwright로 전 구간 검증: 셔플(3회 재접속 시 다른 카드, 15연속 무반복),
게이지 상승률 표시, 13석 표결 예상치, 규약/명분 툴팁, 2라운드 진입 시
주목도 0으로 리셋 확인. 콘솔 에러 0건, 빌드 클린.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
174 lines
3.3 KiB
CSS
174 lines
3.3 KiB
CSS
.desk-bar {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 6px;
|
|
padding: 10px 16px;
|
|
background: var(--color-surface);
|
|
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
|
font-family: var(--font-typewriter);
|
|
}
|
|
|
|
/* 경고/한도초과(bust) 구간을 테두리로 알린다 (§4.2-B) — bust는 실제로 라운드를 강제 종료시킨다. */
|
|
.desk-bar.zone-warning { border-bottom-color: var(--color-risk-critical); }
|
|
.desk-bar.zone-bust { border-bottom-color: var(--color-entropy-critical); }
|
|
|
|
.desk-bar-top {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 10px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.desk-total {
|
|
font-size: 13px;
|
|
}
|
|
|
|
.desk-attention {
|
|
font-weight: 700;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.zone-warning .desk-attention { color: var(--color-risk-critical); }
|
|
.zone-bust .desk-attention { color: var(--color-entropy-critical); }
|
|
|
|
.desk-surcharge { color: var(--color-risk-critical); }
|
|
.desk-tokens { opacity: 0.8; }
|
|
|
|
.desk-zone-banner {
|
|
font-size: 11px;
|
|
padding: 4px 8px;
|
|
border-radius: 4px;
|
|
background: rgba(255, 215, 0, 0.1);
|
|
color: var(--color-risk-critical);
|
|
}
|
|
|
|
.zone-bust .desk-zone-banner {
|
|
background: rgba(139, 0, 0, 0.18);
|
|
color: #ff8a80;
|
|
}
|
|
|
|
.desk-bar-actions {
|
|
display: flex;
|
|
gap: 8px;
|
|
}
|
|
|
|
.desk-guide-btn,
|
|
.desk-combine-btn {
|
|
font-family: var(--font-typewriter);
|
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
border-radius: 4px;
|
|
padding: 7px 12px;
|
|
font-weight: 700;
|
|
cursor: pointer;
|
|
white-space: nowrap;
|
|
font-size: 12px;
|
|
}
|
|
|
|
.desk-guide-btn {
|
|
background: transparent;
|
|
color: var(--color-text);
|
|
}
|
|
|
|
.desk-combine-btn {
|
|
background: var(--color-token-budget);
|
|
color: #0a0a0a;
|
|
border-color: transparent;
|
|
}
|
|
|
|
.desk-combine-btn:disabled {
|
|
background: rgba(255, 255, 255, 0.1);
|
|
color: rgba(255, 255, 255, 0.35);
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.desk-bar-rows {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 3px;
|
|
}
|
|
|
|
.desk-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
background: none;
|
|
border: none;
|
|
color: var(--color-text);
|
|
padding: 3px 4px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
text-align: left;
|
|
width: 100%;
|
|
font-family: var(--font-typewriter);
|
|
}
|
|
|
|
.desk-row:not(:disabled):hover {
|
|
background: rgba(255, 255, 255, 0.05);
|
|
}
|
|
|
|
.desk-row:disabled {
|
|
cursor: default;
|
|
opacity: 0.5;
|
|
}
|
|
|
|
.desk-row-name {
|
|
font-size: 11px;
|
|
width: 28px;
|
|
flex-shrink: 0;
|
|
opacity: 0.75;
|
|
}
|
|
|
|
/* 축별 주목도 — 이 숫자가 게이지 상승률을 결정하므로 장수보다 크게 보여야 한다.
|
|
등급 칩과 값이 같을 때 붙어 보이지 않도록 배경을 줘서 분리한다. */
|
|
.desk-row-attention {
|
|
font-size: 13px;
|
|
font-weight: 700;
|
|
min-width: 30px;
|
|
text-align: center;
|
|
flex-shrink: 0;
|
|
background: rgba(255, 255, 255, 0.1);
|
|
border-radius: 4px;
|
|
padding: 1px 4px;
|
|
}
|
|
|
|
.desk-row-chips {
|
|
display: flex;
|
|
gap: 4px;
|
|
flex: 1;
|
|
flex-wrap: wrap;
|
|
min-width: 0;
|
|
}
|
|
|
|
.desk-chip {
|
|
font-size: 11px;
|
|
background: rgba(255, 255, 255, 0.07);
|
|
padding: 1px 6px;
|
|
border-radius: 4px;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.desk-chip.more { opacity: 0.55; }
|
|
|
|
.desk-row-empty {
|
|
font-size: 11px;
|
|
opacity: 0.35;
|
|
}
|
|
|
|
.desk-row-gauge {
|
|
font-size: 11px;
|
|
opacity: 0.65;
|
|
white-space: nowrap;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.desk-row-rate {
|
|
color: var(--color-risk-critical);
|
|
opacity: 1;
|
|
}
|
|
|
|
.desk-carried {
|
|
opacity: 0.55;
|
|
font-size: 11px;
|
|
}
|