Component gallery

Tier one — the six parts everything else is made of. Every state, both themes. Toggle the theme at the top right.

Component 01

Odds cell

Two lines: the line at full contrast, the price a step down. Three of its states are absences and they must not look alike — an em dash for a market not offered, the word for one that has been pulled, and a struck-through but readable price for one that is stale.

+8−109MGM
Best availableRule under the price, book named. The only emphasised cell in its row.
+7.5−1086 books
ConsensusA count where a book name would go, so it cannot be read as a bettable price.
+7.5−105
Single bookInside a book column — the header carries the identity.
+7.5−104PIN
Sharp referenceHairline above the book name. Marks a benchmark, not a recommendation.
+7.5−105
Current
+8−109
Moved toward
+7−118
Moved away
Not offeredEm dash. Never blank, never N/A.
suspended
Market suspendedIn words — a different decision from not-offered.
+7.5−105
StaleReadable but struck through: the number existed and can no longer be trusted.
O 47.5−110
Total
+185CZR
Moneyline
Component 02

Metric value

Three kinds of model output that must never be mistaken for each other or for a market price. The separation is carried by format rather than colour: two decimals for a model line, a percent sign for a probability, a mandatory sign for EV. The design's fourth kind, edge, is not here — for sports it is the same number as EV, so a board showing both would print one figure under two headings.

+7.80
ProjectionTwo decimals, signed for a spread. Never coloured — a model line has no polarity.
55.43
Projection · totalUnsigned.
53.8%
Win probabilityOne decimal, always the percent sign, never a sign and never a colour.
+6.4%
Expected valueSigned, one decimal, percent. The only metric carrying weight as well as colour.
+6.4%
4% and over · 700
+2.9%
2 to 4% · 600
+1.1%
0.5 to 2% · 500
+0.2%
Inside ±0.5% · no edgeMuted rather than coloured — the model is not making a claim.
−46.2%
Negative, same ladder
+6.4%
Racing bandsThe same +6.4% reads low on a pari-mutuel card, where EV runs from −81% to +37%.
LockedA number exists and you cannot see it.
No projectionThe model has no opinion on this game. A different sentence, and a different remedy.
started
No longer actionable
Component 03

Lock

Redaction at three scales. There is no value underneath any of these — nothing is blurred or masked, the server never sent a number. The block is the width of the value it stands for, and its shape is carried by a 1px edge rather than by fill, because a faint filled bar reads as nothing at all on a phone in bad light.

Cell · restingNo affordance at rest. Thirty invitations at once is noise.
Cell · probability width
Cell · edge widthEach block is the width of its value, so the shapes differ.
Cell · rating width
Free-tier askDashed, no accent. For what an account buys rather than money.
Beside the em dashTHE ADJACENCY TO CHECK ON EVERY COLOUR CHANGE: the dash must stay clearly louder than the lock.
Component 19

Bet rating

Five discrete steps, countable at a glance in a way five stars never are. No red at any value: green and red are spoken for by value polarity, and a rating is not a polarity — a 1 is low conviction, not a loss, and a 5 that loses is still a 5.

5
4
3
2Never occurs in live data — see the packet.
1
044% of live rows. A real state, not an error.
Locked
With the wordOnly where there is room and no column to keep aligned.
Component 04

Data table shell

The chassis every board sits in. Sorting is local and resolves within a frame, so there is no pending state to design — this component accepts no loading prop by design. Every data grid needs a horizontal scroll floor, or a flexible column with a minimum wider than the space left pushes the last column out of view with no scrollbar.

Component 05

State family

Six conditions, one grammar: what is happening, when it changes, and one route to somewhere with activity. No apology, no illustration, and no retry button that reloads the same cached page. For any single league the off-season is most of the calendar, so these are core screens rather than edge cases.

Component 06

Bet row · three access states

The ranked slate's row, deduped, at 44px. The information hierarchy IS the subscription pitch, so what is present and absent in each state matters more than the styling. Anonymous has nothing to rank by, so its slate is ordered by start time and says so.

Anonymous · market only, ordered by start time

ordered by start timeodds 41s old
Matchup
Market
Best
CCST @ USDSat 13:00SpreadCCST +23.5−110DK
BRY @ STONSat 17:00TotalU 43.5−108FD
UNC @ TCUSat 11:00SpreadUNC +8−109MGM
RMU @ WAGstarted 11:00SpreadRMU +5.5no longer offered

