Brand & Design Manual · The source of truth
Moral Hazard
for designers, partners & press
Moral Hazard · brand & design manual v0.4.2 · living document · July 2026
seliqui e.U. · moralhazard.stream Built on Superfluid
00Read me first

A single, binary system.

Every visual decision in this product flows from one conceit: a black-and-white world split by a 15° diagonal. Good is on one side, Bad on the other. There are no greys, no gradients, no decorative colour. What looks like depth is opacity over the contrast colour. What looks like motion is a continuous stream of value.

This manual covers the building blocks — type, logo, the angle, characters, components, colour overrides, stream visualisations — and the rules for assembling them. If you are designing for Moral Hazard, building a collaboration, or running a co-branded campaign, everything you need is here, and the materials are in the brand-kit.

01Brand essence & voice

Direct. Binary. Slightly provocative.

Moral Hazard is an experimental on-chain game, never a financial product. The voice matches: matter-of-fact, mechanical, and unembarrassed about the risks. There is no excitement to manufacture — the game is interesting on its own.

The Question · sacred

Always written exactly. The colon before "Good or Bad?" is intentional.

Do you think humans are, in general:
Good or Bad?

Claim phrase

A short tagline that sits beside the logo or as a hero line on social/print. It distils the whole mechanic into one line:

Stream. Claim. Observe.

Words we don't use

Legal posture matters. These swaps are not stylistic preferences.

AvoidSay instead
invest / investmentparticipate / participation
returns / gains / profit / earningsdistribution share / break-even progress
guaranteed(never imply certainty)
gambling / bettinggame-theoretic experiment
paying / paymenttransferring / transfer
priceasked amount
buy / purchaseclaim
financial product / instrument(never use)
cost (for streaming)streaming outflow
owner / buyer (for Good Spot)Good Spot holder
investor / participant (for Bad)Bad streamer

Always written out

02The 15° angle

One line. Everywhere.

The 15° diagonal is the brand's central conceit. It separates good from bad on every page, anchors the logo, frames the NFT artwork, becomes the chip on a button corner, rotates into a horizontal cut on mobile. Always 15°. Never approximate.

The math

tan(15°) ≈ 0.2679. For a viewport --mh-angle ramp at full height h, the horizontal offset between the top and bottom edges of the cut is h × 0.2679. The canonical clip-path used in production is:

polygon( calc(var(--split) + 50vh * 0.2679) 0%, 100% 0%, 100% 100%, calc(var(--split) - 50vh * 0.2679) 100% )

Page splits

Three split positions ship today. Same angle, different centre.

50 / 50 · Start

Landing & invite. Both characters visible.

25 / 75 · Good

Good Spot, All Spots, Voting, Admin. Content on white.

75 / 25 · Bad

Bad Streams, Profile, FAQ. Content on black.

On phone & tablet

When the viewport is too narrow for a vertical diagonal to make sense, the cut rotates to a horizontal cut at the bottom edge of a header band. Header height: 140 px (phone) / 200 px (tablet). The math doesn't change — the band's horizontal traverse is still headerHeight × 0.2679.

As a styling element

Beyond the page split, the 15° angle also appears as the chipped top-left corner on cards, buttons, and panels. Same tangent, smaller magnitude.

Chipped panel · 24px chip
Chipped panel · 36px chip
Do
15°
Always exactly 15°. Use the canonical clip-path or a multiple of the chip variant.
Don't
35°
Don't approximate the angle. 30°, 35°, 45° all break the brand.
04Colour

Black on white. White on black.

Every shade you see in production is opacity on the contrast colour. There are four base colors that define the main UI coloring. Users can override colors to individualize their interface and store their preferences permanently in their Moral Hazard Profile NFT. Everything else is alpha, computed against whichever contrast is in play.

The four base colors · default

--mh-good255, 255, 255Good side background
--mh-bad0, 0, 0Bad side background
--mh-good-contrast0, 0, 0Text on the good side
--mh-bad-contrast255, 255, 255Text on the bad side

Alpha ladder · the only allowed shades

When you need depth, hover, or hierarchy, reach into this ladder. New alpha values are not introduced ad-hoc.

.05
.10
.20
.30
.40
.50
.60
.80
1.0

UI override · user-selectable palettes

Users can override the colors. The system is unchanged — only the colour values swap. Everything continues to compose because every other colour is alpha on whichever contrast is in play. See §13 · UI override & campaigns for the full set of override and branded-campaign examples.

