feat(design): Projector Noir theme - tungsten amber on film-black

Full visual refonte replacing the generic neon-blue glass look:

- palette: warm film-black surface ladder, tungsten amber primary,
  warm taupe secondary, verdigris teal tertiary; semantic and
  category colors retuned to match (coral live, gold movies)
- typography: Syne (display/headlines) + Instrument Sans (body/UI)
  replace Space Grotesk/Inter/Outfit across all screens
- glassmorphism tokens warmed (amber inner glow, warm-white borders)
- web player theme.css + index.html loader mirror the new tokens
- hardcoded Colors.blue* in streaming settings and recordings tabs
  now use AppColors tokens
- DESIGN_SYSTEM.md updated to v3.0 Projector Noir

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
MichaelandClaude Fable 5 committed 2026-06-10 14:52:45 +02:00
1 parent 9595afcc99
commit e332895d7d
33 files changed
+392 -397

No files matched your search

@@ -1,4 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../../../features/iptv/providers/xtream_provider.dart';
@@ -70,7 +70,7 @@ class MobilePlaylistSelectionScreen extends ConsumerWidget {
color: AppColors.error,
),
const SizedBox(height: 16),
Text('Error loading playlists', style: GoogleFonts.inter()),
Text('Error loading playlists', style: GoogleFonts.instrumentSans()),
TextButton(
onPressed: () => ref.refresh(playlistsProvider),
child: const Text('Retry'),
@@ -92,7 +92,7 @@ class MobilePlaylistSelectionScreen extends ConsumerWidget {
const SizedBox(height: 16),
Text(
'No playlists available',
style: GoogleFonts.inter(color: AppColors.textSecondary),
style: GoogleFonts.instrumentSans(color: AppColors.textSecondary),
),
],
),
@@ -177,7 +177,7 @@ class _MobilePlaylistCard extends StatelessWidget {
children: [
Text(
playlist.name,
style: GoogleFonts.inter(
style: GoogleFonts.instrumentSans(
fontSize: 16,
fontWeight: FontWeight.w600,
color: AppColors.textPrimary,
@@ -188,7 +188,7 @@ class _MobilePlaylistCard extends StatelessWidget {
const SizedBox(height: 4),
Text(
Uri.tryParse(playlist.dns)?.host ?? playlist.dns,
style: GoogleFonts.inter(
style: GoogleFonts.instrumentSans(
fontSize: 13,
color: AppColors.textSecondary,
),
@@ -1,4 +1,4 @@
import 'package:flutter/material.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:google_fonts/google_fonts.dart';
@@ -110,7 +110,7 @@ class _MobileSeriesDetailScreenState
const SizedBox(height: 16),
Text(
'Error: $_error',
style: GoogleFonts.inter(color: AppColors.onSurfaceVariant),
style: GoogleFonts.instrumentSans(color: AppColors.onSurfaceVariant),
),
TextButton(
onPressed: _loadSeriesInfo,
@@ -186,7 +186,7 @@ class _MobileSeriesDetailScreenState
children: [
Text(
_seriesInfo!.name,
style: GoogleFonts.inter(
style: GoogleFonts.instrumentSans(
fontSize: 24,
fontWeight: FontWeight.bold,
color: AppColors.onSurface,
@@ -204,7 +204,7 @@ class _MobileSeriesDetailScreenState
const SizedBox(width: 4),
Text(
_formatRating(_seriesInfo!.rating!)!,
style: GoogleFonts.inter(
style: GoogleFonts.instrumentSans(
color: AppColors.onSurfaceVariant,
fontSize: 13,
),
@@ -213,7 +213,7 @@ class _MobileSeriesDetailScreenState
],
Text(
'${_seriesInfo!.episodes.keys.length} Seasons',
style: GoogleFonts.inter(
style: GoogleFonts.instrumentSans(
color: AppColors.onSurfaceVariant,
fontSize: 13,
),
@@ -235,7 +235,7 @@ class _MobileSeriesDetailScreenState
padding: const EdgeInsets.all(16.0),
child: Text(
_seriesInfo!.plot!,
style: GoogleFonts.inter(color: AppColors.onSurfaceVariant, height: 1.4),
style: GoogleFonts.instrumentSans(color: AppColors.onSurfaceVariant, height: 1.4),
maxLines: 4,
overflow: TextOverflow.ellipsis,
),
@@ -262,7 +262,7 @@ class _MobileSeriesDetailScreenState
},
backgroundColor: AppColors.surfaceContainer,
selectedColor: AppColors.primary,
labelStyle: GoogleFonts.inter(
labelStyle: GoogleFonts.instrumentSans(
color: isSelected ? AppColors.onPrimary : AppColors.onSurfaceVariant,
fontWeight: isSelected ? FontWeight.w600 : FontWeight.w400,
),
@@ -357,7 +357,7 @@ class _MobileSeriesDetailScreenState
children: [
Text(
'E${episode.episodeNum} - ${episode.title}',
style: GoogleFonts.inter(
style: GoogleFonts.instrumentSans(
color: AppColors.onSurface,
fontWeight: FontWeight.w600,
fontSize: 14,
@@ -369,7 +369,7 @@ class _MobileSeriesDetailScreenState
episode.durationSecs! > 0)
Text(
_formatDuration(episode.durationSecs!),
style: GoogleFonts.inter(
style: GoogleFonts.instrumentSans(
color: AppColors.onSurfaceVariant,
fontSize: 12,
),