ART-378. Five variants in two families. V1 / V2 / V3 — approved and unchanged.
V4 / V5 are new, added from Figma page
«Odds CTA»,
and are for review — not signed off.
The two families are different ideas, not two sizes of one thing. V1–V3 are neutral surfaces
(light or white card) that name the bookmaker — V2/V3 by placing its tile beneath the odd.
V4–V5 are brand surfaces: the operator's colour is the whole control, and the odd shares it
with the wordmark. That is why they use the plain-light logo type rather than
rectangle, and why they carry no selection label (§3A, §3B).
V1 — standalone. No bookmaker is named: a single light 36px horizontal block,
100px wide for every selection, with the label and odd centred side by side.
For editorial / neutral contexts.
V2 — sponsored and V3 — best odds share a two-part card: a white top
block holding the selection label and the odd side by side in dark text, and beneath it the
bookmaker's rectangle logo tile at a fixed 26px height — the same height as the odds block above it. V2 repeats one operator's
tile on every card; V3 shows whichever operator has the best odd per selection, so the tiles vary.
This is what ships on
foxbet.gr/analysis.
All three carry the same markets — 1X2 · O 2.5/U 2.5 · Ακριβές σκορ on desktop, with a
G/G slide added on mobile — and the same states, so hover behaves identically in all
three. Each is shown at mobile 360px and desktop ≥1200px.
V4 — brand pill, inline. 40px tall, fluid width: odd │ hairline │ wordmark
centred in what is left. One selection per pill.
V5 — brand block, stacked. 100 × 68px fixed: odd / hairline / wordmark. Drops into a
market row the way the V2/V3 card does.
Both are shown across all 16 bookmaker assets so the fills can be checked at a glance.
UI strings are Greek exactly as they ship; the spec is English.
Editorial / neutral contexts. No tile, no responsible-gaming line. Uniform 100px cards, no flex-grow, with the label and odd centred with a 5px gap. Hover to see the tint enter from the top.
data-variant="v1"One operator sponsors the whole block, so every card carries the same tile. Same betting options as V1 — 1X2 · O 2.5/U 2.5 · Ακριβές σκορ on desktop, plus a G/G slide on mobile. Structurally identical to V3; only the data differs.
data-variant="v2"
Each selection is priced by whichever operator offers the best number, so the tile changes
card to card. This is the configuration on /analysis. Same betting options
and same markup as V2 — only the tile source and the odd differ.
New from Figma. The operator's colour is the whole surface: the odd sits at the left, a hairline, then the wordmark centred in what is left. 40px tall, fluid width — it fills whatever column it is dropped into. One selection per pill, so it stacks under a market rather than sitting in a row of siblings. Hover to see the bevel deepen; tab into it for the focus ring.
data-variant="v4" new · from Figmabo-* fill + plain-light wordmark
The last four carry .is-lt — their fill is white or yellow, so the ink flips to #1A1A1A and the wordmark switches to the plain-dark export
The same brand-fill surface turned vertical: odd on top, hairline, wordmark beneath. 100 × 68px, fixed — no flex-grow, exactly the rule V1 follows, so a 2-selection market never stretches its blocks to half the row while a 3-selection market stays narrow. This is the one that drops straight into a market row the way the V2/V3 card does.
data-variant="v5" new · from Figmabo-* fill + plain-light wordmark
1 /
O 2.5 / G/G Ναι. So the market and the selection must be named
outside the control (a caption above the row, as in the frames here), and the accessible name
has to come from title / aria-label. V2/V3 name the selection inside
the card; these two cannot. This is the one structural decision still open — see §3B.
Extending V2/V3 beyond the three markets shipped today. The card form never changes — only the
label, and therefore the card width. Decided: width is a property of the
market, and every card inside one market carries the same width. A slide is therefore
always uniform, and a desktop row only ever changes width at a .modd-div. One
market per carousel slide on mobile; on desktop, ship the markets that fit the column and
leave the rest to the carousel.
.is-w 92px · 5–8 char labels — one market per group
.is-xw 112px · 9–14 char labels — one market per group
.modd-div. That
keeps the ragged look out without forcing 1 / X / 2 up to
112px. Pick the class from the longest label in that market, then apply it to every card
in the market — never per card.26px top block + 26px
tile — whichever width step it uses. The logo sits centred at its natural size and the brand
colour fills the leftover width, so a 112px card and a 72px card have identical top and bottom
edges. This is the rule that lets widths vary at all.
All three variants share one set of interaction states. Hover / focus / pressed are
live — hover any card and tab into it. V2 and V3 hover exactly like V1: the white part
shifts to the same white → #FFEBE6 gradient with the same soft neutral shadow.
The border is never recoloured and the card is never translated. The logo tile is never
tinted — the operator's colour must stay true in every state.
.modd-card — the white part — in all three, so the
affordance is identical whether or not a tile is present. In V1 the card is the whole
component; in V2/V3 it is the top half and the shadow sits on the shell so it reads around the
tile as well.<a href> stays keyboard-activatable regardless of CSS, so the click
handler must return early for [aria-disabled="true"].
Odds CTA · Jira ART-378 · Foxbet design system. Approved — build as specified.
Ship into foxbet-responsive.html and foxbet-responsive-live.html.
V1 standalone, V2 sponsored, V3 best odds — approved, build as
specified. V2 and V3 are the same card with different data; V1 is a simpler card with no
bookmaker.
V4 brand pill and V5 brand block (§3A, §3B) are new and for review — do
not build them until they are signed off.
Δύο τύποι logo χρησιμοποιούνται, ένας ανά family: rectangle για V1/V2/V3 (logo-assets/rectangle/) και plain-light / plain-dark για τα νέα V4/V5 (logo-assets/plain-light/, logo-assets/plain-dark/). Κάντε κλικ σε οποιοδήποτε για να το κατεβάσετε.
rectangle — V2 / V3
plain-light — V4 / V5, ο default τύπος (λευκό mark πάνω στο brand fill)
plain-dark — V4 / V5 μόνο για τα light fills (.is-lt)
Every operator tile the component can render. The V2 and V3 variants
(§02) place one of these beneath the odd; V1 uses none. Only the
rectangle type is used here. Logos are exported from Figma page
«🧩 Logos» → bookmakers-logos into logo-assets/.
Click any asset name to open the SVG. Colours are listed so the .bk-* class can
be verified against the artwork.
| Operator | Tile | Asset | Class | Background |
|---|---|---|---|---|
| Stoiximan | rectangle/stoiximan.svg |
bk-stoiximan |
#0055FF | |
| bet365 | rectangle/bet365.svg |
bk-bet365 |
#005440 | |
| Fonbet | rectangle/fonbet.svg |
bk-fonbet |
#D42B28 | |
| Betsson | rectangle/betsson.svg |
bk-betsson |
#F26722 | |
| Interwetten | rectangle/interwetten.svg |
bk-interwetten |
#FFD200 | |
| Sportingbet | rectangle/sportingbet.svg |
bk-sportingbet |
#1E87C9 | |
| Vistabet | rectangle/vistabet.svg |
bk-vistabet |
#F05722 | |
| Novibet | rectangle/novibet.svg |
bk-novibet |
#303540 charcoal, not the DS teal — follow the artwork | |
| NetBet | rectangle/netbet.svg |
bk-netbet |
#333743 | |
| N1 Casino | rectangle/n1casino.svg |
bk-n1casino |
#212121 | |
| bwin | rectangle/bwin.svg |
bk-bwin |
#000000 | |
| Elabet | rectangle/elabet.svg |
bk-elabet |
#11143E → #172B89
gradient — .bk-elabet sets background directly, not --bk | |
| Pamestoixima (long) | rectangle/pamestoixima-long.svg |
bk-pamestoixima-long is-tall |
#B92128 — mark fills the tile, so it scales rather than crops (§03) | |
| Pamestoixima | rectangle/pamestoixima.svg |
modd-bk is-lt |
#FFFFFF | |
| Winmasters | rectangle/winmasters.svg |
modd-bk is-lt |
#FFFFFF | |
| Winmasters 2 | rectangle/winmasters-2.svg |
modd-bk is-lt |
#FFFFFF |
The full library — all five types per brand
(rectangle, circle-large, circle-small,
plain-dark, plain-light) — is in
logo-assets/.
This component uses rectangle only.
.is-lt.
winmasters, winmasters-2 and pamestoixima sit on a white
background, which would bleed into the white block above. .is-lt sets
--bk:#FFFFFF and insets the glyph by 2px so the border-top reads as a real
edge.type=Rectangle as SVG, strip the #EFEFEF canvas rect and the
#9747FF component-set boundary rect Figma adds to every export, drop it into
logo-assets/rectangle/, then add one line to the .bk-* block with the
colour sampled from the artwork's own background rect. The class name must match the filename
exactly: bk-stoiximan ↔ rectangle/stoiximan.svg.alt="Stoiximan") — never "logo" and never the odd value. The tile is the only thing
naming the operator, so it is not decorative.Five variants in two families. data-variant sits on the row
container for tracking and compliance — no CSS branches on it.
Neutral family (V1–V3): .modd* classes, rectangle logos, approved.
Brand family (V4–V5): .bodd* classes scoped under .bo,
plain-light logos, new and under review. The two families share no CSS — that
is deliberate, so a change to one can never move the other.
| Variant | Attribute | Card | Bookmaker tile | 21+ line | Use for |
|---|---|---|---|---|---|
| V1 Standalone | data-variant="v1" |
Single light block, 36px tall, 100px wide | None | No | Editorial / neutral odds inside analysis copy |
| V2 Sponsored | data-variant="v2" |
Two-part card — white label+odd block over the tile (§03) | The same operator on every card | Yes | Sponsored blocks tied to a single operator |
| V3 Best odds | data-variant="v3" |
The best-odds operator per selection — differs card to card | Yes | Odds comparison · this is the configuration for /analysis | |
| V4 Brand pill new | data-variant="v4" |
Brand-fill pill — 40px tall, fluid width, odd │ hairline │ wordmark (§3A) | The whole control is the operator's colour; wordmark, no tile | Yes | A single operator's price inside copy or a promo slot |
| V5 Brand block new | data-variant="v5" |
Brand-fill block — 100×68px fixed, odd / hairline / wordmark (§3B) | The whole control is the operator's colour; wordmark, no tile | Yes | A brand-forward alternative to the V2/V3 row |
/analysis, V4/V5 where a single operator is
being featured.Each selection is one link containing two stacked parts: a white top block with the selection label and the odd side by side, and beneath it the operator's rectangle logo tile.
26px at every width. Do not use aspect-ratio: a
ratio makes the tile grow taller as the card widens, which breaks the row's baseline and makes
«O 2.5» taller than «1». The logo still renders at 36px and is cropped by the band, so it keeps its size, and the
brand colour fills whatever width is left.--bk, set by a .bk-<operator> class on the tile. The class must
match the asset, or a seam appears at the logo's edge. Take the values from §01, never by
eye.| Part | Property | Value |
|---|---|---|
Shell.modd |
Width | 72px base · .is-w 92px · .is-xw 112px (§05) |
| Radius / clip | 6px all four corners + overflow:hidden — this is what rounds the tile | |
| Border | 1px #E6E6E6 Base 200 | |
| Background | #FFFFFF | |
Top block.modd-card |
Height | 26px fixed — not content-driven |
| Layout | flex-direction:row, centred, gap:5px, padding:0 6px | |
| Selection label | .modd-lbl — Roboto 10px / 600,
#1A1A1A Base 950,
no uppercase, no letter-spacing | |
| Long-label step-down | .modd-lbl.cs — Roboto 9px / 600,
letter-spacing:-.1px | |
| Odd | .od — Roboto Mono 15px / 700,
#1A1A1A,
letter-spacing:0. The odd is the hero — 1.5× the label's size. | |
Logo tile.modd-bk |
Height | height:26px; flex:0 0 26px — the same as the block above, fixed, identical at every width |
| Width | width:100% — follows the card: 72 / 92 / 112px | |
| Logo | height:36px; width:auto; object-fit:contain, centred by
display:flex; align-items:center; justify-content:center on the tile.
Deliberately taller than the band — see the crop note below. The glyph renders at the same
size whatever the card width; it does not scale with the card. | |
| Crop | overflow:hidden on the tile removes 5px top and 5px bottom
of the asset — its own brand-coloured padding, never the wordmark | |
| Fill | background:var(--bk) — continues the asset's own background across
the leftover width. Set by .bk-<operator>. | |
| Separator | border-top:1px #E6E6E6 | |
| Asset | logo-assets/rectangle/<operator>.svg |
Total card height is always 26 + 26 — two equal halves — so cards of different widths line up top and bottom. That is the rule that lets widths vary at all.
26px but the <img> is still height:36px, so the wordmark
is exactly the size it was at the taller band — the band just crops 5px off the top and bottom of
the asset. Every rectangle export centres its wordmark inside generous
brand-coloured padding, and --bk continues that same colour, so what gets cropped is
invisible. Do not "fix" this by setting the logo to height:100% — that scales
the wordmark down by 28%.interwetten and
pamestoixima at 13.3% padding versus the 13.9% needed, so ~0.2px, sub-pixel and
invisible). pamestoixima-long is the exception: its wordmark fills 87.6% of the
tile with only 1.5% padding at the top, so a crop would cut 4.5px into the glyph. It carries
.is-tall, which scales it to the 26px band instead. Any future export whose mark fills
more than ~72% of its tile needs the same class.Source of truth: Figma page
«Odds CTA» node 8328:283129.
Both new variants are the same construction in two directions, so this section specifies the
shared anatomy once and §3B covers the two layouts. The operator's colour is the entire surface;
there is no neutral card and no tile.
Two nested boxes, and both are load-bearing. They carry the same fill — the only thing separating them is the inner box's drop-shadow, which is what reads as an engraved edge. Collapse them into one box and the control goes visually flat.
| Part | Class | Geometry | Notes |
|---|---|---|---|
| Shell (the link) | .bodd |
border-radius:12px · padding:4px · gap:2px ·
overflow:hidden |
Fill = --bk. Shadow 0 2px 0 0 rgba(0,0,0,.1) — a flat, zero-blur
bevel, not a soft drop shadow. This is the outer edge. |
| Inner box | .bodd-in |
border-radius:8px · padding:4px · gap:2px |
background:inherit — takes the shell's fill, so a new operator needs exactly
one colour declared. filter:drop-shadow(0 2px 7.5px rgba(0,0,0,.4)). |
| Odd | .bodd-od |
height:24px · padding:0 12px (V4) / 0 (V5) |
Roboto Condensed Bold 16 / 24, colour --bo-ink. Not the Roboto Mono
used by V1/V2/V3 — see the note below. |
| Hairline | .bodd-sep |
Zero layout size + a 1px ::after |
rgba(255,255,255,.24) on a dark fill, rgba(26,26,26,.18) on a light
one. See the ⚠ below — this is the easiest thing to get wrong. |
| Wordmark | .bodd-bk › img |
row height:24px · mark height:10px, width:auto,
max-width:100%, object-fit:contain |
plain-light/<op>.svg — never rectangle. |
height:1px and every V5 becomes 69px and stops matching the frame — and
in a row next to a 68px sibling that 1px shows. Ship it as
.bodd-sep{flex:0 0 0;position:relative} with an absolutely-positioned
::after.plain-light, not
rectangle. A rectangle asset bakes in its own background, so dropping
one onto a brand fill draws a second box inside the control — a visible rectangle floating in
the colour. V2/V3 want that background (it is the tile); V4/V5 must not have it. The class
name still matches the filename exactly: bo-stoiximan ↔
plain-light/stoiximan.svg.One declaration per operator, on the shell. The inner box inherits it.
| Operator | Class | Fill | Wordmark | White odd vs fill |
|---|---|---|---|---|
| Stoiximan | bo-stoiximan |
#0055FF |
plain-light | 6.2:1 ✔ confirmed in Figma |
| bet365 | bo-bet365 |
#027B5B |
plain-light | 4.6:1 ✔ confirmed in Figma |
| Fonbet | bo-fonbet |
#D42B28 |
plain-light | 5.2:1 ✔ |
| Betsson | bo-betsson |
#F26722 |
plain-light | 3.0:1 ✖ see §3A·3 |
| Sportingbet | bo-sportingbet |
#1E87C9 |
plain-light | 3.3:1 ✖ see §3A·3 |
| Vistabet | bo-vistabet |
#F05722 |
plain-light | 3.4:1 ✖ see §3A·3 |
| Novibet | bo-novibet |
#303540 |
plain-light | 11.4:1 ✔ |
| NetBet | bo-netbet |
#333743 |
plain-light | 10.9:1 ✔ |
| N1 Casino | bo-n1casino |
#212121 |
plain-light | 15.3:1 ✔ |
| bwin | bo-bwin |
#000000 |
plain-light | 21:1 ✔ |
| Elabet | bo-elabet |
#11143E → #172B89
gradient — sets background directly; the inner box gets the flat mid-stop
#142169 (a gradient cannot be inherited without re-anchoring) |
plain-light | 13.9:1 ✔ |
| Pamestoixima (long) | bo-pamestoixima-long |
#B92128 |
plain-light | 6.5:1 ✔ |
| Interwetten | bo-interwetten is-lt + is-icon |
#FFD200 |
plain-dark | white is invisible → ink flips to #1A1A1A, 14.4:1 ✔ |
| Pamestoixima | bo-pamestoixima is-lt + is-icon |
#FFFFFF |
plain-dark | ink #1A1A1A, 17.4:1 ✔ |
| Winmasters | bo-winmasters is-lt |
#FFFFFF |
plain-dark | ink #1A1A1A, 17.4:1 ✔ |
| Winmasters 2 | bo-winmasters-2 is-lt |
#FFFFFF |
plain-dark | ink #1A1A1A, 17.4:1 ✔ |
.is-icon. Measured across all 16: every wordmark has an aspect ratio
between 2.7 and 10.1, but plain-dark/interwetten.svg is 1.77 and
plain-dark/pamestoixima.svg is 1.03. At the standard height:10px
those render 18px and 10px wide — an illegible speck beside a 60px wordmark.
.is-icon gives them height:20px, the row's full height.
Rule: measure the aspect ratio of any new export; below ~2.5 it is a stacked mark and takes
.is-icon. Do not eyeball this — winmasters-2 at 2.73 looks like a
monogram but is wide enough to follow the normal rule.plain-light/sportingbet.svg carries navy and orange ink rather than white, so on the
#1E87C9 fill the mark is low-contrast — visibly weaker than every other operator in the
gallery. Logos are exempt from text-contrast rules, but this one reads as broken. Either request a
true white export from the brand, or resolve it together with the §3A·3 contrast decision (option (a),
a darker fill, fixes both at once).#027B5B, not the
#005440 of its rectangle tile (§01). Both are correct — they are two different
assets in the Figma library, and the brand-fill component uses the lighter green. Do not
"unify" them. An operator can therefore carry two different greens on the same page: V3's tile
at #005440 and a V4 pill at #027B5B. If that ever appears side by side it
will read as a bug — flagged for the design call..is-ltFour operators have a fill that white ink cannot sit on. .is-lt handles
all of it in one class: --bo-ink:#1A1A1A, --bo-hair:rgba(26,26,26,.18),
and an inset 0 0 0 1px #E6E6E6 added to the bevel so the control still has an edge
against a white page. The wordmark must also be swapped to the plain-dark
export — the class cannot do that for you, it is a different file.
#FFD200 against white is 1.4:1 — a white wordmark on it is
effectively invisible, not merely low-contrast. It takes the same treatment as
winmasters / pamestoixima.#F26722 (3.0:1),
Vistabet #F05722 (3.4:1) and Sportingbet #1E87C9 (3.3:1)
fails that. The frames in this handover render exactly what Figma specifies — the design has
not been quietly altered. Two ways out, both one line:
.is-lt-style dark ink — keeps the brand colour,
changes the ink and needs the plain-dark wordmark.
The fill is the operator's colour, so hover cannot tint it. There is no
#FFEBE6 surface to shift the way V1/V2/V3 have. Affordance comes from the bevel
instead: the shell's flat shadow grows and the inner box brightens.
| State | Change | Rule |
|---|---|---|
| Hover | shell 0 3px 0 rgba(0,0,0,.14) · inner
+ brightness(1.08) | The fill is never recoloured and the wordmark is never tinted — the operator's colour must stay true, same principle as the V2/V3 tile. |
| Focus-visible | box-shadow:0 0 0 2px rgba(253,58,1,.40) |
Identical to V1/V2/V3 — the DS ring, and the only orange in any state. |
| Pressed | translateY(1px) + bevel to 0 1px 0 |
Not scale() as in V1/V2/V3: this control has a 2px bevel, so collapsing it
makes the button physically sink. Scaling a bevelled surface reads as a glitch. |
| Loading | shimmer on .bodd-od only |
A white-alpha shimmer, not the grey one — the surface is dark. The wordmark stays: the operator is already known, only the price is pending. |
| Suspended | inner grayscale(1) + opacity:.55, bevel removed |
Desaturates rather than fading, so the operator stays identifiable — same intent as V2/V3. |
hover property (set to no in the frame) whose yes
state could not be read out. The behaviour above follows the rules already agreed for V1/V2/V3 —
confirm it against the Figma hover variant before build. Same for the
Shiny effect Mobile layer (a 2px blurred white sheen on the shell): present in the
component, hidden in the frame, so it is documented here and not built.[aria-disabled="true"].Same anatomy (§3A), two flex directions. Everything below is the only difference between them.
V4 .bodd--row | V5 .bodd--col | |
|---|---|---|
| Direction | row — odd │ hairline │ wordmark | column — odd / hairline / wordmark |
| Size | height 40px, width:100% — fluid |
100 × 68px — flex:0 0 auto, fixed |
| Odd cell | flex:0 0 auto, padding:0 12px — intrinsic width |
width:100%, padding:0 |
| Logo cell | flex:1 1 auto;min-width:0 — takes the leftover |
width:100% |
| Hairline | vertical: align-self:stretch;width:0 + ::after top:0;bottom:0;width:1px |
horizontal: width:100% + ::after left:0;right:0;height:1px |
| Use for | One selection, full column width — a featured price in copy or a promo slot | A market row of 2–3 selections, like V2/V3 |
1 / O 2.5 / G/G Ναι. Consequences, all of which need a
decision:
title / aria-label, since
the only text in the control is a bare number. A screen reader otherwise announces "2.00, link".
.is-w / .is-xw steps
(§05) exist because labels have different lengths. With no label there is nothing to size for, so
100px is the single width. That is a real simplification, and the reason the ragged-row problem
§05 solves cannot occur here.
21+ · Παίξε υπεύθυνα is not
optional.No bookmaker is named, so there is no tile: one light block holding the selection and the odd. Neutral editorial contexts.
| Element | Class | Spec | Token |
|---|---|---|---|
| Grid | .moddgrid |
display:flex · align-items:stretch · gap:8px · overflow-x:auto |
— |
| Click target | .modd |
flex:0 0 auto · width:100px — fixed and uniform for every market |
— |
| Card | .modd-card |
height:36px · justify-content:center · gap:5px ·
padding:0 6px · radius 8px · overflow:hidden |
--fill / --line |
| Label | .modd-lbl inside .modd-sel |
Roboto 12px / 500 | --ink |
| Odd | .od |
Roboto Mono 14px / 700, letter-spacing:.2px |
--acc #CB2F01 |
100 − 12 padding − 5 gap − 34 odd = 49px of label room, which fits
G/G Όχι.#CB2F01, not
#FD3A01. Primary 500 on #F2F2F2 is ~3.3:1 and fails AA at 14px.
Primary 600 gives 4.76:1 and is what the design system designates for brand orange as text on
light. In V1 the odd is focal through colour, which is what lets the card hold 36px with both
texts small.All three variants carry the same betting options.
| Market | Labels | Cards | V1 width | V2/V3 width |
|---|---|---|---|---|
| 1X2 | 1 · X · 2 | 3 | 100px — uniform for every market | base 72px |
| Over / Under | O 2.5 · U 2.5 | 2 | .is-w 92px | |
| Ακριβές σκορ | 1-0 · 2-1 | 2 | base 72px | |
| G/G (mobile only) | G/G Ναι · G/G Όχι | 2 | .is-w 92px |
| Mobile <1200px | Desktop ≥1200px | |
|---|---|---|
| Layout | Scroll-snap carousel, one market per view — .modd-slide{flex:0 0 100%;scroll-snap-align:center}, grid gap:0, slide gap:6px |
Single centred row — .modd-slide{display:contents} so cards flow straight into the flex row, grid gap:6px |
| Markets | 4 slides — 1X2 · O 2.5/U 2.5 · Ακριβές σκορ · G/G | 3 markets, 7 cards + 2 dividers. G/G carries .only-m and is hidden; the row is already full. |
| Dividers | None — each market is its own slide | .modd-div — 1px #E6E6E6
between markets, margin:6px 4px, align-self:stretch |
| Affordance | .modd-swipe chevron › pinned right, 20×20,
rgba(30,42,58,.5), 2.2s modd-nudge pulse; tap advances one market;
gains .end (fades out) on the last slide |
Not rendered |
| Wrapper | .oddswrap{width:100%;position:relative} |
.oddswrap{width:fit-content;margin:0 auto} |
.modd-div.1-0 / 2-1. The market group is
labelled above the row, so the prefix is redundant. The full string goes in
title / aria-label, so nothing is lost for screen readers.O 2.5 / U 2.5, never bare O / U.8 × 100 + 7 × 8 gaps + 2 × 9 dividers = 874px.
V2/V3 (5 × 72 + 2 × 92) + 7 × 6 + 2 × 9 = 604px. Both fit the analysis column; a
narrower container scrolls horizontally rather than compressing.All three variants share one set of states, so hover behaves identically whether or not a tile is present.
| State | Hook | Visual | Behaviour & a11y |
|---|---|---|---|
| Default | — | V1 --fill card · V2/V3 white block over the tile, --line border, no shadow | — |
| Hover | :hover in @media (hover:hover) |
Internal gradient only —
linear-gradient(180deg,#FFEBE6 0%,#FFFFFF 100%)
on .modd-card, plus 0 2px 8px rgba(26,26,26,.08) (on the shell for
V2/V3). Border unchanged, no transform. The tile is never tinted. |
Hover-query guarded so touch devices never get a stuck hover |
| Focus | :focus-visible |
2px DS ring only — 0 0 0 2px rgba(253,58,1,.40). Border unchanged |
The only Primary 500 in any state |
| Pressed | :active |
scale(.97) on the whole card | — |
| Loading | .is-loading |
Shimmer over the odd only; label and tile stay readable | aria-busy="true", pointer-events:none; animation off under prefers-reduced-motion |
| Suspended | .is-susp |
Odd → —, top block to 55% opacity, dashed border on the shell, tile
greyscaled so the operator stays identifiable, hover suppressed |
aria-disabled="true" + title="Η αγορά δεν είναι διαθέσιμη". Block the click in JS |
#FFEBE6 → #FFFFFF downward, so the colour lands where the eye already is. This
matters most on V2/V3, where the white part is only 26px tall.rgb(254,166,141), about 1.6:1 against white, so it reads as a missing line;
(2) transform:translateY(-1px) — shifting by a fractional device pixel makes the
1px border anti-alias unevenly, top and bottom edges worst. Gradient plus shadow avoids both
failure modes.<a href> stays keyboard-activatable regardless of CSS, so the click handler must
return early for [aria-disabled="true"].| Use | Value | DS name | Where |
|---|---|---|---|
| Primary text · odd (V2/V3) | #1A1A1A |
Base 950 | --ink |
| Odd (V1) | #CB2F01 |
Primary 600 | --acc — AA-safe as text on light |
| Secondary text · 21+ line | #666666 |
Base 700 | --mut |
| Borders · dividers | #E6E6E6 |
Base 200 | --line |
| V1 card fill | #F2F2F2 |
Base 100 | --fill |
| Hover tint | #FFEBE6 |
Primary 50 | Gradient start |
| Focus ring | rgba(253,58,1,.40) |
Primary 500 | Focus only |
| Radius | 6px V2/V3 shell · 8px V1 card | radius default | — |
| Fonts | Roboto · Roboto Mono |
--body / --num | Label · odd |
<span class="modd-rg">21+ · ΠΑΙΞΕ ΥΠΕΥΘΥΝΑ</span>
once below the grid; 10px/600 uppercase in --mut. Required — both name an
operator.handover-footer-eeep.html. It is not duplicated inside the component.| Check | Result |
|---|---|
V2/V3 label & odd — #1A1A1A on #FFFFFF | 18.1:1 — AAA ✔ |
V2/V3 on hover, gradient top — #1A1A1A on #FFEBE6 | 15.2:1 — AAA ✔ |
V1 odd — #CB2F01 on #F2F2F2 | 4.76:1 — AA ✔ |
V1 odd on hover, gradient top — #CB2F01 on #FFEBE6 |
4.64:1 — AA ✔ (worst point of the gradient, so hover passes throughout) |
V1 label — #1A1A1A on #F2F2F2 | 15.6:1 — AAA ✔ |
21+ line — #666666 on #FFFFFF | 5.7:1 — AA ✔ |
| Hover is not colour-only | The fill changes from flat to a gradient and gains a shadow, so the state is a surface change, not a hue swap. Focus additionally carries the 2px ring |
| Operator is not colour-only | The tile carries the operator's wordmark, and the
alt names it in text. Colour alone never conveys which bookmaker it is |
| Brand wordmarks | Logos are exempt from text-contrast rules; each uses the brand's own approved colour on its own approved background |
| Reduced motion | Shimmer, card transitions and the swipe-chevron pulse are disabled
under prefers-reduced-motion |
| Link label | Every .modd needs title /
aria-label naming the selection and, for V2/V3, the operator — e.g.
«Ισοπαλία — καλύτερη απόδοση: bet365». "Best odds by X" is otherwise visual-only |
| Touch target | V2/V3 cards are 53px tall overall (26 + 26 + border) and the whole
.modd is clickable. V1 is 36px. V1 sits under the 44px guideline — consistent
with the DS's deliberate 33px mobile-button decision. Needs your confirmation. |
V4 / V5 — the brand-fill family. Full per-operator ratios are in §3A·1; the summary and the two blockers are here.
| Check | Result |
|---|---|
| Odd on dark fills — white on Stoiximan, Fonbet, bet365, Novibet, NetBet, N1, bwin, Elabet, Pamestoixima-long | 4.6:1 – 21:1 — AA ✔ |
Odd on light fills — #1A1A1A with .is-lt |
14.4:1 – 17.4:1 — AAA ✔ |
Odd on Betsson / Vistabet / Sportingbet — white on
#F26722 / #F05722 / #1E87C9 |
3.0 / 3.4 / 3.3:1 — fails AA ✖. The odd is 16px bold = 12pt, below the 18.66px-bold "large text" threshold, so it needs 4.5:1 not 3:1. Blocker — §3A·3 |
| Hover is not colour-only | The bevel grows and the surface brightens — a depth change, not a hue swap. Focus adds the same 2px ring as V1/V2/V3 |
| Selection is not named in the control | Fails 2.4.4 / 4.1.2 without help ✖. The only text is a bare number, so
title / aria-label is mandatory, not a nicety, and the market
needs a visible caption. Blocker — §3B |
| Touch target | V4 is 40px tall and full-width. V5 is 68px. Both clear the 44px guideline in at least one axis and V5 clears it outright — better than V1/V2/V3 here |
| Reduced motion | Transitions and the loading shimmer are disabled under
prefers-reduced-motion |
<!-- V2 / V3 — v2 repeats one operator, v3 varies it per selection --> <div class="oddswrap"> <div class="moddgrid" data-variant="v3"> <!-- market 1: 1X2 — base 72px, 1-char labels --> <div class="modd-slide"> <a class="modd" href="{deeplink}" target="_blank" rel="noopener" title="Ολλανδία — καλύτερη απόδοση: Stoiximan"> <span class="modd-card"> <span class="modd-lbl">1</span><span class="od">2.00</span> </span> <!-- .bk-* MUST match the src; add .is-lt for white-bg tiles --> <span class="modd-bk bk-stoiximan"> <img src="logo-assets/rectangle/stoiximan.svg" alt="Stoiximan"> </span> </a> <!-- X and 2 identical, each with its own operator tile --> </div> <span class="modd-div" aria-hidden="true"></span> <!-- market 2: O 2.5 / U 2.5 — .is-w (92px), 5-char label --> <div class="modd-slide"> <a class="modd is-w" href="{deeplink}" title="Over 2.5 — …"> <span class="modd-card"> <span class="modd-lbl">O 2.5</span><span class="od">1.85</span> </span> <span class="modd-bk bk-bet365"> … </span> </a> </div> <span class="modd-div" aria-hidden="true"></span> <!-- market 3: Ακριβές σκορ — base 72px --> <div class="modd-slide"> … </div> <!-- market 4: G/G — .is-w, mobile carousel only --> <div class="modd-slide only-m"> … </div> </div> <button class="modd-swipe" type="button" aria-label="Επόμενη αγορά">›</button> </div> <span class="modd-rg">21+ · ΠΑΙΞΕ ΥΠΕΥΘΥΝΑ</span> <!-- V1 — no tile, no 21+ line, uniform 100px cards --> <div class="moddgrid" data-variant="v1"> <a class="modd" href="{deeplink}" title="Ολλανδία"> <span class="modd-card"> <span class="modd-sel"><span class="modd-lbl">1</span></span> <span class="od">2.00</span> </span> </a> </div> <!-- loading --> <a class="modd is-loading" aria-busy="true" …> <!-- suspended --> <a class="modd is-susp" aria-disabled="true" title="Η αγορά δεν είναι διαθέσιμη" …> <!-- odd renders as — -->
V4 / V5 — the brand-fill family (§3A, §3B). Separate classes, separate scope, no shared CSS with the above.
<!-- everything lives under .bo so it cannot collide with .modd rules --> <div class="bo"> <!-- the market MUST be named outside the control — there is no label slot --> <span class="odds-mkt">Over / Under 2.5</span> <!-- your caption class --> <!-- V4 — inline pill, 40px tall, fluid width --> <div data-variant="v4"> <a class="bodd bodd--row bo-stoiximan" href="{deeplink}" target="_blank" rel="noopener" title="Over 2.5 — Stoiximan"> <span class="bodd-in"> <span class="bodd-od">1.85</span> <span class="bodd-sep" aria-hidden="true"></span> <!-- plain-light, NOT rectangle. bo-* must match the filename --> <span class="bodd-bk"> <img src="logo-assets/plain-light/stoiximan.svg" alt="Stoiximan"> </span> </span> </a> </div> <!-- V5 — stacked block, 100×68px fixed. Identical children, --col instead --> <div data-variant="v5" style="display:flex;gap:6px"> <a class="bodd bodd--col bo-bet365" href="{deeplink}" title="Over 2.5 — bet365"> <span class="bodd-in"> <span class="bodd-od">1.85</span> <span class="bodd-sep" aria-hidden="true"></span> <span class="bodd-bk"> <img src="logo-assets/plain-light/bet365.svg" alt="bet365"> </span> </span> </a> </div> <span class="modd-rg">21+ · ΠΑΙΞΕ ΥΠΕΥΘΥΝΑ</span> </div> <!-- light fills — interwetten · winmasters · winmasters-2 · pamestoixima. .is-lt flips the ink; the plain-DARK wordmark must be swapped by hand. --> <a class="bodd bodd--col bo-interwetten is-lt" …> … <img src="logo-assets/plain-dark/interwetten.svg" alt="Interwetten"> … <!-- loading --> <a class="bodd bodd--col bo-bet365 is-loading" aria-busy="true" …> <!-- suspended --> <a class="bodd bodd--col bo-bet365 is-susp" aria-disabled="true" …>
.modd → .modd-card
(.modd-lbl + .od) then .modd-bk → <img>.
The tile is the anchor's second child, a sibling of the top block — not inside it.<img src> at
logo-assets/rectangle/<operator>.svg, give it the operator name as
alt, and put the matching .bk-<operator> on the same
.modd-bk. Add .is-lt for the white-background tiles.height:26px — never aspect-ratio.
Widening a card must not make its tile taller.height:36px inside that 26px band — the overflow crop is
intentional and is what keeps the wordmark full-size. Setting it to height:100%
shrinks every logo by 28%. Add .is-tall only for assets whose mark fills more than
~72% of the tile (currently just pamestoixima-long).overflow:hidden on .modd, or the tile's square corners punch
through the 6px radius.1 X 2 1-0
2-1, .is-w 92px for O 2.5 U 2.5
G/G Ναι G/G Όχι..modd-slide; tag G/G .only-m; put a
.modd-div between markets on desktop. Verify scroll-snap and the
.modd-swipe chevron at 360px..modd-card from
the top, shadow on the shell, border untouched, no transform, tile never tinted.21+ · ΠΑΙΞΕ ΥΠΕΥΘΥΝΑ line (.modd-rg) for V2 and V3.[aria-disabled="true"].foxbet-responsive-live.html — the odds CTA
is the same in both; the only difference on the live page is the countdown versus the live
score/clock elsewhere in the banner.V4 / V5 — do not start until signed off. When they are:
.bodd → .bodd-in →
(.bodd-od + .bodd-sep + .bodd-bk → <img>).
Keep both boxes. The inner one carries the drop-shadow that reads as the engraved edge;
merging them into one flattens the control.flex:0 0 0 + absolute
::after). A real 1px makes every V5 69px instead of 68px.<img src> at
logo-assets/plain-light/<operator>.svg — never
rectangle/, which would draw a second box inside the fill — and put the matching
.bo-<operator> on the .bodd.interwetten, winmasters,
winmasters-2, pamestoixima) add .is-lt
and swap the src to plain-dark/. The class cannot change the
file for you..is-icon to the .bodd-bk of any mark whose aspect ratio is below
~2.5 — currently interwetten and pamestoixima. Measure the export;
don't judge by eye..bodd-in uses
background:inherit. Only bo-elabet needs a second declaration, because
a gradient cannot be inherited.flex:0 0 auto. V4 stays fluid with the
logo cell taking the leftover width.translateY(1px) + a collapsed bevel, not the
scale() of V1/V2/V3.21+ · ΠΑΙΞΕ ΥΠΕΥΘΥΝΑ line and name the market in a caption above the
control — neither variant has a label slot.title / aria-label: the only text inside is a bare
number.#005440 as a tile and #027B5B as a fill (§3A·1).
hover=yes variant (§3A·4).
plain-light export is not white — needs a new asset or a darker fill (§3A·1).