194 lines
13 KiB
Markdown
194 lines
13 KiB
Markdown
# Game frontend CSS architecture
|
|
|
|
The game frontend preserves the rendered contract of `ref/sam`; CSS reuse is
|
|
not a reason to normalize a page's width, height, typography, texture, or
|
|
interaction states. When reuse and the reference geometry conflict, the
|
|
reference geometry wins unless an explicit Core UX policy below changes that contract.
|
|
|
|
## Layers
|
|
|
|
`app/game-frontend/src/assets/main.css` is the single global entry point. It
|
|
loads the following layers:
|
|
|
|
1. `styles/tokens.css`: exact shared font, color, and `/image/game` texture
|
|
values. These are value aliases only and must resolve to the same computed
|
|
value as the ref page.
|
|
2. `styles/game-shell.css`: the flexible shell shared by the main dashboard,
|
|
public dashboard, and chief center. Only declarations proven identical
|
|
across those screens belong here.
|
|
3. `styles/ref-shell.css`: fixed ref geometry, including the 1000px desktop /
|
|
500px mobile family used by the battle center. Its namespace stays separate
|
|
from the flexible shell so a generic responsive rule cannot override it.
|
|
4. Scoped SFC styles: page-specific grids, fixed table dimensions, selectors,
|
|
and state styling. These remain closest to the DOM contract they implement.
|
|
|
|
`styles/legacy-controls.css` is the shared control layer between tokens and the
|
|
two shell layers. It owns only control geometry and state rules that are proven
|
|
identical in the Ref Bootstrap/Lumen family. A page still owns control width,
|
|
grid placement, and any visual family that is not Bootstrap/Lumen.
|
|
|
|
The Ref-style directory pages share a second, deliberately compact control
|
|
family through `LegacySortControls.vue`. Its `.legacy-sort-*` rules own the
|
|
explicit dark select/option palette, the raised submit button, and the
|
|
focus/active states for sortable table headers. A page supplies only the
|
|
available sort keys and placement. NPC·암행부·세력도시는 Ref의 고정 방향을
|
|
유지합니다. 장수 일람은 사용자 조작 계약에 따라 로드한 snapshot 위에서
|
|
`내림차순 → 오름차순 → 해제`를 순환하고, 여러 열의 방향과 우선순위를 scoped
|
|
SFC indicator로 표시합니다. 장수 일람의 성격·특기·부상 설명은 많은 행에서
|
|
eager popup instance를 만들지 않는 `DirectoryTooltip.vue` scoped CSS가 소유하며,
|
|
mobile에서는 viewport 가장자리 8px 안의 고정 설명판으로 전환합니다. 게임 내
|
|
tooltip trigger는 hover/focus 동작과 `cursor: help`를 유지하되, tooltip이 있는 모든
|
|
텍스트에 점선 밑줄을 반복하지 않습니다. keyboard `focus-visible` outline은 별도의
|
|
접근성 상태로 유지합니다.
|
|
|
|
## Button composition
|
|
|
|
Choose the Ref visual family before choosing a semantic color. Buttons from
|
|
different historical families are not made identical merely because they have
|
|
the same label.
|
|
|
|
| Ref family | Core composition | Use |
|
|
| ---------------------------- | ------------------------------------------ | -------------------------------------------------------------------------------------- |
|
|
| Bootstrap/Lumen primary | `.legacy-button.legacy-button--primary` | commit, purchase, submit, or another affirmative mutation |
|
|
| Bootstrap/Lumen secondary | `.legacy-button.legacy-button--secondary` | reset, cancel, neutral toggle, or load-more |
|
|
| Bootstrap/Lumen danger | `.legacy-button.legacy-button--danger` | destructive action only when Ref uses `variant="danger"` |
|
|
| Bootstrap/Lumen info | `.legacy-button.legacy-button--info` | informational or edit action only when Ref uses `variant="info"` |
|
|
| `btn-sammo-base2` navigation | `.legacy-button.legacy-button--navigation` | page back/close and paired reload controls |
|
|
| Bootstrap/Lumen dark | `.legacy-button.legacy-button--dark` | dark navigation or utility control when Ref uses `btn-dark` |
|
|
| dynamic Lumen color | `.legacy-button.legacy-button--lumen` | nation or scenario color supplied through the shared face/edge/text custom properties |
|
|
| page-specific/native control | feature-namespaced scoped class | only when Ref computed geometry or interaction differs from the Bootstrap/Lumen family |
|
|
|
|
The base class supplies accessible link/button normalization and the historical
|
|
`base1` fallback used by already measured screens. The Lumen family selector
|
|
owns the `0 1px 4px` raised edge and the shared hover/active movement. Its
|
|
semantic modifiers only assign `--legacy-button-bg`, `--legacy-button-border`,
|
|
and `--legacy-button-color`; custom nation colors use the explicit
|
|
`.legacy-button--lumen` structure class and assign those same properties. New
|
|
Bootstrap/Lumen controls must add an explicit family or semantic modifier; do
|
|
not infer a mutation role from a label such as `구입` in page CSS. A disabled
|
|
control keeps its semantic color and uses the shared opacity/cursor state.
|
|
Hover and active use the Ref Lumen bottom-border movement rather than an
|
|
unrelated brightness filter.
|
|
|
|
The shared family is opt-in at each rendered control; defining the primitive
|
|
does not connect an existing `.main-menu-link`, `.game-shell__action`, or
|
|
feature button automatically. `MainNavigationLink.vue` exposes
|
|
`lumenVariant="navigation|lumen"` so top-level global and nation links can opt
|
|
in while flat popup menu items stay outside the raised family. The main page's
|
|
global menu, nation menu, desktop synchronization/reload/lobby controls, and
|
|
reserved-turn pull/push/expand row all use the same primitive. When adding a
|
|
new main-page control, inventory every desktop/mobile render site instead of
|
|
validating one representative button.
|
|
|
|
The primitive does not set a fixed `min-height`: Ref's 35.5px default height is
|
|
the result of line-height, padding, and the 4px edge, so it naturally becomes
|
|
34.5px/33.5px while the 1px/2px top margin keeps the bottom coordinate fixed.
|
|
A fixed row opts into `.legacy-button--fixed-height` and supplies only
|
|
`--legacy-button-height`; the shared layer derives the hover/active heights so
|
|
every owner keeps the same bottom-coordinate contract.
|
|
|
|
Only layout belongs in the SFC: width, grid column, the fixed height variable,
|
|
margins required by the page, and breakpoint-specific placement. Color base
|
|
variables may be supplied by the owner for dynamic nation/scenario colors, but
|
|
border construction, font weight, hover/focus/active, and disabled presentation
|
|
belong in `legacy-controls.css` when the Ref family is shared. Generic `.btn`,
|
|
`button`, or `.primary` rules must not be promoted globally.
|
|
|
|
## Class naming
|
|
|
|
- `.game-shell`, `.game-shell__header`, `.game-shell__actions`: flexible
|
|
application shell.
|
|
- `.ref-shell`, `.ref-shell__topbar`, `.ref-shell__control`: measured legacy
|
|
shell and controls.
|
|
- `.game-feedback--error`, `.ref-feedback--error`: feedback scoped to its
|
|
visual family.
|
|
- Feature-specific classes stay namespaced by their feature or component.
|
|
Generic names such as `.title`, `.error`, `.ghost`, `.stack`, and
|
|
`.layout-grid` must not be promoted from a scoped SFC merely because the same
|
|
spelling appears elsewhere.
|
|
|
|
Feature hooks stay inside their owning component. Shared presentation uses one
|
|
of the explicit shell namespaces.
|
|
|
|
## Consolidation rule
|
|
|
|
Before moving declarations out of an SFC:
|
|
|
|
1. Compare every same-named selector's declarations and semantic role.
|
|
2. Confirm the affected pages use the same layout family.
|
|
3. Record desktop and mobile `getBoundingClientRect()` and
|
|
`getComputedStyle()` values before the move.
|
|
4. Move only identical declarations; keep exceptions in the owning SFC.
|
|
5. Re-run Chromium geometry plus hover, focus, active, and disabled states.
|
|
|
|
The main page and chief center are the flexible-shell references. The battle
|
|
center is the fixed ref-shell reference. If another page has a measured ref
|
|
contract that differs from both, preserve that page's local contract rather
|
|
than forcing it into either family.
|
|
|
|
## Asset boundary
|
|
|
|
The CSS variables contain `/image/game/*` URLs but do not import or copy image
|
|
files. Caddy continues to own `/image/*`; Vite must not rewrite the image tree
|
|
as application assets.
|
|
|
|
## Game typography tiers
|
|
|
|
All profile pages share the four sizes in `assets/styles/tokens.css`, applied by
|
|
page styles and `assets/styles/typography.css`. Gateway is outside this policy.
|
|
This is an intentional Core UX decision, expanded on 2026-09-29 from the initial
|
|
2026-09-15 policy. See [the typography contract](frontend-typography.md) for the
|
|
step-down rule, measured fitting, content exceptions, and browser audit command.
|
|
|
|
| Token suffix (`--sammo-font-size-`) | Size | Shared class |
|
|
| ----------------------------------- | ---- | --------------------- |
|
|
| `title` | 24px | `sammo-text-title` |
|
|
| `emphasis` | 16px | `sammo-text-emphasis` |
|
|
| `normal` | 14px | `sammo-text-normal` |
|
|
| `small` | 12px | `sammo-text-small` |
|
|
|
|
`small`, `sub`, `sup`, and semantic log annotations move down one tier:
|
|
24 → 16 → 14 → 12 → 10px. The last size is only for subordinate text inside the
|
|
smallest tier; repeated nesting stops at 10px. Do not reintroduce scoped `small`
|
|
resets, per-page exception tokens, or implicit percentage reductions.
|
|
|
|
## Text alignment on both axes (2026-09-29)
|
|
|
|
Core intentionally centers compact UI text vertically when its cell has spare
|
|
height. Horizontal alignment remains independent: numerical values can stay
|
|
right-aligned and dates or field labels left-aligned. This policy does not change
|
|
game state, field order, font tiers, cell dimensions, or the meaning of Ref data.
|
|
|
|
| Content | Vertical alignment |
|
|
| ------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- |
|
|
| A short heading, status, button/link label, identity or scalar value | Center within its own cell when it fits |
|
|
| A short label that wraps on a narrow viewport | Center the complete label if it fits; allow natural height and preserve wrapping |
|
|
| A form label next to one input | Center against the input; if the field also has help/error text, align to the input rather than the entire help block |
|
|
| Prose, logs, notices, editor content, multi-paragraph detail, card collections | Preserve the reading start at the top |
|
|
| A table cell with text/numbers/actions | Use table-cell `vertical-align: middle`; retain explicit top alignment for narrative/detail cells |
|
|
| A column flex container | The vertical axis is `justify-content`, not `align-items` |
|
|
|
|
Choose the smallest owner of the text. For a block or grid-item cell with inline
|
|
markup, `align-content: safe center` preserves inline wrapping, ellipsis and the
|
|
existing text-align. It also leaves overflowing content at the start. Do not
|
|
turn mixed inline text/links/tooltips into separate flex items to center a label.
|
|
For an existing row flex/grid layout use its appropriate axis; centering the
|
|
whole grid is different from centering the contents of each bordered cell.
|
|
Do not globally style every `td`, `span`, `.center` or user HTML.
|
|
|
|
Avoid fixed-height line-height hacks and manual top padding to imitate centering.
|
|
Existing equal-height line boxes and native table cells need no redundant rewrite.
|
|
Keep raised-button face/edge geometry and hover/active bottom coordinates intact.
|
|
The shared legacy control uses block content alignment without changing display.
|
|
On the mobile Gateway lobby grid, center server identity, portrait, general and
|
|
action cells; the multi-line server information keeps its reading order.
|
|
|
|
For new or changed UI, record the role and both alignment axes before choosing
|
|
CSS. Review shared components plus every rendered desktop/mobile variant. Verify
|
|
in Chromium after fonts/images load: actual text bounds, cell bounds, horizontal
|
|
alignment, wrapping/ellipsis, overflow and focus/hover/active/disabled behavior.
|
|
Test maximum names, narrow layouts and content that outgrows a cell. Preserve
|
|
original screenshots and DOM/computed-style measurements. The alignment checks
|
|
in the game typography/menu/NPC/command suites and Gateway lobby suite use mocked
|
|
API data and production bundles; they are not live-server or deployment proof.
|