Projection, win probability, EV and a rating on all 48 games

No projection, no rating, and therefore nothing to rank by. Presenting an unranked list under a "ranked slate" heading would be the dishonest option.

Free account · the member layout, with the scoring locked

48 betsodds 41s old
Matchup
Market
Your books
Proj
Win
EV
Rating
1CCST @ USDSat 13:00SpreadCCST +23.5−110DK+21.40
2BRY @ STONSat 17:00TotalU 43.5−108FD41.20
3UNC @ TCUSat 11:00SpreadUNC +8−109MGM+7.80
4RMU @ WAGstarted 11:00SpreadRMU +5.5no longer offered+4.80
Identical to the member layout with three cells redacted per row. The projection is the bet’s own line, so it sits in the column a member sees it in; what is missing is everything that scores it.

Member · ranked, with variants and terminal states

48 betsodds 41s old
Matchup
Market
Best
Proj
Win
EV
Rating
1CCST @ USDSat 13:00SpreadCCST +23.5−110DK+21.4057.1%+6.4%
2BRY @ STONSat 17:00TotalU 43.5−108FD41.2055.2%+5.4%
3UNC @ TCUSat 11:00SpreadUNC +8−109MGM+7.8053.8%+2.9%
4RMU @ WAGstarted 11:00SpreadRMU +5.5no longer offered+4.8052.4%+2.1%
4 of 48 shown · sorted by EV, descending
Component 07

Game row

Browse rather than recommendation, so 34px, all three markets at consensus, and nothing about what to do. The projected score column is ABSENT for anonymous rather than locked — a payload shape built by omission, seen from the component side. The last column carries an edge count before kickoff, a live score during, and a final score after.

Anonymous · market only, ordered by start time

5 gamesodds 41s old
Start
Matchup
Spread
Total
Moneyline
State
Score
11:00UNC @ TCU−7.5−110O 47.5−110+255−325scheduled
11:00RMU @ WAG−5.5−113O 39.5−110+172−225Q2 8:4114 – 10
14:00SJSU @ USC+5500−9000scheduledspread and total not posted
17:00SVS @ SCSTpostponed
FriNCST @ UVA−6.5−110O 52.5−110+185−225final17 – 31

Member · ranked, with variants and terminal states

5 gamesodds 41s old
Start
Matchup
Proj score
Spread
Total
Moneyline
State
Edges
11:00UNC @ TCU20.20 – 28.00−7.5−110O 47.5−110+255−325scheduled2 edges
11:00RMU @ WAG−5.5−113O 39.5−110+172−225Q2 8:4114 – 10
14:00SJSU @ USC10.20 – 48.20+5500−9000scheduledspread and total not posted
17:00SVS @ SCSTpostponed
FriNCST @ UVA23.10 – 29.30−6.5−110O 52.5−110+185−225final17 – 31
Component 08

Scoreboard entry

A card, not a row, phone first, every sport. One summary line chosen by a fixed priority ladder so no card is ever blank. The member and open cards differ by exactly one line, and it is the top one — the clearest demonstration in the system of what a subscription buys: not more data, but the model's opinion about the data everyone can see.

Live · memberQ2 8:41

Our position: RMU +5.5 is still live at +2.1%.

MLSpreadPts
Robert Morris+172+5.5−11310
Wagner−225−5.5−11314
Total 39.5 · −110 · −110 44s old
Live · anonymous and freeQ2 8:41

The spread has moved from −4.5 to −5.5 since open.

MLSpreadPts
Robert Morris+172+5.5−11310
Wagner−225−5.5−11314
Total 39.5 · −110 · −110 44s old
Final · closing prices keptfinal

Virginia covered as a 6.5-point favourite.

CloseSpreadPts
N.C. State+185+6.5−11017
Virginia−225−6.5−11031
Total 52.5 · went overwon 15m old
Unpriced · no market coveredfinal

Qualifying round.

Baffins Milton Rovers1
Hartley Wintney0
No market covered 20m old
Component 10

Filter and sort bar

Applied in the browser over data already loaded, so there is no loading state, no submit and no spinner. The one thing it must never do is filter invisibly: a filter derived from saved preferences gets the accent border, a clear control, and a sentence saying how much is hidden.

48 games
9 of 48 games

Two filters come from your preferences. 39 games are hidden.

0 of 48 games

Clearing the edge minimum brings back 31 games. Dropping to your other two books brings back 6.

Component 11

Prop group

