ART-378. Three variants, one set of betting options, one set of interaction states.
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.
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.
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.
Three variants: V1 standalone, V2 sponsored, V3 best odds. V2 and V3 are
the same card with different data; V1 is a simpler card with no bookmaker.
Τα tiles των bookmakers ζουν στον φάκελο logo-assets/rectangle/ — κάντε κλικ σε οποιοδήποτε για να το κατεβάσετε. Μόνο ο τύπος rectangle χρησιμοποιείται σε αυτό το component.
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.One component, three variants. data-variant sits on
.moddgrid for tracking and compliance — no CSS branches on it.
| 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 |
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.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. |
<!-- 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 — -->
.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.