DefaultWhite / Black
WarmOff-white / Charcoal
IceCool pale / Deep navy
SepiaCream / Dark brown

Default black & white is the canonical look and what every external material should use wherever possible. Overrides are primarily a personal preference inside the app — but they may also appear in branded marketing. If a token launches with a partner campaign (e.g. OPx on Optimism), the announcement can swap the black for the Optimism red while keeping the system, the angle, and the characters intact. By default, though: black and white. See §13.

Semantic accents · sparingly

Only two colours sit outside the black/white system by default. They mark things that need an accent to be distinguishable from the rest of the content — never decoration, never filler.

--mh-active16, 185, 129Active streams & anything needing an accent to stand apart · "REACHED" pill · your-own position highlight. User-overridable.
--mh-warn245, 158, 11"DECAY" chip · warnings that need to read at a glance

Two further tokens exist for specific, rare signals and should be treated as exceptions, not part of the everyday palette: --mh-hot (the "HOT" heat label on a Spots card) and --mh-info (active-token dot in the sidebar). Reach for them only where that exact meaning fires.

Do
REACHED  +311%
The accent marks the break-even pill so it stands apart. The colour is a chosen accent for distinguishability — not a signal of profit. It could just as well be blue (and is, if the user overrides it).
Don't
$5,500.00
Don't tint numbers green to imply gain. The accent means "active / needs to stand apart" — never "profit".
Do
SURFACE · 10% ALPHA
Surfaces from the alpha ladder. The page colour shows through.
Don't
GRADIENT
No gradients. No literal grey hex. No "subtle" off-brand tint.
05Typography

Encode Sans. Four weights. No exceptions.

One typeface across the whole system. Light for body, semibold for labels and toggles, bold for headings and numerals that need to anchor. No serif companion, no monospace face, no decorative caps. The mono in event logs and addresses uses the platform's ui-monospace stack — never bundled. Get the family from Encode Sans on Google Fonts ↗.

Weights

Light · 300The Good Spot for fDAIx
Regular · 400The Good Spot for fDAIx
Semibold · 600The Good Spot for fDAIx
Bold · 700The Good Spot for fDAIx

Type scale

TokenSizeUsed for
--fs-4xl88 px"Do you think humans are…" hero
--fs-3xl64 pxLanding hero
--fs-2xl44 pxPage H1
--fs-xl32 pxPage subtitles, hero stats
--fs-lg22 pxSmall headings, big numbers
--fs-md18 pxLead paragraphs, FAQ answers
--fs-base16 pxBody
--fs-sm14 pxBody small · default reading floor
--fs-xs12 pxCaptions, breadcrumbs
--fs-2xs11 pxUppercase labels, chip text

Smallest body size is 14 px. Labels and toggles may still use 11 px intentionally — they are short, all-caps, tracked at 0.12em.

Headings

One holder.
Every stream
flowing in.

Labels

Asked amount · transfer to claim

Body

Claim the spot by transferring the asked amount. Every active stream redirects into your wallet until someone takes it from you. The asked amount ticks up 1% per claim and decays after inactivity.

Numeric

Asked
1.0426
Total flow rate
1 100.00
Do
Take the good spot
Encode Sans, the only sanctioned family.
Don't
Take the Good Spot
Don't substitute. Inter, Roboto, Helvetica — all forbidden.
Do
Active streamers
Labels are uppercase, 11 px, tracked at 0.12em.
Don't
Active streamers
No italic, no decorative casing, no script weights. (No cursive anywhere — the only exception is a direct quote.)
06Characters

Two sides. Two genders. Four files.

The characters are not mascots and they are not flat silhouettes either. They are black-and-white illustrative portraits with real facial detail, hair, clothing, accessories — designed to read clearly even when reduced to a single contrast colour. The good character is open and confident; the bad character is cool, deadpan, sunglasses on and thumbs-up. Always positioned on the side opposite to the content.

The four variants

Good · Guy
Good · Gal
Bad · Guy
Bad · Gal

Placement & direction rules

Character sets & variants

The four-character grid above is the default set. Additional sets exist (and more can be commissioned) — a robot/android set, a couch set, a fighter set, animal sets, and so on. Every set keeps the same rules: two sides, two genders, shared posture for the good pair, a shared “thing” for the bad pair, two colours only.

