Appearance
Elevation — design-system rule
Elevation encodes hierarchy, not decoration. A card's shadow tells the user whether it is a grouping container or a repeating list item — so it must be consistent, token-driven, and never patched per-surface.
One line: list/feed item →
--elevation-flat· grouping panel →--elevation-raised· modal/popover →--elevation-overlay. One radius (--radius-card) for every card.
Tokens
Defined in wp-content/themes/rhinox2/src/input.css and mirrored in apps/web/src/app/tw-theme.css (the component CSS is duplicated across the WP theme and the headless app — change both). They alias the existing shadow scale, so dark mode inherits automatically via the --shadow-* dark overrides.
| Token | Value | Use for |
|---|---|---|
--elevation-flat | --shadow-none | List / feed items, generic boxes |
--elevation-raised | --shadow-rhx (one calm layered shadow) | Standalone grouping panels |
--elevation-overlay | --shadow-lg | Modals, popovers, dropdowns |
--radius-card | --radius-lg (8px) | Every card corner |
Decision test — which role is this surface?
Ask in order; stop at the first yes:
- Floats above the page and is dismissible (modal, popover, dropdown, toast)? → overlay (
--elevation-overlay). - One self-contained panel grouping related content (scorecard summary, fan polls, tournament box, "more matches", a stat block)? → raised panel (
rhx-stats-card). - One of many repeated items in a list or grid (match cards, news cards, entity rows, situation cards)? → flat item (
rhx-box). - Page chrome or a layout region (band, column wrapper, the page itself)? → none.
The hard call is raised vs flat — use the count test: one of it on the surface → raised panel; many of it → flat list item. A match card living inside a "More matches" widget is a flat item even though the widget that contains it is a raised panel.
| Role | Treatment | Canonical class |
|---|---|---|
| Floating / transient | --elevation-overlay | — (popover/modal) |
| Content panel (one) | border + --radius-card + --elevation-raised | rhx-stats-card |
| List/feed item (many) | border + --radius-card + --elevation-flat | rhx-box |
| Page / section | none | — |
The two tiers
- Flat (
rhx-box,rhx-card,rhx-panel) — border +--radius-card, no shadow. Correct for repeating items: a feed of shadowed cards reads as "card soup." Match cards in the matchcentre list, sidebar strips, home strip. - Raised (
rhx-stats-card) — border +--radius-card+--elevation-raised. For standalone informational panels: scorecard summary, tournament, more matches, player stat blocks.
Rules
- Never write a raw
box-shadowon a card shell — consume an--elevation-*token. Raw shadows are howrhx-stats-carddrifted to a bespoke0 8px 24px -12pxthat matched nothing else. - Never patch elevation/radius per-surface (
[data-surface="…"] .card {…}). If a surface needs a different tier, it's a different component, not an override. The deleted[data-surface="matchcentre"] .rhx-stats-cardpatch is the cautionary tale. - One radius. All cards use
--radius-card. No mixing 8/12/16px on adjacent cards. - Heavier shadows (
--shadow-lg/-xl) are for things that genuinely float above the page (overlays), never for inline content panels.
Documented exception
cn-news-cardusesrounded-2xl(16px) on purpose — it mirrors the brand Figma news/logo-variation card and is a deliberate distinct silhouette, not a drift. It stays flat (border only, list item). Any new exception to the one-radius rule must be added here with a reason, or it's a bug.
Principles we follow (and why this rule looks the way it does)
We don't "follow Material 3" or "follow Tailwind" — we follow the cricnepal v2026 design language, expressed in Tailwind, informed by these principles:
- Material Design — elevation + card types. Elevation = height above the page on a consistent scale; encodes importance/interactivity/transience. Card variants: outlined (border) for dense collections, elevated (shadow) for standalone emphasis, filled for low emphasis. → match cards = outlined items; panels = elevated.
- NN/g — visual hierarchy + signifiers. Guide attention with size/contrast/ spacing; a cue must signal truthfully. A resting shadow on a non-interactive tile is a false signifier; a hover-lift on a clickable card is a true one.
- Refactoring UI (by Tailwind's creators). Build hierarchy with size/weight/ colour first, not borders/shadows; use shadow for depth sparingly, on a scale; don't lean on borders when spacing/background already groups. → our subtle
--shadow-*scale +--elevation-*tiers + "never raw box-shadow". - Gestalt — common region / proximity. Items in a shared bordered region read as one group without per-item shadows. → match cards separate via border + whitespace, so the collection stays flat.
Applied as principles, not specs — the brand is deliberately flatter and more editorial than Material's shadow-heavy metaphor (near-zero shadow scale, restrained corners, no ripples/FABs).