diff --git a/src/components/dashboard/SubscriptionCardExpired.tsx b/src/components/dashboard/SubscriptionCardExpired.tsx index 5d86ce7..95d5e46 100644 --- a/src/components/dashboard/SubscriptionCardExpired.tsx +++ b/src/components/dashboard/SubscriptionCardExpired.tsx @@ -107,14 +107,14 @@ export default function SubscriptionCardExpired({ r: 255, g: 184, b: 0, - hex: '#FFB800', + hex: 'rgb(var(--color-urgent-400))', gradient: 'linear-gradient(135deg, #FFB800, #FF8C00)', } : { r: 255, g: 59, b: 92, - hex: '#FF3B5C', + hex: 'rgb(var(--color-critical-500))', gradient: 'linear-gradient(135deg, #FF3B5C, #FF6B35)', }; diff --git a/src/components/dashboard/TrialOfferCard.tsx b/src/components/dashboard/TrialOfferCard.tsx index c930141..4afba16 100644 --- a/src/components/dashboard/TrialOfferCard.tsx +++ b/src/components/dashboard/TrialOfferCard.tsx @@ -115,7 +115,7 @@ export default function TrialOfferCard({ height="26" viewBox="0 0 24 24" fill="none" - stroke="#FFB800" + stroke="rgb(var(--color-urgent-400))" strokeWidth="1.5" aria-hidden="true" > @@ -157,11 +157,14 @@ export default function TrialOfferCard({ > {trialInfo.price_rubles.toFixed(0)} - + {currencySymbol} diff --git a/src/components/subscription/PurchaseCTAButton.tsx b/src/components/subscription/PurchaseCTAButton.tsx index a4c816a..779d367 100644 --- a/src/components/subscription/PurchaseCTAButton.tsx +++ b/src/components/subscription/PurchaseCTAButton.tsx @@ -24,7 +24,7 @@ export default function PurchaseCTAButton({ // Daily tariffs renew automatically — no manual renewal button needed in multi-tariff if (isMultiTariff && isDaily && !isExpired) return null; - const accentColor = isExpired ? '#FF3B5C' : 'rgb(var(--color-accent-400))'; + const accentColor = isExpired ? 'rgb(var(--color-critical-500))' : 'rgb(var(--color-accent-400))'; const buttonText = isExpired ? t('subscription.getSubscription') diff --git a/src/hooks/useTrafficZone.ts b/src/hooks/useTrafficZone.ts index b5eb137..298367a 100644 --- a/src/hooks/useTrafficZone.ts +++ b/src/hooks/useTrafficZone.ts @@ -5,8 +5,8 @@ import type { ThemeColors } from '../types/theme'; const FALLBACKS: Record = { accent: '#3b82f6', - warning: '#FFB800', - error: '#FF3B5C', + warning: 'rgb(var(--color-urgent-400))', + error: 'rgb(var(--color-critical-500))', }; const COLOR_MAP: Record = { diff --git a/src/pages/Subscription.tsx b/src/pages/Subscription.tsx index 2979ec9..5cb6a20 100644 --- a/src/pages/Subscription.tsx +++ b/src/pages/Subscription.tsx @@ -98,7 +98,13 @@ const CountdownTimer = memo(function CountdownTimer({ height="13" viewBox="0 0 24 24" fill="none" - stroke={isExpired ? '#FF3B5C' : isUrgent ? '#FFB800' : g.textSecondary} + stroke={ + isExpired + ? 'rgb(var(--color-critical-500))' + : isUrgent + ? 'rgb(var(--color-urgent-400))' + : g.textSecondary + } strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" @@ -111,7 +117,10 @@ const CountdownTimer = memo(function CountdownTimer({ {t('dashboard.remaining')} {isExpired ? ( -
+
{t('subscription.expired')}
) : ( @@ -121,7 +130,7 @@ const CountdownTimer = memo(function CountdownTimer({ <> {countdown.days} @@ -132,31 +141,31 @@ const CountdownTimer = memo(function CountdownTimer({ )} {String(countdown.hours).padStart(2, '0')} : {String(countdown.minutes).padStart(2, '0')} : {String(countdown.seconds).padStart(2, '0')} @@ -710,8 +719,8 @@ export default function Subscription() { color: subscription.is_active ? zone.mainHex : subscription.is_limited - ? '#FFB800' - : '#FF3B5C', + ? 'rgb(var(--color-urgent-400))' + : 'rgb(var(--color-critical-500))', }} > {subscription.is_active @@ -746,7 +755,7 @@ export default function Subscription() { height="16" viewBox="0 0 24 24" fill="none" - stroke="#FFB800" + stroke="rgb(var(--color-urgent-400))" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" @@ -758,7 +767,10 @@ export default function Subscription() {
-

+

{t('subscription.trafficLimitedTitle')}

@@ -1269,7 +1281,7 @@ export default function Subscription() { color: subscription.is_daily_paused || subscription.status === 'disabled' ? 'rgb(var(--color-accent-400))' - : '#FFB800', + : 'rgb(var(--color-urgent-400))', }} > {pauseMutation.isPending ? ( @@ -1306,7 +1318,7 @@ export default function Subscription() { style={{ background: 'rgba(255,59,92,0.08)', border: '1px solid rgba(255,59,92,0.15)', - color: '#FF3B5C', + color: 'rgb(var(--color-critical-500))', }} > {getErrorMessage(pauseMutation.error)} @@ -1324,11 +1336,14 @@ export default function Subscription() { }} >

-
+
⏸️
-
+
{t('subscription.pause.pausedInfo')}
@@ -2412,7 +2427,7 @@ export default function Subscription() { }} disabled={deleteAllDevicesMutation.isPending} className="text-[11px] font-medium transition-colors" - style={{ color: '#FF3B5C' }} + style={{ color: 'rgb(var(--color-critical-500))' }} > {t('subscription.deleteAllDevices')} diff --git a/src/pages/SubscriptionPurchase.tsx b/src/pages/SubscriptionPurchase.tsx index ae3d1ff..ca2fcf3 100644 --- a/src/pages/SubscriptionPurchase.tsx +++ b/src/pages/SubscriptionPurchase.tsx @@ -477,7 +477,7 @@ export default function SubscriptionPurchase() { height="16" viewBox="0 0 24 24" fill="none" - stroke="#FFB800" + stroke="rgb(var(--color-urgent-400))" strokeWidth="1.5" aria-hidden="true" > @@ -489,7 +489,10 @@ export default function SubscriptionPurchase() {
-
+
{t('subscription.trialUpgrade.title')}
@@ -522,7 +525,7 @@ export default function SubscriptionPurchase() { height="16" viewBox="0 0 24 24" fill="none" - stroke="#FF3B5C" + stroke="rgb(var(--color-critical-500))" strokeWidth="1.5" aria-hidden="true" > @@ -534,7 +537,10 @@ export default function SubscriptionPurchase() {
-
+
{t('subscription.expiredBanner.title')}
diff --git a/src/styles/globals.css b/src/styles/globals.css index 4c3c1d7..fd98cbf 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -180,6 +180,13 @@ --color-error-900: 127, 29, 29; --color-error-950: 69, 10, 10; + /* Subscription-status semantic tokens — distinct from warning/error + because the urgency timeline ("expiring soon" vs "expired") needs a + sharper, hotter signal than the system-wide warning/error roles. + Extracted from inline #FFB800 / #FF3B5C in Subscription.tsx etc. */ + --color-urgent-400: 255, 184, 0; /* #FFB800 — expiring soon */ + --color-critical-500: 255, 59, 92; /* #FF3B5C — expired */ + /* Theme semantic colors (hex for direct use) */ --color-dark-bg: #0a0f1a; --color-dark-surface: #0f172a; diff --git a/tailwind.config.js b/tailwind.config.js index 155b39b..4729ba0 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -101,6 +101,13 @@ export default { 900: withOpacity('--color-error-900'), 950: withOpacity('--color-error-950'), }, + // Subscription-status semantic tokens — see globals.css for rationale. + urgent: { + 400: withOpacity('--color-urgent-400'), + }, + critical: { + 500: withOpacity('--color-critical-500'), + }, }, fontFamily: { sans: [