diff --git a/app.py b/app.py
index e78dcf2..c6889d5 100644
--- a/app.py
+++ b/app.py
@@ -136,6 +136,81 @@ TEAM_EMOTE_OVERRIDES: Dict[str, str] = {
     "default": "<:neutrality:1432391681059197102>",
 }
 
+# Role mapping for ELO tiers (IDs provided by user)
+# Assumption: Top tier is >= 900 ELO rather than strictly >900,
+# to avoid leaving 900 unassigned. Adjust if you want 900 handled differently.
+STANDARD_ELO_ROLE_IDS = {
+    "gte_900": 1432368177014374497,
+    "851_899": 1432368177014374496,
+    "801_850": 1432368177014374495,
+    "eq_800": 1432368177014374494,
+    "751_799": 1432368177014374493,
+    "701_750": 1432368177014374492,
+    "lt_700": 1432368177014374491,
+}
+
+COMPETITIVE_ELO_ROLE_IDS = {
+    "gte_900": 1432368177030893672,
+    "851_899": 1432368177030893671,
+    "801_850": 1432368177030893670,
+    "eq_800": 1432368177030893669,
+    "751_799": 1432368177030893668,
+    "701_750": 1432368177014374499,
+    "lt_700": 1432368177014374498,
+}
+
+def _role_id_for_elo(elo: int, category: str) -> Optional[int]:
+    """Return the role ID for the given ELO and category ('standard'|'competitive')."""
+    ids = STANDARD_ELO_ROLE_IDS if category == "standard" else COMPETITIVE_ELO_ROLE_IDS
+    if elo >= 900:
+        return ids["gte_900"]
+    if 851 <= elo <= 899:
+        return ids["851_899"]
+    if 801 <= elo <= 850:
+        return ids["801_850"]
+    if elo == 800:
+        return ids["eq_800"]
+    if 751 <= elo <= 799:
+        return ids["751_799"]
+    if 701 <= elo <= 750:
+        return ids["701_750"]
+    # < 700
+    return ids["lt_700"]
+
+def _category_role_ids(category: str) -> List[int]:
+    ids = STANDARD_ELO_ROLE_IDS if category == "standard" else COMPETITIVE_ELO_ROLE_IDS
+    return list(ids.values())
+
+async def update_member_elo_role(member: discord.Member, elo: int, category: str, reason: Optional[str] = None):
+    """Ensure the member has exactly one rank role for the given category matching their ELO.
+    - category: 'standard' or 'competitive'
+    """
+    if member is None or member.guild is None:
+        return
+    try:
+        guild = member.guild
+        target_role_id = _role_id_for_elo(elo, category)
+        if not target_role_id:
+            return
+        target_role = guild.get_role(int(target_role_id))
+        if not target_role:
+            return  # Role not found in this guild
+
+        # Remove any other roles from the same category
+        category_ids = set(_category_role_ids(category))
+        roles_to_remove = [r for r in member.roles if r.id in category_ids and r.id != target_role.id]
+        if roles_to_remove:
+            await member.remove_roles(*roles_to_remove, reason=reason)
+
+        # Add the target role if missing
+        if target_role not in member.roles:
+            await member.add_roles(target_role, reason=reason)
+    except discord.Forbidden:
+        # Missing permissions or role hierarchy issue
+        logging.warning(f"Insufficient permissions to modify roles for {member} in category {category}")
+    except discord.HTTPException as e:
+        logging.warning(f"Failed to update roles for {member}: {e}")
+
 # Emoji and formatting helpers
 def _all_accessible_emojis(ctx: commands.Context) -> List[discord.Emoji]:
     """Return emojis from current guild plus all guilds the bot is in."""
@@ -777,6 +852,27 @@ async def hoi4end(ctx, game_name: str, winner_team: str):
                     "UPDATE games SET status = 'finished', winner_team = %s, finished_at = CURRENT_TIMESTAMP WHERE id = %s",
                     (final_result, game['id'])
                 )
+                
+                # After DB updates, try to sync Discord roles for affected players (only for this game's category)
+                try:
+                    guild = ctx.guild
+                    if guild:
+                        for change in elo_changes:
+                            member = guild.get_member(change['discord_id'])
+                            if member is None:
+                                try:
+                                    member = await guild.fetch_member(change['discord_id'])
+                                except Exception:
+                                    member = None
+                            if member:
+                                await update_member_elo_role(
+                                    member,
+                                    change['new_elo'],
+                                    game['game_type'],
+                                    reason=f"HOI4 {game['game_type']} ELO updated in '{game_name}'"
+                                )
+                except Exception as e:
+                    logging.warning(f"Role sync after game end failed: {e}")
             
         # Create result embed
         if is_draw:
@@ -963,6 +1059,16 @@ async def hoi4stats(ctx, user: Optional[discord.Member] = None):
         )
         
         await ctx.send(embed=embed)
+
+        # Try to keep user's roles in sync for both categories when stats are viewed
+        try:
+            if ctx.guild and isinstance(target_user, discord.Member):
+                await update_member_elo_role(
+                    target_user, player['standard_elo'], 'standard', reason='HOI4 stats viewed: role sync')
+                await update_member_elo_role(
+                    target_user, player['competitive_elo'], 'competitive', reason='HOI4 stats viewed: role sync')
+        except Exception as e:
+            logging.warning(f"Role sync on stats failed: {e}")
         
     except Exception as e:
         await ctx.send(f"❌ Error getting stats: {str(e)}")