Animals · Good Guy
Animals · Good Gal
Animals · Bad Guy
Animals · Bad Gal
Robots · Good Guy
Robots · Good Gal
Robots · Bad Guy
Robots · Bad Gal
Fighters · Good Guy
Fighters · Good Gal
Fighters · Bad Guy
Fighters · Bad Gal
Couches · Good Guy
Couches · Good Gal
Couches · Bad Guy
Couches · Bad Gal

Each set ships as four files (good-guy, good-gal, bad-guy, bad-gal) plus a switch icon — all two-colour and following the rules below.

Commissioning a new set · the ruleset

New character sets need to follow these non-negotiable rules:

Sizes

ContextSymbol height
Desktop full-page650 px (default)
Tablet header band (200 px)190 px
Phone header band (140 px)133 px
Inline avatar (e.g. profile card)36–48 px
Do
Good guy on the black side, vertically centred and fully in frame. If it must be cropped, trim the left edge it faces away from — never top & bottom.
Don't
Don't anchor to the bottom so the head is cut. Keep the figure vertically centred; trim top and bottom equally if needed.
Do
Bad character on white. Never cut on the left edge — that's the side it faces.
Don't
Don't flip horizontally or mirror. The figures face inward by design — good toward the right, bad toward the left.
07Iconography

Bespoke. Binary. No emoji.

The icon set is part of the brand. No icon font, no Lucide, no Heroicons. Every icon is drawn in the same vocabulary as the rest of the system: hard corners, no strokes thinner than 1.5 px, theme-adaptive via mask-image.

Emoji & decorative glyphs

Forbidden. No emoji in product copy, marketing copy, or social posts. No unicode glyphs as decoration. The only sanctioned glyphs in body text are the directional arrows and the status dot (used for active-stream / connection indicators).

Invite-code critters

Invite codes are represented by a sequence of animal icons (e.g. bird · cat · dog · duck) — easier to remember and share than an alphanumeric code. These are UICONS by Flaticon (flaticon.com/uicons), not bespoke art — a curated subset chosen to sit alongside the rest of the icon language: hard, simple, legible at small sizes. Because they are a third-party set, they fall under Flaticon's licence terms and are not redistributed in the brand-kit; link to the source instead.

BIRD-CAT-DOG-DUCK

Roster: a curated set of UICONS animals (bird, cat, dog, duck, frog, mouse, snail, squirrel, and more). The exact subset is defined in code; it can grow as the invite space needs it.

Drawing new icons

Do
Go to voting → ← Back to good ↑ ↓ ● active
Literal arrow glyphs only.
Don't
Take the good spot 🎉
No emoji. Anywhere.
08Active streams

Subtle. Peripheral. Continuous.

The streaming feeling is a defining characteristic of the product — money is in motion at all times. The visualisation has to convince of that without becoming attention-grabbing. Three subtle indicators do all the work.

The three indicators

1 · Flow shimmer

A 200%-wide gradient passes across an actively-streaming value once every 2 seconds. Opacity stays at 0.06–0.08 — barely visible, but unmistakable when the eye catches it.

1 100.00

2 · Active dot

A 6 px emerald dot beside the value, slow-ticking between 1.0 and 0.35 opacity every 1.8 seconds. At most one per cluster of streaming values.

1 100.00
One dot per cluster — never multiple ticking dots on screen at once.

3 · Animated balance ticking

