PageSourceSearch

https://www.savetoexo.com/privacy

html savetoexo.com collected 2026-10-02 01:42:30 UTC 14,174 bytes, 389 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en" id="html-root">
3<head>
4    
5    
6
7    
7<script>
8        /* Initialize dark theme */
9        document.documentElement.classList.add('dark');
10    </script>
10
11    <meta charset="UTF-8">
12    <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
13    <meta name="theme-color" content="#f5a623">
14    <meta name="apple-mobile-web-app-capable" content="yes">
15    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
16    <title>Privacy Policy - SaveToExo</title>
17
18    <!-- PWA Manifest & Icons -->
19    <link rel="manifest" href="/static/manifest.json">
20    <link rel="icon" type="image/png" sizes="48x48" href="/static/images/icon-48.png">
21    <link rel="icon" type="image/png" sizes="128x128" href="/static/images/icon-128.png">
22    <link rel="apple-touch-icon" href="/static/images/apple-touch-icon.png">
23
24    <!-- OpenGraph Meta Tags for WhatsApp/Social Sharing -->
25    
26    <meta property="og:title" content="SaveToExo - save anything, ask it anything" />
27    <meta property="og:description" content="Save a link from anywhere. Then ask your saves a question in plain English, or connect your memory to Claude and ChatGPT." />
28    <meta property="og:image" content="https://www.savetoexo.com/static/images/og-image.png" />
29    <meta property="og:url" content="https://www.savetoexo.com" />
30    <meta property="og:type" content="website" />
31    <meta property="og:site_name" content="SaveToExo" />
32    
33
34    <!-- Tailwind CSS -->
35    
36    
36<script src="https://cdn.tailwindcss.com"></script>
36
37
38    <!-- Tailwind Typography Plugin -->
39    <link rel="stylesheet" href="https://unpkg.com/@tailwindcss/[email protected]/dist/typography.min.css">
40
41    <!-- Google Fonts -->
42    <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet">
43
44    <!-- Alpine.js (CSP-safe build, self-hosted).
45         The page CSP deliberately omits 'unsafe-eval' (see main.py `_CSP`);
46         standard Alpine needs eval, this build does not. Components are
47         registered in exo-components.js, which MUST load before the Alpine
48         build, both are `defer` so they execute in document order. -->
49    
49<script defer src="/static/js/exo-components.js"></script>
49
50    
50<script defer src="/static/js/alpine-csp-3.14.1.min.js"></script>
50
51
52    <!-- HTMX -->
53    
53<script src="https://unpkg.com/[email protected]"></script>
53
54
55    <!-- Tailwind Configuration -->
56    
56<script>
57        tailwind.config = {
58            darkMode: 'class',
59            theme: {
60                extend: {
61                    fontFamily: {
62                        display: ['Space Grotesk', 'system-ui', 'sans-serif'],
63                        body: ['Inter', 'system-ui', 'sans-serif']
64                    },
65                    colors: {
66                        background: 'hsl(222, 47%, 6%)',
67                        foreground: 'hsl(45, 20%, 95%)',
68                        card: {
69                            DEFAULT: 'hsl(222, 40%, 9%)',
70                            foreground: 'hsl(45, 20%, 95%)'
71                        },
72                        primary: {
73                            DEFAULT: 'hsl(38, 92%, 55%)',
74                            glow: 'hsl(38, 100%, 65%)',
75                            foreground: 'hsl(222, 47%, 6%)'
76                        },
77                        muted: {
78                            DEFAULT: 'hsl(222, 25%, 15%)',
79                            foreground: 'hsl(222, 15%, 55%)'
80                        },
81                        accent: {
82                            DEFAULT: 'hsl(222, 35%, 20%)',
83                            foreground: 'hsl(45, 20%, 90%)'
84                        },
85                        border: 'hsl(222, 30%, 18%)',
86                        secondary: {
87                            DEFAULT: 'hsl(222, 30%, 18%)',
88                            foreground: 'hsl(45, 15%, 80%)'
89                        }
90                    },
91                    backdropBlur: {
92                        'xl': '24px'
93                    },
94                    boxShadow: {
95                        'card': '0 4px 24px -4px rgba(0, 0, 0, 0.4)',
96                        'card-hover': '0 8px 40px -8px rgba(0, 0, 0, 0.5)',
97                        'glow': '0 0 40px -10px hsl(38 92% 55% / 0.3)'
98                    }
99                }
100            }
101        }
102    </script>
102
103
104    <style>
105        /* Dark Theme Colors (default - only theme) */
106        html, html.dark {
107            --background: hsl(222, 47%, 12%);
108            --foreground: hsl(45, 20%, 95%);
109            --card: hsl(222, 40%, 16%);
110            --card-hover: hsl(222, 40%, 20%);
111            --primary: hsl(38, 92%, 55%);
112            --primary-glow: hsl(38, 100%, 65%);
113            --muted: hsl(222, 25%, 22%);
114            --muted-foreground: hsl(222, 15%, 55%);
115            --border: hsl(222, 30%, 24%);
116            --secondary: hsl(222, 30%, 24%);
117            --accent: hsl(222, 35%, 26%);
118        }
119
120        /* Glass morphism effects - dark theme */
121        html.dark .glass-card {
122            background: rgba(23, 32, 51, 0.8);
123            backdrop-filter: blur(24px);
124            -webkit-backdrop-filter: blur(24px);
125            border: 1px solid rgba(255, 255, 255, 0.05);
126        }
127
128        html.dark .glass-sidebar {
129            background: rgba(15, 23, 42, 0.3);
130            backdrop-filter: blur(16px);
131            -webkit-backdrop-filter: blur(16px);
132        }
133
134        html.dark .glass-nav {
135            background: rgba(23, 32, 51, 0.95);
136            backdrop-filter: blur(24px);
137            -webkit-backdrop-filter: blur(24px);
138        }
139
140        /* Animations */
141        @keyframes fadeInUp {
142            from {
143                opacity: 0;
144                transform: translateY(20px);
145            }
146            to {
147                opacity: 1;
148                transform: translateY(0);
149            }
150        }
151
152        @keyframes pulseGlow {
153            0%, 100% {
154                box-shadow: 0 0 20px -10px hsl(38 92% 55%);
155            }
156            50% {
157                box-shadow: 0 0 40px -5px hsl(38 92% 55%);
158            }
159        }
160
161        .animate-pulse-glow {
162            animation: pulseGlow 2s infinite;
163        }
164
165        @keyframes shimmer {
166            100% {
167                transform: translateX(100%);
168            }
169        }
170
171        .hover-glow:hover {
172            box-shadow: 0 0 40px -10px hsl(38 92% 55% / 0.3);
173            transition: box-shadow 0.3s ease;
174        }
175
176        /* Custom scrollbar */
177        ::-webkit-scrollbar {
178            width: 8px;
179            height: 8px;
180        }
181
182        ::-webkit-scrollbar-track {
183            background: hsl(222, 40%, 9%);
184        }
185
186        ::-webkit-scrollbar-thumb {
187            background: hsl(222, 30%, 18%);
188            border-radius: 4px;
189        }
190
191        ::-webkit-scrollbar-thumb:hover {
192            background: hsl(222, 15%, 55%);
193        }
194
195        /* Safe area for iOS */
196        .pb-safe {
197            padding-bottom: max(1rem, env(safe-area-inset-bottom));
198        }
199
200        /* Hide native search input clear button (we have custom one) */
201        input[type="search"]::-webkit-search-cancel-button,
202        input[type="search"]::-webkit-search-decoration {
203            -webkit-appearance: none;
204            appearance: none;
205        }
206
207        /* Body base styles */
208        body {
209            background-color: var(--background);
210            color: var(--foreground);
211            font-family: 'Inter', system-ui, sans-serif;
212            -webkit-font-smoothing: antialiased;
213            -moz-osx-font-smoothing: grayscale;
214            transition: background-color 0.3s ease, color 0.3s ease;
215        }
216
217        /* Prose styling for markdown content */
218        .prose {
219            color: inherit;
220        }
221
222        .prose strong {
223            color: hsl(45, 20%, 95%);
224            font-weight: 600;
225        }
226
227        .prose p {
228            margin: 0.75rem 0;
229        }
230
231        .prose a {
232            color: hsl(38, 92%, 55%);
233            text-decoration: underline;
234        }
235
236        .prose a:hover {
237            color: hsl(38, 100%, 65%);
238        }
239
240        /* Utility classes */
241        .text-primary-glow {
242            color: hsl(38, 100%, 65%);
243        }
244
245        .bg-primary-glow\/10 {
246            background-color: rgba(244, 164, 96, 0.1);
247        }
248
249        /* Prose typography overrides for markdown content */
250        .prose :where(h1, h2, h3, h4, h5, h6):not(:where([class~="not-prose"] *)) {
251            color: hsl(38, 100%, 75%) !important;  /* Bright amber */
252            font-family: 'Space Grotesk', system-ui, sans-serif !important;  /* Match display font */
253            font-weight: 600 !important;
254            margin-top: 1.5rem;
255            margin-bottom: 0.75rem;
256            line-height: 1.3 !important;
257        }
258
259        .prose :where(h3):not(:where([class~="not-prose"] *)) {
260            font-size: 1rem !important;  /* Match viewport text size */
261        }
262
263        .prose :where(p):not(:where([class~="not-prose"] *)) {
264            color: hsl(45, 20%, 90%) !important;
265            line-height: 1.75 !important;
266            margin-top: 0.5rem;
267            margin-bottom: 0.5rem;
268        }
269
270        /* Tight prose variant for card teasers */
271        .prose-tight :where(h1, h2, h3, h4, h5, h6):not(:where([class~="not-prose"] *)) {
272            font-size: 1rem;  /* text-base = 16px */
273            margin-top: 0.5rem;
274            margin-bottom: 0.25rem;
275        }
276
277        .prose-tight :where(p):not(:where([class~="not-prose"] *)) {
278            margin-top: 0.25rem;
279            margin-bottom: 0.25rem;
280        }
281
282        .prose :where(strong):not(:where([class~="not-prose"] *)) {
283            color: hsl(38, 100%, 75%) !important;
284            font-weight: 600 !important;
285        }
286
287        .prose :where(ul):not(:where([class~="not-prose"] *)) {
288            margin-top: 1rem;
289            margin-bottom: 1rem;
290            padding-left: 1rem !important;
291            border-left: 2px solid hsl(222, 30%, 24%) !important;
292            list-style-type: none !important;
293        }
294
295        .prose :where(li):not(:where([class~="not-prose"] *)) {
296            margin-top: 0.75rem;
297            margin-bottom: 0.75rem;
298            padding-left: 0.5rem !important;
299            line-height: 1.75 !important;
300        }
301
302        .prose :where(ol):not(:where([class~="not-prose"] *)) {
303            margin-top: 1rem;
304            margin-bottom: 1rem;
305            padding-left: 1rem !important;
306        }
307    </style>
308
309    
310</head>
311<body class="min-h-screen">
312    
313<div class="min-h-screen bg-background px-4 py-12">
314  <div class="max-w-2xl mx-auto">
315
316    <!-- Header -->
317    <div class="mb-8">
318      <a href="/" class="text-primary hover:text-primary-glow transition-colors text-sm">
319        ← Back to SaveToExo
320      </a>
321      <h1 class="font-display font-bold text-4xl text-foreground mt-4">Privacy Policy</h1>
322      <p class="text-muted-foreground mt-2">Last updated: August 2026</p>
323    </div>
324
325    <!-- Content -->
326    <div class="prose prose-invert max-w-none space-y-6 text-foreground">
327
328      <section class="space-y-3">
329        <h2 class="text-xl font-semibold text-primary">What we collect</h2>
330        <p class="text-muted-foreground leading-relaxed">
331          SaveToExo collects only what's necessary to provide the service:
332        </p>
333        <ul class="list-disc list-inside text-muted-foreground space-y-2 ml-2">
334          <li>Your Telegram user ID and username (for authentication)</li>
335          <li>Links you save and their content (articles, tweets, videos)</li>
336          <li>AI-generated summaries, tags, and insights from your saved content</li>
337          <li>Anonymous visits to our public landing page, including the page viewed, referring site, device type, and approximate country</li>
338        </ul>
339      </section>
340
341      <section class="space-y-3">
342        <h2 class="text-xl font-semibold text-primary">How we use your data</h2>
343        <ul class="list-disc list-inside text-muted-foreground space-y-2 ml-2">
344          <li>To save and process links you send us</li>
345          <li>To generate AI summaries and make your content searchable</li>
346          <li>To authenticate you via Telegram</li>
347          <li>To understand how people find our public landing page</li>
348        </ul>
349        <p class="text-muted-foreground leading-relaxed">
350          We do not sell your data. We do not show you ads. Your saved content is private to you.
351        </p>
352        <p class="text-muted-foreground leading-relaxed">
353          We use PostHog's EU-hosted service for cookieless, anonymous analytics on the public landing page only.
354          Session replay, interaction tracking, user identification, and analytics on signed-in pages are disabled.
355        </p>
356      </section>
357
358      <section class="space-y-3">
359        <h2 class="text-xl font-semibold text-primary">Data retention</h2>
360        <p class="text-muted-foreground leading-relaxed">
361          Your saved content is stored until you delete it. You can delete individual saves at any time from your feed.
362          If you want to delete your entire account and all associated data, contact us at
363          <a href="mailto:[email protected]" class="text-primary hover:underline">[email protected]</a>.
364        </p>
365      </section>
366
367      <section class="space-y-3">
368        <h2 class="text-xl font-semibold text-primary">Security</h2>
369        <p class="text-muted-foreground leading-relaxed">
370          We use industry-standard security practices including encrypted connections (HTTPS),
371          secure session tokens, and database-level access controls. Your data is hosted on
372          secure cloud infrastructure.
373        </p>
374      </section>
375
376      <section class="space-y-3">
377        <h2 class="text-xl font-semibold text-primary">Contact</h2>
378        <p class="text-muted-foreground leading-relaxed">
379          Questions about this policy? Email us at
380          <a href="mailto:[email protected]" class="text-primary hover:underline">[email protected]</a>.
381        </p>
382      </section>
383
384    </div>
385  </div>
386</div>
387
388</body>
389</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.