Foxbet · Component handover

Ενδεκάδες — το γήπεδο

Οι 11 παίκτες κάθε ομάδας πάνω σε γήπεδο, με τον πάγκο από κάτω. Ένα markup για τα δύο breakpoints: στο desktop δύο μισά γήπεδα δίπλα-δίπλα, στο mobile ένα κάθετο γήπεδο όπου τα δύο μισά ενώνονται. Κάθε παίκτης ανοίγει κάρτα με στατιστικά και μία πρόταση.

Υλοποιημένο · pre-game + live Μετρημένο 2026-08-02 · 1440px / 390px Δεδομένα: demo, seeded από το νούμερο φανέλας

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

Το γήπεδο είναι σχεδόν εξ ολοκλήρου CSS — η χλόη, οι γραμμές, η περιοχή, το τόξο και οι γωνίες είναι borders και gradients, όχι εικόνες. Εικόνες μπαίνουν μόνο σε δύο σημεία: τη σημαία/έμβλημα κάθε ομάδας στην κεφαλίδα και το σήμα χορηγού στο κέντρο.

Σημείωση

Οι σημαίες είναι placeholder από το flagcdn — στο production μπαίνει το έμβλημα της ομάδας από το feed, στο ίδιο κουτί 20×14. Το σήμα χορηγού είναι πάντα η κοπή circle-large: είναι στρογγυλό σημάδι στο κέντρο του γηπέδου, όχι ορθογώνιο logo. Χωρίς χορηγό δεν μπαίνει τίποτα — ούτε δικό μας σήμα.

Ζωντανό demo — και τα δύο breakpoints

Ο πραγματικός κώδικας, σε δύο iframes στα πλάτη που μετρήθηκαν. Δοκίμασε hover σε παίκτη στο desktop και tap στο mobile — είναι δύο διαφορετικές συμπεριφορές, όχι η ίδια κάρτα σε δύο μεγέθη.

Desktop · πραγματικό viewport 1440px (κάρτα 874px)

Δύο μισά δίπλα-δίπλα, καθένα επιτίθεται προς το κέντρο. Εμφανίζεται σε κλίμακα 72% για να χωρέσει στη σελίδα — οι διαστάσεις του πίνακα §01 είναι οι πραγματικές.

Mobile · 390px

Ένα κάθετο γήπεδο· οι δύο πάγκοι πάνε κάτω.

00Διάβασε πρώτα αυτό

Δύο αποφάσεις που ορίζουν το component και δεν είναι στυλιστικές:

