/*
 * SCR-M(내정보/프로필) — WISE 모바일 mypage 이식(구조·컴포넌트·플로우 문자 그대로 차용).
 * 레퍼런스: guardia-messenger/app/uiws/mypage.tsx.
 *   · 프로필 헤드(아바타+카메라 배지 → 사진 선택→미리보기→적용 시에만 업로드)
 *   · 정보 행(InfoRow) · 계정/보안(2FA 상태) · 생체인식 잠금 토글 · 환경설정 · 로그아웃
 * 추가: ① 생체인식 로컬 잠금(진입 게이트) ② 프로필 사진 등록(갤러리/카메라).
 * 보안: 새 시크릿·토큰·자격증명을 console로 출력하지 않는다. 생체 원본은 OS에만.
 */
import { Ionicons } from '@expo/vector-icons';
import { router, useFocusEffect } from 'expo-router';
import React, { useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
  ActivityIndicator,
  Alert,
  Image,
  Modal,
  Pressable,
  ScrollView,
  StyleSheet,
  Switch,
  Text,
  View,
} from 'react-native';
import { Avatar } from '../components/Avatar';
import { Banner } from '../components/Banner';
import { Card } from '../components/Card';
import { useAuth } from '../context/AuthContext';
import { useSecureScreen } from '../context/SecureScreenContext';
import { ApiRequestError, isDegraded } from '../lib/api';
import {
  authenticateBiometric,
  isBiometricEnabled,
  isBiometricSupported,
  isSessionUnlocked,
  markSessionUnlocked,
  setBiometricEnabled,
} from '../lib/biometric';
import {
  isPickerAvailable,
  pickFromCamera,
  pickFromLibrary,
  type PickedImage,
} from '../lib/imagePick';
import { LanguageSelector } from '../components/LanguageSelector';
import { avatarUrl, getMe, getOtpStatus, uploadAvatar } from '../lib/profile';
import { prefGet, prefSet } from '../lib/secureStore';
import type { MePrincipal, OtpStatusDto } from '../lib/types';
import { colors, radius, spacing, touch, type } from '../theme';

// 환경설정(이 기기 로컬 저장 — 서버 동기화 계약 부재, web MyPage와 동일 정책).
const PREFS_KEY = 'kintex.prefs';
interface Prefs {
  notifyDeadline: boolean;
  notifyApproval: boolean;
  notifyPayment: boolean;
}
const DEFAULT_PREFS: Prefs = { notifyDeadline: true, notifyApproval: true, notifyPayment: true };

