diff --git a/apps/mobile/components/MessageActionsSheet.tsx b/apps/mobile/components/MessageActionsSheet.tsx
new file mode 100644
index 0000000..0de024f
--- /dev/null
+++ b/apps/mobile/components/MessageActionsSheet.tsx
@@ -0,0 +1,103 @@
+import { Modal, Pressable, StyleSheet, Text } from 'react-native';
+
+import { ReactionStrip } from './ReactionStrip';
+import { colors } from '../theme/colors';
+
+interface Props {
+ visible: boolean;
+ mine: boolean;
+ onClose: () => void;
+ onReact: (emoji: string) => void;
+ onReply: () => void;
+ onDelete: () => void;
+}
+
+// Bottom-sheet-style modal opened on long-press of a message bubble.
+// Contains the reaction quick-strip plus the action rows. The "Löschen"
+// row is hidden for messages not authored by the current user — the
+// server-side trigger would refuse anyway, but trimming UI keeps the
+// surface honest.
+export function MessageActionsSheet({
+ visible,
+ mine,
+ onClose,
+ onReact,
+ onReply,
+ onDelete,
+}: Props) {
+ return (
+
+
+ undefined}>
+ {
+ onReact(e);
+ onClose();
+ }}
+ />
+ { onReply(); onClose(); }} />
+ {mine && (
+ { onDelete(); onClose(); }}
+ />
+ )}
+
+
+
+
+ );
+}
+
+function Action({
+ label,
+ danger,
+ muted,
+ onPress,
+}: {
+ label: string;
+ danger?: boolean;
+ muted?: boolean;
+ onPress: () => void;
+}) {
+ return (
+ [styles.action, pressed && styles.actionPressed]}
+ >
+
+ {label}
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ backdrop: {
+ flex: 1,
+ justifyContent: 'flex-end',
+ backgroundColor: 'rgba(0,0,0,0.5)',
+ },
+ sheet: {
+ backgroundColor: colors.surface,
+ borderTopLeftRadius: 16,
+ borderTopRightRadius: 16,
+ paddingBottom: 24,
+ },
+ action: {
+ paddingVertical: 14,
+ paddingHorizontal: 20,
+ borderBottomColor: colors.border,
+ borderBottomWidth: 1,
+ },
+ actionPressed: { backgroundColor: colors.bg },
+ actionText: { color: colors.text, fontSize: 15, fontWeight: '500' },
+ actionDanger: { color: colors.danger },
+ actionMuted: { color: colors.textMuted },
+});