1Νούμερα, όχι φωτογραφίες. Η παλιά ενδεκάδα έβαζε την ίδια stock φωτογραφία και στους 22 παίκτες. Κανείς δεν αδειοδοτεί 22 πορτρέτα ανά αγώνα, άρα ο αριθμός φανέλας σε κύκλο είναι ο μόνος τίμιος τρόπος — και είναι δύο στοιχεία ανά παίκτη αντί για τρία, που είναι και το μεγαλύτερο μέρος της οικονομίας ύψους.
2Το πράσινο είναι --win (#027A48), όχι #039855. Λευκά ονόματα στο παλιό πράσινο μετρούν 3.73:1 και κόβονται στο AA· στο --win μετρούν 5.41. Οι κύκλοι: μελάνι σε λευκό 17.40, μελάνι σε χρυσό 9.63.
ℹ️Η σειρά του DOM κάνει τη δουλειά του προσανατολισμού. Η γηπεδούχος γράφεται GK→DEF→MID→FWD και η φιλοξενούμενη FWD→MID→DEF→GK. Έτσι και τα δύο μισά επιτίθενται προς τα μέσα χωρίς καμία αντιστροφή στο markup και χωρίς flex-direction:row-reverse πουθενά.

01Ανατομία μετρημένο 2026-08-02

ΜέροςΚλάσηDesktop (1440)Mobile (390)Κανόνας
Κάρτα.xiwrap874 × 428390 × 827 overflow:hidden + border-radius. Γι' αυτό η κάρτα παίκτη είναι position:fixed στο <body> — μέσα εδώ θα κοβόταν.
Ομάδα.xiteam[data-side]flex column display:contents Στο mobile η ομάδα εξαφανίζεται ως κουτί και τα παιδιά της μπαίνουν στο ίδιο grid με order, ώστε τα δύο μισά να ενωθούν σε ένα γήπεδο.
Κεφαλίδα.xihd437 × 32390 × 32 σημαία 20×14 · όνομα 13/700 · κατάσταση · σχηματισμός δεξιά σε --num.
Γήπεδο.xipitch437 × 258390 × 243 Φόντο --win, padding 4px 10px (desktop) / 10px 4px (mobile).
Γραμμές.lineup / .pline row / columncolumn / row Το ίδιο DOM: στο desktop η γραμμή γίνεται στήλη. min-height 250 / 210.
Παίκτης.plκύκλος 32 · κουτί 48 ύψος ίδιοΚύκλος + όνομα, gap 3px. Το όνομα κόβεται με ellipsis, ποτέ δεν αναδιπλώνεται.
Αριθμός.pl-no32 × 32, --num 13/700 γηπεδούχος λευκό · φιλοξ. --gold
Πάγκος.xisubs437 × 138πλήρες πλάτος Δύο στήλες, ζέβρα ανά ζεύγος σειρών (4n+1, 4n+2).
Στο desktop το .pline θέλει align-items:center και flex:0 0 auto στον παίκτη. Χωρίς αυτά η στήλη κληρονομεί flex-start και τα κουτιά, που παίρνουν πλάτος από το μήκος του ονόματος (μετρημένα 50/53/45/32px), δεν μοιράζονται άξονα — η στήλη διαβάζεται στραβή.

02Σχηματισμός — από τη σειρά, όχι από συντεταγμένες

Δεν υπάρχουν x/y πουθενά. Ένας σχηματισμός είναι μια λίστα από γραμμές και η θέση του παίκτη προκύπτει από τη γραμμή στην οποία ανήκει.

// 4-3-3 γηπεδούχος: GK → DEF → MID → FWD
<div class="lineup">
  <div class="pline">…1 GK…</div>
  <div class="pline">…4 DEF…</div>
  <div class="pline">…3 MID…</div>
  <div class="pline">…3 FWD…</div>
</div>

// φιλοξενούμενη 4-3-3: η ΙΔΙΑ λίστα ανάποδα — FWD → MID → DEF → GK

Ο διαχωρισμός μέσα στη γραμμή είναι justify-content:space-around, οπότε κάθε σχηματισμός δουλεύει χωρίς νέο CSS: 4-4-2, 3-5-2, 5-3-2, 4-2-3-1 — αρκεί να δώσει το feed τις γραμμές. Η θέση (GK/DEF/MID/FWD) που χρειάζεται η κάρτα προκύπτει από τον δείκτη της γραμμής, όχι από πεδίο δεδομένων.

ℹ️Γι' αυτό δεν έχει «διάταξη 4-2-3-1» ως ρύθμιση. Ο σχηματισμός στην κεφαλίδα (.xihd-f) είναι ετικέτα· αυτό που ζωγραφίζει είναι οι γραμμές. Αν οι δύο διαφωνήσουν, φταίει το feed.

03Η κάρτα παίκτη — δύο συμπεριφορές

Desktop (≥1200 & hover)Mobile / touch
Ενεργοποίησηhover = προεπισκόπηση · κλικ = καρφίτσωμα tap = φύλλο (sheet) από κάτω, με scrim
Θέσηposition:fixed, πάνω από τον παίκτη· αν δεν χωρά, αναποδογυρίζει από κάτωκολλημένο κάτω, το CSS ορίζει τη θέση — το JS δεν υπολογίζει left/top
Αλληλεπίδρασηpointer-events:none όσο είναι preview· γίνεται auto μόνο καρφιτσωμένηπάντα interactive, με ✕ και scrim

Περιεχόμενο ανά θέση — 2–4 στατιστικά και μία πρόταση:

ΘέσηΣτατιστικάΠρόταση
ΤερματοφύλακαςΣυμμετοχές · Επεμβάσεις/αγώνα · Clean sheets · % επεμβάσεωνClean sheet
ΑμυντικόςΣυμμετοχές · Tackles/αγώνα · Εκκαθαρίσεις · Μονομαχίες2+ tackles
ΜέσοςΣυμμετοχές · Πάσες · Key passes · Σουτ στην εστία1+ ασίστ ή 1+ σουτ στην εστία
ΕπιθετικόςΣυμμετοχές · Γκολ · Γκολ/90΄ · Σουτ · xGΝα σκοράρει
Το «Γκολ / 90΄» είναι ΠΑΡΑΓΩΓΟ, όχι τυχαίο. Υπολογίζεται γκολ ÷ συμμετοχές από τις δύο σειρές από πάνω του. Αν το ρίξεις στην ίδια γεννήτρια τυχαίων, η κάρτα αυτοαναιρείται (10 γκολ σε 24 συμμετοχές δίπλα σε «0.72 / 90΄») — και η διαίρεση δύο νούμερων στην οθόνη είναι το πρώτο που κάνει ο αναγνώστης.
ℹ️Τα demo νούμερα είναι ντετερμινιστικά. seeded(no,i) = frac(sin(no·37.7 + i·11.3)·10⁴) — ο ίδιος παίκτης δείχνει πάντα τα ίδια νούμερα, αλλά δύο παίκτες δεν μοιάζουν. Στο production όλα αυτά έρχονται από το feed· η φόρμουλα φεύγει.
Η πρόταση δεν είναι ντυμένη σαν Odds CTA. Συνειδητά: στο production αυτή η θέση φιλοξενεί το πραγματικό component, και ένα look-alike εδώ θα ήταν δεύτερη πηγή αλήθειας.

04Ο παλμός — πώς μαθαίνει ο χρήστης ότι πατιούνται

Δεν υπάρχει πια λωρίδα-οδηγία πάνω από το γήπεδο. Ένας παίκτης χτυπά σαν καρδιά και αυτό είναι όλη η πρόσκληση.

ΣτοιχείοΣυμπεριφορά
Ποιος παίκτης Ο επιθετικός με τη μικρότερη απόδοση «Να σκοράρει» — υπολογίζεται με την ίδια φόρμουλα που δίνει την τιμή στην κάρτα του, ώστε να μη διαφωνούν ποτέ. Στα demo δεδομένα: Γκάκπο, №10, @2.32.
Πότε ξεκινά Με IntersectionObserver (threshold .25) — όταν φανεί το γήπεδο, όχι στο load: οι ενδεκάδες είναι βαθιά στη σελίδα και ένα ρολόι από το load θα είχε λήξει πριν φτάσει εκεί ο χρήστης.
Πόσο κρατά20 δευτερόλεπτα, ή μέχρι το πρώτο tap σε οποιονδήποτε παίκτη — τότε η οδηγία έχει κάνει τη δουλειά της.
Τι φαίνεται Διπλός χτύπος στον κύκλο (scale 1→1.24→1→1.15) και δύο δαχτυλίδια που φεύγουν προς τα έξω, ένα λευκό κι ένα χρυσό μισό χτύπο μετά.
Με prefers-reduced-motion ο παλμός γίνεται ένα ακίνητο δαχτυλίδι για τα ίδια 20s: η ένδειξη «εδώ πατάς» παραμένει, η κίνηση φεύγει.

05Το μοντέλο δεδομένων που χρειάζεται

Ό,τι ζωγραφίζει το component, με ονόματα πεδίων. Ό,τι λείπει πρέπει να μην αποδίδεται, όχι να γίνεται κενό κουτί.

{
  "status": "probable" | "confirmed",   // → το pill «Πιθανές/Επιβεβαιωμένες»
  "home": {
    "name": "Ολλανδία",
    "crest": "…/nl.png",          // 20×14, cover
    "formation": "4-3-3",          // ΕΤΙΚΕΤΑ — δεν ζωγραφίζει
    "lines": [                       // ΑΥΤΟ ζωγραφίζει· GK πρώτα
      [ {"no":1,  "name":"Φερμπρούχεν"} ],
      [ {"no":22, "name":"Ντάμφρις"}, … ],
      …
    ],
    "bench": [ {"no":13, "name":"Φλέκεν"}, … ],
    "stats": { "10": { "apps":24, "goals":9, "xg":0.41, … } },
    "props": { "10": { "market":"Να σκοράρει", "odd":2.32, "url":"/go/…" } }
  },
  "away": { … },
  "sponsor": "stoiximan" | null      // null ⇒ ΚΑΝΕΝΑ σήμα στο κέντρο
}
Ο πάγκος δεν έχει όριο 8. Στο demo είναι 8+8 γιατί τόσους έχει το UEFA φύλλο· το grid είναι δύο στήλες με ζέβρα ανά ζεύγος, άρα δέχεται οποιοδήποτε πλήθος. Μην κόψετε τη λίστα στο UI — αν το feed δίνει 12, δείξτε 12.

06Εύκολα λάθη

07Προσβασιμότητα

ΘέμαΤι ισχύει
ΑντίθεσηΟνόματα σε --win 5.41:1 · μελάνι σε λευκό κύκλο 17.40 · μελάνι σε χρυσό 9.63. Όλα ≥ AA.
Ομάδα ≠ μόνο χρώμαΛευκό vs χρυσό ξεχωρίζει τις ομάδες, αλλά δεν είναι ο μόνος φορέας: κεφαλίδα με σημαία και όνομα πάνω από κάθε μισό, και τα μισά είναι χωριστά στον χώρο.
Στόχος αφήςΟ κύκλος είναι 32px αλλά ο στόχος είναι όλο το .pl (48px ύψος) — και στο mobile ο παίκτης πιάνει το πλάτος της γραμμής του.
ΚίνησηΟ παλμός σβήνει με prefers-reduced-motion και μένει ακίνητο δαχτυλίδι.
Πληκτρολόγιο Εκκρεμεί Οι παίκτες είναι <div> με hover/click. Για production χρειάζονται tabindex="0", role="button", ενεργοποίηση με Enter/Space και Esc για κλείσιμο. Είναι το μόνο γνωστό κενό του component.

08Πού τρέχει & τι το περιβάλλει

ΣελίδαΚατάσταση
foxbet-responsive.html — pre-game pill = «Πιθανές» (data-xi="prob")
foxbet-responsive-live.html — live pill = «Επιβεβαιωμένες» (data-xi="conf"). Τίποτε άλλο δεν αλλάζει.

Από πάνω του κάθεται η διαφημιστική θέση — σήμερα το ticker των 38px, με το LED wall ως concept για desktop. Τα δύο κολλάνε: η πινακίδα κρατά τις πάνω γωνίες και το .xiwrap γίνεται 0 0 16px 16px, ώστε να διαβάζονται ως ένα αντικείμενο. Μην στρογγυλέψετε και τα δύο.

Ζωντανά: pre-game · live. Άνοιξε τις ενδεκάδες και κάνε hover/tap σε παίκτη.

Foxbet · Analysis page · Ενδεκάδες. Υλοποιημένο και στις δύο σελίδες ανάλυσης· μετρημένο στο browser (1440px / 390px) 2026-08-02. Τα στατιστικά και οι αποδόσεις των παικτών είναι demo δεδομένα — στο production έρχονται από το feed.