ART-378 · Odds CTA · V1 standalone / V6 bare / V7 with selection

Design → Dev Handover

Odds CTA · Jira ART-378 · Foxbet design system. Three variants ship: V1 standalone (neutral, no bookmaker), and the brand-fill pair V6 bare and V7 with selection, each of those in a desktop and a mobile form. Approved — build as specified. Ship into foxbet-responsive.html and foxbet-responsive-live.html.

01The buttons

Four variants. V1 standalone is the neutral card — no bookmaker, label and odd either side of a hairline; V8 is that card with the operator's icon added as a third cell. V6 bare is logo + odd and V7 adds the selection inside the chip with a rule between; those two are brand-fill, and each has a desktop and a stacked mobile form (same markup, plus .bodd--m). Everything below this is reference.

V1 · desktop · three markets, .modd-div between them
the width hugs the label · 88.67px is a floor, not a cap
V1 states · hover the second, tab to the third
12.00 Default 12.00 Hover — forced here; the real one is :hover. The tint enters from the top 12.00 Focus — forced; the real one is :focus-visible. The only orange in any state 12.00 Loading — .is-loading, the odd shimmers 12.00 Suspended — .is-susp, dashed border
V8 · .modd--bk · mark | selection | odd · derived, no node
V8 · the width still hugs · floor 88.67 + 55px
V8 · all 16 operators — the mark carries its own background, so none needs a token
197 × 48 · best odds per selection
V6 mobile · 101 × 81 · .bodd--m · derived, no node
States · Figma 11252:107363 · hover the middle one, tab to the third
Stoiximan3.12 Default Stoiximan3.12 Hover — forced here; the real one is :hover Stoiximan3.12 Focus — forced; the real one is :focus-visible Stoiximan3.12 Disable — .is-susp
V7 desktop · Figma 11309:72 · 225 × 48
V7 mobile · Figma 11313:371 · 101 × 81 · .bodd--m

Assets που χρησιμοποιούνται

Δύο τύποι logo χρησιμοποιούνται, ένας ανά family: rectangle — πλέον αχρησιμοποίητο στα CTA (logo-assets/rectangle/) και plain-light / plain-dark για V2/V3/V4/V5 (logo-assets/plain-light/, logo-assets/plain-dark/). Κάντε κλικ σε οποιοδήποτε για να το κατεβάσετε.

rectangle — αχρησιμοποίητο από v4.1 (αρχείο)

plain-light — V4 / V5, ο default τύπος (λευκό mark πάνω στο brand fill)

plain-dark — V4 / V5 μόνο για τα light fills (.is-lt)

02Bookmaker logo assets

Every operator tile the component can render. The V2 and V3 variants (§02) place one of these beneath the odd; V1 uses none. Since v4.1 they use the plain-light / plain-dark type, not rectangle. 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.

OperatorTileAssetClassBackground
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.

White tiles need .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.
Adding an operator: export 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-stoiximanrectangle/stoiximan.svg.
Alt text is the operator name only (alt="Stoiximan") — never "logo" and never the odd value. The tile is the only thing naming the operator, so it is not decorative.

03Variant map

Two variants ship, each in a desktop and a mobile form. Both are brand-fill pills built on the same shell, so the gradient, the ledge, the operator colours and all four states are defined once and inherited.

VariantClassDesktopMobileSource
V1 — standalone
selection | odd, no bookmaker
.modd.modd-card
neutral family
hugs from 88.67 × 41 same card, carousel per market Figma 10001:631
V8 — V1 with bookmaker
mark | selection | odd
.modd.modd--bk
modifier on V1
hugs from 143.67 × 41 same card, carousel per market no node — derived
V6 — bare
logo + odd
.bodd.bodd--pill
mobile adds .bodd--m
197 × 48 101 × 81 stacked Figma 21016:61050
mobile derived — no node
V7 — with selection
logo + selection | odd
.bodd.bodd--pill.bodd--sel
mobile adds .bodd--m
225 × 48 101 × 81 stacked Figma 11309:72 / 11313:371
V2–V5 are not in this handover. The two-part tile card (V2/V3) and the earlier brand-fill forms (V4/V5) are not specified here and their CSS is not present — leaving rules for variants the document does not describe is how a dev ends up lifting a class with no spec behind it. If one is needed again, restore it from version control rather than re-deriving it. V1 was restored on 2026-07-31 after being dropped with them; its rules came back verbatim from the pre-strip file, so they are the ones signed off on 2026-07-30.

04Spec — V1 standalone

