Index: backend/subjects/consts.py
===================================================================
--- backend/subjects/consts.py	(revision b9a043ae3cd897c768eb2bbfc70479463ea55ec4)
+++ backend/subjects/consts.py	(revision 5dd5fcb6767602ba71469766386a300613beee10)
@@ -3,8 +3,8 @@
 
 WEIGHTS = {
-    "professors": 0.0325,
-    "assistants": 0.0325,
-    "technologies": 0.065,
-    "tags": 0.4,
+    "professors": 0.055,
+    "assistants": 0.055,
+    "technologies": 0.075,
+    "tags": 0.35,
     "evaluation": 0.15, 
     "effort": 0.3,
Index: backend/subjects/utils.py
===================================================================
--- backend/subjects/utils.py	(revision b9a043ae3cd897c768eb2bbfc70479463ea55ec4)
+++ backend/subjects/utils.py	(revision 5dd5fcb6767602ba71469766386a300613beee10)
@@ -258,22 +258,94 @@
     return subjects_tag_scores
 
-def get_recommended_subjects(subjects_tag_scores):
-    """
-    generates a list of recommended subjects based on weighted scores.
-
-    args:
-        filtered_subjects_vector (dict): a dictionary where each key is a subject and each value is another dictionary
-            mapping feature keys to their corresponding scores for that subject.
-    returns:
-        list: a list of top N subject names recommended based on their normalized scores. if all scores are zero, returns empty list.
-    """
-    subject_scores = {}
-    for subject in subjects_tag_scores:
-        keys = subjects_tag_scores[subject]
-        score = 0
-        for key in keys:
-            score += WEIGHTS[key] * keys[key]
-        subject_scores[subject] = score
-    
-    top_subjects = list(dict(sorted(subject_scores.items(), key=lambda item: item[1], reverse=True)))[:NUMBER_OF_SUGGESTIONS]
-    return top_subjects
+def get_explanation_message(criterion, score):
+    """Generates a human-readable explanation for a single matching criterion."""
+
+    # Thresholds to decide if a match is significant enough to be an "explanation"
+    thresholds = {
+        'tags': 0.7, 'evaluation': 0.5, 'technologies': 0.5,
+        'professors': 0.5, 'assistants': 0.5, 'participant_score': 0.5,
+    }
+
+    if score < thresholds.get(criterion, 1.0):
+        return None
+
+    messages = {
+        'tags': f"Супер совпаѓање со твоите полиња на интерес ({score:.1%})",
+        'evaluation': f"Се совпаѓа со твоите посакувани методи на евалуација ({score:.1%})",
+        'technologies': f"Се совпаѓа со технологиите кои ги сакаш ({score:.1%})",
+        'professors': f"Го предаваат професори кои ги сакаш ({score:.1%})",
+        'assistants': f"Има асистенти кои ги сакаш ({score:.1%})",
+        'participant_score': f"Има голем број на студенти",
+    }
+    return messages.get(criterion)
+
+# def get_detailed_tag_matches(student_vector, subject_vector):
+#     """Identifies the specific tags that matched between the student and subject."""
+
+#     student_tags_indices = {i for i, val in enumerate(student_vector['tags']) if val == 1}
+#     subject_tags_indices = {i for i, val in enumerate(subject_vector['tags']) if val == 1}
+    
+#     matching_indices = student_tags_indices.intersection(subject_tags_indices)
+    
+#     # Map indices back to tag names from the vocabulary
+#     all_tags = VOCABULARY.get('tags', [])
+#     matching_tags = [all_tags[i] for i in matching_indices if i < len(all_tags)]
+    
+#     return matching_tags
+
+
+def get_recommendations_with_details(subjects_tag_scores):
+    """
+    Generates a sorted list of recommended subjects with detailed explanations.
+
+    Args:
+        subjects_tag_scores (dict): Scores for each subject across different criteria.
+
+    Returns:
+        list: A list of dictionaries, each containing detailed info for a recommended subject.
+    """
+    detailed_results = []
+
+    for subject_name, individual_scores in subjects_tag_scores.items():
+        total_score = 0
+        weighted_scores = {}
+        explanations = []
+
+        for criterion, score in individual_scores.items():
+            weight = WEIGHTS.get(criterion, 0)
+            weighted_score = weight * score
+            total_score += weighted_score
+            weighted_scores[criterion] = weighted_score
+            
+            message = get_explanation_message(criterion, score)
+            if message:
+                explanations.append(message)
+
+            # Sort explanations by their match percentage, it extracts the percentage from the message (e.g. Something (72.8%)) and sorts them in descending order
+            explanations.sort(key=lambda msg: -(float(msg.split('(')[-1].replace('%)', '')) if '(' in msg and '%' in msg else float('-inf')))
+        # primary_reason_criterion = max(weighted_scores, key=weighted_scores.get)
+        # primary_reason_score = individual_scores[primary_reason_criterion]
+        # primary_reason = get_explanation_message(primary_reason_criterion, primary_reason_score)
+        # if not primary_reason:
+        #     primary_reason = f"Добро совпаѓање поради {primary_reason_criterion.replace('_', ' ')}"
+
+        # matching_tags = get_detailed_tag_matches(student_vector, eligible_subjects_dict[subject_name])
+
+        detailed_results.append({
+            'subject_name': subject_name,
+            'total_score': total_score,
+            # 'primary_reason': primary_reason,
+            'explanations': explanations,
+            # 'detailed_scores': individual_scores,
+            # 'matching_tags': matching_tags,
+            'match_percentage': min(total_score * 100, 100)
+        })
+
+
+    max_score = max([res['total_score'] for res in detailed_results]) or 1
+    for res in detailed_results:
+        res['match_percentage'] = round((res['total_score'] / max_score) * 100, 1)
+
+    detailed_results.sort(key=lambda x: x['total_score'], reverse=True)
+    return detailed_results[:NUMBER_OF_SUGGESTIONS]
+    
Index: backend/subjects/views.py
===================================================================
--- backend/subjects/views.py	(revision b9a043ae3cd897c768eb2bbfc70479463ea55ec4)
+++ backend/subjects/views.py	(revision 5dd5fcb6767602ba71469766386a300613beee10)
@@ -9,9 +9,10 @@
 from rest_framework.permissions import IsAuthenticated
 from django.db.models import Case, When, Count, F, Q
-from subjects.utils import get_eligible_subjects, get_recommendations_cache_key, get_recommended_subjects, map_to_subjects_vector, score_for_preferences, get_student_vector
+from subjects.utils import get_eligible_subjects, get_recommendations_cache_key, get_recommendations_with_details, map_to_subjects_vector, score_for_preferences, get_student_vector
 from .serializers import SubjectSerializer, EvaluationReviewSerializer, OtherReviewSerializer
 from .models import Subject, Review, EvaluationReview, OtherReview, ReviewVote
 from rest_framework.pagination import LimitOffsetPagination
 from auth_form.permissions import IsStudent, IsAdmin
+import logging
 
 def index(request):
@@ -42,22 +43,49 @@
             cached_data = cache.get(cache_key)
             if cached_data:
-                return Response({"data": json.loads(cached_data)}, status=status.HTTP_200_OK)
-        try:
-            subjects = get_eligible_subjects(student, season=season, not_activated=not_activated)
-            subject_vectors = map_to_subjects_vector(subjects)
+                return Response(json.loads(cached_data), status=status.HTTP_200_OK)
+        try:
+            eligible_subjects = get_eligible_subjects(student, season=season, not_activated=not_activated)
+            if not eligible_subjects:
+                return Response({"data": []}, status=status.HTTP_200_OK)
+            
+            eligible_subjects_dict = map_to_subjects_vector(eligible_subjects)
             student_vector = get_student_vector(student)
 
-            final_subjects = get_recommended_subjects(score_for_preferences(student_vector, subject_vectors))
-
-            order = Case(*[When(name=subject_name, then=pos) for pos, subject_name in enumerate(final_subjects)])
-
-            recommended_subject_objects = Subject.objects.filter(name__in=final_subjects).order_by(order)
+            subjects_scores = score_for_preferences(student_vector, eligible_subjects_dict)
+            
+            recommendations_with_details = get_recommendations_with_details(
+                subjects_scores
+            )
+
+            if not recommendations_with_details:
+                return Response({"data": []}, status=status.HTTP_200_OK)
+            final_subject_names = [rec['subject_name'] for rec in recommendations_with_details]
+            details_map = {rec['subject_name']: rec for rec in recommendations_with_details}
+
+            order = Case(*[When(name=name, then=pos) for pos, name in enumerate(final_subject_names)])
+            recommended_subject_objects = Subject.objects.filter(name__in=final_subject_names).order_by(order)
 
             serializer = SubjectSerializer(recommended_subject_objects, many=True)
+            
+            final_response_data = []
+            for subject_data in serializer.data:
+                details = details_map.get(subject_data['name'])
+                if details:
+                    subject_data['recommendation_details'] = {
+                        'match_percentage': details['match_percentage'],
+                        # 'primary_reason': details['primary_reason'],
+                        'explanations': details['explanations'],
+                        # 'matching_tags': details['matching_tags'],
+                        # 'detailed_scores': details['detailed_scores']
+                    }
+                final_response_data.append(subject_data)
+
+            response_payload = {"data": final_response_data}
             if cache_key:
-                cache.set(cache_key, json.dumps(serializer.data), timeout=60 * 60 * 24 * 14) # 14 days
-            return Response({"data": serializer.data}, status=status.HTTP_200_OK)
+                cache.set(cache_key, json.dumps(response_payload), timeout=60 * 60 * 24 * 14)
+            return Response(response_payload, status=status.HTTP_200_OK)
 
         except Exception as e:
+            logging.error(f"Recommendation error for student {student.id}: {e}", exc_info=True)
             return Response({"message": f"An error occurred: {str(e)}"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
 
Index: frontend/src/components/SubjectCatalog/SubjectCard.tsx
===================================================================
--- frontend/src/components/SubjectCatalog/SubjectCard.tsx	(revision b9a043ae3cd897c768eb2bbfc70479463ea55ec4)
+++ frontend/src/components/SubjectCatalog/SubjectCard.tsx	(revision 5dd5fcb6767602ba71469766386a300613beee10)
@@ -12,4 +12,11 @@
 	isRecommended?: boolean;
 	isLoading?: boolean;
+	recommendationDetails?: {
+		match_percentage: number;
+		primary_reason: string;
+		explanations: string[];
+		matching_tags: string[];
+		detailed_scores: Record<string, number>;
+	};
 }
 
@@ -22,35 +29,82 @@
 	isRecommended = false,
 	isLoading = false,
+	recommendationDetails,
 }: SubjectCardProps) => {
 	return (
 		<div
 			key={subject.id}
-			className="border border-gray-200 bg-white rounded-lg overflow-hidden shadow-sm hover:shadow-md transition-shadow duration-200"
+			className="border border-gray-200 bg-white rounded-lg overflow-hidden shadow-sm hover:shadow-md transition-shadow duration-200 h-full"
 		>
-			<div className="p-4 min-h-full flex flex-col gap-1">
-				<div
-					className={`flex justify-between items-start 
-					${isRecommended ? "mb-16" : "mb-8"}`}
-				>
-					<div>
-						<h3 className="text-lg font-semibold">{subject.name}</h3>
-						<p className="text-gray-600">{subject.code}</p>
+			<div className="p-4 h-full flex flex-col relative">
+				<div className="flex justify-between items-start mb-4">
+					<div className="flex-1">
+						<h3 className="text-lg font-semibold line-clamp-2 leading-tight">
+							{subject.name}
+						</h3>
+						<p className="text-gray-600 text-sm mt-1">{subject.code}</p>
 					</div>
 				</div>
-				<div className="absolute inset-0 flex items-center justify-center pointer-events-none">
-					{isRecommended && subject.subject_info.activated === false ? (
-						<span className="bg-red-500 text-white font-bold px-3 py-1 rounded-full shadow-lg text-xs transition-opacity duration-300 z-10">
+
+				{isRecommended && subject.subject_info.activated === false && (
+					<div className="absolute top-16 left-1/2 transform -translate-x-1/2 z-10">
+						<span className="bg-red-500 text-white font-bold px-3 py-1 rounded-full shadow-lg text-xs whitespace-nowrap">
 							Никогаш не бил активиран!
 						</span>
-					) : isFirst ? (
-						<span className="bg-blue-600 text-white font-bold px-3 py-1 rounded-full shadow-lg text-xs transition-opacity duration-300 z-10">
-							Најсоодветен!
-						</span>
-					) : null}
+					</div>
+				)}
+
+				<div className="flex-1 mb-4">
+					{recommendationDetails && (
+						<div
+							className={`rounded-md px-3 py-2 text-sm border ${
+								recommendationDetails.match_percentage === 100 && isFirst
+									? "bg-green-50 text-green-800 border-green-200"
+									: recommendationDetails.match_percentage > 50
+									? "bg-blue-50 text-blue-800 border-blue-200"
+									: "bg-red-50 text-red-800 border-red-200"
+							}`}
+						>
+							{isFirst ? (
+								<div className="flex justify-center mb-2">
+									<span className="bg-green-50 text-green-800 border-green-200 font-bold px-3 py-1 rounded-full text-sm">
+										Најсоодветен!
+									</span>
+								</div>
+							) : (
+								<p className="font-semibold mb-2">
+									{recommendationDetails.match_percentage >= 90
+										? "Супер за тебе"
+										: recommendationDetails.match_percentage >= 75
+										? "Многу добар избор"
+										: recommendationDetails.match_percentage >= 50
+										? "Добар избор"
+										: "Не е најдобриот избор"}
+								</p>
+							)}
+							<ul className="space-y-1">
+								{recommendationDetails.explanations.map(
+									(explanation, index) => (
+										<li key={index} className="text-xs leading-relaxed">
+											• {explanation}
+										</li>
+									)
+								)}
+							</ul>
+						</div>
+					)}
 				</div>
-				<div className="flex justify-between mt-auto gap-3">
+
+				<div className="flex justify-between items-center gap-3 pt-2 border-t border-gray-100 mt-auto">
 					<div className="flex items-center gap-2">
-						<button onClick={() => openSubjectDetails(subject)}>
-							<img src="src/assets/eye.svg" className="w-5 h-5" />
+						<button
+							onClick={() => openSubjectDetails(subject)}
+							className="p-1 hover:bg-gray-100 rounded transition-colors"
+							title="Погледни детали"
+						>
+							<img
+								src="src/assets/eye.svg"
+								className="w-5 h-5"
+								alt="View details"
+							/>
 						</button>
 						<FavoriteButton subjectId={subject.id} isLoading={isLoading} />
@@ -62,5 +116,5 @@
 						)}
 					</div>
