main
html 1,012 lines 48.4 KB
Raw
1 <html>
2
3 <head>
4 <title>Email Integration</title>
5 <script type="module">
6 import { store } from "/plugins/_email_integration/webui/email-config-store.js";
7 </script>
8 </head>
9
10 <body>
11 <div x-data x-init="$store.emailConfig.init(config, context)" x-destroy="$store.emailConfig.cleanup()">
12 <template x-if="config">
13 <div class="email-settings">
14 <div class="section-title">Email</div>
15
16 <template x-if="$store.emailConfig.didInit && $store.emailConfig.handlers.length === 0">
17 <div class="email-empty">
18 <div class="email-empty-title">Connect Agent Zero and your email account</div>
19 <div class="email-empty-copy">
20 Most people only need a provider, an email address, and an app password.
21 </div>
22 <button class="btn btn-field" @click="$store.emailConfig.addHandler()">
23 Connect
24 </button>
25 </div>
26 </template>
27
28 <template x-for="(handler, idx) in $store.emailConfig.handlers" :key="idx">
29 <div class="email-card">
30 <div class="email-card-header" @click="$store.emailConfig.toggleEditing(idx)">
31 <div class="email-card-heading">
32 <div class="email-card-title" x-text="$store.emailConfig.handlerTitle(handler, idx)">
33 </div>
34 <div class="email-card-subtitle" x-text="$store.emailConfig.handlerSubtitle(handler)">
35 </div>
36 </div>
37 <div class="email-card-actions">
38 <span class="email-status-pill"
39 :class="'tone-' + $store.emailConfig.statusTone(handler)"
40 x-text="$store.emailConfig.statusLabel(handler)"></span>
41 <button class="btn btn-action delete"
42 @click.stop="$confirmClick($event, () => $store.emailConfig.removeHandler(idx))"
43 title="Remove inbox">
44 <x-icon name="delete"></x-icon>
45 </button>
46 <x-icon class="email-card-chevron"
47 :class="{ 'is-open': $store.emailConfig.editing === idx }" name="expand_more"></x-icon>
48 </div>
49 </div>
50
51 <template x-if="$store.emailConfig.editing === idx">
52 <div class="email-card-body">
53 <div class="email-provider-panel"
54 :class="{ 'has-provider': $store.emailConfig.hasProvider(handler) }">
55 <div class="email-provider-topline">
56 <div class="email-provider-copy">
57 <div class="email-provider-title"
58 x-text="$store.emailConfig.hasProvider(handler) ? $store.emailConfig.providerLabel($store.emailConfig.providerValue(handler)) : 'Choose your email provider'">
59 </div>
60 <div class="email-provider-description"
61 x-text="$store.emailConfig.hasProvider(handler) ? $store.emailConfig.providerHint(handler) : 'Pick a provider and Agent Zero will prepare the usual incoming and outgoing mail settings.'">
62 </div>
63 <template x-if="$store.emailConfig.providerHelpUrl(handler)">
64 <a class="email-intro-link"
65 :href="$store.emailConfig.providerHelpUrl(handler)"
66 target="_blank"
67 rel="noopener"
68 x-text="$store.emailConfig.providerHelpLabel(handler)"></a>
69 </template>
70 </div>
71 <template x-if="$store.emailConfig.hasProvider(handler)">
72 <button type="button" class="btn btn-field email-change-provider"
73 @click.stop="$store.emailConfig.changeProvider(idx)"
74 x-text="$store.emailConfig.showProviderChoices(handler, idx) ? 'Done' : 'Change'">
75 </button>
76 </template>
77 </div>
78
79 <div class="email-provider-grid"
80 x-show="$store.emailConfig.showProviderChoices(handler, idx)">
81 <template x-for="provider in $store.emailConfig.providerOptions"
82 :key="provider.value">
83 <button type="button" class="email-provider-option"
84 :class="($store.emailConfig.providerValue(handler) === provider.value ? 'is-selected ' : '') + 'logo-' + provider.logo"
85 :aria-pressed="$store.emailConfig.providerValue(handler) === provider.value ? 'true' : 'false'"
86 :title="provider.label"
87 @click.stop="$store.emailConfig.selectProvider(handler, provider.value, idx)">
88 <span class="email-provider-logo" aria-hidden="true">
89 <template x-if="provider.logo === 'microsoft365'">
90 <span class="email-microsoft-mark">
91 <span></span>
92 <span></span>
93 <span></span>
94 <span></span>
95 </span>
96 </template>
97 <template
98 x-if="provider.logo !== 'microsoft365' && (provider.logo === 'icloud' || provider.logo === 'custom-imap')">
99 <x-icon
100 :name="provider.logoText"></x-icon>
101 </template>
102 <template
103 x-if="provider.logo !== 'microsoft365' && provider.logo !== 'icloud' && provider.logo !== 'custom-imap'">
104 <span x-text="provider.logoText"></span>
105 </template>
106 </span>
107 <span class="email-provider-name" x-text="provider.label"></span>
108 <span class="email-provider-hint" x-text="provider.hint"></span>
109 </button>
110 </template>
111 </div>
112 </div>
113
114 <div class="email-post-provider" x-show="$store.emailConfig.hasProvider(handler)">
115 <div class="field">
116 <div class="field-label">
117 <div class="field-title">Turn on this inbox</div>
118 <div class="field-description">Enable when you are ready for Agent Zero to
119 start checking mail.</div>
120 </div>
121 <div class="field-control">
122 <label class="toggle">
123 <input type="checkbox" x-model="handler.enabled" />
124 <span class="toggler"></span>
125 </label>
126 </div>
127 </div>
128
129 <div class="field">
130 <div class="field-label">
131 <div class="field-title">Email address</div>
132 <div class="field-description">Usually the full address for this inbox.</div>
133 </div>
134 <div class="field-control">
135 <input type="text" x-model="handler.username"
136 @input="$store.emailConfig.maybeAutoname(handler)"
137 placeholder="name@company.com" />
138 </div>
139 </div>
140
141 <div class="field">
142 <div class="field-label">
143 <div class="field-title">Password</div>
144 <div class="field-description">An app password is best. Many mail providers
145 block regular account passwords.</div>
146 </div>
147 <div class="field-control">
148 <input type="password" x-model="handler.password" />
149 </div>
150 </div>
151
152 <template x-if="$store.emailConfig.showExchangeServer(handler)">
153 <div>
154 <div class="field">
155 <div class="field-label">
156 <div class="field-title"
157 x-text="$store.emailConfig.incomingLabel(handler)"></div>
158 <div class="field-description"
159 x-text="$store.emailConfig.incomingDescription(handler)"></div>
160 </div>
161 <div class="field-control">
162 <input type="text" x-model="handler.imap_server"
163 :placeholder="$store.emailConfig.incomingPlaceholder(handler)" />
164 </div>
165 </div>
166 </div>
167 </template>
168
169 <template x-if="$store.emailConfig.showManualServers(handler)">
170 <div class="email-grid">
171 <div class="field">
172 <div class="field-label">
173 <div class="field-title">Incoming mail server</div>
174 <div class="field-description">The IMAP server for this inbox.</div>
175 </div>
176 <div class="field-control">
177 <input type="text" x-model="handler.imap_server"
178 placeholder="imap.your-provider.com" />
179 </div>
180 </div>
181
182 <div class="field">
183 <div class="field-label">
184 <div class="field-title">Incoming port</div>
185 <div class="field-description">993 is the usual SSL port.</div>
186 </div>
187 <div class="field-control">
188 <input type="number" x-model.number="handler.imap_port"
189 placeholder="993" />
190 </div>
191 </div>
192
193 <div class="field">
194 <div class="field-label">
195 <div class="field-title">Outgoing mail server</div>
196 <div class="field-description">The SMTP server used for replies.
197 </div>
198 </div>
199 <div class="field-control">
200 <input type="text" x-model="handler.smtp_server"
201 placeholder="smtp.your-provider.com" />
202 </div>
203 </div>
204
205 <div class="field">
206 <div class="field-label">
207 <div class="field-title">Outgoing port</div>
208 <div class="field-description">587 is the usual TLS port.</div>
209 </div>
210 <div class="field-control">
211 <input type="number" x-model.number="handler.smtp_port"
212 placeholder="587" />
213 </div>
214 </div>
215 </div>
216 </template>
217
218 <template
219 x-if="!$store.emailConfig.showManualServers(handler) && !$store.emailConfig.showExchangeServer(handler) && $store.emailConfig.providerValue(handler)">
220 <div class="email-note">
221 Server settings are filled in for <span
222 x-text="$store.emailConfig.providerLabel($store.emailConfig.providerValue(handler))"></span>.
223 You can change them any time in Advanced.
224 </div>
225 </template>
226
227 <div class="email-missing"
228 x-show="$store.emailConfig.missingBits(handler).length > 0">
229 Still needed:
230 <span x-text="$store.emailConfig.missingBits(handler).join(', ')"></span>
231 </div>
232
233 <div class="field">
234 <div class="field-label">
235 <div class="field-title">Routing instructions</div>
236 <div class="field-description">Extra guidance for how incoming email should be
237 routed into chats.</div>
238 </div>
239 <div class="field-control">
240 <textarea x-model="handler.dispatcher_instructions" rows="3"
241 placeholder="Always start a new chat for invoices or billing questions."></textarea>
242 </div>
243 </div>
244
245 <div class="field">
246 <div class="field-label">
247 <div class="field-title">Reply instructions</div>
248 <div class="field-description">Extra guidance for the agent when it replies by
249 email.</div>
250 </div>
251 <div class="field-control">
252 <textarea x-model="handler.agent_instructions" rows="3"
253 placeholder="Reply in a calm, concise tone."></textarea>
254 </div>
255 </div>
256
257 <div class="email-test-panel">
258 <div class="email-test-copy">
259 <div class="email-test-title">Check the connection</div>
260 <div class="email-test-description"
261 x-text="$store.emailConfig.testIntro(handler)"></div>
262 </div>
263 <button class="btn btn-field" @click.stop="$store.emailConfig.testConnection(idx)"
264 :disabled="$store.emailConfig.testing === idx || !$store.emailConfig.canTest(handler)">
265 <span x-text="$store.emailConfig.testButtonLabel(handler, idx)"></span>
266 </button>
267 </div>
268
269 <template
270 x-if="$store.emailConfig.testResults && $store.emailConfig.testResultsFor === idx">
271 <div class="email-results"
272 :class="{ 'is-error': !$store.emailConfig.testResults.success }">
273 <template x-for="result in $store.emailConfig.testResults.results"
274 :key="result.test + result.message">
275 <div class="email-result-row">
276 <span class="email-result-icon" x-text="result.ok ? '✓' : '✗'"></span>
277 <div class="email-result-copy">
278 <div class="email-result-title"
279 x-text="$store.emailConfig.resultTitle(result)"></div>
280 <div class="email-result-message"
281 x-text="$store.emailConfig.resultMessage(result)"></div>
282 </div>
283 </div>
284 </template>
285 </div>
286 </template>
287 </div>
288
289 <details class="email-advanced" x-show="$store.emailConfig.hasProvider(handler)">
290 <summary>
291 <span>Advanced</span>
292 <x-icon class="email-advanced-chevron"
293 aria-hidden="true" name="keyboard_arrow_down"></x-icon>
294 </summary>
295 <div class="email-advanced-body">
296 <div class="field">
297 <div class="field-label">
298 <div class="field-title">Inbox name</div>
299 <div class="field-description">A friendly internal label for this
300 connection.</div>
301 </div>
302 <div class="field-control">
303 <input type="text" x-model="handler.name" placeholder="support" />
304 </div>
305 </div>
306
307 <div class="email-grid">
308 <div class="field">
309 <div class="field-label">
310 <div class="field-title">Incoming mail server</div>
311 <div class="field-description">Override the auto-filled incoming
312 server if needed.</div>
313 </div>
314 <div class="field-control">
315 <input type="text" x-model="handler.imap_server"
316 placeholder="imap.your-provider.com" />
317 </div>
318 </div>
319
320 <div class="field">
321 <div class="field-label">
322 <div class="field-title">Incoming port</div>
323 <div class="field-description">993 is the common SSL port.</div>
324 </div>
325 <div class="field-control">
326 <input type="number" x-model.number="handler.imap_port"
327 placeholder="993" />
328 </div>
329 </div>
330
331 <div class="field">
332 <div class="field-label">
333 <div class="field-title">Outgoing mail server</div>
334 <div class="field-description">Override the auto-filled reply server
335 if needed.</div>
336 </div>
337 <div class="field-control">
338 <input type="text" x-model="handler.smtp_server"
339 placeholder="smtp.your-provider.com" />
340 </div>
341 </div>
342
343 <div class="field">
344 <div class="field-label">
345 <div class="field-title">Outgoing port</div>
346 <div class="field-description">587 is the common TLS port.</div>
347 </div>
348 <div class="field-control">
349 <input type="number" x-model.number="handler.smtp_port"
350 placeholder="587" />
351 </div>
352 </div>
353 </div>
354
355 <div class="field">
356 <div class="field-label">
357 <div class="field-title">Project</div>
358 <div class="field-description">Open email conversations inside a
359 specific project.</div>
360 </div>
361 <div class="field-control">
362 <select :value="handler.project"
363 @change="handler.project = $event.target.value">
364 <option value="">No project</option>
365 <template x-for="proj in $store.emailConfig.projects"
366 :key="proj.name">
367 <option :value="proj.name" x-text="proj.title || proj.name"
368 :selected="handler.project === proj.name"></option>
369 </template>
370 </select>
371 </div>
372 </div>
373
374 <div class="field">
375 <div class="field-label">
376 <div class="field-title">Allowed senders</div>
377 <div class="field-description">Leave empty to allow anyone. Wildcards
378 like *@company.com work.</div>
379 </div>
380 <div class="field-control">
381 <input type="text" :value="$store.emailConfig.whitelistText(handler)"
382 @input="$store.emailConfig.setWhitelist(handler, $event.target.value)"
383 placeholder="*@company.com, founder@company.com" />
384 </div>
385 </div>
386
387 <div class="field">
388 <div class="field-label">
389 <div class="field-title">Catch up on unread mail</div>
390 <div class="field-description">On startup, process unread mail from the
391 last N days. Use 0 for brand-new mail only.</div>
392 </div>
393 <div class="field-control">
394 <input type="number" x-model.number="handler.process_unread_days"
395 min="0" placeholder="0" />
396 </div>
397 </div>
398
399 <div class="field">
400 <div class="field-label">
401 <div class="field-title">Check for new mail</div>
402 <div class="field-description"
403 x-text="$store.emailConfig.frequencyHint(handler)"></div>
404 </div>
405 <div class="field-control">
406 <select :value="$store.emailConfig.frequencyValue(handler)"
407 @change="$store.emailConfig.applyFrequency(handler, $event.target.value)">
408 <option value="15">Every 15 seconds</option>
409 <option value="30">Every 30 seconds</option>
410 <option value="60">Every minute</option>
411 <option value="300">Every 5 minutes</option>
412 <option value="900">Every 15 minutes</option>
413 <option value="custom">Custom schedule</option>
414 </select>
415 </div>
416 </div>
417
418 <div class="field"
419 x-show="$store.emailConfig.frequencyValue(handler) === 'custom'">
420 <div class="field-label">
421 <div class="field-title">Scheduling mode</div>
422 <div class="field-description">Use seconds for a simple interval, or
423 switch to cron for full control.</div>
424 </div>
425 <div class="field-control">
426 <select x-model="handler.poll_mode">
427 <option value="seconds">Seconds</option>
428 <option value="cron">Cron</option>
429 </select>
430 </div>
431 </div>
432
433 <div class="field"
434 x-show="$store.emailConfig.frequencyValue(handler) === 'custom' && handler.poll_mode === 'seconds'">
435 <div class="field-label">
436 <div class="field-title">Poll interval (seconds)</div>
437 <div class="field-description">The exact delay between inbox checks.
438 </div>
439 </div>
440 <div class="field-control">
441 <input type="number" x-model.number="handler.poll_interval_seconds"
442 min="5" placeholder="60" />
443 </div>
444 </div>
445
446 <div class="field"
447 x-show="$store.emailConfig.frequencyValue(handler) === 'custom' && handler.poll_mode === 'cron'">
448 <div class="field-label">
449 <div class="field-title">Cron expression</div>
450 <div class="field-description">For example, */2 * * * * checks every two
451 minutes.</div>
452 </div>
453 <div class="field-control">
454 <input type="text" x-model="handler.poll_interval_cron"
455 placeholder="*/2 * * * *" />
456 </div>
457 </div>
458
459 <div class="field">
460 <div class="field-label">
461 <div class="field-title">Routing model</div>
462 <div class="field-description">Utility is faster. Chat is more capable
463 when routing gets nuanced.</div>
464 </div>
465 <div class="field-control">
466 <select x-model="handler.dispatcher_model">
467 <option value="utility">Utility</option>
468 <option value="chat">Chat</option>
469 </select>
470 </div>
471 </div>
472
473 <div class="field">
474 <div class="field-label">
475 <div class="field-title">Conversation config</div>
476 <div class="field-description">Optional model preset for new chats created from this inbox.</div>
477 </div>
478 <div class="field-control">
479 <select x-model="handler.chat_model_preset">
480 <option value="">Default</option>
481 <template x-for="preset in $store.emailConfig.modelPresets" :key="preset.name">
482 <option :value="preset.name" x-text="preset.name"></option>
483 </template>
484 </select>
485 </div>
486 </div>
487
488 </div>
489 </details>
490 </div>
491 </template>
492 </div>
493 </template>
494
495 <template x-if="$store.emailConfig.handlers.length > 0">
496 <button class="btn btn-field email-add-another" @click="$store.emailConfig.addHandler()">
497 Connect another inbox
498 </button>
499 </template>
500 </div>
501 </template>
502 </div>
503
504 <style>
505 .email-settings {
506 display: flex;
507 flex-direction: column;
508 gap: 0.9rem;
509 }
510
511 .email-advanced summary {
512 cursor: pointer;
513 list-style: none;
514 font-weight: 700;
515 display: flex;
516 align-items: center;
517 gap: 0.75rem;
518 }
519
520 .email-advanced summary::-webkit-details-marker {
521 display: none;
522 }
523
524 .email-advanced summary {
525 padding: 0.95rem 1rem;
526 }
527
528 .email-advanced-chevron {
529 margin-left: auto;
530 flex: 0 0 auto;
531 transition: transform 0.18s ease, opacity 0.18s ease;
532 opacity: 0.72;
533 }
534
535 .email-advanced[open] .email-advanced-chevron {
536 transform: rotate(180deg);
537 opacity: 1;
538 }
539
540 .email-guide-card {
541 border: 1px solid color-mix(in srgb, var(--color-border) 80%, white 20%);
542 border-radius: 12px;
543 padding: 0.9rem 1rem;
544 background: color-mix(in srgb, var(--color-background) 88%, white 12%);
545 }
546
547 .email-guide-title {
548 font-weight: 700;
549 margin-bottom: 0.55rem;
550 }
551
552 .email-guide-list {
553 margin: 0;
554 padding-left: 1.1rem;
555 color: var(--color-text-secondary);
556 line-height: 1.55;
557 }
558
559 .email-empty {
560 border-radius: 0.5rem;
561 padding: 1rem;
562 background: color-mix(in srgb, var(--color-background) 94%, white 6%);
563 }
564
565 .email-empty-title {
566 font-size: 1.05rem;
567 font-weight: 700;
568 }
569
570 .email-empty-copy {
571 margin-top: 0.35rem;
572 margin-bottom: 0.9rem;
573 color: var(--color-text-secondary);
574 line-height: 1.5;
575 }
576
577 .email-card {
578 border-radius: 0.5rem;
579 overflow: hidden;
580 }
581
582 .email-card-header {
583 display: flex;
584 justify-content: space-between;
585 gap: 1rem;
586 align-items: flex-start;
587 padding: var(--spacing-sm) 0;
588 border-bottom: 1px solid var(--color-border);
589 cursor: pointer;
590 }
591
592 .email-card-heading {
593 min-width: 0;
594 flex: 1 1 auto;
595 }
596
597 .email-card-title {
598 font-weight: 700;
599 font-size: 1rem;
600 line-height: 1.35;
601 overflow-wrap: anywhere;
602 }
603
604 .email-card-subtitle {
605 margin-top: 0.3rem;
606 color: var(--color-text-secondary);
607 font-size: var(--font-size-small);
608 line-height: 1.45;
609 }
610
611 .email-card-actions {
612 display: flex;
613 align-items: center;
614 gap: 0.45rem;
615 flex: 0 0 auto;
616 }
617
618 .email-card-chevron {
619 transition: transform 0.18s ease;
620 opacity: 0.7;
621 }
622
623 .email-card-chevron.is-open {
624 transform: rotate(180deg);
625 }
626
627 .email-provider-panel {
628 margin: 1rem 0;
629 padding: 0.95rem;
630 border: 1px solid color-mix(in srgb, var(--color-border) 86%, white 14%);
631 border-radius: 0.5rem;
632 background: color-mix(in srgb, var(--color-background) 92%, white 8%);
633 }
634
635 .email-provider-panel.has-provider {
636 background: color-mix(in srgb, var(--color-background) 88%, white 12%);
637 }
638
639 .email-provider-topline {
640 display: flex;
641 align-items: flex-start;
642 justify-content: space-between;
643 gap: 1rem;
644 }
645
646 .email-provider-copy {
647 min-width: 0;
648 }
649
650 .email-provider-title {
651 font-size: 1rem;
652 font-weight: 800;
653 line-height: 1.35;
654 }
655
656 .email-provider-description {
657 margin-top: 0.35rem;
658 color: var(--color-text-secondary);
659 line-height: 1.5;
660 }
661
662 .email-change-provider {
663 flex: 0 0 auto;
664 }
665
666 .email-provider-grid {
667 display: grid;
668 grid-template-columns: repeat(3, minmax(0, 1fr));
669 gap: 0.7rem;
670 margin-top: 0.95rem;
671 }
672
673 .email-provider-option {
674 appearance: none;
675 width: 100%;
676 min-height: 5.5rem;
677 border: 1px solid color-mix(in srgb, var(--color-border) 84%, white 16%);
678 border-radius: 0.5rem;
679 padding: 0.8rem;
680 background: color-mix(in srgb, var(--color-background) 96%, white 4%);
681 color: var(--color-text);
682 display: grid;
683 grid-template-columns: auto minmax(0, 1fr);
684 grid-template-rows: auto auto;
685 align-items: center;
686 column-gap: 0.75rem;
687 row-gap: 0.15rem;
688 font: inherit;
689 text-align: left;
690 cursor: pointer;
691 transition: border-color 0.16s ease, background 0.16s ease, transform 0.16s ease;
692 }
693
694 .email-provider-option:hover,
695 .email-provider-option:focus-visible {
696 border-color: color-mix(in srgb, var(--color-highlight) 58%, var(--color-border) 42%);
697 background: color-mix(in srgb, var(--color-background) 88%, white 12%);
698 transform: translateY(-1px);
699 outline: none;
700 }
701
702 .email-provider-option.is-selected {
703 border-color: color-mix(in srgb, var(--color-highlight) 78%, white 22%);
704 background: color-mix(in srgb, var(--color-highlight) 10%, var(--color-background) 90%);
705 }
706
707 .email-provider-logo {
708 grid-row: 1 / span 2;
709 width: 2.7rem;
710 height: 2.7rem;
711 border-radius: 0.5rem;
712 display: inline-flex;
713 align-items: center;
714 justify-content: center;
715 overflow: hidden;
716 font-size: 1.1rem;
717 font-weight: 900;
718 letter-spacing: 0;
719 }
720
721 .email-provider-logo .material-symbols-outlined {
722 font-size: 1.45rem;
723 }
724
725 .logo-gmail .email-provider-logo {
726 background: #ffffff;
727 color: #ea4335;
728 border: 1px solid rgba(234, 67, 53, 0.45);
729 }
730
731 .logo-icloud .email-provider-logo {
732 background: linear-gradient(135deg, #e0f2fe, #ffffff);
733 color: #2563eb;
734 }
735
736 .logo-yahoo .email-provider-logo {
737 background: #6001d2;
738 color: #ffffff;
739 }
740
741 .logo-exchange .email-provider-logo {
742 background: #0078d4;
743 color: #ffffff;
744 }
745
746 .logo-custom-imap .email-provider-logo {
747 background: color-mix(in srgb, var(--color-background) 72%, white 28%);
748 color: var(--color-text-secondary);
749 }
750
751 .email-microsoft-mark {
752 width: 1.55rem;
753 height: 1.55rem;
754 display: grid;
755 grid-template-columns: repeat(2, minmax(0, 1fr));
756 gap: 0.16rem;
757 }
758
759 .email-microsoft-mark span:nth-child(1) {
760 background: #f25022;
761 }
762
763 .email-microsoft-mark span:nth-child(2) {
764 background: #7fba00;
765 }
766
767 .email-microsoft-mark span:nth-child(3) {
768 background: #00a4ef;
769 }
770
771 .email-microsoft-mark span:nth-child(4) {
772 background: #ffb900;
773 }
774
775 .email-provider-name {
776 min-width: 0;
777 font-weight: 800;
778 line-height: 1.25;
779 overflow-wrap: anywhere;
780 }
781
782 .email-provider-hint {
783 min-width: 0;
784 color: var(--color-text-secondary);
785 font-size: var(--font-size-small);
786 line-height: 1.35;
787 overflow-wrap: anywhere;
788 }
789
790 .email-post-provider {
791 margin-top: 0.3rem;
792 }
793
794 .email-intro-copy {
795 margin: 1rem 0;
796 padding: 0.85rem 0.95rem;
797 border-radius: 12px;
798 background: color-mix(in srgb, #3b82f6 12%, var(--color-background) 88%);
799 color: var(--color-text-secondary);
800 line-height: 1.5;
801 }
802
803 .email-intro-link {
804 display: inline-flex;
805 margin-top: 0.55rem;
806 color: var(--color-highlight);
807 font-weight: 600;
808 text-decoration: none;
809 }
810
811 .email-intro-link:hover {
812 text-decoration: underline;
813 }
814
815 .email-grid {
816 display: grid;
817 grid-template-columns: repeat(2, minmax(0, 1fr));
818 gap: 0.85rem;
819 }
820
821 .email-note,
822 .email-missing {
823 margin-top: 0.2rem;
824 margin-bottom: 0.85rem;
825 padding: 0.8rem 0.9rem;
826 border-radius: 12px;
827 font-size: var(--font-size-small);
828 line-height: 1.5;
829 }
830
831 .email-note {
832 background: color-mix(in srgb, var(--color-background) 82%, white 18%);
833 color: var(--color-text-secondary);
834 }
835
836 .email-missing {
837 background: color-mix(in srgb, #f59e0b 14%, var(--color-background) 86%);
838 color: var(--color-text-secondary);
839 }
840
841 .email-advanced {
842 margin-top: 0.95rem;
843 border: 1px solid color-mix(in srgb, var(--color-border) 88%, white 12%);
844 border-radius: 14px;
845 overflow: hidden;
846 }
847
848 .email-advanced summary {
849 padding: 0.9rem 1rem;
850 background: color-mix(in srgb, var(--color-background) 88%, white 12%);
851 }
852
853 .email-advanced-body {
854 padding: 1rem;
855 display: flex;
856 flex-direction: column;
857 gap: 0.2rem;
858 }
859
860 .email-test-panel {
861 margin-top: 1rem;
862 padding: var(--spacing-xs) 0;
863 display: flex;
864 justify-content: space-between;
865 align-items: center;
866 gap: 1rem;
867 }
868
869 .email-test-copy {
870 min-width: 0;
871 }
872
873 .email-test-title {
874 font-weight: 700;
875 margin-bottom: 0.25rem;
876 }
877
878 .email-test-description {
879 color: var(--color-text-secondary);
880 line-height: 1.5;
881 font-size: var(--font-size-small);
882 }
883
884 .email-results {
885 margin-top: 0.9rem;
886 border-radius: 14px;
887 border: 1px solid color-mix(in srgb, #22c55e 28%, var(--color-border) 72%);
888 background: color-mix(in srgb, #22c55e 8%, var(--color-background) 92%);
889 padding: 0.35rem 0.9rem;
890 }
891
892 .email-results.is-error {
893 border-color: color-mix(in srgb, #ef4444 28%, var(--color-border) 72%);
894 background: color-mix(in srgb, #ef4444 8%, var(--color-background) 92%);
895 }
896
897 .email-result-row {
898 display: flex;
899 align-items: flex-start;
900 gap: 0.8rem;
901 padding: 0.7rem 0;
902 }
903
904 .email-result-row+.email-result-row {
905 border-top: 1px solid color-mix(in srgb, var(--color-border) 85%, white 15%);
906 }
907
908 .email-result-icon {
909 width: 1.25rem;
910 font-weight: 800;
911 line-height: 1.3;
912 }
913
914 .email-result-copy {
915 min-width: 0;
916 }
917
918 .email-result-title {
919 font-weight: 700;
920 margin-bottom: 0.18rem;
921 }
922
923 .email-result-message {
924 color: var(--color-text-secondary);
925 line-height: 1.5;
926 font-size: var(--font-size-small);
927 overflow-wrap: anywhere;
928 }
929
930 .email-status-pill {
931 display: inline-flex;
932 align-items: center;
933 justify-content: center;
934 min-width: 5.25rem;
935 padding: 0.35rem 0.7rem;
936 border-radius: 999px;
937 font-size: 0.8rem;
938 font-weight: 700;
939 letter-spacing: 0.01em;
940 }
941
942 .email-status-pill.tone-success {
943 background: rgba(34, 197, 94, 0.14);
944 color: #7ee7a4;
945 }
946
947 .email-status-pill.tone-ready {
948 background: rgba(59, 130, 246, 0.16);
949 color: #93c5fd;
950 }
951
952 .email-status-pill.tone-warning {
953 background: rgba(245, 158, 11, 0.16);
954 color: #fcd34d;
955 }
956
957 .email-status-pill.tone-muted {
958 background: rgba(148, 163, 184, 0.14);
959 color: #cbd5e1;
960 }
961
962 .email-add-another {
963 align-self: flex-start;
964 }
965
966 @media (max-width: 900px) {
967
968 .email-provider-grid {
969 grid-template-columns: repeat(2, minmax(0, 1fr));
970 }
971
972 .email-guide-body,
973 .email-grid {
974 grid-template-columns: minmax(0, 1fr);
975 }
976 }
977
978 @media (max-width: 640px) {
979
980 .email-card-header,
981 .email-test-panel {
982 flex-direction: column;
983 align-items: stretch;
984 }
985
986 .email-card-actions {
987 justify-content: space-between;
988 width: 100%;
989 }
990
991 .email-provider-topline {
992 flex-direction: column;
993 align-items: stretch;
994 }
995
996 .email-provider-grid,
997 .email-grid {
998 grid-template-columns: minmax(0, 1fr);
999 }
1000
1001 .email-change-provider {
1002 align-self: flex-start;
1003 }
1004
1005 .email-status-pill {
1006 min-width: 0;
1007 }
1008 }
1009 </style>
1010 </body>
1011
1012 </html>