export default function ProfileScreen() {
  const { t } = useTranslation();
  const { user, signOut } = useAuth();

  // 개인정보 화면 — 캡처 차단 + 백그라운드 마스킹(B4/B7).
  useSecureScreen('profile');

  const [me, setMe] = useState<MePrincipal | null>(null);
  const [loading, setLoading] = useState(false);
  const [loadErr, setLoadErr] = useState('');
  const [otp, setOtp] = useState<OtpStatusDto | null>(null);

  // 프로필 사진 — 선택 → 미리보기(적용/취소) → 적용 시에만 업로드(WISE 불변식).
  const [photoUrl, setPhotoUrl] = useState<string | null>(null);
  const [photoBusy, setPhotoBusy] = useState(false);
  const [previewImg, setPreviewImg] = useState<PickedImage | null>(null);
  const [previewErr, setPreviewErr] = useState('');
  const [photoPending, setPhotoPending] = useState(false); // 서버 미반영(degrade) 로컬 프리뷰 상태

  // 생체인식
  const [bioSupported, setBioSupported] = useState(false);
  const [bioEnabled, setBioEnabled] = useState(false);
  const [locked, setLocked] = useState(false); // 잠금 게이트 통과 전 콘텐츠 차단

  // 환경설정
  const [prefs, setPrefs] = useState<Prefs>(DEFAULT_PREFS);

  const displayName = me?.displayName ?? user?.displayName ?? t('common.user');

  const loadProfile = useCallback(async () => {
    setLoading(true);
    setLoadErr('');
    try {
      const p = await getMe();
      setMe(p);
      setPhotoUrl(avatarUrl(p.userId));
      setPhotoPending(false);
    } catch (e) {
      // /me 실패 시 최소한 로그인 세션 정보로 화면 유지(전면 오류 회피).
      setLoadErr(e instanceof ApiRequestError ? e.message : t('profile.loadErr'));
    } finally {
      setLoading(false);
    }
    try {
      setOtp(await getOtpStatus());
    } catch {
      setOtp(null); // 상태 조회 실패는 무시(섹션은 안내로 degrade)
    }
  }, [t]);

  // 환경설정 로드
  useEffect(() => {
    prefGet(PREFS_KEY)
      .then((raw) => {
        if (raw) setPrefs({ ...DEFAULT_PREFS, ...(JSON.parse(raw) as Partial<Prefs>) });
      })
      .catch(() => setPrefs(DEFAULT_PREFS));
  }, []);

  // 생체 지원/토글 상태
  useEffect(() => {
    isBiometricSupported().then(setBioSupported).catch(() => setBioSupported(false));
    isBiometricEnabled().then(setBioEnabled).catch(() => setBioEnabled(false));
  }, []);

  // 진입 게이트 — 생체 잠금 활성 + 세션 미해제 시 인증 요구.
  const runLockGate = useCallback(async () => {
    const enabled = await isBiometricEnabled();
    if (!enabled || isSessionUnlocked()) {
      setLocked(false);
      return;
    }
    setLocked(true);
    const ok = await authenticateBiometric();
    if (ok) {
      markSessionUnlocked();
      setLocked(false);
    }
  }, []);

  useFocusEffect(
    useCallback(() => {
      runLockGate();
      loadProfile();
    }, [runLockGate, loadProfile]),
  );

  const savePrefs = async (next: Prefs) => {
    setPrefs(next);
    try {
      await prefSet(PREFS_KEY, JSON.stringify(next));
    } catch {
      /* graceful */
    }
  };

  const toggleBiometric = async (next: boolean) => {
    if (next) {
      // 활성화 전 1회 본인 확인.
      const ok = await authenticateBiometric();
      if (!ok) {
        Alert.alert(t('profile.biometric'), t('profile.bioFailed'));
        return;
      }
      markSessionUnlocked(); // 방금 인증했으므로 이 세션은 통과 처리(즉시 재프롬프트 방지).
    }
    await setBiometricEnabled(next);
    setBioEnabled(next);
  };

  // ── 사진 선택(미리보기용) — 업로드 호출 없음 ──
  const pickForPreview = async (from: 'library' | 'camera') => {
    if (photoBusy) return;
    if (!isPickerAvailable()) {
      Alert.alert(t('profile.photoTitle'), t('profile.photoPickerUnavailable'));
      return;
    }
    const img = from === 'library' ? await pickFromLibrary() : await pickFromCamera();
    if (!img) {
      // 권한 거부/취소/미설치: 모달이 열려있으면 유지, 아니면 무동작 + 권한 안내.
      return;
    }
    setPreviewImg(img);
    setPreviewErr('');
  };

  // ── 적용 — 이 시점에만 1회 업로드. 미구현/네트워크면 로컬 프리뷰로 degrade ──
  const applyPhoto = async () => {
    if (!previewImg || photoBusy) return;
    setPhotoBusy(true);
    setPreviewErr('');
    try {
      const res = await uploadAvatar(previewImg);
      const base = res.photoUrl || (me ? avatarUrl(me.userId) : null);
      setPhotoUrl(base ? `${base}${base.includes('?') ? '&' : '?'}_t=${Date.now()}` : previewImg.uri);
      setPhotoPending(false);
      setPreviewImg(null);
    } catch (e) {
      if (isDegraded(e)) {
        // 백엔드 아바타 업로드 미구현 — 로컬 프리뷰 유지 + 대기 안내(파괴적 실패 아님).
        setPhotoUrl(previewImg.uri);
        setPhotoPending(true);
        setPreviewImg(null);
      } else {
        setPreviewErr(e instanceof ApiRequestError ? e.message : t('profile.uploadErr'));
      }
    } finally {
      setPhotoBusy(false);
    }
  };

  const cancelPreview = () => {
    if (photoBusy) return;
    setPreviewImg(null);
    setPreviewErr('');
  };

  const onChangePhoto = () => {
    if (photoBusy) return;
    Alert.alert(t('profile.photoTitle'), t('profile.photoSelect'), [
      { text: t('profile.photoLibrary'), onPress: () => pickForPreview('library') },
      { text: t('profile.photoCamera'), onPress: () => pickForPreview('camera') },
      { text: t('common.cancel'), style: 'cancel' },
    ]);
  };

  const onSignOut = () => {
    Alert.alert(t('profile.signOut'), t('profile.signOutConfirm'), [
      { text: t('common.cancel'), style: 'cancel' },
      {
        text: t('profile.signOut'),
        style: 'destructive',
        onPress: async () => {
          await signOut();
          router.replace('/login');
        },
      },
    ]);
  };

  // 생체 잠금 게이트 — 미통과 시 콘텐츠 차단 화면.
  if (locked) {
    return (
      <View style={styles.lockWrap}>
        <Ionicons name="finger-print" size={56} color={colors.primary600} />
        <Text style={styles.lockTitle}>{t('profile.lockTitle')}</Text>
        <Text style={styles.lockHint}>{t('profile.lockHint')}</Text>
        <Pressable
          style={styles.lockBtn}
          onPress={runLockGate}
          accessibilityRole="button"
          accessibilityLabel={t('common.retry')}
        >
          <Text style={styles.lockBtnText}>{t('common.retry')}</Text>
        </Pressable>
      </View>
    );
  }

  const roles = me?.eventRoles ? Object.values(me.eventRoles) : [];

  return (
    <ScrollView style={styles.wrap} contentContainerStyle={styles.scroll}>
      {/* ── 프로필 ── */}
      <Text style={styles.section}>{t('profile.sectionInfo')}</Text>
      {loading ? (
        <ActivityIndicator color={colors.primary600} style={{ marginVertical: spacing.md }} />
      ) : (
        <Card>
          <View style={styles.profileHead}>
            <Pressable
              testID="profile-photo"
              onPress={onChangePhoto}
              disabled={photoBusy}
              accessibilityLabel="프로필 사진 변경"
              accessibilityRole="button"
            >
              <Avatar photoUrl={photoUrl} name={displayName} size={56} testID="profile-avatar" />
              <View style={styles.photoEdit}>
                {photoBusy ? (
                  <ActivityIndicator color={colors.white} size="small" />
                ) : (
                  <Ionicons name="camera" size={13} color={colors.white} />
                )}
              </View>
            </Pressable>
            <View style={{ flex: 1, marginLeft: 12 }}>
              <Text style={styles.profileName}>{displayName}</Text>
              <Text style={styles.profileId}>
                {me?.userId ?? user?.userId ?? '-'}
                {me?.roleCode ? ` · ${me.roleCode}` : ''}
              </Text>
            </View>
          </View>

          {photoPending ? (
            <Text style={styles.pendingNote}>{t('profile.photoPending')}</Text>
          ) : null}

          {loadErr ? <Banner tone="warning">{loadErr}</Banner> : null}

          <InfoRow label={t('profile.labelName')} value={displayName} />
          <InfoRow label={t('profile.labelUserId')} value={me?.userId ?? user?.userId ?? null} testID="profile-userid" />
          <InfoRow label={t('profile.labelGlobalRole')} value={me?.roleCode ?? null} />
          <InfoRow label={t('profile.labelTenant')} value={me?.tenantId ?? null} />
          <InfoRow
            label={t('profile.labelType')}
            value={me?.hallManager ?? user?.hallManager ? t('profile.typeInternal') : t('profile.typeGeneral')}
          />
        </Card>
      )}

      {/* ── 참여 행사 역할 ── */}
      {roles.length > 0 ? (
        <>
          <Text style={styles.section}>{t('profile.sectionEventRoles')}</Text>
          <Card>
            {Object.entries(me!.eventRoles).map(([eventId, r]) => (
              <View key={eventId} style={styles.infoRow}>
                <Text style={styles.infoLabel} numberOfLines={1}>
                  {eventId}
                </Text>
                <View style={styles.rolePill}>
                  <Text style={styles.rolePillText}>{t(`roles.${r}` as const, { defaultValue: r })}</Text>
                </View>
              </View>
            ))}
          </Card>
        </>
      ) : null}

      {/* ── 계정·보안(2차 인증) ── */}
      <Text style={styles.section}>{t('profile.sectionSecurity')}</Text>
      <Card>
        <View style={styles.bioRow}>
          <View style={{ flex: 1, paddingRight: 12 }}>
            <Text style={styles.rowTitle}>{t('profile.otpTitle')}</Text>
            <Text style={styles.hint}>
              {otp?.otpEnabled
                ? otp.verifyMethod === 'OTP'
                  ? t('profile.otpOnAuth')
                  : t('profile.otpOnMethod', { method: otp.verifyMethod || 'OTP' })
                : t('profile.otpOff')}
            </Text>
          </View>
          <View style={otp?.otpEnabled ? styles.badgeOn : styles.badgeOff}>
            <Text style={otp?.otpEnabled ? styles.badgeOnText : styles.badgeOffText}>
              {otp?.otpEnabled ? t('profile.on') : t('profile.off')}
            </Text>
          </View>
        </View>
      </Card>

      {/* ── 생체인식 잠금 ── */}
      <Text style={styles.section}>{t('profile.sectionBiometric')}</Text>
      <Card>
        {bioSupported ? (
          <View style={styles.bioRow}>
            <View style={{ flex: 1, paddingRight: 12 }}>
              <Text style={styles.rowTitle}>{t('profile.bioTitle')}</Text>
              <Text style={styles.hint}>{t('profile.bioDesc')}</Text>
            </View>
            <Switch
              testID="profile-biometric-toggle"
              value={bioEnabled}
              onValueChange={toggleBiometric}
              trackColor={{ false: colors.neutral200, true: colors.primary600 }}
              thumbColor={colors.white}
            />
          </View>
        ) : (
          <Text style={styles.hint}>{t('profile.bioUnsupported')}</Text>
        )}
      </Card>

      {/* ── 언어 설정 ── */}
      <Text style={styles.section}>{t('lang.title')}</Text>
      <LanguageSelector />

      {/* ── 환경설정(알림) ── */}
      <Text style={styles.section}>{t('profile.sectionNotify')}</Text>
      <Card>
        {(
          [
            ['notifyDeadline', t('profile.notifyDeadline')],
            ['notifyApproval', t('profile.notifyApproval')],
            ['notifyPayment', t('profile.notifyPayment')],
          ] as const
        ).map(([key, label]) => (
          <View key={key} style={styles.bioRow}>
            <Text style={[styles.rowTitle, { flex: 1 }]}>{label}</Text>
            <Switch
              testID={`profile-pref-${key}`}
              value={prefs[key as keyof Prefs]}
              onValueChange={(v) => savePrefs({ ...prefs, [key]: v })}
              trackColor={{ false: colors.neutral200, true: colors.primary600 }}
              thumbColor={colors.white}
            />
          </View>
        ))}
        <Text style={styles.hint}>{t('profile.notifyNote')}</Text>
      </Card>

      {/* ── 로그아웃 ── */}
      <Pressable
        style={styles.logoutBtn}
        onPress={onSignOut}
        accessibilityRole="button"
        accessibilityLabel={t('profile.signOut')}
      >
        <Ionicons name="log-out-outline" size={18} color={colors.error} />
        <Text style={styles.logoutText}>{t('profile.signOut')}</Text>
      </Pressable>

      <Text style={styles.version}>{t('profile.version')}</Text>

      {/* ── 프로필 사진 미리보기 모달(선택→미리보기→적용 확정) ── */}
      <Modal visible={!!previewImg} transparent animationType="fade" onRequestClose={cancelPreview}>
        <Pressable style={styles.modalBackdrop} onPress={cancelPreview}>
          <Pressable style={styles.modalSheet} onPress={() => {}}>
            <View style={styles.modalHeaderRow}>
              <Text style={styles.modalTitle}>{t('profile.photoChange')}</Text>
              <Pressable
                testID="photo-cancel-x"
                onPress={cancelPreview}
                disabled={photoBusy}
                hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}
                accessibilityLabel={t('common.close')}
              >
                <Ionicons name="close" size={22} color={colors.neutral500} />
              </Pressable>
            </View>

            <View style={styles.previewWrap}>
              {previewImg ? (
                <Image
                  testID="photo-preview-image"
                  source={{ uri: previewImg.uri }}
                  style={styles.previewImg}
                  resizeMode="cover"
                />
              ) : null}
              {photoBusy ? (
                <View style={styles.previewOverlay}>
                  <ActivityIndicator color={colors.white} size="small" />
                </View>
              ) : null}
            </View>
            <Text style={styles.previewCaption}>{t('profile.photoCaption')}</Text>

            <View style={styles.modalPickRow}>
              <Pressable
                testID="photo-pick-library"
                style={[styles.pickBtn, photoBusy && styles.disabled]}
                onPress={() => pickForPreview('library')}
                disabled={photoBusy}
              >
                <Ionicons name="image-outline" size={16} color={colors.neutral900} />
                <Text style={styles.pickText}>{t('profile.photoLibrary')}</Text>
              </Pressable>
              <Pressable
                testID="photo-pick-camera"
                style={[styles.pickBtn, photoBusy && styles.disabled]}
                onPress={() => pickForPreview('camera')}
                disabled={photoBusy}
              >
                <Ionicons name="camera-outline" size={16} color={colors.neutral900} />
                <Text style={styles.pickText}>{t('profile.photoCamera')}</Text>
              </Pressable>
            </View>

            {previewErr ? <Text style={styles.err}>{previewErr}</Text> : null}

            <Pressable
              testID="photo-apply"
              style={[styles.applyBtn, photoBusy && styles.disabled]}
              onPress={applyPhoto}
              disabled={photoBusy}
            >
              {photoBusy ? (
                <View style={styles.applyBusyRow}>
                  <ActivityIndicator color={colors.white} size="small" />
                  <Text style={styles.applyText}>{t('profile.photoApplying')}</Text>
                </View>
              ) : (
                <Text style={styles.applyText}>{t('profile.photoApply')}</Text>
              )}
            </Pressable>
            <Pressable
              testID="photo-cancel"
              style={[styles.cancelBtn, photoBusy && styles.disabled]}
              onPress={cancelPreview}
              disabled={photoBusy}
            >
              <Text style={styles.cancelText}>{t('common.cancel')}</Text>
            </Pressable>
          </Pressable>
        </Pressable>
      </Modal>
    </ScrollView>
  );
}

