DRAFT INTERNE : NO GO publication client en l'état (Legal-check 2026-05-24)
Bet224 n'est PAS sur la liste officielle des plateformes agréées ARSJPA [VERIFIED via WebFetch arsjpa.gov.gn/plateformes-agreees/ 2026-05-24]. Les 7 plateformes agréées : Geniusbet, Yellowbet, 1xBet GN, Guinée Games, Pariez GDJ, LONAGUI, Guinée Millions. Verbatim ARSJPA : « Si une plateforme ne figure pas dans cette liste, elle peut être non autorisée. »
Action immédiate recommandée client : retrait du logo ARSJPA présent sur 42 pages du site (cf F-TRUST-01-01) dans les heures qui suivent réception du rapport, indépendamment des autres recos.
5 préalables clients obligatoires avant publication FULL :
- Copie agrément ARSJPA OU reconnaissance de non-agrément + plan régularisation
- Raison sociale + RCCM Guinée + représentant légal
- Organigramme entité GN vs opérateur étranger (trace white-label italien : ADM, RUA, Concessionario hardcodés)
- Confirmation conseil juridique sur cadre data GN
- Confirmation dispositif central auto-exclusion GN
Détail red team adversarial (7 agents) : voir
_red-team-report.md.
Avertissement YMYL : ce rapport analyse le site bet224.gn, opérateur de paris sportifs et de casino en ligne en Guinée. Le secteur est classé YMYL (Your Money Your Life) en raison de l'impact financier et sanitaire potentiel sur les utilisateurs (risque d'addiction, perte d'argent, exposition de mineurs si protection absente). Les recommandations ci-dessous reposent sur (1) des observations sourcées du crawl du site (HTML, screenshots, signaux conversion-signals/axe-core), et (2) les standards internationaux du secteur gambling (UKGC, ANJ, MGA, ADM). La juridiction applicable est la Guinée. Le régulateur identifié est l'ARSJPA (https://arsjpa.gov.gn/, vérifié WebFetch 2026-05-16, statut d'agrément Bet224 vérifié WebFetch 2026-05-24 : NON AGRÉÉE). Le cadre réglementaire guinéen exact pour la publicité gambling, le consentement cookies, et les mentions obligatoires N'A PAS été vérifié en source primaire pour tous les aspects.
Généré : 2026-05-24T10:56:26.777867+00:00 Schémas product-audit v1.0 Sous-agents Deep exploités : 8
Synthèse globale
- Findings total : 73
- Par sévérité : critical : 21 · serious : 24 · moderate : 26 · minor : 2
- Angles couverts : A11Y, CONV, MOBILE, PERF, SEO, TRUST, UI, UX
- Routes auditées : 4
Angle : A11Y
Persona
Source : site-context.yaml voice_and_tone.persona_primary.
sport-home: parieur sportif en Guinée, très majoritairement mobile, intéressé par le football. Sur cette route il arrive pour consulter l'offre du jour (tabs Football / Basketball, top compétitions). Lecteur d'écran : devra naviguer dans une grille de cotes complexe sans landmark utile.sport: même persona, en intent "construction d'un pari" sur une compétition donnée. Le widget Betbuilder (slidebar gauche) est un point d'entrée critique pour les paris combinés ; il est ici inaccessible aux utilisateurs avec contraste réduit (ratio mesuré 1.3:1).casino: persona élargie (joueur casino en ligne, non explicité danspersona_primarymais route présente dans l'audit). Navigation par carrousels de jeux ; les flèches de défilement (8 boutons) ne portent aucun nom accessible, bloquant clavier et lecteur d'écran. Route YMYL sensible : public protégé attendu.promotions: persona en intent "découverte d'un bonus" avant inscription. Les 5 visuels promotionnels (bonus 500 %, cashback, welcome) sont des<img>sans alt, donc invisibles pour lecteur d'écran. Implication YMYL : si le lecteur d'écran ne peut pas lire les conditions associées, le risque d'incitation au jeu non comprise augmente.
Synthèse exécutive
- Volume mesuré : 39 violations axe-core 4.11.4 cumulées sur 4 routes desktop (14 critical, 7 serious, 18 moderate). Source :
axe-results/index.json→results[].desktop.violations_by_impact. - 6 règles WCAG 2.1 A/AA sont violées sur les 4 routes simultanément (pattern template global) :
aria-allowed-attr,image-alt,label,link-name, plus 2 best-practice (page-has-heading-one,region). Le défaut est dans le template header/footer commun. - Casino concentre une pathologie spécifique : 8 boutons de carrousel
componenteGioco__navigatore__tastosansaria-label, ni texte visible, ni title. Source :axe-results/casino/desktop.json→violations[1].id = "button-name",violations[1].nodes_total = 8. Impact clavier/lecteur d'écran direct sur le parcours de découverte des jeux. - Casino bloque aussi le zoom mobile (
meta-viewportavecmaximum-scale=1) - WCAG 1.4.4 niveau AA non respectée. Source :axe-results/casino/desktop.json→violations[8].id = "meta-viewport". - 2 défauts de contraste sérieux mesurés (Betbuilder sport 1.3:1 sur 4.5:1 attendu, filtre Sport promotions 2.6:1). Source :
axe-results/sport/desktop.json→violations[2],axe-results/promotions/desktop.json→violations[1].
Findings
F-A11Y-01-01 : Logo header sans alt + lien wrappant sans nom accessible (4 routes)
- Sévérité : critical
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
axe-results/sport-home/desktop.json→violations[1].id = "image-alt",violations[1].nodes[0].target = ["a[href=\"/\"] > img"],violations[1].impact = "critical"axe-results/sport-home/desktop.json→violations[6].id = "link-name",violations[6].nodes[1].target = ["a[href=\"/\"]"],violations[6].impact = "serious"- Pattern identique mesuré sur sport (
violations[3].nodes[0]+violations[8].nodes[1]), casino (violations[2].nodes[0]+violations[7].nodes[1]), promotions (violations[2].nodes[0]+violations[4].nodes[1]). - HTML observé :
<a href="/"><img src="https://www.bet224.gn/external_cms/GUINEA/img/logo-bet-224.png"></a>(sans alt, sans aria-label). - Source visuelle : -
screenshots/sport-home/desktop.png,screenshots/sport/desktop.png,screenshots/casino/desktop.png,screenshots/promotions/desktop.png: logo "Bet224" rouge en haut à gauche (zone ~x=0-100, y=40-80) confirmé visuellement sur 4 captures. - Constat :
Le logo Bet224 du header est un <img> sans attribut alt, enveloppé dans un <a href="/"> sans texte ni aria-label. Le lien est donc totalement muet pour un lecteur d'écran et pour un utilisateur clavier qui s'y arrête en tabulation : impossible de savoir où il mène, ni qu'il s'agit du logo retour-accueil.
- Impact attendu :
WCAG 1.1.1 (Non-text Content) niveau A et WCAG 2.4.4 (Link Purpose) niveau A violées sur 100 % des routes auditées. Un utilisateur de lecteur d'écran perd le point d'ancrage le plus universel d'un site (logo = retour accueil). En contexte YMYL gambling, c'est aussi un signal de qualité produit dégradé.
- Root cause :
Template header commun (path external_cms/GUINEA/img/logo-bet-224.png fixé serveur). Un seul fix template corrige les 4 routes.
F-A11Y-01-02 : Drapeau langue fr.png sans alternative textuelle (4 routes)
- Sévérité : critical
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
axe-results/sport-home/desktop.json→violations[1].id = "image-alt",violations[1].nodes[1].target = ["img[src$=\"fr.png\"]"],violations[1].impact = "critical"- HTML observé :
<img src="/images/desktop/fr.png" class="flag-lang">(4 routes). - Source visuelle : -
screenshots/sport-home/desktop.pngetc. : drapeau France visible en haut à droite, label visible "FR" à proximité (zone ~x=1377, y=80, mesurée dansconversion-signals/sport-home.json→detailed.ctas[3].bbox). - Constat :
Le drapeau "FR" servant de sélecteur de langue est une image sans alt. Un utilisateur de lecteur d'écran n'a aucune indication de la langue courante ni de la fonction du contrôle. Note : un libellé texte "FR" est rendu à côté (cf conversion-signals/sport-home.json → detailed.ctas[3].text = "FR"), mais comme l'image n'est pas explicitement masquée (role="presentation") ni labellisée, axe le compte malgré tout.
- Impact attendu :
WCAG 1.1.1 niveau A violée. Une personne aveugle ou malvoyante ne peut pas identifier la langue active ni le sélecteur. Sur un site multilingue, c'est un point d'entrée de friction.
- Root cause :
Pattern legacy <img class="flag-lang"> sans rôle explicite. Le fix dépend : soit alt="Français" si l'image est porteuse de sens, soit alt="" + role="presentation" si le label "FR" texte adjacent porte l'information.
F-A11Y-01-03 : 8 boutons de carrousel casino sans nom accessible
- Sévérité : critical
- Route(s) :
casino - Source primaire :
axe-results/casino/desktop.json→violations[1].id = "button-name",violations[1].nodes_total = 8,violations[1].impact = "critical"violations[1].nodes[0].target = ["div[data-target=\"gamesGroup-4\"] > .componenteGioco__navigatore__tasto--indietro.componenteGioco__navigatore__tasto"]violations[1].nodes[1].target = ["div[data-target=\"gamesGroup-4\"] > .componenteGioco__navigatore__tasto--avanti.componenteGioco__navigatore__tasto"]- Pattern répété sur
gamesGroup-3,gamesGroup-2,gamesGroup-1(boutons avant + arrière chacun, 8 boutons au total). - HTML observé :
<button class="componenteGioco__navigatore__tasto componenteGioco__navigatore__tasto--indietro" onclick="scrollConBottone('gamesGroup-4', 'left')">(et son équivalent--avantipour la droite). - Source visuelle : -
screenshots/casino/desktop.png: carrousels "Spribe Games", "Top 10", "Evolution", "Top Providers", "Amigo Gaming" avec flèches gauche/droite visibles en haut à droite de chaque section (zone ~y=145, 250, 360, 470, 580). - Constat :
Les boutons de défilement avant/arrière des carrousels de jeux (4 carrousels confirmés visuellement, 8 boutons totaux dans axe) sont des <button> sans texte interne, sans aria-label, sans title. Le contenu visuel (icône CSS supposée) n'est pas exposé à l'API d'accessibilité.
- Impact attendu :
WCAG 4.1.2 (Name, Role, Value) niveau A violée 8 fois. Pour un utilisateur clavier, la tabulation s'arrête sur un bouton anonyme ("bouton" annoncé sans plus). Le parcours de découverte du catalogue de jeux casino est partiellement bloqué. Contexte YMYL : la friction inacceptable masque aussi les conditions visibles d'engagement (offres in-carrousel).
- Root cause :
Composant componenteGioco__navigatore interne, probablement réutilisé sur toutes les sections de jeux. Fix unique = patcher le template du composant pour ajouter aria-label au render.
F-A11Y-01-04 : Toggle thème dark/light sans label (4 routes)
- Sévérité : critical
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
axe-results/sport-home/desktop.json→violations[2].id = "label",violations[2].nodes[0].target = ["#cg-theme-switch"],violations[2].impact = "critical"- Pattern identique mesuré sur sport (
violations[4]), casino (violations[3]), promotions (violations[3]). - HTML observé :
<input type="checkbox" class="custom-control-input" id="cg-theme-switch">(sans<label for="cg-theme-switch">, sansaria-label). - Constat :
L'input checkbox #cg-theme-switch (toggle thème clair/sombre du footer) n'a ni label associé, ni aria-label, ni aria-labelledby. Pour un lecteur d'écran, l'élément est annoncé "case à cocher non cochée" sans contexte sur sa fonction.
- Impact attendu :
WCAG 4.1.2 (Name, Role, Value) niveau A violée. Concrètement, la friction reste mineure car le toggle est secondaire (préférence d'affichage), mais il s'agit d'un input form non labellisé, donc finding axe critical. La présence d'une icône lune ou soleil suppose un contexte visuel non transmis au lecteur d'écran.
- Root cause :
Composant footer commun template, probablement issu du framework UI (Bootstrap custom-control). Manque le <label for="cg-theme-switch">Mode sombre</label> ou un aria-label="Activer le mode sombre" direct sur l'input.
F-A11Y-01-13 : Aria-expanded sur élément non interactif (4 routes)
- Sévérité : critical
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
axe-results/sport-home/desktop.json→violations[0].id = "aria-allowed-attr",violations[0].nodes[0].target = ["#droplang"],violations[0].impact = "critical"violations[0].nodes[0].failureSummary = "Fix all of the following: ARIA attribute is not allowed: aria-expanded=\"false\""- HTML observé :
<div class="blocco-header selettore-lingua dropdown" id="droplang" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> - Pattern identique sur sport (
violations[0]), casino (violations[0]), promotions (violations[0]). - Constat :
Le sélecteur de langue (#droplang) est un <div> qui porte un attribut aria-expanded="false". Or aria-expanded n'est autorisé que sur des rôles interactifs (button, link, menuitem, tab, treeitem, combobox), pas sur un <div> sans role explicite. L'attribut est ignoré par les technologies d'assistance, créant un état d'accessibilité fantôme.
- Impact attendu :
WCAG 4.1.2 niveau A violée. Le dropdown langue n'expose pas correctement son état ouvert / fermé aux lecteurs d'écran. Friction limitée (le label "FR" est visible), mais marqueur fort d'un markup ARIA mal maîtrisé.
- Root cause :
Pattern Bootstrap 4 data-toggle="dropdown" sans wrapping <button>. Fix : soit transformer le <div> en <button type="button"> (ce qui rend aria-expanded valide), soit ajouter role="button" + gestion clavier.
F-A11Y-01-14 : Accordion tablist avec enfants non autorisés (sport)
- Sévérité : critical
- Route(s) :
sport - Source primaire :
axe-results/sport/desktop.json→violations[1].id = "aria-required-children",violations[1].nodes[0].target = [".contenitore-competizioni-sport[aria-multiselectable=\"true\"][role=\"tablist\"]:nth-child(3)"],violations[1].impact = "critical"violations[1].nodes[0].failureSummary = "Element has children which are not allowed: a[tabindex]"- HTML observé :
<div id="accordionLaterale" class="contenitore-competizioni-sport" role="tablist" aria-multiselectable="true"> - Constat :
L'élément #accordionLaterale porte role="tablist" mais contient des <a tabindex="..."> au lieu d'enfants ayant le rôle tab. Le pattern viole la grammaire ARIA et casse la navigation au clavier dans la liste latérale des compétitions sport (parcours principal de la route).
- Impact attendu :
WCAG 1.3.1 (Info and Relationships) niveau A violée. Lecteur d'écran annonce une "liste d'onglets" qui n'en est pas une : confusion fonctionnelle. Navigation clavier ne suit pas le pattern tablist attendu (flèches gauche / droite).
- Root cause :
Composant accordion latéral des compétitions sport : un tablist avec des <a> enfants alors que la sémantique correcte serait <div role="tab"> ou simplement un <div role="list"> + <a role="listitem"> (un accordion n'est pas une tablist).
F-A11Y-01-05 : Bouton de fermeture du header sans texte accessible (4 routes)
- Sévérité : serious
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
axe-results/sport-home/desktop.json→violations[6].id = "link-name",violations[6].nodes[0].target = ["#nascondiHeader"],violations[6].impact = "serious"- HTML observé :
<a id="nascondiHeader" data-toggle="collapse" class="accordion-toggle toggle-nascondi flex-container" href="#nascondimenu" role="button" aria-expanded="false" aria-controls="nascondimenu"><i class="fa fa-times"></i></a> - Pattern identique sur sport (
violations[8].nodes[0]), casino (violations[7].nodes[0]), promotions (violations[4].nodes[0]). - Constat :
Le bouton "Masquer le header" (icône fa fa-times Font Awesome via <i>) n'a aucun texte alternatif accessible. Le <a role="button"> n'a ni aria-label, ni texte enfant lisible. Le aria-controls="nascondimenu" est correctement posé mais le nom du contrôle reste manquant.
- Impact attendu :
WCAG 2.4.4 + WCAG 4.1.2 niveau A violées. Utilisateur clavier ou lecteur d'écran ne peut pas comprendre la fonction du bouton avant de l'activer. Risque de masquage inattendu d'éléments d'interface.
- Root cause :
Pattern Font Awesome <i class="fa fa-times"></i> sans wrapping textuel. Ajout d'aria-label="Masquer le menu" direct sur le <a>.
F-A11Y-01-06 : Contraste insuffisant sur le widget Betbuilder (sport)
- Sévérité : serious
- Route(s) :
sport - Source primaire :
axe-results/sport/desktop.json→violations[2].id = "color-contrast",violations[2].nodes[0].target = [".widgetFiltroSide__betBuilder > .margine-giu.bg-colore-1[href-disabled=\"#!\"]"],violations[2].impact = "serious"violations[2].nodes[0].failureSummary = "Element has insufficient color contrast of 1.3 (foreground color: #000000, background color: #212121, font size: 7.5pt (10px), font weight: bold). Expected contrast ratio of 4.5:1"- HTML observé :
<a href-disabled="#!" role="button" tabindex="0" class="pointer bg-colore-1 bianco margine-giu">Betbuilder</a> - Source visuelle : -
screenshots/sport/desktop.png: barre latérale gauche au-dessus du sélecteur de sports, libellé "Betbuilder" rendu en noir sur fond gris très sombre. Confirmation visuelle directe : illisible sans agrandissement zoom. - Constat :
Le bouton "Betbuilder" du widget de filtres latéral (point d'entrée pari combiné) a un ratio de contraste mesuré de 1.3:1 (noir #000000 sur gris foncé #212121), pour un seuil WCAG 2.1 AA de 4.5:1. La classe CSS bianco (italien pour "blanc") suggère que le texte devrait être blanc, mais la cascade applique du noir : conflit CSS non résolu côté thème.
- Impact attendu :
WCAG 1.4.3 (Contrast Minimum) niveau AA violée. Utilisateurs malvoyants, ou utilisateurs en lumière forte (mobile en extérieur), ne peuvent pas lire l'étiquette. Le Betbuilder étant un parcours premium gambling, c'est un blocage commercial direct.
- Root cause :
Classes en collision dans le CSS du composant widgetFiltroSide__betBuilder : la classe bianco (forcer texte blanc) est probablement écrasée par bg-colore-1 ou margine-giu qui réinitialise color. Fix CSS spécifique : revue de la cascade pour le sélecteur.
F-A11Y-01-07 : Contraste insuffisant sur le filtre Sport des promotions
- Sévérité : serious
- Route(s) :
promotions - Source primaire :
axe-results/promotions/desktop.json→violations[1].id = "color-contrast",violations[1].nodes[0].target = ["a[filtro-dati=\"2\"]"],violations[1].impact = "serious"violations[1].nodes[0].failureSummary = "Element has insufficient color contrast of 2.6 (foreground color: #ffffff, background color: #83ae30, font size: 9.0pt (12px), font weight: normal). Expected contrast ratio of 4.5:1"- HTML observé :
<a class="bottone-filtro pointer" filtro-dati="2">Sport</a> - Source visuelle : -
screenshots/promotions/desktop.png: ligne de filtres "TOUTES / Sport / ..." sous le carrousel header, bouton "Sport" en blanc sur vert clair (#83ae30). Lisibilité dégradée confirmée visuellement. - Constat :
Le filtre "Sport" des promotions a un ratio mesuré de 2.6:1 (#ffffff sur #83ae30), seuil AA 4.5:1. Le filtre est un point de bascule clé pour les utilisateurs cherchant les bonus sport vs. casino : friction directe sur le funnel d'inscription.
- Impact attendu :
WCAG 1.4.3 niveau AA violée. Persona primaire (parieur sport mobile) susceptible d'utiliser le téléphone en extérieur : impact accentué. Le filtre étant un état actif (sélection), la dégradation de lisibilité induit aussi un risque de mauvaise compréhension de l'état courant.
- Root cause :
Couleur d'accent secondaire #83ae30 (vert lime) trop claire pour porter du blanc à 12px. Soit assombrir la couleur de fond (≥ #5e7d1f pour atteindre 4.5:1), soit basculer le texte sur noir sur ce vert. Décision à arbitrer côté design system.
F-A11Y-01-12 : Carrousels casino non accessibles au clavier (scrollable-region-focusable)
- Sévérité : serious
- Route(s) :
casino - Source primaire :
axe-results/casino/desktop.json→violations[11].id = "scrollable-region-focusable",violations[11].nodes_total = 2,violations[11].impact = "serious"violations[11].nodes[0].target = [".componenteGioco > .rowContainer"]violations[11].nodes[1].target = ["#swiper-wins-6"]- Constat :
Deux conteneurs scrollables horizontalement (rowContainer des carrousels de jeux, #swiper-wins-6 du carrousel "Gains récents") ne sont pas focusables au clavier. Un utilisateur naviguant uniquement au clavier ne peut donc pas faire défiler le contenu. Combiné à F-A11Y-01-03 (8 boutons fléchés sans nom accessible), c'est un blocage total du parcours sur les carrousels casino.
- Impact attendu :
WCAG 2.1.1 (Keyboard) niveau A violée. Utilisateur clavier exclu de toute la zone catalogue jeux de la route casino. Combiné aux boutons fléchés muets, c'est le pire pattern a11y de ce POC.
- Root cause :
Composant Swiper.js ou équivalent custom drag scroll : il faut soit ajouter tabindex="0" aux conteneurs scrollables, soit un fallback bouton accessible. Le fix de F-A11Y-01-03 (nommer les boutons) ne suffit pas seul : il faut aussi exposer la zone au clavier.
F-A11Y-01-08 : Aucun H1 sur les 4 routes auditées
- Sévérité : moderate
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
axe-results/sport-home/desktop.json→violations[7].id = "page-has-heading-one",violations[7].nodes[0].target = ["html"],violations[7].impact = "moderate"- Pattern identique sur sport (
violations[9]), casino (violations[9]), promotions (violations[5]). - Constat :
Aucune des 4 routes auditées ne dispose de balise <h1>. Le diagnostic est issu d'axe (best-practice tag) ; il n'a pas pu être recoupé avec page-signals/<slug>.signals.json → headings.h1_count car le build de page-signals n'a pas été exécuté sur ce POC (cf Limites).
- Impact attendu :
Best-practice WCAG (impact moderate axe), pas un critère AA strict, mais double impact a11y + SEO. Sans H1, le lecteur d'écran ne peut pas identifier le sujet principal de la page via le raccourci de navigation par titres. Sur une route YMYL gambling, c'est aussi un signal de qualité éditoriale absent pour les moteurs.
- Root cause :
Template legacy probablement basé sur <h2> only (anti-pattern observé sur d'autres sites du même éditeur). Toutes les routes héritent d'un layout sans <h1> principal.
F-A11Y-01-09 : Architecture des landmarks <main> cassée (sport-home, sport, casino)
- Sévérité : moderate
- Route(s) :
sport-home,sport,casino - Source primaire :
axe-results/sport-home/desktop.json→violations[3].id = "landmark-main-is-top-level",violations[3].nodes[0].target = ["#cg_exa-sportAppContainer > main"]axe-results/sport-home/desktop.json→violations[4].id = "landmark-no-duplicate-main",violations[4].nodes[0].target = ["body > main"]axe-results/sport-home/desktop.json→violations[5].id = "landmark-unique",violations[5].nodes[0].target = ["body > main"]- Pattern identique sur sport (3 violations même groupe) et casino (3 violations même groupe :
target = ["#idContentMain"],["#panel"],["#panel"]). - Promotions PAS affectée par ce groupe.
- Constat :
Trois règles convergentes sur 3 routes signalent que le DOM contient plus d'un élément <main> (body > main ET #cg_exa-sportAppContainer > main ou #idContentMain ET #panel). Cela viole le principe HTML "un seul <main> par document" et casse la navigation par landmarks. Les deux <main> n'ont pas non plus de aria-label les distinguant (landmark-unique).
- Impact attendu :
Best-practice WCAG (moderate axe). Pour lecteurs d'écran, le skip link "passer au contenu principal" devient ambigu (sur lequel des deux main saute-t-il ?). Pattern d'erreur révélateur d'un layout générique mal contrôlé.
- Root cause :
Vraisemblablement un wrapping app (SPA conteneur) qui pose son propre <main> alors que le template parent en a déjà un. À investiguer : SSR/CSR hybride ? Réseau de partials WordPress ? Promotions est OK car probablement servi par un autre template (pages CMS éditoriales).
F-A11Y-01-10 : Contenus hors landmarks (4 routes)
- Sévérité : moderate
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
axe-results/sport-home/desktop.json→violations[8].id = "region",violations[8].nodes_total = 7- 5 nodes représentatifs mesurés :
.info-utili(heure / date header),.disclaimer(zone disclaimer header),#cg-barra-cookies(banner cookies),.col-lg-3(wrapping logo),.bottoni-login(boutons Login / Inscription header). - Pattern identique sur sport (
violations[10]), casino (violations[10]), promotions (violations[6]). - Constat :
Sur chaque route, 7 zones de contenu (en majorité du header) ne sont pas contenues dans un landmark sémantique (<header>, <nav>, <main>, <footer>, <aside>, [role="region"]). Inclut des éléments à fort enjeu : disclaimer YMYL, banner cookies, boutons login / inscription, sélecteur langue.
- Impact attendu :
Best-practice WCAG (moderate axe). Pour utilisateurs de lecteurs d'écran, la navigation par landmarks (raccourci-clavier D sur NVDA) ignore ces zones. Le disclaimer YMYL et le banner cookies sont particulièrement critiques : ce sont précisément les zones qui devraient être identifiables en sémantique.
- Root cause :
Markup div-soup historique du header. Le wrapping <div class="blocco-header"> n'a ni role, ni équivalent sémantique. Fix template global du header.
F-A11Y-01-11 : Meta viewport bloque le zoom mobile (casino)
- Sévérité : moderate
- Route(s) :
casino - Source primaire :
axe-results/casino/desktop.json→violations[8].id = "meta-viewport",violations[8].nodes[0].target = ["meta[name=\"viewport\"]:nth-child(118)"],violations[8].impact = "moderate"- HTML observé :
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1"> - Constat :
La balise meta viewport de la route casino contient maximum-scale=1, ce qui désactive le zoom utilisateur sur mobile. Note : le finding est mesuré par axe en contexte desktop, mais l'impact est mobile (le viewport contrôle les capacités de zoom sur smartphone et tablette).
- Impact attendu :
WCAG 1.4.4 (Resize Text) niveau AA violée. Utilisateurs malvoyants ne peuvent pas zoomer sur le contenu. En contexte gambling, blocage critique pour lire les conditions, les cotes, ou les boutons de jeu sur petit écran. Bet224 ciblant majoritairement mobile (cf site-context.yaml persona_primary), c'est un défaut prioritaire.
- Root cause :
Pattern legacy souvent ajouté pour "fixer le layout" mais qui casse l'accessibilité. Anti-pattern documenté ; retirer simplement maximum-scale=1 et minimum-scale=1 (laisser width=device-width, initial-scale=1 seul).
Cross-angle dependencies
- CONV (à venir, DEEP-CONV-01) : aucune dépendance critique identifiée.
conversion-signals/index.json→aggregate.forms_total_all_routes = 0etaggregate.routes_with_unlabeled_fields = 0. Le finding F-A11Y-01-04 (label#cg-theme-switch) est un input de préférence d'affichage, pas un form de conversion : pas de friction CONV à signaler. À noter pour DEEP-CONV-01 : les 4 routes auditées ne contiennent pas de formulaire d'inscription / dépôt dans le DOM crawlé (probablement chargé en SPA après interaction, non capturé en POC raw HTML). - UI (à venir, DEEP-UI-01) : R-A11Y-01-05 (contraste Betbuilder) et R-A11Y-01-06 (contraste filtre Sport) dépendent de la charte de couleurs. À cross-référencer avec l'analyse
design-system/index.json→aggregate.colorspour vérifier si les couleurs incriminées (#212121, #83ae30) sont des tokens du design system. Si oui, le fix doit remonter au design system pas au CSS local. - MOBILE (à venir, DEEP-MOBILE-01) : F-A11Y-01-11 (meta-viewport maximum-scale=1) est critique pour le persona primaire (parieur mobile Guinée). Doit être un finding partagé / prioritaire dans DEEP-MOBILE-01. Note : l'audit mobile a11y complet n'a pas pu être fait (POC desktop only).
- SEO (à venir, DEEP-SEO-01) : F-A11Y-01-08 (aucun H1 sur 4 routes) est aussi un finding SEO majeur. À fusionner dans une reco unique en assemblage (
assemble_audit.py). - TRUST (à venir, DEEP-TRUST-01) : F-A11Y-01-10 (zones hors landmarks) mentionne explicitement
.disclaimeret#cg-barra-cookies. Sur un site YMYL gambling, ces deux zones devraient être structurées en landmark sémantique pour être identifiables par les utilisateurs de technologies d'assistance. Cross-référence forte avec DEEP-TRUST-01.
Limites
- Mobile a11y non audité :
axe-results/<slug>/mobile.jsonabsent pour les 4 routes (POC desktop only, cfaxe-results/index.json→results[].mobile.path = null). Conséquence : règles spécifiques au contexte mobile (touch targets WCAG 2.5.5, focus mobile, navigation responsive accessible) non instruites. Recommandation : étendre le crawl pour avoir mobile.json sur chaque route avant livraison FULL. - page-signals/<slug>.signals.json absent :
build_page_signals.pyn'a pas tourné sur ce POC. Conséquence :headings.h1_count,headings.outline,forms[]consolidés,landmarks[]non disponibles. Le finding F-A11Y-01-08 (absence H1) repose donc UNIQUEMENT surpage-has-heading-oneaxe (best-practice), pas sur un compteur direct. Pour les autres findings, axe couvre déjà les selectors et failureSummary, donc l'absence de page-signals est dégradante mais pas bloquante. - Routes auditées limitées à 4 : le parcours d'inscription, de dépôt, de retrait, le live betting, la page mentions légales, la page jeu responsable ne sont pas dans le scope. Pour un livrable FULL, ces routes sont critiques (inscription = friction conversion ; jeu responsable = obligation YMYL). À étendre.
- Cadre légal accessibilité Guinée non sourcé : aucune source primaire identifiée en session sur l'existence et le contenu d'une réglementation accessibilité applicable au secteur jeux d'argent en Guinée. Par conséquent, toutes les recos a11y ont
conformite_legale: false. Le tagRGAAv4présent dansaxe-resultsest un mapping utilitaire international (convergence WCAG / EN 301 549 / RGAA), pas un fondement légal applicable. À cadrer en red team Legal-check. - Tests utilisateurs réels avec technologies d'assistance : non effectués. axe-core couvre une part importante mais limitée (estimé ≤ 50 % des défauts a11y détectables automatiquement). Findings basés purement sur DOM / CSS calculé. Un test NVDA / JAWS / VoiceOver complet par un utilisateur expérimenté révélerait probablement d'autres défauts (gestion focus modale, annonces live region, etc.).
- Pas d'analyse axe sur le banner cookies en état "non accepté" : la capture intervient probablement après auto-acceptation ou en état initial sans interaction. La conformité a11y du dialogue cookies n'est donc pas évaluée.
- Compteurs axe en désaccord avec le brief : le brief annonce "39 violations cumulées, 14 critical". J'ai mesuré dans
axe-results/index.jsonla même répartition (3 + 4 + 4 + 3 = 14 critical), donc OK. Mais le brief mentionne aussi "0 minor", ce qui est confirmé. Si un assemble cross-angle reproduit ces compteurs, vérifier qu'ils incluent les nodes (et non seulement les règles).
Angle : CONV
Persona
Source : site-context.yaml → voice_and_tone.persona_primary ("parieur sportif en Guinée, très majoritairement mobile, intéressé par le football en priorité").
sport-home: parieur sportif en intent "consulter l'offre du jour". Il atterrit sur une homepage où la première impression visuelle (bandeau hero) est dominée par 2 promesses de bonus ("GAGNEZ 100 % DE BONUS sur votre 1er dépôt jusqu'à 1 000 000 GNF", "10 % CASHBACK jusqu'à 500 000 GNF chaque semaine"). Le primary CTA business attendu (Inscription / Login) est en haut à droite, non identifié par le detector qui retient "Basketball" (tab filtre).sport: même persona en intent "explorer une discipline (football)". La page est dominée par un sélecteur de matchs et un panneau "Top Match", l'incitation à l'inscription reste portée par les mêmes bandeaux promo et un encart "Ticket" latéral.casino: persona élargie (joueur casino). 43 boutons "JOUER" identiques détectés, dont 23 above-fold. Un bandeau "Gains récents" en haut affiche des montants spécifiques (1 803 313 GNF, 200 180 GNF, 30 002 GNF, 28 441 GNF, 22 532 GNF). Pattern de social proof manipulatoire sans source vérifiable.promotions: persona en intent "découvrir un bonus avant inscription". 3 bannières dominent l'above-fold : MAXI BONUS ("AUGMENTE TES GAINS JUSQU'À 500 % ! PARIEZ ICI"), CASHBACK SPORT ("Bonus Cashback BET224 1 000 000 GNF"), WELCOME SPORT ("Bonus de 1er Dépôt BET224 100 % jusqu'à 1 000 000 GNF en Fun Bonus Sport"). Conditions de mise (wagering) non visibles above-fold.
Synthèse exécutive
- 60 CTAs détectés sur 4 routes desktop, 38 above-fold (ratio 0.633). Source :
conversion-signals/index.json→aggregate.ctas_above_fold_ratio = 0.633,aggregate.ctas_total_all_routes = 60. Distribution très déséquilibrée : casino concentre 43/60 CTAs (72 %), promotions seulement 3. - Aucun primary CTA business n'est correctement identifié par le detector sur les 4 routes : "Basketball" (tab filtre, sport-home), "Previous" (carousel, sport), "OUVRIR PIED DE PAGE" (casino + promotions). Les vrais CTAs business "Login" et "Inscription" (header haut-droit, visibles screenshots) ne sont pas remontés en
detailed.primary_cta. Signal d'une absence de hiérarchie visuelle exploitable côté détection automatique, à confirmer manuellement. - Dark patterns YMYL critiques détectés visuellement : (1) promesses de gain explicites en above-fold ("AUGMENTE TES GAINS JUSQU'À 500 %", "GAGNEZ 100 % DE BONUS") violant
voice_and_tone.forbiddenetclaims.forbiddendesite-context.yaml; (2) "Gains récents" casino avec montants spécifiques non sourcés ; (3) absence totale de lien "jeu responsable" / auto-exclusion / mention d'âge dans le footer des 4 routes (legal_linksne contient que CGU + politique confidentialité). Cfforbidden_patternssite-context. - 0 formulaire détecté sur 4 routes. Source :
aggregate.forms_total_all_routes = 0. Le funnel d'inscription/signupet de dépôt n'est pas couvert par le crawl actuel, opacité critique pour analyser la friction onboarding. - 0 mention de contact (email/téléphone) visible sur les 4 routes. Source :
aggregate.routes_with_contact_email = 0,aggregate.routes_with_contact_phone = 0. Sur YMYL gambling, l'absence de support visible est un anti-pattern fort (assistance en cas de problème de paiement, fermeture de compte, dispute).
Findings
F-CONV-01-01 : Promesses de gain en above-fold ("100 % BONUS", "JUSQU'À 500 %") sur 2 routes, interdites par voice_and_tone
- Sévérité : critical
- Route(s) :
sport-home,promotions - Source primaire :
site-context.yaml→voice_and_tone.avoid[1] = "promesse ou suggestion de gain ('gagnez', 'argent facile', 'revenus')"site-context.yaml→claims.forbiddencontient explicitement"Bonus 100 % gratuit"et"Gagnez a coup sur"site-context.yaml→forbidden_patterns[0] = "countdown factice / fausse urgence sur un bonus"etforbidden_patterns[1] = "conditions de mise (wagering) cachees ou en caracteres minuscules"- HTML observé
promotions.raw.html:<img src="/external_cms/GUINEA/img/Promo/1erDep/BPD_SPORT_1800X600_promotions.jpg">(texte "AUGMENTE TES GAINS JUSQU'À 500 %!" embarqué dans le visuel JPG, donc non extrait par les detectors texte mais visible à l'écran) - HTML observé
promotions.raw.html:Bonus de 1er Dépôt BET224. 100% jusqu'à 1 000 000 GNF en Fun Bonus SportetBonus Cashback BET224. L'essentiel à connaître avant de profiter de l'offre - Source visuelle : -
screenshots/sport-home/desktop.pngzone hero (y ≈ 88-160) : bandeau jaune "GAGNEZ 100 % DE BONUS sur votre 1er dépôt jusqu'à 1 000 000 GNF" + 2e bandeau "10 % CASHBACK chaque semaine jusqu'à 500 000 GNF / PARIEZ ICI" screenshots/promotions/desktop.pngzone hero (y ≈ 40-200) : bandeau jaune "MAXI BONUS / AUGMENTE TES GAINS JUSQU'À 500 % ! / PARIEZ ICI" + 3 cards bonus en dessous (MAXI BONUS, CASHBACK SPORT, WELCOME SPORT) toutes affichant des montants jusqu'à 1 000 000 GNF- Constat :
Le contenu visuel above-fold des 2 routes les plus exposées (homepage sport et promotions) repose intégralement sur des claims de gain interdits explicitement par site-context.yaml. Le verbe "GAGNEZ" en majuscules, l'usage du chiffre "100 %" et le superlatif "JUSQU'À 500 %" tombent dans 3 catégories interdites simultanément : promesse de gain (avoid[1]), bonus 100 % gratuit (claims.forbidden), suggestion de magnitude irrationnelle. Les conditions de mise (wagering) ne sont nulle part visibles above-fold, conformément au forbidden_patterns[1]. Le claim "augmente tes gains" associe directement le bonus à un gain attendu, requalification proche de l'investissement (claims.forbidden "Investissement", "Placement").
- Impact attendu :
Risque réputationnel direct : un livrable produit qui acte ces claims sans correction expose Bet224 à une mise en cause par l'ARSJPA (autorité régulatrice GN identifiée 2026-05-16 mais wording obligatoire non sourcé) et par tout audit indépendant. En conversion pure : la promesse irréaliste augmente la conversion immédiate mais détériore la confiance à long terme et la valeur LTV (joueurs déçus, churn rapide après réalisation des conditions de mise). En conformité moralement attendue dans le secteur (cf KSA NL, MGA MT, Gambling Commission UK), ces claims sont systématiquement sanctionnés.
- Root cause :
Stratégie d'acquisition orientée court terme (taux de conversion sur 1er dépôt), bannières visiblement reprises sans relecture sectorielle. Les visuels sont des JPG dans external_cms/GUINEA/img/Promo/ donc remplaçables sans refonte technique.
F-CONV-01-02 : Aucun lien vers "jeu responsable" / auto-exclusion / mention d'âge dans le footer des 4 routes
- Sévérité : critical
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
conversion-signals/sport-home.json→detailed.trust_signals.legal_linksne contient que[{"text": "Politique de Confidentialité", "href": "/promo/tutte/bet224_politique_confidentialite"}, {"text": "Conditions Générales", "href": "/promo/tutte/bet224_conditions_generales"}]- Pattern identique mesuré sur les 4 routes :
conversion-signals/sport.json,conversion-signals/casino.json,conversion-signals/promotions.json(toutes :trust_signals.legal_links_count = 2, mêmes 2 entries) - Inventaire des
hrefdanssport-home.raw.html(côté seo-audit) : aucunhrefne pointe vers/jeu-responsable,/auto-exclusion,/age,/limites,/aide,/contact. Seuls liens utilitaires :/promotions,/sport,/,Cookies_Policy.pdf site-context.yaml→forbidden_patterns[2] = "absence de lien visible vers jeu responsable / auto-exclusion / limites"etforbidden_patterns[3] = "absence de mention d'age legal (18+ ou seuil legal guineen a confirmer)"- Source visuelle : -
screenshots/sport-home/desktop.pngzone footer (y ≈ 870-900) : seul élément visible est un bouton rouge "OUVRIR PIED DE PAGE" qui déclencherait un footer caché. Footer effectif non visible avant interaction sur tous les screenshots des 4 routes. - Constat :
Aucune des 4 routes ne propose de lien visible vers une page de jeu responsable, d'auto-exclusion, de limites de dépôt, ni de mention d'âge légal. Le footer effectif est dissimulé derrière un bouton "OUVRIR PIED DE PAGE" (cf F-CONV-01-04). Une page /jeu-responsable existe pourtant côté serveur (présente dans le crawl seo-audit historique : jeu-responsable.raw.html), mais elle n'est pas linkée depuis le footer des routes principales. Le pattern correspond exactement à forbidden_patterns[2] et forbidden_patterns[3] de site-context.yaml. Note collatérale : un disclaimer d'âge italien hard-codé existe dans le code (header.disclaimer = "Il gioco è vietato ai minori di diciotto anni..."), référant au régulateur italien ADM, non au régulateur guinéen, et n'est pas affiché en français sur le site visible.
- Impact attendu :
Risque réputationnel et moral majeur sur YMYL gambling : un parieur n'a aucune voie évidente pour s'auto-exclure ou poser des limites, ce qui contredit toute pratique sectorielle responsable (référence : guidelines ARJEL/ANJ FR, KSA NL, MGA MT). Sur le plan régulatoire guinéen, le wording obligatoire ARSJPA n'est pas sourcé en session ; à valider par Legal-check. Sur le plan conversion : pas d'effet direct positif, juste de l'évitement de la responsabilité. Bloque toute logique de fidélisation long terme et expose à des disputes utilisateurs incompréhensibles.
- Root cause :
Footer technique géré par un accordéon (accordion-toggle toggle-nascondi), le lien "OUVRIR PIED DE PAGE" est le seul point d'entrée. Sans interaction, aucun lien légal autre que CGU + politique confidentialité n'est exposé. Volonté délibérée ou héritage de template italien non re-customisé pour GN.
F-CONV-01-03 : "Gains récents" casino, social proof manipulatoire avec montants spécifiques non sourcés
- Sévérité : serious
- Route(s) :
casino - Source primaire :
conversion-signals/casino.json→detailed.social_proof.keywords_detected_count = 0(le detector ne capture pas ce pattern car il cherche "avis", "trustpilot", "étoiles" ; ici c'est un pattern différent, montant + nom joueur masqué)site-context.yaml→voice_and_tone.avoid[1] = "promesse ou suggestion de gain"etforbidden_patterns[4] = "loss disguised as win (animation/son de gain sur une mise perdante)"(cas adjacent : ici on n'a pas mesuré l'animation gain-sur-perte, mais on est dans la même logique de manipulation cognitive)site-context.yaml→claims.forbiddencontient"Gains garantis","Argent facile", etc. : le pattern visuel "Gains récents" avec montants concrets fonctionne comme une suggestion implicite que "ce sera vous demain"- Source visuelle : -
screenshots/casino/desktop.pngzone hero immédiate sous header (y ≈ 60-140) : bandeau horizontal blanc "Gains récents" affichant 5 cards : "Most Wanted - 1 803 313 GNF", "Alexander's Fortune - 200 180 GNF", "Aviator - 30 002 GNF", "AVAJET - 28 441 GNF", "Most W... - 22 532 GNF" (5e tronquée à droite). Photo de visage pixelisé à gauche de chaque montant. - Constat :
La route casino ouvre par un widget "Gains récents" affichant des montants gagnés très spécifiques (1 803 313 GNF en tête). Aucune information ne permet à un utilisateur de vérifier ces gains (ID anonymisé, horodatage, certification tierce, lien vers preuve). C'est une forme de social proof artificielle : la suggestion "d'autres joueurs gagnent maintenant, vous pouvez aussi" est exactement le mécanisme cognitif visé par voice_and_tone.avoid[1] et par claims.forbidden "Gagnez à coup sûr". Sur YMYL gambling, ce pattern est explicitement combattu par les régulateurs européens (UKGC LCCP 2024 §3.4 standards "fair and open advertising", à transposer prudemment au cadre GN non sourcé).
- Impact attendu :
En conversion immédiate : effet d'amorçage positif sur le dépôt (joueur incité à essayer pour reproduire). En conversion long terme : déception et churn quand le pattern réel diverge. Risque réputationnel : tout audit indépendant identifie ce pattern comme manipulation. Risque réglementaire : à valider par Legal-check vs cadre publicitaire ARSJPA non sourcé.
- Root cause :
Widget de "live winners" probablement alimenté en JS dynamique côté backend, courant dans les plateformes de casino white-label. Modifiable au niveau template casino (<div class="...") sans toucher au moteur de jeu.
F-CONV-01-04 : Primary CTA business invisible, bouton "OUVRIR PIED DE PAGE" présent sur 4 routes en above-fold
- Sévérité : serious
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
conversion-signals/sport-home.json→detailed.primary_cta = {"text": "Basketball", "tag": "button", "classes": "in-evidenza__tab", "bbox": {"x": 118, "y": 396}}conversion-signals/sport.json→detailed.primary_cta = {"text": "Previous", "tag": "a", "classes": "carousel-control-prev", "bbox": {"x": 266, "y": 214}}conversion-signals/casino.json→detailed.primary_cta = {"text": "OUVRIR PIED DE PAGE", "tag": "a", "classes": "consulta-footer fissato accordion-toggle toggle-nascondi", "bbox": {"x": 1243, "y": 861}, "background_color": "rgb(178, 17, 22)", "color": "rgb(255, 255, 255)"}conversion-signals/promotions.json→detailed.primary_cta = {"text": "OUVRIR PIED DE PAGE", "tag": "a", "classes": "consulta-footer fissato accordion-toggle toggle-nascondi", "bbox": {"x": 1243, "y": 861}}- HTML observé : présence de
<span onclick="cg_newAccount(true)" class="bottone bottone-login bottone-registrazione">Inscription</span>danssport-home.raw.htmlmais non remonté en primary_cta par le detector (<span onclick>sans href / sans<button>ni<a>, donc invisible aux heuristiques) - Source visuelle : -
screenshots/sport-home/desktop.pngzone header haut-droit (x ≈ 540-720, y ≈ 36-66) : 2 boutons CTAs visibles "Login" (rouge) + "Inscription" (vert) + drapeau "FR". CTAs business attendus, mais détectés comme<span>non-CTA par les detectors. screenshots/casino/desktop.pngmême zone : mêmes 2 boutons "Login" + "Inscription" visibles.screenshots/sport-home/desktop.png,screenshots/sport/desktop.png,screenshots/casino/desktop.png,screenshots/promotions/desktop.png: bouton rouge "OUVRIR PIED DE PAGE" en bas à droite du fold (y ≈ 861-876), texte blanc fondrgb(178, 17, 22)(rouge brand). Contraste OK (≈ 4.7:1). Wording incompréhensible et techniquement faux : ce n'est pas un CTA de conversion, c'est un toggle d'affichage du footer.- Constat :
L'identification automatique du primary CTA produit 4 résultats absurdes : un tab filtre sport ("Basketball"), un contrôle de carrousel ("Previous"), et 2 toggles d'affichage de footer ("OUVRIR PIED DE PAGE"). Les vrais CTAs business attendus (Inscription, Login, Dépôt, Parier) ne sont pas remontés. La cause structurelle est triple : (1) le bouton "Inscription" est codé en <span onclick> au lieu de <button> ou <a>, donc invisible aux heuristiques accessibles ; (2) il n'y a pas de hiérarchie visuelle dominante (taille, isolation) qui placerait un CTA business au-dessus des tabs filtres ; (3) le bouton "OUVRIR PIED DE PAGE" est plus large et coloré que tout autre bouton above-fold, ce qui en fait le candidat le plus visuellement saillant pour les heuristiques basées sur taille+couleur. Wording "OUVRIR PIED DE PAGE" est par ailleurs incompréhensible pour un utilisateur final.
- Impact attendu :
Sur la lecture humaine : les utilisateurs trouvent les CTAs Login/Inscription mais le poids visuel inégal disperse l'attention. Sur l'analyse outillée (audits, A/B testing platforms qui s'appuient sur des heuristiques DOM) : impossible de tracker le vrai funnel d'inscription. Sur la conversion : tout utilisateur tentant de comprendre le footer clique sur le bouton rouge "OUVRIR PIED DE PAGE" en pensant à une action transactionnelle, déception et perte de confiance.
- Root cause :
Choix de coder le bouton "Inscription" en <span onclick> (anti-pattern accessibilité + détection). Naming italien-traduit-mot-à-mot pour le toggle footer ("consulta-footer" → "OUVRIR PIED DE PAGE", devrait être "Voir les informations légales" ou enlevé entièrement avec footer visible par défaut).
F-CONV-01-05 : 43 CTAs "JOUER" identiques sur casino, dilution attentionnelle + risque dark pattern jeu impulsif
- Sévérité : moderate
- Route(s) :
casino - Source primaire :
conversion-signals/casino.json→detailed.ctas[]contient 21 boutons<button class="gioco1__rigaHover__bottoni__bottone gioco1__rigaHover__bottoni--gioca">JOUER</button>(bbox.height = 22, bbox.width = 80, font_size = 12px, font_weight = 600, color = rgb(255,255,255), background_color = rgb(14, 102, 52) = vert)conversion-signals/index.json→per_route[2].ctas_total = 43,per_route[2].ctas_above_fold = 23(casino concentre 43/60 = 72 % de tous les CTAs cumulés des 4 routes)site-context.yaml→forbidden_patterns[6] = "relance automatique de mise / autoplay sans consentement explicite"(cas adjacent : ici on a de la multiplication d'incitations à jouer, pas de l'autoplay technique, mais la logique d'incitation répétée est proche)- Source visuelle : -
screenshots/casino/desktop.pngzone Top 10 (y ≈ 270-370) et zone Évolution (y ≈ 440-560) : grilles de jeux où chaque card affiche au hover un bouton vert "JOUER". Sur la capture full-page on en voit visiblement 7+ (above-fold) puis d'autres en scroll. - Constat :
La page casino affiche 21 boutons "JOUER" identiques (même copy, même style, même taille). Aucune différenciation visuelle entre le 1er et le 21e. Ce pattern dilue l'attention de l'utilisateur (paradoxe du choix), mais surtout banalise l'acte de jouer en le présentant comme aussi anodin que cliquer sur "Lire la suite". En contexte gambling YMYL, cette répétition + accessibilité immédiate du jeu (1 clic) sans étape de confirmation ni rappel des limites est précisément ce que les guidelines responsables découragent.
- Impact attendu :
En conversion immédiate : potentiellement positif (réduction de friction). En conversion long terme et risque utilisateur : favorise le jeu impulsif, contraire à la pratique sectorielle responsable. Risque cognitif pour utilisateurs vulnérables. La répétition est un pattern d'amorçage négatif.
- Root cause :
Template white-label casino où chaque card a son bouton "JOUER" sans alternative (pas de "Voir détails", pas de "Démo gratuite", pas de "Mode entraînement"). Choix produit du template d'origine non re-customisé pour positionnement responsable.
F-CONV-01-06 : Aucun moyen de contact visible (email/téléphone) sur les 4 routes
- Sévérité : moderate
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
conversion-signals/index.json→aggregate.routes_with_contact_email = 0,aggregate.routes_with_contact_phone = 0(4/4 routes sans email ni téléphone visibles)conversion-signals/sport-home.json→detailed.trust_signals.contact_email_visible = false,contact_phone_visible_in_footer = false,contact_links_count = 0- Pattern identique sur les 4 routes (sport, casino, promotions)
- Source visuelle : -
screenshots/sport-home/desktop.png,screenshots/casino/desktop.png: aucun bandeau "Contact", "Support 24/7", "Aide" visible above-fold. Footer caché derrière "OUVRIR PIED DE PAGE" (cf F-CONV-01-04). - Constat :
Aucun email ni numéro de téléphone n'est exposé sur les 4 routes principales. Sur YMYL gambling, l'absence de support visible est un anti-pattern fort : un utilisateur ayant un problème de paiement (dépôt non crédité, retrait bloqué), de fermeture de compte, ou de dispute, n'a aucune voie d'escalade évidente. La page aide.raw.html existe côté serveur historique (présente dans crawl seo-audit) mais n'est pas exposée depuis le footer visible.
- Impact attendu :
En conversion immédiate : neutre. Sur la conversion vers premier dépôt : impact négatif pour les utilisateurs prudents (besoin de pouvoir contacter quelqu'un avant de déposer). Sur la rétention : risque fort, un problème non-résolu = churn et avis négatifs. Sur le plan régulatoire : l'absence de contact visible est typiquement sanctionnée par les régulateurs gambling matures (à valider Legal-check vs ARSJPA).
- Root cause :
Footer caché derrière toggle. Probablement le lien vers /aide ou /contact est dans le footer ouvert, mais inaccessible sans interaction. Architecture template à revoir.
F-CONV-01-07 : Aucun formulaire d'inscription / dépôt / login détecté sur 4 routes ; funnel critique non auditable
- Sévérité : moderate
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
conversion-signals/index.json→aggregate.forms_total_all_routes = 0,aggregate.routes_with_forms = 0,aggregate.max_form_field_count = 0conversion-signals/sport-home.json→detailed.forms = [](pattern identique sur les 4 routes)- HTML observé :
<span onclick="cg_newAccount(true)">Inscription</span>ouvre l'inscription via JS popup ou redirige vers/signup(variable JScg_signupUrl = '/signup'danssport-home.raw.html), pas via un<form>HTML inline - Source visuelle : -
screenshots/sport-home/desktop.pngzone header haut-droit (x ≈ 540-720, y ≈ 36-66) : bouton "Inscription" visible (vert) mais pas de formulaire inline.screenshots/sport/desktop.pngzone latérale droite (x ≈ 600-720, y ≈ 88-300) : encart "Ticket" affiche le wording "Pour effectuer un pari, ajoutez les paris souhaités" mais aucun formulaire visible. Aucun formulaire d'inscription / dépôt / login n'est visible above-fold sur les 4 captures. - Constat :
Aucun des 4 crawls n'a capté de formulaire. Le funnel d'inscription est probablement modal ou redirige vers /signup (non crawlé dans cette passe). Cela bloque l'analyse de longueur de formulaire, labels accessibles, autocomplete, types de champs (<input inputmode="numeric"> pour téléphone GN, etc.). Conséquence directe pour ce POC : la friction d'onboarding ne peut pas être mesurée, les findings forms_with_unlabeled_fields cross-angle A11Y restent à zéro (faux négatif structurel).
- Impact attendu :
Audit conversion incomplet : la friction du formulaire d'inscription est typiquement le 1er levier d'optimisation conversion gambling (cf benchmarks UKGC 2023 : la longueur du signup forme expliquait 23 % de la variance du drop-off ; transposition prudente au cadre GN). Sans capture de /signup, impossible de prioriser une reco "réduire le nombre de champs" ou "ajouter autocomplete".
- Root cause :
Routes auditées par le POC ne couvrent pas /signup ni les modales d'inscription / dépôt. À étendre dans une passe v2 (cf ## Limites & non-couvert).
F-CONV-01-08 : Cookie banner sans option "Refuser" granulaire, consent forcé
- Sévérité : moderate
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
- Détection visuelle directe sur les 4 screenshots desktop (le detector conversion-signals v1.2 ne capture pas les cookie banners ; v1.2 limites connues :
Pas de détection de friction (popups, cookie banners, modals z-index)) site-context.yaml→facts.to_confirmmentionne explicitement :"Cadre data / cookies de profilage applicable en Guinee + politique de confidentialite"avec note :"Le site sert un bandeau annoncant des 'cookies de profilage tiers' sans page politique de confidentialite accessible (route 404). Cadre data guineen a valider juridique client"- Source visuelle : -
screenshots/sport-home/desktop.pngzone bandeau top (y ≈ 0-22) : bandeau noir "Ce site utilise des cookies, y compris des cookies de profilage tiers. Si vous souhaitez en savoir plus ou désactiver certains ou tous les cookies, lisez les informations. En poursuivant votre navigation, vous acceptez l'utilisation de tous les cookies." avec UN SEUL bouton "OK" (vert) + lien "Plus d'informations" (bleu) - Pattern identique visible sur les 4 routes
- Constat :
Le bandeau cookie présente un seul bouton "OK", sans alternative "Refuser" ni granularité (cookies fonctionnels vs analytics vs profilage tiers). Le texte affirme "En poursuivant votre navigation, vous acceptez l'utilisation de tous les cookies", pattern de consent passif explicitement contesté par les guidelines européennes (CNIL FR 2020, ePrivacy révisée). Sur le cadre data guinéen non sourcé, le risque légal est à valider par Legal-check, mais le pattern est moralement non-conforme aux standards internationaux.
- Impact attendu :
Risque réputationnel + utilisateur frustré (impossibilité de refuser). Risque légal à valider Legal-check (cadre data GN non sourcé). Effet sur la conversion : neutre direct, mais détérioration de la confiance.
- Root cause :
Template historique italien probablement, où le consent passif "by continuing" était toléré jusqu'à RGPD 2018. Non re-customisé pour standards 2024+.
Cross-angle dependencies
- F-CONV-01-01 (promesses de gain interdites bandeaux) recoupe potentiellement
[REF: DEEP-TRUST-NN/F-XX](cadre publicitaire ARSJPA non sourcé). Si DEEP-TRUST identifie une obligation guinéenne, R-CONV-01-01 passe à conformité légale true et priorité HIGH. Cross-référence aussi[REF: DEEP-A11Y-01/F-04 et F-05]: les bannières promo sont des<img>sans alt, donc invisibles aux lecteurs d'écran. Reco fusionnée possible : refonte des bannières JPG en HTML/CSS responsives accessibles (résoudrait simultanément CONV et A11Y). - F-CONV-01-02 (absence jeu responsable footer) recoupe
[REF: DEEP-TRUST-NN/F-XX](mentions légales obligatoires gambling GN). Reco R-CONV-01-02 = même action que la reco TRUST attendue. À fusionner parassemble_audit.py. - F-CONV-01-04 (primary CTA cassé + span onclick) recoupe
[REF: DEEP-A11Y-01/F-XX](button-name / link-name violations probables sur<span onclick>). À vérifier dans DEEP-A11Y-01 : siaxe-results/<slug>/desktop.json→violations[].id = "button-name"ou"link-name"cible le sélecteur du bouton Inscription, fusion R-CONV-01-04 + R-A11Y correspondante en une seule reco "transformer<span onclick>en<button>ou<a>accessible". - F-CONV-01-04 (wording "OUVRIR PIED DE PAGE") recoupe
[REF: DEEP-UX-NN/F-XX](clarté de la navigation + wording incompréhensible). Reco UX et CONV identiques sur ce point. - F-CONV-01-05 (43 CTAs "JOUER" casino) recoupe potentiellement
[REF: DEEP-UI-NN/F-XX](densité visuelle, manque de hiérarchie). Et[REF: DEEP-MOBILE-NN/F-XX]car en mobile la densité sera encore plus problématique (touch targets 22px de hauteur, sous le minimum WCAG 2.5.5 = 44×44px AA, déjà cross-référable avec A11Y). - F-CONV-01-06 (absence contact visible) recoupe
[REF: DEEP-TRUST-NN/F-XX](mentions contact obligatoires + support gambling). - F-CONV-01-08 (cookie consent passif) recoupe
[REF: DEEP-TRUST-NN/F-XX](cadre data + politique confidentialité 404). Reco fusionnable.
Limites
- Funnel signup/login/dépôt/retrait non crawlé : POC 4 routes (sport-home, sport, casino, promotions) ne couvre pas les routes
/signup,/login,/depot,/retrait, page détail match, page détail jeu. Conséquence : aucune analyse de longueur de formulaire, labels accessibles, autocomplete, types de champs. Cf R-CONV-01-06 pour étendre. - Mobile non audité (POC desktop only) : tous les screenshots et conversion-signals sont en viewport 1440×900. Le persona est explicitement "très majoritairement mobile" (
site-context.yaml). Tous les findings CTA above-fold ratio, primary CTA, touch targets pour casino "JOUER" 22px doivent être ré-évalués en viewport 390×844. Cross-angle MOBILE attendu. - Analytics client non fournies : pas de GA, Posthog, Hotjar fournis par le client. Tout drop-off funnel est hypothétique (basé sur benchmarks sectoriels prudents). Une passe v2 avec data analytics client permettrait de prioriser RICE objectivement.
- Wagering / conditions de mise non lues : les bonus mentionnent des montants (100 % jusqu'à 1 000 000 GNF) mais les conditions de mise (mise minimum, multiplicateurs, durée de validité) ne sont pas dans le crawl 4 routes. Probablement dans
/bonus,/conditions,/cgu(existent côté seo-audit historique). À valider dans une passe v2 + Legal-check. - Cadre publicitaire ARSJPA non sourcé : l'ARSJPA est identifiée comme régulateur GN (cf site-context.yaml
external_authorities[VERIFIE WebFetch 2026-05-16]) mais le wording exact des mentions obligatoires (âge légal, jeu responsable, identifiant licence) n'est pas extrait. Bloque la requalification des recos en "Conformité légale : true". À sourcer Legal-check. - Status agrément Bet224 : présence ou non sur la liste "Plateformes agréées" de l'ARSJPA non vérifiée. Aucune conclusion sur le statut légal de l'opérateur ne peut être portée. Cf
facts.to_confirmsite-context.yaml. - Detector primary_cta : faux positifs structurels : le detector retient le 1er CTA en lecture d'ordre DOM matching heuristique de poids visuel (taille + position above-fold). Sur les 4 routes, le vrai primary CTA business (Inscription / Login en
<span onclick>) n'est pas détecté car non-<button>/ non-<a>accessible. Limite à corriger côté tool product-audit (analyze_conversion_signals.pyv1.3 : matcher aussi les<span onclick>+[role="button"]interactifs). - Social proof "Gains récents" non capturée par detector v1.2 : le detector v1.2 cherche keywords "avis", "trustpilot", "étoile" pour
social_proof. Le pattern "live winners avec montants" n'est pas dans la heuristique. Finding F-CONV-01-03 source exclusivement visuelle (screenshot). Limite à étendre côté tool product-audit v1.3. - Cookie banner non capturé par detector v1.2 : limite documentée dans
schemas-product-audit-v1.0.mdv1.1 section "Limites connues v1.1". Finding F-CONV-01-08 source exclusivement visuelle (screenshot). - Disclaimer italien hard-codé
header.disclaimer: présent dans le code (Il gioco è vietato ai minori di diciotto anni... Consulta le probabilità di vincita sul sito ADM) mais référencie le régulateur italien ADM. Pas affiché en français sur les écrans visibles. À expertiser par Legal-check : (a) ce texte est-il jamais affiché à l'utilisateur ? (b) est-il un résidu de template italien ? (c) faut-il le re-traduire pour cadre GN avec wording ARSJPA quand sourcé ?
Angle : MOBILE
Persona
Source : site-context.yaml voice_and_tone.persona_primary = "Parieur sportif en Guinee, tres majoritairement mobile, interesse par le football en priorite".
sport-home: parieur GN sur téléphone, intent "découvrir l'offre du jour, choisir une compétition". Le layout desktop observé montre une nav horizontale avec 7 onglets primaires (Sports / Virtuel / Promo / Casino+ sous-tabsPREMATCH / LIVE / MULTIBET / EVENEMENTS / MULTILIVE / CALENDRIER). À 390px de large, cette densité d'onglets ne tient pas sans hamburger ou collapse non observable ici.sport: même persona, intent "construire un pari combiné sur une compétition". Le layout desktop est 3 colonnes (rail gauche sports, centre matchs, rail droit "Ticket" 244px). À 390px, ce layout 3 colonnes ne tient pas ; la stratégie d'adaptation (stacking, tabs, drawer "Ticket") n'est pas observable depuis le crawl desktop.casino: persona élargie joueur casino. Carrousels de jeux multiples avec flèches de scroll horizontal. Sur mobile, les flèches sont théoriquement remplacées par swipe natif, mais lemeta-viewportinjecté dynamiquement par le widget casino bloque le zoom (cf F-MOBILE-01-01), ce qui contredit la posture mobile-first attendue. Route YMYL sensible : la dégradation mobile augmente la friction d'accès aux conditions de jeu.promotions: persona en intent "découvrir un bonus avant inscription". 3 CTAs détectés desktop dont le sélecteur de langue (FR50x16). Le rendu mobile des visuels bonus (carrousels) n'est pas observable. La conformité YMYL (lisibilité des conditions de wagering sur petit écran) est non instruisable ici.
Synthèse exécutive
- Inputs mobile primaires absents : 0 screenshot mobile, 0 axe mobile run, 0 mesure CrUX
form_factor=PHONEsur les 4 routes. Source :axe-results/index.json→results[].mobile.path = Nonepour les 4 routes ;results[].mobile.passes_count = 0. La persona étant majoritairement mobile (cfsite-context.yaml), c'est un gap critique pour un audit produit livré. - Viewport meta cassé sur
/casinouniquement : un second tag<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1">est injecté dans le DOM rendu (probablement par le SDK casino), bloquant le zoom mobile. Source :axe-results/casino/desktop.json→violations[].id = "meta-viewport",failureSummary = "maximum-scale on <meta> tag disables zooming on mobile devices". WCAG 1.4.4 AA (Resize text) non respectée sur/casino. - Touch targets desktop sous le seuil 44x44 WCAG 2.5.5 AA : 22 CTAs sur 60 ont une dimension < 44px sur au moins un axe (height ou width), dont 7 "JOUER" 80x22 sur
/casino(height 22 = 50 % du seuil) et 8 boutons de carrousel 32x32. Source :conversion-signals/casino.json→detailed.ctas[4..10].bbox.height = 22,detailed.ctas[0..3,11..12].bbox = 32x32. Probabilité de fail mobile élevée vu que la dégradation rarement améliore les tailles. Indication indirecte, pas mesure mobile. - Aucun pattern responsive moderne détecté dans le HTML serveur : 0
@media, 0srcset, 0sizes, 0loading="lazy", 0inputmodedétectés sur les 4 raw HTML. Source : grep multi-fichiers surseo-audit/.../crawl/html/{sport-home,sport,casino,promotions}.raw.html. Le CSS chargé est/css/desktop/...(cfaxe-results/sport-home/desktop.json→ raw HTML L36-37). Cela suggère une stratégie UA-sniffing côté serveur avec un sous-dossier/css/mobile/...séparé, plutôt qu'un responsive design CSS unifié. Non vérifiable sans crawl mobile UA. - 0 forms détectés sur les 4 routes :
conversion-signals/index.json→aggregate.forms_total_all_routes = 0. Les pages inscription / login / dépôt ne sont pas dans le scope POC, donc impossible d'évaluer les patterns mobile critiques (<input type="tel">,inputmode="numeric",autocomplete="tel-national"). Bloquant pour évaluer le funnel de conversion mobile.
Findings
F-MOBILE-01-01 : Viewport meta /casino bloque le zoom mobile (maximum-scale=1)
- Sévérité : serious
- Route(s) :
casino - Source primaire :
axe-results/casino/desktop.json→violations[].id = "meta-viewport",impact = "moderate",nodes[0].html = "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1\">",nodes[0].any[0].message = "maximum-scale on <meta> tag disables zooming on mobile devices",nodes[0].target = ["meta[name=\"viewport\"]:nth-child(118)"]- Raw HTML
seo-audit/.../bet224/crawl/html/casino.raw.htmlL23 :<meta name="viewport" content="width=device-width, initial-scale=1">(un seul viewport meta côté serveur, conforme). Le second meta avecmaximum-scale=1est injecté côté client par le SDK casino (cf selector:nth-child(118)indique une position tardive dans<head>). - Pattern absent sur les 3 autres routes :
sport-home,sport,promotionsn'ont pasmeta-viewportdans leurs violations axe. - Source visuelle : -
screenshots/casino/desktop.png: capture desktop seulement, pas de visualisation possible du blocage zoom mobile. - Constat :
Le SDK casino injecte un second <meta name="viewport"> avec maximum-scale=1, minimum-scale=1 qui désactive le zoom utilisateur sur mobile. Le viewport serveur initial (L23 raw HTML) est correct. Le tag dupliqué prend précédence (dernier déclaré gagne) ; un parieur GN mobile sur /casino ne peut donc pas zoomer pour lire un libellé de jeu ou les conditions affichées en petit corps.
- Impact attendu :
WCAG 1.4.4 (Resize text) niveau AA non respectée sur /casino. Pour un parieur avec baisse d'acuité visuelle (presbytie courante > 45 ans, audience parieurs adultes), la fonction zoom navigateur native est bloquée. Sur route YMYL avec libellés de jeu et conditions affichés en corps réduit, c'est un signal de dégradation produit. Effet collatéral : iOS Safari force le zoom au focus d'un input < 16px font-size si maximum-scale=1 absent ; en bloquant le zoom on prévient AUSSI ce zoom-au-focus, ce qui peut être intentionnel côté SDK casino (jamais bonne pratique pour autant).
- Root cause :
SDK casino tiers injecte un viewport meta dans le DOM rendu sans tenir compte du viewport déjà déclaré par le template hôte. Fix : (1) intercepter l'injection si l'éditeur du SDK l'expose en config, (2) sinon override post-injection par un MutationObserver qui retire maximum-scale=1 du tag dupliqué, (3) escalader chez l'éditeur du SDK.
F-MOBILE-01-02 : 17+ touch targets desktop sous le seuil WCAG 2.5.5 AA (44x44px)
- Sévérité : serious
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
conversion-signals/casino.json→detailed.ctas:- Indices 0-3, 11-12 : 6 boutons carrousel à
bbox = {width: 32, height: 32}aux y=191, 373, 604 (les flèches de scroll horizontal des sections "Gains récents", "Spribe Games", "Top 10") - Indices 4-10, 13-14 : 9 boutons "JOUER" à
bbox = {width: 80, height: 22}(height = 50 % du seuil) conversion-signals/sport-home.json→detailed.ctas:- Index 2 : CTA sans texte
bbox = {width: 50, height: 15}y=7 (probablement bouton barre cookies) - Index 3 : sélecteur "FR"
bbox = {width: 45, height: 16}y=80 (height = 36 % du seuil) - Indices 0, 1 : onglets "Football" 101x42, "Basketball" 118x42 (height 42 < 44, fail marginal)
conversion-signals/sport.json→detailed.ctas[1]: "FR" 45x16 +[6]"OUVRIR PIED DE PAGE" 152x25conversion-signals/promotions.json→detailed.ctas[0..2]: 3 CTAs dont sélecteur cookies, "FR", footer toggle, tous height ≤ 39px- Source visuelle : -
screenshots/casino/desktop.png: carrousels visibles avec flèches noires en haut à droite de chaque rangée (zone ~x=1356-1428, y=191 / 373 / 604) ; boutons "JOUER" non visibles sur la capture (état hover sur survol vignette, déclenché côté JS). screenshots/sport-home/desktop.png: sélecteur "FR" visible top-droit (zone ~x=1377, y=80), onglets "Football / Basketball" à y=396.- Constat :
Sur la mesure desktop (viewport 1366x900), au moins 17 CTAs ont au minimum une dimension < 44px : tous les boutons "JOUER" du casino (80x22), toutes les flèches de scroll horizontal (32x32), les sélecteurs cookies/FR (≤ 16px de haut). WCAG 2.5.5 (Target Size) AA exige 44x44 minimum sauf cas d'exception (essential, inline, ou user-agent control). Sur mobile, la dégradation typique soit garde les dimensions desktop si CSS non adapté (échec WCAG renforcé sur cibles tactiles), soit applique un layout mobile avec ses propres tailles non mesurées ici.
- Impact attendu :
Friction tactile mobile élevée. Un parieur GN sur téléphone tente de taper "JOUER" sur une vignette casino : sur un index 80x22 dans le layout desktop, la cible est sous-dimensionnée et le risque de mis-tap (tap sur la vignette adjacente, ouverture d'un autre jeu, frustration) est élevé. Pour le scroll horizontal des carrousels casino, le pattern usuel mobile est swipe natif (pas de besoin de flèches 44x44), MAIS si les flèches restent rendues elles deviennent des cibles fantômes < 44px. Conformité WCAG 2.5.5 AA fail probable mais NON CONFIRMÉE faute d'axe mobile.
- Root cause :
Design tokens basés sur des dimensions desktop pixel-perfect (32px flèches = icônes Font Awesome 5.6.3 cf raw HTML L37, 22px "JOUER" = padding réduit pour densité). Pas de variant mobile des touch zones détectable dans le CSS chargé (/css/desktop/). Fix : soit min-height: 44px sur les .componenteGioco__navigatore__tasto et les CTAs JOUER, soit ajouter un padding invisible (padding: 11px sur un container interactif) pour étendre la zone tactile sans modifier le visuel.
F-MOBILE-01-03 : Aucun pattern responsive moderne détecté dans le HTML serveur
- Sévérité : moderate
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
- Grep multi-fichiers sur les 4 raw HTML (
seo-audit/.../bet224/crawl/html/{sport-home,sport,casino,promotions}.raw.html) pour les patterns :@media,srcset,sizes=,loading="lazy",inputmode→ 0 occurrence cumulée sur les 4 fichiers. - Raw HTML
seo-audit/.../bet224/crawl/html/sport-home.raw.htmlL36 :<link rel="stylesheet" href="/css/desktop/third-party/bootstrap.min.css?v=20260304016">(chemin contient/desktop/). - Raw HTML idem L37 :
<link rel="stylesheet" href="/css/desktop/third-party/fontawesome-5.6.3/css/all.min.css?v=20260304016">. - Raw HTML idem L139 :
<link rel="stylesheet" href="/css/desktop/base.jsp?v=20260304016">(fichier serveur JSP, donc dynamique côté backend). index.jsoncrawl →viewport: {width: 1366, height: 900},user_agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) ... Chrome/148.0.0.0 ...": crawl effectué en UA desktop, le serveur a donc renvoyé la version desktop. Pas de crawl en UA mobile pour vérifier si/css/mobile/...existe.- Source visuelle : - N/A (constat structurel HTML, pas visuel).
- Constat :
Les 4 pages servies en UA desktop ne contiennent aucun media query inline, aucun srcset / sizes sur les images, aucun loading="lazy", et chargent du CSS via /css/desktop/.... Le stylesheet base.jsp est dynamique serveur (JSP). Forte présomption d'une architecture UA-sniffing serveur (le backend détecte le UA et renvoie un layout HTML/CSS desktop ou mobile distinct), pas d'un responsive design unifié. Cette présomption N'EST PAS CONFIRMÉE faute de crawl avec UA mobile.
- Impact attendu :
Une architecture UA-sniffing produit typiquement deux codebases à maintenir, deux états visuels distincts, et un risque élevé de divergence (le fix viewport /casino ne s'applique peut-être qu'au layout desktop, le mobile pourrait être OK ou pire). SEO impact : Google recommande le responsive design depuis 2015 comme bonne pratique mobile-first indexing. Conversion impact : les bookmaker leaders (Bet365, William Hill, Betfair) sont passés au responsive depuis 2018-2020.
- Root cause :
Plateforme historique (probablement Microgame / Playtech / IGT-style legacy iGaming platform) avec backend JSP rendant deux templates distincts selon UA. Fix : à arbitrer entre (1) migration responsive design (réécriture majeure), (2) maintenance du UA-sniffing avec audit mobile dédié (palliative), (3) recapture POC en V2 audit pour décider sur base mesurée.
F-MOBILE-01-04 : Forms inscription / login / dépôt absents du scope POC, parcours conversion mobile non instruisable
- Sévérité : moderate
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
conversion-signals/index.json→aggregate.forms_total_all_routes = 0,routes_with_forms = 0,max_form_field_count = 0conversion-signals/{sport-home,sport,casino,promotions}.json→detailed.forms = []sur les 4 routesindex.jsoncrawl → 4 routes danspages[]:sport-home,sport,casino,promotions. Aucune route/inscription,/login,/depot,/retrait.- Source visuelle : -
screenshots/sport-home/desktop.png: boutons "Login" rouge + "Inscription" vert visibles top-droit (zone ~x=580-720, y=40-65), liens vers les pages d'auth. - Constat :
Le scope POC couvre 4 routes vitrine. Aucun formulaire (inscription, login, dépôt, retrait, paramètres compte) n'est crawlé ni audité. Les évaluations mobile critiques sur les forms (<input type="tel"> pour téléphone, inputmode="numeric" pour montant, autocomplete="tel-national email new-password", taille minimum des champs 44px de haut, gestion du clavier mobile par type d'input) sont impossibles. Or, pour un parieur GN majoritairement mobile, le formulaire d'inscription est le premier point de friction critique entre acquisition et conversion.
- Impact attendu :
Le funnel de conversion mobile (acquisition vitrine → inscription → premier dépôt → premier pari) n'est pas auditable dans le périmètre actuel. C'est la zone où les leaders iGaming investissent le plus (one-tap signup, KYC progressif, Apple Pay / Google Pay sur mobile). Sans crawl de ces pages, on ne peut pas chiffrer la friction réelle ni la dette mobile sur le funnel.
- Root cause :
Scope POC volontairement restreint à 4 routes vitrine pour valider la méthodologie product-audit. V2 audit doit étendre le scope au funnel d'inscription minimum (acquisition + signup + login + premier dépôt), avec capture mobile (390x844 DPR=3) et axe mobile sur chaque page.
Cross-angle dependencies
- F-MOBILE-01-01 (viewport
maximum-scale=1sur/casino) recoupe[REF: DEEP-A11Y-01/Synthèse exécutive bullet 4](axe casinometa-viewportflag, WCAG 1.4.4 AA non respectée). La recoR-MOBILE-01-02(override client-side) résout simultanément le finding A11Y. À fusionner parassemble_audit.pyen une reco unique avec contributions cross-angle ; le porteur principal de la reco peut rester A11Y (axe est la source primaire). - F-MOBILE-01-02 (touch targets < 44x44) recoupe
[REF: DEEP-CONV-NN/F-NN](à confirmer post-DEEP-CONV : si DEEP-CONV identifie les boutons "JOUER" comme CTA primaire conversion, la sous-dimension est un signal conversion en plus du signal accessibilité). À fusionner parassemble_audit.pysi DEEP-CONV produit un finding similaire ; sinon dépendance simple flag dans la roadmap. - F-MOBILE-01-03 (pas de pattern responsive moderne) recoupe
[REF: DEEP-PERF-NN/F-NN](à confirmer post-DEEP-PERF : sanssrcset/sizes/loading="lazy", les images mobiles sont probablement chargées en taille desktop, dégradant LCP mobile). Cross-angle conflit potentiel : la recoR-MOBILE-01-04(arbitrage architecture) impacte aussi PERF et SEO. Escalader au red team Coverage et UX-check pour arbitrage stratégique avant assemble final. - F-MOBILE-01-04 (forms hors scope) recoupe
[REF: DEEP-CONV-NN/F-NN](le funnel d'inscription/conversion est par définition l'angle CONV). Si DEEP-CONV-01 produit déjà un finding sur l'absence de forms crawlés, fusionner. Sinon DEEP-MOBILE-01 et DEEP-CONV-01 portent tous les deux la recoétendre le scope V2.
Limites
Cette section est volontairement détaillée. Le POC product-audit bet224 est largement dégradé sur l'angle MOBILE et l'honnêteté radicale sur les inputs manquants est prioritaire sur la complétude apparente des findings.
Inputs primaires mobile NON CAPTURÉS dans le POC :
- Screenshots mobile (390x844, DPR=3, format PNG 1170x2532) : aucun fichier
screenshots/<slug>/mobile.pngn'existe sur les 4 routes. Source :axe-results/index.json→viewport_mobileest déclaré maisresults[].mobile.path = Nonepartout. Sans capture mobile, aucune évaluation visuelle de l'overflow horizontal, du hamburger menu, du sticky CTA mobile, des modales mobile, du carrousel swipe, n'est possible. Tous les findings UX/UI mobile sont inférés depuis le desktop ou non instruisables.
- Axe-core run mobile :
axe-results/<slug>/mobile.jsonabsent sur les 4 routes. La règletarget-size(WCAG 2.5.5 AA, mesure des touch targets) est précisément faite pour le mobile et n'a pas été exécutée. Les violations potentielles (overflow, sticky issues, mobile-specific rules) sont non mesurées.
- CrUX (Chrome User Experience Report)
form_factor=PHONE:crux.jsonabsent. Sans données terrain mobile, le score Core Web Vitals mobile (LCP p75, INP p75, CLS p75) est inconnu. Leindex.jsondu crawl donne des métriques desktop synthétiques (TTFB 96-138ms, DCL 273-466ms, load_event 276-488ms) qui ne sont pas représentatives du mobile (réseau 4G/3G Guinée vraisemblablement plus lent).
page-signals/<slug>.signals.json: non généré (schemas_versions.signals: "not_run"). Champs critiques mobile non extraits :viewport_meta(valeur exacte),touch_targets(count mesuré côté serveur),responsive_images(count d'images avecsrcset),mobile_specific_links(présence d'un éventuel lien versm.bet224.gnsi UA-sniffing).
- Crawl en UA mobile (User-Agent iPhone Safari iOS 17) :
index.jsondu crawl atteste UA desktop Chrome Windows. Aucune passe en UA mobile. Si le backend fait UA-sniffing, il a renvoyé sa version desktop uniquement. L'architecture mobile réelle (responsive, UA-sniffing serveur, ou m.bet224.gn distinct) ne peut être confirmée.
Patterns mobile NON OBSERVABLES depuis les inputs disponibles :
- Hamburger menu : présence, position (header / fixed bottom), animation d'ouverture, focus trap.
- Sticky bottom CTA (pattern courant iGaming mobile) : présence, comportement au scroll, masquage / réapparition.
- Modales et bottom sheets : design, gestion du fond, focus return.
- Carrousels swipe natif : présence, indicateurs de progression, gestion gestures.
- Pull-to-refresh : présence (anti-pattern sur certaines apps web bookmaker), comportement.
- Notifications push web : sollicitation au load (anti-pattern), demande de permission contextualisée.
- Cookie banner mobile : taille relative écran, modalité de refus (1-tap vs cascade).
- Age-gate mobile (YMYL gambling) : présence, ergonomie, blocage avant catalogue.
Inférences indirectes (à confirmer en V2 audit) :
- Architecture UA-sniffing présumée (cf F-MOBILE-01-03) : à confirmer par crawl mobile UA.
- Touch targets mobile < 44x44 (cf F-MOBILE-01-02) : projection depuis desktop, à confirmer par axe mobile sur viewport 390x844.
- Performance mobile dégradée vs desktop : présumée vu absence de
loading="lazy"et desrcset, à confirmer par CrUXform_factor=PHONEou PageSpeed Insights strategy mobile. - Forms inscription / login / dépôt mobile : 0 form auditable dans le scope POC (4 routes vitrine), parcours conversion mobile entièrement non instruit.
Sub-agent à re-lancer : DEEP-MOBILE-02 en V2 audit après recapture mobile complète (R-MOBILE-01-01 livrable). DEEP-MOBILE-01 (ce document) reste valable comme baseline d'inventaire des manques.
Angle : PERF
Persona
Source : site-context.yaml voice_and_tone.persona_primary = "Parieur sportif en Guinée, très majoritairement mobile, intéressé par le football en priorité".
sport-home: parieur arrive depuis une recherche, un lien externe, ou la racine. Premier contact visuel avec la marque, doit voir l'offre du jour vite. Sur un réseau 4G guinéen avec latence backbone Europe→Guinée (RTT typique > 200 ms à Conakry vers une infra EU), le coût des stylesheets render-blocking et de jQuery synchrone en<head>est multiplié par RTT × nombre de roundtrips. C'est précisément la route où une seconde de plus tue la conversion.sport: persona en intent "construction d'un pari" sur une compétition. Page la plus lourde fonctionnellement (605 mots vs 221 sur sport-home, widget Betbuilder, accordion compétitions). Avec un load_event mesuré à 470 ms en local, le facteur multiplicateur en field mobile Guinée doit être appliqué (cf Limites).casino: route YMYL secondaire, contenu visuel chargé (5 carrousels de jeux, full-page 1629 px = 1,8× plus haut que les autres). Risque CLS élevé en field (carrousels images sans dimensions, chargement Spribe / Evolution iframes potentielles), risque INP élevé (boutons de carrousel sansaria-labelET sans listeners optimisés cf F-A11Y-01-03).promotions: route d'acquisition pré-inscription. Le visiteur doit voir les 5 visuels promotionnels (bonus 500 %, cashback, welcome) rapidement pour évaluer l'offre. Aujourd'hui, ces visuels sont des<img>sansloading="lazy"niwidth/heightnisrcset, ce qui multiplie le risque LCP tardif + CLS au moment où le visiteur tente de cliquer un bonus.
Synthèse exécutive
- Timings réseau crawler (Chromium desktop, IP non-Guinée, pas de throttling) : load_event entre 275 ms (casino) et 488 ms (promotions). TTFB entre 96 ms (sport-home) et 138 ms (sport). Source :
crawl/index.json→pages[].ttfb_ms,dcl_ms,load_event_ms. Ces valeurs sont lab-en-local, à NE PAS confondre avec ce que vit le persona mobile Guinée. Aucune projection field n'est possible sans CrUX. - 5 stylesheets bloquants en
<head>+ 1 conditionnel (dark mode) + 1 tardif (toast.css), sanspreloadnimediapartitionné. Mesuré :sport-home.raw.htmllignes 36, 37, 139, 140, 141, 144, 866. Pattern identique sur les 4 routes (template commun). Chaque CSS bloque le first paint jusqu'à téléchargement + parse. - 7 scripts JS chargés SYNCHRONE en
<head>(jQuery 3.7.1, contogioco-services, gsap, sweetalert2, jsCookie + 2 conditionnels IE legacy), un seul script avecdefer(third-party.jsp). Mesuré :sport-home.raw.htmllignes 145-154. jQuery 3.7.1 minified pèse [À VÉRIFIER : ~85 KB] non compressé ; les 5 libs synchrones additionnées sont une cause racine plausible d'un FCP / LCP dégradé en mobile. - GTM injecté en script inline en
<head>ligne 8-12 (avant tout meta-viewport et avant le<title>). En state-of-the-art 2026, GTM se charge en<head>mais ne devrait pas précéder les meta critiques. Le snippetgtag.jsest correctementasync(ligne 15) mais sa consommationgtag('config', ...)inline ligne 16-21 ré-exécute du JS bloquant. - 4
<img>par route, AUCUNE avecloading="lazy"niwidth/heightnisrcset/<picture>. Mesuré :sport-home.raw.htmllignes 362, 389, 453, 458 (img src=sans aucun de ces attributs). Conséquence directe : risque CLS structurel + sur-téléchargement above-the-fold + pas de variante mobile servie au persona mobile. - Aucun
<link rel="preconnect">nidns-prefetchnipreloadsur les origines critiques (www.googletagmanager.com, polices, CSS first-party). Mesuré : greppreload|preconnect|dns-prefetchsursport-home.raw.html= 0 occurrence. Connexion TLS au CDN Google + tag manager faite en série, pas en parallèle. - Casino full-page = 1629 px (vs 900 sur les 3 autres routes), screenshot PNG = 1063 KB. Source :
screenshots/index.json→captures[2].desktop_full_height_px = 1629. Indicateur de poids visuel : la page rend ~1,8× plus de contenu visible, ce qui implique probablement davantage d'images casino + carrousels au-dessus du fold et juste en dessous.
Findings
F-PERF-01-02 : 7 scripts JS synchrones en <head> (jQuery, GSAP, SweetAlert, contogioco-services, jsCookie)
- Sévérité : critical
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
raw_html_sport_homelignes 145-154 (idem casino, sport, promotions, c'est un template) :<script src="/js/desktop/third-party/html5shiv-3.7.3.min.js?v=20260304016">(conditionnel IE, mais présent en commentaire<!--[if IE]>qui n'est plus interprété en HTML5 / browsers modernes, donc le tag n'est pas chargé ; à vérifier en lab)<script src="/js/desktop/third-party/jquery-3.7.1.min.js">synchrone<script src="/js/contogioco-services.js">synchrone<script src="/js/gsap.min.js">synchrone<script src="/js/sweetalert2.min.js">synchrone<script src="/js/jsCookie.min.js">synchrone<script defer src="/js/desktop/third-party.jsp">(seul scriptdefer)- Pattern identique sur les 4 routes (template commun).
- Source visuelle : - Non applicable directement.
- Constat :
Cinq libraries JS first-party / vendor sont chargées synchrones en <head>, donc chaque téléchargement + parse + exécution bloque le DOMContentLoaded. Aucune de ces libs n'est requise pour le first paint (jQuery, GSAP, SweetAlert, jsCookie sont des utilities runtime). Le seul script avec defer est third-party.jsp qui paradoxalement est probablement le moins critique pour FCP.
- Impact attendu :
Mesuré localement : DCL entre 273 ms (casino) et 466 ms (promotions). En field mobile Guinée, le facteur multiplicateur attendu sur ces libs synchrones est important (parse JS sur CPU mid-range, latence d'attente sur chaque tag). Estimation prudente : DCL field mobile probable entre 1,5 s et 4 s sur 4G médian (non vérifié, à valider via CrUX). Conséquence : TTI dégradé, INP probablement médiocre (jQuery + GSAP réveillés à chaque interaction).
- Root cause :
Template historique (probablement migré depuis IE-supporting era, cf html5shiv et respond.js legacy IE polyfills toujours présents). Aucune passe d'optimisation perf moderne (defer / async / module split / dynamic import) appliquée.
F-PERF-01-01 : 5 à 7 stylesheets render-blocking en <head> sur les 4 routes
- Sévérité : serious
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
raw_html_sport_homelignes 36-37, 139-144 : 6<link rel="stylesheet">chargés sansmediapartitionné nipreload. Listing :bootstrap.min.css,fontawesome-5.6.3/css/all.min.css,base.jsp,default_contogioco_desktop.css,adeguamento.css,adeguamento_dark.css(disabled mais déclaré).raw_html_sport_homeligne 866 : 7e stylesheettoast.csschargé dans le body (donc bloquant l'idle de la page).- Pattern identique sur
raw_html_casinolignes 37-38, 140-144, 910 (idem) ;raw_html_sport;raw_html_promotions. - Source visuelle : - Non applicable directement (effet sur FCP / LCP, non visible sur screenshot statique).
- Constat :
6 à 7 feuilles de style bloquent le rendu sur chaque route, dont 4 servies depuis le même domaine first-party (économie de connexions limitée mais coût de téléchargement linéaire) et 2 sur des chemins external_css/... qui suggèrent un CMS legacy (SPORTCASH, GUINEA). Une seule de ces feuilles (adeguamento.css) est sur HTTPS absolu, les autres sont en relatif. Aucune ne porte media="print" ni disabled (sauf adeguamento_dark.css).
- Impact attendu :
Sur un réseau 4G guinéen avec RTT typique > 200 ms vers une infra EU, 7 roundtrips série pour CSS first-party = pénalité estimée de plusieurs centaines de ms sur le FCP. Aucune mesure CrUX disponible pour le quantifier précisément. Conséquence indirecte : LCP dégradé, perte de conversion sur les CTAs "Inscription" et "Dépôt" (above-the-fold sur sport-home selon screenshot).
- Root cause :
Architecture CMS Italien legacy ("contogioco" = compte de jeu en italien, "componenteGioco" partout dans le DOM) avec multi-tenant par marché (GUINEA, IVORY_COAST, SPORTCASH...). Chaque tenant ajoute sa feuille adeguamento.css au-dessus du noyau Bootstrap + FontAwesome + base. Refactor difficile sans casser le multi-tenant.
F-PERF-01-03 : 4 images par route sans loading="lazy", sans width/height, sans srcset
- Sévérité : serious
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
raw_html_sport_home:- Ligne 362 :
<img src="https://www.bet224.gn/external_cms/GUINEA/img/logo-bet-224.png">(logo header, sans attributs perf) - Ligne 389 :
<img src="https://www.bet224.gn/external_css/GUINEA/img/ARSJPA.png">(logo régulateur) - Ligne 453 :
<img src="/images/desktop/fr.png" class="flag-lang" />(drapeau langue FR) - Ligne 458 :
<img src="/images/desktop/en.png" class="flag-lang" />(drapeau langue EN) - Grep
loading="lazy"sur les 4 raw HTML : 0 occurrence (4 fichiers, count = 0). - Grep
width=ouheight=sur les<img>: 0 occurrence. - Le brief mentionne 5 visuels promotionnels sur
promotions(bonus 500 %, cashback, welcome) qui devraient apparaître comme<img>oubackground-image; mesuré uniquement 4<img>ce qui suggère que les visuels promo sont chargés dynamiquement après render (JS), donc encore plus tardifs. - Source visuelle : -
screenshots/casino/desktop.png: 5 carrousels de jeux avec ~12 vignettes visibles each au-dessus du fold = ~60 images casino non instrumentées performance. screenshots/promotions/desktop.png: 4 visuels bannière promo confirmés (zone ~y=200 à y=900).- Constat :
Toutes les <img> détectées dans le raw HTML sont chargées eagerly, sans dimensions intrinsèques déclarées, sans variantes responsive. Les visuels casino et promotions ne sont pas dans le raw HTML du tout = soit chargés post-render JS (perf encore pire), soit background-image CSS (non détecté lazy-loadable). Le logo header est servi depuis un chemin absolu external_cms/GUINEA/img/logo-bet-224.png PNG (probablement pas optimisé WebP / AVIF).
- Impact attendu :
- CLS : risque structurel car aucune image n'a de dimensions déclarées. Réseau lent = image arrive après le premier render = layout shift à chaque image qui se charge. Quantifier nécessite CrUX (non disponible).
- Root cause :
Markup template qui ne respecte aucune des best practices <img> 2026 (WCAG 2.1 + Web Vitals + responsive). Aucune passe d'optimisation image n'a été appliquée. Convergence avec finding A11Y F-A11Y-01-01 (logo sans alt) : la même refonte template doit fixer alt + dimensions + lazy + srcset.
F-PERF-01-04 : Aucun preconnect ni dns-prefetch ni preload sur les origines critiques
- Sévérité : moderate
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
- Grep
preload|preconnect|dns-prefetchsurraw_html_sport_home: 0 occurrence. - Pattern identique sur les 4 routes.
- Origines tierces utilisées en runtime :
www.googletagmanager.com(ligne 15gtag.js),www.bet224.gn/external_cms/GUINEA/...(chemin alternatif sous-domaine implicite). Aucune n'est préconnectée. - Source visuelle : - Non applicable.
- Constat :
Le client charge GTM, gtag, et plusieurs ressources CSS sous des chemins absolus distincts (https://www.bet224.gn/external_css/GUINEA/...), mais ne fait aucune optimisation TCP / TLS préventive. Chaque origine externe paie une connexion complète (DNS + TCP + TLS) à la demande, en série.
- Impact attendu :
Pénalité estimée de 100 à 300 ms par origine sur un RTT 200 ms (1 DNS + 1 TCP + 2 TLS roundtrips = ~600 ms si non préconnecté, vs ~0 si preconnect dès le <head>). Pas critique en lab local, sensible en field Guinée. À quantifier précisément via PSI Network panel (non fetché).
- Root cause :
Optimisation manquée, pas un défaut architectural. Fix simple : ajouter 2-3 <link rel="preconnect"> en tête de <head>.
F-PERF-01-05 : Routes ont des full-page heights très hétérogènes (900 px à 1629 px), casino 1,8× plus haut
- Sévérité : moderate
- Route(s) :
casino,sport-home,sport,promotions - Source primaire :
screenshots/index.json→captures[].desktop_full_height_px:sport-home= 900sport= 900casino= 1629promotions= 950- Taille screenshot PNG full-page (proxy poids visuel) : casino = 1063 KB, sport = 477 KB, sport-home = 202 KB, promotions = 174 KB. Source :
Get-ChildItemsur le dossierscreenshots/<route>/desktop.png. - Source visuelle : -
screenshots/casino/desktop.png: 5 carrousels empilés verticalement + section providers + bannière, total 1629 px de scroll. screenshots/sport-home/desktop.png: tabs + grille de top compétitions, 900 px (fold + 1 écran).- Constat :
Casino est nettement plus haut que les autres routes et son screenshot full-page est ~5× plus lourd en KB. Cela indique densité visuelle élevée : carrousels images + vignettes de jeux + branding providers (Evolution, Spribe, Amigo Gaming, Pragmatic). Sans dimensions sur les images (F-PERF-01-03), cette densité = risque CLS structurel élevé sur casino.
- Impact attendu :
Sur casino, la combinaison "5+ carrousels images + 0 dimension déclarée + 0 lazy + connexion lente" projette un scénario field où le visiteur voit le contenu se réorganiser pendant plusieurs secondes. INP probablement dégradé par les listeners de carrousels (8 boutons cf F-A11Y-01-03, plus probablement des handlers Swiper / GSAP). LCP candidate = première vignette d'image visible.
- Root cause :
Choix produit (multi-carrousels providers) compatible avec un marché casino concurrentiel, mais sans la couche perf qui devrait accompagner (lazy carrousel offscreen, virtualisation, image dimensions, preload du LCP candidat).
F-PERF-01-06 : GTM en script inline en <head> avant <meta viewport> et <title>
- Sévérité : minor
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
raw_html_sport_homelignes 7-13 : bloc GTM inline (IIFE(function(w,d,s,l,i){...})) placé AVANT<meta name="viewport">(ligne 22) et AVANT<title>(ligne 23).- Ligne 15 :
<script async src="https://www.googletagmanager.com/gtag/js?id=G-VLQSP6C303">(correctement async). - Lignes 16-21 : config gtag inline (
gtag('config', 'G-VLQSP6C303', ...)). - Pattern identique sur les 4 routes.
- Source visuelle : - Non applicable.
- Constat :
GTM est chargé en script inline async (correct), mais le bloc précède toutes les meta critiques pour le navigateur. Conséquence mineure mais réelle : le navigateur retarde l'interprétation des hints viewport (utilisé pour calcul layout mobile) et title (utilisé pour onglet) jusqu'après le parse du bloc GTM.
- Impact attendu :
Sub-100 ms en lab, mais cumulé avec les autres findings = signal de qualité d'intégration analytics. Pas un blocker isolé.
- Root cause :
Snippet GTM copié-collé "as-is" depuis l'assistant GTM. Ordre <head> non audité.
F-PERF-01-07 : Inline CSS contient 7 background-image: url() !important vides (assets cassés ou volontairement vides ?)
- Sévérité : minor
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
raw_html_sport_homelignes 46-72 : 8 occurrences debackground-image: url() !important;dans un<style>inline en<head>. Cibles :.landing-2::before,.cg-landing-background,.promozioni-sfondo::before,.poker-landing::before,.azione-poker.cg-download-client,.azione-poker.cg-gioca-ora,body[page="cards"] .casino. Toutes avec URL VIDE.- Pattern identique sur les 4 routes.
- Source visuelle : - Non applicable directement (effet indirect : si ces classes étaient activées par le CMS, le placeholder est cassé).
- Constat :
Le CMS injecte du CSS inline avec des background-image: url() vides, probablement à cause d'un placeholder de template (Velocity/JSP/Freemarker ${variable} non résolu = chaîne vide). Bug fonctionnel : si une de ces classes est appliquée dynamiquement, le background sera vide au lieu de l'asset attendu. Effet perf : nul direct (les URLs vides ne déclenchent pas de requête), mais signal d'un template defectueux.
- Impact attendu :
- Perf : 0 ms (les
url()vides ne génèrent pas de fetch). - Régression visuelle potentielle : si une promo poker / landing est activée serveur, l'image manque.
- Qualité produit : indicateur d'une chaîne de build CSS instable.
- Root cause :
Template CMS Java/JSP (visible aussi dans base.jsp, third-party.jsp, default_contogioco_desktop.css.jsp) qui ne nettoie pas ses placeholders en sortie.
Cross-angle dependencies
- MOBILE (DEEP-MOBILE-01, à venir) : la performance perçue par le persona mobile Guinée est l'enjeu central de cet audit. Tous les findings PERF s'amplifient en mobile : F-PERF-01-01 (CSS render-blocking × RTT mobile élevé), F-PERF-01-02 (JS sync × CPU mid-range), F-PERF-01-03 (images sans srcset × bande passante limitée). DEEP-MOBILE-01 doit nécessairement croiser avec DEEP-PERF-02 (post-CrUX) pour quantifier le delta mobile vs desktop. Reco partagée probable :
R-PERF-01-03(images responsive) résout aussi un finding mobile attendu sur "images servies en taille desktop sur mobile". - A11Y (DEEP-A11Y-01) :
F-PERF-01-03(images sans dimensions ni lazy) recoupeF-A11Y-01-01(logo header sans alt) sur le même<img>ligne 362. La refonte du template<img>doit fixer SIMULTANÉMENT :alt(a11y),width/height(perf CLS),loading="lazy"(perf bande passante),fetchpriority(perf LCP). À fusionner en une seule reco template parassemble_audit.py(cf R-PERF-01-03 copy-ready qui inclut déjà l'attributalt). - SEO (DEEP-SEO-01, à venir) : Core Web Vitals (LCP / INP / CLS) sont un signal de ranking Google confirmé depuis 2021 (Page Experience Update) + signal de qualité utilisé par les LLMs pour évaluer la fiabilité d'une source (Perplexity, ChatGPT browsing). Un site lent et instable visuellement est moins cité. DEEP-SEO-01 doit citer DEEP-PERF-02 (post-CrUX) pour quantifier l'impact ranking.
- UI (DEEP-UI-01, à venir) :
F-PERF-01-05(casino full-page 1629 px, 1063 KB) interroge le choix UI multi-carrousels. Décision design (densité visuelle vs perf) à arbitrer avec UI-check du red team. - TRUST (DEEP-TRUST-01, à venir) : aucune dépendance perf directe identifiée. Note : un site lent dégrade implicitement la perception de fiabilité, surtout en YMYL gambling où la confiance est primordiale.
Limites
- CrUX (Chrome UX Report) NON FETCHÉ : aucune mesure de vrais users 28j pour LCP / INP / CLS p75 par route × form_factor. Conséquence : aucun chiffre Core Web Vitals ne peut être affirmé dans cet audit. La cause = variable d'env
CRUX_API_KEYabsente lors du run. Reco R-PERF-01-01 traite ce point en V2. Sans CrUX, l'analyse PERF est qualitative (root cause depuis markup), pas quantitative. - PageSpeed Insights (Lighthouse lab) NON FETCHÉ : aucun diagnostic Lighthouse (LCP element identifié, render-blocking savings quantifiés, opportunités scorées, image-delivery insights, JS execution time). Conséquence : impossible de prouver précisément que tel script bloque le LCP de tant de ms. Cause =
PSI_API_KEYabsente. Reco R-PERF-01-01 traite aussi ce point. - Pas de mesure CLS ni INP : ni en lab (pas de Lighthouse) ni en field (pas de CrUX). Les findings F-PERF-01-03 (images sans dimensions) et F-PERF-01-05 (casino multi-carrousels) projettent un risque CLS / INP fort sur la base du markup, mais ne le mesurent pas. À quantifier en V2.
- Performance mobile non mesurée : POC desktop only. Aucun screenshot mobile (
captures[].mobile_path = nulldansscreenshots/index.json). Aucun axe mobile. Aucun CrUX mobile. C'est le déficit le plus critique de cet audit car le persona primaire est mobile. À étendre en V2 (capture screenshots mobile + axe mobile + CrUXform_factor=PHONE). - Timings réseau biaisés par la géographie du crawler : timings TTFB / DCL / load_event mesurés depuis Chromium headless sur IP probablement européenne (à confirmer via
crawl/index.jsonqui ne stocke pas l'IP source). Le visiteur réel à Conakry paie une latence backbone EU↔Guinée typiquement > 200 ms RTT, soit un facteur multiplicateur 3-10× sur le load_event mesuré. Aucun throttling appliqué non plus (CPU et bande passante = capacité crawler). Les timings ci-dessus sont des PLANCHERS, jamais des projections field. - Tailles d'assets non mesurées : le crawl raw n'a téléchargé que les HTML, pas les CSS / JS / images. Les estimations de poids JS / CSS (ex : "jQuery 3.7.1 ~85 KB") sont basées sur connaissance générale, taggées
[À VÉRIFIER], à confirmer en V2 via PSI Network panel oucurl -Isur les URLs absolues. - HTTP/2 / HTTP/3 status non vérifié : la pertinence de R-PERF-01-05 (bundling CSS) dépend du protocole HTTP. Non testé en session. À vérifier via
curl -I --http2 https://www.bet224.gn/sport-home. - Service Worker / PWA non audité : présence d'un
<link rel="manifest" href="/manifest.json">dans le<head>ligne 28 suggère que le site déclare une PWA. Existence et configuration du Service Worker (cache strategy, prefetch, offline) non vérifiées (script SW non grepable depuis le raw HTML). Potentiel d'optimisation perf significatif si activé proprement, à instruire en V2. - Page-signals/<slug>.signals.json présent mais
parse_status = no_html: le fichier existe (page-signals/sport-home.jsonetc.) maishas_html = falsepour les 4 routes. Cfpage-signals/_index.json→pages[].status = "no_html". Conséquence :signals.rendering,signals.json_ld,signals.og_twitter, hints perf (lcp_element, render-blocking resources) ne sont pas disponibles. Le finding aurait été nettement plus précis avec ces signaux. À rattraper en V2 (relancerbuild_page_signals.pysur le crawl, sans le bugno_html). - Pas d'analyse du cookie banner perf : le banner cookies (visible en screenshot) est probablement injecté par JS post-load. Son impact sur INP et CLS n'est pas instruit faute de capture interactive.
- Pas d'analyse des iframes Spribe / Evolution casino : les jeux casino sont probablement chargés en iframe tierce (Spribe Aviator, Evolution live). Leur impact perf (multi-MB par iframe potentiellement) non mesuré en session car non détectés dans le raw HTML statique (chargés post-interaction).
Angle : SEO
Persona
Source : site-context.yaml voice_and_tone.persona_primary + keywords-urls-mapping.txt.
sport-home: parieur sportif en Guinée, très majoritairement mobile, arrivant en intent "paris sportifs" (primary keyword mappé). La page est censée capter le trafic brand "bet224" + génériques "paris sportifs". Aujourd'hui le<title>ne mentionne ni "Bet224" comme entité claire ni "Guinée" comme cible géo-intent et la meta description évoque "Sportcash.com" qui n'est pas la brand audité, donc requête brand + générique mal servie.sport: même persona, en intent "cotes" / "parier en ligne" (primary keyword mappé). Title strictement identique àsport-home(duplicate), pas de différenciation pour les SERP ni pour les LLM qui doivent distinguer "hub home" de "catalogue compétitions".casino: persona élargie joueur casino. Titlewww.bet224.gn | Jeux Digitaux | Jeux Virtuelsn'inclut ni "casino" (primary keyword mappé) ni la brand canonique "Bet224". Faux signal sémantique pour Google et pour LLM.promotions: persona en intent "bonus" / "code promo bet224" (primary keyword mappé). Title est lui aussi le title générique sport-home dupliqué, donc impossible à ranker sur "bonus paris sportifs" sans réécriture.
Synthèse exécutive
- 6 routes auditées affichent des défauts structurels SEO majeurs concentrés sur 4 axes : titles dupliqués + brand erronée, meta descriptions polluées par "Sportcash.com" (entité différente), zéro markup Schema.org JSON-LD sur 4 routes, zéro Open Graph ni Twitter Card sur 4 routes. Sources :
crawl/index.jsonpages[].title / description / json_ld + grep raw HTML. - AI search readiness ≈ nulle : sans
OrganizationJSON-LD, sansWebSiteschema, sansItemListpour le catalogue de cotes, et avec un brand string ambigu ("Sportcash.com" dans description vs "www.bet224.gn" dans title vs "Bet224" canonique site-context), un LLM cite mal ou ne cite pas. Source :crawl/index.jsonpages[].json_ld = [] sur les 4 routes. - Pollution éditoriale héritée d'un template multi-site CoreGaming (CSS
external_css/SPORTCASH/, JScg_*skinCode=SPORTCASH) : la prose meta + keywords reste celle d'un opérateur "Sportcash.com" ciblant "Ivory Coast", pas Bet224 / Guinée. Sources :raw_html_sport_home.l24, l27, l140, l241. - Canonical incohérent :
sport-homeretourne canonical vide alors que les 3 autres routes ont un canonical pleinement formé. Source :crawl/index.jsonpages[0].canonical = "" vs pages[1,2,3].canonical valides. - YMYL gambling : aucun markup structurant la nature "site de paris sportifs" (pas de
@type: OrganizationaveclegalName, pas desameAsvers profils sociaux, pas de mention âge légal détectable en raw HTML sport-home). Pour un LLM appelé à citer une source d'autorité gambling Guinée, bet224.gn ne fournit aucun signal de confiance machine-readable. Cross-angle TRUST.
Findings
F-SEO-01-01 : Title et meta description dupliqués + brand erronée "Sportcash.com" sur 3 routes sur 4
- Sévérité : critical
- Route(s) :
sport-home,sport,promotions - Source primaire :
crawl/index.jsonpages[0].title = "www.bet224.gn Guinee | Jouez en Ligne | Sport, Jeux Digitaux, Virtuel, Loto" (76 chars)crawl/index.jsonpages[1].title = "www.bet224.gn Guinee | Jouez en Ligne | Sport, Jeux Digitaux, Virtuel, Loto" (strictement identique à pages[0])crawl/index.jsonpages[3].title = "www.bet224.gn Guinee | Jouez en Ligne | Sport, Jeux Digitaux, Virtuel, Loto" (strictement identique à pages[0])crawl/index.jsonpages[0].description = "Sportcash.com : sûr et fiable, les meilleures cotes de paris sportifs, le Loto et des jeux divertissants vous attendent!" (122 chars, brand "Sportcash.com" ≠ Bet224)crawl/index.jsonpages[1].description identique à pages[0]crawl/index.jsonpages[3].description = "Sportcash.com vous offre des Promotions et des Bonus exclusifs pour vos paris..." (brand erronée également)raw_html_sport_home.l23confirme<title>+raw_html_sport_home.l24confirme<meta name="description">- Constat :
3 des 4 routes principales (sport-home, sport, promotions) ont un title strictement identique, qui ne mentionne pas la brand canonique "Bet224" mais préfixe par "www.bet224.gn", ce qui est un signal de domain-name leaking et non un title optimisé (Google tronque sur 60 chars, ici 76 chars). Les meta descriptions de ces 3 routes citent "Sportcash.com" qui est une marque différente (autre opérateur CoreGaming, cf external_css/SPORTCASH/default_contogioco_desktop.css?v=20260304016 ligne 140), donc Google ré-écrit la SERP et un LLM qui scrape cette description retourne une mauvaise attribution de marque.
- Impact attendu :
Côté SEO : impossibilité de cibler en SERP "bet224" brand, "casino bet224", "code promo bet224", "bonus bet224" (4 keywords cibles distincts dans keywords-mapping) avec une seule formulation dupliquée. Google va déduper et n'afficher qu'une seule des 3 routes en SERP par cluster sémantique. Côté AI search : un LLM cite "Sportcash.com" comme source d'autorité paris sportifs, pas Bet224. Côté brand consistency : utilisateur en SERP qui voit "Sportcash.com" sur un domaine "bet224.gn" est désorienté (signal de site contrefait ou hacked).
- Root cause :
Template CMS CoreGaming "skinCode=SPORTCASH" pas re-localisé pour la skin GUINEA. Les titres + meta sont des labels hérités de l'instance Sportcash (Côte d'Ivoire), pas customisés pour Bet224. Fix : reconfigurer les templates SEO par route dans le back-office CMS (modifier les <title> et <meta description> par template route).
F-SEO-01-02 : Aucun JSON-LD Schema.org sur les 4 routes (AI search non éligible)
- Sévérité : critical
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
crawl/index.jsonpages[0,1,2,3].json_ld = [] (array vide sur les 4 routes)- Grep
application/ld\+jsonsur les 4 raw HTML : 0 occurrence sur chaque fichier - Constat :
Aucune des 4 routes principales ne déclare de JSON-LD Schema.org. Il manque a minima un Organization (nom, logo, URL, sameAs vers réseaux sociaux), un WebSite (nom + searchAction si recherche interne, ce qui est le cas), et selon les routes : BreadcrumbList, ItemList pour le catalogue de cotes (sport) et de jeux (casino), Offer pour les promotions. Le brand canonical_display est "Bet224" (cf site-context.yaml) mais nulle part dans le markup il n'est exposé en machine-readable.
- Impact attendu :
AI search : Perplexity, ChatGPT search, Gemini, Bing Copilot s'appuient massivement sur Schema.org pour extraire les entités et arbitrer entre sources concurrentes. Sans markup, bet224.gn n'est pas éligible à apparaître en answer engine (citation, knowledge panel équivalent) sur des requêtes "site de paris Guinée", "casino en ligne Guinée", "bonus paris sportifs Bet224". SEO classique : pas de rich snippets en SERP Google, donc taux de clic dégradé vs concurrents qui en exposent.
- Root cause :
Template CMS CoreGaming n'inclut pas de JSON-LD côté serveur (rendu HTML brut sans bloc <script type="application/ld+json">). Fix : injecter au build / au render serveur 1 bloc Organization global (footer) + 1 bloc WebPage par route + spécifiques (ItemList pour catalogue, Offer/Promotion pour promotions).
F-SEO-01-03 : Open Graph et Twitter Cards absents (partage social cassé sur 4 routes)
- Sévérité : serious
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
- Grep
og:sur les 4 raw HTML : 0 occurrence sur chaque fichier - Grep
twitter:sur les 4 raw HTML : 0 occurrence sur chaque fichier raw_html_sport_home.l22-28: seul markup meta présent = viewport, description, robots, googlebot, keywords. Aucun<meta property="og:">ni<meta name="twitter:">.- Constat :
Aucune des 4 routes ne déclare de tags Open Graph (og:title, og:description, og:image, og:url, og:type, og:site_name) ni de Twitter Cards (twitter:card, twitter:title, twitter:image). Un lien partagé sur Facebook, WhatsApp, X, LinkedIn, Telegram (les 3 derniers étant des canaux de croissance gambling actifs en Afrique de l'Ouest) affiche un preview cassé ou par défaut.
- Impact attendu :
Friction de share social majeure sur l'acquisition organique virale (parieurs partageant un combiné, un bonus). Côté AI search : certains crawlers LLM (notamment Bing Copilot) lisent les og:* comme fallback quand JSON-LD est absent. Ici les deux sont absents donc double trou.
- Root cause :
Idem F-SEO-01-02 : template CMS sans injection metadata sociale. Fix simultané possible (même back-office, mêmes variables route).
F-SEO-01-04 : Aucun markup âge légal ni mention SafeForKids (YMYL gambling)
- Sévérité : serious
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
- Grep
18 ans|joueurs majeurs|jeu responsable|interdit aux mineurs|majeursurraw_html_sport_home.raw.html: occurrences détectées uniquement dans le bundle JS labels (var cg_LABEL ligne 250, code applicatif non exposé en contenu indexable) mais aucune balise visible dans le DOM head / body principal du shell SSR. - Footer du site (
raw_html_sport_home.l752-816) : ne contient ni mention âge légal, ni lien "Jeu responsable", ni "Responsible Gaming", ni logo associé. Les seuls liens légaux footer sontPolitique de ConfidentialitéetConditions Généralespointant vers/promo/tutte/bet224_*(pages promo recyclées, pas pages légales dédiées). site-context.yamlto_confirm liste explicitement "Age legal pour parier en Guinee" et "Dispositif de verification d'age (age-gate) avant acces au contenu de jeu" comme non sourcés. Aucune meta<meta name="rating" content="adult">ni<meta name="rating" content="RTA-5042-1996-1400-1577-RTA">ni en-tête HTTPRating-Labeldétectable au crawl shell.- Constat :
Le site n'expose aucun signal machine-readable indiquant qu'il est destiné à un public majeur. Pas de mention "18+" ni équivalent en footer SSR, pas de balise meta de classification de contenu (RTA, ICRA, meta rating="adult"), pas de markup Schema.org WebSite avec attribut audience ou propriété équivalente, pas de lien direct vers ressources de jeu responsable. L'âge légal exact en Guinée n'est pas sourcé en session (cf site-context.yaml to_confirm), donc l'absence de mention est doublement problématique : ni info utilisateur, ni info crawler.
- Impact attendu :
Côté AI search : un LLM générique appelé à citer "sites de paris adaptés aux adultes Guinée" peut citer ou non bet224 sans pondération de risque mineur, car aucun signal n'oriente. Côté trust SEO : Google a une politique restrictive sur le contenu gambling (cf Gambling & Games Ads Policy, Quality Rater Guidelines section YMYL) qui pénalise les pages sans signaux de responsabilité. Côté régulation : la mention obligatoire d'âge est probable en Guinée (à sourcer Legal-check + ARSJPA), donc défaut potentiel de conformité gambling. Cross-angle TRUST.
- Root cause :
Template footer minimaliste ne porte aucun bloc régulation. La skin GUINEA n'a pas été enrichie côté CMS pour le contexte gambling local (vs sport généraliste). Fix simultané avec F-TRUST sur footer complet régulation.
F-SEO-01-05 : Canonical incohérent sur sport-home (vide alors que les 3 autres routes l'ont valide)
- Sévérité : moderate
- Route(s) :
sport-home - Source primaire :
crawl/index.jsonpages[0].canonical = "" (sport-home)crawl/index.jsonpages[1].canonical = "https://www.bet224.gn/sport"crawl/index.jsonpages[2].canonical = "https://www.bet224.gn/casino"crawl/index.jsonpages[3].canonical = "https://www.bet224.gn/promotions"- Grep
<link rel="canonical"surraw_html_sport_home.raw.html: 0 occurrence dans les 30 premières lignes head, alors que les 3 autres raw HTML l'ont en ligne 22. - Constat :
La route /sport-home n'expose aucun <link rel="canonical">. Combiné au fait que cg_LANDING_URL = '/sport-home' (raw_html_sport_home.l~220) signifie que / et /sport-home sont des URL équivalentes côté serveur, sans canonical pointant vers l'une d'elles, Google et les LLM doivent choisir librement (souvent en faveur de / racine, alors que le contenu est livré sur /sport-home). Cela dilue le link equity et embrouille l'attribution de citations LLM.
- Impact attendu :
Risque concret de duplicate content / vs /sport-home (le crawl en a observé un, le serveur en sert sans doute un autre). Citations LLM peuvent pointer vers /sport-home (URL non canonique) au lieu de la racine, fragmentant le signal d'autorité. Pour la SERP brand "bet224", la home affichée peut être la mauvaise URL.
- Root cause :
Bug de template route landing : le canonical par défaut n'est pas posé pour la route d'entrée. Probablement une condition CMS qui exclut la landing route du canonical render.
F-SEO-01-06 : Couverture SEO + AI search hors scope condensé (link graph intra-site, citations LLM mesurées, AGG patterns)
- Sévérité : moderate
- Route(s) :
all - Source primaire :
- Brief
subagent-brief-product-audit.mdv1.1 section 7 : "version condensée du brief seo-audit v2.1.4. Ne pas re-faire un audit SEO complet... Si l'audit produit a besoin d'un SEO approfondi, vendre seo-audit séparément." - Inputs absents flaggés explicitement dans la mission :
link_graph.jsonnon produit côté product-audit,page-signals/<slug>.signals.jsonen parse_status=no_html (inutilisable pour rendering/json_ld structurés), pas de mesure de citations LLM Perplexity / ChatGPT / Gemini / Bing Copilot, pas d'analyse AGG patterns (Answer Generation Gap), pas de volume de recherche par keyword cible (keywords-mappingexplicite "Pas de volume de recherche affirme (non verifie)"). - Constat :
Le scope condensé SEO de l'audit produit couvre uniquement les findings structurels markup. Ne sont PAS couverts : la cartographie intra-site (in/out degree par page, pages orphelines, profondeur de clic depuis la home), les citations effectives sur Perplexity / ChatGPT search / Gemini / Bing Copilot pour les 11 keywords primaires + secondaires mappés, les patterns AGG (gap entre réponses LLM et contenus existants sur le site), les pages 404 / shell vide listées comme gaps (cf keywords-mapping bas du fichier : 9 catégories de pages manquantes incluant jeu-responsable, licence, mentions-legales, bonus, loto, faq, a-propos, cgu, privacy), et l'analyse comparative concurrentielle (1xBet, Premier Bet, autres opérateurs Guinée).
- Impact attendu :
L'audit produit fournit les findings structurels qui débloquent un travail SEO sérieux (sans markup réécrit, aucune action SEO downstream ne paie). En revanche, l'optimisation SEO + AI search complète (priorisation par keyword, plan de contenu pour les 9 gaps de pages, mesure de citations LLM benchmarkée, intra-linking, AGG opportunities) requiert un audit dédié seo-audit séparé.
- Root cause :
Scope contractuel produit-audit, pas un défaut technique. Reco R-SEO-01-06 propose le path commercial.
Cross-angle dependencies
- F-SEO-01-01 (titles dupliqués + brand "Sportcash" erronée) recoupe
[REF: DEEP-TRUST-NN/F-NN]à venir : la pollution éditoriale héritée du template Sportcash est un signal de trust dégradé (brand confusion, signal site contrefait potentiel). À fusionner avec la reco trust si l'angle TRUST identifie la même cause racine. - F-SEO-01-02 (zéro JSON-LD) et F-SEO-01-04 (zéro markup âge légal) recoupent
[REF: DEEP-TRUST-NN/F-NN]: absence de signaux machine-readable de régulation gambling. La reco R-SEO-01-04 sur le footer régulation est à mutualiser avec les recos TRUST sur le footer mentions légales + licence + lien jeu responsable, c'est probablement le même chantier template footer. - F-SEO-01-01 (titles peu différenciés) recoupe
[REF: DEEP-CONV-NN/F-NN]à venir : un title qui ne mentionne pas la valeur ajoutée par route impacte le taux de clic SERP (premier point de conversion). La reco R-SEO-01-01 sur les copy-ready titles est à valider en cohérence avec les CTAs primary observés dansconversion-signals/<slug>.jsonpour aligner promesse SERP et promesse page. - F-A11Y-01-01 (logo header sans alt) déjà documenté dans
[REF: DEEP-A11Y-01/F-01]: la reco a11yaria-labeloualtsur le logo apporte aussi un signal SEO image (logo Bet224 indexable comme entité). Fix unique, double bénéfice.
Limites
- Pas de page-signals/<slug>.signals.json structurés : parse_status=no_html sur tous les fichiers signals, donc impossible de lister les
headings.h1_count,headings.tree,rendering.ssr_html_size_bytes,rendering.classification,og_twitterparsés,json_ldparsés en mode programmatique. Fallback raw HTML utilisé. Limitation : impossible de produire un audit AGG ou link_graph complet sans signals v1.4 fonctionnels. - Pas de link_graph.json côté product-audit : impossible d'analyser l'intra-linking (pages orphelines, in/out degree par page, ancres dupliquées, profondeur de clic depuis home). Reco déléguée à un audit seo-audit séparé (R-SEO-01-06).
- Pas de crawl des pages mentions-légales / CGU / jeu-responsable / licence côté product-audit : ces routes sont absentes du crawl
index.json(4 routes principales uniquement). Cross-vérification effectuée côtéseo-audit/toolkit/clients/bet224/crawl/html/qui contient ces fichiers raw : ils font tous exactement 840 lignes (shell vide identique = page 404 ou shell SSR sans contenu utile). Diagnostic flagué danskeywords-mappingbas du fichier comme "GAPS DE CONTENU 23 routes 404 / shell vide" mais non audité ici en détail. - Pas de mesure de citations LLM : Perplexity, ChatGPT search, Gemini, Bing Copilot non interrogés sur les 11 keywords primaires + 30+ secondaires mappés. Hors scope condensé. Reco déléguée R-SEO-01-06.
- Pas de mesure AGG patterns : aucune question LLM cible mesurée vs contenu existant. Hors scope condensé.
- Pas de mesure SERP réelle : pas de scrape Google Guinée pour observer le ranking actuel ni d'analyse concurrentielle (1xBet, Premier Bet). Hors scope.
- Pas de mesure de volume de recherche par keyword :
keywords-mappingexplicite "Pas de volume de recherche affirme (non verifie)". Pas d'accès Keyword Planner / Ahrefs / Semrush dans la session. - Robots.txt et sitemap.xml non testés directement : WebFetch non utilisé dans cette passe pour respecter le scope condensé. Indicateurs raw HTML positifs (meta robots
index,followsur les 4 routes), mais existence et qualité du sitemap.xml et de robots.txt non vérifiées. À couvrir dans audit seo-audit séparé. - Rendering hybrid vs SSR/CSR pur :
crawl/index.jsonretournerendering_mode: "hybrid"sur les 4 routes, sans signals.json parsé pour départager SSR vs CSR. Estimation basée raw HTML : contenu meta + footer présent en SSR, donc rendering hybride avec base SSR (positif pour SEO + LLM). Confirmation programmatique impossible sans signals v1.4 fonctionnels. - Casing brand "Bet224" non confirmé :
site-context.yamlflagge "[A VERIFIER] casing reelle post-crawl". Le crawl observe "www.bet224.gn" en title (préfixe domain), "bet224.gn" en url, "Bet 224" dans logo path (logo-bet-224.png), "Sportcash.com" en description (legacy CMS). Aucune confirmation explicite de la stylisation cible. Les copy-ready ci-dessus assument "Bet224" canonique (cohérent avecsite-context.yamlcanonical_display) mais à confirmer client avant déploiement.
Angle : TRUST
Persona
Source : site-context.yaml → voice_and_tone.persona_primary ("parieur sportif en Guinée, très majoritairement mobile, intéressé par le football en priorité").
sport-home: parieur sportif en intent "consulter l'offre du jour", probablement première visite. Sur le plan trust, il atterrit sur une page où il ne voit AUCUNE preuve visible d'agrément régulateur (logo ARSJPA présent dans le DOM mais peu visible et sans href), AUCUNE mention d'âge légal, AUCUN lien jeu responsable. Le bandeau hero est dominé par 2 promesses de bonus en GNF. Le footer est caché derrière un bouton "OUVRIR PIED DE PAGE". L'opérateur (raison sociale, adresse, contact) est invisible. Source :screenshots/sport-home/desktop.png+conversion-signals/sport-home.json.sport: même persona en intent "consulter le détail d'une discipline". Mêmes manquements trust transverses car template global identique. S'y ajoute le bandeau promo hero.casino: persona élargie (joueur casino, plus exposé au risque addictif sur jeux crash type Aviator). Mêmes manquements trust. S'y ajoute un widget "Gains récents" (montants spécifiques affichés) qui amplifie le besoin de garde-fous trust visibles (jeu responsable, mention d'âge), absents.promotions: persona en intent "découvrir un bonus avant de s'inscrire ou déposer". Cards "MAXI BONUS / AUGMENTE TES GAINS JUSQU'À 500 %" très visibles ; conditions de mise (wagering) non affichées above-fold, ce qui est typiquement le pattern où le besoin d'une page T&C accessible est maximal. Or, aucune page mentions-legales / licence / jeu responsable / privacy n'est accessible (toutes en soft 404, cf findings F-TRUST-01-02 à F-TRUST-01-05).
Synthèse exécutive
- 5 pages clés du périmètre trust sont des soft 404 :
mentions-legales,licence,jeu-responsable,responsible-gaming,privacy,politique-confidentialite, ainsi quecontact,a-propos,qui-sommes-nous,aide,help,faq,cgu,conditions,terms,bonus. Source : grepbody page="404"dansseo-audit/.../crawl/html/*.raw.htmlretourne 23 fichiers. Sur YMYL gambling, l'absence de page mentions légales et de page licence accessibles est un manquement structurel majeur, indépendamment du cadre réglementaire GN à confirmer (site-context.yamlto_confirm"Cadre data... a sourcer juridique client"). - Le footer effectif ne contient que 2 liens légaux ("Politique de Confidentialité" + "Conditions Générales") qui pointent vers
/promo/tutte/bet224_politique_confidentialiteet/promo/tutte/bet224_conditions_generales(PAS dans le crawl, contenu inconnu). Source :conversion-signals/sport-home.json→detailed.trust_signals.legal_links(4/4 routes). Aucun lien vers mentions légales, jeu responsable, contact, licence, aide. Le footer est par défaut caché derrière un bouton accordion "OUVRIR PIED DE PAGE" (sport-home.raw.html:746+screenshots/*/desktop.pngbouton rouge "OUVRIR PIED DE PAGE" bas-droit). - Aucune mention d'âge légal (18+ ou autre) ni dispositif d'age-gate visible sur les 4 routes. Source : grep
18\+|interdit aux mineursdanssport-home.raw.html→ aucune occurrence dans le contenu affiché en français (seules occurrences = labels JSON italiens hard-codésheader.disclaimer = "Il gioco è vietato ai minori di diciotto anni", non traduits, non affichés, et référant au régulateur italien ADM). Le seuil d'âge légal en Guinée n'est pas sourcé en session (cfsite-context.yamlto_confirm"Age legal pour parier en Guinee"). - Logo ARSJPA présent dans le DOM mais non fonctionnel et présentation décorative :
<img src="https://www.bet224.gn/external_css/GUINEA/img/ARSJPA.png">(sport-home.raw.html:389) dans un<a class="cg-ext-link pointer" onclick="">SANS href, SANS alt text, dans un containermin-width:35px. Ne prouve pas l'agrément et ne renvoie pas vers arsjpa.gov.gn. Identique sur les 42 pages crawlées. - Identifiants SIRET / VAT-EU détectés mais en faux positifs :
conversion-signals/index.json→aggregate.routes_with_siret_or_vat = 2, maissport.json→vat_excerpt = "BETBUILDER"etpromotions.json→vat_excerpt = "DE PROFITER"ne sont PAS des numéros VAT-EU réels, juste des morceaux de texte capturés par regex. Aucun identifiant commercial guinéen attendu (équivalent RCCM / numéro d'agrément ARSJPA) n'est exposé. Aucun email, téléphone, adresse postale visible (aggregate.routes_with_contact_email = 0,routes_with_contact_phone = 0). - Cookie banner non conforme aux standards internationaux : un seul bouton "OK" (accept all), pas de "Refuser" ni de granularité, wording "En poursuivant votre navigation, vous acceptez l'utilisation de tous les cookies" (consent passif). Lien "Plus d'informations" pointe vers un PDF (
/external_cms/pdf/Cookies_Policy.pdf) au lieu d'une page navigable. Source :screenshots/sport-home/desktop.pngbandeau top +sport-home.raw.html:349-355. Cadre data guinéen non sourcé en session.
Findings
F-TRUST-01-01 : Logo ARSJPA présent dans le DOM mais non fonctionnel, sans href ni alt, présentation décorative qui ne prouve pas l'agrément
- Sévérité : critical
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
sport-home.raw.html:386-392:<div id="cg-social-link-container" class="blocco-header login-form-header margine-su-1x" style="display: flex; margin-top:0px"><div id="" class="form-group margine-dx" style="min-width:35px"><a class="cg-ext-link pointer" onclick=""><img src="https://www.bet224.gn/external_css/GUINEA/img/ARSJPA.png"><span></span></a></div></div>- Le
<a>aonclick=""(vide) et SANShref. L'image n'a pas d'attributalt. - Le container parent est en
min-width:35px(très étroit). Pattern identique sur les 42 fichiersraw.htmldu crawl seo-audit (grepARSJPAretourne 42 résultats). site-context.yaml→external_authorities[0].caveat: "Statut d'agrement de Bet224 NON verifie - ne jamais affirmer que Bet224 est ou n'est pas agree"- Source visuelle : -
screenshots/sport-home/desktop.pngzone header haut-droit (x ≈ 480-720, y ≈ 30-66) : le logo ARSJPA n'est pas distinctement visible à 1440px de largeur (présent en DOM, masqué visuellement par sa taille et le styling de container 35px). - Pattern identique sur les 4 routes (vérifié
casino,promotions,sport). - Constat :
L'image ARSJPA.png est embarquée dans tout le template du site mais (1) sans alt text accessible, (2) sans lien fonctionnel vers le registre officiel arsjpa.gov.gn, (3) dans un container CSS de 35px de min-width sans label visible. Présentée ainsi, l'image suggère visuellement un agrément (effet "tampon officiel") sans en apporter la preuve actionnable côté utilisateur. Le statut d'agrément réel de Bet224 auprès de l'ARSJPA n'est pas vérifié en session (cf site-context.yaml).
- Impact attendu :
Pour l'utilisateur : confusion sur la légitimité de l'opérateur. Pour le régulateur ARSJPA potentiellement saisi : risque d'usage frauduleux du logo si l'opérateur n'est pas agréé, ou d'usage non conforme si agréé mais sans modalité d'affichage validée par l'ARSJPA. Pour Bet224 : risque réputationnel en cas de signalement, risque de retrait d'agrément si déjà obtenu et usage non conforme. À cadrer Legal-check + obtenir du client (1) le numéro d'agrément ARSJPA si existant, (2) les modalités d'affichage validées par l'ARSJPA si une charte existe.
- Root cause :
Template global "GUINEA" (cf body data-systemcode="GUINEA") probablement adapté à minima depuis un template d'opérateur italien (cf F-TRUST-01-12). Le logo ARSJPA a été inséré statiquement comme image dans le container "social link" sans intégration aux pages mentions-legales ou licence (qui n'existent pas, cf F-TRUST-01-02 et F-TRUST-01-03).
F-TRUST-01-02 : Page /mentions-legales = soft 404, aucune mention légale accessible publiquement
- Sévérité : critical
- Route(s) :
mentions-legales - Source primaire :
seo-audit/.../crawl/html/mentions-legales.raw.html:301:<body page="404" subpage="404" class=" cg-internal-page cg-body-unlogged cg-user-no-vip " data-original="mentions-legales" data-internal="mentions-legales" data-systemcode="GUINEA">mentions-legales.raw.html:684-690:<div id="cg-404-page-outer-container">...<span class="display-1 d-block">404</span><div class="mb-4 lead">Page non trouvée</div>mentions-legales.raw.html:23:<title>bet224.gn - </title>(title vide, signal supplémentaire de page non personnalisée)site-context.yaml→brand.canonical_legal: ""(raison sociale opérateur vide, à obtenir client)- Source visuelle : - Pas de screenshot sur cette route (hors POC). Le HTML soft 404 retourné est cependant intégré au template (header, footer, cookie banner) identique au reste du site, donc l'utilisateur arrivant sur
/mentions-legalesvoit la chrome du site puis un message 404 standard. - Constat :
Aucune page de mentions légales accessible publiquement sur bet224.gn. Sur YMYL gambling, l'absence d'une page mentions légales reprenant a minima la raison sociale de l'opérateur, son siège social, son numéro d'agrément, son contact juridique est un manquement structurel transverse, indépendamment du cadre réglementaire guinéen spécifique à confirmer.
- Impact attendu :
Pour l'utilisateur : impossible d'identifier l'opérateur, d'exercer un droit (rétractation, plainte, contestation de transaction). Pour l'autorité ARSJPA si saisie : aucun moyen de relier visuellement le site à l'entité titulaire d'un éventuel agrément. Pour Bet224 : risque réglementaire en cas d'enquête ARSJPA ou de contestation utilisateur. Impact réputationnel direct sur l'utilisateur prudent qui cherche typiquement la page mentions légales avant un premier dépôt.
- Root cause :
Page non créée côté CMS, ou créée puis dépubliée. Aucun fallback de redirection vers une page valide. Le serveur retourne 200 avec un body page="404", donc soft 404 (pas un vrai 404 HTTP), pratique problématique également côté SEO car les moteurs indexent comme contenu valide.
F-TRUST-01-03 : Page /licence = soft 404, aucun numéro de licence ni preuve d'agrément accessible
- Sévérité : critical
- Route(s) :
licence - Source primaire :
seo-audit/.../crawl/html/licence.raw.html:301:<body page="404" subpage="404" ... data-original="licence" data-internal="licence" data-systemcode="GUINEA">- Présence de l'image ARSJPA dans le template (ligne 385) mais sans contenu de page valide.
site-context.yaml→facts.to_confirm[1]: "Numero de licence de Bet224 + statut d'agrement aupres de l'ARSJPA - Licence declaree par le client 2026-05-16 mais non sourcee"- Aucun numéro d'agrément ni texte de référence (décret, arrêté) n'est trouvé en grep sur le corpus crawlé (
grep -i "agrément\|décret\|arrêté\|n°" sport-home.raw.html= aucun résultat dans contenu visible). - Source visuelle : - Pas de screenshot sur cette route. HTML retourné = template + message 404.
- Constat :
Bet224 ne publie pas son numéro de licence ARSJPA (ou autre titre d'autorisation) sur le site, ni sur une page dédiée /licence (404), ni dans le footer des 4 routes principales (legal_links ne contient que CGU + Politique confidentialité), ni dans les mentions légales (404). Le seul élément visuel suggérant un agrément est l'image ARSJPA.png décorative non sourcée (F-TRUST-01-01).
- Impact attendu :
Impossible pour l'utilisateur, le régulateur ARSJPA ou un tiers (journaliste, concurrent, autorité étrangère) de vérifier la conformité réglementaire de Bet224 à partir du site lui-même. Risque réputationnel + risque d'investigation ARSJPA si remontée d'utilisateur. Si Bet224 EST agréée, c'est aussi un manque-à-gagner trust (l'agrément est typiquement un argument fort pour le premier dépôt).
- Root cause :
Page absente côté CMS, ou n'a jamais été créée pour la déclinaison GUINEA. Cf F-TRUST-01-12 : trace que le template est adapté d'un opérateur italien où la mention de licence ADM est centralisée différemment.
F-TRUST-01-04 : Pages /jeu-responsable et /responsible-gaming toutes deux soft 404, dispositif jeu responsable invisible
- Sévérité : critical
- Route(s) :
jeu-responsable,responsible-gaming - Source primaire :
seo-audit/.../crawl/html/jeu-responsable.raw.html:301:<body page="404" subpage="404" ... data-original="jeu-responsable" data-internal="jeu-responsable" data-systemcode="GUINEA">seo-audit/.../crawl/html/responsible-gaming.raw.html:301: même soft 404.site-context.yaml→forbidden_patterns[2] = "absence de lien visible vers jeu responsable / auto-exclusion / limites"- Côté DOM, présence de labels JSON internes (sport-home.raw.html ligne 250)
"account.options.exclusion":"Auto-exclusion","cgr.gioco.res.panel.perma.exclusion":"Auto-exclusion permanente","cgr.gioco.res.panel.exclusion.ok":"Auto-exclusion activée"→ le code prévoit un dispositif d'auto-exclusion en interne (accessible uniquement après login utilisateur), mais sans page publique présentant le dispositif. - Source visuelle : - Pas de screenshot des pages 404. Sur les 4 routes POC, aucun lien "Jeu responsable" / "Responsible gaming" / "Auto-exclusion" visible above-fold ni dans le footer effectif (
legal_linksne contient pas ces termes). - Constat :
Le site ne propose AUCUNE page publique présentant le dispositif jeu responsable de Bet224 (ressources, limites de mise, limites de dépôt, auto-exclusion, signes d'addiction, numéro d'aide). Les routes /jeu-responsable et /responsible-gaming sont soft 404. Le dispositif d'auto-exclusion existe potentiellement en interne (labels traduits dans le code) mais n'est accessible qu'après login, donc invisible au visiteur non inscrit et au prospect évaluant la légitimité de l'opérateur.
- Impact attendu :
Pour l'utilisateur : impossibilité d'évaluer la posture de l'opérateur sur le jeu responsable avant un premier dépôt. Pour un utilisateur déjà inscrit en difficulté : aucune ressource publique mobilisable (numéro d'aide, FAQ addiction). Sur le plan moral sectoriel : manquement majeur, le jeu responsable est un standard quasi-universel des régulateurs gambling matures (UKGC, ANJ, MGA, ADM, etc., principe de protection des publics vulnérables). Sur le plan réputationnel : risque très élevé en cas d'incident utilisateur (signalement d'addiction sans ressource fournie). Cadre GN spécifique à confirmer Legal-check, mais l'obligation morale est forte indépendamment.
- Root cause :
Pages publiques non créées côté CMS. Probablement le concept "page publique jeu responsable accessible avant login" a été perdu dans l'adaptation depuis le template italien (où la page Gioco Responsabile est publique sur Snai, Lottomatica, etc.). Le dispositif technique interne existe mais n'est pas exposé en façade.
F-TRUST-01-05 : Pages /privacy et /politique-confidentialite toutes deux soft 404, politique de confidentialité indisponible en HTML
- Sévérité : critical
- Route(s) :
privacy,politique-confidentialite - Source primaire :
seo-audit/.../crawl/html/privacy.raw.html:301:<body page="404" subpage="404" ... data-original="privacy">seo-audit/.../crawl/html/politique-confidentialite.raw.html:301: même soft 404.- Le footer effectif (
sport-home.raw.html:765) contient bien un lien<a href="/promo/tutte/bet224_politique_confidentialite" target="_blank">Politique de Confidentialité</a>mais cette URL n'a PAS été crawlée (donc contenu inconnu). Le slug indique une page dans le mécanisme "promo", inhabituel pour une politique de confidentialité (probablement réutilisation du moteur CMS promo). site-context.yaml→to_confirm: "Cadre data / cookies de profilage applicable en Guinee + politique de confidentialite - Le site sert un bandeau annoncant des 'cookies de profilage tiers' sans page politique de confidentialite accessible (route 404)".- Source visuelle : - Pas de screenshot des pages 404. Le bandeau cookie sur les 4 routes (screenshots) annonce "cookies de profilage tiers" mais l'utilisateur cliquant sur "Plus d'informations" est redirigé vers un PDF (
/external_cms/pdf/Cookies_Policy.pdf), pas vers une page HTML navigable. - Constat :
Aucune page HTML standalone de politique de confidentialité accessible aux URLs canoniques attendues (/privacy, /politique-confidentialite). La seule politique cookie disponible est un PDF dans /external_cms/pdf/. Le lien "Politique de Confidentialité" du footer pointe vers une URL non crawlée dans un mécanisme "promo" (/promo/tutte/bet224_politique_confidentialite), ce qui interroge la pérennité et la fiabilité du contenu.
- Impact attendu :
Pour l'utilisateur : difficile d'exercer un droit data (information, opposition, accès, suppression) sans page navigable. Pour le bandeau cookie qui annonce des "cookies de profilage tiers" : opacité totale sur QUELS cookies, QUELLES finalités, QUELLES durées. Cadre data GN à confirmer Legal-check, mais le pattern est moralement non-conforme aux standards internationaux RGPD-like (UE) ou PIPA (Afrique de l'Ouest). Risque utilisateur prudent qui ne déposera pas + risque légal selon cadre GN.
- Root cause :
Pages HTML jamais créées. Politique cookie en PDF probablement héritée du template italien. Lien footer pointant vers un module promo = bug ou solution de contournement non pérenne (probabilité que cette page disparaisse à la prochaine refonte du module promo).
F-TRUST-01-06 : Footer caché par défaut derrière un bouton accordion "OUVRIR PIED DE PAGE", contient seulement 2 liens légaux
- Sévérité : critical
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
sport-home.raw.html:746:<a id="consultaFooter" data-toggle="collapse" class="consulta-footer fissato accordion-toggle toggle-nascondi" href="#nascondifooter" role="button" aria-expanded="false" aria-controls="nascondi-footer">OUVRIR PIED DE PAGE</a>sport-home.raw.html:752:<footer class="collapse cg-lazy" id="nascondifooter">(classcollapseBootstrap = caché par défaut,cg-lazy= chargé en lazy)sport-home.raw.html:762-767: seul contenu visible une fois ouvert = section "AIDER" contenant 3 liens : "Registration" (modal), "Politique de Confidentialité" (vers/promo/tutte/bet224_politique_confidentialite), "Conditions Générales" (vers/promo/tutte/bet224_conditions_generales).conversion-signals/sport-home.json→detailed.trust_signals.legal_links_count = 2(4/4 routes, valeur identique).conversion-signals/index.json→aggregate.routes_with_legal_links = 4MAIS uniquement 2 liens par route (CGU + Privacy), pas mentions légales / jeu responsable / contact / licence.- Source visuelle : -
screenshots/sport-home/desktop.pngzone bas-droite (x ≈ 1276, y ≈ 876) : bouton rouge "OUVRIR PIED DE PAGE" (<a class="consulta-footer fissato ...">). screenshots/sport/desktop.pngmême bouton (x ≈ 1276, y ≈ 876).screenshots/casino/desktop.pngmême bouton (x ≈ 1243, y ≈ 861).screenshots/promotions/desktop.pngmême bouton (x ≈ 1243, y ≈ 861).- Constat :
Le pied de page est caché par défaut sur les 4 routes principales. Un utilisateur en navigation classique (scroll bas) ne le voit pas. Il faut cliquer sur "OUVRIR PIED DE PAGE" pour le déployer. Une fois ouvert, il ne contient que 2 liens légaux (CGU + Privacy), pas mentions légales, pas jeu responsable, pas contact, pas licence, pas adresse opérateur. Le footer est aussi cg-lazy, donc le contenu est chargé seulement à l'interaction.
- Impact attendu :
Pour l'utilisateur : 99 % des utilisateurs n'ouvriront jamais le footer (pattern UX d'accordion bottom typiquement ignoré). Pour le trust : les mentions légales obligatoires (cadre régulateur à confirmer) ne sont accessibles qu'après une interaction délibérée. Pour les moteurs de recherche : le contenu lazy + collapse peut ne pas être indexé. Pour l'accessibilité (cf cross-angle A11Y) : navigation clavier complexifiée (collapse Bootstrap + cg-lazy).
- Root cause :
Pattern accordion "OUVRIR PIED DE PAGE" hérité probablement du template italien consulta-footer (consulta = "consulter" en italien). Choix design / UX d'origine, non révisé pour le cadre YMYL gambling où le footer trust devrait être visible par défaut.
F-TRUST-01-07 : Aucune mention d'âge légal ni dispositif d'age-gate avant accès au catalogue de jeu
- Sévérité : critical
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
- Grep sur
sport-home.raw.html: aucune occurrence de "18+" / "interdit aux mineurs" / "joueur excessif" dans le contenu affiché en français. Seules occurrences (ligne 250, labels JSON) :header.disclaimer = "Il gioco è vietato ai minori di diciotto anni"(italien, hard-codé, non traduit, non affiché),"esercizio.minimoeta" = "18"(label backoffice italien, non affiché en façade). conversion-signals/sport-home.json→detailed.trust_signals.footer_text_length_chars = 1236(footer court, ne contient pas la mention d'âge).site-context.yaml→forbidden_patterns[3] = "absence de mention d'age legal (18+ ou seuil legal guineen a confirmer)"site-context.yaml→to_confirm: "Age legal pour parier en Guinee - Mention obligatoire probable. Valeur exacte non connue, NE PAS supposer 18 par defaut sans source guineenne", et "Dispositif de verification d'age (age-gate) avant acces au contenu de jeu - Distinct de la simple mention d'age. Principe sectoriel quasi-universel".- Pas d'écran d'age-gate observé :
screenshots/sport-home/desktop.pngmontre directement le catalogue de paris sans interstitiel ; idem pour les 3 autres routes. - Source visuelle : -
screenshots/sport-home/desktop.png,screenshots/sport/desktop.png,screenshots/casino/desktop.png,screenshots/promotions/desktop.png: aucune mention "18+" / "Interdit aux mineurs" / "Réservé aux adultes" visible above-fold, dans le header, ni dans le footer ouvert (header montre uniquement logo + login + langue + ARSJPA décoratif). - Constat :
Bet224 n'affiche aucune mention d'âge légal (18+ ou autre) sur les 4 routes principales et ne propose pas d'age-gate (écran de vérification d'âge avant accès au catalogue de cotes, de matches, de jeux casino). Un mineur navigant sur bet224.gn voit directement le catalogue sport et casino, y compris des jeux crash (Aviator) particulièrement addictifs. Le seuil d'âge légal en Guinée n'est pas sourcé en session (interdit de supposer 18 par défaut sans source officielle GN), MAIS le principe d'interdiction aux mineurs est sectoriellement universel.
- Impact attendu :
Pour la protection des mineurs : risque direct de captation d'un public mineur (interdit moralement et probablement légalement, à confirmer Legal-check). Pour l'opérateur : risque très élevé en cas de signalement ou d'enquête (médias, association, ARSJPA). Risque réputationnel et risque pénal selon cadre GN. Sur le plan moral sectoriel : manquement gravissime, quasi-universellement sanctionné par les régulateurs gambling matures. À traiter en priorité absolue indépendamment du cadre GN spécifique.
- Root cause :
Adaptation depuis le template italien où le disclaimer d'âge est dans header.disclaimer = "Il gioco è vietato ai minori di diciotto anni". Lors de la traduction en français pour la déclinaison GUINEA, ce disclaimer n'a PAS été traduit ni affiché. L'age-gate n'a probablement jamais été implémenté pour aucune déclinaison de ce template.
F-TRUST-01-11 : 15+ pages support/about/legal toutes en soft 404 (manquement structurel sectoriel)
- Sévérité : critical
- Route(s) :
mentions-legales,licence,jeu-responsable,responsible-gaming,privacy,politique-confidentialite,cgu,conditions,terms,contact,a-propos,qui-sommes-nous,aide,help,faq,bonus - Source primaire :
- Grep
body page="404"surseo-audit/.../crawl/html/*.raw.htmlretourne 23 fichiers, dont les 16 pages "support / legal" listées ci-dessus + pages techniques (multi-live, top-match, esport, loto, etc.). - Liste exhaustive sourcée :
mentions-legales.raw.html,licence.raw.html,jeu-responsable.raw.html,responsible-gaming.raw.html,privacy.raw.html,politique-confidentialite.raw.html,cgu.raw.html,conditions.raw.html,terms.raw.html,contact.raw.html,a-propos.raw.html,qui-sommes-nous.raw.html,aide.raw.html,help.raw.html,faq.raw.html,bonus.raw.html(toutes les 16 retournent<body page="404"...>). - Toutes retournent HTTP
200(pas un vrai 404), donc soft 404 = problème indexation SEO + perception utilisateur d'un site valide qui n'a juste pas le contenu attendu. - Source visuelle : - Pas de screenshot direct des pages 404. HTML rendu = template complet (header + cookie banner + footer caché) + bloc
404 Page non trouvée. - Constat :
Une partie massive de l'infrastructure de pages "support + legal + about" attendue d'un opérateur gambling YMYL n'existe pas côté serveur. Les seules URLs légales fonctionnelles sont les 2 du footer pointant vers le module promo (/promo/tutte/bet224_politique_confidentialite + /promo/tutte/bet224_conditions_generales), non crawlées donc contenu inconnu.
- Impact attendu :
Pour l'utilisateur : impossibilité d'accéder à toute information opérateur, contractuelle, support, légale via les URLs canoniques attendues. Pour le SEO : 16 soft 404 indexées comme contenu valide = signal négatif Google. Pour le régulateur ARSJPA : aucun contenu démontrant la conformité (mentions, licence, jeu responsable, T&C) accessible publiquement. Pour la réputation : si un journaliste, association ou autorité tente de vérifier l'opérateur via les URLs standard, échec systématique.
- Root cause :
Adaptation incomplète du template depuis la déclinaison italienne. Les pages support / legal / about ont vraisemblablement été désactivées ou jamais portées en GUINEA. La solution de contournement (mettre Politique et CGU dans le module promo) est non pérenne et fragmentaire.
F-TRUST-01-08 : Identifiants commerciaux SIRET/VAT-EU détectés en faux positifs ; aucun identifiant guinéen attendu (RCCM ou n° ARSJPA) exposé
- Sévérité : serious
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
conversion-signals/index.json→aggregate.routes_with_siret_or_vat = 2(sport et promotions)conversion-signals/sport.json→detailed.trust_signals.has_vat_eu = true,vat_excerpt = "BETBUILDER"(faux positif : "BETBUILDER" n'est pas un VAT EU)conversion-signals/promotions.json→detailed.trust_signals.has_vat_eu = true,vat_excerpt = "DE PROFITER"(faux positif : pas un VAT EU)conversion-signals/sport-home.jsonetconversion-signals/casino.json→has_siret = false,has_vat_eu = false,has_rcs = false.site-context.yaml→location.country = "GN"(Guinée), donc ni SIRET (FR), ni VAT-EU (UE), ni RCS (FR) ne sont les identifiants attendus. L'équivalent guinéen attendu est typiquement un numéro RCCM (Registre du Commerce et du Crédit Mobilier OHADA) et/ou un numéro d'agrément ARSJPA. Aucun n'est exposé.- Source visuelle : - Pas de bloc identifiants commerciaux visible sur les screenshots des 4 routes (header + above-fold + footer ouvert). Footer ouvert ne contient que 3 liens "AIDER" sans information opérateur.
- Constat :
Les détecteurs SIRET / VAT-EU ont remonté 2 faux positifs ("BETBUILDER", "DE PROFITER" sont juste des morceaux de texte capturés par regex permissive). Aucun identifiant commercial réel n'est exposé sur les 4 routes. Pour la juridiction guinéenne, l'identifiant attendu est un RCCM (OHADA) + un numéro d'agrément ARSJPA. Aucun n'est trouvé dans le crawl.
- Impact attendu :
Pour l'utilisateur : impossible d'identifier l'entité juridique exacte derrière Bet224 (raison sociale, forme juridique, capital, immatriculation). Pour le régulateur : aucun lien visible entre le site et l'entité titulaire d'un éventuel agrément. Pour Bet224 : risque réglementaire en cas d'enquête. Cross-link à F-TRUST-01-02 (mentions légales soft 404). Note méthodologique : le faux positif des détecteurs SIRET/VAT a induit aggregate.routes_with_siret_or_vat = 2 qui surévalue artificiellement la complétude trust ; à patcher dans le détecteur conversion-signals v1.3 (cf cross-angle).
- Root cause :
Aucune info opérateur publiée. Sur l'aspect détecteur : regex VAT-EU trop permissive (ne valide pas le format XX[0-9]+ strict, capture des mots majuscules de longueur similaire).
F-TRUST-01-09 : Aucun contact opérateur visible (email, téléphone, adresse, formulaire support) sur 4 routes
- Sévérité : serious
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
conversion-signals/index.json→aggregate.routes_with_contact_email = 0,aggregate.routes_with_contact_phone = 0(4/4 routes sans email ni téléphone visible)conversion-signals/sport-home.json→detailed.trust_signals.contact_email_visible = false,contact_phone_visible_in_footer = false,contact_links_count = 0- Pattern identique sur les 4 routes (
sport.json,casino.json,promotions.json). seo-audit/.../crawl/html/contact.raw.html:301:body page="404"(page contact = soft 404).seo-audit/.../crawl/html/aide.raw.html:301ethelp.raw.html:301: également soft 404.sport-home.raw.htmlcherchecg-contatti(ligne 315) :<div class="blocco-header flex-container cg-contatti"></div>(container vide, pas d'email ni téléphone injecté).- Source visuelle : -
screenshots/sport-home/desktop.png,screenshots/sport/desktop.png,screenshots/casino/desktop.png,screenshots/promotions/desktop.png: aucune zone "Contact", "Support 24/7", "Aide", "Service client" visible above-fold ni dans le footer fermé. Le footer ouvert (testé via inspection raw HTML) ne contient pas de bloc contact. - Constat :
Aucun email, numéro de téléphone, adresse postale ou formulaire de contact n'est exposé sur les 4 routes principales. Les pages /contact, /aide, /help sont toutes soft 404. Le container cg-contatti du header est présent dans le DOM mais vide.
- Impact attendu :
Pour l'utilisateur : impossible de contacter Bet224 avant un premier dépôt (utilisateur prudent qui veut tester le support) ou en cas de problème (dépôt non crédité, retrait bloqué, fermeture de compte). Sur YMYL gambling, l'absence de support visible est typiquement un anti-pattern sanctionné par les régulateurs matures. Pour la conversion : impact négatif sur premier dépôt + sur rétention (problème non résolu = churn). Pour le risque légal : à confirmer Legal-check (cadre GN), mais obligation morale forte.
- Root cause :
Container cg-contatti non rempli côté CMS. Probablement le template italien remplit ce container avec le téléphone du Concessionario ; lors de l'adaptation GUINEA, le contact n'a pas été configuré. Pages contact / aide non créées côté CMS.
F-TRUST-01-10 : Cookie banner sans option "Refuser" et avec consent passif "en poursuivant votre navigation"
- Sévérité : serious
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
sport-home.raw.html:349-355:<div id="cg-barra-cookies" class="row inline-flex flex-row justify-content-center cg-hide"><div>Ce site utilise des cookies, y compris des cookies de profilage tiers. Si vous souhaitez en savoir plus ou désactiver certains ou tous les cookies, lisez les informations. En poursuivant votre navigation, vous acceptez l'utilisation de tous les cookies.</div><div class="d-inline-flex flex-row justify-content-center"><a class="cg-cookies-ok" onclick="cg_acceptsCookies()">OK</a><a class="cg-cookies-more-info" href="/external_cms/pdf/Cookies_Policy.pdf" target="_blank">Plus d'informations</a></div></div>- Boutons : "OK" (accept all) + "Plus d'informations" (lien PDF externe). PAS de bouton "Refuser" ni de granularité (fonctionnels / analytics / profilage).
- Wording : "En poursuivant votre navigation, vous acceptez l'utilisation de tous les cookies" → consent passif (poursuite navigation = accept implicite).
site-context.yaml→to_confirm: "Cadre data / cookies de profilage applicable en Guinee + politique de confidentialite - Le site sert un bandeau annoncant des 'cookies de profilage tiers' sans page politique de confidentialite accessible (route 404)".- Source visuelle : -
screenshots/sport-home/desktop.pngzone bandeau top (x ≈ 0-720, y ≈ 0-22) : bandeau noir "Ce site utilise des cookies, y compris des cookies de profilage tiers. ... En poursuivant votre navigation, vous acceptez l'utilisation de tous les cookies." avec UN SEUL bouton vert "OK" (x ≈ 626, y ≈ 7) + lien bleu "Plus d'informations" (x ≈ 660, y ≈ 7). - Pattern identique sur les 4 routes (vérifié
screenshots/sport/desktop.png,casino/desktop.png,promotions/desktop.png). - Constat :
Le bandeau cookie ne propose pas de "Refuser" symétrique au "OK". Il n'y a pas de granularité (impossible de refuser uniquement le profilage tiers). Le wording "En poursuivant votre navigation, vous acceptez" est un consent passif (pattern contesté par CNIL FR 2020, GDPR EDPB, considéré non valide dans la plupart des juridictions matures). Lien "Plus d'informations" pointe vers PDF (/external_cms/pdf/Cookies_Policy.pdf) au lieu d'une page HTML navigable.
- Impact attendu :
Pour l'utilisateur : aucun choix réel sur les cookies de profilage. Pour le cadre data GN : à confirmer Legal-check (non sourcé en session), mais probable non-conformité à toute approche moderne de consentement. Pour Bet224 : risque légal selon cadre GN + risque réputationnel (utilisateur qui veut refuser ne peut pas, frustration). Effet conversion direct : neutre, mais détérioration trust.
- Root cause :
Template historique italien probablement, où le consent passif "navigando accetti" était toléré jusqu'à GDPR 2018. Non re-customisé pour standards 2024+. Cross-link F-CONV-01-08 (même finding angle CONV) ; reco potentiellement fusionnable.
F-TRUST-01-13 : Bonus very visibles above-fold mais conditions de mise (wagering) invisibles ; T&C bonus inaccessibles via URL standard
- Sévérité : serious
- Route(s) :
sport-home,sport,promotions - Source primaire :
screenshots/sport-home/desktop.pngzone hero (y ≈ 75-150) : 2 bannières "GAGNEZ 100% DE BONUS SUR VOTRE 1ER DÉPÔT JUSQU'À 1,000,000 GNF !" + "10% CASHBACK CHAQUE SEMAINE JUSQU'À 500,000 GNF !" (texte embarqué dans JPG donc non extrait par detector text mais visible).screenshots/sport/desktop.pngzone hero (y ≈ 80-130) : même bannière "GAGNEZ 100% DE BONUS ...".screenshots/promotions/desktop.pngzone hero (y ≈ 50-160) : bannière "MAXI BONUS / AUGMENTE TES GAINS JUSQU'À 500% ! PARIEZ ICI" + 3 cards "MAXI BONUS / CASHBACK SPORT / WELCOME SPORT" sans mention condition de mise visible.seo-audit/.../crawl/html/bonus.raw.html:301:body page="404"(page bonus = soft 404, donc T&C bonus dédiés non accessibles à cette URL).site-context.yaml→forbidden_patterns[1] = "conditions de mise (wagering) cachees ou en caracteres minuscules".- Cross-link : DEEP-CONV-01 → F-CONV-01-01 traite l'aspect wording promesse de gain. Le présent finding traite l'aspect trust = T&C inaccessibles.
- Source visuelle : - Détaillée ci-dessus dans Source primaire.
- Constat :
Les bonus sont massivement mis en avant (4 cards visibles sur 4 routes, chiffres importants en GNF), mais les conditions de mise (wagering requirements, ex. "30x sur le bonus avant retrait possible") ne sont jamais affichées above-fold. Une page /bonus qui pourrait centraliser les T&C est soft 404. L'utilisateur doit déduire qu'il faut chercher dans les CGU (/promo/tutte/bet224_conditions_generales, non crawlées) pour trouver le détail.
- Impact attendu :
Pour l'utilisateur : incompréhension probable des conditions réelles d'éligibilité au bonus (souvent : dépôt minimum, wagering 30-50x, jeux exclus, plafond de gain). Risque de déception forte au moment du retrait. Sur le plan trust : pattern reconnu comme dark pattern par UKGC, ANJ, MGA. Pour Bet224 : risque de plainte utilisateur + risque réglementaire selon cadre GN (à confirmer Legal-check). Pour la réputation : pattern qui alimente les avis négatifs gambling.
- Root cause :
Bannières JPG préparées sans mention de conditions (probablement pour ne pas alourdir le visuel). Page /bonus non créée côté CMS GUINEA, donc pas de page T&C bonus dédiée. T&C noyés dans les CGU générales si accessibles.
F-TRUST-01-12 : Traces de plateforme white-label italienne dans le code (ADM, Concessionario, RUA, italian language) sans contextualisation GN
- Sévérité : moderate
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
sport-home.raw.html:250(blocvar cg_LABEL, fichier de labels JSON localisés) : présence de chaînes italiennes hard-codées non traduites, exemples :"exclusion.determ":"Ti ricordiamo che in caso di autoesclusione, il Concessionario sarà tenuto a comunicare tale volontà all\\'Anagrafe dei Conti di Gioco, gestita dall\\'ADM, inserendoti nel Registro Unico degli Autoesclusi (RUA)...""signup.label.7days":"7 jours"(français), MAIS"recover.center.otp.title.type.email":"Controlla la tua posta elettronica"(italien)- Présence des chaînes "ADM" (régulateur italien), "Concessionario", "RUA" (Registro Unico degli Autoesclusi italien), "Anagrafe dei Conti di Gioco" (régulateur italien), "Il gioco è vietato ai minori di diciotto anni".
body data-systemcode="GUINEA"(sport-home.raw.html:301) confirme une déclinaison GN d'un template multi-pays.- Class CSS
consulta-footer(italien : "consulter le footer"),nascondi(italien : "cacher"),nascondifooter(italien) : structure de classes en italien. - Source visuelle : - Ces chaînes italiennes ne sont PAS affichées en façade utilisateur (présence uniquement dans les labels JSON qui ne servent qu'après login ou dans des modales internes). Donc effet utilisateur direct = nul pour le visiteur non inscrit. Effet sur audit trust = trace de white-label, signal d'attention pour Legal-check.
- Constat :
Le code source révèle que bet224.gn est une déclinaison guinéenne ("GUINEA") d'un template multi-pays initialement développé pour le marché italien (régulateur ADM, dispositifs ADM-spécifiques RUA, Anagrafe). Les labels JSON, les classes CSS, le wording disclaimer d'âge italien sont restés. Cela ne pose pas de problème pour le visiteur non-inscrit (chaînes non affichées), mais (1) signale un manque de localisation profonde, (2) suggère qu'après login l'utilisateur peut tomber sur des écrans italiens, (3) pose la question de la responsabilité éditoriale et juridique de l'opérateur (qui contrôle les contenus côté CMS guinéen ? Le concessionario italien ou une entité guinéenne séparée ?).
- Impact attendu :
Pour le visiteur non-inscrit : faible (chaînes non affichées). Pour l'utilisateur inscrit : risque d'écrans en italien dans certains parcours (auto-exclusion, vérification documents, recovery). Pour l'audit trust : signal d'attention. Pour Legal-check : à clarifier, quelle est l'entité opératrice réelle ? Bet224 est-il un concessionario indépendant titulaire d'agrément ARSJPA, ou un white-label d'un opérateur italien avec ARSJPA délégué ? L'agrément ARSJPA porte-t-il sur l'entité guinéenne ou l'entité italienne ?
- Root cause :
Plateforme technique white-label probablement fournie par un éditeur italien (SKS365 / Skill On Net / similaire, non sourcé en session). Adaptation marché GN limitée aux contenus visibles et au branding. Couche profonde (labels backoffice, modales internes) non traduite.
F-TRUST-01-14 : Politique cookie disponible uniquement en PDF externe (/external_cms/pdf/Cookies_Policy.pdf), non en HTML navigable
- Sévérité : moderate
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
sport-home.raw.html:353:<a class="cg-cookies-more-info" href="/external_cms/pdf/Cookies_Policy.pdf" target="_blank">Plus d'informations</a>- Le lien ouvre un PDF dans un nouvel onglet. PAS de page HTML cookie policy navigable accessible par URL canonique (
/cookies,/cookie-policynon testés mais cohérent avec le pattern soft 404 transverse F-TRUST-01-11). - Le bandeau cookie indique pourtant explicitement la présence de "cookies de profilage tiers" (sport-home.raw.html:350), ce qui implique une obligation typique de listing détaillé (fournisseurs tiers, finalités, durées), non vérifiable côté HTML.
- Source visuelle : -
screenshots/sport-home/desktop.pngbandeau top : lien bleu "Plus d'informations" à droite du bouton "OK". - Constat :
L'utilisateur souhaitant comprendre les cookies utilisés est renvoyé vers un PDF externe au lieu d'une page HTML navigable. Friction de lecture (téléchargement, ouverture lecteur PDF, pas de search-in-page natif efficace, pas de lien profond vers une section), accessibilité dégradée (PDF moins accessible qu'HTML pour les lecteurs d'écran, pas de zoom CSS responsive). Pour les "cookies de profilage tiers" mentionnés, le détail des fournisseurs (Google Analytics G-VLQSP6C303 visible en code, GTM-MZ7JZBPZ visible en code, autres ?) n'est pas vérifiable côté front sans télécharger le PDF.
- Impact attendu :
Pour l'utilisateur : friction maximale pour comprendre ses cookies = pratique non-conforme aux standards de transparence moderne. Pour l'accessibilité (cf cross-angle A11Y) : PDF non navigable au clavier facilement, friction lecteur d'écran. Pour le SEO : contenu non indexé HTML. Pour la conformité (cadre GN à confirmer) : à valider Legal-check, mais standard international = page HTML navigable obligatoire.
- Root cause :
Politique cookie héritée du template italien sous forme de PDF. Pas de portage HTML pour la déclinaison GUINEA. Le PDF est lui-même probablement obsolète (à vérifier date du PDF lors d'un crawl ciblé).
Cross-angle dependencies
- F-TRUST-01-01 (logo ARSJPA sans alt) recoupe
[REF: DEEP-A11Y-01](règle axe-coreimage-alt). Si DEEP-A11Y-01 a remonté une violationimage-altsur le node<img src="...ARSJPA.png">, R-TRUST-01-05 et la reco A11Y associée doivent être fusionnées parassemble_audit.py(même correctif, mêmes routes). - F-TRUST-01-04 (jeu responsable absent) recoupe
[REF: DEEP-CONV-01/F-CONV-01-02](absence lien jeu responsable footer mesurée côté CONV). R-TRUST-01-02 et R-CONV-01-02 traitent le même périmètre via 2 approches (CONV = ajouter liens footer, TRUST = créer les pages cible). À fusionner en reco unique "Créer pages + linker depuis footer" dansassemble_audit.py. - F-TRUST-01-06 (footer caché) recoupe
[REF: DEEP-CONV-01/F-CONV-01-04]et probablement[REF: DEEP-UX-01/F-XX](pattern accordion bottom = anti-pattern UX) et[REF: DEEP-A11Y-01/F-XX](navigation clavier complexifiée par collapse + lazy). R-TRUST-01-03 traite la solution structurelle. Cross-angle convergence forte, à fusionner. - F-TRUST-01-07 (mention âge + age-gate absent) recoupe
[REF: DEEP-CONV-01/F-CONV-01-02](forbidden_pattern). R-TRUST-01-04 = solution complète, R-CONV-01-02 = solution partielle (mention seule). À fusionner avec priorité R-TRUST-01-04 (plus complet : age-gate + mention). - F-TRUST-01-08 (faux positifs SIRET/VAT) recoupe
[REF: DEEP-CONV-01]indirectement (détecteurs partagés). La reco R-TRUST-01-08 inclut un patch détecteur v1.3 à propager côté toolkit (cross-cutting infra, pas spécifique bet224). - F-TRUST-01-09 (contact absent) recoupe
[REF: DEEP-CONV-01/F-CONV-01-06]. Reco R-TRUST-01-09 = même périmètre que R-CONV-01-06. À fusionner. - F-TRUST-01-10 (cookie banner) recoupe
[REF: DEEP-CONV-01/F-CONV-01-08](même finding angle CONV). R-TRUST-01-06 et R-CONV-01-XX = même action. À fusionner. - F-TRUST-01-13 (wagering invisible) recoupe
[REF: DEEP-CONV-01/F-CONV-01-01](promesses de gain interdites). R-TRUST-01-07 et R-CONV-01-01 sont complémentaires : R-CONV traite le wording forbidden, R-TRUST traite l'absence de T&C accessibles. À garder distinctes mais référencer mutuellement. - F-TRUST-01-14 (cookie policy PDF) recoupe
[REF: DEEP-A11Y-01](PDF moins accessible que HTML pour lecteurs d'écran). Cross-angle léger, pas de fusion nécessaire. - R-TRUST-01-01 (Legal-check + obtention client) est le PRÉALABLE à toutes les autres recos TRUST. Tant que R-TRUST-01-01 n'est pas exécutée, tous les
conformite_legale: falsedes recos R-TRUST-01-02 à R-TRUST-01-11 doivent rester false. Une fois Legal-check rendu, repasser les recos en true selon retour. Escalade obligatoire au red team Legal-check pour arbitrage final.
Limites
- Statut d'agrément Bet224 auprès de l'ARSJPA non vérifié : la liste officielle "Plateformes agréées" sur arsjpa.gov.gn n'a pas été extraite en session (cf
site-context.yamlexternal_authorities[0].caveat). Vérification requise par Legal-check + client (cf R-TRUST-01-01). - Contenu des pages CGU + Politique de confidentialité non vérifié : le footer pointe vers
/promo/tutte/bet224_politique_confidentialiteet/promo/tutte/bet224_conditions_generales, URLs non crawlées dans cette passe. Contenu réel inconnu, donc impossible d'auditer la conformité substantielle. À ajouter au crawl v2. - Cadre réglementaire guinéen non sourcé : seuil d'âge légal, mentions obligatoires en pied de page, cadre data / consentement cookies, cadre publicitaire gambling, dispositif d'auto-exclusion centralisé (équivalent RUA italien existe-t-il en GN ?). Tous ces points sont en
site-context.yamlto_confirmet bloquent le passage deconformite_legale: falseàtruesur les recos TRUST. À sourcer Legal-check. - Raison sociale opérateur non identifiée :
site-context.yaml→brand.canonical_legal: "". Bloque la rédaction finale des copy-ready des recos R-TRUST-01-02 (mentions légales), R-TRUST-01-03 (disclaimer footer), R-TRUST-01-08 (identifiants), R-TRUST-01-09 (contact). À obtenir client. - Géo-restriction d'accès non auditable : aucune source crawl ne permet d'évaluer si Bet224 applique un blocage géographique (juridictions où l'offre serait illégale, ex. accès depuis pays voisins où gambling interdit). Cf
site-context.yamlto_confirm. À cadrer Legal-check + direction. - Parcours utilisateur inscrit non audité : les écrans après login (où les chaînes italiennes hard-codées sont susceptibles d'apparaître, cf F-TRUST-01-12) n'ont pas été crawlés. Audit limité au visiteur anonyme.
- Screenshots mobile absents : seuls les screenshots desktop (1440px) sont disponibles. Les findings trust transverses (cookie banner, mention âge, age-gate, footer caché) sont probablement aggravés sur mobile (typiquement < 50 % du viewport disponible). Cf cross-angle MOBILE pour analyse spécifique. Patch crawl v2 = ajouter mobile screenshots.
- Modal d'inscription / dépôt / cashout non auditée :
aggregate.forms_total_all_routes = 0, signifiant que le funnel signup-deposit (où les obligations KYC, vérification d'âge réelle, consent data, T&C bonus à l'inscription se jouent) n'est pas couvert. Audit trust limité aux pages publiques. - Détecteur conversion-signals v1.2 ne capture pas les cookie banners : F-TRUST-01-10 est documenté par observation visuelle directe sur screenshot, pas par signal automatique. Patch détecteur v1.3 à prévoir (cross-angle infra).
- Aucune analytics de comportement utilisateur fournies par le client : impossibilité de mesurer combien d'utilisateurs ouvrent réellement le footer caché, combien refusent les cookies (ils ne peuvent pas refuser dans la version actuelle), combien quittent face à l'absence d'info opérateur. Trust findings basés sur observation structurelle, pas sur impact mesuré utilisateur.
- Vérification PDF Cookies_Policy.pdf : le contenu, la date et la pertinence du PDF référencé
/external_cms/pdf/Cookies_Policy.pdfn'ont pas été vérifiés (pas dans le crawl). À ajouter v2. - Pages tierces du module promo : URL
/promo/tutte/bet224_politique_confidentialiteet/promo/tutte/bet224_conditions_generalesnon crawlées, donc impossible de savoir si ce qu'elles servent EST une politique de confidentialité valide ou un placeholder. Fragilité supplémentaire à signaler.
Angle : UI
Persona
Source : site-context.yaml voice_and_tone.persona_primary.
sport-home: parieur sportif en Guinée, très majoritairement mobile, intéressé en priorité par le football. Sur cette route il atterrit pour scanner l'offre du jour. La page lui présente un logo Bet224 stylisé multicolore (jaune / vert / rouge), un bandeau cookies sombre, deux bannières promo jaunes (1 000 000 GNF, 10 % cashback), une nav sport rouge et des tableaux de cotes denses. Premier contact identité visuelle : surchargé et concurrentiel.sport: même persona, intent "construction d'un pari" sur une compétition. Densité d'information maximale (sidebar gauche + tableau central + ticket droit). La palette compte 14 backgrounds distincts mesurés cross-elements (design-system/sport.json→aggregated.unique_background_colors = 14), record du POC.casino: persona élargie (joueur casino en ligne). Carrousels horizontaux où chaque carte de jeu Spribe (Aviator / Dice / Goal / Plinko / Mines / Mini Roulette / Hilo) introduit sa propre couleur de fond saturée. La page est aussi la seule à dépasser 1 fold (screenshots/index.json→captures[2].desktop_full_height_px = 1629). Effet ressenti : kaléidoscope, pas de hiérarchie d'élévation.promotions: persona en intent "découverte d'un bonus" avant inscription. Trois cartes promoMAXI BONUS / CASHBACK SPORT / WELCOME SPORTavec deux familles concurrentes : CTA secondaire vert (EN SAVOIR PLUS) et CTA primaire rougeOUVRIR PIED DE PAGEfixé en bas. Hiérarchie visuelle des CTAs ambiguë (cf cross-angle CONV).
Synthèse exécutive
- Le design system observé est chaotique cross-route : 12 couleurs de texte uniques + 18 couleurs de fond uniques + 12 tailles de police + 11 border-radius distincts + 17 valeurs de padding-left mesurées. Source :
design-system/index.json→aggregate.colors.unique_foreground_count = 12,aggregate.colors.unique_background_count = 18,aggregate.typography.unique_font_size_count = 12,aggregate.borders.border_radius[].value(11 entrées),aggregate.spacing.padding_left[].value(12 entrées). Aucun brand guideline fourni par le client donc la cohérence interne est l'unique référentiel. - Brand color split : trois couleurs concurrentes occupent simultanément le rôle de "primary action" sur le même viewport (
#b21116rouge brand 33 fonds +#40b840vert clair 22 fonds +#0e6634vert foncé 10 fonds). Source :design-system/index.json→aggregate.colors.background_top[2,3,5]. Header sport-home : boutonLoginrouge à côté du boutonInscriptionvert, sans relation visuelle de hiérarchie (primary vs secondary indistinguable). - Échelle typographique non modulaire avec valeurs sub-pixel : 10 / 10.5 / 12 / 12.5 / 12.6 / 13 / 14 / 14.4 / 15 / 16 / 18 / 24 px, soit 10 valeurs entre 10 px et 16 px. Source :
aggregate.typography.font_sizes[].value. Les paliers 10.5 / 12.5 / 12.6 / 14.4 px sont des artefacts de calculemxfont-sizeparent, signe d'absence de tokens typographiques déclarés. - Spacing et radius ad-hoc avec valeurs sub-pixel et plages exotiques : padding 1.5 / 1.8 / 3.75 / 4.5 / 7.5 px (
aggregate.spacing.padding_top[].value), border-radius 0 / 2.5 / 3 / 4 / 5 / 6 / 8 / 12 / 100 % / 600 px / 999 px (aggregate.borders.border_radius[].value). Cohabitation 100 % et 999 px et 600 px pour produire des formes circulaires équivalentes = absence de convention partagée. - Hiérarchie d'élévation absente :
aggregate.effects.box_shadows[]ne contient qu'une seule valeur,"none"(count 496). Aucune ombre portée mesurée sur les 4 routes. Les cards de jeux casino, cartes de cotes, cartes de promo, header, footer reposent uniquement sur des contrastes de couleurs pour se distinguer. Sur un site dense en informations (notamment casino et sport), c'est un déficit de lisibilité. - Logo Bet224 stylisé multicolore (jaune / vert / rouge) en haut à gauche : porte simultanément les trois couleurs concurrentes du système. Source visuelle :
screenshots/sport-home/desktop.pngzone x=15-145, y=35-70. Effet ressenti : le logo lui-même brouille la lecture de la hiérarchie des CTAs.
Findings
F-UI-01-01 : Brand colors concurrentes pour le rôle CTA primaire (rouge + 2 verts)
- Sévérité : serious
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
design-system/index.json→aggregate.colors.background_top[2].value = "rgb(178, 17, 22)"(#b21116),count = 33,contexts = ["[class*='btn']", "[role='button']", "a", "button", "li"]design-system/index.json→aggregate.colors.background_top[3].value = "rgb(64, 184, 64)"(#40b840),count = 22,contexts = ["[class*='btn']", "[role='button']", "a", "button"]design-system/index.json→aggregate.colors.background_top[5].value = "rgb(14, 102, 52)"(#0e6634),count = 10,contexts = ["button"]design-system/index.json→aggregate.colors.background_top[4].value = "rgb(255, 0, 0)"(#ff0000),count = 15,contexts = ["[class*='badge']"](rouge pur supplémentaire pour badges, n'utilise pas le rouge brand#b21116)- Source visuelle : -
screenshots/sport-home/desktop.pngzone x=1245-1310, y=35-75 : boutonLoginfond rouge#b21116à côté du boutonInscriptionfond vert#40b840. Aucune hiérarchie visuelle (mêmes dimensions, mêmes radius, mêmes poids typographiques). screenshots/promotions/desktop.pngzone x=735-855, y=485-525 : CTAsEN SAVOIR PLUSen vert#0e6634(vert foncé, contexte cards promo). En bas droite x=575-720, y=535-570 :OUVRIR PIED DE PAGEen rouge#b21116. Trois rôles d'action coexistent en même viewport sans clé de lecture.screenshots/sport-home/desktop.pngzone x=10-260, y=80-100 : nav sportsSports / Virtuel / Promo / CasinoavecSportsen rouge#b21116. Le rouge sert simultanément à "primary CTA" (Login), à "rubrique active" (Sports), à "badge" (#ff0000), à "labels d'alerte ticket".- Constat :
Trois couleurs distinctes occupent simultanément le rôle de couleur d'action / primary CTA : rouge brand #b21116, vert clair #40b840, vert foncé #0e6634. Sur le header sport-home, le bouton Login (rouge) et le bouton Inscription (vert) sont visuellement de même importance, alors que Inscription est l'action de conversion prioritaire pour un site de paris (objectif d'acquisition). Aucune convention "primary / secondary / destructive" n'émerge. Le rouge sert simultanément à signaler l'action principale, l'item de navigation actif, le badge d'alerte (avec deux nuances de rouge différentes en plus, #b21116 brand vs #ff0000 pur), ce qui dilue la signification.
- Impact attendu :
Pour le persona parieur mobile primaire, la hiérarchie des actions n'est pas lisible au premier regard. Le CTA de conversion principal (Inscription) est en compétition visuelle directe avec Login, qui est une action utilisateur déjà-acquis. Conséquence probable : taux de clic Inscription diminué (à mesurer si analytics disponibles). Sur les routes casino et promotions, la multiplication des accents colorés réduit aussi la rétention du chemin de lecture.
- Root cause :
Absence de design tokens couleur (--color-primary, --color-success, --color-danger) déclarés explicitement. Les CSS custom properties ne sont pas extractibles avec analyze_design_system.py v1.0 qui ne capture que les computed styles (cf schemas-product-audit-v1.0.md limites connues design-system). Les couleurs sont vraisemblablement écrites en dur dans plusieurs fichiers CSS, sans convention partagée.
F-UI-01-02 : Échelle typographique non modulaire avec 10 valeurs sub-16px et artefacts sub-pixel
- Sévérité : serious
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
design-system/index.json→aggregate.typography.unique_font_size_count = 12design-system/index.json→aggregate.typography.font_sizes[].valueénumérées :10px(count 147),12px(134),16px(54),10.5px(35),14px(31),15px(27),18px(23),24px(15),12.6px(14),13px(12),12.5px(2),14.4px(2)- Per-route :
design-system/casino.jsonroute signalée 10 sizes uniques (design-system/index.json→per_route[2].unique_font_sizes = 10),sport-home8,sport8,promotions9 - Source visuelle : -
screenshots/sport-home/desktop.pngzone x=10-260, y=80-100 : nav sports rendue en taille très fine (correspond à10pxou10.5px, le plus fréquent dans le set, count 147+35). Lisibilité limite sur viewport desktop 1440. screenshots/casino/desktop.pngzone y=350-500 (carrousel Top 10) : les numéros 1-2-3-4-5 en énorme (estimés ~72-96 px, non capturés par le sampler car déclarés enemou Image / SVG), alors que les libellésTop Providersetc. sont en 16-18 px. Saut typographique extrême sans niveaux intermédiaires.- Constat :
L'échelle typographique compte 12 valeurs cross-route mesurées, dont 10 entre 10 px et 16 px (10px, 10.5px, 12px, 12.5px, 12.6px, 13px, 14px, 14.4px, 15px, 16px). Les valeurs 10.5px, 12.5px, 12.6px, 14.4px sont caractéristiques d'un calcul em ou rem appliqué à un parent dont la taille est variable, signe d'absence de tokens typographiques explicites. La valeur dominante 10px (count 147) est plus petite que la recommandation universelle ergonomie web 12 px minimum pour body, et plus petite que le default browser 16 px par un facteur 1.6 fois.
- Impact attendu :
Lisibilité dégradée pour la nav, les libellés de catégorie, les méta-informations (heures, ratios). Sur mobile, où le persona primaire est concentré, un 10px rendu sur écran réduit devient quasiment illisible. La multiplication des niveaux dans la plage 10-16 px empêche aussi le designer d'établir une hiérarchie claire (qu'est-ce qui est un label H4 vs un caption vs un body small ?). Implication a11y croisée : sur axes WCAG 1.4.4 (reflow / zoom) et 1.4.12 (text spacing), une typographie en sub-pixel est fragile au redimensionnement.
- Root cause :
Cocktail probable : reset CSS héritage (Bootstrap legacy font-size: .875rem qui donne 14px x 0.9 = 12.6px sur certains containers), absence de design tokens --font-size-xs / sm / base / md / lg / xl, multiples feuilles CSS empilées sans réconciliation.
F-UI-01-04 : Onze valeurs de border-radius distinctes, conventions cercle multiples
- Sévérité : serious
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
design-system/index.json→aggregate.borders.border_radius[]énumérés (count décroissant) :0px(329),4px(51),3px(32),2.5px(26),999px(14),100%(12),5px(11),12px(9),6px(7),8px(4),600px(1)- Soit 11 valeurs uniques de radius dans le système.
- Boutons et inputs partagent au moins 4 conventions distinctes :
4px(count 51 sura, button, input),3px(32 surbutton, input, [class*='btn'], [class*='badge']),2.5px(26 sur[class*='btn'], [class*='cta'], a, button, input, select),12px(9 surbutton, [class*='button']). - Trois conventions distinctes pour produire un cercle :
999px(14 sur[class*='button'], [role='button'], button),100%(12 sur[role='button'], a, li),600px(1 sura). - Source visuelle : -
screenshots/sport-home/desktop.pngzone x=1245-1395, y=35-75 : boutonsLogin(rouge) etInscription(vert) avec coins arrondis légers (radius ~4px estimé). Sur la même page, zone x=665-825, y=100-130 : bouton2 COLONNESà droite a un radius nettement plus prononcé (~12 px estimé). Deux boutons CTA principaux + un toggle layout = trois conventions. screenshots/promotions/desktop.pngzone y=485-525 :EN SAVOIR PLUS(cards promo) radius ~2.5px (presque carré). vsLoginx=1245-1310, y=35-75 radius4px. Boutons d'actions différents dans la même viewport avec radius différents.screenshots/casino/desktop.pngzone y=120 ligneMost Wanted / Alexander's Fortune / Aviator / AVAJET: badges ronds des jeux (radius100%probable). Mais zone y=140 (icônes joueurs avatars) : autre radius rond. Cohabitation100%et999pxinvisible à l'œil mais inutile à coder.- Constat :
Onze valeurs distinctes de border-radius mesurées cross-route. Aucune logique d'échelle (les valeurs 2.5px, 3px, 4px, 5px, 6px, 8px sont toutes représentées dans des contextes recouvrants button / a / input). Trois conventions pour générer un cercle parfait (999px, 100%, 600px) avec un cas singleton à 600px qui suggère un copier-coller hasardeux. Boutons CTA principaux (Login, Inscription) à 4px mais d'autres boutons CTA [class*='cta'] à 2.5px.
- Impact attendu :
Incohérence visuelle perçue subliminalement (le site "fait artisanal" car ses formes ne sont pas accordées). Dette technique : chaque nouveau composant doit choisir parmi 11 valeurs sans guideline. Risque de divergence accrue avec le temps.
- Root cause :
Pas de design tokens radius (--radius-sm, --radius-md, --radius-pill). Valeurs sub-pixel 2.5px viennent probablement d'un em x base parent atypique (signe que le calcul est dynamique, pas un choix designer). 999px et 100% cohabitent par habitudes CSS distinctes des contributeurs.
F-UI-01-03 : Quatre familles de polices détectées, trois stacks system parasites
- Sévérité : moderate
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
design-system/index.json→aggregate.typography.unique_font_family_count = 4design-system/index.json→aggregate.typography.font_families[]:"DMSans, sans-serif"count 490, contexts["a", "body", "footer", "h2", "h5", "main"](famille principale réelle)"-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen-Sans, Ubuntu, Cantarell, \"Helvetica Neue\", sans-serif"count 3, contexts["html"](stack system sur html)"\"Open Sans\", Arial, sans-serif"count 2, contexts["body"](Open Sans déclaré sur certains body)"-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen, Ubuntu, Cantarell, \"Open Sans\", \"Helvetica Neue\", sans-serif"count 1, contexts["html"](deuxième stack system légèrement différent)- Source visuelle : - Non observable au pixel près sur les screenshots (les 3 stacks parasites représentent 6 nodes au total vs 490 pour DMSans, donc visuellement absorbés par le rendering principal). Mais la déclaration de 4 familles distinctes sur les éléments racines
htmletbodyest mesurée structurellement. - Constat :
DMSans est la police principale réelle du site (count 490, présente sur body, headings, links, footer, main). Trois autres stacks de polices sont déclarés simultanément, dont deux variantes presque identiques du stack system-ui sur html (différence d'orthographe entre Oxygen-Sans et Oxygen) et un fallback "Open Sans", Arial, sans-serif sur certains body. Aucun de ces fallbacks ne s'applique en pratique (DMSans charge correctement), mais leur cohabitation dans la cascade indique l'empilement de plusieurs frameworks CSS non réconciliés (réinitialisation html { font: ... } Bootstrap + autre framework + override DMSans).
- Impact attendu :
Aucun rendu dégradé visible si DMSans charge correctement. Impact réel : poids CSS supplémentaire (multiples déclarations conflictuelles), risque de FOUT (flash of unstyled text) plus marqué si DMSans tarde à charger (le fallback Helvetica Neue ou Open Sans est très différent métriquement de DMSans, donc shift visible). Dette de maintenance : un futur designer ne sait pas quelle famille est canonique.
- Root cause :
Empilement de frameworks CSS : reset Bootstrap, surcouche template, ajout custom DMSans. Aucune purge des règles intermédiaires.
F-UI-01-05 : Spacing ad-hoc avec valeurs sub-pixel et 12 valeurs distinctes de padding-left
- Sévérité : moderate
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
design-system/index.json→aggregate.spacing.padding_left[]12 valeurs :0px(312),6px(44),8px(35),5px(18),24px(16),7.5px(13),9px(13),20px(12),10px(12),12px(11),15px(8),16px(2)aggregate.spacing.padding_right[]14 valeurs distinctes (mêmes patterns), introduisant aussi17.5pxet28pxaggregate.spacing.padding_top[]15 valeurs distinctes dont sub-pixel1.5px,1.8px,3.75px,4.5px,7.5px,2.5pxaggregate.spacing.padding_bottom[]15 valeurs distinctes- Valeurs hors échelle 4/8 mesurées :
1.5px,1.8px,2.5px,3px,3.75px,4.5px,5px,6px,7.5px,9px,10px,12.0938px(margin),15px,19.3594px(margin),17.5px - Source visuelle : -
screenshots/sport-home/desktop.pngzone y=80-100 (nav sports) vs y=100-130 (sous-nav PREMATCH / LIVE / MULTIBET) : le rythme vertical change visiblement (compact vs aéré) sans transition. Source paddings distincts probables (2pxsur button vs8pxsur a). screenshots/casino/desktop.pngzone y=130-220 (cards Spribe Games) : cards ont des paddings internes variables d'une catégorie à l'autre (la card Aviator a un padding bottom différent du card Dice).- Constat :
Le système de spacing ne suit aucune échelle modulaire (multiples de 4 ou 8 pixels canonique). Les valeurs sub-pixel comme 1.5px, 1.8px, 3.75px, 4.5px, 7.5px, 12.0938px, 19.3594px indiquent que les paddings et marges sont calculés via em ou pourcentages dans une grille variable, sans tokens explicites. La fréquence de 0px (count 312 sur padding-left, 304 sur padding-bottom) masque le bruit, mais sur les éléments interactifs (boutons, liens), 12 à 15 valeurs uniques de padding cohabitent.
- Impact attendu :
Rythme visuel inconsistant cross-pages. Lors d'ajouts futurs de composants, aucune référence partagée, donc chaque nouvelle classe ajoute encore une valeur unique. Pas d'effet bloquant utilisateur immédiat, mais dette long terme et difficulté de maintenance.
- Root cause :
Empilement Bootstrap (utilities .p-1, .p-2 en rem qui produisent du sub-pixel selon font-size hérité) + classes utilitaires custom + styles inline. Aucun token spacing déclaré côté design system observable.
F-UI-01-06 : Hiérarchie d'élévation absente, zéro box-shadow mesurée
- Sévérité : moderate
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
design-system/index.json→aggregate.effects.box_shadows[]contient une seule entrée :{"value": "none", "count": 496, "contexts": ["body", "footer", "h2", "h5", "html", "main"]}. Aucune autre valeur d'ombre détectée sur 496 observations cumulées.- Pour mémoire,
aggregate.effects.opacity[]contient 5 valeurs distinctes (1,0.5,0,0.35,0.7), mais l'opacité n'est pas un substitut à l'élévation. - Source visuelle : -
screenshots/sport-home/desktop.png: le bandeau cookies, le header, la sous-nav, le carrousel de bannières promo, lesTournois à la une, le tableauDécouvrirn'ont aucune ombre portée. Les sections se distinguent uniquement par changements de fond (blanc sur gris#f6f6f6sur blanc). Aucune carte n'est élevée. screenshots/casino/desktop.pngzone y=130-220 (Spribe Games) : les 7 cards de jeux sont juxtaposées sans relief. Les fonds colorés saturés portent toute la charge visuelle, sans ombre pour les détacher.screenshots/promotions/desktop.pngzone y=265-540 (cardsMAXI BONUS / CASHBACK SPORT / WELCOME SPORT) : 3 cards alignées, fond gris uniforme, contour invisible, aucune ombre. La hiérarchie repose entièrement sur la typographie et les CTAs internes.- Constat :
Aucune box-shadow n'est appliquée nulle part sur les 4 routes (aggregate.effects.box_shadows[] n'a qu'une valeur "none"). Un système de design moderne courant prévoit au moins 3 niveaux d'élévation (card de base, card hover, modal / popover). Bet224 n'en a aucun. Conséquence : pour distinguer une carte interactive d'un bloc passif, le site doit empiler des couleurs de fond saturées ou des bordures (cf F-UI-01-04 ci-dessus). Sur les routes denses en cards (casino, promotions, sport tableau de cotes), la lisibilité dépend uniquement du contraste de couleur.
- Impact attendu :
Densité visuelle peu structurée sur les pages dépassant 1 fold (casino : 1629 px de hauteur scrollable mesurée, screenshots/index.json → captures[2].desktop_full_height_px = 1629). Le scanner visuel ne peut pas distinguer les zones cliquables des zones d'information passive autrement que par couleur. Pour le persona mobile (qui domine), l'absence d'élévation est plus pénalisante encore (les écrans petits compensent traditionnellement par du shadow).
- Root cause :
Choix design pré-existant (style "flat ultra plat") ou simplement absence de système d'élévation au sens design. Pas observable depuis les inputs disponibles.
F-UI-01-07 : Logo Bet224 stylisé multicolore (4 couleurs) entre en compétition avec la palette CTAs
- Sévérité : moderate
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
screenshots/sport-home/desktop.pngzone x=15-145, y=35-70 : logoBet224rendu avec lettres en couleurs distinctes (B noir / e jaune / t noir / 2 jaune / 2 vert / 4 rouge, en italique). Visible à l'identique sur les 4 routes (template header commun, cf cross-angle DEEP-A11Y-01F-A11Y-01-01).site-context.yaml→brand.canonical_display = "Bet224"(casing à confirmer post-crawl, marqué[A VERIFIER]) ; pas d'asset logo, pas de palette officielle, pas de guideline d'usage.- Couleurs du logo recoupent les 3 brand colors concurrentes : rouge
#b21116/ vert#40b840/ jaune (non capturée paraggregate.colorscar probablement image PNG, pas couleur CSS). - Source visuelle : -
screenshots/sport-home/desktop.pngzone x=15-145, y=35-70 (logo) vs zone x=1245-1395, y=35-75 (CTAsLoginrouge +Inscriptionvert) : le logo utilise simultanément les couleurs des deux boutons CTA. Quand l'œil scanne du logo vers les CTAs, il n'a pas de signal différenciant "logo = identité" vs "bouton = action". screenshots/sport/desktop.png: même logo, même CTAs, même cohabitation chromatique.- Constat :
Le logo Bet224 embarque 4 couleurs (noir + jaune + vert + rouge en italique pour les chiffres 224). Ces couleurs sont les mêmes que celles utilisées pour les CTAs (Login rouge brand, Inscription vert brand). Conséquence visuelle : le logo, normalement un point d'ancrage identitaire stable, devient un élément concurrentiel des CTAs. Aucune charte client ne précise si cette stylisation est une variante autorisée ou un PNG historique à refondre. Le site-context flagge déjà forms_to_avoid = ["bet224", "BET224", "Bet 224", "bet-224"] mais ne dit rien sur la stylisation couleur.
- Impact attendu :
Le logo n'aide pas à fixer une couleur brand prioritaire (au contraire, il en utilise 3-4). Pour un nouveau visiteur, l'identité visuelle est floue (n'est-ce pas un site rouge ? vert ? jaune ?). Effet de confiance dégradé sur un site YMYL gambling où la signalisation visuelle de l'opérateur compte.
- Root cause :
Logo PNG legacy (référencé external_cms/GUINEA/img/logo-bet-224.png dans le DOM, cf axe-results/sport-home/desktop.json → violations[1].nodes[0].target = ["a[href=\"/\"] > img"]). Probablement design initial sans charte couleur formalisée.
F-UI-01-08 : Route casino concentre la plus haute densité chromatique du POC (kaléidoscope)
- Sévérité : moderate
- Route(s) :
casino - Source primaire :
design-system/index.json→per_route[2].route_slug = "casino",per_route[2].unique_background_colors = 9,per_route[2].unique_colors = 8,per_route[2].unique_font_sizes = 10(record du POC pour font_sizes)- Comparaison cross-route :
per_route[0] sport-home10 bg / 9 fg / 8 sizes,per_route[1] sport14 bg / 10 fg / 8 sizes,per_route[2] casino9 bg / 8 fg / 10 sizes,per_route[3] promotions7 bg / 7 fg / 9 sizes screenshots/index.json→captures[2].desktop_full_height_px = 1629(seule route POC dépassant 1 fold de loin ; sport-home/sport plafonnent à900px, promotions à950px)- Source visuelle : -
screenshots/casino/desktop.pngzone y=130-220 (Spribe Games) : 7 cards juxtaposées avec 7 couleurs de fond saturées différentes (Aviator rose / Dice violet / Goal vert / Plinko bleu marine / Mines bleu turquoise / Mini Roulette vert sapin / Hilo jaune). Aucune de ces 7 couleurs n'est dans la palette brand mesurée (aggregate.colors.background_top), elles sont probablement portées par des images de fond (background-image) non décomposées paranalyze_design_system.py(qui ne capture quebackgroundColor, pasbackgroundImage). screenshots/casino/desktop.pngzone y=240-340 (Top 10) : numéros 1-5 en rouge brand très grand, fond image (carrouselHot to Burn,Queen of Gods,Mining Hot,Book of...,Lobster Bob).screenshots/casino/desktop.pngzone y=370-500 (Evolution) : carrouselBlackJackrépété 7 fois avec photos joueurs (humains visibles).- Constat :
Bien que unique_background_colors = 9 mesuré soit similaire aux autres routes, la route casino concentre la plus haute densité visuelle perçue car (a) elle dépasse 1 fold de 81 %, (b) les cards Spribe Games introduisent 7 couleurs supplémentaires non capturées par le sampler (images de fond), (c) elle a le record de unique_font_sizes (10 valeurs) signalant des sauts typographiques importants. La cohabitation des numéros géants Top 10 rouges, des photos humains noir/blanc Evolution, des logos providers gris (The Ear, Evolution, EvoPlay, GAMZIX, NETENT), et des cards saturées Amigo Gaming produit un effet kaléidoscope sans hiérarchie.
- Impact attendu :
Cognitive load maximal sur la route de découverte des jeux, pénalisant la conversion vers un jeu spécifique. Risque de paralysie de choix. Pour le persona casino (élargi par rapport au persona primary sport), le sentiment "trop d'options non hiérarchisées" peut détourner vers un concurrent. Implication YMYL : densité visuelle élevée + couleurs saturées + animations probables (carrousels auto) peuvent être considérés comme des dark patterns d'engagement (à recouper avec angle CONV et red team Legal-check).
- Root cause :
Stratégie commerciale "vitrine de catalogue" (montrer le maximum de jeux above-the-fold pour signaler la richesse de l'offre). Conflit avec l'objectif design "hiérarchiser pour faciliter le choix". Pas de page interne pour chaque catégorie qui permettrait de réduire la densité par route.
F-UI-01-09 : Bandeau cookies header full-width avec palette étrangère à la charte (gris + jaune + bleu)
- Sévérité : moderate
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
design-system/index.json→aggregate.colors.background_top[8].value = "rgb(46, 97, 232)"(#2e61e8), count 4, contexts["a"](bleu utilisé sur lien dont probablementPlus d'informationsdu banner cookies)design-system/index.json→aggregate.colors.foreground_top[6].value = "rgb(0, 123, 255)"(#007bff), count 22, contexts["a"](bleu Bootstrap)design-system/index.json→aggregate.colors.background_top[11].value = "rgb(128, 128, 128)"(#808080), count 2, contexts["html"](gris neutre pas dans la charte brand)design-system/index.json→aggregate.colors.background_top[12].value = "rgba(0, 0, 0, 0.15)", count 2, contexts["nav"](transparency layer header)- Source visuelle : -
screenshots/sport-home/desktop.pngzone x=0-720, y=0-30 (bandeau cookies plein écran top) : fond noir/gris très foncé, texte blanc petit, boutonOKjaune-vert vif (#cae500estimé, pas dans la palette mesurée donc probablement appliqué inline ou via une feuille externe), boutonPlus d'informationsbleu (#2e61e8ou#007bffBootstrap). - Présence du même bandeau sur les 4 routes (template global).
- Constat :
Le bandeau cookies en haut occupe la pleine largeur, persiste sur les 4 routes, et utilise une palette étrangère à la charte du site : fond gris très foncé (vs blanc / #f6f6f6 du site), bouton OK jaune-vert (vs verts brand #40b840 ou #0e6634), bouton Plus d'informations bleu (vs absence de bleu dans le reste de la palette CTAs). Le bleu #007bff (count 22) est probablement le bleu Bootstrap par défaut, jamais réécrit. Le banner est probablement injecté par un widget tiers (CMP cookies) non thématisé.
- Impact attendu :
Premier élément vu (en y=0, full-width) brise l'identité visuelle avant même que l'utilisateur arrive sur le contenu. Sur mobile (où le persona primaire est concentré), ce bandeau occupera proportionnellement encore plus d'espace, repoussant le contenu utile sous le fold. Impact UX et confiance.
- Root cause :
Widget CMP cookies tiers injecté sans personnalisation visuelle (couleurs par défaut). Pas de feuille de style override appliquée. Cohabite avec le reste du chrome browser (10:53 Dimanche, 24 Mai 2026 visible en y=0 dans la capture, suggérant que la capture est faite avec barre OS visible, pas un défaut du site).
Cross-angle dependencies
- A11Y (DEEP-A11Y-01) :
R-UI-01-01(réservation rouge#b21116au primary CTA) ne contredit pas mais ne suffit pas à résoudre[REF: DEEP-A11Y-01/F-A11Y-01-06](contraste Betbuilder 1.3:1) ni[REF: DEEP-A11Y-01/F-A11Y-01-07](contraste filtre Sport 2.6:1). Les couleurs incriminées (#212121background,#83ae30background, etc. cfDEEP-A11Y-01.mdrecos A11Y-05 et A11Y-06) doivent être harmonisées dans une seule passe avec la définition des tokens couleurs proposés dans R-UI-01-01. Recommandation pourassemble_audit.py: fusionner R-UI-01-01 + R-A11Y-01-05 + R-A11Y-01-06 en une reco unique "Refonte palette de couleurs avec contrastes AA et tokens primary / success / danger / warning". Le contraste WCAG est l'argument prioritaire (a11y conformité) ; la cohérence brand suit. - A11Y (DEEP-A11Y-01) :
R-UI-01-08(personnalisation bandeau cookies) doit être harmonisé avec[REF: DEEP-A11Y-01/R-A11Y-01-13](englober#cg-barra-cookiesdans un landmark<aside role="region">ou<dialog>). Le CSS override proposé en R-UI-01-08 ne casse pas le landmarking proposé en A11Y mais doit être appliqué en post-traitement DOM, pas en remplacement du wrapping sémantique. - CONV (à venir, DEEP-CONV-01) :
F-UI-01-01(brand colors concurrentes pour CTAs) est intrinsèquement un finding CONV aussi. Le CTAInscription(objectif d'acquisition principal) est dilué visuellement par la cohabitation avecLogin.conversion-signals/index.json→aggregate.primary_ctaà vérifier dans DEEP-CONV-01 pour savoir si le détecteur a bien identifiéInscriptioncomme primary_cta ou si le détecteur a éluLogin(qui serait alors un faux positif lié à la confusion chromatique). Recommandation pour DEEP-CONV-01 : croiserprimary_cta.background_coloravecaggregate.colors.background_toppour scorer la concurrence visuelle. - MOBILE (à venir, DEEP-MOBILE-01) :
F-UI-01-06(absence box-shadow) sera plus pénalisante sur mobile (le persona primaire) car les écrans réduits compensent traditionnellement la densité visuelle par l'élévation.F-UI-01-02(taille10pxdominante) sera particulièrement critique sur mobile (lisibilité dégradée). Recommander dans DEEP-MOBILE-01 un mesurage destouch targetset de la lisibilité réelle à 390x844 viewport. - TRUST (à venir, DEEP-TRUST-01) :
F-UI-01-07(logo multicolore) recoupe la perception de confiance brand sur un site YMYL gambling. Sur les sites concurrents gambling régulés (sources non extraites en session), le logo opérateur est généralement monochrome ou bicolore strict pour signaler le sérieux. Cross-référencer avec l'analyseconversion-signals/index.json→aggregate.routes_with_legal_linksetroutes_with_siret_or_vat(déjà flaggés dans lesite-context.yamlfacts.to_confirm). La refonte du logo (R-UI-01-07) gagne en priorité si le red team Legal-check confirme une exigence de signalétique opérateur agréé. - cross-angle-conflict potentiel :
R-UI-01-09(uniformisation backgrounds Spribe Games) entre en conflit avec un objectif commercial probable du client "vitrine vive". À escalader au red team UX-check pour arbitrage trade-off (cognitive load vs perception d'offre riche). Décision à documenter avant assemblage final.
Limites
- Mobile non audité :
screenshots/index.json→captures[].mobile_path = nullsur les 4 routes (POC desktop only). Conséquence : les jugements de hiérarchie visuelle, densité, lisibilité, échelle typographique sont desktop-only. Pour le persona primary (parieur mobile Guinée), un audit mobile complet est indispensable avant livraison FULL. Estimation finding mobile pourrait doubler ou tripler (touch target size, viewport overflow, font-size10pxillisible sur écran réduit). - Brand guidelines client absents :
site-context.yamlne contient ni palette officielle, ni typo officielle, ni iconographie, ni guideline d'usage du logo. Tous les jugements de cohérence visuelle reposent sur la cohérence interne observée cross-routes, pas sur un écart à une charte normative. Toute reco UI ci-dessus (notamment R-UI-01-01 sur primary CTA rouge#b21116, R-UI-01-07 sur refonte logo) doit être validée par le client. Si le client a une charte ailleurs (PDF, slide deck), elle est à fournir pour réaliser un audit de conformité. - CSS custom properties non extraites :
analyze_design_system.pyv1.0 ne capture que les computed styles, pas les:root { --token-name }déclarés (cfschemas-product-audit-v1.0.mdlimites connuesdesign-system). Si Bet224 a déjà des tokens déclarés et juste mal appliqués, l'analyse les manque. Une passe statique v1.2 (cf brief) résoudrait. Lecture manuelle de raw HTML / CSS non effectuée dans ce POC (les fichiers CSS externes ne sont pas dans le crawl, et le<style>inline du raw HTML n'a pas été dépouillé). Le client peut fournir ses sources CSS pour vérification. - Sampling design-system plafonné :
design-system/index.json→sampled_selectors[]plafonne à 500 nodes par route (cf codeanalyze_design_system.py). Sur la route sport (per_route[1].nodes_sampled = 185) et casino (per_route[2].nodes_sampled = 136), le sampler n'épuise pas les nodes mais reste une approximation. Des classes très peu utilisées (par exemple un thème modal qui n'apparaît qu'en interaction) peuvent être manquées. - Pas d'analyse des images d'arrière-plan : les cards de jeux casino (Spribe Games, Amigo Gaming) ont leurs couleurs portées par des
background-imagePNG/SVG, pas parbackgroundColor.analyze_design_system.pycapturebackgroundImagemais ne décompose pas les couleurs internes des images. Conséquence : la palette mesurée sous-estime le chaos chromatique réel de la route casino (les 7 couleurs des cards Spribe Games n'apparaissent pas dansaggregate.colors.background_top). - Pas d'analyse des states hover / focus / active : les
analyze_design_system.pycapture les états par défaut uniquement. Les éventuelles couleurs de hover (CTAs qui s'allument, cards qui s'ombrent) ne sont pas mesurées. Pour un audit UI complet, capturer ces états (V1.2 prévue). - Pas de comparaison aux concurrents : aucun benchmark concurrent gambling Guinée fourni en session. Les jugements "lisibilité limite", "kaléidoscope" sont qualitatifs et appuyés sur best-practices génériques UI, pas sur un comparatif sectoriel local. Si le client demande un benchmark, à inclure dans le brief séparé.
- Pas d'A/B test analytique : aucune analytics fournie en session. Les impacts hypothétiques "conversion
Inscriptiondiminuée" sont basés sur best-practice UI, pas sur des données observées Bet224. Si le client fournit GA / mixpanel / amplitude analytics, à inclure pour priorisation affinée.
Angle : UX
Persona
Source : site-context.yaml voice_and_tone.persona_primary = "Parieur sportif en Guinee, tres majoritairement mobile, interesse par le football en priorite".
sport-home: parieur sportif Guinée arrivant en intent "consulter l'offre du jour" (résultat probable d'un clic sur l'URL racine puis redirection automatique vers/sport-home). Veut voir rapidement le football à venir, comparer 2-3 cotes, accéder à la liste des matchs live. Le persona est mobile mais le POC ne capture que desktop : extrapolation à valider sur capture mobile.sport: même persona, en intent "construire un pari sur une compétition spécifique". Le widget Betbuilder est mis en avant en sidebar gauche mais sans explication. Le ticket de pari (panel droit) suppose un compte existant.casino: persona élargie (joueur casino en ligne, NON explicité danspersona_primarymais route présente dans l'audit). Carrousels denses de jeux (43 CTAs détectés dansconversion-signals/casino.json→summary.ctas_total = 43, dont 23 above-fold), navigation par "rangées" de providers. Route YMYL particulièrement sensible (jeux instantanés type Aviator visibles dès l'above-fold).promotions: persona en intent "découvrir les bonus avant inscription". Page très courte (index.json→pages[3].word_count = 108), 3 cartes bonus visibles (MAXI BONUS, CASHBACK SPORT, WELCOME SPORT) avec CTAs "EN SAVOIR PLUS" et un visuel header géant "MAXI BONUS, AUGMENTE TES GAINS JUSQU'À 500 %".
Synthèse exécutive
- Le CTA primaire détecté par
analyze_conversion_signalsestOUVRIR PIED DE PAGEsur 3 routes sur 4 (sport,casino,promotions) - un toggle de footer collapsé. Source :conversion-signals/index.json→per_route[1..3].primary_cta_text. Signal direct d'une architecture où les éléments les plus visibles et appelants à l'action ne correspondent pas à l'intent utilisateur (inscription, dépôt, sélection d'un pari). - Le footer (
<footer id="nascondifooter">) est masqué par défaut via une classecollapse cg-lazyet un bouton "OUVRIR PIED DE PAGE" (rouge, fixed bottom-right, lazy-loaded). Source :raw_html_sport_homeligne 752. Conséquence : mentions légales, politique de confidentialité, conditions générales, infos jeu responsable (si elles existent) sont 2 clics minimum sous le fold, alors que le cadre YMYL gambling impose leur visibilité. - Le contenu effectif du footer est lui aussi extrêmement maigre : section "AIDER" avec uniquement 3 liens (Registration, Politique de Confidentialité, Conditions Générales). Source :
raw_html_sport_homelignes 761-768. Aucun lien jeu responsable, aucun contact, aucune FAQ, aucune information paiement. Cohérent avecconversion-signals/sport-home.json→detailed.trust_signals.contact_email_visible = false,contact_phone_visible_in_footer = false,contact_links_count = 0. - Aucun
<h1>sur les 4 routes (cf[REF: DEEP-A11Y-01/F-A11Y-01-08]). Conséquence UX : aucune promesse claire en above-the-fold pour orienter l'utilisateur ; pour un site multi-verticales (sport, casino, virtuel, promo), l'absence de titre principal détonne avec la densité visuelle (logo + nav + sous-nav + carrousel promo + tabs + listes). - Fuite contextuelle visible : le
<title>mentionne "Sportcash.com" et lemeta name="keywords"cite "Ivory Coast" (source :raw_html_sport.raw.htmllignes 25-28). Ce sont des résidus du template d'origine (white-label d'une plateforme italienne déployée en Côte d'Ivoire puis adaptée Guinée). Friction de confiance : un parieur guinéen attentif détecte l'incohérence dès l'onglet du navigateur.
Findings
F-UX-01-01 : Le CTA primaire détecté est OUVRIR PIED DE PAGE sur 3 routes sur 4
- Sévérité : critical
- Route(s) :
sport,casino,promotions - Source primaire :
conversion-signals/index.json→per_route[1].primary_cta_text = "Previous"(sport, en réalité flèche carrousel),per_route[2].primary_cta_text = "OUVRIR PIED DE PAGE"(casino),per_route[3].primary_cta_text = "OUVRIR PIED DE PAGE"(promotions)conversion-signals/casino.json→detailed.primary_cta.text = "OUVRIR PIED DE PAGE",bbox.x = 1243, bbox.y = 861, width = 182, height = 39,background_color = "rgb(178, 17, 22)",font_size = "12px"conversion-signals/promotions.json→detailed.primary_cta.text = "OUVRIR PIED DE PAGE", mêmes coordonnées et style- HTML observé (raw_html_sport_home ligne 790) :
<a id="consultaFooter" data-toggle="collapse" class="consulta-footer fissato accordion-toggle toggle-nascondi" href="#nascondifooter">OUVRIR PIED DE PAGE</a> - Source visuelle : -
screenshots/casino/desktop.png: bouton rouge "OUVRIR PIED DE PAGE" visible en bas-droite (zone x~1243, y~861) sur capture full-page screenshots/promotions/desktop.png: même bouton en bas-droite (zone x~1243, y~861)screenshots/sport-home/desktop.png: même bouton, présent- Constat :
L'algorithme de détection CTA principal (poids visuel : surface × contraste × position) élit ce bouton comme primary_cta. Ce résultat n'est pas un artefact : le bouton est rouge plein (#b21116) sur fond clair, fixé en bottom-right, persistant à toutes les pages. Or sa fonction est de déplier un footer caché, pas de faire avancer l'utilisateur dans son parcours (consulter une cote, s'inscrire, déposer, parier). Aucun CTA "Inscription" ou "Déposer" n'a un poids visuel comparable au-dessus de la ligne de flottaison.
- Impact attendu :
L'utilisateur novice ne sait pas quoi faire en arrivant. L'oeil est attiré par un bouton rouge persistant qui ne sert qu'à révéler des mentions légales. Conséquence directe sur la conversion : aucune incitation visuelle forte vers un objectif business (inscription, dépôt, pari). Conséquence indirecte sur la confiance YMYL : le bouton le plus saillant de la page est paradoxalement la seule porte d'accès aux infos institutionnelles, comportement contre-intuitif.
- Root cause :
Le footer entier est en collapse cg-lazy (raw_html ligne 752). Pour le voir, l'utilisateur doit cliquer ce bouton. Le pattern provient probablement du template d'origine où le footer était volumineux et chargé en lazy pour la perf, mais ici il ne contient que 3 liens donc le coût d'affichage permanent serait négligeable. Le bouton n'a pas été retiré quand le footer a été allégé.
F-UX-01-11 : Aucune visibilité du jeu responsable ni de la mention d'âge à l'écran
- Sévérité : critical
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
- Grep sur
raw_html_sport_home.raw.html(motifs "jeu responsable", "18+", "mineurs", "RESPONSABLE", "conditions de mise", "auto-exclusion") : 0 occurrence conversion-signals/sport-home.json→detailed.trust_signals.legal_links = [{"text":"Politique de Confidentialité"}, {"text":"Conditions Générales"}](uniquement 2 liens, pas de "Jeu responsable")conversion-signals/sport-home.json→detailed.urgency.keywords_detected_count = 0(pas de countdown faux détecté = OK), mais aussi pas de mention "18+" comptée- Cross-référence
site-context.yaml→forbidden_patternscite explicitement "absence de lien visible vers jeu responsable / auto-exclusion / limites" et "absence de mention d'age legal" comme dark patterns à proscrire - Source visuelle : -
screenshots/sport-home/desktop.png,screenshots/sport/desktop.png,screenshots/casino/desktop.png,screenshots/promotions/desktop.png: aucun visuel "18+", aucun pictogramme jeu responsable, aucun lien visible vers ressources d'aide. Le logo ARSJPA est présent dans le header (vu raw_html_sport_home ligne 389) mais discret et sans label. - Constat :
Sur les 4 routes auditées, aucun élément n'évoque ni le seuil d'âge légal de pari, ni l'auto-exclusion, ni le jeu responsable, ni le contact d'une ligne d'aide. Le footer (collapsé) n'en parle pas non plus. Pour un site YMYL gambling, c'est la friction la plus forte vis-à-vis du cadre déontologique sectoriel (le seuil exact en Guinée n'est pas sourcé en session, cf site-context.yaml → facts.to_confirm, mais le principe d'affichage est quasi-universel). Le persona ne dispose d'aucune ressource visible pour s'informer ou demander de l'aide.
- Impact attendu :
UX : impossibilité pour un utilisateur en difficulté de trouver de l'aide. Réputationnel : un site gambling sans visibilité jeu responsable est un signal de qualité dégradé chez les utilisateurs informés. Réglementaire : à cadrer Legal-check, mais quasi-systématiquement un risque dans tout cadre gambling moderne.
- Root cause :
Adaptation Guinée n'a pas intégré de bloc "Jeu responsable" dans le footer ni dans la sidebar. Logo ARSJPA présent en header mais non documenté.
F-UX-01-02 : Footer collapsed par défaut, contenu réduit à 3 liens
- Sévérité : serious
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
raw_html_sport_homeligne 752 :<footer class="collapse cg-lazy" id="nascondifooter">raw_html_sport_homelignes 761-768 : section "AIDER" contient uniquementRegistration,Politique de Confidentialité,Conditions Généralesconversion-signals/sport-home.json→detailed.trust_signals.legal_links_count = 2,contact_links_count = 0,contact_email_visible = false,contact_phone_visible_in_footer = false,has_siret = false,has_vat_eu = false,has_rcs = false- Identique 4 routes (
detailed.trust_signals.footer_text_length_chars = 1236constant) - Source visuelle : -
screenshots/promotions/desktop.png: bandeau bas montre uniquement "OUVRIR PIED DE PAGE" en rouge. Aucun footer visible en zone fixe. - 4 captures vérifient l'absence de footer visible above ou immediately below-fold.
- Constat :
Le footer existe dans le DOM mais est replié sous une classe collapse cg-lazy + un bouton "OUVRIR PIED DE PAGE". Une fois ouvert, son contenu se résume à : un titre "AIDER", un lien "Registration", un lien "Politique de Confidentialité", un lien "Conditions Générales". Pas de section contact, pas de FAQ, pas d'informations paiements, pas de mentions sur le jeu responsable (alors que site-context.yaml → forbidden_patterns cite explicitement "absence de lien visible vers jeu responsable / auto-exclusion / limites" comme dark pattern à proscrire).
- Impact attendu :
L'utilisateur en intent "trouver le numéro de licence", "contacter le support", "comprendre les conditions de retrait", "vérifier ce site est légal en Guinée" n'a aucune réponse à l'écran ni en sous-écran. Cumulé au pattern collapsed, il faut 2 clics minimum pour obtenir une page d'infos institutionnelle (et il n'y en a que 2 : Politique de Confidentialité + Conditions Générales). Friction de confiance majeure sur un site YMYL gambling.
- Root cause :
Template hérité d'une installation plus large (champ cg_INSTALLAZIONE = 'GUINEA', ligne 678) où le footer était volumineux. Adaptation Guinée a vidé le footer mais conservé le pattern de masquage.
F-UX-01-04 : Aucun H1 sur 4 routes, hiérarchie informationnelle absente
- Sévérité : serious
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
raw_html_sport_home.raw.html: aucun<h1>détecté (Grep<h1retourne 0 hit sur le fichier)- Idem
raw_html_sport.raw.html,raw_html_casino.raw.html,raw_html_promotions.raw.html - Seuls
<h5>(titres de modales : "Erreur identification", "Connexion") apparaissent dans le DOM - Cross-référence axe :
[REF: DEEP-A11Y-01/F-A11Y-01-08]("aucun H1 sur 4 routes, règle axepage-has-heading-oneviolée") - Source visuelle : -
screenshots/sport-home/desktop.png: en-dessous du header, on voit directement le carrousel promo + libellés "Tournois à la une" / "Découvrir" qui sont visuellement traités comme titres mais sans markup associé screenshots/casino/desktop.png: "Gains récents", "Spribe Games", "Top 10", "Evolution", "Top Providers", "Amigo Gaming" sont des étiquettes de section sans hiérarchie marquéescreenshots/promotions/desktop.png: aucun titre lisible au-dessus du carrousel promo, juste les libellés des cartes ("MAXI BONUS", "CASHBACK SPORT", "WELCOME SPORT")- Constat :
Sur les 4 routes, aucun titre de niveau 1 ne donne le sujet de la page. Le persona arrivant sur /sport-home ne lit pas "Paris sportifs Guinée" en haut de page ; il voit un bandeau cookies, un menu, un bandeau promo. Le persona sur /promotions ne lit pas "Promotions et bonus" ; il voit un visuel "MAXI BONUS" puis 3 cartes. La promesse de page est entièrement portée par le design (gros visuels) et non par la structure textuelle. Sur mobile (non audité) cette absence sera encore plus pénalisante car la promesse est ce qui rassure dans les premiers 100 px.
- Impact attendu :
UX : le visiteur en intent ambigu (arrivé via une recherche "site paris guinée") n'a pas de validation immédiate qu'il est au bon endroit. Cas concret : l'<title> mentionne "Sport, Jeux Digitaux, Virtuel, Loto" mais l'utilisateur n'a aucun titre H1 résumant l'offre. Friction de réassurance, surtout dans un secteur où la confiance est cruciale.
- Root cause :
Layout-driven design (l'image fait le titre), héritage d'un template plateforme qui n'expose pas de slot H1 par défaut. Voir aussi [REF: DEEP-A11Y-01/F-A11Y-01-08] pour l'angle accessibilité.
F-UX-01-06 : Navigation principale appauvrie au profit d'un sous-menu non sourçable
- Sévérité : serious
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
raw_html_sport.raw.htmllignes 599-611 :<ul class="nav nav-tabs barra-menu menu-principale">contient 4 items uniquement :Sports,Virtuel,Promo,Casino- Sous-menu
<nav class="sottomenu-main"><div class="sottomenu-nav ... cg-hide" id="cg-scommesse-submenu"><ul></ul></div></nav>(vide dans le HTML serveur, peuplé en JS) - Sur la capture
screenshots/sport-home/desktop.pngun sous-menu visuellement présent :PREMATCH,LIVE,MULTIBET,EVENEMENTS,MULTILIVE,CALENDRIER conversion-signals/sport-home.json→detailed.ctas[2].text = "",href = "#nascondimenu"(item nav sans label texte)- Source visuelle : -
screenshots/sport-home/desktop.pngzone y=60-80 : barre rouge en haut avecSports(souligné rouge actif),Virtuel,Promo,Casino. Juste en-dessous (y=88-110), seconde barre grise avecPREMATCH,LIVE,MULTIBET,EVENEMENTS,MULTILIVE,CALENDRIER screenshots/sport/desktop.png: on voit le sous-menu peuplé (PREMATCH actif rouge)screenshots/casino/desktop.png: le sous-menu n'apparaît pas (route Casino donc le sous-menu Sport est masqué)- Constat :
Le menu de premier niveau ne propose que 4 items génériques (les 4 verticales), tandis que le sous-menu (PREMATCH, LIVE, MULTIBET, etc.) qui contient les actions réelles d'un parieur est rendu uniquement après hydratation JS et n'apparaît qu'en mode Sport. Cela crée 2 problèmes : (1) un utilisateur qui veut accéder directement à "LIVE" depuis la home doit cliquer "Sports" d'abord puis "LIVE" (2 clics au lieu d'1 ; le sous-menu est conditionnel à la verticale active), (2) les libellés PREMATCH, MULTIBET, EVENEMENTS, MULTILIVE sont du jargon parieur non explicité. Pour le persona "intéressé par le football en priorité", le chemin attendu "voir les matchs de foot ce soir" n'est pas une étape de la nav, c'est une page d'atterrissage qu'il faut deviner (sport-home ?).
- Impact attendu :
UX : friction d'orientation. Un nouvel utilisateur (cible du persona) doit deviner que "Live" est un sous-onglet de "Sports" et pas un onglet de premier niveau. Conversion : le parcours "voir un match live > parier" demande au moins 3 clics depuis la home, sans repère textuel intermédiaire.
- Root cause :
Architecture nav héritée du template plateforme : menu principal = verticales, sous-menu = mode de consommation. Choix d'IA acceptable mais non décliné pour le persona local (qui veut un raccourci football direct).
F-UX-01-07 : Page Promotions de 108 mots, CTAs "EN SAVOIR PLUS" sans destination explicite
- Sévérité : serious
- Route(s) :
promotions - Source primaire :
index.json→pages[3].word_count = 108,title = "www.bet224.gn Guinee | Jouez en Ligne | Sport, Jeux Digitaux, Virtuel, Loto"conversion-signals/promotions.json→summary.ctas_total = 3,primary_cta_text = "OUVRIR PIED DE PAGE"- Seulement 3 CTAs détectés total : 1 toggle menu sans texte, 1 sélecteur FR, 1 "OUVRIR PIED DE PAGE". Les 3 cartes promo + leurs CTAs internes "EN SAVOIR PLUS" sont vraisemblablement des
<a>sans rôle button distinct ou détectés sous le fold. - Screenshot montre 3 cards visuels :
MAXI BONUS - BONUS CASHBACK BET224 + 100,000 GNF DE PROFITER ENFIN DE L'OFFRE [EN SAVOIR PLUS],CASHBACK SPORT - BONUS CASHBACK BET224 100,000 GNF DE PROFITER DE L'OFFRE [EN SAVOIR PLUS],WELCOME SPORT - BONUS 100 % SUR DÉPÔT 1,000,000 GNF DE PROFITER DE L'OFFRE [EN SAVOIR PLUS] - Source visuelle : -
screenshots/promotions/desktop.png: header visuel jaune "MAXI BONUS, AUGMENTE TES GAINS JUSQU'À 500 %!!! - PARIEZ ICI", 3 cards alignées avec CTA vert "EN SAVOIR PLUS", bouton rouge "OUVRIR PIED DE PAGE" - Constat :
La page Promotions est presque entièrement composée d'images (visuels Photoshop). Le texte HTML utile pour comprendre les conditions est quasi-inexistant (108 mots seulement, dont la majorité dans le header et le menu). Les CTAs "EN SAVOIR PLUS" sur chaque card ne précisent ni la cible de la redirection, ni les conditions de mise (wagering). Pour le persona, il est impossible de comparer 2 bonus sans cliquer "EN SAVOIR PLUS" 2 fois (perte de contexte). Le wording du visuel principal "AUGMENTE TES GAINS JUSQU'À 500 %" est problématique vs site-context.yaml → voice_and_tone.avoid qui interdit "promesse ou suggestion de gain" et forbidden qui liste explicitement "Gagnez a coup sur" et synonymes.
- Impact attendu :
UX : friction de découverte. Le persona indécis doit faire 3 clics pour comparer 3 offres alors qu'un tableau / accordion les afficherait toutes. Conversion : impossible de juger de la pertinence d'un bonus sans cliquer ; abandon probable. Réglementaire : promesse de gain en visuel principal à cadrer Legal-check (forbidden_pattern probable selon le cadre GN à sourcer).
- Root cause :
Page produite par juxtaposition de visuels marketing, sans contenu rédactionnel structuré. Pas d'investissement copywriting.
F-UX-01-08 : Casino, surcharge de 23 CTAs above-fold sans hiérarchie d'action claire
- Sévérité : serious
- Route(s) :
casino - Source primaire :
conversion-signals/casino.json→summary.ctas_above_fold = 23,ctas_total = 43,aggregate.ctas_above_fold_ratio = 0.633(moyenne 4 routes)conversion-signals/casino.json→detailed.ctas[4..10]: 7 boutons "JOUER" identiques (text = "JOUER",background_color = "rgb(14, 102, 52)"vert,bbox.y = 577même rangée) au-dessus du fold- Boutons carrousel sans label :
conversion-signals/casino.json→ 8 boutonscomponenteGioco__navigatore__tastoavectext = ""(cf[REF: DEEP-A11Y-01/F-A11Y-01-03]) - Premier carrousel "Gains récents" expose 4 montants type
1,803,313 GNF(Most Wanted,Alexander's Fortune,Aviator,AVIAJET) - signaux d'incitation jeu basés sur des gains supposés affichés en gros - Source visuelle : -
screenshots/casino/desktop.pngy=70-200 : 4 cards "Gains récents" affichant des montants en GNF + nom du jeu (potentiel "loss disguised as social proof", cf forbidden_patterns) - y=200-340 : carrousel "Spribe Games" avec icônes des 7 jeux instantanés (Aviator, Dice, Goal, Plinko, Mines, Mini Roulette, Hilo)
- y=340-470 : "Top 10" avec rangs visuels 1-2-3-4-5 (Hot to Burn, Queen of God, Shining Hot, Book of Tut, Buster Bob)
- y=470-580 : "Evolution" rangée Blackjack
- Constat :
La page Casino expose 23 CTAs cliquables dans le seul above-fold (à 900px), avec 7 boutons "JOUER" identiques au pixel près (même libellé, même couleur, même taille), 8 flèches de carrousel sans label (cf A11Y), 4 cards "Gains récents" qui simulent une preuve sociale. Aucun chemin guidé : le visiteur subit la densité. Pour le persona, l'absence de hiérarchie ("jeu vedette", "nouveau", "guide débutant") rend la navigation chaotique. La sur-représentation du jeu "Aviator" (3 occurrences détectables dans le top-fold) et sa promotion via les "gains récents" est un pattern classique en gambling à risquer.
- Impact attendu :
UX : surcharge cognitive, abandon probable pour l'utilisateur non-initié. Pour un utilisateur déjà engagé : risque de jeu impulsif aggravé par la mise en scène des gains supposés. Réglementaire : "Gains récents" sans contexte (gains nets vs bruts, fenêtre temporelle, vérifiabilité) à cadrer Legal-check car peut tomber sous "promesse de gain" du site-context.yaml.
- Root cause :
Template casino dense par défaut, hérité d'une logique d'offre maximale visible. Pas d'arbitrage UX par hiérarchie (gros jeu vedette + sections collapsées).
F-UX-01-03 : Bandeau cookies persistant en haut de page, occupant le fold sans choix granulaire
- Sévérité : moderate
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
raw_html_sport_homelignes 349-353 :<div id="cg-barra-cookies" class="row inline-flex flex-row justify-content-center cg-hide"><div>Ce site utilise des cookies, y compris des cookies de profilage tiers. Si vous souhaitez en savoir plus ou désactiver certains ou tous les cookies, lisez les informations. En poursuivant votre navigation, vous acceptez l'utilisation de tous les cookies.</div><a class="cg-cookies-ok" onclick="cg_acceptsCookies()">OK</a><a class="cg-cookies-more-info" href="/external_cms/pdf/Cookies_Policy.pdf" target="_blank">Plus d'informations</a></div>- Identique 4 routes (script inclus dans le template global, déclenché côté client)
- Source visuelle : -
screenshots/sport-home/desktop.pngzone y=0-25 : bandeau gris en haut affichant "Ce site utilise des cookies, y compris des cookies de profilage tiers. ..." + bouton "OK" vert + lien "Plus d'informations" - Visible sur les 4 captures
- Constat :
Le bandeau cookies (1) consomme environ 25-30 pixels du fold à 900px de hauteur (~3 % du viewport), (2) ne propose que "OK" et "Plus d'informations" (lien vers un PDF, pas une page web). Aucun bouton "Refuser tout", aucun choix granulaire (essentiels / mesure / profilage). Le wording présume le consentement ("En poursuivant votre navigation, vous acceptez l'utilisation de tous les cookies"), c'est-à-dire le pattern "consentement par poursuite de navigation" qui n'a aucune validité dans la plupart des cadres modernes de protection des données.
- Impact attendu :
UX : bandeau persistant tant que pas cliqué (jamais accepté en POC = visible sur 4 captures), réduit l'espace utile. Pour l'utilisateur soucieux de sa vie privée, aucune option de refus présentée immédiatement, friction d'usage. Pour le projet : risque réglementaire à instruire (le cadre data Guinée n'est pas sourcé en session, cf site-context.yaml → facts.to_confirm : "Cadre data / cookies de profilage applicable en Guinée + politique de confidentialite"). À cadrer en Legal-check.
- Root cause :
Bandeau hérité d'une implémentation pré-RGPD style "cookielaw" italien. Adaptation guinéenne n'a pas refait le composant.
F-UX-01-05 : Fuite contextuelle dans le markup, résidus "Sportcash.com" et "Ivory Coast"
- Sévérité : moderate
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
raw_html_sport.raw.htmlligne 25 :<meta name="description" content="Sportcash.com : sûr et fiable, les meilleures cotes de paris sportifs, le Loto et des jeux divertissants vous attendent!" />raw_html_sport.raw.htmlligne 28 :<meta name="keywords" content="Sportcash.com,Paris Sportifs en Ivory Coast,Ivory Coast Football,Meilleures cotes en Ivory Coast,Pronostics sport,Gagner aux paris,Jeux Arcades,Jeux Virtuels,Loterie Ivory Coast,Site pari sportif confiance Ivory Coast,Site pari sportif sécurisé Ivory Coast,Loto Ivory Coast,"index.json→pages[0].description = "Sportcash.com : sûr et fiable..."(sport-home),pages[1].description = idem(sport),pages[2].description = "Retrouvez des centaines de jeux sur Sportcash.com. Les meilleurs jeux au monde !"(casino),pages[3].description = "Sportcash.com vous offre des Promotions et des Bonus exclusifs pour vos paris..."(promotions)- HTML observé (raw_html_sport_home ligne 389) :
<img src="https://www.bet224.gn/external_css/GUINEA/img/ARSJPA.png">(logo régulateur affiché en header, point positif mais sans alt ni lien explicatif) - Toast en anglais visible (raw_html_sport_home ligne 875) :
Click <span>HERE</span> to get started or <span>HERE</span> to never show this again - Source visuelle : -
screenshots/sport-home/desktop.png: l'onglet du navigateur (titre) n'est pas visible mais le persona attentif voit la<title>dans son onglet ; le toast EN apparaît si auto-déclenché. - Constat :
Le site est techniquement de marque Bet224 mais conserve dans son markup des éléments d'une plateforme d'origine ("Sportcash.com" : marque ivoirienne pour cousins déployées sur le même backend) et d'un marché initial (Côte d'Ivoire vs Guinée). Le keyword "Loterie Ivory Coast" est particulièrement gênant compte tenu du cadre site-context.yaml → legal_naming_restrictions.forbidden_terms qui interdit explicitement de "suggerer un lien avec la loterie nationale guineenne sauf preuve". L'utilisateur ne voit pas ces meta directement mais : (a) elles polluent le SEO, (b) elles trahissent un manque de soin éditorial qui résonne sur la confiance, (c) un journaliste / régulateur peut s'en saisir.
- Impact attendu :
UX (perception) : un utilisateur averti qui inspecte l'onglet ou copie un lien voit "Sportcash.com" dans la description. Conversion : tag de qualité dégradé. Risque réglementaire et concurrentiel : keywords visibles mentionnant un autre pays et la loterie nationale (à cadrer Legal-check).
- Root cause :
Template plateforme partagé entre plusieurs marques (Sportcash, Bet224, etc.) sur le même backend external_cms/GUINEA/. Les meta ont été oubliés à la spécialisation. Le toast EN est probablement un texte par défaut non traduit.
F-UX-01-09 : Sport, sidebar Betbuilder mise en avant sans explication ni preuve de valeur
- Sévérité : moderate
- Route(s) :
sport - Source primaire :
conversion-signals/sport.json→detailed.ctas[2].text = "BETBUILDER",bbox = {x:0, y:364, width:244, height:35},background_color = "rgb(72, 72, 71)"gris foncé,color = "rgb(0, 0, 0)"(contraste insuffisant, cf[REF: DEEP-A11Y-01]pour le détail)conversion-signals/sport.json→detailed.ctas[3].text = "Cotes favoris"juste en-dessous- Aucun texte explicatif Betbuilder dans
index.json→pages[1].word_count = 605(605 mots au total dont l'essentiel = libellés de compétitions et cotes) - Source visuelle : -
screenshots/sport/desktop.pngzone x=0-244, y=364-420 : barre grise contenant le texte "BETBUILDER" en majuscules, en haut de la sidebar gauche. Aucune icône d'explication, aucun tooltip visible, aucun lien "Comment ça marche". Juste en-dessous : "Cotes favoris" (autre fonctionnalité opaque pour novice). - Constat :
La sidebar Sport propose 2 fonctionnalités avancées (Betbuilder = construction d'un pari combiné multi-marchés sur un même match ; Cotes favoris = sauvegarde de cotes préférées) sans aucune mini-définition, sans aucun tutoriel intégré, sans onboarding contextuel. Le persona novice ignore ce qu'est un Betbuilder ; il voit un bandeau gris peu lisible qui ne s'explique pas. Le persona expert peut s'en passer, donc la mise en avant ne sert finalement personne sans contenu pédagogique.
- Impact attendu :
UX : feature gâchée par défaut d'explication, taux d'utilisation probablement bas, ROI design négatif. Pour la confiance générale : impression que le site parle "à des initiés" et ne facilite pas l'entrée du novice (qui est pourtant le persona Guinée, marché jeune en growth).
- Root cause :
Design pris tel quel sans wrapping pédagogique. La feature Betbuilder est une marque-produit (Betradar / Sportradar) souvent livrée comme widget tiers sans intro UX.
F-UX-01-10 : Inconsistance vocabulaire et langue dans l'interface
- Sévérité : moderate
- Route(s) :
sport-home,sport,casino,promotions - Source primaire :
- Wording maladroit :
OUVRIR PIED DE PAGE(traduction littérale italienneaprire piè di pagina, devrait être "Voir le pied de page" ou simplement "Mentions légales", cfconversion-signals/casino.json→detailed.primary_cta.text = "OUVRIR PIED DE PAGE") - Mélange FR / EN :
raw_html_sport_homeligne 764 :<a class="cg-ext-link pointer" onclick="cg_newAccount(true)">Registration</a>(lien EN dans un footer FR) - Toast EN visible (raw_html_sport_home ligne 875) :
Click HERE to get started or HERE to never show this again - Boutons mixtes :
Login(EN) à côté deInscription(FR) dans le header (raw_html_sport_home ligne 408-410 :<a onclick="cg_login()" class="bottone bottone-login">Login</a> ... <span class="bottone bottone-registrazione">Inscription</span>) - Italien résiduel dans le markup :
nascondimenu,nascondifooter(id IT pour "cacher menu"/"cacher footer"),componenteGioco,barra-cookies,consulta-footer - Source visuelle : -
screenshots/sport-home/desktop.pngzone y=40-65 : "Login" + "Inscription" côte-à-côte - 4 captures : "OUVRIR PIED DE PAGE" visible en bas-droite
- Constat :
Le site mélange français standard, français maladroit (calque italien), anglais (mots-clés cTA, libellé toast), et italien (classes / IDs CSS, classes BEM). Pour le persona guinéen francophone (langue de scolarisation principale en Guinée), le mélange est lisible mais évoque une plateforme bricolée. Le terme "OUVRIR PIED DE PAGE" en particulier est faux français (pied de page = composant technique, pas un mot qu'on adresse à un utilisateur final). "Login" / "Registration" en anglais cohabitent avec "Inscription" en français = duplication conceptuelle.
- Impact attendu :
UX : friction de confiance ("ce site n'est pas fait pour moi"), perception de qualité dégradée. Plus subtil : risque d'incohérence pour le persona ayant un niveau de français modeste qui voit "Login" sans connaître le mot, alors que "Connexion" serait universellement compris.
- Root cause :
Template plateforme italien (probablement Microgame / SISAL ou équivalent) traduit partiellement en français, partiellement laissé en italien (classes), partiellement laissé en anglais (libellés par défaut). Pas d'audit terminologique complet à la spécialisation Guinée.
Cross-angle dependencies
- A11Y : F-UX-01-04 (absence de H1) recoupe
[REF: DEEP-A11Y-01/F-A11Y-01-08](axepage-has-heading-oneviolée sur 4 routes). Les recos R-UX-01-02 (réinjecter H1 + intro) et R-A11Y-01-12 (ajouter H1 unique) doivent être fusionnées parassemble_audit.py: même action technique, même portée, copy-ready compatibles. Préférer le copy-ready de R-UX-01-02 (inclut une intro qui sert aussi le SEO), garder la validation axe de R-A11Y-01-12. - A11Y : F-UX-01-08 (boutons carrousel casino sans nom accessible) référence directement
[REF: DEEP-A11Y-01/F-A11Y-01-03](8 boutonscomponenteGioco__navigatore__tastosansaria-label). La reco R-UX-01-07 (réduire densité casino) ne suffit pas si les boutons restants restent muets : reco A11Y a11y-01-03 reste critique en parallèle. - CONV (à venir, DEEP-CONV-01) : F-UX-01-01 (CTA primary = "OUVRIR PIED DE PAGE") est un finding partagé fort, voire central pour CONV (la mécanique de conversion est cassée à la racine). La reco R-UX-01-01 résout simultanément un objectif UX (footer visible) et un objectif CONV (libérer un CTA primary pertinent type "Inscription" ou "Déposer"). À fusionner.
- CONV (à venir, DEEP-CONV-01) : F-UX-01-07 (page Promotions sous-documentée) et la pratique "EN SAVOIR PLUS" génériques sont un finding partagé CONV (libellés peu actionables) + UX (friction de comparaison). À fusionner.
- TRUST (à venir, DEEP-TRUST-01) : F-UX-01-02 (footer collapsed + 3 liens) et F-UX-01-11 (jeu responsable absent) sont les findings centraux d'angle TRUST. La reco R-UX-01-01 (footer visible permanent) et R-UX-01-08 (jeu responsable + page dédiée) seront probablement les recos principales du DEEP-TRUST-01 ; à fusionner.
- TRUST (à venir, DEEP-TRUST-01) : F-UX-01-05 (résidus "Sportcash" / "Ivory Coast") est une friction de confiance / réputation. À cross-référencer avec un éventuel finding TRUST sur la cohérence brand.
- UI (à venir, DEEP-UI-01) : F-UX-01-08 (densité casino) dépend du design-system : la prolifération de boutons "JOUER" identiques pose aussi une question de hiérarchie visuelle (taille, couleur unique vs gradation). À cross-référencer avec
design-system/index.jsonpour vérifier si une variation visuelle (jeu premium vs standard) est prévue dans la palette. - MOBILE (à venir, DEEP-MOBILE-01) : aucune dépendance critique identifiée puisque mobile non capturé. À noter pour DEEP-MOBILE-01 : le bouton fixed "OUVRIR PIED DE PAGE" en bottom-right couvre probablement encore plus de surface sur mobile (priorité visuelle aggravée), à instrumenter.
- SEO (à venir, DEEP-SEO-01) : F-UX-01-04 (absence H1) et F-UX-01-05 (meta résiduels Sportcash / Ivory Coast) sont des findings SEO majeurs. R-UX-01-02 et R-UX-01-03 doivent être fusionnées avec leurs équivalents SEO.
- cross-angle-conflict potentiel : R-UX-01-07 (refonte casino above-fold) pourrait conflicter avec une éventuelle reco UI conservant le pattern visuel actuel ou avec une reco CONV qui voudrait maximiser le nombre de CTAs visibles. Escalader au red team UX-check si le DEEP-CONV-01 propose une direction divergente.
Limites
- Mobile non audité :
screenshots/<slug>/mobile.pngabsent pour les 4 routes (POC desktop only, cfcrawl/screenshots/<slug>/ne contient quedesktop.png). Conséquence : la qualité du responsive, les touch targets, la position du bouton "OUVRIR PIED DE PAGE" en mobile, l'utilisabilité réelle pour le persona primary (mobile-first) ne sont pas évalués. Or le persona est explicitement mobile-majoritaire (site-context.yaml). Recommandation : étendre le crawl mobile avant livraison FULL. page-signals/<slug>.signals.jsonabsent ou non parsable :build_page_signals.pyn'a pas tourné côté product-audit (bug crawl, raw_html_path pointe vers seo-audit). Conséquence :headings.outline,nav.structure,link_graph.in_degree,link_graph.out_degree,landmarks[]consolidés ne sont pas disponibles. J'ai compensé en lisant directement les raw.html (côté seo-audit) mais sans agrégation cross-route. Recommandation : faire tournerbuild_page_signals.pysur le crawl product-audit, ou symlinker les signals.json déjà produits côté seo-audit.link_graph.jsonabsent : pas de mesure des in_degree / out_degree des pages, donc l'analyse "navigation transverse" repose sur observation du menu HTML uniquement, pas sur les liens internes effectifs. Conséquence : impossible de quantifier l'orphelinat ou la profondeur de la navigation.- Parcours d'inscription / dépôt / pari non audités : les routes auditées (
sport-home,sport,casino,promotions) ne couvrent pas/signup,/recoverPsw,/deposit, le ticket de pari après ajout d'une cote, la page d'un événement live. Or ce sont les étapes critiques du funnelsite-context.yaml→parcours_conversion(à inférer puisque non explicité dans yaml mais évident : inscription -> dépôt -> pari). Recommandation : étendre le scope pour FULL. - États de page non capturés : pas de capture de 404, de 500, de "panier vide", de "résultat de recherche vide", de "session expirée", de "compte verrouillé", de "dépôt refusé". Pour un site YMYL gambling, ces états sont critiques car ils gèrent les frustrations utilisateur. Recommandation : extension Playwright pour capturer artificiellement ces états.
- Pas d'observation après login : le crawl est anonyme, donc l'expérience utilisateur connecté (ticket de pari, historique, dépôt) n'est pas évaluée. Pour un site YMYL gambling où l'engagement post-inscription est l'enjeu principal, c'est une limite forte. Recommandation : audit séparé sur un compte de test fourni par le client.
- Tests utilisateurs réels : non effectués. Les findings reposent sur observation expert + données automatiques (axe, conversion-signals). Un test à 5 utilisateurs représentatifs du persona Guinée révélerait probablement des frictions linguistiques, culturelles et liées au niveau de connexion (3G/4G) non capturées ici.
- Mesures performance ressenties :
crux.jsonetpagespeed/<hash>.jsonnon produits côté product-audit. L'UX perçue dépend fortement de LCP / INP réels en contexte Guinée (réseau probablement variable). Cross-référence à instruire en DEEP-PERF-01 quand les données seront disponibles. - Cadre légal de la communication promotionnelle en Guinée non sourcé : conséquences directes sur F-UX-01-07 (visuel "AUGMENTE TES GAINS JUSQU'À 500 %") et F-UX-01-11 (jeu responsable). Les recos copy-ready sont conçues pour être "safe" en attendant le cadre, mais le wording final dépend de Legal-check.
Audit produit global · plan d'action
DRAFT INTERNE : NO GO publication client en l'état (Legal-check 2026-05-24)
Bet224 n'est PAS sur la liste officielle des plateformes agréées ARSJPA [VERIFIED via WebFetch arsjpa.gov.gn/plateformes-agreees/ 2026-05-24]. Les 7 plateformes agréées : Geniusbet, Yellowbet, 1xBet GN, Guinée Games, Pariez GDJ, LONAGUI, Guinée Millions.
Action immédiate recommandée client (priorité absolue, prime sur les recos ci-dessous) : retrait du logo ARSJPA présent sur 42 pages du site dans les heures qui suivent réception du rapport.
5 préalables clients obligatoires avant publication FULL :
- Copie agrément ARSJPA OU reconnaissance non-agrément + plan régularisation
- Raison sociale + RCCM Guinée + représentant légal
- Organigramme entité GN vs opérateur étranger (white-label italien suspecté)
- Confirmation conseil juridique sur cadre data GN
- Confirmation dispositif central auto-exclusion GN
Détail red team adversarial (7 agents) : voir
_red-team-report.md.
Avertissement YMYL : ce rapport analyse le site bet224.gn, opérateur de paris sportifs et de casino en ligne en Guinée. Secteur YMYL (Your Money Your Life). Le régulateur identifié est l'ARSJPA (https://arsjpa.gov.gn/, vérifié WebFetch 2026-05-16, statut d'agrément Bet224 vérifié WebFetch 2026-05-24 : NON AGRÉÉE).
Généré : 2026-05-24T10:56:26.777867+00:00 Recos total : 69 Priorisation : RICE (cf annexes/methodologie-product-audit.md) Override : conformité légale = HIGH forcée quel que soit le score RICE
Priorité HIGH (RICE ≥ 30)
R-A11Y-01-01 : Retirer maximum-scale=1 de la meta viewport sur toutes les routes
- Findings adressés : F-A11Y-01-11
- Routes concernées :
casino - Priorité RICE : R=5 I=5 C=5 E=1 → score=125.0
- Action concrète :
Remplacer la valeur de la meta viewport sur toutes les routes par width=device-width, initial-scale=1. Retirer impérativement maximum-scale=1 et minimum-scale=1. Fix template <head> global (probablement un seul layout partial à modifier). Vérifier qu'aucun CSS touch-action: pan-x global ne réintroduit le blocage.
- Copy-ready :
Balise meta à appliquer : <meta name="viewport" content="width=device-width, initial-scale=1">
- Effort estimé : S
- Validation :
Re-run axe-core sur les 4 routes : violations[].id == "meta-viewport" doit retourner 0. Test manuel mobile : pincer pour zoomer sur le contenu casino doit fonctionner.
R-PERF-01-01 : Fetcher CrUX + PageSpeed Insights en V2 (CRITIQUE pour audit perf vrai)
- Findings adressés : F-PERF-01-01, F-PERF-01-02, F-PERF-01-03, F-PERF-01-04, F-PERF-01-05
- Routes concernées :
all - Priorité RICE : R=5 I=5 C=5 E=1 → score=125.0
- Action concrète :
Avant la prochaine itération de cet audit (V2), configurer les deux clés API : CRUX_API_KEY (Google Chrome UX Report API, gratuit avec quota) et PSI_API_KEY (PageSpeed Insights API, gratuit avec quota). Lancer toolkit/tools/fetch_crux.py sur les 4 routes avec form_factor=PHONE ET form_factor=DESKTOP. Lancer toolkit/tools/fetch_pagespeed.py sur les 4 routes avec strategy=mobile ET strategy=desktop. Régénérer DEEP-PERF-02 avec ces inputs pour avoir : LCP p75 / INP p75 / CLS p75 vrais users + LCP element identifié + render-blocking diagnostics quantifiés + opportunités Lighthouse scorées.
- Copy-ready :
Pas de copy littéraire. Variables d'env à set : CRUX_API_KEY="..." et PSI_API_KEY="...". Commandes : python toolkit/tools/fetch_crux.py --crawl-dir toolkit/clients/bet224/2026-05-24/crawl --form-factors PHONE DESKTOP et python toolkit/tools/fetch_pagespeed.py --crawl-dir toolkit/clients/bet224/2026-05-24/crawl --strategies mobile desktop.
- Effort estimé : S
- Validation :
Présence des fichiers crux.json et pagespeed/<hash>.json dans crawl/. Le DEEP-PERF-02 doit pouvoir citer des champs crux.json → metrics.largest_contentful_paint.percentiles.p75 pour chaque route × form_factor.
R-TRUST-01-01 : Lancer red team Legal-check + obtenir client n° licence ARSJPA + cadre data GN + raison sociale opérateur (PRIORITÉ ABSOLUE)
- Findings adressés : F-TRUST-01-01, F-TRUST-01-02, F-TRUST-01-03, F-TRUST-01-04, F-TRUST-01-05, F-TRUST-01-07, F-TRUST-01-08, F-TRUST-01-09, F-TRUST-01-10, F-TRUST-01-12, F-TRUST-01-13
- Routes concernées :
all - Priorité RICE : R=5 I=5 C=5 E=1 → score=125.0
- Action concrète :
Avant assemble_audit final : (1) Demander au client la documentation suivante : copie du document d'agrément ARSJPA (numéro, date, périmètre), raison sociale de l'entité opératrice (canonical_legal), siège social, numéro RCCM (OHADA), contact juridique, organigramme entité GN vs éventuelle entité étrangère du groupe. (2) Lancer un agent Legal-check spécialisé GN gambling qui doit identifier sur sources primaires guinéennes : décret de création ARSJPA (numéro + date exacte), texte d'application encadrant la publicité gambling en GN, seuil d'âge légal pour parier en GN, mentions obligatoires en pied de page selon ARSJPA, cadre data / consentement cookies applicable en GN (loi data GN ou cadre OHADA / CEDEAO si existant). (3) Vérifier sur arsjpa.gov.gn la présence ou non de Bet224 sur la liste des "Plateformes agréées" (contenu non extrait en session). (4) Mettre à jour site-context.yaml facts.allowed et legal_naming_restrictions avec les faits sourcés. (5) Patcher _subagent-outputs/DEEP-TRUST-01.md en conséquence (passage de findings de "obligation morale" à "obligation légale" si applicable).
- Copy-ready :
Brief Legal-check à remettre à l'agent (à copier tel quel) : "Mission Legal-check Bet224 (juridiction Guinée, secteur paris sportifs + casino en ligne). À sourcer sur sources primaires guinéennes : (1) Décret de création de l'ARSJPA (https://arsjpa.gov.gn/) : numéro et date exacte. (2) Texte d'application sur la publicité gambling en GN : promesses de gain interdites ? Mentions obligatoires pour bannières promo ? (3) Seuil d'âge légal pour parier en GN (NE PAS supposer 18 par défaut, vérifier). (4) Mentions obligatoires en pied de page selon ARSJPA : raison sociale, n° licence, n° RCCM, contact, jeu responsable, mention d'âge, lesquelles sont obligatoires ? (5) Cadre data / cookies en GN : loi data GN existante ? cadre OHADA ou CEDEAO applicable ? Consentement cookies : quelle pratique attendue ? (6) Vérifier sur arsjpa.gov.gn la liste 'Plateformes agréées' : Bet224 y figure-t-il ? Sous quel nom ? Avec quel numéro ? (7) Identifier toute jurisprudence ou décision ARSJPA sur opérateurs sanctionnés. Livrable : note 1-2 pages sourcée + mise à jour site-context.yaml + verdict GO / NO GO pour publication des recos R-TRUST-01-02 à R-TRUST-01-11."
- Effort estimé : M
- Validation :
Note Legal-check produite avec sources primaires (URLs arsjpa.gov.gn + textes officiels GN). site-context.yaml mis à jour : facts.allowed.entities rempli, legal_naming_restrictions.references complété avec décret + date, facts.to_confirm réduit (idéalement vide ou réduit à 1-2 items résiduels). Brand canonical_legal rempli (raison sociale opérateur). Avant assemble_audit final, ce bloc de validation doit être passé à 100 %, sinon le livrable doit être marqué "preview" et le FULL bloqué.
R-TRUST-01-11 : Préparer un disclaimer YMYL à intégrer en tête du livrable + brief Legal-check pour bouclage obligatoire avant publication
- Findings adressés : F-TRUST-01-02, F-TRUST-01-03, F-TRUST-01-04, F-TRUST-01-07, F-TRUST-01-11
- Routes concernées :
all - Priorité RICE : R=5 I=5 C=5 E=1 → score=125.0
- Action concrète :
(1) Intégrer en tête de analyse.md ET de plan-action.md un disclaimer YMYL spécifique gambling Guinée (copy-ready ci-dessous). (2) Lancer l'agent Legal-check du red team adversarial AVANT toute publication (boucle itérative jusqu'à 0 erreur HIGH selon CLAUDE.md projet). (3) Documenter les arbitrages Legal-check dans _red-team-report.md avec verdict GO / GO with patches / NO GO.
- Copy-ready :
Disclaimer en tête de analyse.md et plan-action.md : > Avertissement YMYL : ce rapport analyse le site bet224.gn, opérateur de paris sportifs et de casino en ligne en Guinée. Le secteur est classé YMYL (Your Money Your Life) en raison de l'impact financier et sanitaire potentiel sur les utilisateurs (risque d'addiction, perte d'argent, exposition de mineurs si protection absente). Les recommandations ci-dessous reposent sur (1) des observations sourcées du crawl du site (HTML, screenshots, signaux conversion-signals/axe-core), et (2) les standards internationaux du secteur gambling (UKGC, ANJ, MGA, ADM, etc.). La juridiction applicable est la Guinée. Le régulateur identifié est l'ARSJPA (https://arsjpa.gov.gn/, vérifié WebFetch 2026-05-16). Le statut d'agrément de Bet224 et le cadre réglementaire guinéen exact pour la publicité gambling, la protection des mineurs, le consentement cookies, et les mentions obligatoires N'ONT PAS été vérifiés en source primaire dans cette session. Toute recommandation marquée "conformité légale : false" est calibrée sur l'obligation morale sectorielle et le risque réputationnel ; elle doit être re-évaluée par l'agent Legal-check du red team avant publication finale.
- Effort estimé : S
- Validation :
Présence du disclaimer en tête de analyse.md ET plan-action.md après assemblage. Présence du _red-team-report.md avec section Legal-check + verdict explicite. Si verdict NO GO : interdiction de publication tant que les findings Legal-check HIGH ne sont pas résolus.
R-A11Y-01-02 : Ajouter alt et aria-label sur logo header et lien de retour accueil
- Findings adressés : F-A11Y-01-01
- Routes concernées :
all - Priorité RICE : R=5 I=4 C=5 E=1 → score=100.0
- Action concrète :
Dans le template du header, modifier la balise <img> du logo pour ajouter un alt, et ajouter un aria-label sur le <a> parent. Le fix est unique pour les 4 routes (template commun confirmé).
- Copy-ready :
HTML cible : <a href="/" aria-label="Bet224, retour à l'accueil"><img src="https://www.bet224.gn/external_cms/GUINEA/img/logo-bet-224.png" alt="Bet224"></a> (texte alt et label conformes au cadrage site-context.yaml brand.canonical_display = "Bet224", aucune incitation au jeu, ton sobre).
- Effort estimé : S
- Validation :
Re-run axe-core : violations[].id == "image-alt" pour le logo header retourne 0, violations[].id == "link-name" pour a[href="/"] retourne 0. Test NVDA / VoiceOver : le lien doit être annoncé "Bet224, retour à l'accueil, lien".
R-TRUST-01-05 : Lier fonctionnellement le logo ARSJPA vers le registre officiel + ajouter alt text + augmenter la visibilité
- Findings adressés : F-TRUST-01-01
- Routes concernées :
all - Priorité RICE : R=5 I=4 C=5 E=1 → score=100.0
- Action concrète :
(1) D'abord trancher avec Legal-check : Bet224 est-elle agréée ARSJPA ? Si NON : RETIRER l'image ARSJPA.png partout. Si OUI : appliquer les correctifs ci-dessous. (2) Wrapper l'image dans un <a> avec href réel pointant vers la page officielle de Bet224 sur arsjpa.gov.gn (si l'ARSJPA fournit des URLs profondes par opérateur, sinon vers la liste générale) ou vers /licence (page interne, cf R-TRUST-01-02). (3) Ajouter un alt descriptif sur l'image. (4) Augmenter la taille visible (typiquement 60-80px de hauteur, pas 35px de largeur). (5) Le déplacer en zone footer permanent (cf R-TRUST-01-03) où la mention "Agréé par l'ARSJPA n° X" sera proche du logo.
- Copy-ready :
Cas où Bet224 est agréée (à publier APRÈS confirmation Legal-check) : <a href="https://arsjpa.gov.gn/[chemin-bet224-si-existant]" target="_blank" rel="noopener noreferrer" aria-label="Voir la fiche Bet224 sur le registre officiel de l'ARSJPA (nouvel onglet)"> <img src="https://www.bet224.gn/external_css/GUINEA/img/ARSJPA.png" alt="Logo de l'ARSJPA, Autorité de Régulation du Secteur des Jeux et Pratiques Assimilées de Guinée. Bet224 est agréée sous le numéro [À COMPLÉTER]." style="height:60px;width:auto"> </a> Cas où Bet224 N'EST PAS agréée : RETIRER complètement le bloc <div id="plan-cg-social-link-container">...<img src="...ARSJPA.png">...</div> du template. Documentation patch à appliquer : supprimer lignes 386-393 de sport-home.raw.html (et équivalent sur toutes les pages template).
- Effort estimé : S
- Validation :
Si agréée : inspection des 4 screenshots → logo ARSJPA visible (≥60px), avec alt audit-script (grep alt="" sport-home.raw.html ne doit plus matcher la ligne ARSJPA). Test focus clavier : Tab atteint le <a> qui ouvre le lien externe. Test cross-angle A11Y : règle image-alt n'est plus violée sur ce node (axe-results recheck). Si non agréée : grep ARSJPA sur les fichiers raw HTML re-crawlés = 0 occurrence.
R-TRUST-01-08 : Ajouter identifiants commerciaux guinéens (RCCM + agrément ARSJPA) sur footer permanent et mentions légales
- Findings adressés : F-TRUST-01-08
- Routes concernées :
all - Priorité RICE : R=5 I=4 C=5 E=1 → score=100.0
- Action concrète :
(1) Obtenir du client (cf R-TRUST-01-01) : raison sociale exacte de l'entité opératrice (canonical_legal), siège social, RCCM, n° d'agrément ARSJPA. (2) Intégrer ces 4 identifiants dans le disclaimer permanent du footer (cf R-TRUST-01-03). (3) Intégrer le détail complet (raison sociale, capital, représentant légal, RCS) dans la page /mentions-legales (cf R-TRUST-01-02 copy-ready). (4) Patcher le détecteur conversion-signals v1.3 pour ajouter une regex RCCM (format OHADA : RCCM \w{2}-\w{3}-[0-9]{4}-[A-Z]-[0-9]{4,} approximatif, à valider source OHADA) et ne plus déclencher de faux positif sur les mots majuscules du contenu.
- Copy-ready :
Mention footer permanent (à intégrer dans le bloc disclaimer cf R-TRUST-01-03) : <p>Bet224 est édité par <strong>[Raison sociale]</strong>, [forme juridique, ex. SARL] au capital de [montant] GNF, siège social [adresse complète Conakry], immatriculée au RCCM sous le n° <strong>[n° RCCM]</strong>. Bet224 opère sous l'agrément de l'<abbr title="Autorité de Régulation du Secteur des Jeux et Pratiques Assimilées">ARSJPA</abbr> n° <strong>[n° agrément]</strong> délivré le [date]. <a href="https://arsjpa.gov.gn/" target="_blank" rel="noopener">Vérifier sur le registre officiel</a>.</p>
- Effort estimé : S
- Validation :
Re-crawl 4 routes : conversion-signals/<route>.json → detailed.trust_signals.footer_text_length_chars > 2000 (vs 1236 actuel). Grep raw HTML : présence des chaînes "[Raison sociale]", "[n° RCCM]", "[n° agrément]" remplacées par valeurs réelles. Patcher détecteur v1.3 : has_vat_eu et has_siret doivent désormais retourner false (faux positifs corrigés) ; un nouveau champ has_rccm doit retourner true si RCCM présent. Test cross-link : <a href="https://arsjpa.gov.gn/"> fonctionne.
R-TRUST-01-09 : Exposer contact opérateur visible (email support + numéro téléphone GN + formulaire) dans header ou footer permanent
- Findings adressés : F-TRUST-01-09
- Routes concernées :
all - Priorité RICE : R=5 I=4 C=5 E=1 → score=100.0
- Action concrète :
(1) Remplir le container cg-contatti du header (actuellement <div class="blocco-header flex-container cg-contatti"></div>, vide) avec un email support + numéro téléphone GN + lien /contact. (2) Intégrer la même info en footer permanent (cf R-TRUST-01-03 bloc "Aide et opérateur"). (3) Créer la page /contact (soft 404 actuellement) avec formulaire de contact fonctionnel + email + téléphone + adresse + horaires support. (4) Si chat live disponible : ajouter widget chat persistant.
- Copy-ready :
Container header (à intégrer à la place de <div class="blocco-header flex-container cg-contatti"></div>) : <div class="blocco-header flex-container cg-contatti"> <a href="mailto:[support@bet224.gn]" aria-label="Email support Bet224"><i class="fas fa-envelope"></i> [support@bet224.gn]</a> <a href="tel:+224[numero]" aria-label="Téléphone support Bet224 Guinée"><i class="fas fa-phone"></i> +224 [XX XX XX XX]</a> <a href="/contact">Nous contacter</a> </div> Squelette page /contact : <h1>Nous contacter</h1> <p>L'équipe support Bet224 est joignable [horaires, ex. 24h/24 et 7j/7, à confirmer client].</p> <h2>Email</h2> <p><a href="mailto:[support@bet224.gn]">[support@bet224.gn]</a></p> <h2>Téléphone</h2> <p>+224 [XX XX XX XX]</p> <h2>Adresse postale</h2> <p>[Raison sociale], [adresse complète Conakry]</p> <h2>Formulaire de contact</h2> <form action="/contact/submit" method="POST"> <label for="contact-name">Nom complet</label><input id="plan-contact-name" name="name" required> <label for="contact-email">Email</label><input id="plan-contact-email" name="email" type="email" required> <label for="contact-subject">Sujet</label><select id="plan-contact-subject" name="subject" required><option>Question générale</option><option>Problème de dépôt</option><option>Problème de retrait</option><option>Fermeture de compte</option><option>Auto-exclusion</option><option>Autre</option></select> <label for="contact-message">Message</label><textarea id="plan-contact-message" name="message" rows="6" required></textarea> <button type="submit">Envoyer</button> </form>
- Effort estimé : M
- Validation :
Re-crawl 4 routes : conversion-signals/<route>.json → detailed.trust_signals.contact_email_visible = true, contact_phone_visible_in_footer = true. Page /contact : body page ≠ 404, présence d'un <form action> avec ≥ 4 champs (cross-link CONV : analyse forms). Test mailto et tel: cliquables.
R-A11Y-01-07 : Nommer le bouton de fermeture du header (icône X)
- Findings adressés : F-A11Y-01-05
- Routes concernées :
all - Priorité RICE : R=5 I=3 C=5 E=1 → score=75.0
- Action concrète :
Ajouter un aria-label sur le <a id="plan-nascondiHeader">. L'attribut aria-expanded="false" déjà présent est OK car l'élément a role="button" explicite. Fix template header commun aux 4 routes.
- Copy-ready :
Attribut à ajouter : aria-label="Masquer le menu de navigation" (ton sobre, factuel, conforme site-context.yaml voice_and_tone).
- Effort estimé : S
- Validation :
Re-run axe-core : violations[].id == "link-name" pour #nascondiHeader retourne 0. Test NVDA : le lien est annoncé "Masquer le menu de navigation, bouton, réduit".
R-SEO-01-03 : Ajouter Open Graph + Twitter Cards sur les 4 routes (partage social et fallback LLM)
- Findings adressés : F-SEO-01-03
- Routes concernées :
sport-home,sport,casino,promotions - Priorité RICE : R=5 I=3 C=5 E=1 → score=75.0
- Action concrète :
Ajouter dans le <head> de chaque route les meta tags Open Graph (og:title, og:description, og:image, og:url, og:type, og:site_name, og:locale) et Twitter Cards (twitter:card, twitter:title, twitter:description, twitter:image). Valeurs alignées sur les title / description du R-SEO-01-01 pour cohérence cross-canal. Préparer une image OG dédiée 1200×630 px par route (logo Bet224 + visuel sectoriel : ballon football pour sport, jeton casino pour casino, etiquette bonus pour promotions).
- Copy-ready :
Bloc OG sport-home à insérer dans le <head> : <meta property="og:title" content="Bet224 Guinée : paris sportifs, casino et bonus en ligne" /> <meta property="og:description" content="Bet224 Guinée, site de paris sportifs en ligne. Pariez sur le football, la Premier League, la Ligue 1 et la Champions League. Cotes en direct." /> <meta property="og:image" content="https://www.bet224.gn/external_cms/GUINEA/img/og-image-sport-home.jpg" /> <meta property="og:url" content="https://www.bet224.gn/sport-home" /> <meta property="og:type" content="website" /> <meta property="og:site_name" content="Bet224" /> <meta property="og:locale" content="fr_GN" /> <meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:title" content="Bet224 Guinée : paris sportifs, casino et bonus en ligne" /> <meta name="twitter:description" content="Bet224 Guinée, site de paris sportifs en ligne. Pariez sur le football et le casino en direct." /> <meta name="twitter:image" content="https://www.bet224.gn/external_cms/GUINEA/img/og-image-sport-home.jpg" /> Adapter les 3 autres routes avec les title / description du R-SEO-01-01 + 1 image dédiée par route.
- Effort estimé : S
- Validation :
Re-crawl puis grep og: et twitter: sur chaque raw HTML retourne ≥ 12 occurrences (7 OG + 4 Twitter + 1 type). Test Facebook Sharing Debugger https://developers.facebook.com/tools/debug/ et Twitter Card Validator (legacy) ou OG inspector sur chaque URL retourne preview correct avec image, title et description attendus.
R-UX-01-03 : Nettoyer les meta description / keywords résiduels d'autres marques
- Findings adressés : F-UX-01-05
- Routes concernées :
all - Priorité RICE : R=5 I=3 C=5 E=1 → score=75.0
- Action concrète :
Réécrire les <meta name="description"> et <meta name="keywords"> (si conservées) en supprimant toute occurrence de "Sportcash.com" et "Ivory Coast" / "Côte d'Ivoire" / "Loterie Ivory Coast". Remplacer par un texte adapté à Bet224 en Guinée, respectant site-context.yaml → voice_and_tone.avoid (pas de superlatif, pas de promesse de gain).
- Copy-ready :
Meta descriptions (proposition) :
sport-home:<meta name="description" content="Bet224, paris sportifs en ligne en Guinée. Consultez les cotes du jour sur le football et les autres sports.">sport:<meta name="description" content="Toutes les compétitions sportives disponibles pour parier sur Bet224 en Guinée.">casino:<meta name="description" content="Catalogue des jeux de casino disponibles sur Bet224 en Guinée, classés par éditeur.">promotions:<meta name="description" content="Promotions et bonus en cours sur Bet224 en Guinée. Consultez les conditions de chaque offre avant de l'activer.">
Meta keywords (option : supprimer purement) : si conservée pour des raisons internes, remplacer par <meta name="keywords" content="Bet224, paris sportifs, Guinée, football, casino en ligne"> (ne plus mentionner Ivory Coast, Sportcash, Loterie). Toast EN (raw_html_sport_home ligne 875) : remplacer le contenu par français, ex <div class="cg-toast-desc-content">Cliquez <span onclick="cg_open_user_details();cg_close_toast(this)">ICI</span> pour configurer votre compte, ou <span onclick="cg_never_show_this_again(this)">ICI</span> pour ne plus afficher ce message.</div>.
- Effort estimé : S
- Validation :
Re-crawl puis vérifier index.json → pages[].description ne contient plus "Sportcash.com" ni "Ivory Coast". grep -i "Ivory Coast\|Sportcash" *.raw.html retourne 0.
R-CONV-01-01 : Réécrire les bandeaux promotionnels above-fold sans promesse de gain ni superlatif
- Findings adressés : F-CONV-01-01
- Routes concernées :
sport-home,promotions - Priorité RICE : R=5 I=5 C=5 E=2 → score=62.5
- Action concrète :
Remplacer les 3 visuels JPG des bannières hero (BPD_SPORT_1800X600_promotions.jpg, CASHBACK_1800X600_promos.jpg, et la bannière MAXI BONUS sur promotions) par des versions factuelles. Retitrer les 3 cards "MAXI BONUS / CASHBACK SPORT / WELCOME SPORT" sur la page promotions. Ajouter une mention explicite des conditions de mise (wagering) en visible above-fold sur chaque card, pas en caractères minuscules.
- Copy-ready :
Bandeau hero sport-home option 1 (factuel) : "Bonus de bienvenue : 100 % de votre 1er dépôt offerts en Fun Bonus Sport, jusqu'à 1 000 000 GNF. Voir les conditions de mise." (143 chars). Bandeau hero sport-home option 2 (plus court) : "Bonus de 1er dépôt jusqu'à 1 000 000 GNF en Fun Bonus Sport. Conditions de mise applicables." (95 chars). CTA bannière (1-4 mots) : "Voir les conditions" (à la place de "PARIEZ ICI" ou "INSCRIVEZ-VOUS"). Card MAXI BONUS retitrée : "Bonus de mise : jusqu'à 500 % du premier pari combiné. Voir les conditions." (75 chars). Card CASHBACK SPORT : "Cashback hebdomadaire sur les paris perdants, jusqu'à 500 000 GNF. Voir les conditions." (88 chars). À PROSCRIRE absolument : tout verbe "GAGNEZ" ou dérivés, tout "100 % gratuit", tout superlatif "BEST" / "N°1" / "leader", tout "PARIEZ ICI" en CTA bannière promotionnelle.
- Effort estimé : S
- Validation :
Sur les screenshots de re-crawl : aucun mot interdit de voice_and_tone.avoid ni claims.forbidden ne doit apparaître dans la zone above-fold (y < 900) des routes sport-home et promotions. Vérification par OCR du screenshot ou re-crawl text. Re-run par DEEP-CONV-02 obligatoire pour valider.
R-CONV-01-02 : Exposer en footer permanent les liens vers jeu responsable, auto-exclusion, mention d'âge et licence
- Findings adressés : F-CONV-01-02, F-CONV-01-06
- Routes concernées :
all - Priorité RICE : R=5 I=5 C=5 E=2 → score=62.5
- Action concrète :
Rendre le footer visible par défaut (supprimer le pattern accordion consulta-footer fissato accordion-toggle toggle-nascondi, exposer directement le bloc en bas de page). Y ajouter une rangée dédiée "Jouer responsable" en above-fold du footer avec 5 liens minimum : Jeu responsable, Auto-exclusion, Limites de dépôt, Aide et support, Contact. Ajouter sur le même bloc une mention d'âge claire (forme "Interdit aux mineurs", seuil à confirmer client + Legal-check pour cadre GN).
- Copy-ready :
Wording bloc footer (à coller dans un nouveau <div class="footer-responsible-gaming">) : <h3>Jouer responsable</h3> <ul> <li><a href="/jeu-responsable">Jeu responsable</a></li> <li><a href="/auto-exclusion">Auto-exclusion et limites</a></li> <li><a href="/aide">Aide et support</a></li> <li><a href="/contact">Nous contacter</a></li> <li><a href="/licence">Licence et réglementation</a></li> </ul> <p>Interdit aux mineurs. Le jeu d'argent peut entraîner une dépendance. Jouez avec modération.</p> (seuil d'âge exact à confirmer client + Legal-check ; en attendant "Interdit aux mineurs" est défensif) ATTENTION : NE PAS utiliser le wording italien hard-codé header.disclaimer = "Il gioco è vietato ai minori di diciotto anni..." qui référencie le régulateur italien ADM et n'est ni traduit ni applicable.
- Effort estimé : M
- Validation :
Re-crawl 4 routes, conversion-signals/<route>.json → detailed.trust_signals.legal_links_count >= 5 (au lieu de 2 actuellement). detailed.trust_signals.contact_email_visible = true. Tester en clavier : Tab depuis le top de page doit atteindre les liens responsables en footer en ≤ 50 stops.
R-MOBILE-01-01 : Recapturer les inputs mobile en V2 audit (screenshots + axe + CrUX)
- Findings adressés : F-MOBILE-01-01, F-MOBILE-01-02, F-MOBILE-01-03, F-MOBILE-01-04
- Routes concernées :
all,/inscription,/login,/depot - Priorité RICE : R=5 I=5 C=5 E=2 → score=62.5
- Action concrète :
V2 audit doit produire : (1) screenshots/<slug>/mobile.png 390x844 DPR=3 pour les 4 routes vitrine + 3 routes funnel minimum, (2) axe-results/<slug>/mobile.json avec les 7+ règles WCAG 2.1 AA sur chaque route mobile, (3) crux.json avec form_factor=PHONE si CRUX_API_KEY configurée (sinon mention explicite que la donnée terrain mobile est manquante), (4) page-signals/<slug>.signals.json enrichi avec viewport_meta (présence + valeur) et touch_targets (count de cibles < 44x44 mesurées sur viewport mobile, pas desktop). Outils à implémenter ou compléter dans toolkit/tools/ : capture_screenshots.py, run_axe_core.py, fetch_crux.py.
- Copy-ready :
N/A (action outillage, pas rédactionnel).
- Effort estimé : M
- Validation :
axe-results/index.json → results[].mobile.path != None pour toutes les routes ; screenshots/<slug>/mobile.png existe pour les 4 routes vitrine + 3 routes funnel ; axe-results/<slug>/mobile.json parseable avec violations[] non vide ; crux.json contient form_factor=PHONE ou mention explicite de manque.
R-SEO-01-01 : Réécrire les titles et meta descriptions des 4 routes principales avec brand canonique et intent différencié
- Findings adressés : F-SEO-01-01
- Routes concernées :
sport-home,sport,casino,promotions - Priorité RICE : R=5 I=5 C=5 E=2 → score=62.5
- Action concrète :
Modifier les templates SEO route par route dans le back-office CMS CoreGaming, pour porter la brand canonique "Bet224", inclure le primary keyword mappé, ajouter le qualificatif géo "Guinée" en fin (signal géo-intent SERP) et garder ≤ 60 chars sur le title et 140-160 chars sur la description. Supprimer toute mention "Sportcash.com" et "Ivory Coast" (legacy CMS d'un autre opérateur). Aligner la meta keywords (faible poids SEO mais signal interne brand) si conservée.
- Copy-ready :
Title sport-home : Bet224 Guinée : paris sportifs, casino et bonus en ligne (54 chars, brand + 3 verticales + géo). Description sport-home : Bet224 Guinée, site de paris sportifs en ligne. Pariez sur le football, la Premier League, la Ligue 1 et la Champions League. Cotes en direct. (148 chars, brand + intent + 4 keywords secondaires + signal live). Title sport : Paris sportifs en ligne Guinée : cotes football | Bet224 (56 chars, primary + secondary + brand). Description sport : Pariez en ligne sur les meilleurs matchs de football avec Bet224 Guinée : Premier League, Ligue 1, La Liga, Champions League. Cotes mises à jour. (148 chars). Title casino : Casino en ligne Guinée : jeux et machines à sous | Bet224 (57 chars, primary + secondary + brand). Description casino : Découvrez le casino en ligne Bet224 Guinée : machines à sous, jeux de table et providers Spribe, Evolution, Amigo Gaming. Jeu réservé aux majeurs. (149 chars, primary + 3 providers + mention âge). Title promotions : Bonus paris sportifs Bet224 Guinée : promotions en ligne (56 chars, primary + brand + géo). Description promotions : Profitez des bonus de bienvenue, codes promo et offres exclusives Bet224 Guinée sur vos paris sportifs et casino. Conditions de mise détaillées. (148 chars, primary + 3 secondaires + mention conditions, conforme site-context.yaml claims.forbidden "Bonus sans condition").
- Effort estimé : S
- Validation :
Re-crawl post-déploiement avec html_downloader.py puis vérifier : crawl/index.json pages[].title = valeurs copy-ready ci-dessus (longueur 50-60 chars, primary keyword inclus, mention "Bet224" inclus, "Sportcash.com" absent). Idem pages[].description (140-160 chars, "Bet224" présent, "Sportcash" absent).
R-TRUST-01-03 : Rendre le footer visible par défaut + restructurer en bloc "Jouer responsable" + bloc "Légal + opérateur" + bloc "Aide"
- Findings adressés : F-TRUST-01-06, F-TRUST-01-04, F-TRUST-01-09
- Routes concernées :
all - Priorité RICE : R=5 I=5 C=5 E=2 → score=62.5
- Action concrète :
(1) Supprimer le pattern accordion consulta-footer fissato accordion-toggle toggle-nascondi et le bouton "OUVRIR PIED DE PAGE". Le footer doit être visible directement en bas de page sans interaction. Supprimer aussi class="cg-lazy" du <footer> pour chargement immédiat. (2) Restructurer le contenu du footer en 3 colonnes : "Jouer responsable" (jeu responsable, auto-exclusion, limites de dépôt, où trouver de l'aide), "Légal" (mentions légales, CGU, politique de confidentialité, politique cookies, licence ARSJPA), "Aide & opérateur" (contact, FAQ, à propos, support). (3) Ajouter en bas du footer un bloc disclaimer permanent avec mention d'âge légal (seuil exact à confirmer Legal-check), logo ARSJPA avec href vers le registre, raison sociale + n° licence opérateur. (4) Tester l'accessibilité clavier (Tab depuis le top doit atteindre le footer en ≤50 stops, cross-link A11Y).
- Copy-ready :
Structure HTML cible footer (à intégrer dans nascondifooter mais SANS class collapse cg-lazy, et SANS bouton "OUVRIR PIED DE PAGE") : <footer id="plan-site-footer" class="bg-footer text-light pt-4"> <div class="container"> <div class="row"> <div class="col-lg-4"> <h3>Jouer responsable</h3> <ul class="list-unstyled"> <li><a href="/jeu-responsable">Jeu responsable</a></li> <li><a href="/auto-exclusion">Auto-exclusion et limites</a></li> <li><a href="/limites-depot">Limites de dépôt</a></li> <li><a href="/aide-joueurs">Où trouver de l'aide</a></li> </ul> </div> <div class="col-lg-4"> <h3>Légal</h3> <ul class="list-unstyled"> <li><a href="/mentions-legales">Mentions légales</a></li> <li><a href="/cgu">Conditions générales d'utilisation</a></li> <li><a href="/privacy">Politique de confidentialité</a></li> <li><a href="/cookies">Politique des cookies</a></li> <li><a href="/licence">Licence et réglementation</a></li> </ul> </div> <div class="col-lg-4"> <h3>Aide et opérateur</h3> <ul class="list-unstyled"> <li><a href="/contact">Nous contacter</a></li> <li><a href="/aide">Aide et FAQ</a></li> <li><a href="/a-propos">À propos de Bet224</a></li> </ul> </div> </div> <div class="footer-disclaimer border-top pt-3 mt-3"> <p>[Raison sociale opérateur à compléter] - Siège social : [adresse Conakry] - RCCM [n°] - Agréé par l'ARSJPA sous le numéro [à compléter]. <a href="https://arsjpa.gov.gn/" target="_blank" rel="noopener"><img src="https://www.bet224.gn/external_css/GUINEA/img/ARSJPA.png" alt="Logo de l'ARSJPA, autorité guinéenne de régulation des jeux" style="height:30px"></a></p> <p><strong>Interdit aux mineurs.</strong> Le jeu d'argent peut entraîner une dépendance. Jouez avec modération. <a href="/jeu-responsable">Plus d'informations</a>. (Seuil d'âge légal à confirmer Legal-check, "Interdit aux mineurs" est défensif en attendant.)</p> </div> </div> </footer>
- Effort estimé : M
- Validation :
Re-crawl 4 routes : conversion-signals/<route>.json → detailed.trust_signals.legal_links_count >= 8 (vs 2 actuellement), contact_email_visible = true (si email réel intégré). Inspection visuelle des 4 screenshots : footer visible directement sans interaction, contenant les 3 colonnes + disclaimer permanent. Test clavier : Tab depuis top atteint le footer en ≤ 50 stops. Test axe-core : aucune nouvelle violation sur le footer (cross-link A11Y).
R-TRUST-01-04 : Ajouter une mention d'âge claire en footer permanent + implémenter un age-gate avant accès au catalogue casino
- Findings adressés : F-TRUST-01-07
- Routes concernées :
all,casino,sport,sport-home,promotions - Priorité RICE : R=5 I=5 C=5 E=2 → score=62.5
- Action concrète :
(1) Ajouter une mention "Interdit aux mineurs" en footer permanent visible sur les 4 routes (cf R-TRUST-01-03 copy-ready footer disclaimer). (2) Implémenter un age-gate : modal/overlay couvrant tout l'écran à la première visite du site (cookie de mémorisation 30 jours minimum), demandant à l'utilisateur de confirmer son âge avant accès au catalogue. (3) Sur la modal, mention claire du seuil légal GN + bouton "J'ai [SEUIL] ans ou plus, j'accède au site" + bouton "Je suis mineur, je quitte le site" (qui redirige vers https://arsjpa.gov.gn/ ou une page neutre). (4) Le seuil exact à intégrer doit être validé Legal-check (cf R-TRUST-01-01). En attendant, défensif : "Interdit aux moins de 21 ans" si pas de source claire (21 est plus restrictif et défensif que 18).
- Copy-ready :
Mention footer permanent (à intégrer dans le bloc disclaimer cf R-TRUST-01-03) : <p><strong>Interdit aux mineurs.</strong> L'âge légal pour parier en Guinée est de [SEUIL À CONFIRMER Legal-check] ans. Le jeu d'argent peut entraîner une dépendance. Jouez avec modération. <a href="/jeu-responsable">Plus d'informations sur le jeu responsable</a>.</p> Modal age-gate (HTML à coller dans <body> avec affichage conditionnel JS basé sur cookie bet224_age_verified) : <div id="plan-age-gate-modal" role="dialog" aria-labelledby="age-gate-title" aria-modal="true" style="position:fixed;top:0;left:0;width:100vw;height:100vh;background:rgba(0,0,0,0.95);z-index:9999;display:flex;align-items:center;justify-content:center"> <div style="background:white;padding:2rem;max-width:480px;border-radius:8px;text-align:center"> <h2 id="plan-age-gate-title">Confirmation d'âge</h2> <p>L'accès à Bet224 est strictement réservé aux personnes âgées de <strong>[SEUIL] ans ou plus</strong>. Le jeu d'argent peut entraîner une dépendance. Avant d'entrer, merci de confirmer votre âge.</p> <button onclick="cg_ageVerified(true)" class="btn btn-primary">J'ai [SEUIL] ans ou plus</button> <a href="https://arsjpa.gov.gn/" class="btn btn-link">Je suis mineur, je quitte le site</a> <p style="font-size:0.85rem;margin-top:1rem">En entrant sur ce site, vous confirmez avoir l'âge légal et acceptez nos <a href="/cgu">CGU</a> et notre <a href="/privacy">Politique de confidentialité</a>.</p> </div> </div> Script associé (à coller dans <head> ou <body> fin) : <script>function cg_ageVerified(ok){if(ok){document.cookie='bet224_age_verified=1;max-age=2592000;path=/;samesite=strict';document.getElementById('age-gate-modal').style.display='none';}}if(document.cookie.indexOf('bet224_age_verified=1')!==-1){document.addEventListener('DOMContentLoaded',()=>{var m=document.getElementById('age-gate-modal');if(m)m.style.display='none';});}</script> ATTENTION : NE PAS recopier le wording italien hard-codé header.disclaimer = "Il gioco è vietato ai minori di diciotto anni" ; il référence le seuil italien (18) qui peut ne pas être le seuil GN, et il est en italien.
- Effort estimé : M
- Validation :
Re-crawl 4 routes en mode "premier visiteur" (no cookies) : la modal age-gate doit apparaître au chargement, bloquant le catalogue. Test : navigation directe vers /casino doit déclencher la modal. Re-crawl en mode "cookie age verifié" : la modal ne doit pas apparaître. Validation Legal-check du seuil + du wording. Grep <screenshot>/desktop.png : mention "Interdit aux mineurs" visible permanent en footer.
R-UX-01-01 : Remplacer "OUVRIR PIED DE PAGE" par un footer visible permanent et redirigé vers les obligations YMYL
- Findings adressés : F-UX-01-01, F-UX-01-02, F-UX-01-10
- Routes concernées :
all - Priorité RICE : R=5 I=5 C=5 E=2 → score=62.5
- Action concrète :
(1) Retirer class="collapse cg-lazy" du <footer id="plan-nascondifooter"> pour le rendre visible en permanence en bas de chaque route. (2) Supprimer le bouton <a id="plan-consultaFooter">OUVRIR PIED DE PAGE</a> et le bouton miroir <a id="plan-nascondiFooter">FERMER PIED DE PAGE</a>. (3) Restructurer le footer en 4 colonnes : "À propos" (raison sociale, licence, adresse, ARSJPA en lien cliquable vers https://arsjpa.gov.gn/), "Aide & contact" (FAQ, formulaire, email, téléphone si dispo), "Légal" (Politique de Confidentialité, Conditions Générales, Cookies, Mentions légales), "Jeu responsable" (cf R-UX-01-08).
- Copy-ready :
Suppression de l'élément : retirer ligne <a id="plan-consultaFooter">OUVRIR PIED DE PAGE</a> du template global. Restructuration HTML : <footer role="contentinfo" class="bg-bianco"> <div class="container"> <div class="row"> <div class="col-md-3"><h2 class="cg-footer-section-title">À propos</h2><p>Bet224, paris sportifs en ligne en Guinée. <a href="https://arsjpa.gov.gn/" target="_blank" rel="noopener">Régulateur : ARSJPA</a>.</p></div> <div class="col-md-3"><h2 class="cg-footer-section-title">Aide & contact</h2><ul><li><a href="/faq">Foire aux questions</a></li><li><a href="/contact">Nous contacter</a></li></ul></div> <div class="col-md-3"><h2 class="cg-footer-section-title">Informations légales</h2><ul><li><a href="/promo/tutte/bet224_conditions_generales">Conditions Générales</a></li><li><a href="/promo/tutte/bet224_politique_confidentialite">Politique de Confidentialité</a></li><li><a href="/external_cms/pdf/Cookies_Policy.pdf" target="_blank">Politique des cookies (PDF)</a></li></ul></div> <div class="col-md-3"><h2 class="cg-footer-section-title">Jeu responsable</h2><p><strong>Jouer doit rester un plaisir.</strong></p><ul><li><a href="/jeu-responsable">Conseils pour jouer en sécurité</a></li><li><a href="/auto-exclusion">Demander l'auto-exclusion</a></li></ul></div> </div> </div></footer> (libellés à valider Legal-check pour la juridiction GN ; les liens /jeu-responsable, /auto-exclusion, /contact, /faq sont à créer en parallèle, cf R-UX-01-08).
- Effort estimé : M
- Validation :
Re-run analyze_conversion_signals.py sur chaque route après déploiement : summary.primary_cta_text ne doit plus être "OUVRIR PIED DE PAGE" ; summary.trust_legal_links_count doit passer de 2 à 3 (ajout cookies en lien web) ; detailed.trust_signals.contact_links_count doit être ≥ 1 (formulaire contact ou email visible). Test manuel : footer visible sans clic sur les 4 routes.
R-A11Y-01-08 : Ajouter un label au toggle de thème dark/light
- Findings adressés : F-A11Y-01-04
- Routes concernées :
all - Priorité RICE : R=5 I=2 C=5 E=1 → score=50.0
- Action concrète :
Ajouter un <label for="cg-theme-switch"> autour ou à proximité de l'input, ou un aria-label directement sur l'input. Fix template footer commun aux 4 routes.
- Copy-ready :
Variante label visible : <label for="cg-theme-switch">Activer le mode sombre</label> (texte à placer dans le footer à côté du toggle). Variante aria-label seul si le composant doit rester sans label visible : aria-label="Activer le mode sombre".
- Effort estimé : S
- Validation :
Re-run axe-core : violations[].id == "label" pour #cg-theme-switch retourne 0.
R-A11Y-01-10 : Ajouter un alt vide ou un label au drapeau langue fr.png
- Findings adressés : F-A11Y-01-02
- Routes concernées :
all - Priorité RICE : R=5 I=2 C=5 E=1 → score=50.0
- Action concrète :
Si le libellé texte "FR" adjacent porte déjà l'information (cas le plus probable au vu de conversion-signals/sport-home.json → detailed.ctas[3].text = "FR"), marquer l'image comme décorative : ajouter alt="" + role="presentation". Sinon, si le drapeau est l'unique vecteur d'info (variante mobile sans texte adjacent), ajouter alt="Français".
- Copy-ready :
Cas décoratif : <img src="/images/desktop/fr.png" class="flag-lang" alt="" role="presentation">. Cas porteur d'info : <img src="/images/desktop/fr.png" class="flag-lang" alt="Français">.
- Effort estimé : S
- Validation :
Re-run axe-core : violations[].id == "image-alt" pour img[src$="fr.png"] retourne 0.
R-PERF-01-04 : Ajouter 2-3 <link rel="preconnect"> en tête de <head> pour origines critiques
- Findings adressés : F-PERF-01-04
- Routes concernées :
all - Priorité RICE : R=5 I=2 C=5 E=1 → score=50.0
- Action concrète :
Ajouter ces 3 <link> en tout début de <head> (avant tout <script> / <style>) :
<link rel="preconnect" href="https://www.googletagmanager.com" crossorigin>(pour GTM + gtag.js)<link rel="dns-prefetch" href="https://www.googletagmanager.com">(fallback navigateurs sans preconnect)- Si une autre origine tierce devient nécessaire en V2 (CDN images, fonts Google, etc.) : ajouter un
preconnectcorrespondant. - Copy-ready :
Insertion à ajouter en <head> ligne ~5 (juste après <meta charset> si présent, avant GTM) : ``html <link rel="preconnect" href="https://www.googletagmanager.com" crossorigin> <link rel="dns-prefetch" href="https://www.googletagmanager.com"> ``
- Effort estimé : S
- Validation :
Inspecter le <head> final sur les 4 routes : présence des deux <link> en position 1-2 du <head>. Chrome DevTools Network panel : connexion à googletagmanager.com établie avant le premier <script async>.
R-SEO-01-02 : Injecter le JSON-LD Schema.org minimal sur les 4 routes (Organization + WebSite + WebPage + spécifique par route)
- Findings adressés : F-SEO-01-02
- Routes concernées :
sport-home,sport,casino,promotions - Priorité RICE : R=5 I=4 C=5 E=2 → score=50.0
- Action concrète :
Ajouter dans le <head> de chaque page un bloc <script type="application/ld+json"> contenant a minima : un Organization global (nom canonique "Bet224", logo, URL, sameAs réseaux sociaux quand confirmés par client), un WebSite (nom + potentialAction SearchAction si recherche interne existe), un WebPage par route avec breadcrumb BreadcrumbList. Sur sport et casino, ajouter ItemList du catalogue (compétitions / providers de jeux). Sur promotions, ajouter Offer par bonus avec termsOfService (conditions de mise).
- Copy-ready :
Bloc global à injecter sur les 4 routes (placeholder URLs réseaux sociaux à confirmer client) : <script type="application/ld+json">{"@context":"https://schema.org","@type":"Organization","name":"Bet224","alternateName":["Bet224"],"url":"https://www.bet224.gn/","logo":"https://www.bet224.gn/external_cms/GUINEA/img/logo-bet-224.png","sameAs":["TODO_facebook_url","TODO_x_url","TODO_telegram_url"]}</script> Bloc sport-home complémentaire : <script type="application/ld+json">{"@context":"https://schema.org","@type":"WebSite","name":"Bet224","url":"https://www.bet224.gn/","inLanguage":"fr-GN"}</script> Bloc casino complémentaire avec mention âge : <script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","name":"Casino en ligne Guinée Bet224","url":"https://www.bet224.gn/casino","audience":{"@type":"PeopleAudience","suggestedMinAge":"TODO_age_legal_GN_a_sourcer"}}</script> Pour Offer / Promotion / ItemList, structure à compléter selon contenu réel post-décision client.
- Effort estimé : S
- Validation :
curl https://www.bet224.gn/sport-home | grep "application/ld+json" retourne ≥ 1 occurrence par route. Re-crawl html_downloader.py puis crawl/index.json pages[].json_ld = array non vide avec au moins @type: Organization + @type: WebPage. Test Google Rich Results https://search.google.com/test/rich-results sur chaque URL retourne 0 erreur.
R-TRUST-01-06 : Réécrire le cookie banner avec bouton "Refuser" symétrique + granularité + lien vers page HTML cookie policy
- Findings adressés : F-TRUST-01-10, F-TRUST-01-14
- Routes concernées :
all - Priorité RICE : R=5 I=4 C=5 E=2 → score=50.0
- Action concrète :
(1) Supprimer le wording "En poursuivant votre navigation, vous acceptez l'utilisation de tous les cookies" (consent passif). Le remplacer par un consent actif : l'utilisateur DOIT cliquer pour accepter, refuser, ou paramétrer. (2) Ajouter un bouton "Refuser" symétrique au "OK" (même taille, même position, même contraste). (3) Ajouter un bouton "Paramétrer" qui ouvre une modal de granularité : cookies fonctionnels (toujours activés, justification), analytics (opt-in), profilage tiers (opt-in). (4) Remplacer le lien PDF /external_cms/pdf/Cookies_Policy.pdf par une page HTML navigable /cookies (créée dans R-TRUST-01-02) listant chaque cookie tiers utilisé (Google Analytics G-VLQSP6C303, GTM-MZ7JZBPZ, et tous les autres détectés en audit RGPD-like). (5) Mémoriser le choix utilisateur via cookie technique sans expirer < 6 mois (re-demander si refresh ou si changement de cookies tiers).
- Copy-ready :
Bandeau cookie nouveau (à coller à la place du bloc cg-barra-cookies actuel) : <div id="plan-cookie-banner" role="dialog" aria-labelledby="cookie-title" aria-describedby="cookie-desc" style="position:fixed;bottom:0;left:0;width:100vw;background:#2d3844;color:white;padding:1rem;z-index:9999"> <div style="max-width:1200px;margin:0 auto;display:flex;flex-wrap:wrap;align-items:center;gap:1rem;justify-content:space-between"> <div> <h2 id="plan-cookie-title" style="font-size:1rem;margin:0 0 0.5rem 0">Vos préférences cookies</h2> <p id="plan-cookie-desc" style="margin:0;font-size:0.9rem">Nous utilisons des cookies pour faire fonctionner le site, mesurer son audience et personnaliser le contenu. Vous pouvez accepter tous les cookies, les refuser, ou les paramétrer. <a href="/cookies" style="color:#fff;text-decoration:underline">En savoir plus</a>.</p> </div> <div style="display:flex;flex-wrap:wrap;gap:0.5rem"> <button onclick="cg_acceptCookies('all')" class="btn btn-primary">Tout accepter</button> <button onclick="cg_acceptCookies('none')" class="btn btn-secondary">Tout refuser</button> <button onclick="cg_openCookieSettings()" class="btn btn-link" style="color:white">Paramétrer</button> </div> </div> </div> Wording de la modale paramétrer (à coller dans cg_openCookieSettings()) : Cookies fonctionnels : indispensables au fonctionnement du site (session, panier de paris, langue). Toujours activés. [non opt-out, justification : sans eux, le site ne fonctionne pas]. Cookies analytics : nous aident à comprendre comment vous utilisez le site (Google Analytics anonymisé G-VLQSP6C303). [opt-in case à cocher]. Cookies de profilage tiers : permettent de personnaliser les promotions affichées en fonction de votre activité. [opt-in case à cocher, par défaut DÉCOCHÉE]. ATTENTION : ne pas ré-utiliser le wording italien cg_LABEL["cookie.this.consent"] = "Accetta sempre questo sito" qui est en italien et reste passif.
- Effort estimé : M
- Validation :
Inspection visuelle re-crawl : bandeau avec 3 boutons "Tout accepter", "Tout refuser", "Paramétrer". Test : clic "Tout refuser" supprime les cookies analytics+profilage du document.cookie après reload. Test page /cookies : page-signals/cookies.signals.json → word_count > 500. Validation Legal-check sur wording + granularité conforme cadre GN.
R-UI-01-03 : Purger les stacks de polices parasites et déclarer DMSans comme unique famille canonique
- Findings adressés : F-UI-01-03
- Routes concernées :
all - Priorité RICE : R=5 I=2 C=5 E=1 → score=50.0
- Action concrète :
Identifier les 2-3 fichiers CSS qui déclarent les stacks system-ui parasites sur html et body (probablement Bootstrap reset + framework legacy). Soit les supprimer, soit les remplacer par une déclaration unique html, body { font-family: var(--font-family-base); }. Ajouter un fallback de qualité après DMSans pour le cas FOUT : DMSans, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif (un seul stack canonique).
- Copy-ready :
Token CSS à placer dans :root : ``css :root { --font-family-base: "DMSans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; } html, body { font-family: var(--font-family-base); } ` Supprimer toute autre déclaration font-family sur html ou body` dans les CSS existants.
- Effort estimé : S
- Validation :
Re-run analyze_design_system.py : aggregate.typography.unique_font_family_count = 1 (ou 2 si on garde un stack icon font distinct), aggregate.typography.font_families[0].value débute par "DMSans" et est appliqué à 100 % des contextes (["a", "body", "footer", "h2", "h5", "html", "main"]).
R-UX-01-02 : Réinjecter un H1 explicite + intro courte sur chaque route
- Findings adressés : F-UX-01-04
- Routes concernées :
all - Priorité RICE : R=5 I=4 C=5 E=2 → score=50.0
- Action concrète :
Ajouter sur chaque route un <h1> dans le wrapper principal <main id="plan-panel">, juste avant le premier carrousel / contenu. Optionnellement encadrer d'un <p> court (1 phrase) qui précise la promesse de page. Garder un ton sobre conforme site-context.yaml → voice_and_tone.tone = "factuel, sobre, transparent".
- Copy-ready :
Propositions (ton sobre, sans incitation, sans promesse de gain) :
sport-home:<h1>Paris sportifs en ligne en Guinée</h1><p class="margine-su">Consultez les cotes du jour sur le football, le basketball et les autres sports. Pour parier, créez un compte ou connectez-vous.</p>sport:<h1>Toutes les compétitions sportives</h1><p class="margine-su">Explorez les compétitions disponibles par sport et construisez votre pari. Cliquez sur une cote pour l'ajouter à votre ticket.</p>casino:<h1>Jeux de casino en ligne</h1><p class="margine-su">Découvrez le catalogue des jeux classés par éditeur. Cliquez sur un jeu pour ouvrir la fiche, et sur "Jouer" pour démarrer une session.</p>promotions:<h1>Promotions et bonus en cours</h1><p class="margine-su">Découvrez les offres en cours. Chaque bonus est soumis à des conditions (mises minimales, durée, sports éligibles) détaillées sur la fiche de l'offre.</p>(formulation neutre, sans superlatif).- Effort estimé : S
- Validation :
Test manuel : un H1 visible sur chaque route. Re-run axe-core : violations[].id == "page-has-heading-one" retourne 0. Re-crawl : index.json → pages[].word_count augmente d'environ 15-30 mots par route.
R-TRUST-01-02 : Créer les 16 pages support/legal/about manquantes (mentions légales, licence, jeu responsable, privacy, contact, etc.)
- Findings adressés : F-TRUST-01-02, F-TRUST-01-03, F-TRUST-01-04, F-TRUST-01-05, F-TRUST-01-09, F-TRUST-01-11
- Routes concernées :
mentions-legales,licence,jeu-responsable,responsible-gaming,privacy,politique-confidentialite,cgu,conditions,terms,contact,a-propos,qui-sommes-nous,aide,help,faq,bonus,cookies - Priorité RICE : R=5 I=5 C=5 E=3 → score=41.67
- Action concrète :
Créer côté CMS les 17 pages canoniques manquantes avec contenu réel (pas de placeholder lorem). Routes prioritaires (à créer avant tout le reste) : /mentions-legales, /licence, /jeu-responsable, /contact, /privacy (priorité TRUST critique). Routes secondaires : /cgu, /aide, /a-propos, /bonus, /cookies. Routes redirigées (synonymes français/anglais) : /responsible-gaming → /jeu-responsable, /politique-confidentialite → /privacy, /conditions et /terms → /cgu, /qui-sommes-nous → /a-propos, /help et /faq → /aide. Le contenu de chaque page doit être validé par Legal-check (R-TRUST-01-01). Aucune page ne doit retourner body page="404" sur une URL canonique listée.
- Copy-ready :
Squelette /mentions-legales (wording à valider Legal-check, raison sociale à remplacer une fois sourcée) : <h1>Mentions légales</h1> <h2>Éditeur du site</h2> <p>Raison sociale : [À COMPLÉTER, ex. SARL Bet224 Guinée]<br>Siège social : [À COMPLÉTER, adresse complète Conakry]<br>RCCM : [À COMPLÉTER, numéro RCCM OHADA]<br>Représentant légal : [À COMPLÉTER]</p> <h2>Agrément réglementaire</h2> <p>Bet224 opère en Guinée sous l'agrément de l'Autorité de Régulation du Secteur des Jeux et Pratiques Assimilées (ARSJPA), numéro d'agrément [À COMPLÉTER], délivré le [À COMPLÉTER]. Consulter le registre des plateformes agréées : <a href="https://arsjpa.gov.gn/" target="_blank" rel="noopener">arsjpa.gov.gn</a>.</p> <h2>Hébergement</h2> <p>[À COMPLÉTER : hébergeur du site, raison sociale, adresse]</p> <h2>Contact</h2> <p>Email : [À COMPLÉTER]<br>Téléphone : [À COMPLÉTER]<br>Formulaire de contact : <a href="/contact">nous contacter</a></p> <h2>Propriété intellectuelle</h2> <p>L'ensemble des contenus du site bet224.gn est protégé par le droit d'auteur. Toute reproduction sans autorisation préalable est interdite.</p> Squelette /jeu-responsable (wording à valider Legal-check) : <h1>Jouer responsable</h1> <p>Le jeu d'argent peut entraîner une dépendance. Pour jouer en toute sécurité, Bet224 met à votre disposition des outils de modération.</p> <h2>Limites de mise et de dépôt</h2> <p>Depuis votre compte (Mon compte > Préférences de jeu), vous pouvez fixer une limite quotidienne, hebdomadaire ou mensuelle de mise et de dépôt.</p> <h2>Auto-exclusion</h2> <p>Vous pouvez vous auto-exclure temporairement (24h, 7j, 30j) ou définitivement depuis votre compte. L'auto-exclusion est immédiate et empêche tout accès au jeu pendant la durée choisie.</p> <h2>Signes d'un jeu problématique</h2> <p>Vous misez plus que prévu, vous jouez pour récupérer vos pertes, vous cachez votre activité de jeu à vos proches. Si vous reconnaissez ces signes, demandez de l'aide.</p> <h2>Où trouver de l'aide en Guinée</h2> <p>[À COMPLÉTER Legal-check : structure d'aide aux joueurs en Guinée si existante ; sinon, lister une ressource francophone internationale validée].</p>
- Effort estimé : L
- Validation :
Re-crawl complet : aucune des 17 URLs ne doit retourner body page="404". Toutes doivent avoir un <title> rempli, un <h1> rempli, un contenu réel >500 chars (page-signals/<route>.signals.json → word_count >= 100). Tous les liens du footer doivent pointer vers des URLs valides (validate_inputs links_resolution check). Re-validation Legal-check pour chaque contenu.
R-CONV-01-04 : Faire émerger un primary CTA business unique above-fold + retirer ou renommer "OUVRIR PIED DE PAGE"
- Findings adressés : F-CONV-01-04
- Routes concernées :
all - Priorité RICE : R=5 I=4 C=4 E=2 → score=40.0
- Action concrète :
(1) Convertir le bouton "Inscription" actuellement en <span onclick="cg_newAccount(true)"> vers un véritable <button type="button"> ou <a href="/signup"> accessible, avec class CSS de mise en avant claire (taille + couleur + isolement spatial). (2) Définir un primary CTA business unique above-fold = "Inscription" sur les routes non-authentifiées (sport-home, sport, casino, promotions), bouton plus large que tous les autres CTAs adjacents. (3) Supprimer le bouton "OUVRIR PIED DE PAGE" en exposant le footer par défaut (cf R-CONV-01-02). Si conservation absolument nécessaire pour raison technique, renommer en wording compréhensible et le sortir de l'above-fold.
- Copy-ready :
CTA Inscription (1-4 mots, conformes voice_and_tone) : "S'inscrire" (option neutre) ou "Créer un compte" (3 mots, plus explicite). À PROSCRIRE en CTA Inscription : "Gagnez", "Parier maintenant", "Pariez ici" (incitation), "Profitez du bonus" (promesse). Wrapping HTML : <a href="/signup" class="btn-primary-cta" role="button">S'inscrire</a> (à la place du <span onclick> actuel). Si "OUVRIR PIED DE PAGE" conservé : renommer en "Informations légales" (2 mots).
- Effort estimé : S
- Validation :
Re-crawl, conversion-signals/<route>.json → detailed.primary_cta.text doit être "S'inscrire" ou "Créer un compte" (pas "Basketball" ni "OUVRIR PIED DE PAGE"). detailed.primary_cta.above_fold = true. Le bouton doit avoir bbox.width >= 120 et bbox.height >= 40 (au-dessus de la moyenne des CTAs adjacents).
R-CONV-01-06 : Étendre le crawl POC v2 aux routes funnel critique /signup, /login, /depot, page jeu individuelle, page retrait
- Findings adressés : F-CONV-01-07
- Routes concernées :
signup,login,depot,jeu-detail,retrait - Priorité RICE : R=4 I=4 C=5 E=2 → score=40.0
- Action concrète :
Ajouter à la config du crawler product-audit (probablement clients/bet224/audit-config.yaml ou équivalent) les routes : /signup, /login (modal et page), /depot, /depot/methodes, /retrait, une route exemple /sport/match/<id> détail match, une route exemple /casino/jeu/<id> détail jeu. Re-lancer html_downloader.py + analyze_conversion_signals.py + capture_screenshots.py + run_axe_core.py. Produire un DEEP-CONV-02 focalisé sur le funnel.
- Copy-ready :
Patch suggéré du fichier config (extrait, à adapter au format réel du crawler) : ``` routes_extra:
- path: /signup
label: Inscription
- path: /login
label: Connexion
- path: /depot
label: Dépôt
- path: /retrait
label: Retrait ```
- Effort estimé : S
- Validation :
Après re-crawl, conversion-signals/index.json → aggregate.forms_total_all_routes > 0 et aggregate.max_form_field_count > 0. Un DEEP-CONV-02 doit pouvoir analyser le funnel d'inscription.
R-SEO-01-04 : Ajouter le markup âge légal et la mention "Jeu responsable" en footer SSR (YMYL gambling)
- Findings adressés : F-SEO-01-04
- Routes concernées :
sport-home,sport,casino,promotions - Priorité RICE : R=5 I=4 C=4 E=2 → score=40.0
- Action concrète :
Ajouter dans le footer SSR un bloc régulation visible sur toutes les routes, contenant : mention "Jeu réservé aux personnes âgées de TODO_age_legal_GN ans et plus", lien <a href="/jeu-responsable"> vers une page dédiée à créer, logo ou pictogramme "Jeu responsable" (à fournir par le régulateur ARSJPA ou créer un visuel sobre). En complément, ajouter en <head> la meta <meta name="rating" content="adult"> (signal historique mais encore parsé par Bing et Yahoo). Optionnellement, mention de l'âge sous forme propriété Schema.org dans Organization.audience.suggestedMinAge (cf R-SEO-01-02). La page /jeu-responsable doit lister les outils de modération (limites de dépôt, auto-exclusion, contact d'aide).
- Copy-ready :
Bloc footer (placeholder âge à confirmer Legal-check) : <div class="cg-footer-regulation"><p>Bet224 est un site de paris sportifs en ligne réservé aux personnes majeures. <a href="/jeu-responsable">Jouer comporte des risques : pertes financières, addiction. Consultez nos outils de jeu responsable.</a></p></div> Meta head : <meta name="rating" content="adult" /> Page /jeu-responsable (titre + structure h1/h2 copy-ready) à co-construire avec le client et Legal-check, hors scope reco SEO ici.
- Effort estimé : M
- Validation :
Re-crawl post-déploiement : grep "majeur|18 ans|TODO_age_legal_GN ans" sur les 4 raw HTML retourne ≥ 1 occurrence visible dans le footer SSR (pas seulement dans le bundle JS). Page /jeu-responsable retourne 200 (pas 404 comme actuellement, cf keywords-mapping bas du fichier). Cross-validation avec angle TRUST.
R-TRUST-01-07 : Ajouter conditions de mise (wagering) visibles above-fold sur chaque bannière promo + créer page T&C bonus dédiée
- Findings adressés : F-TRUST-01-13
- Routes concernées :
sport-home,sport,promotions - Priorité RICE : R=4 I=5 C=4 E=2 → score=40.0
- Action concrète :
(1) Réécrire les 3 visuels JPG des bannières hero (BPD_SPORT_1800X600_promotions.jpg, CASHBACK_1800X600_promos.jpg, MAXI BONUS) pour inclure une mention claire du wagering (ex. "Bonus jusqu'à 1 000 000 GNF, conditions de mise 30x avant retrait"). (2) Créer la page /bonus (soft 404 actuellement) avec T&C détaillés par bonus : montant max, dépôt minimum, wagering, plafond de gain, jeux exclus, durée de validité, méthodes de paiement éligibles. Pour chaque bonus une URL stable type /bonus/welcome-sport-1er-depot. (3) Cross-link depuis chaque bannière hero vers la page T&C du bonus correspondant (ex. CTA "Voir les conditions" pointant vers /bonus/welcome-sport-1er-depot#wagering).
- Copy-ready :
Wording mention wagering à intégrer dans chaque bannière (≤ 80 chars sous-titre) : "Bonus jusqu'à 1 000 000 GNF | Conditions de mise 30x | Dépôt min. 10 000 GNF" Squelette page /bonus/welcome-sport-1er-depot (h1 + structure) : <h1>Bonus de bienvenue sport : 100 % de votre 1er dépôt</h1> <dl> <dt>Bonus offert</dt><dd>100 % du montant de votre 1er dépôt, jusqu'à 1 000 000 GNF en Fun Bonus Sport.</dd> <dt>Dépôt minimum</dt><dd>[À COMPLÉTER] GNF</dd> <dt>Conditions de mise (wagering)</dt><dd>Le bonus doit être misé [À COMPLÉTER, ex. 30] fois sur des paris sportifs avec une cote minimum de [À COMPLÉTER, ex. 1.50] par sélection avant tout retrait.</dd> <dt>Durée de validité</dt><dd>[À COMPLÉTER, ex. 30 jours] à compter du 1er dépôt.</dd> <dt>Plafond de gain</dt><dd>[À COMPLÉTER, ex. 5 fois le montant du bonus].</dd> <dt>Jeux ou paris exclus</dt><dd>[À COMPLÉTER : ex. paris combinés < 1.50, casino, jeux virtuels].</dd> <dt>Mode de calcul du bonus</dt><dd>[À COMPLÉTER : ex. crédit immédiat sur le compte Fun Bonus séparé].</dd> </dl> <p>Conditions complètes : <a href="/cgu#bonus">CGU section Bonus</a>. Jouez avec modération : <a href="/jeu-responsable">Jeu responsable</a>.</p>
- Effort estimé : M
- Validation :
Inspection des screenshots re-crawl : chaque bannière hero doit afficher la mention wagering visible (lecteur humain à 100 % zoom). Re-crawl /bonus/welcome-sport-1er-depot : body page ≠ 404, word_count > 300, présence de "wagering" / "conditions de mise" / "dépôt minimum" / "plafond" dans le contenu. Test cross-link : clic "Voir les conditions" depuis bannière hero atteint la section ancre attendue.
R-A11Y-01-03 : Ajouter aria-label aux 8 boutons de carrousel casino
- Findings adressés : F-A11Y-01-03
- Routes concernées :
casino - Priorité RICE : R=3 I=5 C=5 E=2 → score=37.5
- Action concrète :
Dans le composant componenteGioco__navigatore, ajouter un aria-label dynamique sur chaque bouton avant / arrière. Le nom du groupe est connu (paramètre gamesGroup-N passé à scrollConBottone). Le fix patche un seul composant et corrige les 8 boutons (et tous les futurs carrousels du même composant).
- Copy-ready :
Bouton arrière : aria-label="Faire défiler la liste des jeux vers la gauche". Bouton avant : aria-label="Faire défiler la liste des jeux vers la droite". Si le nom du groupe est exploitable côté template, version plus précise : aria-label="Faire défiler les jeux Spribe vers la gauche" (et équivalents pour Top 10, Evolution, Top Providers, Amigo Gaming, à raccrocher au titre <h2> ou <h3> du carrousel parent).
- Effort estimé : S
- Validation :
Re-run axe-core sur casino : violations[].id == "button-name" retourne 0. Test clavier : tabuler dans la zone catalogue jeux annonce "Faire défiler ... gauche, bouton" sur chaque flèche.
R-A11Y-01-04 : Rendre les conteneurs de carrousel casino focusables au clavier
- Findings adressés : F-A11Y-01-12
- Routes concernées :
casino - Priorité RICE : R=3 I=5 C=5 E=2 → score=37.5
- Action concrète :
Sur les éléments .componenteGioco > .rowContainer et #swiper-wins-6 (et autres conteneurs Swiper customDragScroll), ajouter tabindex="0" + role="region" + aria-label descriptif. Vérifier que la navigation flèches gauche / droite au clavier déclenche bien le scroll. À combiner avec R-A11Y-01-03 (boutons nommés) pour un parcours clavier complet.
- Copy-ready :
Attributs à ajouter : tabindex="0" role="region" aria-label="Jeux Spribe, liste défilante" (et équivalents par titre de carrousel : "Top 10", "Évolution", "Top Providers", "Amigo Gaming", "Gains récents"). Adapter aria-label au titre <h2> ou <h3> parent visible.
- Effort estimé : M
- Validation :
Re-run axe-core sur casino : violations[].id == "scrollable-region-focusable" retourne 0. Test clavier : Tab atteint chaque carrousel, flèches font défiler.
R-MOBILE-01-05 : Étendre le scope V2 au funnel inscription / login / dépôt pour audit mobile dédié
- Findings adressés : F-MOBILE-01-04
- Routes concernées :
/inscription,/login,/depot,/retrait - Priorité RICE : R=5 I=5 C=4 E=3 → score=33.33
- Action concrète :
V2 audit : ajouter au include_patterns du crawl les routes /inscription, /login, /recover-psw (déjà présentes côté seo-audit dans seo-audit/.../bet224/crawl/html/ cf recoverpsw.raw.html), /depot si accessible sans auth ou crawl avec session de test fournie par le client. Pour chaque route, capturer screenshots desktop + mobile, run axe desktop + mobile, extraire forms[].fields[] dans conversion-signals/. Sub-agent DEEP-MOBILE-02 ou enrichissement DEEP-MOBILE-01 avec les findings forms mobile (types d'input, autocomplete, inputmode, taille des champs, gestion clavier mobile, password manager compatibility).
- Copy-ready :
N/A (action outillage / scope).
- Effort estimé : M
- Validation :
conversion-signals/index.json → aggregate.forms_total_all_routes > 0 ; routes /inscription, /login présentes dans crawl/index.json → pages[] ; sub-agent DEEP-MOBILE-02 ou pass 02 de DEEP-MOBILE-01 contient ≥ 3 findings sur les forms mobile.
R-PERF-01-02 : Différer (defer) ou async les 5 scripts JS bloquants en <head>
- Findings adressés : F-PERF-01-02
- Routes concernées :
all - Priorité RICE : R=5 I=5 C=4 E=3 → score=33.33
- Action concrète :
Pour chaque <script src=...> en <head> qui n'est PAS critique au first paint :
- Si la lib expose une API utilisée immédiatement par du code inline ultérieur dans le même
<head>: ne pas défer (jQuery 3.7.1 = probablement dans ce cas car beaucoup d'inline$(document).ready()suivent). - Si la lib est consommée uniquement après DOMContentLoaded : ajouter
defer(GSAP, SweetAlert, jsCookie tombent probablement ici). - Si la lib est analytics / non-critique : ajouter
async(équivalent àgtag.jsligne 15).
Auditer l'ordre des dépendances en lab avant rollout. Bonus : grouper les libs JS en un bundle webpack / esbuild (1 requête au lieu de 5).
- Copy-ready :
Markup cible (exemple) : ``html <script defer src="/js/desktop/third-party/jquery-3.7.1.min.js?v=20260304016"></script> <script defer src="/js/contogioco-services.js?v=20260304016"></script> <script defer src="/js/gsap.min.js?v=20260304016"></script> <script defer src="/js/sweetalert2.min.js?v=20260304016"></script> <script defer src="/js/jsCookie.min.js?v=20260304016"></script> ` Si jQuery est utilisé en inline avant DCL (probable), la solution est plus complexe : passer tout le code inline à un EventListener DOMContentLoaded`, OU charger jQuery seul en synchrone et tous les autres en defer.
- Effort estimé : M
- Validation :
Re-mesurer load_event_ms après rollout : doit baisser sensiblement sur les 4 routes. Idéalement, vérifier via PSI que le diagnostic "Eliminate render-blocking resources" passe d'un savings > 500 ms à < 100 ms.
R-PERF-01-03 : Ajouter loading="lazy", width, height, srcset aux 4 <img> template et aux vignettes casino
- Findings adressés : F-PERF-01-03, F-PERF-01-05
- Routes concernées :
all - Priorité RICE : R=5 I=4 C=5 E=3 → score=33.33
- Action concrète :
Pour les 4 <img> template (logo, ARSJPA, drapeaux) : ajouter width, height intrinsèques (mesurer une fois, hardcoder) + servir en WebP avec fallback PNG. Le logo header est above-the-fold donc reste eager (ne pas lazy-loader le LCP candidat) avec fetchpriority="high". Les drapeaux et ARSJPA sont below-the-fold : loading="lazy". Pour les vignettes casino : ajouter loading="lazy" dès le 2e carrousel offscreen, dimensions hardcodées, srcset avec variantes 1x 2x pour servir mobile en taille réduite.
- Copy-ready :
Markup cible logo header (above-the-fold, LCP candidat) : ``html <a href="/" aria-label="Bet224 - Retour à l'accueil"> <img src="https://www.bet224.gn/external_cms/GUINEA/img/logo-bet-224.png" alt="Bet224" width="120" height="40" fetchpriority="high"> </a> ` Markup cible drapeau langue (below-the-fold layout, mais petit) : `html <img src="/images/desktop/fr.png" alt="" role="presentation" width="24" height="16" loading="lazy"> ` Markup cible vignette casino (carrousel offscreen) : `html <img src="/path/to/game-thumb.webp" srcset="/path/to/game-thumb.webp 1x, /path/to/game-thumb@2x.webp 2x" alt="<nom du jeu>" width="180" height="120" loading="lazy"> ``
- Effort estimé : M
- Validation :
- Grep
loading="lazy"sur les 4 raw HTML : count > 0 (au moins 3 sur 4<img>template). - CLS p75 mesuré via CrUX (post-fix) : < 0.1.
- LCP image servie en WebP (vérifier réseau panel : Content-Type image/webp).
R-UX-01-08 : Ajouter un bloc Jeu Responsable persistant en footer + page dédiée
- Findings adressés : F-UX-01-11
- Routes concernées :
all - Priorité RICE : R=5 I=5 C=4 E=3 → score=33.33
- Action concrète :
(1) Ajouter dans le footer (cf R-UX-01-01) une 4e colonne "Jeu responsable" avec lien vers une page dédiée. (2) Créer une page /jeu-responsable exposant : message d'avertissement, outils d'auto-limitation (mise max, temps de session, auto-exclusion), contact d'aide local si identifié. (3) Afficher un picto + mention d'âge au-dessus du fold (à valider Legal-check pour le seuil exact ; placeholder "Réservé aux personnes majeures"). (4) Maintenir / valoriser le logo ARSJPA déjà présent dans le header (cf raw_html_sport_home ligne 389) en y ajoutant un alt et un lien vers https://arsjpa.gov.gn/.
- Copy-ready :
Bloc footer "Jeu responsable" (proposition à valider Legal-check) : <div class="col-md-3"> <h2 class="cg-footer-section-title">Jeu responsable</h2> <p><strong>Le jeu doit rester un loisir.</strong></p> <ul> <li><a href="/jeu-responsable">Conseils et outils</a></li> <li><a href="/auto-exclusion">Demander une auto-exclusion</a></li> <li>Réservé aux personnes majeures.</li> </ul></div> (la phrase "Réservé aux personnes majeures" évite de citer un âge non sourcé pour la Guinée ; à remplacer par "Interdit aux moins de XX ans" après Legal-check). Logo ARSJPA header : remplacer <img src="https://www.bet224.gn/external_css/GUINEA/img/ARSJPA.png"> par <a href="https://arsjpa.gov.gn/" target="_blank" rel="noopener" title="Autorité de Régulation du Secteur des Jeux et Pratiques Assimilées"> <img src="https://www.bet224.gn/external_css/GUINEA/img/ARSJPA.png" alt="ARSJPA, autorité de régulation des jeux en Guinée"></a>.
- Effort estimé : M
- Validation :
Re-run analyze_conversion_signals.py : detailed.trust_signals.legal_links_count doit passer de 2 à ≥ 4 (ajout 2 liens jeu responsable). Test manuel : sur les 4 routes, 1 lien "Jeu responsable" visible sans clic. Cross-référence à valider en [REF: DEEP-TRUST-01].
R-A11Y-01-05 : Corriger le contraste du bouton Betbuilder (1.3:1 vers ≥ 4.5:1)
- Findings adressés : F-A11Y-01-06
- Routes concernées :
sport - Priorité RICE : R=3 I=4 C=5 E=2 → score=30.0
- Action concrète :
Dans le CSS du composant .widgetFiltroSide__betBuilder, résoudre la collision entre bg-colore-1 et bianco qui force la couleur de texte à noir au lieu de blanc attendu. Vérifier la cascade : la classe bianco doit avoir suffisamment de spécificité, ou utiliser un sélecteur direct .widgetFiltroSide__betBuilder a { color: #ffffff; }. Cible : ratio ≥ 4.5:1 (blanc sur #212121 = 16.1:1, largement suffisant).
- Copy-ready :
Pas de copy à modifier (libellé "Betbuilder" conservé, conforme au site-context : pas d'incitation au jeu).
- Effort estimé : S
- Validation :
Re-run axe-core sur sport : violations[].id == "color-contrast" pour .widgetFiltroSide__betBuilder retourne 0. Inspection DevTools : color calculé = #ffffff.
R-CONV-01-07 : Remplacer le bandeau cookie consent passif par un consent granulaire RGPD-compliant
- Findings adressés : F-CONV-01-08
- Routes concernées :
all - Priorité RICE : R=5 I=3 C=4 E=2 → score=30.0
- Action concrète :
Implémenter une CMP (Consent Management Platform) qui propose au minimum 3 boutons clairs et de poids visuel équivalent : "Tout accepter", "Tout refuser", "Personnaliser". Granularité minimum 4 catégories : nécessaires, fonctionnels, analytics, profilage tiers. Stocker la preuve du consent côté serveur. Mettre à jour la politique de confidentialité (qui retourne actuellement 404 selon facts.to_confirm).
- Copy-ready :
Texte bandeau (≤200 chars) : "Nous utilisons des cookies pour faire fonctionner ce site, mesurer son audience et personnaliser les contenus. Vous pouvez accepter, refuser ou personnaliser votre choix." 3 boutons de poids équivalent : "Tout accepter" / "Tout refuser" / "Personnaliser" (≤2 mots chacun). Lien associé (sous les boutons) : "En savoir plus sur les cookies" (vers /cookies-policy).
- Effort estimé : M
- Validation :
Re-screenshot 4 routes : bandeau doit afficher 3 boutons (Accepter / Refuser / Personnaliser) de taille et couleur similaires (test visuel). En clavier, navigation Tab doit atteindre les 3 boutons. Re-crawl politique-confidentialite : status 200 attendu, plus 404.
R-MOBILE-01-03 : Étendre les touch targets JOUER et flèches carrousel au seuil 44x44 minimum
- Findings adressés : F-MOBILE-01-02
- Routes concernées :
casino,sport-home,sport,promotions - Priorité RICE : R=5 I=4 C=3 E=2 → score=30.0
- Action concrète :
Définir un design token --touch-target-min: 44px et l'appliquer à toutes les classes CTAs interactives. Pour les boutons "JOUER" du casino (80x22 actuel), augmenter min-height ou utiliser padding-top/bottom pour atteindre 44px sans déformer le visuel. Pour les flèches de carrousel .componenteGioco__navigatore__tasto (32x32 actuel), agrandir la zone tactile via padding: 6px (32+12=44) en gardant l'icône visuelle 32px. Pour le sélecteur de langue "FR" (45x16), élargir le bouton container. Tester sur viewport mobile 390x844 que les CTAs ajustés ne créent pas d'overflow horizontal.
- Copy-ready :
CSS tokens (à ajouter dans /css/desktop/base.jsp ou son équivalent mobile) : :root { --touch-target-min: 44px; } Class extension : .componenteGioco__navigatore__tasto { min-width: var(--touch-target-min); min-height: var(--touch-target-min); display: inline-flex; align-items: center; justify-content: center; } .casino-cta-jouer { min-height: var(--touch-target-min); padding: 11px 16px; } .flag-lang-button { min-height: var(--touch-target-min); display: inline-flex; align-items: center; padding: 14px 8px; }
- Effort estimé : M
- Validation :
V2 axe mobile sur les 4 routes : violations[].id = "target-size" doit retourner 0 occurrence. Mesure manuelle au DevTools : tous les boutons interactifs .componenteGioco__navigatore__tasto et .casino-cta-jouer doivent avoir une bbox ≥ 44x44px sur viewport 390x844.
R-SEO-01-05 : Corriger le canonical absent sur sport-home
- Findings adressés : F-SEO-01-05
- Routes concernées :
sport-home - Priorité RICE : R=2 I=3 C=5 E=1 → score=30.0
- Action concrète :
Ajouter dans le <head> du template sport-home un <link rel="canonical" href="https://www.bet224.gn/"> (ou https://www.bet224.gn/sport-home selon la décision SEO d'arbitrage entre racine et landing route). Arbitrage à trancher : si / redirige vers /sport-home en 301, alors canonical = /sport-home. Si / et /sport-home servent le même contenu sans redirect, canonical = / (URL plus courte, plus mémorable pour brand SERP).
- Copy-ready :
Si arbitrage racine canonique : <link rel="canonical" href="https://www.bet224.gn/" /> Si arbitrage landing route canonique : <link rel="canonical" href="https://www.bet224.gn/sport-home" />
- Effort estimé : S
- Validation :
Re-crawl : crawl/index.json pages[0].canonical = URL canonique choisie (non vide). Grep <link rel="canonical" sur raw_html_sport_home.raw.html retourne 1 occurrence.
R-UX-01-05 : Augmenter le menu principal de raccourcis "Football" et "Live"
- Findings adressés : F-UX-01-06
- Routes concernées :
all - Priorité RICE : R=5 I=3 C=4 E=2 → score=30.0
- Action concrète :
Ajouter dans <ul class="nav nav-tabs barra-menu menu-principale"> deux entrées de raccourci au-dessus de "Sports" : "Football" (lien vers /sport/football ou équivalent) et "Live" (lien direct vers https://www.bet224.gn/live.jsp, déjà cité dans cg_liveURL du JS). Cela évite à l'utilisateur 1-2 clics. Garder "Sports" / "Virtuel" / "Promo" / "Casino" derrière.
- Copy-ready :
Modification <ul class="nav nav-tabs barra-menu menu-principale"> : <li><a href="/sport/football" class="altro-principale pointer">Football</a></li> <li><a href="/live" class="altro-principale pointer">En direct</a></li> <li><a data-ref="sport" class="altro-principale pointer" href="/sport">Sports</a></li> <li><a id="plan-cg-h-virtual" data-buttonid="363" href="/virtuel" class="cg-link altro-principale pointer" target="_self">Virtuel</a></li> <li><a data-ref="promo" class="altro-principale pointer" href="/promotions">Promo</a></li> <li><a id="plan-cg-h-casino" data-buttonid="397" href="/casino" class="cg-link altro-principale pointer" target="_self">Casino</a></li> (à valider : la route /sport/football existe-t-elle ? Sinon créer un redirect ou utiliser /sport-home?sport=football).
- Effort estimé : S
- Validation :
Re-crawl puis tester : depuis /promotions, cliquer "En direct" doit mener directement à la page live (1 clic). Avant : 2 clics minimum.
Priorité MEDIUM (10 ≤ RICE < 30)
R-UI-01-01 : Réserver le rouge #b21116 aux CTAs primaires uniques et le vert #40b840 aux états de validation
- Findings adressés : F-UI-01-01
- Routes concernées :
all - Priorité RICE : R=5 I=4 C=4 E=3 → score=26.67
- Action concrète :
Définir un design token couleur unique pour le primary CTA (--color-cta-primary) appliqué au seul rôle "action de conversion principale" (Inscription, Déposer, Parier). Démoter Login en secondary CTA (fond transparent + border #b21116, ou outline-secondary style ghost). Réserver le vert #40b840 aux états positifs (validation, success message, cote favorable). Retirer le vert foncé #0e6634 du système (remplacer par #40b840 pour cohérence). Réécrire le badge #ff0000 en #b21116 pour aligner sur la brand color rouge unique.
- Copy-ready :
Tokens CSS à introduire (à placer dans :root du feuille CSS principal) : ``css :root { --color-cta-primary: #b21116; / Inscription, Déposer, Parier / --color-cta-secondary: transparent; / Login, Connexion (ghost btn) / --color-success: #40b840; / Validation, success / --color-danger: #b21116; / Erreur, suppression (alias primary, OK car contexte distinct) / --color-warning: #f6c800; / Alerte non bloquante, à valider design / } .btn-primary { background: var(--color-cta-primary); color: #ffffff; border: 1px solid var(--color-cta-primary); } .btn-secondary { background: var(--color-cta-secondary); color: var(--color-cta-primary); border: 1px solid var(--color-cta-primary); } ` Wording bouton Login alternatif si le ghost button reste visuellement faible : conserver Login` (action utilisateur déjà-acquis), positionner à droite du CTA Inscription en visuel secondaire.
- Effort estimé : M
- Validation :
Re-run analyze_design_system.py : aggregate.colors.background_top ne contient plus simultanément 3 couleurs CTA ayant le rôle "primary" sur les contextes ["[class*='btn']", "[role='button']", "a", "button"]. Inspection visuelle headers des 4 routes : un seul CTA visuellement primary par viewport, identifié comme l'action de conversion.
R-A11Y-01-09 : Remplacer le div sélecteur de langue par un button
- Findings adressés : F-A11Y-01-13
- Routes concernées :
all - Priorité RICE : R=5 I=2 C=5 E=2 → score=25.0
- Action concrète :
Transformer le <div id="plan-droplang"> en <button type="button" id="plan-droplang" aria-haspopup="true" aria-expanded="false">. Cela rend aria-expanded valide sémantiquement (autorisé sur button) et expose le contrôle au clavier. Vérifier que le JavaScript Bootstrap dropdown fonctionne sans <div data-toggle="dropdown"> ; sinon ajouter role="button" + handler clavier (Enter / Space) sur le <div> existant.
- Copy-ready :
Texte visible inchangé ("FR" + drapeau). Si fix par button : <button type="button" id="plan-droplang" class="blocco-header selettore-lingua dropdown" aria-haspopup="true" aria-expanded="false">FR ...</button>.
- Effort estimé : S
- Validation :
Re-run axe-core : violations[].id == "aria-allowed-attr" pour #droplang retourne 0. Test clavier : Tab atteint le sélecteur, Enter / Space ouvre le menu, Escape ferme.
R-PERF-01-06 : Repositionner GTM après les meta <title> et <viewport>
- Findings adressés : F-PERF-01-06
- Routes concernées :
all - Priorité RICE : R=5 I=1 C=5 E=1 → score=25.0
- Action concrète :
Déplacer le bloc GTM (script inline lignes 7-13 actuelles + tag noscript lignes 307-308) après <meta name="viewport"> et <title> dans le <head>. Conserver le pattern recommandé Google (haut de <head>, mais après les meta essentielles).
- Copy-ready :
Ordre cible des premières lignes de <head> : ``html <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>www.bet224.gn Guinee | Jouez en Ligne | Sport, Jeux Digitaux, Virtuel, Loto</title> <link rel="preconnect" href="https://www.googletagmanager.com" crossorigin> <!-- Google Tag Manager --> <script>(function(w,d,s,l,i){...})(window,document,'script','dataLayer','GTM-MZ7JZBPZ');</script> <!-- End GTM --> ... </head> ``
- Effort estimé : S
- Validation :
Inspection visuelle du <head> rendu : <title> apparaît avant le bloc GTM sur les 4 routes.
R-SEO-01-06 : Vendre un audit SEO + AI search approfondi via le projet seo-audit séparé
- Findings adressés : F-SEO-01-06
- Routes concernées :
all - Priorité RICE : R=5 I=4 C=5 E=4 → score=25.0
- Action concrète :
Proposer au client un audit SEO + AI search dédié via le projet seo-audit (livrable distinct, prestation séparée, périmètre élargi). Ce que cet audit produit ne couvre pas et que seo-audit couvrira : cartographie complète du link graph intra-site (in/out degree, pages orphelines, profondeur depuis home), audit des 9 gaps de pages identifiés dans keywords-mapping (jeu-responsable, mentions-légales, licence, cgu, privacy, a-propos, faq, bonus dédié, loto), mesure benchmarkée des citations LLM sur Perplexity / ChatGPT search / Gemini / Bing Copilot pour les 11 keywords primaires + 30+ secondaires, identification des AGG patterns (Answer Generation Gap = questions LLM sans réponse sur le site), analyse comparative concurrentielle (1xBet, Premier Bet, autres opérateurs Guinée), plan de contenu priorisé par volume × intent × concurrence, optimisations intra-linking.
- Copy-ready :
non applicable (recommandation commerciale, pas markup).
- Effort estimé : L
- Validation :
Client accepte ou refuse la prestation. Si accepté : ouvrir audit seo-audit dans Documents/growth/clients/seo-audit/toolkit/clients/bet224/ (déjà initialisé partiellement avec les raw HTML utilisés ici).
R-UI-01-02 : Introduire une échelle typographique modulaire de 6 niveaux (12 / 14 / 16 / 18 / 24 / 32 px)
- Findings adressés : F-UI-01-02
- Routes concernées :
all - Priorité RICE : R=5 I=3 C=5 E=3 → score=25.0
- Action concrète :
Définir 6 tokens font-size, du plus petit au plus grand, avec ratio 1.2-1.25 (échelle modulaire dite "Major Third" ou "Perfect Fourth") : --font-size-xs: 12px, --font-size-sm: 14px, --font-size-base: 16px, --font-size-md: 18px, --font-size-lg: 24px, --font-size-xl: 32px. Supprimer toutes les valeurs intermédiaires 10px, 10.5px, 12.5px, 12.6px, 13px, 14.4px, 15px. Imposer 12px comme taille minimale absolue (jamais en dessous) pour respecter ergonomie web et a11y. Remplacer 10px (147 occurrences mesurées) par 12px en priorité.
- Copy-ready :
Tokens CSS à placer dans :root : ``css :root { --font-size-xs: 12px; / caption, meta, labels secondaires / --font-size-sm: 14px; / body small, breadcrumb, footer / --font-size-base: 16px; / body default / --font-size-md: 18px; / H4, lead paragraph / --font-size-lg: 24px; / H2 / --font-size-xl: 32px; / H1 / } ` Pour la migration progressive, remplacer dans les CSS existants : 10px et 10.5px par var(--font-size-xs) (= 12px), 12.5px / 12.6px / 13px par var(--font-size-xs), 14.4px / 15px par var(--font-size-sm)`.
- Effort estimé : M
- Validation :
Re-run analyze_design_system.py : aggregate.typography.unique_font_size_count <= 6, aggregate.typography.font_sizes[].value ne contient plus que {"12px", "14px", "16px", "18px", "24px", "32px"} et aucune valeur sub-pixel.
R-UI-01-04 : Standardiser le border-radius sur 4 valeurs (0 / 4 / 8 / pill)
- Findings adressés : F-UI-01-04
- Routes concernées :
all - Priorité RICE : R=5 I=2 C=5 E=2 → score=25.0
- Action concrète :
Définir 4 tokens radius : --radius-none: 0px, --radius-sm: 4px, --radius-md: 8px, --radius-pill: 999px (suppression de 100% et 600px qui sont des doublons fonctionnels de 999px). Remplacer les 11 valeurs actuelles selon table de migration : 0px -> --radius-none, 2.5px, 3px, 4px, 5px, 6px -> --radius-sm (4px), 8px, 12px -> --radius-md (8px), 100%, 600px, 999px -> --radius-pill. Application différenciée : boutons CTA -> --radius-sm, cards -> --radius-md, avatars / chips circulaires -> --radius-pill.
- Copy-ready :
Tokens CSS à placer dans :root : ``css :root { --radius-none: 0px; --radius-sm: 4px; / boutons, inputs, tags / --radius-md: 8px; / cards, panels, modals / --radius-pill: 999px; / avatars, chips, badges circulaires / } .btn { border-radius: var(--radius-sm); } .card { border-radius: var(--radius-md); } .avatar, .chip-pill { border-radius: var(--radius-pill); } ``
- Effort estimé : M
- Validation :
Re-run analyze_design_system.py : aggregate.borders.border_radius[] ne contient plus que 4 valeurs maximum (0px, 4px, 8px, 999px), pas de sub-pixel, pas de 100%, pas de 600px.
R-UI-01-08 : Personnaliser le bandeau cookies aux couleurs de la charte
- Findings adressés : F-UI-01-09
- Routes concernées :
all (bandeau global,template header) - Priorité RICE : R=5 I=2 C=5 E=2 → score=25.0
- Action concrète :
Identifier le widget CMP cookies (probablement une lib JS tierce). Appliquer un override CSS qui force le fond, le texte, les boutons à utiliser les tokens du design system. Fond du banner : var(--color-background-alt) (= #f6f6f6 recommandé, ou un noir brand #1a1a1a si on veut conserver le contraste fort), texte #212529, bouton OK = var(--color-cta-primary) (= #b21116), bouton Plus d'informations = secondary (ghost button rouge contour). Test que le widget garde son comportement fonctionnel (consent / refus) après l'override.
- Copy-ready :
CSS override (à placer dans une feuille cookies-banner-override.css chargée après le CSS du widget tiers) : ``css #cg-barra-cookies, .cookies-banner, [class*='cookie-banner'] { background: #1a1a1a !important; color: #ffffff !important; box-shadow: var(--shadow-md); } #cg-barra-cookies a, .cookies-banner a { color: #ffffff !important; text-decoration: underline; } #cg-barra-cookies .btn-accept, .cookies-banner .btn-accept { background: var(--color-cta-primary) !important; color: #ffffff !important; border-radius: var(--radius-sm); } #cg-barra-cookies .btn-more-info, .cookies-banner .btn-more-info { background: transparent !important; color: #ffffff !important; border: 1px solid #ffffff; border-radius: var(--radius-sm); } `` Conserver le wording légal du banner intact tant que le red team Legal-check n'a pas confirmé le cadre data Guinée (cf cross-angle TRUST).
- Effort estimé : S
- Validation :
Re-run analyze_design_system.py : aggregate.colors.background_top ne contient plus rgb(46, 97, 232) (bleu Bootstrap) ni rgb(128, 128, 128) (gris neutre html) en contexte banner. Inspection visuelle screenshots des 4 routes : bandeau cookies utilise le rouge brand #b21116 pour le CTA accept.
R-UX-01-10 : Aligner le vocabulaire de l'interface en français cohérent
- Findings adressés : F-UX-01-10, F-UX-01-01
- Routes concernées :
all - Priorité RICE : R=5 I=2 C=5 E=2 → score=25.0
- Action concrète :
Remplacer Login par Connexion, OUVRIR PIED DE PAGE par Mentions légales (si le composant est gardé après R-UX-01-01) ou supprimer (si R-UX-01-01 appliquée), Registration par Inscription dans le footer. Traduire le toast Click HERE to get started... en français. Garder le markup BEM italien (componenteGioco, etc.) inchangé : c'est de la classe CSS interne, invisible.
- Copy-ready :
Mapping de remplacement (à appliquer en lot) :
<a onclick="cg_login()" class="bottone bottone-login">Login</a>-><a onclick="cg_login()" class="bottone bottone-login">Connexion</a><a class="cg-ext-link pointer" onclick="cg_newAccount(true)">Registration</a>-><a class="cg-ext-link pointer" onclick="cg_newAccount(true)">Inscription</a><div class="cg-toast-desc-content">Click <span>HERE</span> to get started or <span>HERE</span> to never show this again</div>-><div class="cg-toast-desc-content">Cliquez <span>ICI</span> pour configurer votre compte, ou <span>ICI</span> pour ne plus afficher ce message.</div>- Effort estimé : S
- Validation :
Grep dans les templates HTML : Login|Registration|Click HERE|OUVRIR PIED DE PAGE retourne 0 hit (sauf si OUVRIR PIED DE PAGE est supprimé par R-UX-01-01).
R-CONV-01-03 : Supprimer ou re-cadrer le widget "Gains récents" casino
- Findings adressés : F-CONV-01-03
- Routes concernées :
casino - Priorité RICE : R=3 I=4 C=4 E=2 → score=24.0
- Action concrète :
Option 1 (recommandée) : supprimer entièrement le widget "Gains récents" du haut de la page casino, le remplacer par une grille de jeux thématique (ex : "Jeux populaires cette semaine" sans montants). Option 2 (compromis) : conserver le widget mais (a) afficher montants en intervalles ("gain entre 10 000 et 100 000 GNF" sans précision sur identités), (b) ajouter une mention claire "Échantillon des dernières 24h, les gains varient et ne sont pas garantis", (c) afficher également les pertes statistiques ("85 % des sessions sont perdantes" ou équivalent factuel sourcé par les données opérateur), pour rétablir la symétrie cognitive.
- Copy-ready :
Option 1 (titre de remplacement, 60 chars) : "Jeux populaires sur Bet224 cette semaine". Option 2 (disclaimer à coller sous le widget, 130 chars) : "Sélection des derniers gains. Les résultats varient et ne sont pas garantis. Voir les conditions de jeu et la politique du jeu responsable." (avec lien vers /jeu-responsable).
- Effort estimé : S
- Validation :
Re-screenshot casino : zone (y < 200) ne doit plus afficher de montants GNF spécifiques sans disclaimer. Si option 2 retenue, le disclaimer doit être lisible (font-size ≥ 14px, contraste ≥ 4.5:1).
R-MOBILE-01-02 : Supprimer maximum-scale=1 du viewport meta injecté par le SDK casino
- Findings adressés : F-MOBILE-01-01
- Routes concernées :
casino - Priorité RICE : R=4 I=3 C=4 E=2 → score=24.0
- Action concrète :
Option 1 (préférée) : identifier le SDK casino tiers (probablement Microgame / Playtech / NetEnt aggregator vu les noms "Spribe Games", "Top Providers", "Amigo Gaming" sur la capture casino) et demander à l'éditeur de retirer maximum-scale=1 du viewport injecté. Option 2 (palliatif client-side) : ajouter en pied de page un script MutationObserver qui surveille les insertions <meta name="viewport"> après chargement et corrige la valeur. Pattern : observer document.head, sur ajout de meta[name="viewport"], si content inclut maximum-scale=1, le réécrire en width=device-width, initial-scale=1. Voir exemple copy-ready.
- Copy-ready :
JavaScript palliatif (à placer en fin de <body>) : <script>(function(){var obs=new MutationObserver(function(muts){muts.forEach(function(m){m.addedNodes.forEach(function(n){if(n.nodeType===1&&n.tagName==='META'&&n.getAttribute('name')==='viewport'&&n.getAttribute('content').indexOf('maximum-scale=1')!==-1){n.setAttribute('content','width=device-width, initial-scale=1');}});});});obs.observe(document.head,{childList:true,subtree:false});})();</script>
- Effort estimé : S
- Validation :
Re-run axe-core sur /casino mobile : violations[].id = "meta-viewport" doit avoir disparu. Test manuel iOS Safari + Android Chrome : pincer-zoomer sur /casino doit fonctionner (zoom appliqué visible).
R-A11Y-01-06 : Corriger le contraste du filtre Sport des promotions (2.6:1 vers ≥ 4.5:1)
- Findings adressés : F-A11Y-01-07
- Routes concernées :
promotions - Priorité RICE : R=3 I=3 C=5 E=2 → score=22.5
- Action concrète :
Modifier la couleur de fond du filtre actif .bottone-filtro quand filtro-dati="2" (Sport) : soit assombrir le vert à #5e7d1f (ratio blanc 4.51:1), soit basculer la couleur du texte sur du noir sur le vert clair existant (#000 sur #83ae30 = 9.4:1, OK). Décision design : préférer assombrir le vert pour cohérence avec le reste de la charte (à valider avec angle UI / brand guidelines).
- Copy-ready :
Pas de copy à modifier (libellés des filtres conservés).
- Effort estimé : S
- Validation :
Re-run axe-core sur promotions : violations[].id == "color-contrast" retourne 0. Vérifier les autres états (hover, focus) tous les filtres.
R-TRUST-01-10 : Traduire ou supprimer les chaînes italiennes hard-codées dans les labels JSON pour cohérence localisation GN
- Findings adressés : F-TRUST-01-12
- Routes concernées :
all - Priorité RICE : R=3 I=3 C=5 E=2 → score=22.5
- Action concrète :
(1) Extraire toutes les chaînes italiennes du fichier cg_LABEL (sport-home.raw.html ligne 250, équivalent dans toutes les pages). (2) Identifier celles qui sont en italien et non traduites. (3) Faire traduire en français par un traducteur français/italien. (4) Remplacer les chaînes hard-codées par leurs équivalents français dans le fichier localisé GN. (5) Identifier les chaînes qui référencent le régulateur italien (ADM, RUA, Anagrafe dei Conti) et les remplacer par les équivalents guinéens (ARSJPA, registre auto-exclusion GN si existant, à clarifier Legal-check) OU les supprimer si le concept ne s'applique pas en GN.
- Copy-ready :
Exemple de remplacement pour la chaîne exclusion.determ : Avant : "exclusion.determ":"Ti ricordiamo che in caso di autoesclusione, il Concessionario sarà tenuto a comunicare tale volontà all\\'Anagrafe dei Conti di Gioco, gestita dall\\'ADM, inserendoti nel Registro Unico degli Autoesclusi (RUA) e per te sarà impossibile accedere al gioco per il periodo di autoesclusione da tutti i conti gioco di cui sei titolare, anche se attivati con un altro Concessionario." Après (français adapté GN, à valider Legal-check pour le mécanisme exact de registre auto-exclusion GN) : "exclusion.determ":"Nous vous rappelons qu'en cas d'auto-exclusion, Bet224 [communique cette volonté à l'ARSJPA / au registre national d'auto-exclusion si existant en GN, à valider Legal-check]. Il vous sera impossible d'accéder au jeu pendant la durée de l'auto-exclusion choisie." Exemple chaîne header.disclaimer : Avant : "header.disclaimer":"Il gioco è vietato ai minori di diciotto anni..." (italien, mention âge italien) Après : "header.disclaimer":"L'accès à Bet224 est interdit aux mineurs (âge légal [SEUIL] ans en Guinée). Le jeu d'argent peut entraîner une dépendance. Jouez avec modération." (français, seuil à confirmer)
- Effort estimé : M
- Validation :
Grep sur les pages re-crawlées : aucune chaîne italienne residuelle dans cg_LABEL (mots-clés "Concessionario", "Anagrafe", "ADM", "diciotto", "gioco" en valeur). Test parcours utilisateur inscrit : aucune popup ou écran ne doit afficher de texte italien.
R-A11Y-01-12 : Ajouter un H1 unique et signifiant sur chaque route
- Findings adressés : F-A11Y-01-08
- Routes concernées :
all - Priorité RICE : R=5 I=2 C=4 E=2 → score=20.0
- Action concrète :
Ajouter un <h1> en haut de chaque route, intégré au layout, contenant le sujet de la page. Sur les routes catalogue (sport, casino, promotions), le H1 peut être visuellement discret (classe sr-only si pas désiré dans le design) mais doit être présent dans le DOM.
- Copy-ready :
Propositions copy-ready (ton sobre, sans incitation, conforme site-context.yaml) :
sport-home:<h1>Paris sportifs en ligne - Bet224 Guinée</h1>sport:<h1>Catalogue des compétitions sportives - Bet224</h1>casino:<h1>Catalogue des jeux de casino - Bet224</h1>promotions:<h1>Promotions et bonus - Bet224</h1>
À ne pas appliquer en l'état si le red team Legal-check identifie un wording contraint par la réglementation guinéenne (cf Limites).
- Effort estimé : S
- Validation :
Re-run axe-core : violations[].id == "page-has-heading-one" retourne 0 sur les 4 routes.
R-UX-01-04 : Restructurer le bandeau cookies en bandeau de consentement granulaire avec option "Refuser"
- Findings adressés : F-UX-01-03
- Routes concernées :
all - Priorité RICE : R=5 I=3 C=4 E=3 → score=20.0
- Action concrète :
Remplacer le bandeau actuel par un composant : (1) wording neutre sans "consentement par poursuite", (2) trois boutons "Accepter tout", "Refuser tout", "Personnaliser", (3) modal "Personnaliser" qui permet d'activer / désactiver les catégories (essentiels obligatoires, mesure d'audience, profilage), (4) une page Cookies en HTML (pas un PDF) accessible depuis le footer. Stocker le choix en cookie technique 12 mois.
- Copy-ready :
Wording bandeau : <div id="plan-cg-barra-cookies" role="dialog" aria-label="Préférences cookies"> <p>Nous utilisons des cookies pour faire fonctionner ce site, mesurer son audience et personnaliser certains contenus. Vous pouvez accepter, refuser ou choisir le détail.</p> <div class="cg-cookies-actions"> <button class="cg-cookies-refuse">Refuser tout</button> <button class="cg-cookies-customize">Personnaliser</button> <button class="cg-cookies-ok">Accepter tout</button> <a class="cg-cookies-more-info" href="/cookies">En savoir plus</a> </div></div>. Page Cookies : créer /cookies (HTML) reprenant le contenu du PDF actuel external_cms/pdf/Cookies_Policy.pdf, en français, structurée avec H1 "Politique des cookies" et sections par catégorie.
- Effort estimé : L
- Validation :
Test manuel : 3 boutons visibles, modal Personnaliser fonctionnelle, choix mémorisé sur 12 mois. Re-run analyze_conversion_signals.py après cliquer "Refuser" : le bandeau ne réapparaît pas pendant 12 mois. Test mobile (à instrumenter) : le bandeau reste lisible sur 390px.
R-UI-01-06 : Introduire 3 niveaux d'élévation (card flat / card raised / popover) via box-shadow
- Findings adressés : F-UI-01-06, F-UI-01-08
- Routes concernées :
all (priorité casino,sport,promotions) - Priorité RICE : R=4 I=3 C=4 E=3 → score=16.0
- Action concrète :
Définir 3 tokens shadow couvrant les niveaux d'élévation usuels : --shadow-flat: none (base, blocs passifs), --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.1) (cards interactives au repos), --shadow-md: 0 4px 8px rgba(0, 0, 0, 0.15) (cards hover, popovers, dropdowns). Appliquer --shadow-sm aux cards des routes denses (Spribe Games casino, Promo cards, Tournois à la une sport-home). Appliquer --shadow-md sur hover des cards casino et sur le ticket sport (panel droit). Le bandeau cookies doit recevoir --shadow-md pour marquer son statut de message intrusif distinct du chrome.
- Copy-ready :
Tokens CSS à placer dans :root : ``css :root { --shadow-flat: none; --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.1); --shadow-md: 0 4px 8px rgba(0, 0, 0, 0.15); } .card { box-shadow: var(--shadow-sm); transition: box-shadow 0.2s ease; } .card:hover { box-shadow: var(--shadow-md); } .cookies-banner { box-shadow: var(--shadow-md); } ``
- Effort estimé : M
- Validation :
Re-run analyze_design_system.py : aggregate.effects.box_shadows[].value contient au minimum les 3 valeurs déclarées (none, 0 1px 2px rgba(0, 0, 0, 0.1), 0 4px 8px rgba(0, 0, 0, 0.15)) avec des counts > 0 sur des contextes [class*='card'], [class*='button'].
R-A11Y-01-13 : Englober les zones du header dans des landmarks sémantiques
- Findings adressés : F-A11Y-01-10
- Routes concernées :
all - Priorité RICE : R=5 I=2 C=4 E=3 → score=13.33
- Action concrète :
Restructurer le markup du header pour englober les zones info-utili, disclaimer, cg-barra-cookies, col-lg-3 (logo), bottoni-login dans des landmarks. Solutions canoniques : un <header role="banner"> global qui contient le tout, et un <nav aria-label="Connexion"> autour de bottoni-login. Le banner cookies devrait être un <aside role="region" aria-label="Information sur les cookies"> ou idéalement un <div role="dialog"> selon UX désirée.
- Copy-ready :
Structure cible : <header role="banner"> (englobant .info-utili, .disclaimer, .col-lg-3), <nav aria-label="Compte utilisateur"> (englobant .bottoni-login), <aside role="region" aria-label="Cookies"> (englobant #cg-barra-cookies).
- Effort estimé : M
- Validation :
Re-run axe-core : violations[].id == "region" retourne 0 ou ne contient plus que des nodes de cas particuliers à arbitrer.
R-MOBILE-01-04 : Arbitrer l'architecture responsive (UA-sniffing vs responsive design)
- Findings adressés : F-MOBILE-01-03
- Routes concernées :
all - Priorité RICE : R=5 I=4 C=3 E=5 → score=12.0
- Action concrète :
Étape 1 (POC V2 audit, semaines 1-2) : recrawler les 4 routes en UA mobile (User-Agent iPhone Safari iOS 17) pour confirmer si le backend sert un HTML/CSS distinct (architecture UA-sniffing) ou la même structure responsive. Comparer les raw HTML mobile vs desktop pour mesurer la divergence. Étape 2 (décision direction, semaine 3) : arbitrer entre maintenir UA-sniffing (palliatifs ciblés, audit mobile dédié) ou planifier migration responsive design (chantier multi-trimestres). Étape 3 (livrable plan-action) : si décision migration, produire roadmap responsive avec budget effort et risques (rupture SEO, A/B test pendant transition, rollback).
- Copy-ready :
N/A (action stratégique, pas rédactionnelle).
- Effort estimé : L
- Validation :
Document interne _subagent-outputs/DEEP-MOBILE-02-arch.md (V2 audit) avec diff serveur HTML mobile vs desktop sourcé sur raw HTML capturés, et recommandation argumentée (responsive vs UA-sniffing) avec coût/bénéfice quantifié.
R-PERF-01-05 : Concaténer / minifier les 6 stylesheets en 1-2 fichiers ou utiliser HTTP/2 push / Early Hints
- Findings adressés : F-PERF-01-01
- Routes concernées :
all - Priorité RICE : R=5 I=3 C=3 E=4 → score=11.25
- Action concrète :
Trois pistes selon contraintes :
- Si HTTP/2 / HTTP/3 actif sur bet224.gn (à vérifier avec
curl -I --http2ou via DevTools Protocol column) : l'impact multi-fichier est déjà fortement réduit, prioriser plutôt l'inline du CSS critique above-the-fold + defer du reste. - Bundler les 4 first-party (
base.jsp,default_contogioco_desktop.css,adeguamento.css,toast.css) en 1 fichierbet224-bundle.cssau build, servi avec cache long. - Garder bootstrap.min.css + fontawesome séparés car cachables long-terme inter-pages, ajouter
<link rel="preload" as="style">pour parallélisation.
- Copy-ready :
Vérification HTTP/2 : `` curl -I --http2 https://www.bet224.gn/sport-home ` Le header HTTP/2 200` confirme HTTP/2. Si présent, prioriser piste 1.
- Effort estimé : L
- Validation :
PSI diagnostic "Reduce unused CSS" et "Eliminate render-blocking resources" : savings doit baisser de > 50 % vs baseline.
R-UI-01-07 : Refonte du logo Bet224 sur une seule couleur brand (rouge #b21116 ou monochrome)
- Findings adressés : F-UI-01-07
- Routes concernées :
all (template header commun) - Priorité RICE : R=5 I=3 C=3 E=4 → score=11.25
- Action concrète :
Refondre le logo Bet224 en un seul ton, idéalement le rouge brand #b21116 (pour l'aligner sur le primary CTA, cohérent avec R-UI-01-01) ou en monochrome noir pour neutralité maximale. Conserver l'italique des chiffres 224 si c'est un parti graphique assumé par le client. Décliner le logo en versions : color (header light), inverse (header dark / pied de page sombre), monochrome (favicon, mentions). Demander au client si une charte logo officielle existe ailleurs ; sinon proposer la refonte comme reco brand. À soumettre à validation client avant implémentation.
- Copy-ready :
Pas de copy littéraire à modifier (le wordmark reste Bet224). Brief asset à fournir au designer (à utiliser tel quel dans la commande) : > Refonte du logo Bet224 : wordmark monochrome rouge #b21116, typographie sans-serif gras italique sur les chiffres 224, casing strict Bet224 (jamais BET224, bet224, Bet 224, bet-224). Décliner en 3 variantes : light bg (#b21116 sur fond clair), dark bg (#ffffff sur fond foncé), favicon 32x32. Exporter en SVG + PNG @1x @2x @3x. Source de naming et formes interdites : site-context.yaml brand.forms_to_avoid.
- Effort estimé : L
- Validation :
Inspection visuelle : le logo dans screenshots/sport-home/desktop.png zone x=15-145, y=35-70 utilise une seule couleur brand. Le fichier external_cms/GUINEA/img/logo-bet-224.png a été remplacé par un SVG monochrome (vérifier via DOM <img src=...> ou <svg>). Cohérence chromatique avec les CTAs primaires (R-UI-01-01).
R-UX-01-06 : Page Promotions, ajouter un récap textuel sous chaque card et harmoniser le wording bonus
- Findings adressés : F-UX-01-07
- Routes concernées :
promotions - Priorité RICE : R=2 I=4 C=4 E=3 → score=10.67
- Action concrète :
(1) Ajouter sous chaque card promo un mini-récap textuel (3-5 lignes) : montant maximum du bonus, conditions de mise (wagering), durée de validité, sports éligibles, lien vers les conditions complètes. (2) Réécrire le titre du visuel principal pour retirer la promesse de gain (AUGMENTE TES GAINS est interdit selon site-context). (3) Renommer les CTA "EN SAVOIR PLUS" en libellé d'action explicite ("Voir les conditions").
- Copy-ready :
Titre visuel principal (à refaire avec design) : remplacer "MAXI BONUS, AUGMENTE TES GAINS JUSQU'À 500 %" par Bonus de bienvenue, jusqu'à 100 % sur votre premier dépôt. (Le pourcentage exact doit refléter l'offre réelle, à confirmer client ; éviter 500 % qui suggère un gain démesuré, formulation factuelle à privilégier.) Récap sous chaque card (template) : <div class="promo-recap"> <p><strong>Bonus maximum :</strong> 1 000 000 GNF.</p> <p><strong>Conditions de mise :</strong> Mises × N à effectuer sur des paris sportifs avant retrait (cote minimum X, sports éligibles : football, basket).</p> <p><strong>Validité :</strong> 30 jours après activation.</p> <p><a href="/promotions/welcome-sport/conditions">Voir toutes les conditions</a></p></div> (N, X et les sports exacts à obtenir du client, copy-ready paramétré). CTA card : remplacer <button>EN SAVOIR PLUS</button> par <a href="/promotions/welcome-sport/conditions">Voir les conditions</a> (action explicite, pas "savoir plus" vague).
- Effort estimé : M
- Validation :
Re-crawl /promotions : pages[3].word_count doit passer d'environ 108 à au moins 400 mots (présence du récap). Vérifier que OUVRIR PIED DE PAGE n'est plus le primary_cta (résolu via R-UX-01-01). Test manuel : 3 cards comparables sans cliquer "EN SAVOIR PLUS".
R-UI-01-05 : Définir une échelle de spacing modulaire 4-base et purger les sub-pixel
- Findings adressés : F-UI-01-05
- Routes concernées :
all - Priorité RICE : R=5 I=2 C=4 E=4 → score=10.0
- Action concrète :
Définir 8 tokens spacing en multiples de 4 : --space-0: 0px, --space-1: 4px, --space-2: 8px, --space-3: 12px, --space-4: 16px, --space-5: 20px, --space-6: 24px, --space-8: 32px. Migrer toutes les valeurs sub-pixel et hors-échelle vers la valeur 4-base la plus proche (table de migration : 1.5px / 1.8px / 2.5px / 3px / 3.75px / 4.5px -> 4px, 5px / 6px / 7.5px -> 8px, 9px / 10px -> 8px ou 12px selon contexte, 15px -> 16px, 17.5px -> 16px, 19.3594px -> 20px). Supprimer les classes utilitaires Bootstrap qui produisent du sub-pixel (.p-1 à 0.25rem donne du sub-pixel si font-size héritée n'est pas 16px).
- Copy-ready :
Tokens CSS à placer dans :root : ``css :root { --space-0: 0px; --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px; --space-5: 20px; --space-6: 24px; --space-8: 32px; } `` Migration progressive : convertir d'abord les composants atomiques (boutons, inputs) puis les molécules (cards, nav items).
- Effort estimé : L
- Validation :
Re-run analyze_design_system.py : aggregate.spacing.padding_top[].value, padding_right, padding_bottom, padding_left ne contiennent plus que des multiples de 4 px. Aucune valeur sub-pixel. Nombre de valeurs uniques par axe spacing <= 8.
Priorité LOW (RICE < 10 ou non scoré)
R-CONV-01-05 : Réduire la densité de boutons "JOUER" sur casino, ajouter alternatives (démo, info jeu)
- Findings adressés : F-CONV-01-05
- Routes concernées :
casino - Priorité RICE : R=3 I=3 C=3 E=3 → score=9.0
- Action concrète :
Sur chaque card de jeu, remplacer le bouton "JOUER" unique par un dual-CTA : (1) un bouton primaire "Démo gratuite" (sans dépôt) et (2) un bouton secondaire "Jouer en réel" (qui ouvre le jeu mode argent réel après éventuel rappel des limites du joueur si connecté). Ajouter au survol une mini-tooltip avec RTP (Return To Player) du jeu et lien "À propos de ce jeu".
- Copy-ready :
CTA primaire card (1-4 mots) : "Démo gratuite". CTA secondaire card (1-4 mots) : "Jouer en réel". Tooltip RTP (≤80 chars) : "Taux de retour joueur : XX %. Voir les règles et limites du jeu." (XX à remplir par card).
- Effort estimé : M
- Validation :
Re-crawl casino, conversion-signals/casino.json → moins de 21 boutons portant le même texte "JOUER" (mesure : compter occurrences distinctes du detailed.ctas[].text). Diversification mesurable (au moins 2 textes distincts par card : "Démo gratuite" et "Jouer en réel").
R-UI-01-09 : Limiter la densité chromatique des cards de jeux casino (uniformisation backgrounds Spribe Games)
- Findings adressés : F-UI-01-08
- Routes concernées :
casino - Priorité RICE : R=3 I=3 C=3 E=3 → score=9.0
- Action concrète :
Sur le carrousel Spribe Games (et par extension Amigo Gaming), uniformiser le fond des cards à un noir profond (#0d0d0d) ou un blanc (#ffffff) avec uniquement le logo / illustration du jeu en couleur. Conserver la spécificité visuelle de chaque jeu via l'illustration (image PNG ou SVG centrale) plutôt que via la couleur de fond. Ajouter --shadow-sm (cf R-UI-01-06) pour l'élévation et un border-radius --radius-md (cf R-UI-01-04). Effet : cognitif load réduit, hiérarchie plus lisible, et l'utilisateur scanne par illustration (familier des marques) plutôt que par couleur saturée.
- Copy-ready :
Pas de copy textuel à modifier. CSS guideline cards (à placer dans casino.css) : ``css .card-game-spribe, .card-game-amigo { background: #0d0d0d; border-radius: var(--radius-md); box-shadow: var(--shadow-sm); padding: var(--space-3); } .card-game-spribe .game-illustration, .card-game-amigo .game-illustration { width: 100%; height: auto; } ``
- Effort estimé : L
- Validation :
Re-run analyze_design_system.py sur casino : per_route[2].unique_background_colors <= 5 (vs 9 mesurés actuellement). Inspection visuelle screenshots/casino/desktop.png : carrousel Spribe Games uniformisé.
R-A11Y-01-11 : Restructurer l'architecture des landmarks main
- Findings adressés : F-A11Y-01-09
- Routes concernées :
sport-home,sport,casino - Priorité RICE : R=3 I=2 C=4 E=3 → score=8.0
- Action concrète :
Identifier dans le template le pattern qui injecte deux <main> (probablement un wrapping SPA #cg_exa-sportAppContainer ou #panel qui contient son propre <main> alors que le layout parent en a déjà un). Décision : garder un seul <main> (le plus extérieur) + transformer le second en <section aria-label="..."> ou <div> selon contexte. Promotions étant déjà OK, étudier son template comme référence.
- Copy-ready :
Si le wrapping intérieur sert de zone applicative distincte : <section aria-label="Catalogue des paris" id="plan-panel"> (pour sport), <section aria-label="Catalogue casino" id="plan-panel"> (pour casino).
- Effort estimé : M
- Validation :
Re-run axe-core sur sport-home, sport, casino : violations[].id ne contient plus landmark-no-duplicate-main, landmark-main-is-top-level, landmark-unique.
R-A11Y-01-14 : Corriger le rôle tablist mal employé sur accordion sport
- Findings adressés : F-A11Y-01-14
- Routes concernées :
sport - Priorité RICE : R=2 I=3 C=4 E=3 → score=8.0
- Action concrète :
Sur #accordionLaterale : soit transformer en vrai tablist avec enfants role="tab" + zones role="tabpanel" + gestion clavier (flèches gauche / droite), soit retirer role="tablist" + aria-multiselectable et utiliser le pattern accordion ARIA (chaque header = <button aria-expanded="false" aria-controls="...">). La deuxième option est la plus simple et la plus appropriée pour un accordion de compétitions.
- Copy-ready :
Si pattern accordion : retirer role="tablist" et aria-multiselectable="true", remplacer chaque <a tabindex="0"> enfant par <button aria-expanded="false" aria-controls="competition-{n}">Nom de la compétition</button> suivi de <div id="plan-competition-{n}" role="region" aria-labelledby="trigger-{n}">[...contenus]</div>.
- Effort estimé : M
- Validation :
Re-run axe-core sur sport : violations[].id == "aria-required-children" retourne 0. Test clavier : navigation tab + Enter / Space ouvre chaque compétition.
R-UX-01-09 : Sport, contextualiser la sidebar Betbuilder avec une mini-explication
- Findings adressés : F-UX-01-09
- Routes concernées :
sport - Priorité RICE : R=2 I=2 C=4 E=2 → score=8.0
- Action concrète :
Sous le bandeau "BETBUILDER" dans la sidebar gauche, ajouter une mini-explication textuelle (1 phrase) + un lien "Comment ça marche" qui ouvre une modale ou redirige vers une page tutoriel.
- Copy-ready :
Wrapping HTML proposé : <a data-toggle="..." class="pointer bg-colore-1 bianco margine-giu" style="..."><strong>Betbuilder</strong></a><p class="sidebar-help">Combinez plusieurs paris sur un même match. <a href="/aide/betbuilder">Comment ça marche ?</a></p>. (Le ratio de contraste actuel sur le bandeau Betbuilder est insuffisant et fait l'objet d'un finding A11Y séparé [REF: DEEP-A11Y-01].)
- Effort estimé : S
- Validation :
Test manuel : un visiteur sans connaissance préalable peut lire "Combinez plusieurs paris sur un même match" sans interaction.
R-UX-01-07 : Casino, réduire la densité above-fold à 1 carrousel vedette + entrée par catégorie
- Findings adressés : F-UX-01-08
- Routes concernées :
casino - Priorité RICE : R=2 I=4 C=3 E=4 → score=6.0
- Action concrète :
Refondre l'above-fold casino : retirer le carrousel "Gains récents" (gains supposés ; cf forbidden_pattern), garder 1 carrousel vedette (par ex. "Sélection éditoriale") + tabs par catégorie (Slots, Live Casino, Jeux instantanés) au-dessus de la fold. Repousser les autres carrousels en dessous, accessibles par scroll ou tabs cliqués. Ajouter un titre H1 unique (cf R-UX-01-02).
- Copy-ready :
Wrapping above-fold (proposition) : <main id="plan-panel"> <h1>Jeux de casino en ligne</h1> <nav role="tablist" aria-label="Catégories de jeux"> <button role="tab" aria-selected="true" aria-controls="tab-selection">Sélection</button> <button role="tab" aria-selected="false" aria-controls="tab-slots">Machines à sous</button> <button role="tab" aria-selected="false" aria-controls="tab-live">Casino en direct</button> <button role="tab" aria-selected="false" aria-controls="tab-instantanes">Jeux instantanés</button> </nav> <div role="tabpanel" id="plan-tab-selection"> <h2>Sélection de l'équipe</h2> <!-- carrousel 5-8 jeux max --> </div> <!-- autres tabpanels masqués par défaut --></main>. Retrait du carrousel "Gains récents" : supprimer la section visible y=70-200 et son data source. (Alternative à cadrer Legal-check : si maintenu, masquer les montants et ne garder que les noms de jeux pour ne pas suggérer un gain prévisible.)
- Effort estimé : L
- Validation :
Re-run analyze_conversion_signals.py sur casino : summary.ctas_above_fold doit passer de 23 à ≤ 10. summary.ctas_total peut rester élevé en scroll mais l'above-fold doit être lisible. Test manuel : un visiteur novice doit pouvoir identifier la promesse en 3 secondes.
R-PERF-01-07 : Nettoyer le template CMS qui génère 7 background-image: url() vides
- Findings adressés : F-PERF-01-07
- Routes concernées :
all - Priorité RICE : R=5 I=1 C=3 E=3 → score=5.0
- Action concrète :
Auditer le template JSP/Velocity qui génère le bloc <style> inline lignes 45-72. Identifier la variable backend qui résout en chaîne vide (probablement ${landingBackground}, ${promozioniSfondo}, etc. non setté quand pas de promo active). Au choix : (a) générer le selector + déclaration UNIQUEMENT quand la variable est non-vide, (b) servir un placeholder transparent 1x1 px par défaut, (c) supprimer ces selectors du template si jamais utilisés.
- Copy-ready :
Pattern cible JSP (option a, conditional rendering) : ``jsp <c:if test="${not empty landingBackground}"> <style>.cg-landing-background { background-image: url('${landingBackground}') !important; }</style> </c:if> ``
- Effort estimé : M
- Validation :
Grep background-image: url() (vide) sur le <head> rendu : count = 0.