For values that actually grow (a streamer's accumulated balance), interpolate the digits between server polls. RAF-driven at ~100 ms cadence, polling every 5 s. The number counts up smoothly. Tabular figures keep the layout from jittering.

When to use them

ValueShimmerDotTicking
Total flow rate (per game)✓ (one for the cluster)
Your stream's flow rate
Your accumulated received
Total streamers count
Asked amount (changes only on claim)
Do
1 100.00
One dot + subtle shimmer = "this is moving".
Don't
▲ 1 100.00
No coloured glow, no arrows, no "gain"-style framing. Streams aren't gains.

Flow & distribution lines

The inbound flow lines and outbound distribution lines that literally connect each streamer to the good spot are animated stream visualisations — their encoding rules and a live example now live in §11 Animation.

09Components

Hairlines, not shadows.

Every container in the system is bounded by a 1 px hairline at 10–20% opacity. No drop shadows. No glow. The two exceptions: the emerald pulse on a successful action, and the flow shimmer on a streaming number.

Buttons

Pills

NEUTRAL REACHED HOT DECAY INFO OUTLINE

Stats

Asked amount
1.0426 fDAIx
min next claim · 1.0530 (+1%)
Total flow rate
1 100.00
/ month · 2 streamers

Cards

DECAY · −0.8% / 8d
Asked amount
1.0426

Holder reached break-even on day 4. Claim now and every active stream redirects to your wallet.

Labels & toggles

Sort by

Break-even bar

Two states. Below 100%: a neutral grey fill on the alpha-ladder track, the percent shown as a label — no pill. At or above 100%: the bar fills with --mh-active and a single REACHED  +N% pill sits on the right, carrying the overshoot percent inside it. There is never a "reached" pill while the bar is still filling.

Break-even · 0x12…A4 · in progress
62%
Break-even · 0xBA…9D8A · reached
REACHED  +311%
10Motion

Linear. Or cubic-bezier(0.4, 0, 0.2, 1).

No bounce. No spring. No overshoot. Motion is functional — page transitions, hover fades, stream shimmers. Anything that draws the eye without communicating state change is forbidden.

Durations

TokenmsUsed for
--dur-fast150Hover opacity, simple state swaps
--dur-base300Color, transform
--dur-page700Layout-shell diagonal slide
--dur-shimmer2000Flow-shimmer cycle

Easing

cubic-bezier(0.4, 0, 0.2, 1) for everything UI. Linear for the shimmer and the dot tick. No ease-out-back, ease-out-cubic, or spring-based curves.

Hover / press

Slow reveal · headlines

Large page headlines fade and rise in on first paint — a slow, single reveal (opacity 0→1, a few pixels of upward travel), gated so it plays once when the content becomes active. Never loop it, never apply it to body text or numbers. On print, PDF export, and prefers-reduced-motion the end-state shows immediately. Easing cubic-bezier(0.4, 0, 0.2, 1), ~500–700 ms.

Page transitions

The 700 ms diagonal slide between /good, /bad, and the landing is the brand. Don't replace it with a fade or a slide. Don't shorten it.

11Animation

Loops, swipes, pulses — never decoration.

Every animation earns its place by communicating something: a continuous stream of value, a state change carried along the 15° angle, or the one next step a user should take. Animations are generally infinite loops — streams read as continuous moving strokes, distributions as lines that build up fully and disappear again. Opacity and stroke-dash are the only animated properties — never hue, never scale-bounce.

The logo's own idle loop lives with the mark in §03; the functional UI-motion tokens (durations, easing, hover/press, page transitions) are in §10.

Content swipe · the 15° angle

Swapping the content of a panel in place — like the /bad story ↔ dashboard toggle — never cross-fades. The outgoing content is wiped away along the brand's 15° diagonal and the incoming content is revealed behind it, so the signature angle carries every state change. Component: <AngledSwap>, ~700 ms, cubic-bezier(0.4, 0, 0.2, 1), keyed on the content id so it fires on an actual swap — not on every re-render.

DASHBOARD
STORY

The wipe edge is parallel to the page split — 15° off vertical. Same direction every time; never animate hue or scale. Reference: <AngledSwap> on /good & /bad.

Next-step pulse

When a flow has one obvious next action — Take it after an Approve confirms, Connect to Pool after a stream opens, Claim Deposit once it unlocks — that single control pulses to pull the eye to it. A faint ring pings outward while the button's opacity breathes between 1 and 0.7. Only ever one element pulses at a time; it stops the moment it's clicked or is no longer the next step. Never pulse a destructive action.

1 · Approve 2 · Take it

Flow & distribution lines

On the game pages the streams are drawn literally: lines connecting each bad streamer to the good spot. Two directions, encoded differently:

YOU GOOD SPOT ▶ FLOW IN ◀ DISTRIBUTION OUT

Reference implementation: the /good and /bad page stream visualisations. Mirror their thickness mapping, per-line speed jitter, and the --mh-active treatment for the viewer's own stream. See also §09.

12NFT media

Three NFTs. One system.

Every NFT is a server-rendered SVG that queries the live contract for current stats. They share one system: the same diagonal background, the same logo and "powered by" marks, the same character treatment. The forms stay put; the colours flip by side. The holder's chosen characters, gender, side and colour overrides carry through — good/bad spot NFTs use the holder's characters, the ProfileNFT reflects the user's own settings.

The three NFTs

Good Spot NFT example
GoodSpot NFT · ERC-721
Transferable. Exactly one per game. Transferring redirects every incoming stream to the new holder. Shows the holder's good character.
Bad Spot NFT example
BadSpot NFT · ERC-5192 soulbound
Minted on stream open, burned on close. Shows the streamer's bad character. Soulbound while the stream is active.
Profile NFT example
Profile NFT · ERC-5192 soulbound
User-mintable. Stores the four colour overrides, character gender + side, notification prefs, acknowledged-warnings flags. Reflects the user's own settings.
13Don'ts gallery

A short list of forbidden moves.

Each of these has appeared in concept work or pitches. None of them ship.

Don't
Gradient hero
Gradients, rounded corners, multi-colour. None of these are Moral Hazard.
Don't
+412.4% 🚀
Your gains today
No "gains" framing. No emoji. No financial-product copy.
Don't
Moral Hazard
Wrong typeface. Encode Sans only.
Don't
SOFT GLOW CARD
No drop shadows. No glow. No rounded corners past 8 px.
Don't
Frosted glass
1.0426
No backdrop blur. The system is opaque blocks of colour, never frosted.
Don't
Moral Hazard
— the human nature game ™
No italic, no "tm/sm" decoration, no marketing puffery in the wordmark.
14UI override & campaigns

Same system. Swapped paint.

The whole product is built so the four base colours and the character set can be swapped without anything breaking. That powers two things: a personal UI override (a user theming their own app), and a branded campaign (a partner integration that temporarily dresses the UI in their colours and characters). The rules below keep both on-system.

What can be overridden

Override examples

DefaultWhite / Black — the canonical look
Optimism campaignWhite / OP red — branded launch of OPx
Polygon campaignWhite / Polygon purple
Warm (personal)Off-white / Charcoal

Branded campaign · live demo

A campaign keeps the diagonal, the characters, and every layout rule — it just swaps the bad-side colour for the partner's. Here the same "you are one of N" hero, rendered default vs. an Optimism-red campaign:

BAD STREAMS · fDAIx
You are one
of 12.
DEFAULT · BLACK
BAD STREAMS · OPx
You are one
of 12.
CAMPAIGN · OPTIMISM RED

Note the accent: when the bad side becomes red, an accent that would clash (like a red "HOT") gets re-picked; --mh-active stays distinct. Always sanity-check accent legibility against the overridden base before shipping a campaign.

Rules for collaborators

15Brand-kit manifest

What ships in the .zip

A deliberately public-safe set of files for other projects, partners, and press — only material we own and can legally redistribute. It does not ship third-party assets (token icons, chain logos, the UICONS animals, the font binaries); those are linked to their sources instead. One folder and this design manual at the root.

Download the MoralHazard-BrandKit.zip

brand-kit/

design-manual.html · this document for offline usage logo/ logo-symbol.svg · static circular symbol logo-symbol.png · 512px raster fallback logo-symbol-animated.svg · idle / buildup animation logo-symbol-merged.svg · flattened path — for cutting/printing logo-wordmark-lockup.svg · wordmark + symbol (both sides) logo-wordmark-only.svg · wordmark, no symbol logo-stacked.svg · rare vertical lockup (text below) characters/ default/ robot/ … · each set: good-guy, good-gal, bad-guy, bad-gal (+ gender-switch) prompt-template.txt · ruleset to commission a new set reference-grid-2x2.jpg · canonical posture reference 3d/ · 3D / render-ready character material *.glb · for video, AR, hero renders nft/ GoodSpotNFT-template.svg · layout template, placeholder data BadSpotNFT-template.svg · layout template, placeholder data ProfileNFT-template.svg · layout template, placeholder data backgrounds/ diagonal-50-50.svg · 50/50 split · 16:9 + 9:16 + 1:1 diagonal-25-75.svg · good-page split · same ratios diagonal-75-25.svg · bad-page split · same ratios

Deliberately excluded (for licensing / legal reasons): token icons, logos from other companies/projects, the UICONS invite animals, and the font binaries.

Encode Sans font via Google Fonts Superfluid Brand kit UICONS by Flaticon

Get in touch

Something to
discuss in person?

Planning a collaboration, a co-branded campaign, or have a question this manual doesn't answer?

Get in touch