diff --git a/MovieActorLookup/Components/Layout/MainLayout.razor b/MovieActorLookup/Components/Layout/MainLayout.razor index 1cb0578..7b09b53 100644 --- a/MovieActorLookup/Components/Layout/MainLayout.razor +++ b/MovieActorLookup/Components/Layout/MainLayout.razor @@ -28,42 +28,4 @@ height: 100vh; overflow: hidden; } - - .sidebar { - width: 250px; - background: #ffffff; - border-right: 1px solid rgba(0, 0, 0, 0.06); - position: relative; - z-index: 100; - } - - .main-content { - flex: 1; - display: flex; - flex-direction: column; - min-height: 0; - width: 100%; - } - - .top-row { - background: rgba(255, 255, 255, 0.95); - border-bottom: 1px solid rgba(0, 0, 0, 0.06); - display: flex; - justify-content: flex-end; - align-items: center; - height: 3.5rem; - padding: 0 24px; - } - - .top-row a { - color: #6c757d; - text-decoration: none; - font-weight: 500; - font-size: 14px; - transition: color 0.2s ease; - } - - .top-row a:hover { - color: #667eea; - } diff --git a/MovieActorLookup/Components/Layout/MainLayout.razor.css b/MovieActorLookup/Components/Layout/MainLayout.razor.css index 45d97f6..2865b4e 100644 --- a/MovieActorLookup/Components/Layout/MainLayout.razor.css +++ b/MovieActorLookup/Components/Layout/MainLayout.razor.css @@ -8,34 +8,6 @@ main { flex: 1; } -.sidebar { - background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); -} - -.top-row { - background-color: #f7f7f7; - border-bottom: 1px solid #d6d5d5; - justify-content: flex-end; - height: 3.5rem; - display: flex; - align-items: center; -} - - .top-row ::deep a, .top-row ::deep .btn-link { - white-space: nowrap; - margin-left: 1.5rem; - text-decoration: none; - } - - .top-row ::deep a:hover, .top-row ::deep .btn-link:hover { - text-decoration: underline; - } - - .top-row ::deep a:first-child { - overflow: hidden; - text-overflow: ellipsis; - } - @media (max-width: 640.98px) { .top-row { justify-content: space-between; diff --git a/MovieActorLookup/Components/Pages/Home.razor b/MovieActorLookup/Components/Pages/Home.razor index 85d70ea..e99db84 100644 --- a/MovieActorLookup/Components/Pages/Home.razor +++ b/MovieActorLookup/Components/Pages/Home.razor @@ -8,7 +8,7 @@

This app helps you quickly identify actors, find out what else they've been in, and explore cast details for your favorite movies and TV shows.

🎬 Search Movies - 📺 Search TV Shows + 📺 Search TV Shows
@@ -180,24 +180,13 @@ } .cta-button.primary { - background: linear-gradient(45deg, #667eea, #764ba2); - color: white; - box-shadow: 0 10px 30px rgba(102, 126, 234, 0.4); - } - - .cta-button.primary:hover { - transform: translateY(-3px) scale(1.05); - box-shadow: 0 20px 40px rgba(102, 126, 234, 0.6); - } - - .cta-button.secondary { background: rgba(255, 255, 255, 0.15); color: white; border: 2px solid rgba(255, 255, 255, 0.3); backdrop-filter: blur(10px); } - .cta-button.secondary:hover { + .cta-button.primary:hover { transform: translateY(-3px) scale(1.05); background: rgba(255, 255, 255, 0.25); border-color: rgba(255, 255, 255, 0.5); diff --git a/MovieActorLookup/Components/Pages/SearchMovies.razor b/MovieActorLookup/Components/Pages/SearchMovies.razor index ec3cddb..6e58e5c 100644 --- a/MovieActorLookup/Components/Pages/SearchMovies.razor +++ b/MovieActorLookup/Components/Pages/SearchMovies.razor @@ -3,154 +3,920 @@ @using MovieActorLookup.Models.Movies @using System.ComponentModel.DataAnnotations @inject MovieService MovieService +@inject IJSRuntime JSRuntime @rendermode InteractiveServer -

Search for Actor by Movie and Character Name

+
+
+ +

Discover Actors & Their Movies

+

Search by movie and character to explore an actor's complete filmography

+
-
- - - -
- -@if (_isSearching) -{ -

Searching...

-} - -else if (_actor != null) -{ -

Actor: @_actor.Name

- - @if (_matchedMovie != null) - { -
- Movie Poster -
-
@_matchedMovie.MovieTitle
- @_matchedMovie.CharacterName -
- @_matchedMovie.Franchise - Release Date: @_matchedMovie.ReleaseDate +
+
+
+ +
🎬
+
+
+ +
🎭
- } - - @foreach (var franchiseGroup in _actor.MovieCharacters - .GroupBy(mc => mc.Franchise) - .OrderBy(g => g.Key == "Standalone") - .ThenBy(g => g.Key)) - { -
@franchiseGroup.Key
-
- @foreach (var movieCharacter in (franchiseGroup.Key == "Standalone" - ? franchiseGroup.OrderByDescending(mc => - DateTime.TryParse(mc.ReleaseDate, out var d) ? d : DateTime.MinValue) - : franchiseGroup.OrderBy(mc => - DateTime.TryParse(mc.ReleaseDate, out var d) ? d : DateTime.MaxValue))) + +
+ + @if (_isSearching) + { +
+
+
+
+
+
+

Finding the perfect match...

+
+ } + else if (_actor != null) + { +
+
+

@_actor.Name

+
@_actor.MovieCharacters.Count movie@(_actor.MovieCharacters.Count != 1 ? "s" : "") found
+
+ + @if (_matchedMovie != null) + { +
+

Your Search Match

+
} + +
+

Complete Movie Filmography

+ + @foreach (var group in _actor.MovieCharacters + .GroupBy(mc => mc.Franchise) + .OrderBy(g => g.Key == "Standalone") + .ThenBy(g => g.Key)) + { + @if (group.Key != "Standalone") + { +
+
@group.Key Collection
+
+ } + +
+ @foreach (var movie in (group.Key == "Standalone" + ? group.OrderByDescending(mc => DateTime.TryParse(mc.ReleaseDate, out var d) ? d : DateTime.MinValue) + : group.OrderBy(mc => DateTime.TryParse(mc.ReleaseDate, out var d) ? d : DateTime.MaxValue))) + { +
+
+ @movie.MovieTitle Poster +
+
+ View Details +
+
+
+
+
@movie.MovieTitle
+
as @movie.CharacterName
+ @if (!string.IsNullOrEmpty(movie.Overview)) + { +
+

+ @movie.Overview +

+ @if (movie.Overview.Length > 150) + { + + } +
+ } +
@movie.ReleaseDate
+
+
+ } +
+ } +
} -} -else -{ -

Enter a movie title and character name to begin your search.

-} + else if (!string.IsNullOrEmpty(_movieTitle) || !string.IsNullOrEmpty(_characterName)) + { +
+
🔍
+

No matches found

+

Try adjusting your search terms or check the spelling

+
+ } + else + { +
+
🎬
+

Ready to explore?

+

Enter a movie title and character name to discover an actor's complete film journey

+
+ } +
+ + + + @code { - private string _movieTitle; - private string _characterName; + private string _movieTitle = ""; + private string _characterName = ""; private Actor _actor; private MovieCharacter _matchedMovie; private bool _isSearching = false; + private HashSet _expandedOverviews = new HashSet(); + + private bool IsOverviewExpanded(string movieTitle) + { + return _expandedOverviews.Contains(movieTitle); + } + + private void ToggleOverview(string movieTitle) + { + if (_expandedOverviews.Contains(movieTitle)) + { + _expandedOverviews.Remove(movieTitle); + } + else + { + _expandedOverviews.Add(movieTitle); + } + } private async Task SearchForActorAndCharacters() { + if (string.IsNullOrWhiteSpace(_movieTitle) || string.IsNullOrWhiteSpace(_characterName)) + return; + _isSearching = true; _actor = null; - _matchedMovie = null; // reset matched movie + _matchedMovie = null; StateHasChanged(); - if (!string.IsNullOrWhiteSpace(_movieTitle) && !string.IsNullOrWhiteSpace(_characterName)) + await Task.Delay(100); + await JSRuntime.InvokeVoidAsync("startAnimations"); + + try { var movies = await MovieService.GetMoviesByTitle(_movieTitle); + foreach (var movie in movies) { var credits = await MovieService.GetMovieCreditsByMovieId(movie.Id); + foreach (var castMember in credits.Cast) { - if (castMember.Character.ToLower().Contains(_characterName.ToLower())) + if (castMember.Character.Contains(_characterName, StringComparison.OrdinalIgnoreCase)) { if (_actor == null) { _actor = new Actor(castMember.Name); - int personId = castMember.Id; - - var filmography = await MovieService.GetActorMovieCreditsById(personId); - if (filmography?.Cast != null) - { - foreach (var role in filmography.Cast) - { - var fullMovie = await MovieService.GetMovieDetailsById(role.Id); - - var movieCharacter = new MovieCharacter - { - MovieTitle = role.Title, - CharacterName = role.Character, - MoviePosterPath = role.PosterPath, - ReleaseDate = DateTime.TryParse(fullMovie?.ReleaseDate, out var parsedDate) - ? parsedDate.ToString("MM/dd/yyyy") - : "N/A", - Overview = fullMovie?.Overview ?? "", - Franchise = fullMovie?.BelongsToCollection?.Name ?? "Standalone" - }; - - _actor.MovieCharacters.Add(movieCharacter); - - if (_matchedMovie == null) - { - if (role.Title == movie.Title && role.Character == castMember.Character) - { - _matchedMovie = movieCharacter; - } - } - } - } + await LoadActorFilmography(castMember.Id, movie, castMember); } + break; } } + + if (_actor != null) break; + } + } + catch (Exception ex) + { + Console.WriteLine($"Search error: {ex.Message}"); + } + finally + { + _isSearching = false; + StateHasChanged(); + } + } + + private async Task LoadActorFilmography(int personId, object originalMovie, object originalCast) + { + var filmography = await MovieService.GetActorMovieCreditsById(personId); + + if (filmography?.Cast != null) + { + foreach (var role in filmography.Cast) + { + var fullMovie = await MovieService.GetMovieDetailsById(role.Id); + + var movieCharacter = new MovieCharacter + { + MovieTitle = role.Title ?? "Unknown Title", + CharacterName = role.Character ?? "Unknown Character", + MoviePosterPath = role.PosterPath ?? "", + ReleaseDate = DateTime.TryParse(fullMovie?.ReleaseDate, out var parsedDate) + ? parsedDate.ToString("MMM dd, yyyy") + : "Unknown Date", + Overview = fullMovie?.Overview ?? "", + Franchise = fullMovie?.BelongsToCollection?.Name ?? "Standalone" + }; + + _actor.MovieCharacters.Add(movieCharacter); + + if (_matchedMovie == null && + string.Equals(role.Title, GetPropertyValue(originalMovie, "Title")?.ToString(), StringComparison.OrdinalIgnoreCase) && + string.Equals(role.Character, GetPropertyValue(originalCast, "Character")?.ToString(), StringComparison.OrdinalIgnoreCase)) + { + _matchedMovie = movieCharacter; + } } } - - _isSearching = false; - StateHasChanged(); } - - private async Task GetProperMovieBasedOffOfActorInvolvement(string movieActorTitle, CastMember actor) + private object GetPropertyValue(object obj, string propertyName) { - List overallCredits = new(); - - List actorMovies = await MovieService.GetMoviesByTitle(movieActorTitle); - - foreach (Movie movie in actorMovies) - { - overallCredits.Add(await MovieService.GetMovieCreditsByMovieId(movie.Id)); - } - - Credits actorMovieCredits = overallCredits.FirstOrDefault(x => x.Cast.Any(c => c.Id == actor.Id)); - Movie movie1 = actorMovies.Where(x => x.Id == actorMovieCredits.Id).FirstOrDefault(); - - return movie1; + if (obj == null) return null; + var property = obj.GetType().GetProperty(propertyName); + return property?.GetValue(obj); } } \ No newline at end of file diff --git a/MovieActorLookup/Components/Pages/SearchShows.razor b/MovieActorLookup/Components/Pages/SearchShows.razor index 839ae33..08d7ea5 100644 --- a/MovieActorLookup/Components/Pages/SearchShows.razor +++ b/MovieActorLookup/Components/Pages/SearchShows.razor @@ -6,6 +6,12 @@
+

Discover Actors & Their Shows

Search by TV show and character to explore an actor's complete filmography

@@ -74,6 +80,11 @@ alt="@_matchedShow.ShowTitle Poster" loading="lazy" />
✨ Match
+
+
+ View Details +
+
@_matchedShow.ShowTitle
@@ -116,6 +127,11 @@ src="@($"https://image.tmdb.org/t/p/w500{show.ShowPosterPath}")" alt="@show.ShowTitle Poster" loading="lazy" /> +
+
+ View Details +
+
@show.ShowTitle
@@ -154,7 +170,7 @@ else {
-
🎬
+
📺

Ready to explore?

Enter a TV show title and character name to discover an actor's complete television journey

@@ -167,37 +183,167 @@ margin: 0 auto; padding: 2rem 1rem; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%); + min-height: 100vh; + position: relative; + } + + .search-container::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: url('data:image/svg+xml,') repeat; + opacity: 0.4; + pointer-events: none; + animation: float 25s ease-in-out infinite; + } + + @@keyframes float { + 0%, 100% + + { + transform: translateY(0px) rotate(0deg); + } + + 50% { + transform: translateY(-30px) rotate(180deg); + } + } .search-header { text-align: center; margin-bottom: 2.5rem; + position: relative; + z-index: 1; } + .navigation-toggle { + display: flex; + justify-content: center; + margin-bottom: 1.5rem; + animation: slideInDown 0.8s ease-out 0.2s both; + } + + .nav-btn { + background: rgba(255,255,255,0.15); + color: white; + text-decoration: none; + padding: 0.75rem 1.5rem; + border-radius: 2rem; + font-weight: 600; + font-size: 0.9rem; + display: flex; + align-items: center; + gap: 0.5rem; + transition: all 0.3s ease; + backdrop-filter: blur(10px); + border: 1px solid rgba(255,255,255,0.2); + box-shadow: 0 4px 15px rgba(0,0,0,0.1); + } + + .nav-btn:hover { + background: rgba(255,255,255,0.25); + transform: translateY(-2px); + box-shadow: 0 8px 25px rgba(0,0,0,0.15); + color: white; + text-decoration: none; + } + + .nav-btn:active { + transform: translateY(0px); + } + + .nav-icon { + font-size: 1.1rem; + transition: transform 0.3s ease; + } + + .nav-btn:hover .nav-icon { + transform: scale(1.2); + } + + .movies-btn { + background: linear-gradient(135deg, rgba(102, 126, 234, 0.3), rgba(118, 75, 162, 0.3)); + } + + .movies-btn:hover { + background: linear-gradient(135deg, rgba(102, 126, 234, 0.5), rgba(118, 75, 162, 0.5)); + } + .search-title { font-size: 2.5rem; font-weight: 700; - color: #1a1a1a; + color: white; margin-bottom: 0.5rem; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; + text-shadow: 2px 2px 4px rgba(0,0,0,0.3); + animation: slideInDown 1s ease-out; + } + + @@keyframes slideInDown { + from + + { + opacity: 0; + transform: translateY(-50px); + } + + to { + opacity: 1; + transform: translateY(0); + } + } .search-subtitle { font-size: 1.1rem; - color: #666; + color: rgba(255,255,255,0.9); margin: 0; + animation: fadeIn 1.5s ease-out 0.3s both; + } + + @@keyframes fadeIn { + from + + { + opacity: 0; + } + + to { + opacity: 1; + } + } .search-form { - background: white; - border-radius: 1rem; + background: rgba(255,255,255,0.95); + border-radius: 1.5rem; padding: 2rem; - box-shadow: 0 8px 25px rgba(0,0,0,0.08); + box-shadow: 0 20px 40px rgba(0,0,0,0.1); margin-bottom: 2rem; - border: 1px solid #f0f0f0; + backdrop-filter: blur(10px); + border: 1px solid rgba(255,255,255,0.2); + animation: slideInUp 1s ease-out 0.6s both; + position: relative; + z-index: 1; + } + + @@keyframes slideInUp { + from + + { + opacity: 0; + transform: translateY(30px); + } + + to { + opacity: 1; + transform: translateY(0); + } + } .input-group { @@ -215,9 +361,9 @@ .search-input { width: 100%; - padding: 0.875rem 1rem 0.875rem 3rem; + padding: 1rem 1rem 1rem 3.5rem; border: 2px solid #e1e5e9; - border-radius: 0.75rem; + border-radius: 1rem; font-size: 1rem; transition: all 0.3s ease; background: #fafbfc; @@ -225,25 +371,31 @@ .search-input:focus { outline: none; - border-color: #667eea; + border-color: #4f46e5; background: white; - box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); + box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1), 0 8px 25px rgba(79, 70, 229, 0.15); + transform: translateY(-2px); } .input-icon { position: absolute; - left: 1rem; + left: 1.2rem; top: 50%; transform: translateY(-50%); - font-size: 1.2rem; + font-size: 1.3rem; + transition: transform 0.3s ease; + } + + .input-wrapper:focus-within .input-icon { + transform: translateY(-50%) scale(1.1); } .search-btn { - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%); border: none; color: white; - padding: 0.875rem 2rem; - border-radius: 0.75rem; + padding: 1rem 2.5rem; + border-radius: 1rem; font-size: 1rem; font-weight: 600; cursor: pointer; @@ -251,13 +403,18 @@ display: flex; align-items: center; gap: 0.5rem; - min-width: 140px; + min-width: 160px; justify-content: center; + box-shadow: 0 4px 15px rgba(79, 70, 229, 0.3); } .search-btn:hover:not(:disabled) { - transform: translateY(-2px); - box-shadow: 0 8px 25px rgba(102, 126, 234, 0.3); + transform: translateY(-3px); + box-shadow: 0 12px 35px rgba(79, 70, 229, 0.4); + } + + .search-btn:active:not(:disabled) { + transform: translateY(-1px); } .search-btn:disabled { @@ -266,17 +423,34 @@ } .spinner { - width: 16px; - height: 16px; + width: 18px; + height: 18px; border: 2px solid rgba(255,255,255,0.3); border-top: 2px solid white; border-radius: 50%; + animation: spin 1s linear infinite; + } + + @@keyframes spin { + 0% + + { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } + } .loading-state, .welcome-state, .no-results { text-align: center; padding: 3rem 2rem; - color: #666; + color: rgba(255,255,255,0.9); + animation: fadeIn 0.5s ease-out; + position: relative; + z-index: 1; } .loading-animation { @@ -287,19 +461,58 @@ } .loading-dot { - width: 8px; - height: 8px; - background: #667eea; + width: 12px; + height: 12px; + background: white; border-radius: 50%; + animation: bounce 1.4s ease-in-out infinite both; + } + + .loading-dot:nth-child(1) { + animation-delay: -0.32s; + } + + .loading-dot:nth-child(2) { + animation-delay: -0.16s; + } + + @@keyframes bounce { + 0%, 80%, 100% + + { + transform: scale(0); + } + + 40% { + transform: scale(1); + } + } .welcome-icon, .no-results-icon { - font-size: 3rem; + font-size: 4rem; margin-bottom: 1rem; + animation: pulse 2s ease-in-out infinite; + } + + @@keyframes pulse { + 0%, 100% + + { + transform: scale(1); + } + + 50% { + transform: scale(1.1); + } + } .results-section { margin-top: 2rem; + animation: slideInUp 0.8s ease-out; + position: relative; + z-index: 1; } .actor-header { @@ -309,22 +522,29 @@ margin-bottom: 2rem; flex-wrap: wrap; gap: 1rem; + background: rgba(255,255,255,0.1); + padding: 1.5rem 2rem; + border-radius: 1rem; + backdrop-filter: blur(10px); } .actor-name { font-size: 2rem; font-weight: 700; - color: #1a1a1a; + color: white; margin: 0; + text-shadow: 2px 2px 4px rgba(0,0,0,0.3); } .results-count { - background: #f0f4ff; - color: #4c63d2; - padding: 0.5rem 1rem; + background: rgba(255,255,255,0.2); + color: white; + padding: 0.5rem 1.5rem; border-radius: 2rem; font-weight: 500; font-size: 0.9rem; + backdrop-filter: blur(10px); + border: 1px solid rgba(255,255,255,0.1); } .matched-show-section { @@ -334,11 +554,12 @@ .section-title { font-size: 1.5rem; font-weight: 600; - color: #1a1a1a; + color: white; margin-bottom: 1.5rem; display: flex; align-items: center; gap: 0.5rem; + text-shadow: 1px 1px 2px rgba(0,0,0,0.3); } .franchise-group { @@ -348,10 +569,13 @@ .franchise-title { font-size: 1.3rem; font-weight: 600; - color: #4c63d2; + color: white; margin: 0; - padding-left: 1rem; - border-left: 4px solid #4c63d2; + padding: 1rem 1.5rem; + background: rgba(255,255,255,0.1); + border-radius: 0.5rem; + border-left: 4px solid rgba(255,255,255,0.5); + backdrop-filter: blur(10px); } .shows-grid { @@ -363,22 +587,23 @@ .show-card { background: white; - border-radius: 1rem; + border-radius: 1.2rem; overflow: hidden; - box-shadow: 0 4px 15px rgba(0,0,0,0.08); - transition: all 0.3s ease; - border: 1px solid #f0f0f0; + box-shadow: 0 8px 25px rgba(0,0,0,0.15); + transition: all 0.4s ease; + border: 1px solid rgba(255,255,255,0.2); position: relative; + transform-style: preserve-3d; } .show-card:hover { - transform: translateY(-4px); - box-shadow: 0 8px 30px rgba(0,0,0,0.12); + transform: translateY(-8px) scale(1.02); + box-shadow: 0 20px 40px rgba(0,0,0,0.25); } .show-card.featured { - border: 2px solid #667eea; - box-shadow: 0 8px 30px rgba(102, 126, 234, 0.15); + border: 2px solid rgba(255,255,255,0.5); + box-shadow: 0 12px 35px rgba(79, 70, 229, 0.25); } .show-card.matched { @@ -390,6 +615,7 @@ width: 100%; aspect-ratio: 2/3; overflow: hidden; + background: linear-gradient(45deg, #f0f0f0, #e0e0e0); } .poster-image { @@ -397,27 +623,53 @@ height: 100%; object-fit: contain; background-color: #f8f9fa; - transition: transform 0.3s ease; + transition: all 0.4s ease; + } + + .poster-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: linear-gradient(to bottom, transparent 0%, rgba(0,0,0,0.8) 100%); + opacity: 0; + transition: all 0.3s ease; + display: flex; + align-items: flex-end; + padding: 1rem; + } + + .show-card:hover .poster-overlay { + opacity: 1; } .show-card:hover .poster-image { transform: scale(1.05); } + .overlay-content { + color: white; + font-weight: 600; + font-size: 0.9rem; + } + .match-badge { position: absolute; - top: 0.5rem; - right: 0.5rem; + top: 0.8rem; + right: 0.8rem; background: linear-gradient(135deg, #10b981, #059669); color: white; - padding: 0.3rem 0.8rem; - border-radius: 1rem; + padding: 0.4rem 1rem; + border-radius: 1.5rem; font-size: 0.8rem; font-weight: 600; + box-shadow: 0 4px 15px rgba(16, 185, 129, 0.4); + z-index: 2; } .card-content { - padding: 1.25rem; + padding: 1.5rem; } .show-title { @@ -429,7 +681,7 @@ } .character-name { - color: #667eea; + color: #4f46e5; font-weight: 500; margin-bottom: 0.75rem; font-size: 0.95rem; @@ -456,18 +708,19 @@ .read-more-btn { background: none; border: none; - color: #667eea; + color: #4f46e5; font-size: 0.85rem; font-weight: 600; cursor: pointer; padding: 0.25rem 0; margin-top: 0.5rem; text-decoration: underline; - transition: color 0.3s ease; + transition: all 0.3s ease; } .read-more-btn:hover { - color: #4c63d2; + color: #3730a3; + transform: translateX(5px); } .air-date { @@ -477,42 +730,43 @@ } @@media (max-width: 768px) { - .search-container { - padding: 1rem; - } + .search-container - .search-title { - font-size: 2rem; - } + { + padding: 1rem; + } - .input-group { - flex-direction: column; - } + .search-title { + font-size: 2rem; + } - .input-wrapper { - min-width: auto; - } + .input-group { + flex-direction: column; + } - .actor-header { - flex-direction: column; - align-items: stretch; - } + .input-wrapper { + min-width: auto; + } + + .actor-header { + flex-direction: column; + align-items: stretch; + } + + .shows-grid { + grid-template-columns: 1fr; + gap: 1rem; + } - .shows-grid { - grid-template-columns: 1fr; - gap: 1rem; - } } @code { @@ -592,7 +864,6 @@ _matchedShow = null; StateHasChanged(); - // Start animations after a small delay to ensure DOM is ready await Task.Delay(100); await JSRuntime.InvokeVoidAsync("startAnimations");