From 4ce397026ca336797628b1abee47dcb184b1547d Mon Sep 17 00:00:00 2001 From: JUSN Date: Thu, 16 Jul 2026 21:32:18 +0200 Subject: [PATCH] Apple-natives Design: SF Symbols statt Emojis, iOS-System-Optik MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Neue Ikone-Komponente (expo-symbols): echte SF Symbols auf iOS, Material Symbols auf Android — alle Emojis in Buttons/Kacheln/ Checkboxen/Ampel/Chevrons ersetzt - Theme: iOS-Systemgrau (#F2F2F7) statt Papier-Ton, weiße Karten ohne Rahmen und Schatten (wie Einstellungen/Health), "graue Taste" für Sekundär-Buttons statt Umrandung - Kernaussage-Karte: dezenter Marken-Tint statt Textmarker-Gelb - Frist/Termin-Zeilen ohne Emoji-Präfixe - Layout unverändert (Kacheln, Ampel-Streifen, großer Titel) Co-Authored-By: Claude Fable 5 --- App.tsx | 3 +- package-lock.json | 51 ++++++++++++++------ package.json | 1 + src/components/Ampel.tsx | 13 +++--- src/components/GrossButton.tsx | 53 +++++++++------------ src/components/Ikone.tsx | 72 +++++++++++++++++++++++++++++ src/screens/AnalyseScreen.tsx | 58 ++++++++++++----------- src/screens/AntwortScreen.tsx | 6 +-- src/screens/EinstellungenScreen.tsx | 2 +- src/screens/HomeScreen.tsx | 42 +++++++---------- src/screens/ScanScreen.tsx | 6 +-- src/theme.ts | 32 ++++++------- 12 files changed, 209 insertions(+), 130 deletions(-) create mode 100644 src/components/Ikone.tsx diff --git a/App.tsx b/App.tsx index 031b0ed..400719b 100644 --- a/App.tsx +++ b/App.tsx @@ -49,8 +49,7 @@ export default function App() { options={{ title: 'BehördenKlar', headerLargeTitle: true, - headerLargeTitleStyle: { color: farben.primaer, fontWeight: '800' }, - headerLargeStyle: { backgroundColor: farben.hintergrund }, + headerLargeTitleStyle: { color: farben.primaer }, }} /> diff --git a/package-lock.json b/package-lock.json index 7ee14c8..cd85eee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "expo-speech": "~57.0.0", "expo-splash-screen": "~57.0.2", "expo-status-bar": "~57.0.0", + "expo-symbols": "~57.0.1", "react": "19.2.3", "react-native": "0.86.0", "react-native-safe-area-context": "~5.7.0", @@ -1275,6 +1276,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@expo-google-fonts/material-symbols": { + "version": "0.4.41", + "resolved": "https://registry.npmjs.org/@expo-google-fonts/material-symbols/-/material-symbols-0.4.41.tgz", + "integrity": "sha512-BKNSJ6oFGWi+aXu6PF+1EdI43J8Ag+Sm7Ste1SXYmC2eYOJasyjXHkKjgkIieBB1eDZQJSPWuPv421Vg6N5tCQ==", + "license": "MIT AND Apache-2.0" + }, "node_modules/@expo/code-signing-certificates": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/@expo/code-signing-certificates/-/code-signing-certificates-0.0.6.tgz", @@ -4254,6 +4261,20 @@ "react-native": "*" } }, + "node_modules/expo-font": { + "version": "57.0.1", + "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-57.0.1.tgz", + "integrity": "sha512-QyS9L1Kh9sKJg4gfU6rdbpxpmH+DyzBX8z6jVvXMUDoqLr1GqmkO/Wu379KCXjL///kWbhpNlbi7AgBuj4VdIQ==", + "license": "MIT", + "dependencies": { + "fontfaceobserver": "^2.1.0" + }, + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, "node_modules/expo-image-loader": { "version": "57.0.0", "resolved": "https://registry.npmjs.org/expo-image-loader/-/expo-image-loader-57.0.0.tgz", @@ -4450,6 +4471,22 @@ "react-native": "*" } }, + "node_modules/expo-symbols": { + "version": "57.0.1", + "resolved": "https://registry.npmjs.org/expo-symbols/-/expo-symbols-57.0.1.tgz", + "integrity": "sha512-8Zf+a83OywV0vf1NUtSKpNqKcULmO0GTI+zfFnGYl7SLDH9FjL5RcEZoy6CHvCgq2KDrQF21pl3r7Tb4ItPscw==", + "license": "MIT", + "dependencies": { + "@expo-google-fonts/material-symbols": "^0.4.1", + "sf-symbols-typescript": "^2.0.0" + }, + "peerDependencies": { + "expo": "*", + "expo-font": "*", + "react": "*", + "react-native": "*" + } + }, "node_modules/expo/node_modules/@expo/cli": { "version": "57.0.6", "resolved": "https://registry.npmjs.org/@expo/cli/-/cli-57.0.6.tgz", @@ -4761,20 +4798,6 @@ "react-native": "*" } }, - "node_modules/expo/node_modules/expo-font": { - "version": "57.0.0", - "resolved": "https://registry.npmjs.org/expo-font/-/expo-font-57.0.0.tgz", - "integrity": "sha512-zF+J7WrNFjqyAADwdvDgkFEoIQv9DqcjJ57HVstNEH7/7Tx1ThPEhKraodEQOwSjMYWirP+4BYsVbdb+/Zr4QQ==", - "license": "MIT", - "dependencies": { - "fontfaceobserver": "^2.1.0" - }, - "peerDependencies": { - "expo": "*", - "react": "*", - "react-native": "*" - } - }, "node_modules/expo/node_modules/expo-keep-awake": { "version": "57.0.0", "resolved": "https://registry.npmjs.org/expo-keep-awake/-/expo-keep-awake-57.0.0.tgz", diff --git a/package.json b/package.json index 795b148..226bad2 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "expo-speech": "~57.0.0", "expo-splash-screen": "~57.0.2", "expo-status-bar": "~57.0.0", + "expo-symbols": "~57.0.1", "react": "19.2.3", "react-native": "0.86.0", "react-native-safe-area-context": "~5.7.0", diff --git a/src/components/Ampel.tsx b/src/components/Ampel.tsx index 1b8aeee..fadb538 100644 --- a/src/components/Ampel.tsx +++ b/src/components/Ampel.tsx @@ -1,22 +1,23 @@ /** * Dringlichkeits-Ampel als gut sichtbares Banner. - * Farbe + Symbol + Text — nicht nur Farbe (Barrierefreiheit: Farbenblindheit). + * Farbe + Icon + Text — nicht nur Farbe (Barrierefreiheit: Farbenblindheit). */ import React from 'react'; import { StyleSheet, Text, View } from 'react-native'; import { AmpelStatus } from '../utils/ampel'; import { abstand, schrift } from '../theme'; +import { Ikone, IkonenName } from './Ikone'; -const SYMBOL: Record = { rot: '⚠️', gelb: '⏰', gruen: 'ℹ️' }; +const IKONE: Record = { rot: 'warnung', gelb: 'wecker', gruen: 'info' }; export function Ampel({ status }: { status: AmpelStatus }) { return ( - {SYMBOL[status.stufe]} + {status.text} ); @@ -26,12 +27,10 @@ const styles = StyleSheet.create({ banner: { flexDirection: 'row', alignItems: 'center', - borderWidth: 1, borderLeftWidth: 6, - borderRadius: 14, + borderRadius: 12, padding: abstand.m, gap: abstand.s, }, - symbol: { fontSize: 28 }, text: { flex: 1, fontSize: schrift.gross, fontWeight: '700' }, }); diff --git a/src/components/GrossButton.tsx b/src/components/GrossButton.tsx index 8ea91f5..a9c0458 100644 --- a/src/components/GrossButton.tsx +++ b/src/components/GrossButton.tsx @@ -1,10 +1,15 @@ /** - * Großer, barrierefreier Button: min. 56px hoch, große Schrift, - * hoher Kontrast. Varianten: primär (gefüllt) und sekundär (Umriss). + * Großer, barrierefreier Button nach iOS-Vorbild: + * - primär: gefüllt mit der Marken-Tintfarbe (wie "prominente" iOS-Buttons) + * - sekundär: hellgraue Fläche mit Tint-Text (wie Apples "graue Taste" — + * bewusst keine Umrandung, das wirkt nativer) + * - gefahr: rot gefüllt + * Min. 56px hoch, große Schrift, System-Icons statt Emojis. */ import React from 'react'; -import { ActivityIndicator, Pressable, StyleSheet, Text } from 'react-native'; +import { ActivityIndicator, Pressable, StyleSheet, Text, View } from 'react-native'; import { farben, schrift, abstand, TOUCH_TARGET } from '../theme'; +import { Ikone, IkonenName } from './Ikone'; interface Props { titel: string; @@ -12,7 +17,7 @@ interface Props { variante?: 'primaer' | 'sekundaer' | 'gefahr'; deaktiviert?: boolean; laedt?: boolean; - symbol?: string; + ikone?: IkonenName; } export function GrossButton({ @@ -21,10 +26,11 @@ export function GrossButton({ variante = 'primaer', deaktiviert = false, laedt = false, - symbol, + ikone, }: Props) { const istPrimaer = variante === 'primaer'; const istGefahr = variante === 'gefahr'; + const inhaltsFarbe = istPrimaer || istGefahr ? farben.primaerText : farben.primaer; return ( {laedt ? ( - + ) : ( - - {symbol ? `${symbol} ` : ''} - {titel} - + + {ikone ? : null} + {titel} + )} ); @@ -61,24 +61,17 @@ export function GrossButton({ const styles = StyleSheet.create({ button: { minHeight: TOUCH_TARGET, - borderRadius: 16, + borderRadius: 14, justifyContent: 'center', alignItems: 'center', paddingHorizontal: abstand.l, paddingVertical: abstand.s, }, - primaer: { - backgroundColor: farben.primaer, - // Tiefe fürs wichtigste Element auf dem Bildschirm - shadowColor: farben.primaer, - shadowOffset: { width: 0, height: 4 }, - shadowOpacity: 0.28, - shadowRadius: 6, - elevation: 4, - }, - sekundaer: { backgroundColor: farben.flaeche, borderWidth: 2, borderColor: farben.primaer }, + zeile: { flexDirection: 'row', alignItems: 'center', gap: abstand.xs + 2 }, + primaer: { backgroundColor: farben.primaer }, + sekundaer: { backgroundColor: farben.flaecheSekundaer }, gefahr: { backgroundColor: farben.fehler }, - deaktiviert: { opacity: 0.5 }, - gedrueckt: { opacity: 0.8, transform: [{ translateY: 1 }] }, - text: { fontSize: schrift.gross, fontWeight: '700', textAlign: 'center' }, + deaktiviert: { opacity: 0.4 }, + gedrueckt: { opacity: 0.65 }, + text: { fontSize: schrift.gross, fontWeight: '600', textAlign: 'center' }, }); diff --git a/src/components/Ikone.tsx b/src/components/Ikone.tsx new file mode 100644 index 0000000..169a5a2 --- /dev/null +++ b/src/components/Ikone.tsx @@ -0,0 +1,72 @@ +/** + * Zentrale Icon-Komponente — echte System-Icons statt Emojis: + * SF Symbols auf iOS (Apple-Look), Material Symbols auf Android. + * Alle in der App verwendeten Icons sind hier benannt, damit die + * Plattform-Zuordnung an einer Stelle liegt. + */ +import React from 'react'; +import { SymbolView } from 'expo-symbols'; + +export type IkonenName = + | 'kamera' + | 'galerie' + | 'dokument' + | 'buch' + | 'zahnrad' + | 'brief' + | 'pfeilRechts' + | 'vorlesen' + | 'stopp' + | 'kalender' + | 'stift' + | 'teilen' + | 'muell' + | 'globus' + | 'checkAn' + | 'checkAus' + | 'warnung' + | 'wecker' + | 'info' + | 'funken'; + +// `as const` hält die Namen als Literal-Typen — so prüft TypeScript gegen +// die offizielle SF-Symbol-/Material-Namensliste von expo-symbols +const NAMEN = { + kamera: { ios: 'camera.fill', android: 'photo_camera' }, + galerie: { ios: 'photo.on.rectangle', android: 'image' }, + dokument: { ios: 'doc.fill', android: 'description' }, + buch: { ios: 'book.fill', android: 'menu_book' }, + zahnrad: { ios: 'gearshape.fill', android: 'settings' }, + brief: { ios: 'envelope.open.fill', android: 'mail' }, + pfeilRechts: { ios: 'chevron.right', android: 'chevron_right' }, + vorlesen: { ios: 'speaker.wave.2.fill', android: 'volume_up' }, + stopp: { ios: 'stop.fill', android: 'stop' }, + kalender: { ios: 'calendar.badge.plus', android: 'event' }, + stift: { ios: 'square.and.pencil', android: 'edit' }, + teilen: { ios: 'square.and.arrow.up', android: 'share' }, + muell: { ios: 'trash.fill', android: 'delete' }, + globus: { ios: 'globe', android: 'language' }, + checkAn: { ios: 'checkmark.square.fill', android: 'check_box' }, + checkAus: { ios: 'square', android: 'check_box_outline_blank' }, + warnung: { ios: 'exclamationmark.triangle.fill', android: 'warning' }, + wecker: { ios: 'alarm.fill', android: 'alarm' }, + info: { ios: 'info.circle.fill', android: 'info' }, + funken: { ios: 'wand.and.stars', android: 'auto_awesome' }, +} as const; + +interface Props { + name: IkonenName; + groesse?: number; + farbe: string; +} + +export function Ikone({ name, groesse = 22, farbe }: Props) { + const eintrag = NAMEN[name]; + return ( + + ); +} diff --git a/src/screens/AnalyseScreen.tsx b/src/screens/AnalyseScreen.tsx index ef128d7..13ae141 100644 --- a/src/screens/AnalyseScreen.tsx +++ b/src/screens/AnalyseScreen.tsx @@ -23,7 +23,8 @@ import { formatiereDatum } from '../services/erinnerungen'; import { berechneAmpel } from '../utils/ampel'; import { Ampel } from '../components/Ampel'; import { GrossButton } from '../components/GrossButton'; -import { farben, schrift, abstand, kartenSchatten, TOUCH_TARGET } from '../theme'; +import { Ikone } from '../components/Ikone'; +import { farben, schrift, abstand, TOUCH_TARGET } from '../theme'; type Props = NativeStackScreenProps; @@ -133,9 +134,13 @@ export function AnalyseScreen({ navigation, route }: Props) { accessibilityRole="button" accessibilityLabel={`Sprache ändern. Aktuell: ${sprache.name}`} > - - 🌐 {sprache.eigenname} {uebersetzt ? ' (übersetzt…)' : ''} - + + + + {sprache.eigenname} {uebersetzt ? ' (übersetzt…)' : ''} + + + {/* Kernaussage: Was will das Amt von mir? */} @@ -145,7 +150,7 @@ export function AnalyseScreen({ navigation, route }: Props) { @@ -162,7 +167,7 @@ export function AnalyseScreen({ navigation, route }: Props) { > {analyse.frist && ( - 📅 Frist: {formatiereDatum(analyse.frist.datum)} + Frist: {formatiereDatum(analyse.frist.datum)} {'\n'} {analyse.frist.aktion} @@ -170,13 +175,13 @@ export function AnalyseScreen({ navigation, route }: Props) { {analyse.termin && ( <> - 🕐 Termin: {formatiereDatum(analyse.termin.datum)} + Termin: {formatiereDatum(analyse.termin.datum)} {analyse.termin.uhrzeit ? ` um ${analyse.termin.uhrzeit} Uhr` : ''} - {analyse.termin.ort ? `\n📍 ${analyse.termin.ort}` : ''} + {analyse.termin.ort ? `\nOrt: ${analyse.termin.ort}` : ''} @@ -203,7 +208,11 @@ export function AnalyseScreen({ navigation, route }: Props) { accessibilityRole="checkbox" accessibilityState={{ checked: !!erledigt[i] }} > - {erledigt[i] ? '☑️' : '⬜'} + {punkt} @@ -229,13 +238,13 @@ export function AnalyseScreen({ navigation, route }: Props) { {analyse.antwort_noetig && ( navigation.navigate('Antwort', { briefId: brief.id })} /> )} - + {/* Sprach-Auswahl-Dialog */} @@ -275,23 +284,19 @@ const styles = StyleSheet.create({ zentriert: { flex: 1, justifyContent: 'center', alignItems: 'center' }, karte: { backgroundColor: farben.flaeche, - borderRadius: 16, - borderWidth: 1, - borderColor: farben.rand, + borderRadius: 12, padding: abstand.m, marginTop: abstand.m, gap: abstand.s, - ...kartenSchatten, }, - // DIE Antwort der App — als "Textmarker"-Karte hervorgehoben (Markenzeichen) + // DIE Antwort der App — dezent im Marken-Tint hervorgehoben karteWichtig: { - backgroundColor: farben.markerHintergrund, - borderRadius: 16, + backgroundColor: farben.hervorhebung, + borderRadius: 12, borderWidth: 1, - borderColor: farben.markerRand, + borderColor: farben.hervorhebungRand, padding: abstand.m, marginTop: abstand.m, - ...kartenSchatten, }, abschnittTitel: { fontSize: schrift.gross, @@ -310,22 +315,19 @@ const styles = StyleSheet.create({ minHeight: 44, paddingVertical: 4, }, - checkBox: { fontSize: 24 }, durchgestrichen: { textDecorationLine: 'line-through', color: farben.textSekundaer }, begriffBlock: { marginBottom: abstand.s }, begriff: { fontSize: schrift.basis, fontWeight: '700', color: farben.text }, sprachButton: { marginTop: abstand.m, minHeight: TOUCH_TARGET, - borderRadius: 16, - borderWidth: 1, - borderColor: farben.rand, + borderRadius: 12, backgroundColor: farben.flaeche, justifyContent: 'center', paddingHorizontal: abstand.m, - ...kartenSchatten, }, - sprachButtonText: { fontSize: schrift.basis, color: farben.text, fontWeight: '600' }, + sprachZeileInhalt: { flexDirection: 'row', alignItems: 'center', gap: abstand.s }, + sprachButtonText: { flex: 1, fontSize: schrift.basis, color: farben.text, fontWeight: '600' }, modalHintergrund: { flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', @@ -333,7 +335,7 @@ const styles = StyleSheet.create({ padding: abstand.l, }, modalKarte: { - backgroundColor: farben.hintergrund, + backgroundColor: farben.flaeche, borderRadius: 14, padding: abstand.m, maxHeight: '75%', diff --git a/src/screens/AntwortScreen.tsx b/src/screens/AntwortScreen.tsx index 540df7c..37005a5 100644 --- a/src/screens/AntwortScreen.tsx +++ b/src/screens/AntwortScreen.tsx @@ -146,7 +146,7 @@ export function AntwortScreen({ route }: Props) { - - + + )} diff --git a/src/screens/EinstellungenScreen.tsx b/src/screens/EinstellungenScreen.tsx index c4f1615..b14ce76 100644 --- a/src/screens/EinstellungenScreen.tsx +++ b/src/screens/EinstellungenScreen.tsx @@ -260,7 +260,7 @@ export function EinstellungenScreen({ navigation }: Props) { Daten löschen - + ); diff --git a/src/screens/HomeScreen.tsx b/src/screens/HomeScreen.tsx index 5c9461a..e9affb5 100644 --- a/src/screens/HomeScreen.tsx +++ b/src/screens/HomeScreen.tsx @@ -18,29 +18,30 @@ import { holeConsent } from '../services/storage'; import { berechneAmpel } from '../utils/ampel'; import { formatiereDatum } from '../services/erinnerungen'; import { GrossButton } from '../components/GrossButton'; -import { farben, schrift, abstand, kartenSchatten, TOUCH_TARGET } from '../theme'; +import { Ikone, IkonenName } from '../components/Ikone'; +import { farben, schrift, abstand, TOUCH_TARGET } from '../theme'; type Props = NativeStackScreenProps; -/** Quadratische Navigations-Kachel: Symbol oben, Beschriftung darunter. +/** Quadratische Navigations-Kachel: Icon oben, Beschriftung darunter. * (Löst das Platzproblem nebeneinanderstehender Text-Buttons.) */ function Kachel({ - symbol, + ikone, titel, onPress, }: { - symbol: string; + ikone: IkonenName; titel: string; onPress: () => void; }) { return ( [styles.kachel, pressed && { opacity: 0.7 }]} + style={({ pressed }) => [styles.kachel, pressed && { opacity: 0.65 }]} onPress={onPress} accessibilityRole="button" accessibilityLabel={titel} > - {symbol} + {titel} @@ -105,7 +106,7 @@ export function HomeScreen({ navigation }: Props) { {ampel.text} - + ); }; @@ -122,11 +123,11 @@ export function HomeScreen({ navigation }: Props) { contentContainerStyle={styles.inhalt} ListHeaderComponent={ - + - navigation.navigate('Glossar')} /> + navigation.navigate('Glossar')} /> navigation.navigate('Einstellungen')} /> @@ -149,7 +150,7 @@ export function HomeScreen({ navigation }: Props) { ListEmptyComponent={ briefe.length === 0 ? ( - 📬 + Noch keine Briefe Scannen Sie Ihren ersten Behördenbrief —{'\n'}in einer Minute @@ -173,16 +174,12 @@ const styles = StyleSheet.create({ flex: 1, minHeight: TOUCH_TARGET + 22, backgroundColor: farben.flaeche, - borderRadius: 16, - borderWidth: 1, - borderColor: farben.rand, + borderRadius: 12, alignItems: 'center', justifyContent: 'center', paddingVertical: abstand.s, - gap: 4, - ...kartenSchatten, + gap: 6, }, - kachelSymbol: { fontSize: 26 }, kachelTitel: { fontSize: schrift.klein + 1, fontWeight: '600', color: farben.primaer }, abschnittsLabel: { marginTop: abstand.m, @@ -194,8 +191,6 @@ const styles = StyleSheet.create({ }, suche: { backgroundColor: farben.flaeche, - borderWidth: 1, - borderColor: farben.rand, borderRadius: 12, padding: abstand.s, fontSize: schrift.basis, @@ -206,21 +201,16 @@ const styles = StyleSheet.create({ flexDirection: 'row', alignItems: 'center', backgroundColor: farben.flaeche, - borderRadius: 14, - borderWidth: 1, - borderColor: farben.rand, + borderRadius: 12, borderLeftWidth: 6, padding: abstand.m, marginBottom: abstand.s, gap: abstand.s, - ...kartenSchatten, }, kartenTitel: { fontSize: schrift.basis, fontWeight: '700', color: farben.text }, kartenUntertitel: { fontSize: schrift.klein, color: farben.textSekundaer, marginTop: 2 }, kartenAmpelText: { fontSize: schrift.klein, fontWeight: '600', marginTop: 2 }, - pfeil: { fontSize: 32, color: farben.textSekundaer }, - leerBox: { alignItems: 'center', marginTop: abstand.xl, gap: abstand.xs }, - leerSymbol: { fontSize: 52 }, + leerBox: { alignItems: 'center', marginTop: abstand.xl, gap: abstand.s }, leerTitel: { fontSize: schrift.gross, fontWeight: '700', color: farben.text }, leer: { textAlign: 'center', diff --git a/src/screens/ScanScreen.tsx b/src/screens/ScanScreen.tsx index 9d992c3..ebadad0 100644 --- a/src/screens/ScanScreen.tsx +++ b/src/screens/ScanScreen.tsx @@ -182,9 +182,9 @@ export function ScanScreen({ navigation }: Props) { Fotografieren Sie den Brief gut beleuchtet und von oben. Der ganze Text muss auf dem Foto sein. - - - + + + {NUTZT_PROXY && ( {kontingentLeer diff --git a/src/theme.ts b/src/theme.ts index 5d2fbfb..c4b2679 100644 --- a/src/theme.ts +++ b/src/theme.ts @@ -5,18 +5,20 @@ * - Große Touch-Targets (min. 56px Höhe) */ export const farben = { - // Grundfarben — warmer Papier-Ton als Markenzeichen (wie die Webseite): - // Inhalte liegen als weiße "Blätter" auf Papier - hintergrund: '#FAF7F0', + // Grundfarben — natives iOS-Vorbild: gruppierter System-Hintergrund, + // Inhalte als weiße Karten ohne Rahmen und Schatten (wie Einstellungen/Health) + hintergrund: '#F2F2F7', flaeche: '#FFFFFF', - primaer: '#1A365D', // dunkles, ruhiges Blau + flaecheSekundaer: '#E9EDF3', // "graue Taste" nach Apple-Art (statt Umrandung) + primaer: '#1A365D', // dunkles, ruhiges Blau (Marken-Tint) primaerText: '#FFFFFF', text: '#1A202C', textSekundaer: '#4A5568', - rand: '#E4DECF', - // Akzent: Textmarker-Gelb (sparsam einsetzen — nur für DIE Kernaussage) - markerHintergrund: '#FFF6D2', - markerRand: '#EBDD9A', + textTertiaer: '#AEAEB2', // z. B. Chevrons (iOS systemGray2) + rand: '#E2E2E7', + // Dezente Hervorhebung für DIE Kernaussage (leichter Marken-Tint) + hervorhebung: '#EDF2F9', + hervorhebungRand: '#DCE5F1', // Dringlichkeits-Ampel (kräftig, gut unterscheidbar) ampelRot: '#C0392B', @@ -48,11 +50,9 @@ export const abstand = { /** Mindesthöhe für alle interaktiven Elemente (Barrierefreiheit). */ export const TOUCH_TARGET = 56; -/** Dezenter Schatten, damit weiße Karten sich vom Papier-Grund abheben. */ -export const kartenSchatten = { - shadowColor: '#1A202C', - shadowOffset: { width: 0, height: 2 }, - shadowOpacity: 0.07, - shadowRadius: 6, - elevation: 2, -} as const; +/** + * Bewusst leer: Nach Apple-Vorbild heben sich weiße Karten allein durch + * den grauen System-Hintergrund ab — ohne Schatten und Rahmen. + * (Als No-Op behalten, damit bestehende Spreads harmlos bleiben.) + */ +export const kartenSchatten = {} as const;