-					<div className="flex-1 flex justify-end">
+					<div className="flex-shrink-0">
 						<button
 							onClick={() => openSubjectView(subject)}
@@ -69,7 +123,8 @@
 							<img
 								src="src/assets/open.svg"
-								className="w-4 h-4 xs:mr-0 sm:mr-1"
+								className="w-4 h-4 sm:mr-1"
+								alt="Open"
 							/>
-							<span className="hidden xs:inline">Отвори предмет</span>
+							<span className="hidden sm:inline">Отвори предмет</span>
 						</button>
 					</div>
Index: frontend/src/components/types.ts
===================================================================
--- frontend/src/components/types.ts	(revision b9a043ae3cd897c768eb2bbfc70479463ea55ec4)
+++ frontend/src/components/types.ts	(revision 5dd5fcb6767602ba71469766386a300613beee10)
@@ -15,4 +15,11 @@
 	abstract: string;
 	subject_info: SubjectInfo;
+	recommendation_details?: {
+		match_percentage: number;
+		primary_reason: string;
+		explanations: string[];
+		matching_tags: string[];
+		detailed_scores: Record<string, number>;
+	};
 }
 
Index: frontend/src/pages/Recommendations.tsx
===================================================================
--- frontend/src/pages/Recommendations.tsx	(revision b9a043ae3cd897c768eb2bbfc70479463ea55ec4)
+++ frontend/src/pages/Recommendations.tsx	(revision 5dd5fcb6767602ba71469766386a300613beee10)
@@ -184,5 +184,5 @@
 										<h2 className="text-2xl lg:text-3xl font-bold text-gray-800 mb-2">
 											Вашите препораки за {getSeasonText().toLowerCase()}{" "}