Hundreds of props per game, so this is volume management before it is layout. Collapsed by default, with the header answering the only question that matters when closed: is there anything in here. A group with nothing for the model to say says 'no model' rather than showing an empty scale, and a player with no posted props stays listed — a missing player reads as a gap in coverage.

MarketLineBestProjEVRating
Rushing yardsO 84.5−112DK97.20+7.1%
Rushing attemptsO 17.5−105FD18.40+0.4%
Longest rushO 15.5−120
MarketLineBestProjEVRating
Rushing yardsO 84.5−112DK97.20
Component 15

Record block

The whole of the site's accountability — users cannot log their own bets here, so every claim the product makes is settled in this block or nowhere. The headline is computed FROM the rows rather than carried alongside them, because any figure a reader can add up will be added up. The losing months are drawn at the same weight as the winning ones, and the worst stretch is a headline figure: volunteering it is the cheapest credibility available.

Record225−204−1052.4% of 429 decided · 439 settled
Return on investment+2.30%per unit staked, flat stakes
Worst stretch−11.40%March, 39 bets · the longest run of losing weeks was five
Scope

Bets rated 4 and 5 only. Everything below 3 is excluded because we do not tell anyone to bet it.

Monthly ROI4 losing months of 12
SegmentW−L−DHitROIN
Segment A96−78−455.2%+6.81%178
Segment B61−54−353.0%+3.14%118
Segment C54−61−247.0%−5.27%117
Segment D14−11−1Not enough settled bets to draw a conclusion · 26 of 100
Segment ENo rated bets in this period

Every settled bet is listed and gradeable. Nothing is removed after the fact. Segment D is inside the total but not stated separately — fewer than 100 settled bets cannot support a rate.

Download all 439 as CSV
Component 13

Participant identity

Four fields per team, and each variant binds to exactly one of the three name fields. No variant truncates a longer field to fake a shorter one — a clipped long name and a real short name look different, and only one of them is right. The logo slot is never optional: a row whose label steps left because a file failed stops the column being a column.

UNC@TCU
Dense · table rowAbbreviation, in mono so the pair aligns down the column.
Central Conn. State
Standard · card, scoreboardShort name. Even "Central Conn. State" would break a 34px row carrying nine numbers.
South Dakota
Standard · second side
North Carolina Tar HeelsatTCU Horned Frogs
Header · page titleLong name — the one place it has room. Home and away is carried by the word "at", since order is a convention people get wrong in both directions.
Josh HooverTCU · QB
PlayerFirst and last as the feed supplies them. No initialising, no headshots.
North Carolina
Logo failed to loadThe empty slot, never a lettered circle — and the track still holds.
Component 14

Status pills

One form, two families, never filled — a filled green pill is a sportsbook's celebration device. Live is the only high-contrast pill on the site, and it is a fact about the game rather than about our data, which the freshness indicator owns separately.

scheduled
Scheduled
Q3 4:12
Live
final
Final
postponed
Postponed
won
Won
lost
Lost
push
Push
void
Void
open
Open
Component 16

Upgrade prompts

The two asks share a shape and differ in weight: neutral outline and a text dismissal for the account, accent border and a filled button for the subscription. Both name the specific thing the lock was covering rather than listing features — the reader has just told you exactly what they wanted.

Components 17 & 18

Navigation shell and page header

One shell, three access states, differing by the right-hand end only. The vertical switcher stays visible at every state because a visitor arriving from search needs to know what else is here, and a member sees no upgrade button and nothing shouting about membership. The phone menu carries the same destinations in the same order — a reduced tab set is a second navigation to maintain and a second place for a route to go missing.

League board

48 games · 9 qualifying betsodds 41s old
Sat 29 Aug

Page header — the date stepper sits here rather than in the filter bar, because changing the date is a server round trip and everything in the filter bar is not. Keeping instant and non-instant controls apart is what stops the absence of a loading state reading as a bug.

Footer — obligations and secondary routes, not a second navigation. Track record is not repeated because it sits in the header at every access state, and pricing is a section of How it works rather than a page of its own: a pricing page with one tier on it reads as a product with something missing.

Primitive

Freshness

Reports an age; never animates one. No ticking counter and no pulse. Fresh is deliberately grey rather than green — it is the state of nearly every row nearly all the time, and healthy data is not an achievement.

odds 41s old
Fresh
odds 3m old
Aging
odds 14m old
Stale
last good 18:42
Unreachable