No bookmaker is named, so there is no tile: one white card holding the selection and the odd, split by a hairline. Neutral editorial contexts. Replaced 2026-07-30 from Figma «Odds CTA» 10001:631.

ElementClassSpecToken
Grid.moddgrid display:flex · align-items:stretch · gap:8px · overflow-x:auto
Click target.modd flex:0 0 auto · width:auto · min-width:88.67px — the width hugs the label; 88.67 is a floor, not a cap
Card.modd-card height:41px · justify-content:center · padding:0 6px · radius 8px · box-shadow:0 0 10px rgba(0,0,0,.1) white / --line
Hairline.modd-sel::after 1 × 17px pseudo-element between label and odd — this, not colour, is what separates them. Suppressed by .is-bare. --line
Label.modd-lbl inside .modd-sel Roboto 14px / 400 — regular (min-width:24px) --ink
Odd.od Roboto 14px / 700 — bold (min-width:46px), letter-spacing:0 --ink
Weight is what distinguishes the two texts. Label and odd are the same family, the same 14px and the same --ink, so if both were bold the card read as one undifferentiated string. The label is regular 400 and the odd bold 700: the odd is the hero, the label is its caption, and the hairline separates them. Changed 2026-07-30 — both were previously bold 700. V2/V3 are untouched; their own hierarchy comes from size (10/600 label vs 15/700 odd) inside a 26px block.
88.67px and the 24 / 46px slots are floors, not caps. The Figma frame only ever shows «1», so reading its label and odd slots as fixed silently drops O 2.5 / G/G Όχι / Γκολ 2-3, which V1 has always carried. Multi-market support stays; .is-w / .is-xw are neutralised on V1 because the card sizes itself.
Build the card at 39px, not 41. Figma's stroke sits inside the frame, so 1 + 39 + 1 is the 41px frame — building it at 41 renders 43. (In this handover the border sits on .modd-card itself, so here the declared value is 41.)
The odd is no longer Roboto Mono and no longer --acc orange. Confirmed, not an oversight: odds lose tabular alignment across a row, and V1 loses its only brand accent — in exchange contrast goes 4.76:1 → 18.1:1. --acc is unused by this component. Retired with it: uniform 100 × 36px, #F2F2F2 fill, radius 6, no hairline, label Roboto 12/500, odd Roboto Mono 14/700 #CB2F01. Do not reintroduce.

05Spec — V8, V1 with bookmaker

V1 plus a bookmaker icon, inside the same pill: mark | selection | odd, three cells split by two hairlines. Use it where the price is attributable to one operator but a brand-coloured control would be too loud. Built as a modifier on V1.modd--bk adds the icon cell and nothing else, so the card, the type, the states and the loading and suspended treatments are V1's.

ElementClassSpecToken
Click target.modd.modd--bk min-width:calc(88.67px + 55px) — V1's floor plus the mark block (48 mark + 4 gap + 1 hairline + 2 card gap). Still a floor: the width hugs.
Card.modd-card inherited from V1 — height:41px, radius 8px, white, 1px var(--line), justify-content:center white / --line
Bookmaker mark.modd-ic > img 48 × 24, radius 4px, object-fit:contain. Asset is logo-assets/rectangle/<operator>.svg — the 2:1 cut, which carries its own solid brand background. Not circle-large: at 24px tall a circle is a 24px disc and the wordmark in it cannot be read. the asset's own
Hairline 1.modd-ic::after 1 × 17px, margin-left:4px — between mark and selection --line
Hairline 2.modd-sel::after 1 × 17px — V1's, between selection and odd. Unchanged. --line
Selection.modd-lbl Roboto 14 / 400 — V1's, unchanged--ink
Odd.od Roboto 14 / 700 — V1's, unchanged--ink
Suspended.modd--bk.is-susp .modd-ic img grayscale(1) + opacity:.7 on top of V1's faded dashed card
Safe for all 16 operators, Sportingbet included. The operator's colour is contained inside its own circle, so no text ever sits on a brand fill — which is exactly the failure that blocks Sportingbet's #1E87C9 in V4/V5. V8 needs no --bk token and no is-lt light-fill flag, and adding an operator is dropping in one SVG.
No Figma node backs this variant. The 48 × 24 mark was sized against the 14px type and the 41px card — it started as a 24px circle and became the 2:1 rectangle because the circle's wordmark was unreadable at that height — and the width floor is arithmetic, not a measurement. Both are ours — correct them against a node when one exists, and do not cite them as design-approved geometry.
.modd--bk, not .modd-bk. The single-dash name was V3's brand band beneath the card, which has been deleted. The double dash marks a variant modifier here, the same as .bodd--pill / .bodd--sel / .bodd--m.
It is still V1 underneath. Do not re-declare the card, the type, the hover tint, the focus ring or the shimmer for this variant — they are inherited on purpose, so a change to the neutral card must reach V8 for free. The only V8-specific rules are the four in the block above.

