import React, { useMemo, useState } from 'react'; import { View, Text, StyleSheet, ScrollView, TouchableOpacity, Modal, Alert, Share, } from 'react-native'; import { useLocalSearchParams, useRouter } from 'expo-router'; import { Ionicons } from '@expo/vector-icons'; import * as Haptics from 'expo-haptics'; import * as ImagePicker from 'expo-image-picker'; import { useApp } from '../../context/AppContext'; import { useColors } from '../../constants/Colors'; import { requestPermissions, scheduleWateringReminder, cancelReminder } from '../../services/notificationService'; import { SafeImage } from '../../components/SafeImage'; const parseColorToRgb = (input: string) => { const color = input.trim(); if (color.startsWith('#')) { const hex = color.slice(1); const normalized = hex.length === 3 ? hex.split('').map((char) => `${char}${char}`).join('') : hex; if (normalized.length === 6) { return { r: Number.parseInt(normalized.slice(0, 2), 16), g: Number.parseInt(normalized.slice(2, 4), 16), b: Number.parseInt(normalized.slice(4, 6), 16), }; } } const rgbMatch = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/i); if (rgbMatch) { return { r: Number.parseInt(rgbMatch[1], 10), g: Number.parseInt(rgbMatch[2], 10), b: Number.parseInt(rgbMatch[3], 10), }; } return { r: 127, g: 127, b: 127 }; }; const getReadableTextColor = (background: string, dark: string, light: string) => { const { r, g, b } = parseColorToRgb(background); const luminance = (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255; return luminance > 0.58 ? dark : light; }; const HEALTH_CHECK_CREDIT_COST = 2; const getHealthCopy = (language: 'de' | 'en' | 'es') => { if (language === 'de') { return { title: 'Health Check', action: 'Health-Scan starten', running: 'Neues Foto wird analysiert...', cost: `Kosten: ${HEALTH_CHECK_CREDIT_COST} Credits`, intro: 'Fotografiere die ganze Pflanze plus auffaellige Blaetter. Danach bekommst du Diagnose, Dringlichkeit und einen konkreten Pflegeplan.', creditsLabel: 'Credits', managePlan: 'Plan verwalten', noCreditsTitle: 'Nicht genug Credits', noCreditsMessage: `Du brauchst ${HEALTH_CHECK_CREDIT_COST} Credits fuer den Health-Check.`, insufficientInline: 'Nicht genug Credits fuer den Health-Check.', timeoutInline: 'Health-Check Timeout. Bitte erneut versuchen.', providerInline: 'Health-Check ist gerade nicht verfuegbar.', analysisTitle: 'Analyse', analysisFallback: 'Die Pflanze wirkt insgesamt beurteilbar, aber die gespeicherte Analyse enthaelt noch keine ausformulierte Zusammenfassung. Orientiere dich deshalb an Score, Ursachen und Sofortmassnahmen. Pruefe zuerst die auffaelligsten Blaetter, danach Substratfeuchte und Standort. Wenn die Blaetter innerhalb von 48 Stunden weiter haengen, gelb werden oder Flecken ausbreiten, solltest du ein neues Foto bei hellem indirektem Licht aufnehmen. Ein neuer Health-Scan kann dann genauer zwischen Wasserstress, Lichtstress, Schaedlingen und normaler Blattalterung unterscheiden.', issuesTitle: 'Wahrscheinlichste Ursachen', actionsTitle: 'Sofortmassnahmen', planTitle: '7-Tage-Plan', scoreLabel: 'Gesundheits-Score', healthy: 'Stabil', watch: 'Beobachten', critical: 'Kritisch', lastCheck: 'Zuletzt geprueft', }; } if (language === 'es') { return { title: 'Health Check', action: 'Iniciar health-scan', running: 'Analizando foto nueva...', cost: `Costo: ${HEALTH_CHECK_CREDIT_COST} creditos`, intro: 'Fotografia la planta completa y las hojas llamativas. Luego recibes diagnostico, urgencia y un plan de cuidado concreto.', creditsLabel: 'Creditos', managePlan: 'Gestionar plan', noCreditsTitle: 'Creditos insuficientes', noCreditsMessage: `Necesitas ${HEALTH_CHECK_CREDIT_COST} creditos para el health-check.`, insufficientInline: 'No hay creditos suficientes para el health-check.', timeoutInline: 'Health-check agotado por tiempo. Intenta de nuevo.', providerInline: 'Health-check no disponible ahora.', analysisTitle: 'Analisis', analysisFallback: 'La planta se puede evaluar en general, pero este chequeo guardado todavia no contiene un resumen completo. Usa el puntaje, las causas y las acciones inmediatas como guia principal. Revisa primero las hojas mas llamativas, despues la humedad del sustrato y la ubicacion. Si las hojas empeoran en 48 horas, amarillean o las manchas se expanden, toma una foto nueva con luz indirecta clara. Un nuevo health-scan podra diferenciar mejor entre exceso o falta de agua, luz, plagas y envejecimiento normal.', issuesTitle: 'Causas mas probables', actionsTitle: 'Acciones inmediatas', planTitle: 'Plan de 7 dias', scoreLabel: 'Puntaje de salud', healthy: 'Estable', watch: 'Observar', critical: 'Critico', lastCheck: 'Ultima revision', }; } return { title: 'Health Check', action: 'Start health scan', running: 'Analyzing new photo...', cost: `Cost: ${HEALTH_CHECK_CREDIT_COST} credits`, intro: 'Photograph the full plant plus any suspicious leaves. You will get a diagnosis, urgency level, and a concrete care plan.', creditsLabel: 'Credits', managePlan: 'Manage plan', noCreditsTitle: 'Not enough credits', noCreditsMessage: `You need ${HEALTH_CHECK_CREDIT_COST} credits for the health check.`, insufficientInline: 'Not enough credits for the health check.', timeoutInline: 'Health check timed out. Please try again.', providerInline: 'Health check is unavailable right now.', analysisTitle: 'Analysis', analysisFallback: 'The plant is still assessable, but this saved check does not include a full written summary yet. Use the score, likely causes, and immediate actions as the primary guide. Start by inspecting the most unusual leaves, then check soil moisture and placement. If leaves droop further, yellowing spreads, or spots expand within 48 hours, take a new photo in bright indirect light. A fresh health scan can separate watering stress, light stress, pests, and normal leaf aging more accurately.', issuesTitle: 'Most likely causes', actionsTitle: 'Actions now', planTitle: '7-day plan', scoreLabel: 'Health score', healthy: 'Stable', watch: 'Watch', critical: 'Critical', lastCheck: 'Last checked', }; }; export default function PlantDetailScreen() { const { id } = useLocalSearchParams<{ id: string }>(); const { plants, isDarkMode, colorPalette, language, t, deletePlant, updatePlant, billingSummary, } = useApp(); const colors = useColors(isDarkMode, colorPalette); const router = useRouter(); const [showDeleteConfirm, setShowDeleteConfirm] = useState(false); const [fullscreenImage, setFullscreenImage] = useState(null); const [healthStatus, setHealthStatus] = useState<'idle' | 'insufficient_credits'>('idle'); const [paywallVisible, setPaywallVisible] = useState(false); const plant = plants.find((item) => item.id === id); if (!plant) { return ( Plant not found ); } const localeMap: Record = { de: 'de-DE', en: 'en-US', es: 'es-ES' }; const locale = localeMap[language] || 'de-DE'; const healthCopy = getHealthCopy(language); const availableCredits = billingSummary?.credits.available ?? 0; const formattedWateredDate = new Date(plant.lastWatered).toLocaleDateString(locale); const lastWateredObj = new Date(plant.lastWatered); const nextWateringDate = new Date(lastWateredObj); nextWateringDate.setDate(lastWateredObj.getDate() + plant.careInfo.waterIntervalDays); const formattedNextWatering = nextWateringDate.toLocaleDateString(locale, { weekday: 'short', day: 'numeric', month: 'short', }); const lastWateredText = t.lastWateredDate.replace('{0}', formattedWateredDate); const isWateredToday = new Date(plant.lastWatered).toDateString() === new Date().toDateString(); const daysSinceWatered = Math.max( 0, Math.floor((Date.now() - lastWateredObj.getTime()) / (1000 * 60 * 60 * 24)) ); const nextWaterLabel = language === 'de' ? 'Nächstes Gießen' : language === 'es' ? 'Proximo riego' : 'Next water'; const wateredAgoText = language === 'de' ? `Zuletzt vor ${daysSinceWatered} ${daysSinceWatered === 1 ? 'Tag' : 'Tagen'}` : language === 'es' ? `Ultimo riego hace ${daysSinceWatered} ${daysSinceWatered === 1 ? 'dia' : 'dias'}` : `Last watered ${daysSinceWatered} ${daysSinceWatered === 1 ? 'day' : 'days'} ago`; const textOnPage = getReadableTextColor(colors.pageBase, colors.primaryDark, colors.textOnImage); const textOnSurface = getReadableTextColor(colors.surface, colors.primaryDark, colors.textOnImage); const textOnHeroButton = getReadableTextColor(colors.heroButton, colors.primaryDark, colors.textOnImage); const textOnPrimaryAction = getReadableTextColor(colors.primaryDark, '#ffffff', '#111111'); const textOnAiBadge = getReadableTextColor(colors.primarySoft, colors.primaryDark, colors.textOnImage); const latestHealthCheck = useMemo(() => { if (!plant.healthChecks || plant.healthChecks.length === 0) return null; return plant.healthChecks[0]; }, [plant.healthChecks]); const healthStatusInlineText = (() => { if (healthStatus === 'insufficient_credits') return healthCopy.insufficientInline; if (healthStatus === 'idle' && availableCredits < HEALTH_CHECK_CREDIT_COST) return healthCopy.insufficientInline; return ''; })(); const healthStateColor = (() => { if (healthStatus === 'insufficient_credits') return colors.warning; return colors.textMuted; })(); const latestStatusText = latestHealthCheck ? ( latestHealthCheck.status === 'healthy' ? healthCopy.healthy : latestHealthCheck.status === 'watch' ? healthCopy.watch : healthCopy.critical ) : ''; const latestStatusBg = latestHealthCheck ? ( latestHealthCheck.status === 'healthy' ? colors.successSoft : latestHealthCheck.status === 'watch' ? colors.warningSoft : colors.dangerSoft ) : colors.surfaceMuted; const latestStatusColor = latestHealthCheck ? ( latestHealthCheck.status === 'healthy' ? colors.success : latestHealthCheck.status === 'watch' ? colors.warning : colors.danger ) : colors.textMuted; const latestAnalysisSummary = latestHealthCheck ? latestHealthCheck.analysisSummary || healthCopy.analysisFallback : ''; const timelineEntries = useMemo(() => { const history = plant.wateringHistory && plant.wateringHistory.length > 0 ? plant.wateringHistory : [plant.lastWatered]; return history.slice(0, 5); }, [plant.lastWatered, plant.wateringHistory]); const hasEnoughHealthCredits = availableCredits >= HEALTH_CHECK_CREDIT_COST; const canRunHealthCheck = true; const handleWater = async () => { await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium); const now = new Date().toISOString(); const currentHistory = plant.wateringHistory || []; const newHistory = [now, ...currentHistory].slice(0, 10); updatePlant({ ...plant, lastWatered: now, wateringHistory: newHistory }); }; const handleShare = async () => { try { await Share.share({ message: `Check out my plant: ${plant.name} (${plant.botanicalName}) - identified with GreenLens!`, }); } catch (error: any) { Alert.alert('Error', error.message); } }; const handleDelete = () => { deletePlant(plant.id); router.back(); }; const handleAddPhoto = async () => { const result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ['images'], quality: 0.8, }); if (!result.canceled && result.assets[0]) { const currentGallery = plant.gallery || []; updatePlant({ ...plant, gallery: [...currentGallery, result.assets[0].uri] }); } }; const handleHealthCheck = async () => { if (availableCredits < HEALTH_CHECK_CREDIT_COST) { setPaywallVisible(true); return; } if (healthStatus !== 'idle') { setHealthStatus('idle'); } router.push({ pathname: '/scanner', params: { mode: 'health', plantId: plant.id }, }); }; return ( router.back()} > {plant.name} {plant.botanicalName} {nextWaterLabel} {formattedNextWatering} {isWateredToday ? lastWateredText : wateredAgoText} {isWateredToday ? t.watered : t.waterNow} {[ { icon: 'water' as const, label: t.water, value: `${plant.careInfo.waterIntervalDays} ${t.days}`, iconColor: colors.info, iconBg: colors.infoSoft, }, { icon: 'sunny' as const, label: t.light, value: plant.careInfo.light, iconColor: colors.warning, iconBg: colors.warningSoft, }, { icon: 'thermometer' as const, label: t.temp, value: plant.careInfo.temp, iconColor: colors.success, iconBg: colors.successSoft, }, ].map((item) => ( {item.label} {item.value} ))} Smart Reminders {t.reminderDesc} { if (!plant.notificationsEnabled) { const granted = await requestPermissions(); if (!granted) { Alert.alert(t.reminder, t.reminderPermissionNeeded); return; } await scheduleWateringReminder(plant); } else { await cancelReminder(plant.id); } updatePlant({ ...plant, notificationsEnabled: !plant.notificationsEnabled }); }} > {t.wateringHistory} {timelineEntries.length === 0 ? ( {t.noHistory} ) : ( timelineEntries.map((dateStr, index) => ( {index < timelineEntries.length - 1 && ( )} {new Date(dateStr).toLocaleDateString(locale, { day: '2-digit', month: 'short', year: 'numeric', })} {index === 0 ? t.watered : t.waterNow} {new Date(dateStr).toLocaleTimeString(locale, { hour: '2-digit', minute: '2-digit', })} )) )} {t.galleryTitle} {t.addPhoto} {(!plant.gallery || plant.gallery.length === 0) ? ( {t.noPhotos} ) : ( {plant.gallery.map((uri, index) => ( setFullscreenImage(uri)}> ))} )} {t.aboutPlant} AI {plant.description || t.noDescription} {healthCopy.title} {healthCopy.intro} {healthCopy.action} {healthCopy.creditsLabel}: {availableCredits} {healthCopy.cost} {healthStatusInlineText ? ( {healthStatusInlineText} {healthStatus === 'insufficient_credits' || (healthStatus === 'idle' && !hasEnoughHealthCredits) ? ( router.push('/(tabs)/profile')} > {healthCopy.managePlan} ) : null} ) : null} {latestHealthCheck ? ( {healthCopy.scoreLabel} {latestHealthCheck.overallHealthScore}/100 {latestStatusText} {healthCopy.lastCheck}: {new Date(latestHealthCheck.generatedAt).toLocaleString(locale)} {latestAnalysisSummary ? ( {healthCopy.analysisTitle} {latestAnalysisSummary} ) : null} {healthCopy.issuesTitle} {latestHealthCheck.likelyIssues.map((issue, index) => ( {issue.title} {Math.round(issue.confidence * 100)}% {issue.details} ))} {healthCopy.actionsTitle} {latestHealthCheck.actionsNow.map((item, index) => ( {item} ))} {healthCopy.planTitle} {latestHealthCheck.plan7Days.map((item, index) => ( {item} ))} ) : null} setShowDeleteConfirm(true)}> {t.delete} {t.deleteConfirmTitle} {t.deleteConfirmMessage} setShowDeleteConfirm(false)} > {t.cancel} {t.confirm} {fullscreenImage && } setFullscreenImage(null)}> {/* Health Check Paywall Modal */} setPaywallVisible(false)}> setPaywallVisible(false)} style={styles.paywallClose}> KI-Pflanzendoktor freischalten Nutze fortschrittliche KI, um Probleme zu erkennen, bevor sie deine Pflanze gefährden. {[ { icon: 'search', title: 'Präzise Diagnose', desc: 'Erkennt Schädlinge, Krankheiten und Nährstoffmangel.' }, { icon: 'medkit', title: 'Rettungspläne', desc: 'Schritt-für-Schritt Anleitungen zur Genesung.' }, { icon: 'infinite', title: 'Mehr Scans', desc: 'Erhalte 120 Credits jeden Monat mit GreenLens Pro.' }, ].map((feat, i) => ( {feat.title} {feat.desc} ))} { setPaywallVisible(false); router.push('/profile/billing'); }} > Jetzt upgraden setPaywallVisible(false)} > Vielleicht später ); } const styles = StyleSheet.create({ container: { flex: 1 }, scrollContent: { paddingBottom: 120 }, hero: { height: 450, position: 'relative', }, heroImage: { width: '100%', height: '100%', resizeMode: 'cover', }, heroShade: { ...StyleSheet.absoluteFillObject, opacity: 0.18, }, heroBaseFade: { position: 'absolute', left: 0, right: 0, bottom: 0, height: 172, opacity: 0.95, borderTopLeftRadius: 28, borderTopRightRadius: 28, }, topActions: { position: 'absolute', top: 58, left: 22, right: 22, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', }, floatingAction: { width: 44, height: 44, borderRadius: 14, borderWidth: 1, justifyContent: 'center', alignItems: 'center', shadowColor: '#000', shadowOffset: { width: 0, height: 4 }, shadowOpacity: 0.15, shadowRadius: 10, elevation: 5, }, heroTitleWrap: { position: 'absolute', left: 24, right: 24, bottom: 74, }, heroName: { fontSize: 36, lineHeight: 40, fontWeight: '700', marginBottom: 6, }, heroBotanical: { fontSize: 16, fontStyle: 'italic', fontWeight: '600', opacity: 0.72, }, content: { marginTop: -46, paddingHorizontal: 16, gap: 20, }, waterCard: { borderRadius: 28, borderWidth: 1, paddingHorizontal: 16, paddingVertical: 14, flexDirection: 'row', alignItems: 'center', gap: 12, shadowColor: '#000', shadowOffset: { width: 0, height: 8 }, shadowOpacity: 0.08, shadowRadius: 16, elevation: 4, }, waterInfo: { flex: 1, gap: 2, }, waterHeadline: { flexDirection: 'row', alignItems: 'center', gap: 6, }, waterLabel: { fontSize: 11, textTransform: 'uppercase', letterSpacing: 0.8, fontWeight: '700', }, waterValue: { fontSize: 15, lineHeight: 19, fontWeight: '700', }, waterMeta: { fontSize: 12, fontWeight: '500', }, waterButton: { borderRadius: 16, paddingHorizontal: 20, paddingVertical: 13, flexDirection: 'row', alignItems: 'center', gap: 6, }, waterButtonText: { fontSize: 16, fontWeight: '700', }, careGrid: { flexDirection: 'row', gap: 10, }, careCard: { flex: 1, borderRadius: 22, borderWidth: 1, alignItems: 'center', justifyContent: 'center', paddingHorizontal: 8, paddingVertical: 16, gap: 6, }, careIconWrap: { width: 34, height: 34, borderRadius: 17, alignItems: 'center', justifyContent: 'center', }, careLabel: { fontSize: 10, fontWeight: '700', textTransform: 'uppercase', letterSpacing: 0.5, }, careValue: { width: '100%', fontSize: 12, lineHeight: 15, fontWeight: '700', textAlign: 'center', flexShrink: 1, }, reminderCard: { borderRadius: 24, borderWidth: 1, paddingHorizontal: 14, paddingVertical: 12, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', gap: 12, }, reminderInfoRow: { flexDirection: 'row', alignItems: 'center', gap: 10, flex: 1, }, reminderIconWrap: { width: 40, height: 40, borderRadius: 13, justifyContent: 'center', alignItems: 'center', }, reminderTitle: { fontSize: 14, fontWeight: '700', }, reminderSubtitle: { fontSize: 10, marginTop: 1, }, toggleTrack: { width: 54, height: 30, borderRadius: 999, justifyContent: 'center', position: 'relative', }, toggleThumb: { position: 'absolute', width: 22, height: 22, borderRadius: 11, backgroundColor: '#ffffff', }, summarySection: { gap: 8, }, summaryHeader: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', }, aiBadge: { borderRadius: 999, paddingHorizontal: 10, paddingVertical: 4, }, aiBadgeText: { fontSize: 10, fontWeight: '700', letterSpacing: 0.6, }, summaryCard: { borderRadius: 22, borderWidth: 1, padding: 16, }, summaryText: { fontSize: 14, lineHeight: 22, }, healthActionCard: { borderRadius: 22, borderWidth: 1, padding: 14, gap: 10, }, healthActionRow: { flexDirection: 'row', gap: 10, alignItems: 'center', }, healthActionInfo: { flex: 1, }, healthActionTitle: { fontSize: 14, fontWeight: '700', }, healthActionMeta: { fontSize: 11, marginTop: 2, }, healthActionBtn: { borderRadius: 14, borderWidth: 1, paddingHorizontal: 12, paddingVertical: 10, flexDirection: 'row', alignItems: 'center', gap: 6, }, healthActionBtnText: { fontSize: 12, fontWeight: '700', }, healthMetaRow: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', }, healthMetaText: { fontSize: 12, fontWeight: '500', }, healthInlineWrap: { gap: 8, }, healthInlineText: { fontSize: 12, fontWeight: '600', }, healthPlanButton: { alignSelf: 'flex-start', borderWidth: 1, borderRadius: 12, paddingHorizontal: 10, paddingVertical: 7, }, healthPlanButtonText: { fontSize: 12, fontWeight: '700', }, healthResultCard: { borderRadius: 22, borderWidth: 1, padding: 14, gap: 12, }, healthResultHead: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', }, healthResultTitle: { fontSize: 11, textTransform: 'uppercase', letterSpacing: 0.5, fontWeight: '700', }, healthResultScore: { fontSize: 26, lineHeight: 30, fontWeight: '800', marginTop: 2, }, healthStatusBadge: { borderRadius: 999, paddingHorizontal: 10, paddingVertical: 5, }, healthStatusBadgeText: { fontSize: 11, fontWeight: '700', }, healthTimestamp: { fontSize: 11, }, healthListBlock: { gap: 8, }, healthAnalysisBox: { borderRadius: 16, borderWidth: 1, padding: 12, gap: 6, }, healthAnalysisText: { fontSize: 12, lineHeight: 19, }, healthListTitle: { fontSize: 13, fontWeight: '700', }, healthIssueWrap: { gap: 3, }, healthIssueHead: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', gap: 8, }, healthIssueTitle: { fontSize: 13, fontWeight: '600', flex: 1, }, healthIssueConfidence: { fontSize: 11, fontWeight: '700', }, healthIssueDetails: { fontSize: 12, lineHeight: 18, }, healthBulletRow: { flexDirection: 'row', alignItems: 'flex-start', gap: 8, }, healthBulletDot: { width: 7, height: 7, borderRadius: 4, marginTop: 5, }, healthBulletText: { flex: 1, fontSize: 12, lineHeight: 18, }, sectionHeaderRow: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 10, marginTop: 4, }, sectionTitle: { fontSize: 18, fontWeight: '700', }, timelineCard: { borderRadius: 22, borderWidth: 1, paddingHorizontal: 14, paddingTop: 16, paddingBottom: 10, gap: 4, }, historyEmpty: { width: '100%', alignItems: 'center', justifyContent: 'center', gap: 8, minHeight: 96, paddingVertical: 20, }, historyEmptyText: { fontSize: 13, textAlign: 'center', }, timelineRow: { flexDirection: 'row', alignItems: 'flex-start', gap: 10, }, timelineMarkerColumn: { width: 20, alignItems: 'center', }, timelineDot: { width: 11, height: 11, borderRadius: 6, borderWidth: 2, }, timelineLine: { width: 2, flex: 1, marginTop: 3, minHeight: 26, borderRadius: 2, }, timelineContent: { flex: 1, paddingBottom: 14, }, timelineTopRow: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', gap: 10, }, timelineDate: { fontSize: 14, fontWeight: '700', }, timelineType: { fontSize: 10, textTransform: 'uppercase', letterSpacing: 0.45, fontWeight: '600', }, timelineTime: { fontSize: 12, marginTop: 3, }, galleryHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12, }, addPhotoBtn: { flexDirection: 'row', alignItems: 'center', gap: 5, borderWidth: 1, borderRadius: 18, paddingHorizontal: 10, paddingVertical: 6, }, addPhotoBtnText: { fontSize: 13, fontWeight: '600', }, galleryEmpty: { borderRadius: 18, borderWidth: 1, paddingVertical: 22, alignItems: 'center', justifyContent: 'center', gap: 8, }, galleryScroll: { marginBottom: 2, }, galleryContent: { gap: 12, paddingRight: 20, }, galleryThumb: { width: 96, height: 96, borderRadius: 18, }, deleteAction: { alignSelf: 'center', marginTop: 4, marginBottom: 12, flexDirection: 'row', alignItems: 'center', gap: 6, paddingHorizontal: 8, paddingVertical: 6, }, deleteActionText: { fontSize: 13, fontWeight: '600', }, modalOverlay: { flex: 1, justifyContent: 'center', alignItems: 'center', padding: 24, }, modalCard: { width: '100%', maxWidth: 340, borderRadius: 24, padding: 22, }, modalIcon: { width: 48, height: 48, borderRadius: 24, justifyContent: 'center', alignItems: 'center', alignSelf: 'center', marginBottom: 14, }, modalTitle: { fontSize: 18, fontWeight: '700', textAlign: 'center', marginBottom: 8, }, modalMessage: { fontSize: 13, lineHeight: 20, textAlign: 'center', marginBottom: 20, }, modalActions: { flexDirection: 'row', gap: 10, }, modalButton: { flex: 1, paddingVertical: 14, borderRadius: 14, alignItems: 'center', }, modalButtonText: { fontSize: 13, fontWeight: '700', }, fullscreenOverlay: { flex: 1, backgroundColor: '#000000ee', justifyContent: 'center', alignItems: 'center', }, fullscreenImage: { width: '90%', height: '72%', resizeMode: 'contain', }, fullscreenClose: { position: 'absolute', top: 56, right: 20, backgroundColor: '#00000088', borderRadius: 20, padding: 8, }, paywallOverlay: { flex: 1, backgroundColor: '#000000aa', justifyContent: 'flex-end', }, paywallContent: { borderTopLeftRadius: 32, borderTopRightRadius: 32, padding: 24, paddingBottom: 48, borderTopWidth: 1, }, paywallHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 20, }, paywallIconWrap: { width: 64, height: 64, borderRadius: 20, justifyContent: 'center', alignItems: 'center', }, paywallClose: { padding: 4, }, paywallTitle: { fontSize: 24, fontWeight: '800', marginBottom: 8, letterSpacing: 0.2, }, paywallSubtitle: { fontSize: 15, lineHeight: 22, marginBottom: 28, }, paywallFeatures: { gap: 18, marginBottom: 32, }, paywallFeatureRow: { flexDirection: 'row', gap: 14, alignItems: 'center', }, paywallFeatureIcon: { width: 38, height: 38, borderRadius: 12, justifyContent: 'center', alignItems: 'center', }, paywallFeatureTitle: { fontSize: 15, fontWeight: '700', marginBottom: 2, }, paywallFeatureDesc: { fontSize: 13, lineHeight: 18, }, paywallPrimaryBtn: { borderRadius: 18, paddingVertical: 16, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: 8, shadowOpacity: 0.2, shadowRadius: 10, shadowOffset: { width: 0, height: 4 }, elevation: 4, }, paywallPrimaryBtnText: { fontSize: 17, fontWeight: '700', }, paywallSecondaryBtn: { marginTop: 12, paddingVertical: 12, alignItems: 'center', }, paywallSecondaryBtnText: { fontSize: 14, fontWeight: '600', }, });