-											{getSeasonText().toLowerCase() === "Зимски + Летен"
+											{getSeasonText().toLowerCase() === "зимски + летен"
 												? "семестри"
 												: "семестар"}
@@ -193,12 +193,10 @@
 										</p>
 									</div>
-									<div
-										className={`grid grid-cols-1 md:grid-cols-2 gap-3 md:auto-rows-[300px] relative pb-4`}
-									>
+									<div className="grid grid-cols-1 md:grid-cols-2 gap-4 md:gap-6">
 										{recommendations.map((subject, index) => (
 											<div
 												key={subject.id}
-												className={`border border-gray-200 rounded-lg overflow-hidden shadow-sm hover:shadow-md transition-shadow duration-200 relative ${
-													index % 2 === 0 ? "self-start" : "self-end"
+												className={`border border-gray-200 rounded-lg overflow-hidden shadow-sm hover:shadow-md transition-shadow duration-200 ${
+													index % 2 === 0 ? "md:mt-0" : "md:mt-8"
 												}`}
 												style={{
@@ -215,7 +213,8 @@
 													openSubjectView={openSubjectView}
 													canReview={true}
-													isFirst={index == 0}
+													isFirst={index === 0}
 													isRecommended={true}
 													isLoading={isLoading}
+													recommendationDetails={subject.recommendation_details}
 												/>
 											</div>