function InfoRow({ label, value, testID }: { label: string; value: string | null; testID?: string }) {
  return (
    <View style={styles.infoRow}>
      <Text style={styles.infoLabel}>{label}</Text>
      <Text style={styles.infoValue} testID={testID} numberOfLines={1}>
        {value && value.length ? value : '-'}
      </Text>
    </View>
  );
}

const styles = StyleSheet.create({
  wrap: { flex: 1, backgroundColor: colors.neutral050 },
  scroll: { padding: spacing.md, paddingBottom: spacing.xl },
  section: {
    color: colors.neutral900,
    fontSize: type.h3.fontSize,
    fontWeight: '800',
    marginTop: spacing.md,
    marginBottom: spacing.sm,
  },

  profileHead: { flexDirection: 'row', alignItems: 'center', marginBottom: spacing.sm },
  photoEdit: {
    position: 'absolute',
    right: -2,
    bottom: -2,
    width: 22,
    height: 22,
    borderRadius: 11,
    backgroundColor: colors.primary600,
    alignItems: 'center',
    justifyContent: 'center',
    borderWidth: 2,
    borderColor: colors.white,
  },
  profileName: { color: colors.neutral900, fontSize: type.h2.fontSize, fontWeight: '800' },
  profileId: { color: colors.neutral500, fontSize: type.caption.fontSize, marginTop: 3 },
  pendingNote: { color: colors.warning, fontSize: type.caption.fontSize, marginBottom: spacing.sm },

  infoRow: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    paddingVertical: 9,
    borderTopWidth: 1,
    borderTopColor: colors.neutral200,
  },
  infoLabel: { color: colors.neutral500, fontSize: type.caption.fontSize, fontWeight: '700' },
  infoValue: {
    color: colors.neutral900,
    fontSize: type.body.fontSize,
    fontWeight: '600',
    flexShrink: 1,
    textAlign: 'right',
    marginLeft: 12,
  },
  rolePill: {
    backgroundColor: colors.primary100,
    borderRadius: radius.pill,
    paddingHorizontal: 10,
    paddingVertical: 4,
  },
  rolePillText: { color: colors.primary700, fontSize: type.caption.fontSize, fontWeight: '700' },

  bioRow: { flexDirection: 'row', alignItems: 'center', paddingVertical: 4 },
  rowTitle: { color: colors.neutral900, fontSize: type.body.fontSize, fontWeight: '700', marginBottom: 4 },
  hint: { color: colors.neutral500, fontSize: type.caption.fontSize, lineHeight: 18, marginTop: 4 },

  badgeOn: { backgroundColor: '#E7F5EF', borderRadius: radius.pill, paddingHorizontal: 10, paddingVertical: 4 },
  badgeOnText: { color: colors.success, fontSize: type.caption.fontSize, fontWeight: '800' },
  badgeOff: { backgroundColor: colors.neutral200, borderRadius: radius.pill, paddingHorizontal: 10, paddingVertical: 4 },
  badgeOffText: { color: colors.neutral700, fontSize: type.caption.fontSize, fontWeight: '800' },

  logoutBtn: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
    gap: 8,
    marginTop: spacing.lg,
    minHeight: touch.min,
    borderRadius: radius.sm,
    borderWidth: 1,
    borderColor: colors.error,
    backgroundColor: colors.white,
  },
  logoutText: { color: colors.error, fontSize: type.h3.fontSize, fontWeight: '700' },
  version: { textAlign: 'center', color: colors.neutral500, fontSize: type.caption.fontSize, marginTop: spacing.md },

  // 생체 잠금 게이트
  lockWrap: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    gap: spacing.sm,
    padding: spacing.lg,
    backgroundColor: colors.neutral050,
  },
  lockTitle: { color: colors.neutral900, fontSize: type.h2.fontSize, fontWeight: '800', marginTop: spacing.sm },
  lockHint: { color: colors.neutral500, fontSize: type.body.fontSize, textAlign: 'center' },
  lockBtn: {
    marginTop: spacing.md,
    minHeight: touch.min,
    paddingHorizontal: spacing.lg,
    borderRadius: radius.sm,
    backgroundColor: colors.primary600,
    alignItems: 'center',
    justifyContent: 'center',
  },
  lockBtnText: { color: colors.white, fontSize: type.h3.fontSize, fontWeight: '700' },

  // 사진 미리보기 모달
  modalBackdrop: { flex: 1, backgroundColor: 'rgba(0,0,0,0.55)', justifyContent: 'flex-end' },
  modalSheet: {
    backgroundColor: colors.white,
    borderTopLeftRadius: radius.md,
    borderTopRightRadius: radius.md,
    borderWidth: 1,
    borderColor: colors.neutral200,
    padding: spacing.lg,
    paddingBottom: spacing.xl,
  },
  modalHeaderRow: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' },
  modalTitle: { color: colors.neutral900, fontSize: type.h3.fontSize, fontWeight: '800' },
  previewWrap: {
    width: 120,
    height: 120,
    borderRadius: 60,
    alignSelf: 'center',
    marginVertical: spacing.md,
    overflow: 'hidden',
    borderWidth: 1,
    borderColor: colors.neutral200,
    backgroundColor: colors.primary050,
  },
  previewImg: { width: 120, height: 120, borderRadius: 60 },
  previewOverlay: {
    ...StyleSheet.absoluteFillObject,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: 'rgba(0,0,0,0.35)',
  },
  previewCaption: { color: colors.neutral500, fontSize: type.caption.fontSize, textAlign: 'center', marginTop: -4 },
  modalPickRow: { flexDirection: 'row', gap: 10, marginTop: spacing.md },
  pickBtn: {
    flex: 1,
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
    gap: 8,
    minHeight: touch.min,
    borderRadius: radius.sm,
    borderWidth: 1,
    borderColor: colors.neutral200,
    backgroundColor: colors.white,
  },
  pickText: { color: colors.neutral900, fontSize: type.body.fontSize, fontWeight: '700' },
  applyBtn: {
    marginTop: spacing.md,
    minHeight: touch.min,
    borderRadius: radius.sm,
    backgroundColor: colors.primary600,
    alignItems: 'center',
    justifyContent: 'center',
  },
  applyBusyRow: { flexDirection: 'row', alignItems: 'center', gap: 8 },
  applyText: { color: colors.white, fontSize: type.h3.fontSize, fontWeight: '800' },
  cancelBtn: {
    marginTop: spacing.sm,
    minHeight: touch.min,
    borderRadius: radius.sm,
    borderWidth: 1,
    borderColor: colors.neutral200,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: colors.white,
  },
  cancelText: { color: colors.neutral700, fontSize: type.h3.fontSize, fontWeight: '700' },
  err: { color: colors.error, fontSize: type.caption.fontSize, marginTop: spacing.sm },
  disabled: { opacity: 0.6 },
});
