import React, { useState, useEffect, useRef } from 'react'; import { View, Text, StyleSheet, ScrollView, TouchableOpacity, Modal, TextInput, KeyboardAvoidingView, Platform, SafeAreaView, Animated, Linking, Alert, Share, } from 'react-native'; import { LinearGradient } from 'expo-linear-gradient'; import { Ionicons, Feather, MaterialCommunityIcons, FontAwesome5 } from '@expo/vector-icons'; import { captureRef } from 'react-native-view-shot'; import AsyncStorage from '@react-native-async-storage/async-storage'; import * as bip39 from 'bip39'; import { colors, typography, spacing, borderRadius, shadows } from '../theme/colors'; import { VaultAsset, VaultAssetType, Heir } from '../types'; import BiometricModal from '../components/common/BiometricModal'; import { useAuth } from '../context/AuthContext'; import { useVaultAssets } from '../hooks/useVaultAssets'; // Asset type configuration with nautical theme const assetTypeConfig: Record = { game_account: { icon: 'account-key', iconType: 'material', label: 'Account Login' }, private_key: { icon: 'key', iconType: 'fontawesome5', label: 'Secret Key' }, document: { icon: 'scroll', iconType: 'fontawesome5', label: 'Document' }, photo: { icon: 'image', iconType: 'ionicons', label: 'Sealed Photo' }, will: { icon: 'file-signature', iconType: 'fontawesome5', label: 'Testament' }, custom: { icon: 'gem', iconType: 'fontawesome5', label: 'Treasure' }, }; const accountProviderOptions = [ { key: 'bank', label: 'Bank', icon: 'bank', iconType: 'material' as const }, { key: 'steam', label: 'Steam', icon: 'steam', iconType: 'fontawesome5' as const }, { key: 'facebook', label: 'Facebook', icon: 'facebook-f', iconType: 'fontawesome5' as const }, { key: 'custom', label: 'Other', icon: 'shield-account', iconType: 'material' as const }, ]; const initialHeirs: Heir[] = [ { id: '1', name: 'John Smith', email: 'john.smith@email.com', phone: '+1 415 555 0132', status: 'confirmed', releaseLevel: 3, releaseOrder: 1, paymentStrategy: 'prepaid', }, { id: '2', name: 'Jane Doe', email: 'jane.doe@email.com', phone: '+1 212 555 0184', status: 'confirmed', releaseLevel: 2, releaseOrder: 2, paymentStrategy: 'pay_on_access', }, { id: '3', name: 'Alice Johnson', email: 'alice.j@email.com', phone: '+1 646 555 0149', status: 'invited', releaseLevel: 1, releaseOrder: 3, paymentStrategy: 'pay_on_access', }, ]; const generateMnemonic = () => bip39.generateMnemonic(128).split(' '); const splitMnemonic = (words: string[]) => [ words.slice(0, 4), words.slice(4, 8), words.slice(8, 12), ]; type HeirAssignment = { asset: VaultAsset; heir: Heir; }; // Mock data // const initialAssets: VaultAsset[] = [ // { // id: '1', // type: 'private_key', // label: 'ETH Main Wallet Key', // createdAt: new Date('2024-01-10'), // updatedAt: new Date('2024-01-10'), // isEncrypted: true, // }, // { // id: '2', // type: 'game_account', // label: 'Steam Account Credentials', // createdAt: new Date('2024-01-08'), // updatedAt: new Date('2024-01-08'), // isEncrypted: true, // }, // { // id: '3', // type: 'document', // label: 'Insurance Policy Scan', // createdAt: new Date('2024-01-05'), // updatedAt: new Date('2024-01-05'), // isEncrypted: true, // }, // { // id: '4', // type: 'will', // label: 'Testament Draft v2', // createdAt: new Date('2024-01-02'), // updatedAt: new Date('2024-01-15'), // isEncrypted: true, // }, // ]; const renderAssetTypeIcon = (config: typeof assetTypeConfig[VaultAssetType], size: number, color: string) => { switch (config.iconType) { case 'ionicons': return ; case 'feather': return ; case 'material': return ; case 'fontawesome5': return ; } }; export default function VaultScreen() { const [isUnlocked, setIsUnlocked] = useState(false); const [showBiometric, setShowBiometric] = useState(false); const { assets, setAssets, refreshAssets, createAsset: createVaultAsset, isSealing, createError: addError, clearCreateError: clearAddError, } = useVaultAssets(isUnlocked); const [showAddModal, setShowAddModal] = useState(false); const [selectedType, setSelectedType] = useState('custom'); const [newLabel, setNewLabel] = useState(''); const [showUploadSuccess, setShowUploadSuccess] = useState(false); const [fadeAnim] = useState(new Animated.Value(0)); const [pulseAnim] = useState(new Animated.Value(1)); const [selectedAsset, setSelectedAsset] = useState(null); const [showDetail, setShowDetail] = useState(false); const [showGuardedBiometric, setShowGuardedBiometric] = useState(false); const [showKeyPreview, setShowKeyPreview] = useState(false); const [addStep, setAddStep] = useState(1); const [addMethod, setAddMethod] = useState<'text' | 'file' | 'scan'>('text'); const [addVerified, setAddVerified] = useState(false); const [rehearsalConfirmed, setRehearsalConfirmed] = useState(false); const [showAddBiometric, setShowAddBiometric] = useState(false); const [accountProvider, setAccountProvider] = useState<'bank' | 'steam' | 'facebook' | 'custom'>('bank'); const [showMnemonic, setShowMnemonic] = useState(false); const [showLegacyAssignCta, setShowLegacyAssignCta] = useState(false); const [mnemonicWords, setMnemonicWords] = useState([]); const [mnemonicParts, setMnemonicParts] = useState([]); const [mnemonicStep, setMnemonicStep] = useState<1 | 2 | 3 | 4 | 5>(1); const [heirStep, setHeirStep] = useState<'decision' | 'asset' | 'heir' | 'summary'>('decision'); const [selectedHeir, setSelectedHeir] = useState(null); const [selectedHeirAsset, setSelectedHeirAsset] = useState(null); const [assignments, setAssignments] = useState([]); const [replaceIndex, setReplaceIndex] = useState(null); const [replaceQuery, setReplaceQuery] = useState(''); const [progressIndex, setProgressIndex] = useState(0); const [progressAnim] = useState(new Animated.Value(0)); const { user, token } = useAuth(); const [isCapturing, setIsCapturing] = useState(false); const [treasureContent, setTreasureContent] = useState(''); const mnemonicRef = useRef(null); const progressTimerRef = useRef | null>(null); useEffect(() => { if (!isUnlocked) { const timer = setTimeout(() => { setShowBiometric(true); }, 500); return () => clearTimeout(timer); } }, []); useEffect(() => { if (isUnlocked) { Animated.timing(fadeAnim, { toValue: 1, duration: 600, useNativeDriver: true, }).start(); } }, [isUnlocked]); useEffect(() => { if (!isUnlocked) { Animated.loop( Animated.sequence([ Animated.timing(pulseAnim, { toValue: 1.05, duration: 1500, useNativeDriver: true, }), Animated.timing(pulseAnim, { toValue: 1, duration: 1500, useNativeDriver: true, }), ]) ).start(); } }, [isUnlocked]); const handleUnlock = () => { setShowBiometric(false); const words = generateMnemonic(); const parts = splitMnemonic(words); setMnemonicWords(words); setMnemonicParts(parts); setReplaceIndex(null); setReplaceQuery(''); setMnemonicStep(1); setHeirStep('decision'); setSelectedHeir(null); setSelectedHeirAsset(null); setProgressIndex(0); progressAnim.setValue(0); setTimeout(() => setShowMnemonic(true), 200); AsyncStorage.setItem('sentinel_mnemonic_part_local', parts[0].join(' ')).catch(() => { // Best-effort local store; UI remains available }); }; const handleScreenshot = async () => { try { setIsCapturing(true); const uri = await captureRef(mnemonicRef, { format: 'png', quality: 1, result: Platform.OS === 'web' ? 'data-uri' : 'tmpfile', }); if (Platform.OS === 'web') { try { await Linking.openURL(uri); } catch { // Ignore if the browser blocks data-uri navigation. } } else { await Share.share({ url: uri, message: 'Sentinel key backup', }); } setMnemonicStep(4); } catch (error) { Alert.alert('Screenshot failed', 'Please try again or use email backup.'); } finally { setIsCapturing(false); } }; const handleEmailBackup = () => { // Proceed immediately; email delivery is handled separately. setMnemonicStep(4); setShowMnemonic(true); }; const handleReplaceWord = (word: string) => { if (replaceIndex === null) return; const nextWords = [...mnemonicWords]; nextWords[replaceIndex] = word; setMnemonicWords(nextWords); setMnemonicParts(splitMnemonic(nextWords)); setReplaceIndex(null); setReplaceQuery(''); }; useEffect(() => { if (mnemonicStep !== 4) { if (progressTimerRef.current) { clearInterval(progressTimerRef.current); progressTimerRef.current = null; } return; } const messagesCount = 5; let current = 0; setProgressIndex(current); progressAnim.setValue(0); progressTimerRef.current = setInterval(() => { current += 1; if (current >= messagesCount) { if (progressTimerRef.current) { clearInterval(progressTimerRef.current); progressTimerRef.current = null; } setMnemonicStep(5); return; } setProgressIndex(current); Animated.timing(progressAnim, { toValue: current / (messagesCount - 1), duration: 700, useNativeDriver: false, }).start(); }, 1100); Animated.timing(progressAnim, { toValue: 1 / (messagesCount - 1), duration: 700, useNativeDriver: false, }).start(); return () => { if (progressTimerRef.current) { clearInterval(progressTimerRef.current); progressTimerRef.current = null; } }; }, [mnemonicStep, progressAnim]); const handleHeirDecision = (share: boolean) => { // Placeholder for future heir flow setShowMnemonic(false); setIsUnlocked(true); }; const handleSubmitAssignment = () => { // Placeholder for submitting assignment to API setShowMnemonic(false); setIsUnlocked(true); }; const handleHeirYes = () => { setShowMnemonic(false); setIsUnlocked(true); setShowLegacyAssignCta(true); }; const handleHeirNo = () => { setShowMnemonic(false); setIsUnlocked(true); setShowLegacyAssignCta(true); }; const handleOpenLegacyAssign = () => { setSelectedHeir(null); setSelectedHeirAsset(null); setHeirStep('asset'); setMnemonicStep(5); setShowMnemonic(true); }; const handleSelectHeirAsset = (asset: VaultAsset) => { setSelectedHeirAsset(asset); setHeirStep('heir'); }; const handleSelectHeir = (heir: Heir) => { setSelectedHeir(heir); setHeirStep('summary'); }; const resetAddFlow = () => { setAddStep(1); setAddMethod('text'); setAddVerified(false); setRehearsalConfirmed(false); setSelectedType('custom'); setNewLabel(''); setAccountProvider('bank'); }; const handleAddAsset = async () => { if (!newLabel.trim() || !treasureContent.trim()) return; if (!addVerified) return; if (selectedType === 'private_key' && !rehearsalConfirmed) return; if (!token) { Alert.alert('Not logged in', 'Please sign in first to add a Treasure.'); return; } const result = await createVaultAsset({ title: newLabel.trim(), content: treasureContent.trim(), }); if (result.success) { setNewLabel(''); setTreasureContent(''); setSelectedType('custom'); setAddVerified(false); setRehearsalConfirmed(false); setShowAddModal(false); clearAddError(); setShowUploadSuccess(true); setTimeout(() => setShowUploadSuccess(false), 2500); if (typeof Alert !== 'undefined' && Alert.alert) { Alert.alert('Success', 'Treasure sealed and saved successfully.'); } return; } if (result.isUnauthorized) { setShowAddModal(false); clearAddError(); if (typeof Alert !== 'undefined' && Alert.alert) { Alert.alert( 'Unauthorized', 'Your session has expired or you are not logged in. Please sign in again.', [{ text: 'OK' }] ); } return; } if (result.error && typeof Alert !== 'undefined' && Alert.alert) { Alert.alert('Failed', result.error); } }; const formatDate = (date: Date) => { return date.toLocaleDateString('en-US', { year: 'numeric', month: 'short', day: 'numeric', }); }; const handleOpenDetail = (asset: VaultAsset) => { setSelectedAsset(asset); setShowDetail(true); setShowKeyPreview(false); }; const handleCloseDetail = () => { setShowDetail(false); setSelectedAsset(null); setShowKeyPreview(false); setShowGuardedBiometric(false); }; const handleGuardedAccess = () => { setShowGuardedBiometric(true); }; const handleGuardedSuccess = () => { setShowGuardedBiometric(false); setShowKeyPreview(true); }; const handleAddVerification = () => { setShowAddBiometric(true); }; const handleAddVerificationSuccess = () => { setShowAddBiometric(false); setAddVerified(true); }; const openProviderLogin = async () => { if (accountProvider === 'bank') { Alert.alert( 'Bank App Needed', 'Provide the bank app deep link scheme to enable one-tap login.' ); return; } const providerLinks = { steam: { app: 'steam://openurl/https://store.steampowered.com/login/', web: 'https://store.steampowered.com/login/', }, facebook: { app: 'fb://facewebmodal/f?href=https://www.facebook.com/login', web: 'https://www.facebook.com/login', }, custom: { app: '', web: '', }, } as const; const target = providerLinks[accountProvider]; if (!target?.app) { return; } const canOpen = await Linking.canOpenURL(target.app); if (canOpen) { await Linking.openURL(target.app); } else if (target.web) { await Linking.openURL(target.web); } }; const selectedConfig = selectedAsset ? assetTypeConfig[selectedAsset.type] : null; const detailHeading = selectedAsset?.type === 'private_key' ? 'Key Material' : selectedConfig?.label || 'Vault Asset'; const detailMetaLabel = selectedAsset?.type === 'private_key' ? 'KEY MATERIAL' : 'ASSET CLASS'; const detailMetaValue = selectedAsset?.type === 'private_key' ? '12/24 Words' : selectedConfig?.label || '--'; const canSeal = !!newLabel.trim() && !!treasureContent.trim() && addVerified && !isSealing && (selectedType !== 'private_key' || rehearsalConfirmed); const mnemonicModal = ( setShowMnemonic(false)} > setShowMnemonic(false)} activeOpacity={0.85} > Mnemonic Setup {mnemonicStep === 1 ? ( <> Review your 12-word mnemonic. Tap any word to replace it. {mnemonicWords.map((word, index) => ( setReplaceIndex(index)} activeOpacity={0.8} > {index + 1} {word} ))} {replaceIndex !== null ? ( Replace word {replaceIndex + 1} {(replaceQuery ? bip39.wordlists.english.filter((word) => word.startsWith(replaceQuery.toLowerCase()) ) : bip39.wordlists.english ) .slice(0, 24) .map((word) => ( handleReplaceWord(word)} activeOpacity={0.8} > {word} ))} setReplaceIndex(null)} activeOpacity={0.85} > CANCEL ) : null} setMnemonicStep(2)} activeOpacity={0.85} > NEXT ) : null} {mnemonicStep === 2 ? ( <> Confirm your 12-word mnemonic. {mnemonicWords.join(' ')} setMnemonicStep(3)} activeOpacity={0.85} > CONFIRM setMnemonicStep(1)} activeOpacity={0.85} > EDIT SELECTION ) : null} {mnemonicStep === 3 ? ( <> Back up your mnemonic before entering the Vault. {mnemonicWords.join(' ')} {isCapturing ? 'CAPTURING...' : 'PHYSICAL BACKUP (SCREENSHOT)'} EMAIL BACKUP ) : null} {mnemonicStep === 4 ? ( <> Finalizing your vault protection. {progressIndex === 0 && '1. Your key is being processed'} {progressIndex === 1 && '2. Your key has been split'} {progressIndex === 2 && '3. Part one stored on this device'} {progressIndex === 3 && '4. Part two uploaded to the cloud'} {progressIndex >= 4 && '5. Part three inquiry initiated'} ) : null} {mnemonicStep === 5 ? ( <> {heirStep === 'decision' ? ( <> Share Part Three with your legacy handler? YES, SEND NOT NOW ) : null} {heirStep === 'asset' ? ( <> Select the vault item to assign. {assets.map((asset) => { const config = assetTypeConfig[asset.type]; return ( handleSelectHeirAsset(asset)} activeOpacity={0.8} > {renderAssetTypeIcon(config, 18, colors.vault.primary)} {asset.label} {config.label} ); })} setHeirStep('decision')} activeOpacity={0.85} > BACK ) : null} {heirStep === 'heir' ? ( <> Choose a legacy handler. {initialHeirs.map((heir) => ( handleSelectHeir(heir)} activeOpacity={0.8} > {heir.name} {heir.email} ))} setHeirStep('asset')} activeOpacity={0.85} > BACK ) : null} {heirStep === 'summary' ? ( <> Confirm assignment details. Vault Item {selectedHeirAsset?.label} Legacy Handler {selectedHeir?.name} {selectedHeir?.email} Release Tier Tier {selectedHeir?.releaseLevel} SUBMIT setHeirStep('heir')} activeOpacity={0.85} > EDIT ) : null} ) : null} ); // Lock screen const lockScreen = ( THE DEEP VAULT Where treasures rest in silence setShowBiometric(true)} activeOpacity={0.8} > Captain's Verification setShowBiometric(false)} title="Enter the Vault" message="Verify your identity to access your treasures" isDark /> ); const vaultScreen = ( {/* Header */} THE VAULT SEALED {assets.length} treasures · Encrypted at rest {showLegacyAssignCta && ( Legacy Assignment Continue assigning a vault item to your legacy handler. Continue )} {/* Asset List */} {assets.map((asset) => { const config = assetTypeConfig[asset.type]; return ( handleOpenDetail(asset)} > {renderAssetTypeIcon(config, 22, colors.vault.primary)} {config.label} {asset.label} Sealed {formatDate(asset.createdAt)} ); })} {/* Add Button */} { resetAddFlow(); clearAddError(); setShowAddModal(true); }} activeOpacity={0.9} > Add Treasure {/* Upload Success Toast */} {showUploadSuccess && ( Treasure sealed successfully )} {/* Add Modal */} setShowAddModal(false)} > Add New Treasure {['Title', 'Content', 'Verify'].map((label, index) => { const stepIndex = index + 1; const isActive = addStep === stepIndex; const isDone = addStep > stepIndex; return ( {stepIndex} {label} ); })} {addStep === 1 && ( <> TREASURE TITLE TREASURE TYPE {(Object.keys(assetTypeConfig) as VaultAssetType[]).map((type) => { const config = assetTypeConfig[type]; const isSelected = selectedType === type; return ( setSelectedType(type)} > {renderAssetTypeIcon(config, 22, isSelected ? colors.nautical.teal : colors.nautical.sage)} {config.label} ); })} )} {addStep === 2 && ( <> {selectedType !== 'game_account' && ( <> CAPTURE METHOD {[ { key: 'text', label: 'Text', icon: 'text' }, { key: 'file', label: 'File', icon: 'file-tray' }, { key: 'scan', label: 'Scan', icon: 'camera' }, ].map((item) => { const isActive = addMethod === item.key; return ( setAddMethod(item.key as typeof addMethod)} > {item.label} ); })} CONTENT Data is encrypted on-device. Plaintext is shredded after sealing. )} {selectedType === 'game_account' && ( <> ACCOUNT PROVIDER {accountProviderOptions.map((option) => { const isSelected = accountProvider === option.key; return ( setAccountProvider(option.key as typeof accountProvider)} > {renderAssetTypeIcon( { icon: option.icon, iconType: option.iconType, label: option.label }, 22, isSelected ? colors.nautical.teal : colors.nautical.sage )} {option.label} ); })} Open App to Login TREASURE NAME )} )} {addStep === 3 && ( <> IDENTITY VERIFICATION Biometric required before sealing. {addVerified ? 'Verified' : 'Verify Now'} {selectedType === 'private_key' && ( setRehearsalConfirmed(!rehearsalConfirmed)} activeOpacity={0.8} > I rehearsed the mnemonic once (required). )} Only a masked shard can be revealed, and access is time-limited. )} {addError ? ( {addError} ) : null} { if (addStep === 1) { setShowAddModal(false); setTreasureContent(''); clearAddError(); } else { setAddStep(addStep - 1); clearAddError(); } }} > {addStep === 1 ? 'Cancel' : 'Back'} {addStep < 3 ? ( setAddStep(addStep + 1)} > Continue ) : ( {isSealing ? 'Sealing...' : 'Seal Treasure'} )} setShowAddBiometric(false)} title="Confirm Identity" message="Verify before sealing this treasure" isDark /> {/* Detail Modal */} {detailHeading} {selectedAsset?.type === 'private_key' && ( HIGH-RISK )} SEALED ASSET {selectedAsset?.label} Encrypted at rest · No plaintext stored CREATED {selectedAsset ? formatDate(selectedAsset.createdAt) : '--'} LAST VERIFIED {selectedAsset ? formatDate(selectedAsset.updatedAt) : '--'} STORAGE Cipher Pack {detailMetaLabel} {detailMetaValue} CONTROLLED ACTIONS View Encrypted Digest Export Cipher Pack Reset Sentinel Timer Guarded Reveal Plaintext access requires biometric verification and a memory rehearsal step. Begin Verification {showKeyPreview && ( MNEMONIC SHARD (MASKED) ocean-anchored-ember-veil )} Any reveal attempt is time-limited and logged. Screenshots are blocked by policy. setShowGuardedBiometric(false)} title="Verify Access" message="Confirm to reveal a masked shard of the mnemonic" isDark /> ); return ( {isUnlocked ? vaultScreen : lockScreen} {mnemonicModal} ); } const styles = StyleSheet.create({ root: { flex: 1, }, container: { flex: 1, }, gradient: { flex: 1, }, safeArea: { flex: 1, }, content: { flex: 1, }, lockContainer: { flex: 1, }, lockGradient: { flex: 1, }, lockSafeArea: { flex: 1, }, lockContent: { flex: 1, justifyContent: 'center', alignItems: 'center', paddingHorizontal: spacing.xl, }, lockIconContainer: { marginBottom: spacing.lg, }, lockIconGradient: { width: 130, height: 130, borderRadius: 65, justifyContent: 'center', alignItems: 'center', ...shadows.glow, }, lockTitle: { fontSize: typography.fontSize.xxl, fontWeight: '700', color: colors.vault.text, letterSpacing: typography.letterSpacing.widest, marginBottom: spacing.sm, fontFamily: typography.fontFamily.serif, }, lockSubtitle: { fontSize: typography.fontSize.base, color: colors.vault.textSecondary, marginBottom: spacing.xl, textAlign: 'center', fontStyle: 'italic', }, waveContainer: { marginBottom: spacing.xl, }, unlockButton: { borderRadius: borderRadius.lg, overflow: 'hidden', }, unlockButtonGradient: { flexDirection: 'row', alignItems: 'center', paddingVertical: spacing.md, paddingHorizontal: spacing.xl, gap: spacing.sm, }, unlockButtonText: { fontSize: typography.fontSize.base, color: colors.vault.background, fontWeight: '600', }, header: { paddingHorizontal: spacing.lg, paddingTop: spacing.lg, paddingBottom: spacing.md, }, headerTop: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: spacing.xs, }, headerTitleRow: { flexDirection: 'row', alignItems: 'center', gap: spacing.sm, }, title: { fontSize: typography.fontSize.xl, fontWeight: '700', color: colors.vault.text, letterSpacing: typography.letterSpacing.wider, fontFamily: typography.fontFamily.serif, }, securityBadge: { flexDirection: 'row', alignItems: 'center', backgroundColor: `${colors.vault.success}20`, paddingHorizontal: spacing.sm, paddingVertical: spacing.xs, borderRadius: borderRadius.full, gap: spacing.xs, }, securityText: { fontSize: typography.fontSize.xs, color: colors.vault.success, fontWeight: '700', letterSpacing: 1, }, subtitle: { fontSize: typography.fontSize.sm, color: colors.vault.textSecondary, }, legacyCtaCard: { marginHorizontal: spacing.lg, marginBottom: spacing.sm, padding: spacing.md, borderRadius: borderRadius.lg, backgroundColor: colors.vault.cardBackground, borderWidth: 1, borderColor: colors.vault.cardBorder, flexDirection: 'row', alignItems: 'center', gap: spacing.md, }, legacyCtaInfo: { flex: 1, }, legacyCtaTitle: { color: colors.vault.text, fontSize: typography.fontSize.base, fontWeight: '700', }, legacyCtaText: { color: colors.vault.textSecondary, fontSize: typography.fontSize.sm, marginTop: spacing.xs, }, legacyCtaButton: { paddingHorizontal: spacing.md, paddingVertical: spacing.sm, borderRadius: borderRadius.full, backgroundColor: colors.vault.primary, }, legacyCtaButtonText: { color: colors.vault.background, fontWeight: '700', fontSize: typography.fontSize.sm, }, assetList: { flex: 1, }, assetListContent: { padding: spacing.lg, paddingTop: spacing.sm, }, assetCard: { flexDirection: 'row', alignItems: 'center', backgroundColor: colors.vault.cardBackground, borderRadius: borderRadius.xl, padding: spacing.base, marginBottom: spacing.md, borderWidth: 1, borderColor: colors.vault.cardBorder, }, assetIconContainer: { width: 52, height: 52, borderRadius: 26, backgroundColor: `${colors.vault.primary}15`, justifyContent: 'center', alignItems: 'center', marginRight: spacing.base, }, assetInfo: { flex: 1, }, assetType: { fontSize: typography.fontSize.xs, color: colors.vault.textSecondary, textTransform: 'uppercase', letterSpacing: 1, marginBottom: 2, fontWeight: '600', }, assetLabel: { fontSize: typography.fontSize.base, color: colors.vault.text, fontWeight: '600', marginBottom: 4, }, assetMetaRow: { flexDirection: 'row', alignItems: 'center', gap: spacing.xs, }, assetMeta: { fontSize: typography.fontSize.xs, color: colors.vault.textSecondary, }, encryptedBadge: { width: 36, height: 36, borderRadius: 18, backgroundColor: colors.vault.success, justifyContent: 'center', alignItems: 'center', }, addButton: { position: 'absolute', bottom: 100, left: spacing.lg, right: spacing.lg, borderRadius: borderRadius.lg, overflow: 'hidden', }, addButtonGradient: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', paddingVertical: spacing.md, gap: spacing.sm, }, addButtonText: { fontSize: typography.fontSize.base, color: colors.vault.background, fontWeight: '700', }, successToast: { position: 'absolute', bottom: 170, left: spacing.lg, right: spacing.lg, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', backgroundColor: colors.vault.success, paddingVertical: spacing.md, borderRadius: borderRadius.lg, gap: spacing.sm, }, successText: { fontSize: typography.fontSize.base, color: '#fff', fontWeight: '600', }, modalOverlay: { flex: 1, backgroundColor: 'rgba(26, 58, 74, 0.8)', justifyContent: 'flex-end', }, modalContent: { backgroundColor: colors.nautical.cream, borderTopLeftRadius: borderRadius.xxl, borderTopRightRadius: borderRadius.xxl, padding: spacing.lg, paddingBottom: spacing.xxl, }, modalHandle: { width: 40, height: 4, backgroundColor: colors.nautical.lightMint, borderRadius: 2, alignSelf: 'center', marginBottom: spacing.lg, }, modalHeader: { flexDirection: 'row', alignItems: 'center', gap: spacing.sm, marginBottom: spacing.lg, }, modalTitle: { fontSize: typography.fontSize.lg, fontWeight: '600', color: colors.nautical.navy, }, stepRow: { flexDirection: 'row', justifyContent: 'space-between', marginBottom: spacing.lg, }, stepItem: { alignItems: 'center', flex: 1, }, stepCircle: { width: 28, height: 28, borderRadius: 14, borderWidth: 1, borderColor: colors.nautical.lightMint, alignItems: 'center', justifyContent: 'center', backgroundColor: colors.nautical.paleAqua, }, stepCircleActive: { borderColor: colors.nautical.teal, backgroundColor: colors.nautical.lightMint, }, stepCircleDone: { borderColor: colors.nautical.teal, backgroundColor: colors.nautical.teal, }, stepNumber: { fontSize: typography.fontSize.xs, color: colors.nautical.sage, fontWeight: '600', }, stepNumberActive: { color: colors.nautical.teal, }, stepNumberDone: { color: colors.nautical.cream, }, stepLabel: { fontSize: typography.fontSize.xs, color: colors.nautical.sage, marginTop: spacing.xs, }, stepLabelActive: { color: colors.nautical.teal, fontWeight: '600', }, modalLabel: { fontSize: typography.fontSize.xs, color: colors.nautical.sage, marginBottom: spacing.sm, letterSpacing: typography.letterSpacing.wider, fontWeight: '600', }, methodRow: { flexDirection: 'row', gap: spacing.sm, marginBottom: spacing.lg, }, methodButton: { flex: 1, paddingVertical: spacing.sm, borderRadius: borderRadius.lg, alignItems: 'center', gap: spacing.xs, backgroundColor: colors.nautical.paleAqua, borderWidth: 1, borderColor: colors.nautical.lightMint, }, methodButtonActive: { borderColor: colors.nautical.teal, backgroundColor: colors.nautical.lightMint, }, methodLabel: { fontSize: typography.fontSize.sm, color: colors.nautical.sage, fontWeight: '600', }, methodLabelActive: { color: colors.nautical.teal, }, loginButton: { marginTop: spacing.sm, flexDirection: 'row', alignItems: 'center', justifyContent: 'center', gap: spacing.sm, backgroundColor: colors.nautical.teal, paddingVertical: spacing.sm, borderRadius: borderRadius.full, }, loginButtonText: { color: colors.nautical.cream, fontSize: typography.fontSize.sm, fontWeight: '700', letterSpacing: 0.6, }, typeScroll: { marginBottom: spacing.lg, }, typeScrollContent: { gap: spacing.sm, }, typeButton: { alignItems: 'center', paddingVertical: spacing.sm, paddingHorizontal: spacing.base, borderRadius: borderRadius.lg, backgroundColor: colors.nautical.paleAqua, borderWidth: 2, borderColor: 'transparent', minWidth: 100, }, typeButtonActive: { borderColor: colors.nautical.teal, backgroundColor: colors.nautical.lightMint, }, typeIconContainer: { width: 44, height: 44, borderRadius: 22, backgroundColor: colors.nautical.cream, justifyContent: 'center', alignItems: 'center', marginBottom: spacing.xs, }, typeIconContainerActive: { backgroundColor: `${colors.nautical.teal}15`, }, typeButtonLabel: { fontSize: typography.fontSize.xs, color: colors.nautical.sage, textAlign: 'center', fontWeight: '500', }, typeButtonLabelActive: { color: colors.nautical.teal, fontWeight: '600', }, input: { backgroundColor: colors.nautical.paleAqua, borderRadius: borderRadius.lg, padding: spacing.base, fontSize: typography.fontSize.base, color: colors.nautical.navy, marginBottom: spacing.md, borderWidth: 1, borderColor: colors.nautical.lightMint, }, inputMultiline: { minHeight: 120, paddingTop: spacing.base, }, encryptionNote: { flexDirection: 'row', alignItems: 'center', backgroundColor: colors.nautical.lightMint, borderRadius: borderRadius.lg, padding: spacing.md, marginBottom: spacing.lg, gap: spacing.sm, }, encryptionNoteText: { flex: 1, fontSize: typography.fontSize.sm, color: colors.nautical.teal, lineHeight: typography.fontSize.sm * 1.4, }, addErrorBox: { flexDirection: 'row', alignItems: 'center', backgroundColor: 'rgba(194, 65, 12, 0.12)', borderRadius: borderRadius.lg, padding: spacing.md, marginBottom: spacing.md, gap: spacing.sm, borderWidth: 1, borderColor: 'rgba(194, 65, 12, 0.3)', }, addErrorText: { flex: 1, fontSize: typography.fontSize.sm, color: '#c2410c', lineHeight: typography.fontSize.sm * 1.4, }, modalButtons: { flexDirection: 'row', gap: spacing.md, }, cancelButton: { flex: 1, paddingVertical: spacing.md, borderRadius: borderRadius.lg, backgroundColor: colors.nautical.paleAqua, alignItems: 'center', borderWidth: 1, borderColor: colors.nautical.lightMint, }, cancelButtonText: { fontSize: typography.fontSize.base, color: colors.nautical.sage, fontWeight: '600', }, confirmButton: { flex: 1, borderRadius: borderRadius.lg, overflow: 'hidden', }, confirmButtonGradient: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', paddingVertical: spacing.md, gap: spacing.sm, }, confirmButtonGradientDisabled: { opacity: 0.5, }, confirmButtonText: { fontSize: typography.fontSize.base, color: '#fff', fontWeight: '600', }, verifyCard: { backgroundColor: colors.nautical.paleAqua, borderRadius: borderRadius.lg, padding: spacing.base, marginBottom: spacing.md, borderWidth: 1, borderColor: colors.nautical.lightMint, gap: spacing.sm, }, verifyRow: { flexDirection: 'row', alignItems: 'center', gap: spacing.sm, }, verifyText: { color: colors.nautical.navy, fontSize: typography.fontSize.sm, }, verifyButton: { alignSelf: 'flex-start', paddingHorizontal: spacing.md, paddingVertical: spacing.sm, borderRadius: borderRadius.full, backgroundColor: colors.nautical.teal, }, verifyButtonDone: { backgroundColor: colors.nautical.sage, }, verifyButtonText: { color: colors.nautical.cream, fontWeight: '700', }, rehearsalRow: { flexDirection: 'row', alignItems: 'center', gap: spacing.sm, marginBottom: spacing.md, }, rehearsalText: { color: colors.nautical.navy, fontSize: typography.fontSize.sm, flex: 1, }, detailContainer: { flex: 1, backgroundColor: colors.vault.background, }, detailGradient: { flex: 1, }, detailSafeArea: { flex: 1, }, detailHeader: { paddingHorizontal: spacing.lg, paddingTop: spacing.lg, paddingBottom: spacing.md, flexDirection: 'row', alignItems: 'center', gap: spacing.sm, }, detailBackButton: { width: 36, height: 36, borderRadius: 18, backgroundColor: 'rgba(255, 255, 255, 0.08)', alignItems: 'center', justifyContent: 'center', }, detailTitle: { flex: 1, fontSize: typography.fontSize.lg, color: colors.vault.text, fontWeight: '700', letterSpacing: typography.letterSpacing.wide, }, riskBadge: { backgroundColor: `${colors.vault.warning}25`, borderRadius: borderRadius.full, paddingHorizontal: spacing.sm, paddingVertical: 4, }, riskBadgeText: { fontSize: typography.fontSize.xs, color: colors.vault.warning, fontWeight: '700', letterSpacing: 1, }, detailScroll: { flex: 1, }, detailContent: { padding: spacing.lg, paddingTop: spacing.sm, gap: spacing.lg, }, detailHeroCard: { backgroundColor: colors.vault.cardBackground, borderRadius: borderRadius.xl, padding: spacing.lg, borderWidth: 1, borderColor: colors.vault.cardBorder, flexDirection: 'row', gap: spacing.base, alignItems: 'center', }, detailHeroIcon: { width: 54, height: 54, borderRadius: 27, backgroundColor: 'rgba(184, 224, 229, 0.15)', alignItems: 'center', justifyContent: 'center', }, detailHeroInfo: { flex: 1, }, detailHeroLabel: { fontSize: typography.fontSize.xs, color: colors.vault.textSecondary, letterSpacing: 1, fontWeight: '600', marginBottom: 4, }, detailHeroTitle: { fontSize: typography.fontSize.lg, color: colors.vault.text, fontWeight: '700', marginBottom: 4, }, detailHeroSubtitle: { fontSize: typography.fontSize.sm, color: colors.vault.textSecondary, }, metaGrid: { flexDirection: 'row', flexWrap: 'wrap', gap: spacing.md, }, metaCard: { width: '48%', backgroundColor: 'rgba(255, 255, 255, 0.05)', borderRadius: borderRadius.lg, padding: spacing.base, borderWidth: 1, borderColor: 'rgba(255, 255, 255, 0.08)', }, metaLabel: { fontSize: typography.fontSize.xs, color: colors.vault.textSecondary, letterSpacing: 1, marginBottom: spacing.xs, fontWeight: '600', }, metaValue: { fontSize: typography.fontSize.sm, color: colors.vault.text, fontWeight: '600', }, actionGroup: { gap: spacing.sm, }, sectionTitle: { fontSize: typography.fontSize.xs, color: colors.vault.textSecondary, letterSpacing: 1, fontWeight: '700', }, actionRow: { flexDirection: 'row', alignItems: 'center', gap: spacing.sm, paddingVertical: spacing.sm, paddingHorizontal: spacing.md, borderRadius: borderRadius.lg, backgroundColor: 'rgba(255, 255, 255, 0.06)', borderWidth: 1, borderColor: 'rgba(255, 255, 255, 0.08)', }, actionText: { color: colors.vault.text, fontSize: typography.fontSize.base, fontWeight: '600', }, guardCard: { backgroundColor: 'rgba(229, 115, 115, 0.12)', borderRadius: borderRadius.lg, padding: spacing.base, gap: spacing.sm, borderWidth: 1, borderColor: 'rgba(229, 115, 115, 0.3)', }, guardHeader: { flexDirection: 'row', alignItems: 'center', gap: spacing.sm, }, guardTitle: { fontSize: typography.fontSize.base, color: colors.vault.warning, fontWeight: '700', }, guardText: { fontSize: typography.fontSize.sm, color: colors.vault.textSecondary, lineHeight: typography.fontSize.sm * 1.5, }, guardButton: { alignSelf: 'flex-start', backgroundColor: colors.vault.warning, paddingHorizontal: spacing.md, paddingVertical: spacing.sm, borderRadius: borderRadius.full, }, guardButtonText: { color: colors.vault.text, fontWeight: '700', letterSpacing: 0.6, }, previewCard: { backgroundColor: colors.vault.cardBackground, borderRadius: borderRadius.lg, padding: spacing.base, borderWidth: 1, borderColor: colors.vault.cardBorder, }, previewLabel: { fontSize: typography.fontSize.xs, color: colors.vault.textSecondary, letterSpacing: 1, marginBottom: spacing.xs, fontWeight: '600', }, previewValue: { fontFamily: typography.fontFamily.mono, color: colors.vault.text, fontSize: typography.fontSize.base, letterSpacing: 0.6, }, warningCard: { flexDirection: 'row', alignItems: 'flex-start', gap: spacing.sm, backgroundColor: 'rgba(26, 58, 74, 0.6)', borderRadius: borderRadius.lg, padding: spacing.base, borderWidth: 1, borderColor: 'rgba(229, 115, 115, 0.35)', }, warningText: { flex: 1, color: colors.vault.textSecondary, fontSize: typography.fontSize.sm, lineHeight: typography.fontSize.sm * 1.5, }, mnemonicOverlay: { flex: 1, backgroundColor: 'rgba(11, 20, 24, 0.72)', justifyContent: 'center', padding: spacing.lg, }, mnemonicCard: { borderRadius: borderRadius.xl, padding: spacing.lg, borderWidth: 1, borderColor: colors.sentinel.cardBorder, ...shadows.glow, }, mnemonicHeader: { flexDirection: 'row', alignItems: 'center', gap: spacing.sm, marginBottom: spacing.sm, }, stepDots: { flexDirection: 'row', gap: spacing.sm, marginTop: spacing.sm, justifyContent: 'center', }, stepDot: { width: 8, height: 8, borderRadius: 4, backgroundColor: colors.sentinel.cardBorder, }, stepDotActive: { backgroundColor: colors.sentinel.primary, }, mnemonicClose: { position: 'absolute', top: spacing.sm, right: spacing.sm, width: 32, height: 32, borderRadius: 16, alignItems: 'center', justifyContent: 'center', backgroundColor: 'rgba(26, 58, 74, 0.35)', }, mnemonicTitle: { fontSize: typography.fontSize.lg, fontWeight: '700', color: colors.sentinel.text, letterSpacing: typography.letterSpacing.wide, }, mnemonicSubtitle: { fontSize: typography.fontSize.sm, color: colors.sentinel.textSecondary, marginBottom: spacing.md, }, mnemonicBlock: { backgroundColor: colors.sentinel.cardBackground, borderRadius: borderRadius.lg, paddingVertical: spacing.md, paddingHorizontal: spacing.md, borderWidth: 1, borderColor: colors.sentinel.cardBorder, marginBottom: spacing.lg, }, mnemonicBlockText: { fontSize: typography.fontSize.sm, color: colors.sentinel.text, fontFamily: typography.fontFamily.mono, fontWeight: '600', lineHeight: 22, textAlign: 'center', }, progressContainer: { marginTop: spacing.sm, marginBottom: spacing.md, }, progressTrack: { height: 6, borderRadius: 999, backgroundColor: colors.sentinel.cardBorder, overflow: 'hidden', }, progressFill: { height: '100%', backgroundColor: colors.sentinel.primary, }, progressSteps: { minHeight: 44, justifyContent: 'center', marginBottom: spacing.md, }, progressText: { fontSize: typography.fontSize.sm, color: colors.sentinel.text, textAlign: 'center', lineHeight: typography.fontSize.sm * 1.4, }, wordGrid: { flexDirection: 'row', flexWrap: 'wrap', gap: spacing.sm, marginBottom: spacing.lg, }, wordChip: { minWidth: '30%', paddingHorizontal: spacing.sm, paddingVertical: spacing.sm, borderRadius: borderRadius.lg, borderWidth: 1, borderColor: colors.sentinel.cardBorder, backgroundColor: 'transparent', }, wordChipSelected: { backgroundColor: colors.sentinel.primary, borderColor: colors.sentinel.primary, }, wordChipIndex: { fontSize: typography.fontSize.xs, color: colors.sentinel.textSecondary, marginBottom: 2, }, wordChipText: { color: colors.sentinel.text, fontSize: typography.fontSize.xs, fontWeight: '600', }, wordChipTextSelected: { color: colors.nautical.cream, }, replacePanel: { backgroundColor: colors.sentinel.cardBackground, borderRadius: borderRadius.lg, padding: spacing.md, borderWidth: 1, borderColor: colors.sentinel.cardBorder, marginBottom: spacing.lg, }, replaceTitle: { fontSize: typography.fontSize.sm, color: colors.sentinel.text, fontWeight: '600', marginBottom: spacing.sm, }, replaceInput: { height: 40, borderRadius: borderRadius.full, borderWidth: 1, borderColor: colors.sentinel.cardBorder, paddingHorizontal: spacing.md, color: colors.sentinel.text, fontSize: typography.fontSize.sm, backgroundColor: 'rgba(255, 255, 255, 0.02)', marginBottom: spacing.sm, }, replaceList: { maxHeight: 160, marginBottom: spacing.sm, }, replaceOption: { paddingVertical: spacing.xs, paddingHorizontal: spacing.sm, borderRadius: borderRadius.full, borderWidth: 1, borderColor: colors.sentinel.cardBorder, marginBottom: spacing.xs, }, replaceOptionText: { fontSize: typography.fontSize.xs, color: colors.sentinel.text, fontWeight: '600', }, replaceCancel: { alignSelf: 'flex-end', paddingHorizontal: spacing.md, paddingVertical: spacing.xs, borderRadius: borderRadius.full, borderWidth: 1, borderColor: colors.sentinel.cardBorder, }, replaceCancelText: { fontSize: typography.fontSize.xs, color: colors.sentinel.textSecondary, fontWeight: '600', letterSpacing: typography.letterSpacing.wide, }, selectorList: { maxHeight: 260, marginBottom: spacing.md, }, selectorRow: { flexDirection: 'row', alignItems: 'center', gap: spacing.sm, paddingVertical: spacing.sm, paddingHorizontal: spacing.sm, borderRadius: borderRadius.lg, borderWidth: 1, borderColor: colors.sentinel.cardBorder, backgroundColor: colors.sentinel.cardBackground, marginBottom: spacing.sm, }, selectorIcon: { width: 32, height: 32, borderRadius: 16, alignItems: 'center', justifyContent: 'center', backgroundColor: `${colors.sentinel.primary}1A`, }, selectorContent: { flex: 1, }, selectorTitle: { fontSize: typography.fontSize.sm, color: colors.sentinel.text, fontWeight: '600', }, selectorSubtitle: { fontSize: typography.fontSize.xs, color: colors.sentinel.textSecondary, marginTop: 2, }, summaryCard: { backgroundColor: colors.sentinel.cardBackground, borderRadius: borderRadius.lg, padding: spacing.md, borderWidth: 1, borderColor: colors.sentinel.cardBorder, marginBottom: spacing.md, gap: spacing.xs, }, summaryLabel: { fontSize: typography.fontSize.xs, color: colors.sentinel.textSecondary, letterSpacing: typography.letterSpacing.wide, marginTop: spacing.xs, }, summaryValue: { fontSize: typography.fontSize.sm, color: colors.sentinel.text, fontWeight: '600', }, partGrid: { gap: spacing.sm, marginBottom: spacing.lg, }, partCard: { backgroundColor: colors.sentinel.cardBackground, borderRadius: borderRadius.lg, paddingVertical: spacing.sm, paddingHorizontal: spacing.md, borderWidth: 1, borderColor: colors.sentinel.cardBorder, }, partCardStored: { borderColor: colors.sentinel.primary, }, partLabel: { fontSize: typography.fontSize.xs, color: colors.sentinel.textSecondary, letterSpacing: typography.letterSpacing.wide, marginBottom: 4, fontWeight: '600', }, partValue: { fontSize: typography.fontSize.md, color: colors.sentinel.text, fontFamily: typography.fontFamily.mono, fontWeight: '700', marginBottom: 2, }, partHint: { fontSize: typography.fontSize.xs, color: colors.sentinel.textSecondary, }, mnemonicPrimaryButton: { backgroundColor: colors.sentinel.primary, paddingVertical: spacing.sm, borderRadius: borderRadius.full, alignItems: 'center', marginBottom: spacing.sm, }, mnemonicButtonDisabled: { opacity: 0.6, }, mnemonicPrimaryText: { color: colors.nautical.cream, fontWeight: '700', letterSpacing: typography.letterSpacing.wide, }, mnemonicSecondaryButton: { backgroundColor: 'transparent', paddingVertical: spacing.sm, borderRadius: borderRadius.full, alignItems: 'center', borderWidth: 1, borderColor: colors.sentinel.cardBorder, }, mnemonicSecondaryText: { color: colors.sentinel.text, fontWeight: '700', letterSpacing: typography.letterSpacing.wide, }, });