06Spec — V6 / V7 new

Figma 21016:61050 (V6), 11309:72 and 11313:371 (V7 desktop / mobile). Both are brand-fill pills on one shell, so the gradient, ledge, operator colours and states are defined once.

PartSpec — measured on 21016:61050
Shell
.bodd.bodd--pill
Box197 × 48padding:8px, gap:8px, border-radius:12px, overflow:hidden.
The selected instance is 197; the component's own default is 193. 197 is what ships.
FillLeft-to-right gradient, operator 500 → 950. Figma gives the Stoiximan pair #0055FF#00143D.
Ledgebox-shadow:0 2px 0 rgba(0,0,0,.1) — Figma token 3D effect: a hard 2px step, no blur.
WidthFixed, not fluid — the odds chip absorbs the remainder via flex:1, so three fit a 874px row without stacking.
Logo
.bodd-bk
Box32px tall with padding:0 16px — the 96px frame in Figma is 64px of artwork plus that padding.
Artwork64 × 32 max, object-fit:contain. Figma sizes it by width (a wide wordmark lands ~9.5px tall). The max-height is ours: a stacked mark such as interwetten would otherwise overflow the box. Asset plain-light, or plain-dark on a light fill.
Odds chip
.bodd-in
Boxflex:1, align-self:stretch, padding:8px 4px, border-radius:8px, background:rgba(255,255,255,.1), border:1px solid rgba(255,255,255,.1), drop-shadow(4px 4px 10px rgba(0,0,0,.1)) — Figma Box-Shadow/Regular (offset 4,4, Figma radius 20 = 10px CSS blur).
OddRoboto 14px / 700, #FFFFFF Common-Text/Title-text — Dark, centred, line-height:normal, letter-spacing:0. Figma style Mobile Texts / Text small / Bold.
HairlineNone. .bodd-sep is hidden — this design separates the two halves with the chip's own edge, not a rule.
V7 — «Provider Odds»Spec — Figma 11309:70
Desktop
.bodd--pill.bodd--sel
225 × 48 (node 11309:72, wrapper 49 incl. the ledge). The chip holds selection | 1px rule | odd, both halves flex:1 and centred, chip gap:4px, padding:8px 4px.
V6 mobile
.bodd--pill.bodd--m
101 × 81, the same shell as V7 mobile with the selection removed — chip 85 × 27 holding only the odd, centred, logo beneath, gap 6. No Figma node covers a bare mobile form (11313:371 is the with-selection one), so this is derived by analogy and should be corrected against a node when one exists.
Mobile
+ .bodd--m
101 × 81 (node 11313:371, which supersedes 11309:73's 89) — stacked, chip ON TOP: 8 + 27 (chip) + 6 (gap) + 32 (logo) + 8. Chip gap:2px, padding:6px 2px, height 27, text steps down to 12px, and the selection becomes a fixed 32px. Same markup — order swaps the two children, so nothing is re-rendered at a breakpoint.
Both textsRoboto BOLD — 14px desktop, 12px mobile, white (Common-Text/Title-text — Dark), centred. The selection is bold, same size as the odd; the rule carries the separation, not a weight contrast.
The rule
.bodd-sep
1px, drawn from --bo-hair so it flips under is-lt, spanning the chip's content box. Figma draws it as a rotated line at 100cqh; align-self:stretch is the same result without a container query.
StateWhat changes
DefaultGradient operator 500 → 950 left to right, box-shadow:0 2px 0 rgba(0,0,0,.1) (token 3D effect).
Hover
:hover
Gradient 700 → 950 — the light stop moves, the dark stop and the ledge stay. Wrapped in @media (hover:hover) so it cannot stick on touch.
Uses the operator's declared --bk7 where there is one, else color-mix(in srgb, var(--bk) 60%, #000). 60% is exact for Stoiximan (#0055FF#003399) but not universal: elabet's pair (#1367FF#172B89) is not 60%, which is why the token exists.
Focus
:focus-visible
The ledge is replaced by box-shadow:0 0 0 2px rgba(253,58,1,.4) (11252:107363, token Box-Shadow/Focus State Effect). No new rule: the family's .bo .bodd:focus-visible already declares exactly this and outranks the ledge.
Disabled
.is-susp
opacity:.5 and no ledge. The chip and logo are not greyed — the family greys them for V4/V5, so that is neutralised here. Pair with aria-disabled="true".
NoteHover was briefly implemented as opacity:.8, from the «50% Disabled 80% Hover» note on 11309:70. It is back to the gradient model (Vasilis, 2026-07-31); disabled stays at 50% opacity, which that note also specified.
Watch out for —
· Wrap in .bo. Every brand rule is .bo .bodd… and the operator colours are .bo .bo-<operator>, so the element carrying bo-<operator> cannot also carry .bo.
· Logo asset is plain-light, or plain-dark with is-lt on a light fill. Never rectangle — it bakes in its own background and shows as a patch.
· Every operator needs a --bk. elabet ships a background instead, so it also declares --bk (and --bk7); without it the ramp resolves against --fill and comes out grey.
· The chip's ring is an inset shadow, not a border. Figma strokes sit inside the frame; a CSS border adds 2px and the pill measures 50 instead of 48.
· border:0 on the shell. A host that styles a with a border adds 1px to a fixed-height pill.
· States are inherited from .bodd--pill — do not re-declare them per variant.
· bwin has no visible hover: its --bk is pure black, so 500/700/950 all compute to black. Needs a lifting --bk7; open question.

07Design tokens

UseValueDS nameWhere
Primary text · odd (V2/V3) #1A1A1A Base 950--ink
Odd (V1) #CB2F01 Primary 600--acc — AA-safe as text on light
Borders · dividers #E6E6E6 Base 200--line
V1 card fill #F2F2F2 Base 100--fill
Hover tint #FFEBE6 Primary 50Gradient start
Focus ring rgba(253,58,1,.40) Primary 500Focus only
Radius6px V2/V3 shell · 8px V1 cardradius default
FontsRoboto · Roboto Mono --body / --numLabel · odd

08Responsible gaming & regulatory

Changed 2026-07-30: the component no longer renders an inline 21+ line in any variant. .modd-rg and its 21+ · ΠΑΙΞΕ ΥΠΕΥΘΥΝΑ markup were removed from V2/V3/V4/V5 here and from both analysis pages. It was duplicating a message the page already carries twice, directly under a row that repeats it per market. The obligation did not move — it is now met at page level only.
  • No variant renders an inline line. Do not re-add .modd-rg; the CSS rule is gone and a tombstone comment sits in its place.
  • The host page must carry the message. On the analysis page that is the sticky 21+ ΕΕΕΠ | ΠΑΙΞΕ ΥΠΕΥΘΥΝΑ skin bar and the full ΕΕΕΠ footer row — see handover-footer-eeep.html. Both are verified present on foxbet-responsive.html and foxbet-responsive-live.html.
  • This is a page-level contract, not a component one. If the component is ever syndicated into a page that does not carry the ΕΕΕΠ bar and footer, the inline line has to come back for every variant that names an operator — the component alone is then not compliant.
  • Naming an operator is what triggers the obligation, so V1 was never affected either way.

09Accessibility

CheckResult
V2/V3 label & odd — #1A1A1A on #FFFFFF18.1:1 — AAA ✔
V2/V3 on hover, gradient top — #1A1A1A on #FFEBE615.2:1 — AAA ✔
V1 odd — #CB2F01 on #F2F2F24.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 #F2F2F215.6:1 — AAA ✔
Hover is not colour-onlyThe 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-onlyThe tile carries the operator's wordmark, and the alt names it in text. Colour alone never conveys which bookmaker it is
Brand wordmarksLogos are exempt from text-contrast rules; each uses the brand's own approved colour on its own approved background
Reduced motionShimmer, card transitions and the swipe-chevron pulse are disabled under prefers-reduced-motion
Link labelEvery .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 targetV2/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.

CheckResult
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:1fails 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-onlyThe 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 targetV4 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 motionTransitions and the loading shimmer are disabled under prefers-reduced-motion

10Markup — copy/paste

Two variants, four forms. The mobile forms use the same markup as their desktop counterpart plus .bodd--m — nothing is re-rendered at a breakpoint, so a consumer can add that class by media query and be done.

<!-- V1 STANDALONE — no bookmaker.  height 41px, width hugs from 88.67px -->
<div class="moddgrid">
  <a class="modd" href="{deeplink}" target="_blank" rel="noopener" title="Ολλανδία">
    <span class="modd-card">
      <span class="modd-sel"><span class="modd-lbl">1</span></span>
      <span class="od">2.00</span>
    </span>
  </a>
  <!-- desktop only: a hairline between markets -->
  <span class="modd-div" aria-hidden="true"></span>
</div>

<!-- NOTE: V1 has NO .bo wrapper and no bo-<operator> class. It names no bookmaker. -->

<!-- V8 — V1 WITH BOOKMAKER.  mark | selection | odd.  height 41px, width hugs -->
<a class="modd modd--bk" href="{deeplink}" target="_blank" rel="noopener" title="Ολλανδία — Stoiximan">
  <span class="modd-card">
    <span class="modd-ic"><img src="logo-assets/rectangle/stoiximan.svg" alt="Stoiximan"></span>
    <span class="modd-sel"><span class="modd-lbl">1</span></span>
    <span class="od">2.00</span>
  </span>
</a>

<!-- rectangle (2:1), NOT plain-light and NOT circle-large: the mark needs its
     own background, and a 24px circle is too small to read -->

<!-- V6 BARE — logo + odd.  197 × 48 desktop, +.bodd--m = 101 × 81 stacked -->
<span class="bo">
  <a class="bodd bodd--pill bo-stoiximan" href="{deeplink}"
     target="_blank" rel="noopener" title="1 — Stoiximan">
    <span class="bodd-bk"><img src="logo-assets/plain-light/stoiximan.svg" alt="Stoiximan"></span>
    <span class="bodd-in"><span class="bodd-od">3.12</span></span>
  </a>
</span>

<!-- V7 WITH SELECTION — logo + selection | odd.  225 × 48 desktop, +.bodd--m = 101 × 81 -->
<span class="bo">
  <a class="bodd bodd--pill bodd--sel bo-bet365" href="{deeplink}"
     target="_blank" rel="noopener" title="O 2.5 — bet365">
    <span class="bodd-bk"><img src="logo-assets/plain-light/bet365.svg" alt="bet365"></span>
    <span class="bodd-in">
      <span class="bodd-lbl">O 2.5</span>
      <span class="bodd-sep" aria-hidden="true"></span>
      <span class="bodd-od">1.85</span>
    </span>
  </a>
</span>

<!-- light fill: add is-lt AND use the plain-dark export -->
<a class="bodd bodd--pill bodd--sel bo-interwetten is-lt" …>

<!-- disabled: .is-susp + aria-disabled -->
<a class="bodd bodd--pill bo-bet365 is-susp" aria-disabled="true" …>
The .bo wrapper is not decoration — every brand rule is scoped .bo .bodd…, and the per-operator colours are .bo .bo-<operator> descendant selectors, so the element carrying bo-<operator> cannot also carry .bo.

11Build checklist

  1. V1 is the neutral family: .moddgrid.modd.modd-card, with .modd-sel + .modd-lbl and .od inside. No .bo wrapper, no operator class — it names no bookmaker.
  2. V1's width hugs: min-width:88.67px is a floor and the 24 / 46px text slots are floors too. Never make them fixed — O 2.5, G/G Όχι and Γκολ 2-3 all need the room.
  3. V1's label is regular 400 and its odd bold 700, both 14px --ink: weight is the only thing separating them, plus the hairline. Not Roboto Mono, not --acc orange.
  4. V8 is .modd plus .modd--bk, with .modd-ic as the first child of .modd-card. Inherit everything else from V1 — do not re-declare the card, the type or the states.
  5. V8's mark is logo-assets/rectangle/<operator>.svg at 48 × 24. Never plain-light (no background of its own, so it disappears on the white card) and never circle-large (unreadable at 24px).
  6. Wrap in .bo; put bo-<operator> on the .bodd itself.
  7. V6 = .bodd.bodd--pill (197 × 48). V7 adds .bodd--sel (225 × 48) plus the .bodd-lbl and .bodd-sep children.
  8. Mobile = the same markup plus .bodd--m (101 × 81, stacked, chip on top). Apply it by media query; do not re-render.
  9. Logo asset is plain-light, or plain-dark with is-lt on a light fill. Never rectangle — it bakes in its own background.
  10. Give every operator a --bk. elabet is the one that ships a background instead, so it also declares --bk for the ramp (§06).
  11. States come free from .bodd--pill: hover 80%, disabled 50% via .is-susp + aria-disabled, focus ring from the family. Do not re-declare them.
  12. Odds are data: V6 shows one price, V7 shows selection + price. Best-odds vs sponsored is a feed decision, not a variant.
  13. Check contrast per operator before shipping a new one — the white odd on a light fill needs is-lt (§09).