Files
ihasmail-inbuxa/web/src/styles/app.css
T
jcoffey-dev 087c856a46 Theme the dropdown a native select paints for itself
The From picker's drop-down rendered a light background under light
text, unreadable in any dark theme (#70).

A native <select>'s popup is painted by the browser from the element's
own colours, not the page's. `.from-select` is deliberately transparent
so it sits flush in the composer's From line, which left the popup with
no background of its own: the browser drew a light one while the text
kept the app's light foreground.

Fixed by styling `option` rather than the control, so the popup gets a
background without the closed select gaining a box. Verified: the select
stays transparent, the options are now --bg-elev on --fg, which is
12.5:1 where it was light on light.

Scoped to every select rather than this one. Nothing in the app styled
options anywhere, so this was not one broken dropdown but the first one
anybody happened to open in the dark -- and the next transparent select
would have arrived with the same bug.
2026-08-26 15:09:30 -07:00

1017 lines
78 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* ==========================================================================
ihasmail design system
========================================================================== */
:root {
--font-sans: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
--font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
--fs: 14px;
--radius: 10px;
--radius-sm: 6px;
--radius-lg: 16px;
--shadow-1: 0 1px 2px rgba(0, 0, 0, 0.06), 0 1px 3px rgba(0, 0, 0, 0.08);
--shadow-2: 0 4px 16px rgba(0, 0, 0, 0.12), 0 2px 6px rgba(0, 0, 0, 0.08);
--shadow-3: 0 12px 40px rgba(0, 0, 0, 0.18), 0 4px 12px rgba(0, 0, 0, 0.1);
--row-h: 44px;
--topbar-h: 56px;
--sidebar-w: 256px;
--sidebar-w-collapsed: 68px;
--list-w: 42%;
--ease: cubic-bezier(0.2, 0, 0, 1);
/* Light palette */
--bg: #f6f8fa;
--bg-elev: #ffffff;
--bg-sunken: #eef1f4;
--bg-hover: rgba(15, 23, 42, 0.05);
--bg-active: rgba(15, 23, 42, 0.09);
--fg: #111827;
--fg-muted: #5b6472;
--fg-faint: #8b94a3;
--border: #e3e7ec;
--border-strong: #cbd2da;
--accent: #0f766e;
--accent-fg: #ffffff;
--accent-soft: #d9f1ee;
--accent-soft-fg: #0b5750;
--danger: #dc2626;
--danger-soft: #fee2e2;
--warn: #b45309;
--warn-soft: #fef3c7;
--success: #15803d;
--success-soft: #dcfce7;
--link: #0e7490;
--unread-bg: #ffffff;
--read-bg: #f3f5f7;
--selected-bg: #d9f1ee;
--focus-ring: 0 0 0 3px rgba(15, 118, 110, 0.35);
--star: #f59e0b;
--q1: #2563eb;
--q2: #16a34a;
--q3: #9333ea;
--scrollbar: rgba(0, 0, 0, 0.25);
color-scheme: light;
}
:root[data-theme="dark"] {
--bg: #0b1220;
--bg-elev: #111a2b;
--bg-sunken: #0d1524;
--bg-hover: rgba(255, 255, 255, 0.06);
--bg-active: rgba(255, 255, 255, 0.1);
--fg: #e5e9f0;
--fg-muted: #9aa5b8;
--fg-faint: #6b7689;
--border: #1f2a3d;
--border-strong: #31405a;
--accent: #2dd4bf;
--accent-fg: #052e2b;
--accent-soft: rgba(45, 212, 191, 0.16);
--accent-soft-fg: #99f6e4;
--danger: #f87171;
--danger-soft: rgba(248, 113, 113, 0.15);
--warn: #fbbf24;
--warn-soft: rgba(251, 191, 36, 0.15);
--success: #4ade80;
--success-soft: rgba(74, 222, 128, 0.15);
--link: #67e8f9;
--unread-bg: #121c2e;
--read-bg: #0e1627;
--selected-bg: rgba(45, 212, 191, 0.18);
--focus-ring: 0 0 0 3px rgba(45, 212, 191, 0.4);
--star: #fbbf24;
--q1: #60a5fa;
--q2: #4ade80;
--q3: #c084fc;
--scrollbar: rgba(255, 255, 255, 0.25);
--shadow-1: 0 1px 2px rgba(0, 0, 0, 0.4);
--shadow-2: 0 4px 16px rgba(0, 0, 0, 0.5);
--shadow-3: 0 12px 40px rgba(0, 0, 0, 0.6);
color-scheme: dark;
}
/*
* The "ihasmail" theme: the palette from ihasmail.org, which is a teal-navy
* rather than the blue-slate of the plain dark theme, warmed by the orange the
* logo's cat is drawn in.
*
* It rides on data-theme="dark" rather than replacing it, so every dark-only
* rule further down this file -- tooltips, toasts, the message frame -- keeps
* applying without being duplicated. Only the palette is overridden.
*
* Specificity is doing deliberate work here. This block is [data-palette] plus
* :root, so 0,2,0; the accent variants below are :root[data-theme][data-accent],
* so 0,3,0 and they win. That is what makes the accent swatches keep working on
* top of this theme -- and because the default accent ("teal") has no rule of
* its own, ihasmail.org's own accent is what shows until someone picks another.
*/
:root[data-palette="ihasmail"] {
--bg: #0d2430;
--bg-elev: #12303e;
--bg-sunken: #0a1c26;
--bg-hover: rgba(70, 202, 195, 0.10);
--bg-active: rgba(70, 202, 195, 0.16);
--fg: #eaf6f6;
--fg-muted: #a3c3cb;
--fg-faint: #86aab4;
--border: #21505f;
--border-strong: #2e6a7a;
--accent: #46cac3;
--accent-fg: #062028;
--accent-soft: rgba(70, 202, 195, 0.16);
--accent-soft-fg: #9fe6e2;
--danger: #f87171;
--danger-soft: rgba(248, 113, 113, 0.15);
--warn: #f9a34b;
--warn-soft: rgba(249, 163, 75, 0.14);
--success: #4ade80;
--success-soft: rgba(74, 222, 128, 0.15);
--link: #6fdcd6;
--unread-bg: #163a4a;
--read-bg: #12303e;
--selected-bg: rgba(70, 202, 195, 0.18);
--focus-ring: 0 0 0 3px rgba(70, 202, 195, 0.4);
/* The cat is orange; so is the star. */
--star: #f9a34b;
--q1: #6fdcd6;
--q2: #4ade80;
--q3: #c084fc;
--scrollbar: rgba(163, 195, 203, 0.3);
--shadow-1: 0 1px 2px rgba(0, 0, 0, 0.45);
--shadow-2: 0 8px 24px rgba(0, 0, 0, 0.55);
--shadow-3: 0 22px 60px -28px rgba(0, 0, 0, 0.75);
color-scheme: dark;
}
/* Accent variants */
:root[data-accent="blue"] { --accent: #2563eb; --accent-soft: #dbeafe; --accent-soft-fg: #1e3a8a; --selected-bg: #dbeafe; --focus-ring: 0 0 0 3px rgba(37,99,235,.35); --link:#1d4ed8; }
:root[data-accent="purple"] { --accent: #7c3aed; --accent-soft: #ede9fe; --accent-soft-fg: #4c1d95; --selected-bg: #ede9fe; --focus-ring: 0 0 0 3px rgba(124,58,237,.35); --link:#6d28d9; }
:root[data-accent="rose"] { --accent: #e11d48; --accent-soft: #ffe4e6; --accent-soft-fg: #881337; --selected-bg: #ffe4e6; --focus-ring: 0 0 0 3px rgba(225,29,72,.35); --link:#be123c; }
:root[data-accent="orange"] { --accent: #ea580c; --accent-soft: #ffedd5; --accent-soft-fg: #7c2d12; --selected-bg: #ffedd5; --focus-ring: 0 0 0 3px rgba(234,88,12,.35); --link:#c2410c; }
:root[data-accent="green"] { --accent: #16a34a; --accent-soft: #dcfce7; --accent-soft-fg: #14532d; --selected-bg: #dcfce7; --focus-ring: 0 0 0 3px rgba(22,163,74,.35); --link:#15803d; }
:root[data-theme="dark"][data-accent="blue"] { --accent: #60a5fa; --accent-fg:#0b1a33; --accent-soft: rgba(96,165,250,.18); --accent-soft-fg:#bfdbfe; --selected-bg: rgba(96,165,250,.2); --link:#93c5fd; }
:root[data-theme="dark"][data-accent="purple"] { --accent: #a78bfa; --accent-fg:#1e1040; --accent-soft: rgba(167,139,250,.18); --accent-soft-fg:#ddd6fe; --selected-bg: rgba(167,139,250,.2); --link:#c4b5fd; }
:root[data-theme="dark"][data-accent="rose"] { --accent: #fb7185; --accent-fg:#3b0716; --accent-soft: rgba(251,113,133,.18); --accent-soft-fg:#fecdd3; --selected-bg: rgba(251,113,133,.2); --link:#fda4af; }
:root[data-theme="dark"][data-accent="orange"] { --accent: #fb923c; --accent-fg:#3b1605; --accent-soft: rgba(251,146,60,.18); --accent-soft-fg:#fed7aa; --selected-bg: rgba(251,146,60,.2); --link:#fdba74; }
:root[data-theme="dark"][data-accent="green"] { --accent: #4ade80; --accent-fg:#052e16; --accent-soft: rgba(74,222,128,.18); --accent-soft-fg:#bbf7d0; --selected-bg: rgba(74,222,128,.2); --link:#86efac; }
:root[data-density="comfortable"] { --row-h: 52px; }
:root[data-density="cozy"] { --row-h: 44px; }
:root[data-density="compact"] { --row-h: 36px; }
:root[data-fontsize="small"] { --fs: 13px; }
:root[data-fontsize="large"] { --fs: 15.5px; }
/* Reset ------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html, body, #root { height: 100%; }
html { -webkit-text-size-adjust: 100%; }
body {
margin: 0;
font-family: var(--font-sans);
font-size: var(--fs);
line-height: 1.45;
color: var(--fg);
background: var(--bg);
-webkit-font-smoothing: antialiased;
overscroll-behavior: none;
}
button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: 0; padding: 0; }
a { color: var(--link); }
img { max-width: 100%; }
::selection { background: var(--accent-soft); }
* { scrollbar-width: thin; scrollbar-color: var(--scrollbar) transparent; }
*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-thumb { background: var(--scrollbar); border-radius: 8px; }
:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--radius-sm); }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.muted { color: var(--fg-muted); }
.faint { color: var(--fg-faint); }
.small { font-size: 0.875em; }
.mono { font-family: var(--font-mono); }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.row { display: flex; align-items: center; gap: 8px; }
.col { display: flex; flex-direction: column; }
.grow { flex: 1 1 auto; min-width: 0; }
.spacer { flex: 1; }
.hidden { display: none !important; }
.wrap { flex-wrap: wrap; }
.gap-2 { gap: 2px; } .gap-4 { gap: 4px; } .gap-8 { gap: 8px; } .gap-12 { gap: 12px; } .gap-16 { gap: 16px; }
.mt-8 { margin-top: 8px; } .mt-16 { margin-top: 16px; } .mb-8 { margin-bottom: 8px; } .mb-16 { margin-bottom: 16px; }
.p-16 { padding: 16px; }
.center { display:flex; align-items:center; justify-content:center; }
.nowrap { white-space: nowrap; }
/* Buttons ---------------------------------------------------------------- */
.btn {
display: inline-flex; align-items: center; justify-content: center; gap: 6px;
height: 36px; padding: 0 14px; border-radius: var(--radius-sm);
border: 1px solid var(--border-strong); background: var(--bg-elev); color: var(--fg);
font-weight: 500; white-space: nowrap; user-select: none; transition: background .12s var(--ease), border-color .12s, box-shadow .12s, transform .05s;
}
.btn:hover { background: var(--bg-hover); }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .5; cursor: not-allowed; transform: none; }
.btn-primary { background: var(--accent); border-color: transparent; color: var(--accent-fg); }
.btn-primary:hover { filter: brightness(1.06); background: var(--accent); }
.btn-danger { background: var(--danger); border-color: transparent; color: #fff; }
.btn-danger:hover { filter: brightness(1.06); background: var(--danger); }
.btn-ghost { border-color: transparent; background: transparent; }
.btn-ghost:hover { background: var(--bg-hover); }
.btn-soft { background: var(--accent-soft); border-color: transparent; color: var(--accent-soft-fg); }
.btn-sm { height: 30px; padding: 0 10px; font-size: .9em; }
.btn-lg { height: 44px; padding: 0 20px; font-size: 1.05em; border-radius: var(--radius); }
.btn-pill { border-radius: 999px; }
.btn-block { width: 100%; }
.icon-btn {
display: inline-flex; align-items: center; justify-content: center;
width: 36px; height: 36px; border-radius: 50%; color: var(--fg-muted); flex: 0 0 auto;
transition: background .12s var(--ease), color .12s;
}
.icon-btn:hover { background: var(--bg-hover); color: var(--fg); }
.icon-btn:disabled { opacity: .4; cursor: not-allowed; }
.icon-btn.active { color: var(--accent); background: var(--accent-soft); }
.icon-btn.sm { width: 30px; height: 30px; }
.icon-btn.xs { width: 26px; height: 26px; }
.icon-btn.danger:hover { color: var(--danger); background: var(--danger-soft); }
/* Inputs ----------------------------------------------------------------- */
.input, .select, .textarea {
width: 100%; height: 38px; padding: 0 12px; border-radius: var(--radius-sm);
border: 1px solid var(--border-strong); background: var(--bg-elev); color: var(--fg);
transition: border-color .12s, box-shadow .12s;
}
.textarea { height: auto; min-height: 90px; padding: 10px 12px; resize: vertical; line-height: 1.5; }
.input:focus, .select:focus, .textarea:focus { border-color: var(--accent); box-shadow: var(--focus-ring); outline: none; }
.input::placeholder, .textarea::placeholder { color: var(--fg-faint); }
.input.sm { height: 32px; padding: 0 10px; }
.select { appearance: none; padding-right: 30px; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%238b94a3' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 10px center; }
.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px; }
.field > label, .label { font-size: .85em; font-weight: 600; color: var(--fg-muted); letter-spacing: .01em; }
.field-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; }
.hint { font-size: .85em; color: var(--fg-faint); }
.check { display: flex; align-items: center; gap: 10px; cursor: pointer; padding: 6px 0; }
.check input { width: 18px; height: 18px; accent-color: var(--accent); margin: 0; }
.switch { position: relative; width: 40px; height: 22px; border-radius: 999px; background: var(--border-strong); transition: background .15s; flex: 0 0 auto; }
.switch::after { content: ""; position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; border-radius: 50%; background: #fff; box-shadow: var(--shadow-1); transition: transform .15s var(--ease); }
.switch[aria-checked="true"] { background: var(--accent); }
.switch[aria-checked="true"]::after { transform: translateX(18px); }
.switch-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 10px 0; border-bottom: 1px solid var(--border); }
.switch-row:last-child { border-bottom: 0; }
.switch-row .switch-text { display: flex; flex-direction: column; gap: 2px; }
.switch-row .switch-text .hint { margin: 0; }
.chip { display: inline-flex; align-items: center; gap: 6px; height: 26px; padding: 0 10px; border-radius: 999px; background: var(--bg-sunken); border: 1px solid var(--border); font-size: .85em; max-width: 100%; }
.chip .chip-x { display: inline-flex; border-radius: 50%; padding: 2px; color: var(--fg-muted); }
.chip .chip-x:hover { background: var(--bg-active); color: var(--fg); }
.chip.invalid { border-color: var(--danger); color: var(--danger); }
.badge { display: inline-flex; align-items: center; justify-content: center; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 999px; font-size: 11px; font-weight: 700; background: var(--accent); color: var(--accent-fg); }
.badge.muted { background: var(--bg-active); color: var(--fg-muted); }
.tag { display: inline-flex; align-items: center; gap: 4px; height: 20px; padding: 0 8px; border-radius: 6px; font-size: 11.5px; font-weight: 600; color: #fff; }
.kbd { display: inline-block; min-width: 20px; padding: 1px 6px; border-radius: 4px; border: 1px solid var(--border-strong); border-bottom-width: 2px; background: var(--bg-sunken); font-family: var(--font-mono); font-size: 11.5px; text-align: center; }
/* Avatar ----------------------------------------------------------------- */
.avatar { display: inline-flex; align-items: center; justify-content: center; width: 36px; height: 36px; border-radius: 50%; color: #fff; font-weight: 600; font-size: 13px; flex: 0 0 auto; overflow: hidden; user-select: none; }
.avatar img { width: 100%; height: 100%; object-fit: cover; }
.avatar.sm { width: 28px; height: 28px; font-size: 11px; }
.avatar.lg { width: 56px; height: 56px; font-size: 20px; }
.avatar.xl { width: 88px; height: 88px; font-size: 30px; }
/* Menus / popovers ------------------------------------------------------- */
.popover { position: fixed; z-index: 1000; min-width: 180px; max-width: min(420px, calc(100vw - 16px)); max-height: min(70vh, 520px); overflow: auto; background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-2); padding: 6px; animation: pop .12s var(--ease); }
@keyframes pop { from { opacity: 0; transform: translateY(-4px) scale(.98); } to { opacity: 1; transform: none; } }
.menu-item { display: flex; align-items: center; gap: 10px; width: 100%; padding: 8px 10px; border-radius: var(--radius-sm); text-align: left; color: var(--fg); white-space: nowrap; }
.menu-item:hover, .menu-item.active { background: var(--bg-hover); }
.menu-item:disabled { opacity: .5; cursor: default; }
.menu-item.danger { color: var(--danger); }
.menu-item .menu-kbd { margin-left: auto; color: var(--fg-faint); font-size: .85em; }
.menu-item svg { color: var(--fg-muted); flex: 0 0 auto; }
.menu-item.danger svg { color: var(--danger); }
.menu-sep { height: 1px; background: var(--border); margin: 6px 4px; }
.menu-title { padding: 6px 10px 4px; font-size: .78em; font-weight: 700; color: var(--fg-faint); text-transform: uppercase; letter-spacing: .05em; }
.menu-search { padding: 4px 4px 6px; }
.tooltip { position: fixed; z-index: 2000; background: #1f2937; color: #fff; padding: 5px 8px; border-radius: 6px; font-size: 12px; pointer-events: none; white-space: nowrap; box-shadow: var(--shadow-2); animation: pop .1s var(--ease); }
:root[data-theme="dark"] .tooltip { background: #e5e9f0; color: #0b1220; }
/* Dialogs ---------------------------------------------------------------- */
.dialog-backdrop { position: fixed; inset: 0; z-index: 900; background: rgba(2, 6, 23, 0.45); display: flex; align-items: center; justify-content: center; padding: 16px; animation: fade .15s var(--ease); backdrop-filter: blur(2px); }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
.dialog { background: var(--bg-elev); border-radius: var(--radius-lg); box-shadow: var(--shadow-3); width: 100%; max-width: 520px; max-height: calc(100vh - 32px); display: flex; flex-direction: column; animation: rise .18s var(--ease); border: 1px solid var(--border); }
@keyframes rise { from { opacity: 0; transform: translateY(10px) scale(.98); } to { opacity: 1; transform: none; } }
.dialog.lg { max-width: 760px; }
.dialog.xl { max-width: 980px; }
.dialog.sm { max-width: 400px; }
.dialog-head { display: flex; align-items: center; gap: 8px; padding: 16px 20px 8px; }
.dialog-head h2 { margin: 0; font-size: 1.15em; font-weight: 650; flex: 1; }
.dialog-body { padding: 8px 20px 16px; overflow: auto; }
.dialog-foot { display: flex; align-items: center; justify-content: flex-end; gap: 8px; padding: 12px 20px 16px; border-top: 1px solid var(--border); }
.dialog-foot .left { margin-right: auto; }
/* Toasts ----------------------------------------------------------------- */
.toast-host { position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%); z-index: 3000; display: flex; flex-direction: column; gap: 8px; align-items: center; pointer-events: none; padding: 0 12px; width: 100%; max-width: 520px; }
.toast { pointer-events: auto; display: flex; align-items: center; gap: 12px; background: #1f2937; color: #fff; padding: 10px 10px 10px 16px; border-radius: var(--radius); box-shadow: var(--shadow-2); min-width: 260px; max-width: 100%; position: relative; overflow: hidden; animation: rise .2s var(--ease); }
:root[data-theme="dark"] .toast { background: #e5e9f0; color: #0b1220; }
.toast-error { background: #991b1b; color: #fff; }
:root[data-theme="dark"] .toast-error { background: #fecaca; color: #450a0a; }
.toast-success { background: #14532d; color: #fff; }
:root[data-theme="dark"] .toast-success { background: #bbf7d0; color: #052e16; }
.toast-msg { flex: 1; }
.toast-action { color: #5eead4; font-weight: 700; padding: 6px 8px; border-radius: 6px; }
.toast-action:hover { background: rgba(255,255,255,.12); }
:root[data-theme="dark"] .toast-action { color: #0f766e; }
.toast-close { color: inherit; opacity: .7; display: inline-flex; padding: 4px; border-radius: 50%; }
.toast-close:hover { opacity: 1; background: rgba(255,255,255,.12); }
.toast-progress { position: absolute; left: 0; bottom: 0; height: 3px; background: #5eead4; width: 100%; transform-origin: left; animation: shrink linear forwards; }
@keyframes shrink { from { transform: scaleX(1); } to { transform: scaleX(0); } }
/* Spinner / skeleton ----------------------------------------------------- */
.spinner { width: 20px; height: 20px; border: 2px solid var(--border-strong); border-top-color: var(--accent); border-radius: 50%; animation: spin .7s linear infinite; flex: 0 0 auto; }
.spinner.lg { width: 32px; height: 32px; border-width: 3px; }
@keyframes spin { to { transform: rotate(360deg); } }
.skeleton { background: linear-gradient(90deg, var(--bg-sunken) 25%, var(--bg-hover) 37%, var(--bg-sunken) 63%); background-size: 400% 100%; animation: shimmer 1.4s ease infinite; border-radius: 6px; }
@keyframes shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
.empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; padding: 48px 24px; color: var(--fg-muted); text-align: center; }
.empty svg { color: var(--fg-faint); }
.empty h3 { margin: 8px 0 0; font-weight: 600; color: var(--fg); }
.empty p { margin: 0; max-width: 360px; }
.error-box { padding: 12px 14px; border-radius: var(--radius-sm); background: var(--danger-soft); color: var(--danger); border: 1px solid color-mix(in srgb, var(--danger) 30%, transparent); }
.info-box { padding: 12px 14px; border-radius: var(--radius-sm); background: var(--accent-soft); color: var(--accent-soft-fg); }
.warn-box { padding: 12px 14px; border-radius: var(--radius-sm); background: var(--warn-soft); color: var(--warn); }
/* ==========================================================================
App shell
========================================================================== */
.app { height: 100%; display: grid; grid-template-rows: var(--topbar-h) 1fr; overflow: hidden; }
.topbar { display: flex; align-items: center; gap: 8px; padding: 0 12px; background: var(--bg); position: relative; z-index: 50; }
.topbar .brand { display: flex; align-items: center; gap: 8px; font-weight: 700; font-size: 1.2em; letter-spacing: -.01em; color: var(--fg); text-decoration: none; padding-right: 8px; min-width: 0; }
.topbar .brand img { width: 34px; height: 34px; object-fit: contain; }
.topbar .brand .brand-name { color: #14b8a6; }
.topbar .brand .brand-name span { color: var(--fg-muted); font-weight: 500; }
.searchbar { flex: 1 1 auto; max-width: 720px; margin: 0 auto; position: relative; }
.searchbar .search-input { display: flex; align-items: center; gap: 8px; height: 44px; padding: 0 8px 0 14px; border-radius: 999px; background: var(--bg-sunken); border: 1px solid transparent; transition: background .12s, box-shadow .12s, border-color .12s; }
.searchbar .search-input:focus-within { background: var(--bg-elev); box-shadow: var(--shadow-1); border-color: var(--border); }
.searchbar input { flex: 1; border: 0; background: transparent; outline: none; min-width: 0; height: 100%; }
.searchbar input::placeholder { color: var(--fg-faint); }
.search-panel { position: absolute; top: calc(100% + 6px); left: 0; right: 0; background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-2); padding: 16px; z-index: 60; animation: pop .12s var(--ease); }
.search-panel .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 14px; }
.search-suggest { position: absolute; top: calc(100% + 6px); left: 0; right: 0; background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-2); padding: 6px; z-index: 60; }
.topbar-actions { display: flex; align-items: center; gap: 4px; }
/* Live-updates indicator. Three states, and a raised bead rather than a flat
speck: at 8px flat it was invisible against either theme. The gloss is a
highlight over a solid colour rather than a colour-mix, so it needs no
per-theme variant -- the same bead reads on light and dark alike. */
.push-status { display: inline-flex; align-items: center; padding: 0 4px; }
.push-dot {
width: 12px;
height: 12px;
border-radius: 50%;
background:
radial-gradient(circle at 34% 30%, rgba(255, 255, 255, .8), rgba(255, 255, 255, 0) 46%),
var(--dot);
box-shadow:
0 0 0 3px var(--dot-halo),
0 1px 2px rgba(0, 0, 0, .45),
inset 0 -1px 2px rgba(0, 0, 0, .3);
}
.push-dot.connected { --dot: #16a34a; --dot-halo: rgba(22, 163, 74, .25); }
.push-dot.connecting { --dot: #eab308; --dot-halo: rgba(234, 179, 8, .25); animation: push-pulse 1.6s ease-in-out infinite; }
.push-dot.disconnected { --dot: #dc2626; --dot-halo: rgba(220, 38, 38, .25); }
@keyframes push-pulse { 50% { opacity: .45; } }
@media (prefers-reduced-motion: reduce) { .push-dot.connecting { animation: none; } }
.app-body { display: grid; grid-template-columns: var(--sidebar-w) 1fr; min-height: 0; transition: grid-template-columns .2s var(--ease); }
.app-body.collapsed { grid-template-columns: var(--sidebar-w-collapsed) 1fr; }
.sidebar { display: flex; flex-direction: column; min-height: 0; padding: 4px 8px 8px 8px; gap: 2px; overflow: hidden; }
.sidebar-scroll { overflow-y: auto; overflow-x: hidden; flex: 1; min-height: 0; padding-bottom: 8px; }
.compose-btn { display: flex; align-items: center; gap: 12px; height: 52px; padding: 0 22px 0 18px; margin: 6px 4px 12px; border-radius: 16px; background: var(--bg-elev); box-shadow: var(--shadow-1); font-weight: 600; font-size: 1em; color: var(--fg); transition: box-shadow .15s, transform .05s, background .12s; white-space: nowrap; }
.compose-btn:hover { box-shadow: var(--shadow-2); background: var(--bg-elev); }
.compose-btn svg { color: var(--accent); }
.collapsed .compose-btn { width: 52px; padding: 0; justify-content: center; margin-left: auto; margin-right: auto; }
.collapsed .compose-btn span { display: none; }
.nav-section { display: flex; align-items: center; justify-content: space-between; padding: 10px 12px 4px; font-size: .75em; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--fg-faint); }
.nav-section .icon-btn { width: 24px; height: 24px; }
.collapsed .nav-section { display: none; }
.nav-item { position: relative; display: flex; align-items: center; gap: 12px; height: 36px; padding: 0 12px; border-radius: 0 999px 999px 0; margin-right: 8px; color: var(--fg); text-decoration: none; white-space: nowrap; transition: background .12s; user-select: none; font-weight: 450; }
.nav-item:hover { background: var(--bg-hover); }
.nav-item.unread .nav-label, .nav-item.unread .nav-count { font-weight: 700; color: var(--fg); }
.nav-item.active { background: var(--accent-soft); color: var(--accent-soft-fg); font-weight: 650; }
.nav-item.active.unread .nav-label, .nav-item.active.unread .nav-count { color: inherit; }
.nav-item.drop-target { background: var(--accent-soft); outline: 2px dashed var(--accent); outline-offset: -2px; }
.nav-item.folder-row.dragging { opacity: .45; }
/* A folder colour tints its icon; the label keeps the sidebar's contrast. */
.folder-row .folder-icon { display: inline-flex; align-items: center; }
/* .nav-item svg sets colour on the svg itself, so inheriting from the span is
not enough -- the icon has to be targeted directly to win the cascade.
The fill overrides lucide's own fill="none": a CSS rule beats a presentation
attribute, and a solid folder reads at a glance where an outline does not. */
.folder-row .folder-icon[style*="--folder-color"] svg { color: var(--bg); fill: var(--folder-color); }
/* The Folders heading doubles as the way back to the top level while dragging. */
.nav-section.drop-target { background: var(--accent-soft); outline: 2px dashed var(--accent); outline-offset: -2px; border-radius: var(--radius-sm); color: var(--accent-soft-fg); }
.nav-item svg { flex: 0 0 auto; color: var(--fg-muted); }
.nav-item.active svg { color: inherit; }
.nav-item .nav-label { flex: 1; overflow: hidden; text-overflow: ellipsis; }
.nav-item .nav-count { font-size: .8em; font-weight: 700; color: var(--fg-muted); }
.nav-item.active .nav-count { color: inherit; }
.nav-item .nav-more { opacity: 0; width: 24px; height: 24px; margin-right: -6px; }
.nav-item:hover .nav-more, .nav-item:focus-within .nav-more { opacity: 1; }
.nav-item .nav-twisty { width: 18px; height: 18px; display: inline-flex; align-items: center; justify-content: center; color: var(--fg-faint); border-radius: 4px; }
.nav-item .nav-twisty:hover { background: var(--bg-active); }
/* Folder rows keep the expand chevron in a gutter to the LEFT of the icon, so a
folder with subfolders and one without still line up on their icon. */
.nav-item.folder-row { --folder-indent: 0px; position: relative; padding-left: calc(30px + var(--folder-indent)); }
.nav-item.folder-row.depth-1 { --folder-indent: 16px; }
.nav-item.folder-row.depth-2 { --folder-indent: 32px; }
.nav-item.folder-row.depth-3 { --folder-indent: 48px; }
.nav-item.folder-row.depth-4 { --folder-indent: 64px; }
.nav-item.folder-row .nav-twisty { position: absolute; left: calc(8px + var(--folder-indent)); top: 50%; transform: translateY(-50%); margin: 0; }
/* Labels sit in the same column: a 20px slot matching the folder icons. */
.nav-item.folder-row .nav-label-color { flex: 0 0 20px; width: 20px; height: 20px; border-radius: 0; display: inline-flex; align-items: center; justify-content: center; }
.nav-item.folder-row .nav-label-color::before { content: ""; width: 11px; height: 11px; border-radius: 3px; background: var(--label-color, var(--accent)); }
.collapsed .nav-item { justify-content: center; padding: 0; margin: 0 auto; width: 44px; border-radius: 999px; }
.collapsed .nav-item .nav-label, .collapsed .nav-item .nav-count, .collapsed .nav-item .nav-more, .collapsed .nav-item .nav-twisty { display: none; }
.collapsed .nav-item.depth-1, .collapsed .nav-item.depth-2, .collapsed .nav-item.depth-3 { display: none; }
.collapsed .nav-item .nav-dot { position: absolute; top: 6px; right: 6px; width: 8px; height: 8px; border-radius: 50%; background: var(--accent); }
.nav-label-color { width: 10px; height: 10px; border-radius: 3px; flex: 0 0 auto; }
/* Outlook-style module bar at the bottom of the sidebar */
.module-bar { display: flex; align-items: stretch; justify-content: space-around; gap: 2px; padding: 6px 4px 4px; border-top: 1px solid var(--border); flex: 0 0 auto; }
.module-link { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; flex: 1; min-width: 0; padding: 6px 2px; border-radius: var(--radius-sm); color: var(--fg-muted); text-decoration: none; font-size: 11px; font-weight: 500; transition: background .12s, color .12s; }
.module-link:hover { background: var(--bg-hover); color: var(--fg); }
.module-link.active { color: var(--accent-soft-fg); background: var(--accent-soft); }
.module-link svg { flex: 0 0 auto; }
.module-link .module-label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
.collapsed .module-bar { flex-direction: column; gap: 4px; }
.collapsed .module-link .module-label { display: none; }
.collapsed .module-link { width: 44px; height: 44px; margin: 0 auto; padding: 0; border-radius: 999px; }
.quota { padding: 10px 12px; font-size: .8em; color: var(--fg-muted); }
.quota-bar { height: 4px; background: var(--bg-active); border-radius: 4px; overflow: hidden; margin-top: 6px; }
.quota-bar > span { display: block; height: 100%; background: var(--accent); }
.quota-bar > span.warn { background: var(--warn); }
.quota-bar > span.danger { background: var(--danger); }
.collapsed .quota { display: none; }
.main { min-height: 0; min-width: 0; display: flex; flex-direction: column; background: var(--bg-elev); border-radius: var(--radius-lg) 0 0 0; border: 1px solid var(--border); border-right: 0; border-bottom: 0; overflow: hidden; }
/* Mobile drawer */
.drawer-backdrop { display: none; }
.mobile-tabbar { display: none; }
.fab { display: none; }
/* ==========================================================================
Mail
========================================================================== */
.mail-layout { display: grid; grid-template-columns: minmax(340px, var(--list-w)) 1fr; height: 100%; min-height: 0; flex: 1; }
.mail-layout.pane-off { grid-template-columns: 1fr; }
.mail-layout.pane-off.reading { grid-template-columns: 1fr; }
.mail-layout .mail-list-pane { display: flex; flex-direction: column; min-height: 0; min-width: 0; border-right: 1px solid var(--border); }
.mail-layout.pane-bottom .mail-list-pane { border-right: 0; border-bottom: 1px solid var(--border); }
.mail-layout.pane-off .mail-list-pane { border-right: 0; }
.mail-layout .mail-reading-pane { min-height: 0; min-width: 0; display: flex; flex-direction: column; background: var(--bg-elev); }
.list-toolbar { display: flex; align-items: center; gap: 2px; height: 48px; padding: 0 8px 0 12px; border-bottom: 1px solid var(--border); flex: 0 0 auto; }
.list-toolbar .tb-sep { width: 1px; height: 20px; background: var(--border); margin: 0 6px; }
.list-toolbar .tb-title { font-weight: 650; font-size: 1.02em; margin-right: 8px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.list-toolbar .tb-count { color: var(--fg-muted); font-size: .85em; white-space: nowrap; }
.select-all { width: 18px; height: 18px; accent-color: var(--accent); margin: 0 6px 0 0; cursor: pointer; }
.mail-list { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; position: relative; outline: none; }
.mail-list-inner { position: relative; width: 100%; }
.msg-row { position: absolute; left: 0; right: 0; display: flex; align-items: center; gap: 8px; height: var(--row-h); padding: 0 12px 0 8px; border-bottom: 1px solid var(--border); background: var(--read-bg); cursor: pointer; user-select: none; -webkit-user-select: none; transition: box-shadow .1s; }
.msg-row.unread { background: var(--unread-bg); }
.msg-row.unread .msg-from, .msg-row.unread .msg-subject { font-weight: 700; color: var(--fg); }
.msg-row:hover { box-shadow: inset 0 0 0 1px var(--border-strong), var(--shadow-1); z-index: 2; }
.msg-row.selected { background: var(--selected-bg); }
.msg-row.focused { box-shadow: inset 3px 0 0 var(--accent); }
.msg-row.open { background: var(--selected-bg); }
.msg-row.dragging { opacity: .5; }
.msg-row .msg-check { width: 18px; height: 18px; accent-color: var(--accent); margin: 0; flex: 0 0 auto; opacity: 0; transition: opacity .1s; cursor: pointer; }
.msg-row:hover .msg-check, .msg-row.selected .msg-check, .mail-list.has-selection .msg-check { opacity: 1; }
.msg-row .msg-star { color: var(--fg-faint); flex: 0 0 auto; display: inline-flex; padding: 4px; border-radius: 50%; }
.msg-row .msg-star:hover { color: var(--star); background: var(--bg-hover); }
.msg-row .msg-star.on { color: var(--star); }
.msg-row .msg-from { width: 180px; flex: 0 0 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--fg); display: flex; align-items: center; gap: 6px; }
.msg-row .msg-from .thread-count { color: var(--fg-muted); font-weight: 400; font-size: .9em; }
.msg-row .msg-main { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: 6px; overflow: hidden; }
.msg-row .msg-subject { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 0 1 auto; min-width: 40%; max-width: 100%; color: var(--fg); }
.msg-row .msg-preview { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--fg-muted); flex: 1 1 0; min-width: 0; }
.msg-row .msg-preview::before { content: " "; }
.msg-row .msg-meta { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; color: var(--fg-muted); font-size: .85em; white-space: nowrap; }
.msg-row.unread .msg-meta .msg-date { color: var(--fg); font-weight: 700; }
.msg-row .msg-actions { display: none; align-items: center; gap: 0; margin-left: 4px; }
.msg-row:hover .msg-actions { display: flex; }
.msg-row:hover .msg-meta .msg-date { display: none; }
.msg-row .msg-labels { display: inline-flex; gap: 4px; flex: 0 0 auto; }
.msg-row .msg-labels .tag { height: 18px; font-size: 10.5px; padding: 0 6px; }
.msg-row .avatar { width: 32px; height: 32px; font-size: 12px; }
.mail-list.compact .msg-row .avatar { display: none; }
.msg-row .msg-attach { color: var(--fg-faint); }
.msg-row .msg-answered { color: var(--fg-faint); }
.msg-row .msg-important { color: var(--warn); }
.list-footer { padding: 12px; text-align: center; color: var(--fg-muted); font-size: .9em; }
.list-hint { padding: 8px 12px; font-size: .85em; color: var(--fg-muted); background: var(--bg-sunken); border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 8px; }
.list-hint button { color: var(--link); font-weight: 600; white-space: nowrap; }
.drag-ghost { position: fixed; top: -1000px; left: -1000px; padding: 8px 12px; background: var(--accent); color: var(--accent-fg); border-radius: 999px; font-weight: 600; box-shadow: var(--shadow-2); pointer-events: none; z-index: 5000; }
/* Splitter between list and reading pane */
.splitter { position: relative; background: var(--border); flex: 0 0 auto; z-index: 3; touch-action: none; }
.splitter.vertical { width: 6px; cursor: col-resize; }
.splitter.horizontal { height: 6px; cursor: row-resize; }
.splitter:hover, .splitter:focus-visible { background: var(--accent); box-shadow: none; }
.splitter .splitter-grip { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); border-radius: 4px; background: var(--fg-faint); opacity: 0; transition: opacity .15s; }
.splitter.vertical .splitter-grip { width: 3px; height: 36px; }
.splitter.horizontal .splitter-grip { height: 3px; width: 36px; }
.splitter:hover .splitter-grip { opacity: .8; }
.mail-layout.pane-right { grid-template-columns: var(--list-size, 520px) auto 1fr; }
.mail-layout.pane-bottom { grid-template-columns: 1fr; grid-template-rows: var(--list-size, 340px) auto 1fr; }
/* Two-line rows (narrow lists / mobile) */
.mail-list.two-line .msg-row { height: calc(var(--row-h) * 1.5); align-items: flex-start; padding-top: 8px; }
.mail-list.two-line .msg-row .msg-from { width: auto; flex: 1; }
.mail-list.two-line .msg-row .msg-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.mail-list.two-line .msg-row .msg-line1 { display: flex; align-items: center; gap: 8px; }
.mail-list.two-line .msg-row .msg-main { display: flex; gap: 6px; }
.mail-list.two-line .msg-row .msg-subject { flex: 0 1 auto; }
.mail-list.two-line .msg-row .msg-preview { flex: 1; }
.mail-list.two-line .msg-row .msg-meta { margin-left: auto; }
.mail-list.two-line .msg-row:hover .msg-meta .msg-date { display: inline; }
.mail-list.two-line .msg-row:hover .msg-actions { display: none; }
/* Reading pane / thread view */
.thread-view { display: flex; flex-direction: column; min-height: 0; height: 100%; }
.thread-toolbar { display: flex; align-items: center; gap: 2px; height: 48px; padding: 0 8px; border-bottom: 1px solid var(--border); flex: 0 0 auto; }
.thread-scroll { flex: 1; min-height: 0; overflow-y: auto; padding: 0 0 80px; }
.thread-subject { padding: 20px 24px 8px; display: flex; align-items: flex-start; gap: 12px; }
.thread-subject h1 { margin: 0; font-size: 1.35em; font-weight: 600; line-height: 1.3; flex: 1; overflow-wrap: anywhere; }
.thread-subject .labels { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 6px; }
.message { margin: 0 16px 8px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-elev); transition: box-shadow .12s; }
.message.collapsed { cursor: pointer; }
.message.collapsed:hover { box-shadow: var(--shadow-1); }
.message.unread-msg { border-left: 3px solid var(--accent); }
.message-head { display: flex; align-items: flex-start; gap: 12px; padding: 12px 16px; }
.message-head .who { flex: 1; min-width: 0; }
.message-head .who .from { font-weight: 650; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.message-head .who .from .email { color: var(--fg-muted); font-weight: 400; font-size: .9em; }
.message-head .who .to { color: var(--fg-muted); font-size: .88em; display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.message-head .who .to button { color: var(--fg-muted); display: inline-flex; align-items: center; }
.message-head .who .snippet { color: var(--fg-muted); font-size: .92em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.message-head .meta { display: flex; align-items: center; gap: 2px; color: var(--fg-muted); font-size: .85em; white-space: nowrap; flex: 0 0 auto; }
.message-head .meta .date { margin-right: 6px; }
.message-details { margin: 0 16px 8px; padding: 10px 12px; background: var(--bg-sunken); border-radius: var(--radius-sm); font-size: .88em; display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; }
.message-details dt { color: var(--fg-muted); }
.message-details dd { margin: 0; overflow-wrap: anywhere; }
/*
* Layout containment here is a security control, not a layout tweak.
*
* Message bodies render in a shadow root, which scopes selectors but not
* layout: a `position:fixed` rule in mail CSS is still positioned against the
* viewport, so a sender could paint over the whole application. Containment
* inside the shadow root cannot stop it — mail CSS lives in the same tree and
* simply overrides it, and `:host` reaches the host element too (an
* `!important` there even beats an `!important` from this file, because
* importance reverses tree order). An ancestor of the host is the one thing
* mail CSS has no selector for. `layout` rather than `paint`: it makes this a
* containing block for fixed descendants without clipping tall messages.
*/
.message-body { padding: 4px 16px 16px; contain: layout; }
.message-body .body-host { display: block; }
.remote-banner { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0 0 12px; padding: 8px 12px; background: var(--warn-soft); color: var(--warn); border-radius: var(--radius-sm); font-size: .9em; }
.remote-banner button { color: inherit; font-weight: 700; text-decoration: underline; }
.scheduled-banner { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0 0 12px; padding: 8px 12px; background: var(--accent-soft); color: var(--accent-soft-fg); border-radius: var(--radius-sm); font-size: .9em; }
.scheduled-banner button { color: inherit; font-weight: 700; text-decoration: underline; }
.receipt-banner { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0 0 12px; padding: 8px 12px; background: var(--warn-soft); color: var(--warn); border-radius: var(--radius-sm); font-size: .9em; }
.receipt-banner button { color: inherit; font-weight: 700; text-decoration: underline; }
.quote-toggle { display: inline-flex; align-items: center; gap: 4px; margin: 8px 0; padding: 2px 10px; border-radius: 999px; background: var(--bg-sunken); color: var(--fg-muted); font-size: 12px; border: 1px solid var(--border); }
.quote-toggle:hover { background: var(--bg-active); }
.attachments { display: flex; flex-wrap: wrap; gap: 10px; padding: 4px 16px 16px; }
.attachment { display: flex; align-items: center; gap: 10px; width: 240px; max-width: 100%; padding: 8px 10px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-elev); text-decoration: none; color: inherit; position: relative; transition: box-shadow .12s; }
.attachment:hover { box-shadow: var(--shadow-1); }
.attachment .att-icon { width: 36px; height: 36px; border-radius: 8px; display: flex; align-items: center; justify-content: center; background: var(--accent-soft); color: var(--accent-soft-fg); flex: 0 0 auto; overflow: hidden; }
.attachment .att-icon img { width: 100%; height: 100%; object-fit: cover; }
.attachment .att-text { flex: 1; min-width: 0; }
.attachment .att-name { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: .92em; }
.attachment .att-size { color: var(--fg-muted); font-size: .8em; }
.attachment .att-actions { display: none; gap: 0; }
.attachment:hover .att-actions { display: flex; }
.attachment:hover .att-size { display: none; }
.attachment .att-progress { position: absolute; left: 0; bottom: 0; height: 3px; background: var(--accent); border-radius: 0 0 0 6px; }
.attachment.error { border-color: var(--danger); }
.thread-actions { display: flex; gap: 8px; padding: 8px 16px 16px; flex-wrap: wrap; }
.invite-card { margin: 0 16px 12px; padding: 14px 16px; border: 1px solid var(--border); border-left: 4px solid var(--accent); border-radius: var(--radius-sm); background: var(--bg-sunken); }
.invite-card h4 { margin: 0 0 4px; }
.invite-card .rsvp { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.vcard-card { margin: 0 16px 12px; padding: 12px 16px; border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--bg-sunken); display: flex; align-items: center; gap: 12px; }
.unsubscribe-row { margin: 0 16px 8px; font-size: .88em; color: var(--fg-muted); display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.reply-box { margin: 8px 16px 24px; }
.reply-box .reply-prompt { display: flex; gap: 8px; align-items: center; padding: 12px; border: 1px solid var(--border); border-radius: var(--radius); color: var(--fg-muted); }
.reply-box .reply-prompt button { display: inline-flex; align-items: center; gap: 6px; padding: 8px 14px; border-radius: 999px; border: 1px solid var(--border-strong); color: var(--fg); font-weight: 500; }
.reply-box .reply-prompt button:hover { background: var(--bg-hover); }
.no-thread { height: 100%; display: flex; align-items: center; justify-content: center; flex-direction: column; gap: 8px; color: var(--fg-muted); }
.no-thread img { width: 140px; opacity: .6; filter: grayscale(.3); }
.thread-nav { display: flex; align-items: center; gap: 2px; margin-left: auto; color: var(--fg-muted); font-size: .85em; }
.print-only { display: none; }
/* Labels (keywords) */
.label-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
/* ==========================================================================
Composer
========================================================================== */
.composer-dock { position: fixed; right: 16px; bottom: 0; display: flex; align-items: flex-end; gap: 12px; z-index: 800; pointer-events: none; }
.composer { pointer-events: auto; width: 580px; max-width: calc(100vw - 32px); height: 600px; max-height: calc(100vh - 24px); display: flex; flex-direction: column; background: var(--bg-elev); border-radius: var(--radius-lg) var(--radius-lg) 0 0; box-shadow: var(--shadow-3); border: 1px solid var(--border); border-bottom: 0; overflow: hidden; animation: rise .2s var(--ease); }
.composer.minimized { height: 44px; width: 280px; }
.composer.maximized { position: fixed; inset: 24px; width: auto; height: auto; max-width: none; max-height: none; border-radius: var(--radius-lg); border-bottom: 1px solid var(--border); }
.composer-head { display: flex; align-items: center; gap: 4px; height: 44px; padding: 0 6px 0 14px; background: var(--bg-sunken); border-bottom: 1px solid var(--border); flex: 0 0 auto; cursor: default; }
.composer-head .title { flex: 1; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.composer-head .status { color: var(--fg-faint); font-size: .8em; margin-right: 6px; white-space: nowrap; }
.composer-body { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.composer-fields { flex: 0 0 auto; padding: 0 12px; }
.composer-field { display: flex; align-items: center; gap: 8px; min-height: 40px; border-bottom: 1px solid var(--border); padding: 4px 0; }
.composer-field > label { color: var(--fg-muted); width: 42px; flex: 0 0 auto; font-size: .92em; }
.composer-field .field-extra { display: flex; gap: 4px; color: var(--fg-muted); font-size: .85em; }
.composer-field .field-extra button { color: var(--fg-muted); padding: 2px 6px; border-radius: 4px; }
.composer-field .field-extra button:hover { background: var(--bg-hover); color: var(--fg); }
.composer-field input.plain { flex: 1; border: 0; background: transparent; outline: none; min-width: 80px; height: 30px; }
.composer-field .from-select { flex: 1; border: 0; background: transparent; color: var(--fg); padding: 0; height: 30px; cursor: pointer; }
/*
* A native <select>'s dropdown is painted by the browser from the element's own
* colours, not the page's. `.from-select` is deliberately transparent so it
* sits flush in the composer's From line -- which left its popup with no
* background of its own, so the browser drew a light one while the text kept
* the app's light foreground: light on light, unreadable in any dark theme.
*
* Styling `option` fixes the popup without giving the closed control a box.
* Scoped to every select rather than this one, because nothing else in the app
* styled options either -- the next transparent select would have arrived with
* the same bug.
*/
select option,
select optgroup { background-color: var(--bg-elev); color: var(--fg); }
.recipients { flex: 1; display: flex; flex-wrap: wrap; align-items: center; gap: 4px; min-width: 0; position: relative; }
.recipients .chip { height: 24px; }
.recipients input { flex: 1; min-width: 120px; border: 0; background: transparent; outline: none; height: 28px; }
.composer-editor { flex: 1; min-height: 0; display: flex; flex-direction: column; position: relative; }
.editor-area { flex: 1; min-height: 120px; overflow-y: auto; padding: 12px 16px; outline: none; line-height: 1.5; font-size: 14px; font-family: var(--font-sans); }
.editor-area:empty::before, .editor-area[data-empty="true"]::before { content: attr(data-placeholder); color: var(--fg-faint); pointer-events: none; position: absolute; }
.editor-area blockquote { margin: 0 0 0 .8ex; border-left: 2px solid var(--border-strong); padding-left: 1ex; color: var(--fg-muted); }
.editor-area img { max-width: 100%; height: auto; }
.editor-area a { color: var(--link); }
.editor-area .ihm-signature { color: var(--fg-muted); }
.editor-area pre { font-family: var(--font-mono); background: var(--bg-sunken); padding: 8px; border-radius: 6px; overflow: auto; }
.editor-textarea { flex: 1; border: 0; resize: none; outline: none; padding: 12px 16px; font-family: var(--font-mono); font-size: 13.5px; line-height: 1.5; background: transparent; }
.editor-toolbar { display: flex; align-items: center; gap: 1px; flex-wrap: wrap; padding: 4px 8px; border-top: 1px solid var(--border); flex: 0 0 auto; }
.editor-toolbar .icon-btn { width: 30px; height: 30px; border-radius: 6px; }
.editor-toolbar .tb-sep { width: 1px; height: 18px; background: var(--border); margin: 0 4px; }
.editor-toolbar select { height: 28px; border: 0; background: transparent; color: var(--fg-muted); font-size: .85em; max-width: 110px; }
.composer-attachments { display: flex; flex-wrap: wrap; gap: 8px; padding: 8px 12px 0; max-height: 140px; overflow-y: auto; }
.composer-attachments .attachment { width: 200px; padding: 6px 8px; }
.composer-foot { display: flex; align-items: center; gap: 4px; padding: 8px 12px; border-top: 1px solid var(--border); flex: 0 0 auto; }
.composer-foot .send-group { display: flex; }
.composer-foot .send-group .btn:first-child { border-radius: 999px 0 0 999px; padding-left: 20px; }
.composer-foot .send-group .btn:last-child { border-radius: 0 999px 999px 0; padding: 0 8px; border-left: 1px solid rgba(255,255,255,.3); }
.composer-foot .more-actions { display: flex; align-items: center; gap: 2px; margin-left: 8px; }
.composer.dropping .composer-body { outline: 3px dashed var(--accent); outline-offset: -8px; }
.suggest-list { position: absolute; top: 100%; left: 0; min-width: 300px; max-width: 100%; background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius-sm); box-shadow: var(--shadow-2); z-index: 20; padding: 4px; max-height: 260px; overflow: auto; }
.suggest-item { display: flex; align-items: center; gap: 10px; padding: 6px 8px; border-radius: 6px; cursor: pointer; }
.suggest-item.active, .suggest-item:hover { background: var(--bg-hover); }
.suggest-item .s-name { font-weight: 550; }
.suggest-item .s-email { color: var(--fg-muted); font-size: .85em; }
.suggest-item .s-src { margin-left: auto; font-size: .72em; color: var(--fg-faint); text-transform: uppercase; letter-spacing: .05em; }
.emoji-grid { display: grid; grid-template-columns: repeat(8, 32px); gap: 2px; padding: 4px; }
.emoji-grid button { font-size: 20px; height: 32px; border-radius: 6px; }
.emoji-grid button:hover { background: var(--bg-hover); }
.link-popup { display: flex; gap: 6px; padding: 8px; }
.color-grid { display: grid; grid-template-columns: repeat(8, 22px); gap: 4px; padding: 6px; }
.color-grid button { width: 22px; height: 22px; border-radius: 4px; border: 1px solid rgba(0,0,0,.1); }
/* ==========================================================================
Settings
========================================================================== */
.settings-layout { display: grid; grid-template-columns: 240px 1fr; height: 100%; min-height: 0; flex: 1; }
.settings-nav { border-right: 1px solid var(--border); padding: 12px 8px; overflow-y: auto; }
.settings-nav .nav-item { margin-right: 0; border-radius: var(--radius-sm); }
.settings-content { overflow-y: auto; padding: 24px 32px 64px; max-width: 860px; }
.settings-content h1 { margin: 0 0 4px; font-size: 1.5em; font-weight: 650; }
.settings-content h2 { margin: 28px 0 12px; font-size: 1.05em; font-weight: 650; padding-bottom: 6px; border-bottom: 1px solid var(--border); }
.settings-content .lead { color: var(--fg-muted); margin: 0 0 20px; }
.card { border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-elev); padding: 14px 16px; margin-bottom: 12px; }
.card.clickable { cursor: pointer; transition: box-shadow .12s; }
.card.clickable:hover { box-shadow: var(--shadow-1); }
.card-head { display: flex; align-items: center; gap: 10px; }
.card-head h3 { margin: 0; font-size: 1em; font-weight: 650; flex: 1; }
.theme-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 10px; }
.theme-card { border: 2px solid var(--border); border-radius: var(--radius); padding: 8px; cursor: pointer; text-align: center; font-size: .9em; }
.theme-card.active { border-color: var(--accent); }
.theme-card .preview { height: 56px; border-radius: 6px; margin-bottom: 6px; border: 1px solid var(--border); }
.swatches { display: flex; gap: 10px; flex-wrap: wrap; }
.swatch { width: 32px; height: 32px; border-radius: 50%; border: 3px solid transparent; cursor: pointer; }
.swatch.active { border-color: var(--fg); }
.rule-card { border: 1px solid var(--border); border-radius: var(--radius); padding: 12px 14px; margin-bottom: 10px; background: var(--bg-elev); }
.rule-card.disabled { opacity: .6; }
.rule-card.dragging { opacity: .5; }
/* The line shows which side of this card the dragged rule would land on. */
.rule-card.drop-above { box-shadow: inset 0 3px 0 0 var(--accent); }
.rule-card.drop-below { box-shadow: inset 0 -3px 0 0 var(--accent); }
.rule-card .drag-handle { display: flex; align-items: center; padding: 2px; margin-left: -4px; color: var(--fg-faint); cursor: grab; touch-action: none; }
.rule-card .drag-handle:active { cursor: grabbing; }
.rule-row { display: grid; grid-template-columns: 1fr 1fr 1fr auto; gap: 8px; align-items: center; margin-bottom: 8px; }
.rule-row.actions { grid-template-columns: 1fr 2fr auto; }
/* A header typed by hand needs a box of its own, alongside the comparator. */
.rule-row.named-header { grid-template-columns: 1fr 1fr 1fr 1fr auto; }
.code { font-family: var(--font-mono); font-size: 12.5px; line-height: 1.5; white-space: pre; overflow: auto; background: var(--bg-sunken); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 12px; min-height: 240px; width: 100%; resize: vertical; tab-size: 2; }
.shortcut-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 16px 32px; }
.shortcut-grid h3 { margin: 0 0 6px; font-size: .9em; text-transform: uppercase; letter-spacing: .05em; color: var(--fg-faint); }
.shortcut-row { display: flex; justify-content: space-between; align-items: center; padding: 4px 0; gap: 12px; }
.shortcut-row .keys { display: flex; gap: 4px; }
.sessions-table { width: 100%; border-collapse: collapse; font-size: .92em; }
.sessions-table th, .sessions-table td { text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--border); }
.sessions-table th { color: var(--fg-muted); font-weight: 600; font-size: .85em; }
/* ==========================================================================
Contacts
========================================================================== */
.contacts-layout { display: grid; grid-template-columns: 220px minmax(280px, 360px) 1fr; height: 100%; min-height: 0; flex: 1; }
.contacts-books { border-right: 1px solid var(--border); padding: 12px 8px; overflow-y: auto; overflow-x: hidden; }
.contacts-list { border-right: 1px solid var(--border); display: flex; flex-direction: column; min-height: 0; }
.contacts-list .list-search { padding: 10px 12px; border-bottom: 1px solid var(--border); }
.contacts-scroll { flex: 1; overflow-y: auto; }
.contact-row { display: flex; align-items: center; gap: 12px; padding: 8px 14px; cursor: pointer; border-bottom: 1px solid var(--border); }
.contact-row:hover { background: var(--bg-hover); }
.contact-row.active { background: var(--selected-bg); }
.contact-row .c-name { font-weight: 550; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.contact-row .c-email { color: var(--fg-muted); font-size: .85em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.contact-letter { position: sticky; top: 0; background: var(--bg-sunken); padding: 4px 14px; font-size: .78em; font-weight: 700; color: var(--fg-muted); letter-spacing: .05em; z-index: 1; }
.contact-detail { overflow-y: auto; padding: 28px 32px 64px; }
.contact-hero { display: flex; align-items: center; gap: 20px; margin-bottom: 20px; }
.contact-hero h1 { margin: 0; font-size: 1.6em; font-weight: 650; }
.contact-hero .sub { color: var(--fg-muted); }
.contact-section { margin-bottom: 20px; }
.contact-section h3 { margin: 0 0 8px; font-size: .8em; text-transform: uppercase; letter-spacing: .06em; color: var(--fg-faint); }
.contact-kv { display: flex; align-items: flex-start; gap: 12px; padding: 6px 0; }
.contact-kv .k { width: 90px; color: var(--fg-muted); font-size: .9em; flex: 0 0 auto; padding-top: 2px; }
.contact-kv .v { flex: 1; overflow-wrap: anywhere; }
.contact-form .multi { display: flex; flex-direction: column; gap: 8px; }
.contact-form .multi-row { display: grid; grid-template-columns: 1fr 130px auto; gap: 8px; align-items: center; }
.contact-form .multi-row.address { grid-template-columns: 1fr auto; }
.contact-form .addr-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
/* ==========================================================================
Calendar
========================================================================== */
.cal-layout { display: grid; grid-template-columns: 240px 1fr; height: 100%; min-height: 0; }
.cal-side { border-right: 1px solid var(--border); padding: 12px; overflow-y: auto; display: flex; flex-direction: column; gap: 12px; }
.cal-main { display: flex; flex-direction: column; min-height: 0; min-width: 0; flex: 1; height: 100%; }
.cal-toolbar { display: flex; align-items: center; gap: 8px; padding: 8px 12px; border-bottom: 1px solid var(--border); flex: 0 0 auto; }
.cal-toolbar h2 { margin: 0 8px; font-size: 1.2em; font-weight: 650; min-width: 0; white-space: nowrap; }
.view-switch { display: inline-flex; border: 1px solid var(--border-strong); border-radius: var(--radius-sm); overflow: hidden; }
.view-switch button { padding: 0 12px; height: 34px; font-weight: 500; color: var(--fg-muted); }
.view-switch button.active { background: var(--accent-soft); color: var(--accent-soft-fg); }
.view-switch button:not(:last-child) { border-right: 1px solid var(--border-strong); }
.mini-cal { font-size: .85em; }
.mini-cal .mc-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; font-weight: 650; }
.mini-cal .mc-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; text-align: center; }
.mini-cal .mc-dow { color: var(--fg-faint); font-size: .85em; padding: 2px 0; }
.mini-cal .mc-day { height: 26px; border-radius: 50%; display: flex; align-items: center; justify-content: center; cursor: pointer; }
.mini-cal .mc-day:hover { background: var(--bg-hover); }
.mini-cal .mc-day.other { color: var(--fg-faint); }
.mini-cal .mc-day.today { font-weight: 700; color: var(--accent); }
.mini-cal .mc-day.selected { background: var(--accent); color: var(--accent-fg); }
.mini-cal .mc-day.has-events::after { content: ""; display: block; width: 4px; height: 4px; border-radius: 50%; background: var(--accent); position: relative; top: 9px; left: -1px; }
.cal-list-item { display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: var(--radius-sm); cursor: pointer; }
.cal-list-item:hover { background: var(--bg-hover); }
.cal-list-item .cal-color { width: 14px; height: 14px; border-radius: 4px; border: 2px solid transparent; flex: 0 0 auto; }
.cal-list-item.hidden-cal .cal-color { background: transparent !important; }
.cal-list-item .cal-name { flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cal-list-item .nav-more { opacity: 0; }
.cal-list-item:hover .nav-more { opacity: 1; }
.month-grid { flex: 1; display: grid; grid-template-rows: auto repeat(6, 1fr); min-height: 0; }
.month-grid .dow-row { display: grid; grid-template-columns: repeat(7, 1fr); border-bottom: 1px solid var(--border); }
.month-grid .dow-row div { padding: 6px; text-align: center; font-size: .8em; font-weight: 600; color: var(--fg-muted); text-transform: uppercase; letter-spacing: .04em; }
.month-grid .week-row { display: grid; grid-template-columns: repeat(7, 1fr); min-height: 0; border-bottom: 1px solid var(--border); }
.month-cell { border-right: 1px solid var(--border); padding: 4px; min-width: 0; min-height: 0; display: flex; flex-direction: column; gap: 2px; overflow: hidden; cursor: pointer; position: relative; }
.month-cell:last-child { border-right: 0; }
.month-cell.other { background: var(--bg-sunken); color: var(--fg-faint); }
.month-cell:hover { background: var(--bg-hover); }
.month-cell .day-num { min-width: 26px; height: 26px; padding: 0 4px; display: flex; align-items: center; justify-content: center; border-radius: 999px; font-size: .9em; font-weight: 500; align-self: flex-start; white-space: nowrap; }
.month-cell.today .day-num { background: var(--accent); color: var(--accent-fg); font-weight: 700; }
.month-cell .more { font-size: .78em; color: var(--fg-muted); padding-left: 4px; font-weight: 600; }
.ev-chip { display: flex; align-items: center; gap: 4px; padding: 1px 6px; border-radius: 4px; font-size: .8em; line-height: 1.4; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: pointer; color: #fff; font-weight: 500; flex: 0 0 auto; border: 1px solid transparent; }
.ev-chip.timed { background: transparent !important; color: var(--fg); border-color: transparent !important; }
.ev-chip.timed .ev-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.ev-chip.timed .ev-time { color: var(--fg-muted); }
.ev-chip:hover { filter: brightness(.95); }
.ev-chip.timed:hover { background: var(--bg-hover) !important; }
.ev-chip.declined { text-decoration: line-through; opacity: .6; }
.ev-chip.tentative { border-style: dashed; opacity: .85; }
.ev-chip.cancelled { text-decoration: line-through; opacity: .5; }
.week-view { flex: 1; display: flex; flex-direction: column; min-height: 0; }
.week-head { display: grid; grid-template-columns: 56px repeat(var(--cols, 7), 1fr); border-bottom: 1px solid var(--border); flex: 0 0 auto; }
.week-head .wh-day { padding: 8px 4px 4px; text-align: center; border-left: 1px solid var(--border); cursor: pointer; }
.week-head .wh-day .dow { font-size: .75em; text-transform: uppercase; color: var(--fg-muted); font-weight: 600; }
.week-head .wh-day .dnum { font-size: 1.4em; font-weight: 500; width: 40px; height: 40px; display: inline-flex; align-items: center; justify-content: center; border-radius: 50%; }
.week-head .wh-day.today .dnum { background: var(--accent); color: var(--accent-fg); }
.week-allday { display: grid; grid-template-columns: 56px repeat(var(--cols, 7), 1fr); border-bottom: 1px solid var(--border); min-height: 28px; flex: 0 0 auto; }
.week-allday .ad-cell { border-left: 1px solid var(--border); padding: 2px; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.week-allday .ad-label { font-size: .7em; color: var(--fg-faint); text-align: right; padding: 4px 6px; }
.week-scroll { flex: 1; overflow-y: auto; position: relative; }
.week-body { display: grid; grid-template-columns: 56px repeat(var(--cols, 7), 1fr); position: relative; height: calc(24 * var(--hour-h, 48px)); }
.week-body .time-col { position: relative; }
.week-body .time-col .hour-label { position: absolute; right: 6px; transform: translateY(-50%); font-size: .72em; color: var(--fg-faint); }
.week-body .day-col { position: relative; border-left: 1px solid var(--border); cursor: pointer; }
.week-body .day-col.today { background: color-mix(in srgb, var(--accent-soft) 35%, transparent); }
.week-body .hour-line { position: absolute; left: 0; right: 0; border-top: 1px solid var(--border); pointer-events: none; }
.week-body .half-line { position: absolute; left: 0; right: 0; border-top: 1px dashed color-mix(in srgb, var(--border) 60%, transparent); pointer-events: none; }
.week-body .now-line { position: absolute; left: 0; right: 0; border-top: 2px solid var(--danger); z-index: 5; pointer-events: none; }
.week-body .now-line::before { content: ""; position: absolute; left: -5px; top: -6px; width: 10px; height: 10px; border-radius: 50%; background: var(--danger); }
.week-body .work-hours { position: absolute; left: 0; right: 0; background: color-mix(in srgb, var(--bg-elev) 60%, transparent); pointer-events: none; }
.ev-block { position: absolute; border-radius: 6px; padding: 3px 6px; font-size: .8em; color: #fff; overflow: hidden; cursor: pointer; box-shadow: var(--shadow-1); border: 1px solid rgba(255,255,255,.4); line-height: 1.3; z-index: 2; transition: box-shadow .1s; }
.ev-block:hover { box-shadow: var(--shadow-2); z-index: 3; }
.ev-block .ev-title { font-weight: 650; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ev-block .ev-time { opacity: .9; font-size: .92em; }
.ev-block.declined { opacity: .5; text-decoration: line-through; }
.ev-block.tentative { background-image: repeating-linear-gradient(45deg, rgba(255,255,255,.12) 0 6px, transparent 6px 12px); }
.ev-block.draft-new { opacity: .7; border: 2px dashed #fff; }
.agenda { overflow-y: auto; padding: 12px 16px 64px; }
.agenda-day { display: grid; grid-template-columns: 120px 1fr; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--border); }
.agenda-day .ad-date { font-weight: 600; }
.agenda-day .ad-date.today { color: var(--accent); }
.agenda-day .ad-date small { display: block; color: var(--fg-muted); font-weight: 400; }
.agenda-ev { display: flex; align-items: center; gap: 10px; padding: 6px 8px; border-radius: var(--radius-sm); cursor: pointer; }
.agenda-ev:hover { background: var(--bg-hover); }
.agenda-ev .ev-dot { width: 10px; height: 10px; border-radius: 50%; flex: 0 0 auto; }
.agenda-ev .ev-when { width: 140px; color: var(--fg-muted); font-size: .9em; flex: 0 0 auto; }
.event-popover { width: 360px; max-width: calc(100vw - 24px); padding: 14px 16px; }
.event-popover h3 { margin: 0 0 6px; font-size: 1.15em; font-weight: 650; padding-left: 16px; position: relative; }
.event-popover h3::before { content: ""; position: absolute; left: 0; top: 6px; width: 10px; height: 10px; border-radius: 3px; background: var(--ev-color, var(--accent)); }
.event-popover .ev-line { display: flex; gap: 10px; align-items: flex-start; color: var(--fg-muted); font-size: .92em; margin: 6px 0; }
.event-popover .ev-line svg { flex: 0 0 auto; margin-top: 2px; }
.participant-row { display: flex; align-items: center; gap: 8px; padding: 4px 0; font-size: .92em; }
.participant-row .p-status { width: 10px; height: 10px; border-radius: 50%; flex: 0 0 auto; }
.p-status.accepted { background: var(--success); } .p-status.declined { background: var(--danger); } .p-status.tentative { background: var(--warn); } .p-status.needs-action { background: var(--fg-faint); }
.event-form .time-row { display: grid; grid-template-columns: 1fr auto 1fr; gap: 8px; align-items: center; }
.event-form .alerts-list { display: flex; flex-direction: column; gap: 6px; }
.event-form .alerts-list .row { gap: 6px; }
.freebusy { display: flex; flex-direction: column; gap: 4px; margin-top: 8px; }
.freebusy .fb-row { display: flex; align-items: center; gap: 8px; font-size: .85em; }
.freebusy .fb-bar { flex: 1; height: 14px; background: var(--bg-sunken); border-radius: 4px; position: relative; overflow: hidden; }
.freebusy .fb-busy { position: absolute; top: 0; bottom: 0; background: var(--danger); opacity: .65; }
.freebusy .fb-window { position: absolute; top: 0; bottom: 0; border: 2px solid var(--accent); border-radius: 3px; }
/* ==========================================================================
Files
========================================================================== */
.files-layout { display: flex; flex-direction: column; height: 100%; min-height: 0; flex: 1; }
.files-toolbar { display: flex; align-items: center; gap: 8px; padding: 8px 12px; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.breadcrumb { display: flex; align-items: center; gap: 4px; flex: 1; min-width: 0; overflow: hidden; }
.breadcrumb button { padding: 4px 8px; border-radius: 6px; color: var(--fg-muted); font-weight: 500; white-space: nowrap; }
.breadcrumb button:hover { background: var(--bg-hover); color: var(--fg); }
.breadcrumb button.current { color: var(--fg); font-weight: 650; }
.files-table { width: 100%; border-collapse: collapse; }
.files-table th { text-align: left; padding: 8px 12px; font-size: .8em; color: var(--fg-muted); font-weight: 600; border-bottom: 1px solid var(--border); position: sticky; top: 0; background: var(--bg-elev); z-index: 1; }
.files-table td { padding: 8px 12px; border-bottom: 1px solid var(--border); }
.files-table tr { cursor: pointer; }
.files-table tbody tr:hover { background: var(--bg-hover); }
.files-table tr.selected { background: var(--selected-bg); }
.files-table .f-name { display: flex; align-items: center; gap: 10px; font-weight: 500; }
.files-table .f-name svg { color: var(--fg-muted); }
.files-scroll { flex: 1; overflow: auto; }
.files-layout.dropping .files-scroll { outline: 3px dashed var(--accent); outline-offset: -10px; }
/* ==========================================================================
Login
========================================================================== */
.login-page { min-height: 100%; display: flex; align-items: center; justify-content: center; padding: 24px; background: radial-gradient(1200px 600px at 10% -10%, var(--accent-soft), transparent 60%), radial-gradient(900px 500px at 110% 110%, var(--accent-soft), transparent 60%), var(--bg); }
.login-card { width: 100%; max-width: 400px; background: var(--bg-elev); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow-2); padding: 32px 28px 24px; animation: rise .25s var(--ease); }
.login-card .logo { display: flex; flex-direction: column; align-items: center; gap: 6px; margin-bottom: 20px; }
.login-card .logo img { width: 120px; height: auto; }
/* The logo is the mark alone, so the name is set here rather than baked in. */
.login-card h1 { margin: 0; font-size: 1.6em; font-weight: 800; letter-spacing: -.02em; color: #14b8a6; }
.login-card .sub { color: var(--fg-muted); font-size: .92em; margin: 0; }
.login-card .tagline { color: var(--fg-muted); font-size: 1em; margin: 4px 0 0; text-align: center; }
.login-card .foot a { color: var(--fg-muted); text-decoration: underline; }
.login-card .foot { margin-top: 20px; font-size: .8em; color: var(--fg-faint); text-align: center; }
.login-card .pw-wrap { position: relative; }
.login-card .pw-wrap .icon-btn { position: absolute; right: 2px; top: 1px; }
/* ==========================================================================
Responsive
========================================================================== */
@media (max-width: 1100px) {
:root { --list-w: 44%; }
.msg-row .msg-from { width: 140px; }
.contacts-layout { grid-template-columns: 200px 300px 1fr; }
}
@media (max-width: 900px) {
.mail-layout:not(.pane-off):not(.pane-bottom) { grid-template-columns: 1fr !important; }
.mail-layout.pane-bottom { grid-template-rows: 1fr !important; }
.mail-layout.pane-bottom .mail-reading-pane { display: none; }
.mail-layout.pane-bottom.reading .mail-list-pane { display: none; }
.mail-layout.pane-bottom.reading .mail-reading-pane { display: flex; }
.mail-layout .splitter { display: none; }
.mail-layout:not(.pane-bottom) .mail-reading-pane { display: none; }
.mail-layout.reading .mail-list-pane { display: none; }
.mail-layout.reading .mail-reading-pane { display: flex; }
.settings-layout { grid-template-columns: 1fr; }
.settings-nav { display: none; }
.settings-layout.section .settings-nav { display: none; }
.settings-layout.root .settings-nav { display: block; border-right: 0; }
.settings-layout.root .settings-content { display: none; }
.settings-content { padding: 16px 16px 80px; }
.contacts-layout { grid-template-columns: 1fr; }
.contacts-books { display: none; }
.contacts-layout.detail .contacts-list { display: none; }
.contacts-layout:not(.detail) .contact-detail { display: none; }
.cal-layout { grid-template-columns: 1fr; }
.cal-side { display: none; }
}
@media (max-width: 768px) {
:root { --topbar-h: 52px; }
.app-body, .app-body.collapsed { grid-template-columns: 1fr; }
.sidebar { position: fixed; top: 0; bottom: 0; left: 0; width: min(300px, 85vw); background: var(--bg-elev); z-index: 950; transform: translateX(-105%); transition: transform .22s var(--ease); box-shadow: var(--shadow-3); padding-top: 12px; }
.sidebar.open { transform: none; }
.collapsed .sidebar .nav-item, .collapsed .sidebar .compose-btn { all: revert; }
.collapsed .module-bar { flex-direction: row; }
.collapsed .module-link { width: auto; height: auto; padding: 6px 2px; border-radius: var(--radius-sm); }
.collapsed .module-link .module-label { display: block; }
.drawer-backdrop { display: block; position: fixed; inset: 0; z-index: 940; background: rgba(2,6,23,.45); opacity: 0; pointer-events: none; transition: opacity .2s; }
.drawer-backdrop.open { opacity: 1; pointer-events: auto; }
.main { border-radius: 0; border: 0; }
.topbar { padding: 0 6px; gap: 4px; }
.topbar .brand .brand-name { display: none; }
.searchbar .search-input { height: 40px; }
.topbar-actions .hide-mobile { display: none; }
.msg-row { padding-right: 8px; }
.mail-list { padding-bottom: 72px; }
.composer { width: 100vw; max-width: 100vw; height: 100vh; max-height: 100vh; border-radius: 0; position: fixed; inset: 0; }
.composer.minimized { height: 44px; width: 100vw; top: auto; bottom: 0; }
.composer-dock { right: 0; }
.dialog { max-height: calc(100vh - 16px); }
.fab { display: flex; position: fixed; right: 18px; bottom: 78px; width: 56px; height: 56px; border-radius: 18px; background: var(--accent); color: var(--accent-fg); align-items: center; justify-content: center; box-shadow: var(--shadow-2); z-index: 700; }
.mobile-tabbar { display: grid; grid-template-columns: repeat(4, 1fr); position: fixed; left: 0; right: 0; bottom: 0; height: 60px; background: var(--bg-elev); border-top: 1px solid var(--border); z-index: 700; padding-bottom: env(safe-area-inset-bottom); }
.mobile-tabbar a { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; color: var(--fg-muted); text-decoration: none; font-size: 11px; }
.mobile-tabbar a.active { color: var(--accent); }
.main { padding-bottom: 60px; }
.thread-subject { padding: 14px 16px 8px; }
.message { margin: 0 8px 8px; }
.message-head { padding: 10px 12px; }
.message-body { padding: 4px 12px 12px; }
.thread-toolbar .hide-mobile { display: none; }
.list-toolbar .hide-mobile { display: none; }
.week-head .wh-day .dnum { width: 32px; height: 32px; font-size: 1.1em; }
.cal-toolbar h2 { font-size: 1em; }
.contact-detail { padding: 16px 16px 80px; }
.files-table .hide-mobile { display: none; }
.event-popover { width: calc(100vw - 24px); }
}
@media (hover: none) {
.msg-row .msg-check { opacity: 1; }
.msg-row .msg-actions { display: none !important; }
.msg-row:hover .msg-meta .msg-date { display: inline; }
.nav-item .nav-more, .cal-list-item .nav-more { opacity: 1; }
}
@media print {
.topbar, .sidebar, .mail-list-pane, .thread-toolbar, .composer-dock, .toast-host, .mobile-tabbar, .fab, .reply-box, .thread-actions, .quote-toggle { display: none !important; }
.app, .app-body, .main, .mail-layout, .mail-reading-pane, .thread-view, .thread-scroll { display: block !important; height: auto !important; overflow: visible !important; grid-template-columns: 1fr !important; border: 0 !important; }
.message { break-inside: avoid; border: 1px solid #ccc; }
.print-only { display: block; }
body { background: #fff; color: #000; }
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}
/* Addresses in a message carry a right-click menu (see mail/AddressMenu.tsx). */
.addr { cursor: context-menu; }
.message-details .addr:hover, .message-head .from .addr:hover { text-decoration: underline dotted; text-underline-offset: 2px; }
/* ---- Date & time fields (custom pickers; see ui/datefield.tsx) ---- */
.dp-field { position: relative; display: inline-flex; align-items: center; width: 100%; }
.dp-field .input { width: 100%; padding-right: 30px; }
.dp-open { position: absolute; right: 4px; display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; border: 0; background: none; color: var(--fg-muted); cursor: pointer; border-radius: var(--radius-sm); }
button.dp-open:hover { background: var(--bg-hover); color: var(--fg); }
button.dp-open:disabled { cursor: default; opacity: .5; }
.dp-field.w-auto { width: auto; }
.dp-field.w-auto .input { width: 10em; }
.dp-datetime { display: flex; gap: 6px; align-items: center; }
.dp-datetime .dp-field { flex: 1 1 auto; }
.dp-datetime .dp-time-field { flex: 0 0 8.5em; }
.dp-pop { padding: 10px; }
.dp-pop-wide { display: flex; }
.dp-split { display: flex; gap: 10px; align-items: stretch; }
.dp-cal { width: 15.5em; }
.dp-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; font-weight: 650; }
.dp-dow, .dp-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; text-align: center; }
.dp-dow { color: var(--fg-faint); font-size: .8em; padding-bottom: 2px; }
.dp-day { height: 28px; border: 0; background: none; color: inherit; font: inherit; font-size: .9em; border-radius: 50%; cursor: pointer; }
.dp-day:hover { background: var(--bg-hover); }
.dp-day:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.dp-day.other { color: var(--fg-faint); }
.dp-day.today { font-weight: 700; color: var(--accent); }
.dp-day.selected { background: var(--accent); color: var(--accent-fg); font-weight: 600; }
.dp-foot { display: flex; justify-content: space-between; margin-top: 6px; }
.dp-times { display: flex; flex-direction: column; gap: 1px; overflow-y: auto; max-height: 17em; min-width: 7.5em; border-left: 1px solid var(--border); padding-left: 8px; }
.dp-time { border: 0; background: none; color: inherit; font: inherit; font-size: .9em; text-align: left; padding: 4px 8px; border-radius: var(--radius-sm); cursor: pointer; white-space: nowrap; }
.dp-time:hover { background: var(--bg-hover); }
.dp-time.selected { background: var(--accent); color: var(--accent-fg); }
@media (max-width: 480px) {
.dp-datetime { flex-wrap: wrap; }
.dp-datetime .dp-time-field { flex: 1 1 100%; }
.dp-split { flex-direction: column; }
.dp-times { flex-direction: row; overflow-x: auto; max-height: none; border-left: 0; border-top: 1px solid var(--border); padding: 6px 0 0; }
}