﻿/* ============ Quriou Mail — Chinese-inspired minimal UI ============ */

:root[data-theme="light"] {
  --bg: #f7f5f0;
  --bg-panel: #ffffff;
  --bg-hover: #f0ede6;
  --bg-active: #e9e4d8;
  --text: #2b2b2b;
  --text-dim: #757063;        /* 4.53:1 on --bg (was #8a8578, 3.38:1) */
  --border: #e4dfd3;
  --accent: #14535f;         /* Qmail teal — 7.92:1 on --bg */
  --accent-soft: #dfeceb;
  --accent-strong: #14535f;  /* white on this: 8.63:1 */
  --border-strong: #938e82;  /* 3.00:1 on --bg, for control boundaries */
  /* danger was a single theme-invariant var(--danger) used in 11 rules: 3.92:1 on the
     light ground and 3.93:1 on the dark panel, so it failed AA in BOTH themes.
     Two tokens, measured per theme. */
  --danger: #a8321d;         /* 5.42:1 on --bg */
  --danger-strong: #8f2a18;  /* white on this: 6.68:1 */
  --shadow: 0 2px 12px rgba(60, 50, 30, 0.08);
}

:root[data-theme="dark"] {
  --bg: #171512;
  --bg-panel: #201d19;
  --bg-hover: #2a2620;
  --bg-active: #332e26;
  --text: #eae6dc;
  --text-dim: #8f8a7d;
  --border: #35302a;
  --accent: #2f9c9c;         /* 5.52:1 on --bg, 5.08:1 on --bg-panel */
  --accent-soft: #12292b;
  --accent-strong: #1d7a80;  /* white on this: 5.06:1 */
  --danger: #f08a72;         /* 6.31:1 on --bg, 5.72:1 on --bg-panel */
  --danger-strong: #b3391f;  /* white on this: 5.11:1 */
  --border-strong: #67625c;  /* 3.00:1 on --bg, for control boundaries */
  --shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
}

* { margin: 0; padding: 0; box-sizing: border-box; }

body {
  font-family: 'Noto Sans SC', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  background: var(--bg);
  color: var(--text);
  height: 100vh;   /* fallback */
  height: 100dvh;
  overflow: hidden;
}

.hidden { display: none !important; }
a { color: var(--accent); }

/* ============ Buttons ============ */
.btn {
  border: 1px solid var(--border);
  background: var(--bg-panel);
  color: var(--text);
  padding: 10px 18px;
  border-radius: 6px;
  cursor: pointer;
  font-family: inherit;
  font-size: 14px;
  transition: background 0.15s;
}
.btn:hover { background: var(--bg-hover); }
.btn-primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.btn-primary:hover { filter: brightness(1.1); background: var(--accent); }
.btn-ghost { border: none; background: transparent; color: var(--text-dim); }
.btn-ghost:hover { color: var(--text); background: var(--bg-hover); }
.btn-block { width: 100%; }

.icon-btn {
  border: none; background: transparent; color: var(--text-dim);
  font-size: 18px; cursor: pointer; padding: 8px 10px; border-radius: 6px;
  line-height: 1;
}
.icon-btn:hover { background: var(--bg-hover); color: var(--text); }
.tb-dragging {
  opacity: 0.55;
  background: var(--bg-hover);
  outline: 2px dashed var(--text-dim);
  outline-offset: -2px;
}
.icon-btn.danger:hover { color: var(--danger); } /* was var(--accent) -- the destructive button turned BRAND TEAL on hover */

/* Kill double-tap zoom / 300ms delay on interactive elements (no visual change) */
.btn, .icon-btn, .folder-item, .account-btn, .account-menu-item,
.smart-tab, .ai-chip, .ai-reply, .email-item, .smart-item, .attachment-chip,
input, select, [contenteditable] { touch-action: manipulation; }

/* ============ Login ============ */
.login-page {
  height: 100vh; height: 100dvh; display: flex; align-items: center; justify-content: center;
  background:
    radial-gradient(circle at 20% 20%, var(--accent-soft), transparent 40%),
    var(--bg);
}
.login-card {
  background: var(--bg-panel); border: 1px solid var(--border);
  border-radius: 10px; padding: 48px 40px; width: 340px; text-align: center;
  box-shadow: var(--shadow);
}
/* The signed-out screens showed a serif "Q" in a teal tile -- the brand this
   app retired -- so sign-in, setup and password-reset, i.e. every first
   impression, were the only places still wearing it. They now use the same
   mark as the sidebar. The Noto Serif SC webfont was downloaded solely to
   render that one letter and has been dropped from the font request. */
.login-mark { display: block; width: 56px; height: 56px; margin: 0 auto 16px; }
.login-card h1 { font-size: 22px; font-weight: 700; }
.login-sub { color: var(--text-dim); font-size: 13px; margin: 4px 0 24px; }
.login-card input {
  width: 100%; padding: 12px 14px; margin-bottom: 12px;
  border: 1px solid var(--border); border-radius: 6px;
  background: var(--bg); color: var(--text); font-family: inherit; font-size: 14px;
}
.login-error { color: var(--accent); font-size: 13px; margin-top: 10px; }
.login-note { color: var(--text-dim); font-size: 12px; line-height: 1.5; margin-top: 14px; }

/* --- sign in / create account --- */
.auth-tabs {
  display: flex; gap: 4px; margin-bottom: 18px; padding: 4px;
  background: var(--bg); border: 1px solid var(--border); border-radius: 8px;
}
.auth-tab {
  flex: 1; padding: 8px 6px; border: none; border-radius: 6px; cursor: pointer;
  background: transparent; color: var(--text-dim);
  font-family: inherit; font-size: 13px; transition: background 0.15s, color 0.15s;
}
.auth-tab.is-on { background: var(--bg-panel); color: var(--text); box-shadow: var(--shadow); }
.auth-alt {
  display: block; width: 100%; margin-top: 14px; padding: 6px;
  background: none; border: none; cursor: pointer;
  color: var(--text-dim); font-family: inherit; font-size: 12px; text-decoration: underline;
}
.auth-alt:hover { color: var(--text); }

/* --- provider picker --- */
.setup-card { width: min(460px, 92vw); padding: 40px 28px 28px; }
.provider-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(116px, 1fr));
  gap: 8px; margin: 6px 0 4px; text-align: left;
}
.provider-tile {
  display: flex; align-items: center; gap: 9px; padding: 10px 10px;
  background: var(--bg); border: 1px solid var(--border); border-radius: 10px;
  cursor: pointer; color: var(--text); font-family: inherit; font-size: 13px;
  transition: transform 0.12s, border-color 0.15s, background 0.15s;
}
.provider-tile:hover { background: var(--bg-hover); border-color: var(--accent); transform: translateY(-1px); }
.provider-tile:active { transform: scale(0.97); }
.pv-badge {
  flex: none; width: 26px; height: 26px; border-radius: 6px;
  display: grid; place-items: center; color: #fff; font-weight: 700; font-size: 13px;
}
.pv-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.provider-modal { width: min(430px, 94vw); }
.provider-body { padding: 16px 18px 18px; }
.pv-help {
  background: var(--bg); border: 1px solid var(--border); border-left: 3px solid var(--accent);
  border-radius: 6px; padding: 10px 12px; margin-bottom: 10px;
  font-size: 13px; line-height: 1.55; color: var(--text-dim);
}
.pv-link { display: inline-block; font-size: 13px; margin-bottom: 12px; }
.acc-hint { color: var(--text-dim); font-size: 12px; margin-bottom: 8px; }

/* ============ Layout ============ */
.app { display: flex; height: 100vh; height: 100dvh; overflow: hidden; }

/* Dimmed backdrop behind the mobile sidebar drawer (hidden on desktop) */
.sidebar-backdrop { display: none; }

.sidebar {
  width: 240px; flex-shrink: 0; display: flex; flex-direction: column;
  background: var(--bg-panel); border-right: 1px solid var(--border);
  padding: 16px 14px; gap: 18px;
  overflow-y: auto; min-height: 0;
}
.sidebar-header { display: flex; align-items: center; gap: 10px; }
.logo-seal {
  font-family: 'Noto Serif SC', serif;
  width: 34px; height: 34px; line-height: 34px; text-align: center;
  background: var(--accent); color: #fff; font-size: 19px; border-radius: 6px;
}
.logo-text { font-weight: 700; font-size: 16px; flex: 1; }
.sidebar-close { display: none; }

.compose-btn { padding: 12px; font-weight: 500; }

.sidebar-section { display: flex; flex-direction: column; gap: 6px; }
.sidebar-label {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--text-dim);
}
.sort-select {
  padding: 9px 10px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--bg); color: var(--text); font-family: inherit; font-size: 13px;
  max-width: 100%;
}

/* Floating account menu */
.account-picker { position: relative; }
.account-btn {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 9px 10px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--bg); color: var(--text); font-family: inherit; font-size: 13px;
  cursor: pointer; text-align: left;
}
.account-btn:hover { background: var(--bg-hover); }
.account-btn .acc-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.acc-caret { color: var(--text-dim); font-size: 11px; }
.acc-dot { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; }
.account-menu {
  position: absolute; top: calc(100% + 6px); left: 0; right: -60px; z-index: 60;
  background: var(--bg-panel); border: 1px solid var(--border); border-radius: 10px;
  box-shadow: var(--shadow); padding: 6px; display: flex; flex-direction: column; gap: 2px;
  max-height: 60vh; overflow-y: auto; -webkit-overflow-scrolling: touch;
  max-width: calc(100vw - 24px);
}
.account-menu-item {
  display: flex; align-items: center; gap: 9px; width: 100%;
  border: none; background: transparent; color: var(--text);
  padding: 9px 10px; border-radius: 6px; cursor: pointer;
  font-family: inherit; font-size: 13px; text-align: left;
}
.account-menu-item:hover { background: var(--bg-hover); }
.account-menu-item.active { background: var(--accent-soft); color: var(--accent); font-weight: 500; }
.account-menu-item .acc-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.acc-check { color: var(--accent); }

.ei-account {
  display: inline-block; font-size: 11px; border: 1px solid;
  border-radius: 10px; padding: 0 8px; margin-right: 6px; line-height: 16px;
}
.ei-brand { font-weight: 600; }
.ei-fav {
  width: 16px; height: 16px; border-radius: 4px;
  vertical-align: -3px; margin-right: 7px;
  background: var(--bg-hover);
}

.folder-list { list-style: none; display: flex; flex-direction: column; gap: 2px; }
.folder-item {
  display: flex; width: 100%; text-align: left; gap: 8px; align-items: center;
  border: none; background: transparent; color: var(--text);
  padding: 8px 10px; border-radius: 6px; cursor: pointer;
  font-family: inherit; font-size: 14px;
}
.folder-item:hover { background: var(--bg-hover); }
.folder-item.active { background: var(--accent-soft); color: var(--accent); font-weight: 500; }

.sidebar-footer {
  margin-top: auto; display: flex; justify-content: space-around;
  border-top: 1px solid var(--border); padding-top: 12px;
}

/* ============ Main ============ */
.main { flex: 1; display: flex; flex-direction: column; min-width: 0; }

.topbar {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 18px; border-bottom: 1px solid var(--border);
  background: var(--bg-panel);
  flex-wrap: wrap; row-gap: 6px; flex-shrink: 0;
}
.menu-btn { display: none; }
.searchbar {
  flex: 1; display: flex; align-items: center;
  background: var(--bg); border: 1px solid var(--border); border-radius: 8px;
  padding: 0 4px 0 12px; max-width: 520px;
}
.searchbar input {
  flex: 1; border: none; background: transparent; color: var(--text);
  padding: 10px 0; font-family: inherit; font-size: 14px; outline: none;
}
@media (max-width: 900px) {
  .topbar { flex-wrap: wrap; row-gap: 6px; }
}

/* Enable-notifications banner (shown until the device is subscribed or dismissed) */
.push-banner {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 14px; font-size: 13px;
  background: color-mix(in srgb, var(--accent) 12%, var(--bg-panel));
  border-bottom: 1px solid var(--border); color: var(--text);
}
.push-banner .btn { padding: 5px 12px; font-size: 13px; }
#btn-push.push-off { opacity: 0.55; }

/* Calendar: Month / Agenda tabs + agenda list */
.cal-tabs { display: flex; gap: 4px; background: var(--bg); border: 1px solid var(--border); border-radius: 8px; padding: 3px; }
.cal-tab { border: none; background: transparent; color: var(--text-dim); padding: 5px 14px; border-radius: 6px; cursor: pointer; font-family: inherit; font-size: 13px; font-weight: 600; }
.cal-tab.active { background: var(--accent); color: #fff; }
.cal-agenda { display: flex; flex-direction: column; gap: 14px; padding: 4px 2px 24px; overflow-y: auto; }
.ag-day { border: 1px solid var(--border); border-radius: 10px; padding: 10px 12px; background: var(--bg-panel); }
.ag-day.ag-today { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.ag-day.ag-past { opacity: 0.75; }
.ag-date { font-weight: 700; font-size: 13px; margin-bottom: 8px; display: flex; align-items: center; gap: 8px; }
.ag-count { background: var(--accent); color: #fff; border-radius: 10px; padding: 1px 8px; font-size: 12px; font-weight: 700; }

/* Booking.com per-email tags */
.bk-tag {
  display: inline-block; font-size: 11px; font-weight: 700;
  color: var(--bt); border: 1px solid var(--bt); border-radius: 10px;
  padding: 1px 7px; background: color-mix(in srgb, var(--bt) 10%, transparent);
  vertical-align: 1px;
}
.push-banner .pb-close { margin-left: auto; }

.ic { vertical-align: -3px; margin-right: 2px; flex-shrink: 0; }
.folder-item .ic { margin-right: 4px; }
.smart-fab svg { display: block; margin: auto; }

.content { flex: 1; display: flex; min-height: 0; }
.content.single { align-items: center; justify-content: center; }

/* ============ Email list ============ */
.email-list-pane {
  width: 400px; flex-shrink: 0; display: flex; flex-direction: column;
  border-right: 1px solid var(--border); background: var(--bg-panel);
  min-height: 0;
}
.list-toolbar {
  display: flex; align-items: baseline; gap: 8px;
  padding: 14px 18px 10px; border-bottom: 1px solid var(--border);
}
.list-title { font-weight: 700; font-size: 16px; }
.list-count { color: var(--text-dim); font-size: 12px; }

.email-list {
  list-style: none; overflow-y: auto; flex: 1;
  -webkit-overflow-scrolling: touch; overscroll-behavior: contain;
}
/* smooth deep scrolling: off-screen rows skip layout/paint entirely, so a
   1,000-row list scrolls like a 20-row one */
/* contain-intrinsic-size is the height reported for rows that are SKIPPED by
   content-visibility — it is a scroll-height estimate, not layout. Worth being
   explicit about, because it is what makes this row hard to measure: querying
   an off-screen .email-item returns this number and not the real height. A
   rendered two-line row measures 66px, so 66px is the honest estimate; raising
   it only inflates the scrollbar. */
.email-item { content-visibility: auto; contain-intrinsic-size: auto 66px; }
button, .email-item { -webkit-tap-highlight-color: transparent; }

/* desktop hover quick-actions: read/archive/delete straight from the row */
.row-quick { display: none; }
@media (hover: hover) and (min-width: 641px) {
  .row-quick {
    position: absolute; right: 46px; top: 50%; transform: translateY(-50%);
    display: flex; gap: 2px; opacity: 0;
    background: var(--bg-panel); border-radius: 8px; padding: 2px;
    transition: opacity 0.12s;
  }
  .email-item:hover .row-quick { opacity: 1; }
  .row-quick button {
    border: none; background: transparent; color: var(--text-dim);
    padding: 6px 7px; border-radius: 6px; cursor: pointer;
  }
  .row-quick button:hover { background: var(--bg-hover); color: var(--text); }
  .row-quick button:last-child:hover { color: var(--accent); }
}

/* desktop reading column: comfortable line lengths, not wall-to-wall text */
@media (min-width: 900px) {
  .viewer-body { max-width: 920px; margin: 0 auto; }
  .email-item { padding-top: 9px; padding-bottom: 9px; }
}
.email-item {
  padding: 12px 18px; border-bottom: 1px solid var(--border);
  cursor: pointer; display: flex; flex-direction: column; gap: 3px;
}
.email-item:hover { background: var(--bg-hover); }
.email-item.selected { background: var(--bg-active); }
.email-item.unread .ei-from, .email-item.unread .ei-subject { font-weight: 700; }
.ei-top { display: flex; justify-content: space-between; gap: 10px; }
.ei-from { font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ei-date { font-size: 12px; color: var(--text-dim); flex-shrink: 0; }
.ei-subject { font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ei-badges { font-size: 12px; color: var(--accent); }
.email-empty { padding: 40px 20px; text-align: center; color: var(--text-dim); }
.list-sep {
  padding: 7px 18px 5px; font-size: 11px; font-weight: 700; letter-spacing: 0.07em;
  text-transform: uppercase; color: var(--text-dim); background: var(--bg);
  border-bottom: 1px solid var(--border);
}

/* Block the browser's own horizontal-swipe history navigation — the system
   back gesture is handled in-app (popstate closes viewer/compose/sidebar) */
html, body { overscroll-behavior-x: none; }
.email-list, .viewer-body { touch-action: pan-y; }

/* undo-send hold bar */
.undo-bar {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(18px + env(safe-area-inset-bottom, 0px)); z-index: 95;
  display: flex; align-items: center; gap: 14px;
  background: var(--text); color: var(--bg);
  padding: 10px 12px 10px 18px; border-radius: 10px;
  font-size: 13px; font-weight: 600;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.35);
  animation: sheetUp 0.2s ease;
}
.undo-bar .ub-undo {
  background: var(--accent); color: #fff; border: none;
  padding: 7px 16px; border-radius: 8px; font-weight: 700; cursor: pointer;
  min-height: 34px;
}

/* ============ message action sheet ============ */
.sheet-backdrop {
  position: fixed; inset: 0; z-index: 90;
  background: rgba(0, 0, 0, 0.45);
}
.action-sheet {
  position: fixed; z-index: 91;
  left: 0; right: 0; bottom: 0;
  background: var(--bg-panel);
  border-radius: 16px 16px 0 0;
  border: 1px solid var(--border); border-bottom: none;
  padding: 4px 12px calc(10px + env(safe-area-inset-bottom, 0px));
  max-height: 62vh; overflow-y: auto;
  animation: sheetUp 0.22s cubic-bezier(0.2, 0.9, 0.3, 1);
  box-shadow: 0 -8px 32px rgba(0, 0, 0, 0.25);
}
@keyframes sheetUp { from { transform: translateY(45%); opacity: 0.3; } to { transform: none; opacity: 1; } }
.action-sheet { animation-timing-function: cubic-bezier(0.34, 1.25, 0.5, 1); }

/* motion: sheet contents cascade in */
.sheet-quick .sq-btn { animation: sqPop 0.3s cubic-bezier(0.3, 1.4, 0.5, 1) backwards; }
.sheet-quick .sq-btn:nth-child(1) { animation-delay: 0.03s; }
.sheet-quick .sq-btn:nth-child(2) { animation-delay: 0.06s; }
.sheet-quick .sq-btn:nth-child(3) { animation-delay: 0.09s; }
.sheet-quick .sq-btn:nth-child(4) { animation-delay: 0.12s; }
.sheet-quick .sq-btn:nth-child(5) { animation-delay: 0.15s; }
.sheet-quick .sq-btn:nth-child(6) { animation-delay: 0.18s; }
@keyframes sqPop { from { transform: scale(0.7); opacity: 0; } to { transform: scale(1); opacity: 1; } }
.sheet-list .sheet-item { animation: siIn 0.24s ease backwards; }
.sheet-list .sheet-item:nth-child(1) { animation-delay: 0.05s; }
.sheet-list .sheet-item:nth-child(2) { animation-delay: 0.08s; }
.sheet-list .sheet-item:nth-child(3) { animation-delay: 0.11s; }
.sheet-list .sheet-item:nth-child(4) { animation-delay: 0.14s; }
.sheet-list .sheet-item:nth-child(5) { animation-delay: 0.17s; }
.sheet-list .sheet-item:nth-child(6) { animation-delay: 0.2s; }
.sheet-list .sheet-item:nth-child(7) { animation-delay: 0.23s; }
.sheet-list .sheet-item:nth-child(n+8) { animation-delay: 0.26s; }
@keyframes siIn { from { transform: translateY(10px); opacity: 0; } to { transform: none; opacity: 1; } }

/* motion: tactile press feedback + icon life */
.sq-btn, .sheet-item { transition: transform 0.12s ease, background 0.15s; }
.sq-btn:active { transform: scale(0.92); }
.sheet-item:active { transform: scale(0.985); }
.sq-btn .ic { width: 22px; height: 22px; transition: transform 0.15s cubic-bezier(0.3, 1.5, 0.5, 1); }
.sq-btn:hover .ic { transform: translateY(-2px); }
.si-ic .ic { width: 17px; height: 17px; vertical-align: -3px; }

/* motion: swipe cue pops at each action threshold */
.swipe-cue { display: inline-flex; align-items: center; gap: 8px; animation: cuePop 0.25s cubic-bezier(0.3, 1.6, 0.5, 1); }
.swipe-cue .ic { width: 20px; height: 20px; }
@keyframes cuePop { from { transform: scale(0.5); opacity: 0.3; } to { transform: scale(1); opacity: 1; } }
.sheet-handle {
  width: 38px; height: 4px; border-radius: 2px;
  background: var(--border); margin: 4px auto 10px;
}
.sheet-head { margin-bottom: 7px; display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.sheet-head .sheet-from { flex: 0 1 auto; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sheet-head .sheet-subj { flex: 1 1 0; }
.sheet-from { display: block; font-weight: 700; font-size: 13px; }
.sheet-subj {
  display: block; color: var(--text-dim); font-size: 12px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sheet-quick {
  display: flex; gap: 5px; margin-bottom: 8px;
  overflow-x: auto; scrollbar-width: none; padding-bottom: 2px;
}
.sheet-quick::-webkit-scrollbar { display: none; }
.sq-btn {
  flex: 1 0 46px; min-height: 46px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--bg); color: var(--text); cursor: pointer; font-family: inherit;
}
.sq-btn:hover { background: var(--bg-hover); }
.sq-btn.danger { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 40%, var(--border)); }
.sq-ic { font-size: 17px; }
.sq-lb { font-size: 10px; }
/* subtle, compact two-column list — the sheet stays low instead of towering */
.sheet-list { display: grid; grid-template-columns: 1fr 1fr; gap: 1px 8px; }
.sheet-item {
  display: flex; align-items: center; gap: 8px;
  border: none; background: transparent; color: var(--text);
  padding: 6px 4px; min-height: 32px; cursor: pointer;
  font-family: inherit; font-size: 12px; text-align: left;
  border-radius: 6px;
}
.sheet-item:hover { background: var(--bg-hover); }
.sheet-item.danger { color: var(--accent); }
.si-ic { width: 20px; text-align: center; flex: 0 0 auto; }
.si-ic .ic { opacity: 0.85; }
.si-lb { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.si-caret { color: var(--text-dim); }
.mm-ctl { display: flex; align-items: center; gap: 2px; }
.mm-ctl .btn { min-height: 30px; padding: 3px 10px; font-size: 12px; }
.mm-ctl .icon-btn { width: 30px; height: 30px; min-width: 30px; min-height: 30px; font-size: 13px; }
@media (min-width: 641px) {
  /* desktop: same sheet as a centered action dialog */
  .action-sheet {
    left: 50%; right: auto; bottom: auto; top: 50%;
    transform: translate(-50%, -50%);
    width: 400px; border-radius: 16px; border-bottom: 1px solid var(--border);
    max-height: 80vh;
    animation: popIn 0.18s ease;
  }
  .sheet-handle { display: none; }
}

/* visible reply history at the end of the compose view */
.compose-quote-view {
  margin: 4px 14px 10px; padding: 10px 12px;
  border: 1px dashed var(--border); border-radius: 10px;
  max-height: 32vh; overflow: auto; background: var(--bg);
}
.cqv-label {
  font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-dim); margin-bottom: 8px; text-align: center;
}
.cqv-attr { font-size: 12px; color: var(--text-dim); margin-bottom: 6px; }
/* now an <iframe>, not a <blockquote>: the quoted original is untrusted sender
   HTML and renders sandboxed, like it does in the reading view. fitFrame() sets
   the height, so it must not be constrained here. */
.cqv-quote {
  display: block; width: 100%; border: 0; margin: 0;
  border-left: 2px solid var(--border); padding-left: 12px;
  background: transparent;
}

/* compose attachments */
.compose-atts { display: flex; flex-wrap: wrap; gap: 8px; padding: 0 14px; }
.compose-atts:not(:empty) { padding-bottom: 8px; }
.compose-att-chip {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--border); border-radius: 16px;
  padding: 4px 6px 4px 12px; font-size: 13px; background: var(--bg);
}
.compose-att-chip i { color: var(--text-dim); font-style: normal; font-size: 11px; }
.compose-att-chip .ca-x {
  border: none; background: transparent; color: var(--text-dim);
  cursor: pointer; font-size: 15px; padding: 0 4px; border-radius: 50%;
}
.compose-att-chip .ca-x:hover { color: var(--accent); }

/* conversation threading */
.tcount {
  display: inline-block; margin-left: 6px; padding: 0 7px;
  border-radius: 10px; font-size: 11px; font-weight: 700;
  background: var(--bg-hover); color: var(--text-dim);
  border: 1px solid var(--border); vertical-align: 1px;
}
.email-item.unread .tcount { color: var(--accent); border-color: var(--accent); }
.thread-note { color: var(--text-dim); font-size: 13px; margin: 4px 0 14px; }
.thread-card {
  border: 1px solid var(--border); border-radius: 10px;
  margin-bottom: 10px; background: var(--bg-panel); overflow: hidden;
}
.thread-card.unread { border-left: 3px solid var(--accent); }
.tc-head {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; cursor: pointer;
}
.tc-head:hover { background: var(--bg-hover); }
.tc-avatar {
  width: 30px; height: 30px; border-radius: 50%; flex: 0 0 auto;
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-weight: 700; font-size: 14px;
}
.tc-from { font-weight: 600; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.thread-card.unread .tc-from { font-weight: 700; }
.tc-date { color: var(--text-dim); font-size: 12px; flex: 0 0 auto; }
.tc-body { padding: 0 12px 10px; }
.tc-actions { padding: 0 12px 10px; }
.tc-actions .btn { min-height: 32px; padding: 4px 12px; font-size: 13px; }
.tc-atts { margin-top: 8px; color: var(--text-dim); font-size: 13px; }

.app-version {
  margin-left: auto; align-self: center;
  font-size: 11px; color: var(--text-dim); letter-spacing: 0.04em;
}

/* swipe actions on message rows (touch) */
.email-list { position: relative; }
.email-item.swiping {
  position: relative; z-index: 1;
  background: var(--bg-panel);
  will-change: transform;
}
.swipe-bg {
  position: absolute; left: 0; right: 0; z-index: 0;
  display: flex; align-items: center; padding: 0 18px;
  color: #fff; font-weight: 700; font-size: 13px;
  white-space: nowrap; overflow: hidden;
}
.swipe-bg[data-dir="left"] { justify-content: flex-end; }
.swipe-manage .swipe-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; padding: 6px 0;
}
.swipe-manage .swipe-row-label { font-size: 13px; color: var(--text-dim); }
.swipe-manage select {
  background: var(--bg); color: var(--text); border: 1px solid var(--border);
  border-radius: 8px; padding: 8px 10px; font-family: inherit; font-size: 13px;
  max-width: 55%;
}

/* remote-image tracking-protection banner in the viewer */
.img-banner {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 10px 0; padding: 8px 12px; font-size: 13px;
  border: 1px solid var(--border); border-radius: 10px;
  background: var(--bg-panel); color: var(--text-dim);
}
.img-banner .btn { min-height: 32px; padding: 4px 12px; font-size: 13px; }

/* infinite-scroll sentinel: invisible trigger zone at the list bottom;
   shows a quiet "Loading older emails…" line while the next batch fetches */
.scroll-sentinel {
  text-align: center; color: var(--text-dim); font-size: 12px;
  padding: 8px 0 calc(12px + env(safe-area-inset-bottom, 0px));
}
.scroll-sentinel:empty { display: none; }

/* ============ Viewer ============ */
.email-viewer-pane { flex: 1; display: flex; flex-direction: column; min-width: 0; }
.viewer-toolbar {
  display: flex; align-items: center; gap: 4px;
  padding: 10px 16px; border-bottom: 1px solid var(--border); background: var(--bg-panel);
}
.spacer { flex: 1; }
.tb-sep { width: 1px; height: 20px; background: var(--border); margin: 0 4px; }
.tb-label { font-size: 13px; margin-left: 4px; }
#btn-pin.pinned { color: var(--accent); background: var(--accent-soft); }
.more-wrap { position: relative; }
.more-menu { left: auto; right: 0; top: calc(100% + 6px); min-width: 230px; transform-origin: top right; }

/* AI-native message tools */
.ai-bar { display: flex; gap: 8px; margin-bottom: 14px; flex-wrap: wrap; }
.ai-chip {
  border: 1px solid var(--border); background: var(--bg-panel); color: var(--text);
  padding: 7px 14px; border-radius: 16px; cursor: pointer;
  font-family: inherit; font-size: 13px; font-weight: 500;
  transition: all 0.15s cubic-bezier(0.2, 0.9, 0.3, 1.2);
}
.ai-chip:hover {
  border-color: var(--accent); color: var(--accent);
  background: var(--accent-soft); transform: translateY(-1px);
}
.ai-ask { display: flex; gap: 8px; margin-bottom: 14px; }
.ai-ask input {
  flex: 1; padding: 10px 14px; border: 1px solid var(--border); border-radius: 16px;
  background: var(--bg-panel); color: var(--text); font-family: inherit; font-size: 13px;
  outline: none; transition: border-color 0.15s;
}
.ai-ask input:focus { border-color: var(--accent); }
.ai-ask-btn { border-radius: 16px; padding: 8px 20px; }
.ai-answer { font-size: 13px; line-height: 1.6; }

.ai-out {
  border: 1px solid var(--border); border-left: 3px solid var(--accent);
  border-radius: 10px; padding: 12px 16px; margin-bottom: 16px;
  background: var(--bg-panel); animation: fadeUp 0.3s ease;
}
.ai-out-title {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--accent); font-weight: 700; margin-bottom: 8px;
}
.ai-point { font-size: 13px; line-height: 1.55; margin-bottom: 4px; }
.ai-reply {
  display: block; width: 100%; text-align: left; margin-bottom: 6px;
  border: 1px solid var(--border); background: var(--bg); color: var(--text);
  padding: 9px 13px; border-radius: 8px; cursor: pointer;
  font-family: inherit; font-size: 13px; transition: all 0.15s;
}
.ai-reply:hover { border-color: var(--accent); background: var(--accent-soft); transform: translateX(3px); }
.viewer-body { flex: 1; overflow-y: auto; overflow-x: hidden; padding: 24px 32px; -webkit-overflow-scrolling: touch; }
.viewer-body img { max-width: 100%; height: auto; }
.viewer-subject { font-size: 21px; font-weight: 700; margin-bottom: 14px; }
.viewer-meta {
  display: flex; align-items: center; gap: 12px; margin-bottom: 20px;
  padding-bottom: 16px; border-bottom: 1px solid var(--border);
}
.viewer-avatar {
  width: 42px; height: 42px; border-radius: 50%; flex-shrink: 0;
  background: var(--accent); color: #fff; display: flex;
  align-items: center; justify-content: center; font-weight: 700; font-size: 17px;
}
.viewer-from { font-weight: 500; font-size: 14px; }
.viewer-detail { color: var(--text-dim); font-size: 12px; }
.viewer-html-frame { width: 100%; max-width: 100%; border: none; }
/* the message area itself never scrolls sideways — wide content is scaled to fit */
#viewer-content, .tc-body, .viewer-body { overflow-x: hidden; }
.viewer-text { white-space: pre-wrap; font-size: 14px; line-height: 1.6; }
.viewer-attachments { margin-top: 24px; display: flex; flex-wrap: wrap; gap: 8px; }
.attachment-chip {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--border); border-radius: 20px; padding: 6px 14px;
  font-size: 13px; text-decoration: none; color: var(--text); background: var(--bg-panel);
}
.attachment-chip:hover { background: var(--bg-hover); }

/* ============ Compose ============ */
.modal-backdrop {
  position: fixed; inset: 0; background: rgba(0,0,0,0.45);
  display: flex; align-items: center; justify-content: center; z-index: 50;
}
.modal {
  background: var(--bg-panel); border-radius: 10px; box-shadow: var(--shadow);
  width: min(680px, 94vw); max-height: 90vh; display: flex; flex-direction: column;
}
.modal-header {
  display: flex; justify-content: space-between; align-items: center;
  padding: 14px 20px; border-bottom: 1px solid var(--border); font-weight: 700;
}
.compose-form { display: flex; flex-direction: column; overflow: hidden; }
.compose-row {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 20px; border-bottom: 1px solid var(--border);
}
.compose-row label { width: 56px; color: var(--text-dim); font-size: 13px; flex-shrink: 0; }
.compose-row input, .compose-row select {
  flex: 1; border: none; background: transparent; color: var(--text);
  font-family: inherit; font-size: 14px; outline: none; padding: 6px 0;
}
.compose-body {
  min-height: 220px; max-height: 44vh; overflow-y: auto;
  padding: 16px 20px; font-size: 14px; line-height: 1.6; outline: none;
}
.compose-footer {
  display: flex; align-items: center; gap: 14px;
  padding: 12px 20px; border-top: 1px solid var(--border);
}
.compose-status { color: var(--text-dim); font-size: 13px; }
.later-wrap { position: relative; }
.later-pop { top: auto; bottom: calc(100% + 6px); left: 0; right: auto; min-width: 230px; transform-origin: bottom left; }
.later-custom { display: flex; gap: 6px; padding: 8px 10px; border-top: 1px solid var(--border); }
.later-custom input {
  flex: 1; padding: 7px 8px; border: 1px solid var(--border); border-radius: 6px;
  background: var(--bg); color: var(--text); font-family: inherit; font-size: 13px;
}
.later-custom .btn { padding: 6px 12px; }
.fu-label {
  display: flex; align-items: center; gap: 6px;
  font-size: 13px; color: var(--text-dim); cursor: pointer; white-space: nowrap;
}

/* ============ Misc ============ */
.placeholder-view { text-align: center; color: var(--text-dim); max-width: 380px; padding: 20px; }
.placeholder-glyph { font-size: 52px; margin-bottom: 12px; }
.placeholder-view h2 { color: var(--text); margin-bottom: 8px; }

/* ============ Smart Inbox ============ */
.smart-fab {
  position: fixed; right: 26px; bottom: calc(26px + env(safe-area-inset-bottom, 0px)); z-index: 45;
  width: 56px; height: 56px; border-radius: 50%; border: none; cursor: pointer;
  font-size: 24px; color: #fff;
  background: linear-gradient(135deg, var(--accent), var(--accent-strong));
  box-shadow: 0 4px 20px color-mix(in srgb, var(--accent) 45%, transparent);
  transition: transform 0.18s cubic-bezier(0.2, 0.9, 0.3, 1.4), box-shadow 0.2s;
}
.smart-fab:hover { transform: translateY(-3px) scale(1.06); box-shadow: 0 8px 28px color-mix(in srgb, var(--accent) 60%, transparent); }
.smart-fab:active { transform: scale(0.94); }

.smart-panel {
  position: fixed; right: 26px; bottom: 94px; z-index: 46;
  width: min(400px, calc(100vw - 40px));
  background: var(--bg-panel); border: 1px solid var(--border); border-radius: 16px;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
  display: flex; flex-direction: column; max-height: 65vh;
  animation: popIn 0.25s cubic-bezier(0.2, 0.9, 0.3, 1.2); transform-origin: bottom right;
}
.smart-head {
  display: flex; justify-content: space-between; align-items: center;
  padding: 13px 16px; border-bottom: 1px solid var(--border); font-weight: 700;
}
.smart-tabs { display: flex; gap: 4px; padding: 8px 12px; border-bottom: 1px solid var(--border); }
.smart-tab {
  flex: 1; border: 1px solid var(--border); background: transparent; color: var(--text-dim);
  padding: 7px 6px; border-radius: 8px; cursor: pointer; font-family: inherit; font-size: 13px;
  transition: all 0.15s;
}
.smart-tab.active { background: var(--accent-soft); color: var(--accent); border-color: var(--accent); font-weight: 600; }
.smart-count {
  display: inline-block; background: var(--accent); color: #fff; border-radius: 10px;
  font-size: 11px; padding: 0 6px; margin-left: 3px;
}
.smart-list { overflow-y: auto; flex: 1; padding: 6px; -webkit-overflow-scrolling: touch; }
.smart-item {
  display: flex; align-items: center; gap: 6px; padding: 10px 10px;
  border-radius: 10px; cursor: pointer; animation: fadeUp 0.3s ease backwards;
  transition: background 0.15s, transform 0.15s;
}
.smart-item:hover { background: var(--bg-hover); transform: translateX(3px); }
.smart-item-main { flex: 1; min-width: 0; }
.smart-item-subject {
  font-size: 13px; font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.smart-item-meta {
  display: flex; align-items: center; gap: 8px; margin-top: 3px;
  font-size: 11px; color: var(--text-dim);
  overflow: hidden; white-space: nowrap;
}
.smart-due { color: var(--accent); font-weight: 600; }
.smart-foot {
  display: flex; justify-content: space-between; padding: 8px 12px;
  border-top: 1px solid var(--border);
}
.compose-quote-note { color: var(--text-dim); font-size: 12px; margin-left: auto; }

/* Manage accounts */
.accounts-body { padding: 6px 0 0; overflow-y: auto; }
.accounts-list { list-style: none; margin: 0 0 6px; }
.accounts-row {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 20px; border-bottom: 1px solid var(--border); font-size: 13px;
}
.accounts-row .acc-label { flex: 1; overflow: hidden; text-overflow: ellipsis; }
.account-add-form .btn-ghost { margin: 6px 20px 0; font-size: 13px; }
.acc-advanced { border-top: 1px dashed var(--border); margin-top: 6px; }

.toast {
  position: fixed; bottom: calc(28px + env(safe-area-inset-bottom, 0px)); left: 50%; transform: translateX(-50%);
  background: var(--text); color: var(--bg); padding: 11px 22px;
  border-radius: 8px; font-size: 14px; z-index: 100; box-shadow: var(--shadow);
  max-width: calc(100vw - 32px); width: max-content;
}

/* ============ Motion ============ */
@keyframes fadeUp {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: none; }
}
@keyframes slideInRight {
  from { opacity: 0; transform: translateX(28px); }
  to   { opacity: 1; transform: none; }
}
@keyframes popIn {
  from { opacity: 0; transform: scale(0.94) translateY(8px); }
  to   { opacity: 1; transform: none; }
}
@keyframes glowShift {
  0%   { background-position: 0% 50%; }
  50%  { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}
@keyframes sealPulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 45%, transparent); }
  50%      { box-shadow: 0 0 24px 4px color-mix(in srgb, var(--accent) 25%, transparent); }
}

.login-page {
  background-image:
    radial-gradient(circle at 18% 22%, var(--accent-soft), transparent 42%),
    radial-gradient(circle at 82% 78%, var(--accent-soft), transparent 42%);
  background-size: 180% 180%;
  animation: glowShift 16s ease infinite;
}
.login-card { animation: popIn 0.5s cubic-bezier(0.2, 0.9, 0.3, 1.15) backwards; }
.login-mark { animation: sealPulse 4s ease infinite; border-radius: 10px; }

.email-item {
  animation: fadeUp 0.35s ease backwards;
  transition: background 0.15s, transform 0.18s cubic-bezier(0.2, 0.9, 0.3, 1.2), box-shadow 0.2s;
  border-left: 2px solid transparent;
}
.email-item:hover { transform: translateX(5px); border-left-color: var(--accent); }
.email-item { position: relative; }
.row-more {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  border: 1px solid var(--border); background: var(--bg-panel); color: var(--text-dim);
  border-radius: 8px; padding: 7px 9px; cursor: pointer; opacity: 0;
  transition: opacity 0.15s, background 0.15s, color 0.15s;
}
.email-item:hover .row-more { opacity: 1; }
.row-more:hover { background: var(--bg-hover); color: var(--text); }
@media (hover: none) { .row-more { opacity: 1; border: none; background: transparent; } }
.row-menu { position: fixed; z-index: 80; min-width: 210px; top: auto; left: auto; right: auto; }
.email-item.selected { border-left-color: var(--accent); }

.email-viewer-pane { animation: slideInRight 0.32s cubic-bezier(0.2, 0.9, 0.3, 1.1); }
.viewer-avatar { animation: popIn 0.4s cubic-bezier(0.2, 0.9, 0.3, 1.25) backwards; animation-delay: 0.08s; }
.viewer-subject { animation: fadeUp 0.35s ease backwards; }
.viewer-meta { animation: fadeUp 0.35s ease backwards; animation-delay: 0.05s; }
#viewer-content { animation: fadeUp 0.4s ease backwards; animation-delay: 0.1s; }

.modal-backdrop { animation: fadeUp 0.2s ease; backdrop-filter: blur(3px); }
.modal { animation: popIn 0.32s cubic-bezier(0.2, 0.9, 0.3, 1.2); }
.account-menu { animation: popIn 0.2s cubic-bezier(0.2, 0.9, 0.3, 1.2); transform-origin: top left; }
.toast { animation: fadeUp 0.3s cubic-bezier(0.2, 0.9, 0.3, 1.2); }

.btn, .icon-btn, .folder-item, .account-btn, .account-menu-item {
  transition: background 0.15s, color 0.15s, transform 0.12s, box-shadow 0.2s;
}
.btn:active, .icon-btn:active, .folder-item:active, .account-menu-item:active { transform: scale(0.95); }
.icon-btn:hover { transform: translateY(-1px); }
.folder-item:hover { transform: translateX(3px); }
.btn-primary { box-shadow: 0 2px 10px color-mix(in srgb, var(--accent) 25%, transparent); }
.btn-primary:hover { box-shadow: 0 4px 18px color-mix(in srgb, var(--accent) 45%, transparent); transform: translateY(-1px); }
.compose-btn:hover { transform: translateY(-2px); }
.attachment-chip { transition: transform 0.15s, background 0.15s; }
.attachment-chip:hover { transform: translateY(-2px); }
.sidebar { transition: transform 0.25s cubic-bezier(0.2, 0.9, 0.3, 1.05); }

:root[data-theme="dark"] .email-list-pane,
:root[data-theme="dark"] .sidebar,
:root[data-theme="dark"] .topbar {
  background: linear-gradient(180deg, var(--bg-panel), color-mix(in srgb, var(--bg-panel) 92%, black));
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* ============ Responsive ============ */
/* Tablet: list pane and viewer share space */
@media (max-width: 1024px) {
  .email-list-pane { width: 340px; }
}
@media (min-width: 641px) and (max-width: 860px) {
  .email-list-pane { width: 320px; }
}

/* Phone */
@media (max-width: 640px) {
  /* --- Sidebar: off-canvas drawer + dimmed backdrop --- */
  .sidebar {
    position: fixed; inset: 0 auto 0 0; z-index: 40; transform: translateX(-100%);
    transition: transform 0.22s cubic-bezier(0.3, 1, 0.4, 1); width: min(48vw, 200px);
    padding: 6px 8px;
    overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain;
    padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  }
  .sidebar.open { transform: translateX(0); box-shadow: 8px 0 32px rgba(0, 0, 0, 0.28); }
  /* minimal drawer: navigation only — composing lives on the ✏ FAB */
  .sidebar .compose-btn { display: none; }
  .sidebar .folder-item, .sidebar .account-menu-item { min-height: 38px; font-size: 13px; }
  .sidebar .sidebar-label { font-size: 10px; margin-bottom: 2px; }
  .sidebar .apps-manage-btn { font-size: 12px; padding: 6px 8px; min-height: 34px; }
  .sidebar .sidebar-section { margin-bottom: 8px; }
  .sidebar .sidebar-header { margin-bottom: 6px; }
  .sidebar-close { display: block; }
  .sidebar-backdrop {
    display: block; position: fixed; inset: 0; z-index: 39;
    background: rgba(0, 0, 0, 0.45); opacity: 0; pointer-events: none;
    transition: opacity 0.2s ease;
  }
  .sidebar.open + .sidebar-backdrop { opacity: 1; pointer-events: auto; }
  /* keep the account dropdown inside the drawer / viewport */
  .account-picker .account-menu { left: 0; right: 0; }

  /* --- Topbar: hamburger + search fit --- */
  .menu-btn { display: block; }
  .sort-select { flex: 0 1 auto; min-width: 0; max-width: 44vw; font-size: 12px; padding: 8px 6px; }
  .topbar { gap: 8px; padding: 10px 10px; }
  .searchbar { max-width: none; min-width: 0; }

  /* --- Touch targets (>=44px) --- */
  .icon-btn {
    min-width: 44px; min-height: 44px;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .btn { min-height: 44px; }
  .folder-item, .account-btn, .account-menu-item { min-height: 44px; }
  .smart-tab { min-height: 44px; }
  .ai-chip, .ai-reply, .attachment-chip { min-height: 40px; }

  /* --- iOS: 16px inputs prevent zoom-on-focus --- */
  .login-card input, .searchbar input,
  .compose-row input, .compose-row select, .compose-body { font-size: 16px; }

  /* --- List pane fills width; viewer replaces it --- */
  .email-list-pane { width: 100%; border-right: none; }
  .content.viewing .email-list-pane { display: none; }
  /* reserve room so the FAB never covers the "Older" pager button */
  .scroll-sentinel { padding-right: 84px; } /* keep the FAB clear of the loading line */

  /* --- Viewer toolbar: wraps gracefully, .more-wrap dropdown intact --- */
  .viewer-toolbar { flex-wrap: wrap; gap: 2px; padding: 4px 8px; }
  .tb-sep { display: none; }
  .more-menu { max-width: calc(100vw - 16px); }
  .viewer-body { padding: 16px 14px; }
  .viewer-subject { font-size: 18px; }

  /* --- Compose: full-screen sheet --- */
  .modal-backdrop { align-items: stretch; justify-content: stretch; }
  .modal {
    width: 100%; max-width: 100%; border-radius: 0;
    height: 100vh; height: 100dvh; max-height: none;
  }
  .modal-header { padding-top: calc(14px + env(safe-area-inset-top, 0px)); }
  .compose-form { flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; }
  .compose-row { padding: 8px 14px; }
  .compose-body { max-height: none; min-height: 45vh; padding: 14px; }
  .compose-footer {
    position: sticky; bottom: 0; margin-top: auto; background: var(--bg-panel);
    padding: 12px 14px calc(12px + env(safe-area-inset-bottom, 0px));
  }

  /* --- Smart Inbox: bottom sheet + FAB clear of edges --- */
  .smart-fab {
    right: 14px; bottom: calc(14px + env(safe-area-inset-bottom, 0px));
    width: 52px; height: 52px;
  }
  .smart-panel {
    left: 0; right: 0; bottom: 0; width: 100%;
    border-radius: 16px 16px 0 0;
    border-left: none; border-right: none; border-bottom: none;
    max-height: 80vh; max-height: 80dvh;
    transform-origin: bottom center;
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }

  /* toast sits above the FAB */
  .toast { bottom: calc(82px + env(safe-area-inset-bottom, 0px)); }
}

/* Very narrow phones */
@media (max-width: 400px) {
  .tb-label { display: none; }
  .topbar { padding: 8px 6px; gap: 6px; }
  .viewer-toolbar .icon-btn.tb { min-width: 40px; }
  .login-card { padding: 36px 24px; width: min(340px, calc(100vw - 32px)); }
}

/* ============ Calendar ============ */
.cal-wrap {
  height: 100%;
  display: flex;
  flex-direction: column;
  padding: 18px 22px;
  overflow-y: auto;
  animation: fadeUp 0.35s ease both;
}
.cal-header {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 10px;
}
.cal-header h2 { flex: 1; font-size: 20px; font-weight: 600; }
.cal-nav { display: flex; align-items: center; gap: 4px; }
.cal-nav .icon-btn { font-size: 20px; width: 34px; height: 34px; }
.cal-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  font-size: 12px;
  color: var(--text-dim);
  margin-bottom: 12px;
}
.cal-leg[data-c="event"] { color: #3577d1; }
.cal-leg[data-c="reminder"] { color: #b07d1e; }
.cal-leg[data-c="snooze"] { color: #9c53c9; }
.cal-leg[data-c="send"] { color: #2e9e63; }
.cal-leg[data-c="deadline"] { color: var(--danger); }
.cal-dow {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 6px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-dim);
  padding: 0 2px 6px;
}
.cal-dow span { text-align: center; }
.cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 6px;
}
.cal-cell {
  min-height: 92px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 3px;
  overflow: hidden;
  transition: border-color 0.15s, transform 0.15s, box-shadow 0.15s;
}
.cal-cell:hover { border-color: var(--accent); transform: translateY(-1px); box-shadow: var(--shadow); }
.cal-empty { background: transparent; border-color: transparent; cursor: default; }
.cal-empty:hover { border-color: transparent; transform: none; box-shadow: none; }
.cal-num { font-size: 12px; color: var(--text-dim); }
.cal-today { border-color: var(--accent); background: var(--accent-soft); }
.cal-today .cal-num { color: var(--accent); font-weight: 700; }
.cal-chip {
  --cc: #3577d1;
  font-size: 11px;
  line-height: 1.35;
  padding: 2px 5px;
  border-radius: 4px;
  background: color-mix(in srgb, var(--cc) 16%, var(--bg-panel));
  border-left: 3px solid var(--cc);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--text);
}
.cal-chip b { font-weight: 600; color: var(--cc); }
.cal-more { font-size: 10px; color: var(--text-dim); }
.cal-day-panel {
  margin-top: 14px;
  background: var(--bg-panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px 16px;
  animation: fadeUp 0.25s ease both;
}
.cal-day-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}
.cal-day-head h3 { font-size: 15px; font-weight: 600; }
.cal-day-item {
  --cc: #3577d1;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-left: 3px solid var(--cc);
  border-radius: 6px;
  background: color-mix(in srgb, var(--cc) 8%, var(--bg-panel));
  margin-bottom: 6px;
}
.cal-day-item-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.cal-day-type { font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--cc); font-weight: 600; }
.cal-day-title-txt { font-size: 13px; }
.cal-day-notes { font-size: 12px; color: var(--text-dim); white-space: pre-wrap; }
.event-card { max-width: 440px; }
.event-form { display: flex; flex-direction: column; gap: 10px; padding: 16px 20px 20px; }
.event-form input[type="text"], .event-form input[type="date"], .event-form input[type="time"], .event-form textarea {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text);
  padding: 9px 11px;
  font-family: inherit;
  font-size: 13px;
  width: 100%;
}
.event-form input:focus, .event-form textarea:focus { outline: none; border-color: var(--accent); }
.event-row { display: flex; gap: 10px; }
.event-colors { display: flex; gap: 8px; }
.ev-color {
  width: 24px; height: 24px;
  border-radius: 50%;
  border: 2px solid transparent;
  cursor: pointer;
  transition: transform 0.12s;
}
.ev-color:hover { transform: scale(1.15); }
.ev-color.sel { border-color: var(--text); transform: scale(1.15); }
.event-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 4px; }
#ev-delete { color: var(--danger); }

@media (max-width: 720px) {
  .cal-wrap { padding: 12px 10px calc(20px + env(safe-area-inset-bottom)); }
  .cal-cell { min-height: 56px; padding: 4px; border-radius: 6px; }
  .cal-chip { font-size: 0; padding: 0; height: 5px; border-left: none; background: var(--cc); border-radius: 3px; }
  .cal-chip b { display: none; }
  .cal-more { font-size: 9px; }
  .cal-header h2 { font-size: 16px; }
  .cal-legend { gap: 8px; font-size: 11px; }
  .event-row { flex-direction: column; }
}

/* ============ Drag-to-app + Show-in-app ============ */
.email-item[draggable="true"] { -webkit-user-drag: element; }
.sidebar.drag-hint .folder-item[data-app] { outline: 1px dashed var(--border); outline-offset: -1px; }
.folder-item.drop-target {
  background: var(--accent-soft) !important;
  outline: 2px dashed var(--accent) !important;
  outline-offset: -2px;
  color: var(--accent);
}
.row-menu-title {
  font-size: 11px;
  color: var(--text-dim);
  padding: 8px 12px 4px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 4px;
  max-width: 220px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ============ App unread badges ============ */
.app-badge {
  margin-left: auto;
  background: var(--accent);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  border-radius: 10px;
  padding: 1px 7px;
  min-width: 20px;
  text-align: center;
  animation: popIn 0.25s ease both;
}
.folder-item { display: flex; align-items: center; }

/* ============ Manage apps ============ */
.apps-manage-btn { margin: 4px 12px 0; font-size: 12px; text-align: left; }
.app-emoji { font-size: 15px; width: 18px; display: inline-block; text-align: center; }
.app-manage-row {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 10px; border-bottom: 1px solid var(--border);
}
.app-manage-row.app-hidden .app-manage-label { opacity: 0.45; }
.app-manage-icon { display: flex; align-items: center; color: var(--text-dim); }
.app-manage-label { flex: 1; font-size: 13px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.app-manage-label em { color: var(--text-dim); font-size: 11px; }
.app-manage-actions { display: flex; gap: 2px; }
.app-manage-actions .icon-btn { width: 28px; height: 28px; font-size: 13px; }

/* ============ App drill-down groups ============ */
.folder-item.app-sub { padding-left: 34px; font-size: 13px; }
.app-caret {
  margin-left: 6px;
  color: var(--text-dim);
  font-size: 12px;
  padding: 2px 6px;
  border-radius: 4px;
}
.app-caret:hover { color: var(--text); background: var(--bg-active); }

.acct-dot {
  width: 9px; height: 9px;
  border-radius: 50%;
  display: inline-block;
  flex-shrink: 0;
  margin: 0 4px 0 3px;
}

/* ============ Pull-to-refresh ============ */
.ptr-indicator {
  height: 0;
  opacity: 0;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  color: var(--text-dim);
  transition: color 0.15s;
  flex-shrink: 0;
}
.ptr-indicator.ready { color: var(--accent); }
.ptr-indicator.spinning { height: 44px !important; opacity: 1 !important; animation: ptrspin 0.8s linear infinite; }
@keyframes ptrspin { to { transform: rotate(360deg); } }


/* ============ Bulk select ============ */
.lt-spacer { flex: 1; }
#btn-select.active { color: var(--accent); background: var(--accent-soft); }
.bulk-bar {
  display: flex; align-items: center; gap: 6px;
  padding: 8px 12px; border-bottom: 1px solid var(--border);
  background: var(--accent-soft);
  flex-wrap: wrap;
  animation: fadeUp 0.2s ease both;
}
.bulk-all { display: flex; align-items: center; gap: 5px; font-size: 13px; cursor: pointer; }
.bulk-count { font-size: 12px; color: var(--text-dim); min-width: 70px; }
.bulk-bar .btn { padding: 5px 10px; font-size: 12px; }
.bulk-danger { color: var(--danger); }
.email-item.sel-mode { padding-left: 44px; position: relative; }
.sel-box {
  position: absolute; left: 14px; top: 50%; transform: translateY(-50%);
  font-size: 18px; color: var(--text-dim);
}
.email-item.picked { background: var(--accent-soft); }
.email-item.picked .sel-box { color: var(--accent); }

/* ============ Mobile de-clutter ============ */
/* Smart Inbox lives in the top menu (⚡) only — no floating button */
.smart-fab { display: none !important; }
/* floating Compose — phone only */
.compose-fab { display: none; }
@media (max-width: 720px) {
  .smart-fab {
    width: 46px; height: 46px;
    right: 12px;
    bottom: calc(70px + env(safe-area-inset-bottom));
    box-shadow: 0 4px 14px rgba(0,0,0,0.35);
  }
  .compose-fab {
    display: flex; align-items: center; justify-content: center;
    position: fixed; right: 12px;
    bottom: calc(70px + env(safe-area-inset-bottom));
    width: 46px; height: 46px; border-radius: 50%; border: none;
    background: var(--accent); color: #fff; cursor: pointer; z-index: 45;
    box-shadow: 0 4px 14px rgba(0,0,0,0.35);
  }
  .compose-fab:active { transform: scale(0.94); }
  .compose-fab.hidden { display: none; }
  /* hide the buttons whenever another surface is active — no collisions */
  body:has(#email-viewer-pane:not(.hidden)) .smart-fab,
  body:has(#compose-modal:not(.hidden)) .smart-fab,
  body:has(#smart-panel:not(.hidden)) .smart-fab,
  body:has(#accounts-modal:not(.hidden)) .smart-fab,
  body:has(#apps-modal:not(.hidden)) .smart-fab,
  body:has(#event-modal:not(.hidden)) .smart-fab,
  body:has(.sidebar.open) .smart-fab,
  body:has(#email-viewer-pane:not(.hidden)) .compose-fab,
  body:has(#compose-modal:not(.hidden)) .compose-fab,
  body:has(#smart-panel:not(.hidden)) .compose-fab,
  body:has(#accounts-modal:not(.hidden)) .compose-fab,
  body:has(#apps-modal:not(.hidden)) .compose-fab,
  body:has(#event-modal:not(.hidden)) .compose-fab,
  body:has(.sidebar.open) .compose-fab { display: none; }
  .bulk-bar { gap: 4px; padding: 6px 8px; }
  .bulk-bar .btn { padding: 6px 8px; font-size: 12px; }
}

/* ============ Attachments: chip + ⋮ actions + inline preview ============ */
.attachment-wrap { display: inline-flex; align-items: stretch; margin: 4px 6px 0 0; }
.attachment-wrap .attachment-chip { border-radius: 8px 0 0 8px; margin: 0; }
.attachment-more {
  border: 1px solid var(--border); border-left: none; border-radius: 0 8px 8px 0;
  background: var(--bg); color: var(--text-dim); cursor: pointer;
  padding: 0 9px; font-size: 15px; font-weight: 700;
}
.attachment-more:hover { background: var(--bg-hover); color: var(--text); }
.att-preview {
  margin: 12px 0; border: 1px solid var(--border); border-radius: 10px;
  background: var(--bg-panel); padding: 10px 12px;
}
.att-preview-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.att-frame { width: 100%; height: 70vh; border: none; border-radius: 8px; background: #fff; }
.att-text { max-height: 55vh; overflow: auto; font-size: 13px; white-space: pre-wrap; word-break: break-word; }

/* ============ Mobile visual polish (portrait) ============ */
@media (max-width: 640px) {
  /* Topbar: exactly 3 tight rows — search / sort+actions / account chips.
     The select shrinks (flex-basis 0) so the four icon buttons NEVER wrap
     onto an orphan row; ~150px total instead of the old 216px. */
  .topbar { padding: 6px 10px 4px; gap: 6px; row-gap: 6px; }
  .searchbar { flex: 1 1 calc(100% - 50px); max-width: none; border-radius: 10px; }
  .searchbar input { padding: 9px 0; font-size: 16px; } /* 16px stops iOS zoom-on-focus */
  .sort-select { flex: 1 1 0; min-width: 0; max-width: none; font-size: 13px; padding: 8px 6px; border-radius: 8px; }
  .topbar > .icon-btn, .menu-btn {
    width: 40px; height: 40px; min-width: 40px; min-height: 40px;
    font-size: 17px; flex: 0 0 auto;
  }
  /* Reading view: the search/sort/chips bar is dead weight — reclaim all of it.
     The viewer toolbar's back button is the way out. */
  body:has(#view-mail.viewing) .topbar { display: none; }
  /* list: single-line header, denser rows (one more email per screen) */
  .list-toolbar { padding: 8px 12px 6px; flex-wrap: nowrap; }
  .list-title { font-size: 15px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .list-count { font-size: 11px; min-width: 0; }
  /* tactile: rows depress slightly on touch */
  .email-item { transition: transform 0.1s ease, background 0.15s; }
  .email-item:active { transform: scale(0.985); background: var(--bg-hover); }
  /* Declutter: rows are 2 lines (sender+date / subject). The "✓ read" chip and
     account pill are gone — bold-vs-dim carries read state (plus an accent dot
     on unread), and a thin colored left edge carries the account. The badges
     line only appears when it says something: booking tag, pin, attachment. */
  /* a 42px right gutter reserves the whole ⋮ zone — date, subject and tags
     can never run underneath it, on any row height or screen width */
  .email-item { padding: 12px 44px 12px 10px; gap: 3px; border-left: 3px solid var(--accc, transparent); }
  .ei-from { font-size: 14px; }
  .ei-date { font-size: 11px; }
  .row-more { right: 2px; }
  .email-item.unread .ei-from::before {
    content: ''; display: inline-block; width: 7px; height: 7px; border-radius: 50%;
    background: var(--accent); margin-right: 6px; vertical-align: 1px;
  }
  .ei-subject { font-size: 13px; color: var(--text-dim); }
  .email-item.unread .ei-subject { color: var(--text); }
  .read-chip, .ei-account { display: none; }
  .ei-badges { display: none; }
  .ei-badges:has(.bk-tag), .ei-badges:has(svg.ic) {
    display: flex; flex-wrap: wrap; gap: 5px; align-items: center;
  }
  .row-more { min-width: 40px; min-height: 40px; }
  /* lighter account chips — outline only, less shouting */
  /* viewer: ONE horizontally-scrollable toolbar row (never two stacked rows) */
  .viewer-toolbar { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; gap: 2px; padding: 6px 8px; }
  .viewer-toolbar::-webkit-scrollbar { display: none; }
  .viewer-toolbar .icon-btn { flex: 0 0 auto; width: 40px; height: 40px; min-width: 40px; min-height: 40px; }
  .viewer-subject { font-size: 18px; line-height: 1.3; }
}

/* ============ Read / unread visual state ============ */
/* read rows: dimmed, regular weight — the bold/regular contrast alone carries
   the unread state (whole-list italics read as noise, not as a signal) */
.email-item.read .ei-from,
.email-item.read .ei-subject {
  color: var(--text-dim);
  font-weight: 400;
}
.email-item.read .ei-fav { opacity: 0.55; }
.read-chip {
  border: 1px solid transparent;
  border-radius: 10px;
  padding: 1px 8px;
  font-size: 10px;
  font-family: inherit;
  cursor: pointer;
  letter-spacing: 0.03em;
  transition: all 0.15s;
}
.read-chip.is-new {
  color: var(--accent);
  border-color: var(--accent);
  background: var(--accent-soft);
  font-weight: 700;
}
.read-chip.is-read {
  color: var(--text-dim);
  border-color: var(--border);
  background: transparent;
  font-style: italic;
}
.read-chip:hover { filter: brightness(1.15); border-color: var(--accent); }

/* ============================================================
   Full-screen surfaces: Dashboard & Settings
   ============================================================ */
.screen {
  position: fixed; inset: 0; z-index: 60; background: var(--bg);
  display: flex; flex-direction: column;
  animation: screenIn 0.22s cubic-bezier(0.2, 0.9, 0.3, 1.05);
}
@keyframes screenIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
.screen-head {
  display: flex; align-items: center; gap: 10px; flex: none;
  padding: 10px 14px; border-bottom: 1px solid var(--border); background: var(--bg-panel);
}
.screen-head h2 { font-size: 16px; font-weight: 700; margin-right: auto; }
.screen-body { flex: 1; overflow-y: auto; padding: 14px; }
.range-tabs { display: flex; gap: 2px; padding: 3px; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; }
.range-tabs button {
  border: none; background: transparent; color: var(--text-dim); cursor: pointer;
  padding: 5px 9px; border-radius: 6px; font-family: inherit; font-size: 12px;
}
.range-tabs button.is-on { background: var(--accent); color: #fff; }

/* --- KPI cards --- */
.kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(122px, 1fr)); gap: 10px; margin-bottom: 14px; }
.kpi {
  background: var(--bg-panel); border: 1px solid var(--border); border-radius: 10px;
  padding: 13px 14px; display: flex; flex-direction: column; gap: 2px;
  animation: kpiIn 0.35s backwards;
}
@keyframes kpiIn { from { opacity: 0; transform: translateY(8px); } }
.kpi-v { font-size: 22px; font-weight: 700; line-height: 1.1; }
.kpi-l { font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-dim); }
.kpi-s { font-size: 12px; color: var(--text-dim); }
.kpi.warn .kpi-v { color: var(--accent); }
.kpi.good .kpi-v { color: #4f9d6b; }

/* --- cards & charts --- */
.stat-card {
  background: var(--bg-panel); border: 1px solid var(--border); border-radius: 10px;
  padding: 14px 16px; margin-bottom: 12px;
}
.stat-card h3 { font-size: 13px; font-weight: 700; margin-bottom: 10px; display: flex; gap: 8px; align-items: baseline; }
.stat-sub { font-size: 11px; font-weight: 400; color: var(--text-dim); }
.stat-two { display: grid; grid-template-columns: 1fr; gap: 12px; }
@media (min-width: 860px) { .stat-two { grid-template-columns: 1fr 1fr; } }

.chart { width: 100%; height: 200px; overflow: visible; }
.ch-grid { stroke: var(--border); stroke-width: 1; }
.ch-tick { fill: var(--text-dim); font-size: 9px; }
.ch-area { fill: var(--accent); opacity: 0.13; }
.ch-line {
  fill: none; stroke-width: 2; stroke-linejoin: round; stroke-linecap: round;
  stroke-dasharray: 2200; stroke-dashoffset: 2200; animation: draw 1.1s ease forwards;
}
@keyframes draw { to { stroke-dashoffset: 0; } }
.ch-recv { stroke: var(--accent); }
.ch-sent { stroke: #4a6fb3; opacity: 0.85; }
.ch-hit { fill: var(--accent); opacity: 0; cursor: pointer; transition: opacity 0.12s; }
.ch-hit.on, .ch-hit:hover { opacity: 1; }
.ch-legend { display: flex; gap: 14px; align-items: center; font-size: 12px; color: var(--text-dim); margin-top: 6px; }
.ch-legend i { display: inline-block; width: 10px; height: 3px; border-radius: 2px; margin-right: 5px; vertical-align: middle; }
.sw-recv { background: var(--accent); }
.sw-sent { background: #4a6fb3; }
.ch-read { margin-left: auto; color: var(--text); font-variant-numeric: tabular-nums; }

/* --- heatmap --- */
.heatmap { display: grid; grid-template-columns: 30px 1fr; gap: 4px 6px; align-items: center; }
.hm-rows { display: grid; grid-template-rows: repeat(7, 1fr); gap: 2px; font-size: 10px; color: var(--text-dim); }
.hm-grid { display: grid; grid-template-columns: repeat(24, 1fr); grid-template-rows: repeat(7, 1fr); gap: 2px; }
.hm-cell {
  aspect-ratio: 1; border-radius: 2px; min-height: 9px;
  background: color-mix(in srgb, var(--accent) calc(var(--i) * 100%), var(--bg-hover));
}
.hm-hours { grid-column: 2; display: flex; justify-content: space-between; font-size: 10px; color: var(--text-dim); }

/* --- hour bars --- */
.hours { display: flex; align-items: flex-end; gap: 2px; height: 110px; }
.hour-bar { flex: 1; display: flex; align-items: flex-end; height: 100%; }
.hour-bar i {
  display: block; width: 100%; border-radius: 3px 3px 0 0; background: var(--accent);
  height: calc(var(--h) * 100%); min-height: 2px; opacity: 0.85;
  animation: growUp 0.5s ease backwards; transform-origin: bottom;
}
@keyframes growUp { from { transform: scaleY(0); } }
.hours-axis { display: flex; justify-content: space-between; font-size: 10px; color: var(--text-dim); margin-top: 4px; }

/* --- bar lists --- */
.bars { list-style: none; display: flex; flex-direction: column; gap: 6px; }
.bar-row { display: grid; grid-template-columns: minmax(0, 1fr) 90px 54px; gap: 9px; align-items: center; cursor: pointer; }
.bar-row:hover .bar-label { color: var(--accent); }
.bar-label { font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bar-track { height: 7px; background: var(--bg-hover); border-radius: 4px; overflow: hidden; }
.bar-fill {
  display: block; height: 100%; background: var(--accent); border-radius: 4px;
  animation: growRight 0.6s cubic-bezier(0.2, 0.9, 0.3, 1) backwards; transform-origin: left;
}
@keyframes growRight { from { transform: scaleX(0); } }
.bar-n { font-size: 12px; color: var(--text-dim); text-align: right; font-variant-numeric: tabular-nums; }
.bar-n em { color: var(--accent); font-style: normal; margin-left: 4px; }

.acc-stats { list-style: none; display: flex; flex-direction: column; gap: 8px; }
.acc-stats li { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.as-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.as-n { margin-left: auto; color: var(--text-dim); font-size: 12px; flex: none; }
.as-n em { color: var(--accent); font-style: normal; }

.cloud { display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: baseline; }
.cloud-w { cursor: pointer; line-height: 1.3; }
.cloud-w:hover { color: var(--accent); }
.big-msg { font-size: 13px; line-height: 1.6; }
.stats-loading, .stats-foot { color: var(--text-dim); font-size: 12px; text-align: center; padding: 22px 10px; }

/* ============================================================
   Settings
   ============================================================ */
.settings-body { max-width: 720px; margin: 0 auto; width: 100%; }
.set-card {
  background: var(--bg-panel); border: 1px solid var(--border); border-radius: 10px;
  padding: 15px 16px; margin-bottom: 12px;
}
.set-card h3 { font-size: 13px; font-weight: 700; margin-bottom: 12px; }
.set-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 12px; }
.set-row > label { font-size: 13px; color: var(--text-dim); }
.set-val { color: var(--text); margin-left: 6px; font-variant-numeric: tabular-nums; }
.set-toggle input[type="checkbox"] { width: 18px; height: 18px; accent-color: var(--accent); }
.set-note { font-size: 12px; color: var(--text-dim); line-height: 1.55; margin-bottom: 10px; }
.seg { display: flex; gap: 2px; padding: 3px; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; }
.seg button {
  border: none; background: transparent; color: var(--text-dim); cursor: pointer;
  padding: 6px 11px; border-radius: 6px; font-family: inherit; font-size: 12px;
}
.seg button.is-on { background: var(--accent); color: #fff; }
.swatches { display: flex; gap: 6px; }
.swatch { width: 22px; height: 22px; border-radius: 50%; border: 2px solid transparent; cursor: pointer; }
.swatch.is-on { border-color: var(--text); }
input[type="range"] { accent-color: var(--accent); width: 150px; }

.set-preview-strip {
  background: var(--bg); border: 1px solid var(--border); border-radius: 8px;
  padding: 10px 12px; margin-top: 4px;
}
.sp-row { display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 700; }
.sp-date { margin-left: auto; font-size: 12px; font-weight: 400; color: var(--text-dim); }
.sp-sub { font-size: 13px; color: var(--text-dim); margin-top: 3px; }

.set-accounts { list-style: none; display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px; }
.set-acc {
  display: flex; align-items: center; gap: 9px; padding: 9px 10px;
  background: var(--bg); border: 1px solid var(--border); border-radius: 10px; cursor: grab;
}
.set-acc.dragging { opacity: 0.45; }
.drag-grip { color: var(--text-dim); font-size: 11px; letter-spacing: -2px; flex: none; }
.sa-main { display: flex; flex-direction: column; min-width: 0; margin-right: auto; }
.sa-email { font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sa-host { font-size: 11px; color: var(--text-dim); }
.set-pw { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: 10px; }
.set-pw input {
  flex: 1 1 160px; padding: 9px 11px; border: 1px solid var(--border);
  border-radius: 6px; background: var(--bg); color: var(--text); font-family: inherit; font-size: 13px;
}

/* --- appearance preferences applied app-wide --- */
body[data-density="compact"] .email-item { padding: 7px 14px 7px 10px; gap: 1px; contain-intrinsic-size: auto 48px; }
body[data-density="compact"] .ei-from { font-size: 13px; }
body[data-density="compact"] .ei-subject { font-size: 12px; }

/* The ⋮ button is absolutely positioned over the row, so every row must keep a
   gutter clear for it — on any density, any screen width. Declared last so no
   density shorthand can quietly reclaim it (which is exactly what happened when
   the compact density landed). */
.email-item { padding-right: 46px; }
body[data-density="compact"] .email-item { padding-right: 46px; }
.ei-date { max-width: 45%; overflow: hidden; text-overflow: ellipsis; }
body[data-motion="off"] *, body[data-motion="off"] *::before, body[data-motion="off"] *::after {
  animation: none !important; transition: none !important;
}
body[data-avatars="off"] .tc-avatar, body[data-avatars="off"] .viewer-avatar { display: none; }
/* data controls in Settings */
.set-data-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.danger-btn { color: var(--danger); border-color: var(--danger)55; }
.danger-btn:hover { background: var(--danger)12; border-color: var(--danger); }

/* the sort menu is the only select in the top bar now */
.sort-select { max-width: 46vw; }
@media (min-width: 900px) { .sort-select { max-width: 18rem; } }

/* ============================================================
   Message actions: one floating control instead of a hardcoded row
   ============================================================ */
/* The toolbar buttons stay in the DOM — the reply bar and the action sheet
   drive them programmatically — but only Back is shown. Everything else moved
   into the floating menu, which keeps the top of a message clear of chrome. */
.viewer-toolbar > .icon-btn.tb:not(#btn-back),
.viewer-toolbar > .tb-sep,
.viewer-toolbar > .more-wrap { display: none; }

.viewer-fab {
  position: absolute; z-index: 25;
  top: 8px; right: 12px;
  width: 40px; height: 40px; border-radius: 50%;
  display: grid; place-items: center;
  border: 1px solid var(--border);
  background: color-mix(in srgb, var(--bg-panel) 90%, transparent);
  color: var(--text); cursor: pointer;
  box-shadow: 0 4px 16px rgba(0, 0, 0, .22);
  backdrop-filter: blur(12px) saturate(1.3);
  -webkit-backdrop-filter: blur(12px) saturate(1.3);
  transition: background .15s, transform .1s, border-color .15s;
}
.viewer-fab:hover { background: var(--bg-hover); border-color: var(--accent); }
.viewer-fab:active { transform: scale(.92); }
.email-viewer-pane.hidden .viewer-fab { display: none; }

/* ============================================================
   Conversation history: a slim contents list, not stacked cards
   ============================================================ */
.viewer-history { margin-top: 26px; border-top: 1px solid var(--border); padding-top: 10px; }
.hist-title {
  display: flex; align-items: center; gap: 8px;
  font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--text-dim); margin-bottom: 6px;
}
.hist-title span {
  font-size: 11px; letter-spacing: 0; padding: 1px 6px; border-radius: 8px;
  background: var(--bg-hover); color: var(--text-dim);
}
.hist-row { border-bottom: 1px solid var(--border); }
.hist-row:last-child { border-bottom: none; }
.hist-head {
  width: 100%; display: flex; align-items: baseline; gap: 10px;
  padding: 9px 2px; background: none; border: none; cursor: pointer;
  color: var(--text); font-family: inherit; font-size: 13px; text-align: left;
}
.hist-head:hover .hist-subject { color: var(--accent); }
.hist-subject { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hist-row.unread .hist-subject { font-weight: 700; }
.hist-when { flex: none; font-size: 12px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.hist-body { padding: 0 0 8px; }
.hist-actions { padding-bottom: 8px; }


/* notification permission help */
.perm-modal { width: min(430px, 94vw); }
.perm-body { padding: 16px 18px 18px; }
.perm-lead { font-size: 13px; line-height: 1.55; margin-bottom: 12px; }
.perm-steps { margin: 0 0 12px 18px; padding: 0; display: flex; flex-direction: column; gap: 7px; }
.perm-steps li { font-size: 13px; line-height: 1.5; color: var(--text-dim); }
.perm-steps li b { color: var(--text); font-weight: 600; }

/* ============================================================
   Open message: a compact header, then the mail
   The old header cost ~370px before a single line of content — full subject,
   a three-line address block, three AI chips and an ask box. Now: subject,
   one tappable identity line, and one assistant chip.
   ============================================================ */
.viewer-subject {
  font-size: 15px; font-weight: 700; line-height: 1.35;
  margin-bottom: 8px; text-wrap: balance;
}
.viewer-meta-line {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 6px 0; margin-bottom: 4px;
  background: none; border: none; cursor: pointer;
  color: var(--text); font-family: inherit; font-size: 13px; text-align: left;
}
.viewer-meta-line .viewer-avatar {
  width: 28px; height: 28px; min-width: 28px; line-height: 28px;
  border-radius: 50%; color: #fff; text-align: center;
  font-size: 13px; font-weight: 700; flex: none;
}
.vm-from { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vm-when { margin-left: auto; color: var(--text-dim); font-size: 12px; flex: none; }
.vm-caret { color: var(--text-dim); font-size: 11px; flex: none; transition: transform .15s; }
.viewer-meta-line.is-open .vm-caret { transform: rotate(180deg); }
.viewer-details {
  background: var(--bg); border: 1px solid var(--border); border-radius: 8px;
  padding: 9px 11px; margin-bottom: 10px;
  font-size: 13px; line-height: 1.7; color: var(--text-dim);
}
.viewer-details b { color: var(--text); font-weight: 600; display: inline-block; min-width: 68px; }

/* assistant: one chip that opens the panel, instead of four controls always on */
.ai-strip { margin-bottom: 12px; }
.ai-open {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 14px; border: 1px solid var(--border); border-radius: 16px;
  background: transparent; color: var(--text-dim); cursor: pointer;
  font-family: inherit; font-size: 13px;
  transition: color .15s, border-color .15s, background .15s;
}
.ai-open:hover { color: var(--text); border-color: var(--accent); background: var(--bg-hover); }
.ai-open svg, .ai-open .ic { width: 15px; height: 15px; }
.ai-panel { margin-bottom: 12px; }
.ai-panel .ai-bar { margin-bottom: 8px; }
.ai-panel .ai-ask { margin-bottom: 0; }

/* ============================================================
   Sidebar mailbox picker: it is now the only account switcher, so it
   carries the unread counts the old top-bar dropdown used to show.
   ============================================================ */
.acc-count {
  margin-left: auto; flex: none;
  min-width: 20px; padding: 1px 6px; border-radius: 10px;
  background: var(--accent); color: #fff;
  font-size: 11px; font-weight: 700; text-align: center;
}
.account-menu-item .acc-check { margin-left: 6px; }

/* ============================================================
   Sort rules — the user's own entries in the top sort menu
   ============================================================ */
.sr-modal { width: min(520px, 94vw); }
.sr-body { padding: 14px 16px 16px; max-height: 78vh; overflow-y: auto; }
.sr-list { list-style: none; margin: 12px 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.sr-empty { color: var(--text-dim); font-size: 13px; padding: 10px 2px; }
.sr-item {
  display: flex; align-items: center; gap: 4px;
  padding: 8px 10px; border: 1px solid var(--border); border-radius: 10px;
  background: var(--bg);
}
.sr-meta { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 2px; }
.sr-meta b { font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sr-meta span { font-size: 12px; color: var(--text-dim); }
.sr-item .icon-btn { flex: none; }
.sr-item .icon-btn[disabled] { opacity: 0.3; cursor: default; }
.sr-del:hover { color: var(--danger); }
.sr-form {
  border-top: 1px solid var(--border); padding-top: 12px;
  display: flex; flex-direction: column; gap: 10px;
}
.sr-name {
  width: 100%; padding: 9px 11px; border-radius: 10px;
  border: 1px solid var(--border); background: var(--bg);
  color: var(--text); font-family: inherit; font-size: 13px;
}
.sr-fields { display: flex; flex-wrap: wrap; gap: 10px; }
.sr-fields label {
  flex: 1 1 140px; min-width: 0;
  display: flex; flex-direction: column; gap: 4px;
  font-size: 12px; color: var(--text-dim);
}
.sr-fields select {
  padding: 8px 9px; border-radius: 10px; border: 1px solid var(--border);
  background: var(--bg); color: var(--text); font-family: inherit; font-size: 13px;
}
.sr-check { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text); }

/* ============================================================
   Panel review fixes (v103)
   Everything below is a correction to a measured defect, not a
   restyling. The measurement is quoted with each rule so the next
   person can re-check it instead of trusting the comment.
   ============================================================ */

/* ---- 1. white text on the accent failed AA (3.96:1 in dark) ----
   Anywhere white sits ON the brand colour now uses --accent-strong,
   which is the same hue at >=4.5:1. The accent itself is untouched
   as a text/stroke colour, where it already passed. */
.btn-primary,
.cal-tab.active,
.ag-count,
.acc-count,
.undo-bar .ub-undo,
.compose-fab { background: var(--accent-strong); }
.btn-primary { border-color: var(--accent-strong); }
.btn-primary:hover { background: var(--accent-strong); }

/* ---- 2. control boundaries were 1.39:1 (dark) / 1.22:1 (light) ----
   WCAG 1.4.11 wants 3:1 for the edge of a control. Decorative
   separators keep --border; things you type into or choose from get
   --border-strong so the field is findable. */
input[type="text"], input[type="email"], input[type="password"],
input[type="search"], input[type="date"], input[type="time"],
input[type="datetime-local"], input[type="number"],
textarea, select {
  border-color: var(--border-strong);
}

/* ---- 3. keyboard focus was invisible ----
   Five rules removed the outline from inputs and nothing replaced it;
   the stylesheet had zero :focus-visible rules. This is the whole
   replacement, and it deliberately uses :focus-visible so a mouse or
   touch press does not draw a ring. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}
.searchbar input:focus-visible,
.ai-ask input:focus-visible,
.compose-row input:focus-visible,
.compose-row select:focus-visible,
.compose-body:focus-visible,
.event-form input:focus-visible,
.event-form textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

/* ---- 4. touch targets ----
   135 of 176 controls measured under 44px on their short side.
   44px is the Apple minimum; the top bar goes to 46 where there is room. */
.icon-btn { min-width: 44px; min-height: 44px; }
.read-chip, .sq-btn, .bulk-bar .btn { min-height: 44px; }
/* the select-all box measured 13x13 — the box stays small, the
   *target* around it does not */
.bulk-all {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 44px; padding: 0 6px; cursor: pointer;
}
.bulk-all input[type="checkbox"] { width: 20px; height: 20px; accent-color: var(--accent); }
.sr-check { min-height: 44px; }
.sr-check input[type="checkbox"], .set-toggle input[type="checkbox"] { width: 20px; height: 20px; accent-color: var(--accent); }

/* ---- 5. the floating compose button ----
   It sat 70px off the bottom edge, reading as detached, at 46px
   against a 56dp standard. */
@media (max-width: 720px) {
  .compose-fab {
    width: 56px; height: 56px;
    right: 16px;
    bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  }
  .compose-fab svg { width: 24px; height: 24px; }
}

/* ---- 6. iOS zooms the page when a field under 16px takes focus ----
   24 inputs measured between 12.5px and 13.5px. Only text entry and
   selects trigger it, and only on the phone breakpoint. */
@media (max-width: 720px) {
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
  select, textarea { font-size: 16px; }
  .sr-fields select, .set-row select { font-size: 16px; }
}

/* ---- 7. the top bar was two rows, 102px, 19% of the screen ----
   One row now: menu, search, sort, Smart Inbox, notifications.
   Refresh and theme leave the phone top bar — both already exist in
   the sidebar footer, and pull-to-refresh already works — but they
   stay in the DOM so the "rearrange top menu buttons" setting and the
   desktop layout are untouched. */
@media (max-width: 720px) {
  .topbar { flex-wrap: nowrap; gap: 6px; padding: 6px 10px; }
  .searchbar { flex: 1 1 0; min-width: 0; order: 0; }
  #btn-refresh-top, #btn-theme-top { display: none; }
  /* the sort menu becomes an icon: the native picker still opens on tap
     and still reads every label out, but the closed control no longer
     needs room for "Conversations — newest first" (which measured 167px
     of text in a 179px box, and was visibly clipped) */
  .sort-select {
    flex: 0 0 44px; width: 44px; min-width: 44px; max-width: 44px;
    height: 44px; padding: 0; color: transparent;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%238f8a7d' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M3 6h18'/><path d='M7 12h10'/><path d='M11 18h2'/></svg>");
    background-repeat: no-repeat; background-position: center;
    -webkit-appearance: none; appearance: none;
    text-indent: -9999px;
  }
  /* a dot when the list is not on the default sort, so an icon-only
     control still says that something is filtering the inbox */
  .sort-select.is-custom {
    box-shadow: inset 0 0 0 1px var(--accent);
  }
  .sort-select option { color: var(--text); }
}

/* ---- 8. dead CSS ----
   .smart-fab is display:none !important globally (the Smart Inbox
   moved into the top bar), so the phone-only sizing block and the
   seven :has() rules that tried to hide it were unreachable. They are
   overridden here rather than cut out of the middle of the file. */
.smart-fab { display: none !important; }

/* ---- 9. flag and paperclip moved onto the sender line ----
   They used to sit in .ei-badges, which is the row's third line; a
   message with an attachment measured 82px against 67px for one
   without. Now every row is one height. */
.ei-flags { display: inline-flex; align-items: center; gap: 4px; margin-left: auto; color: var(--text-dim); flex: none; }
.ei-flags:empty { display: none; }
.ei-flags .ic { width: 12px; height: 12px; margin-right: 0; }
.email-item.unread .ei-flags { color: var(--accent); }

/* ============================================================
   Panel review, second pass (v104)
   The first pass missed controls whose rules were more specific than
   a bare .icon-btn, and the sub-16px fix lost to class selectors.
   Numbers below are from re-measuring the deployed v103 with
   animations disabled (measuring mid-popIn had been inflating the
   failure count with scaled boxes).
   ============================================================ */

/* ---- targets: everything that is a real action reaches 44px ----
   Measured 95 controls under 44px on their short side. These rules
   are grouped by the container that was beating the base rule. */
.topbar > .icon-btn, .topbar .menu-btn {
  width: 46px; height: 46px; min-width: 46px; min-height: 46px;
}
.icon-btn.tb, .viewer-fab { min-width: 44px; min-height: 44px; }
.btn, .auth-tab, .auth-alt, .cal-tab, .ub-undo, .smart-tab,
.account-menu-item, .sheet-item, .sq-btn, .read-chip { min-height: 44px; }
.seg button, .range-tabs button, .smart-tabs button { min-height: 44px; }
select { min-height: 44px; }
/* reorder arrows in the settings lists: these sat at 30px */
.mm-ctl .icon-btn, .app-manage-actions .icon-btn,
.tm-up, .tm-down, .sr-item .icon-btn {
  width: 44px; height: 44px; min-width: 44px; min-height: 44px;
}
/* the event colour swatches were 24px dots. The dot stays 24px — a
   44px disc would dominate the form — but the *target* is 44px, drawn
   with padding and background-clip. */
.ev-color {
  width: 44px; height: 44px; min-width: 44px; min-height: 44px;
  padding: 10px; background-clip: content-box; background-origin: content-box;
  border-radius: 50%;
}
/* checkboxes are 20px boxes inside a 44px label, which is the target
   a screen reader and a thumb both act on */
input[type="checkbox"] { width: 20px; height: 20px; accent-color: var(--accent); }
.set-toggle, .set-toggle label, .fu-label, .bulk-all, .sr-check { min-height: 44px; display: flex; align-items: center; gap: 8px; }

/* ---- iOS zoom, properly this time ----
   The first pass used bare element selectors, which lose to
   .sort-select, .sr-fields select and .event-form textarea. Six fields
   were still measuring 12.5-13.5px. */
@media (max-width: 720px) {
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
  select, textarea { font-size: 16px !important; }
}

/* ---- targets, third pass ----
   Three groups survived: buttons carrying only .btn-ghost/.btn-primary
   (no .btn, so the group rule never matched them), the sidebar's
   manage buttons, and the viewer toolbar icons — the last two beaten
   by more specific rules earlier in the file. */
.btn-ghost, .btn-primary { min-height: 44px; }
.apps-manage-btn { min-height: 44px !important; }
.viewer-toolbar .icon-btn, .icon-btn.tb {
  min-width: 44px !important; min-height: 44px !important;
}
.bulk-bar .btn, .event-actions .btn-ghost, .event-actions .btn-primary { min-width: 44px; }
/* inline buttons that sit inside a line of text keep their own height —
   forcing 44px there would break the sentence, and they are paired with
   a same-action control that is already 44px */
.ei-badges .read-chip { min-height: 0; }

/* ---- targets, final pass ----
   What was left after the third pass was: the row overflow button
   (its own class, never matched by .icon-btn), the undo bar's button
   (beaten by .undo-bar .ub-undo), and a set of pills that were 44px
   tall but 32-39px wide. Width counts as much as height. */
.row-more { width: 44px !important; height: 44px !important; }
.undo-bar .ub-undo { min-height: 44px; }
.btn, .btn-ghost, .btn-primary, .seg button, .range-tabs button,
.smart-tabs button, .cal-tab, .auth-tab { min-width: 44px; }

/* ---- targets: the last group ----
   The message-menu state cycler in Settings sat at 30px, held there by
   a rule more specific than .btn. Two checkboxes remain 20px glyphs —
   deliberately: their target is the 44px row label they are bound to,
   which is how a settings row is meant to work. */
.mm-state { min-height: 44px !important; }
.set-toggle label { flex: 1; cursor: pointer; }

/* ---- the single-row top bar on a 320px phone ----
   At 320px the row still overflowed internally: the search field has an
   intrinsic minimum that flex could not shrink past. Let it shrink, and
   tighten the gutters on the narrowest phones. */
.searchbar { min-width: 0; }
.searchbar input { min-width: 0; width: 100%; }
@media (max-width: 360px) {
  .topbar { padding: 6px 8px; gap: 4px; }
  .topbar > .icon-btn, .topbar .menu-btn {
    width: 44px; height: 44px; min-width: 44px; min-height: 44px;
  }
}

/* ============================================================
   Android flagship compatibility (v109)
   Two device traits this app had not accounted for: a system that
   force-darkens web content, and a screen whose glass curves away at
   the left and right edges.
   ============================================================ */

/* ---- the page owns its own light and dark ----
   Declaring color-scheme stops Chrome's Auto Dark Theme (and ColorOS's
   force-dark) from inverting a page that is already dark, and makes the
   native bits — scrollbars, the caret, date pickers, select popups —
   follow the theme instead of the OS. */
:root { color-scheme: light dark; }
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"]  { color-scheme: dark; }

/* ---- curved edges and landscape cutouts ----
   Every safe-area inset in this file was a bottom inset. On a phone with
   a curved display, or held in landscape with the camera cutout on one
   side, content ran under the glass. env() resolves to 0 where there is
   no inset, so nothing moves on a flat screen. */
.topbar {
  padding-left: max(10px, env(safe-area-inset-left));
  padding-right: max(10px, env(safe-area-inset-right));
}
.list-toolbar, .bulk-bar, .viewer-toolbar, .screen-head {
  padding-left: max(14px, env(safe-area-inset-left));
  padding-right: max(14px, env(safe-area-inset-right));
}
.sidebar { padding-left: env(safe-area-inset-left); }
@media (max-width: 720px) {
  /* the 46px gutter the ⋮ button lives in is preserved, with the inset
     added on top of it — never in place of it */
  .email-item {
    padding-left: calc(10px + env(safe-area-inset-left));
    padding-right: calc(46px + env(safe-area-inset-right));
  }
  .row-more { right: calc(2px + env(safe-area-inset-right)); }
  .viewer-body, .compose-body { 
    padding-left: max(14px, env(safe-area-inset-left));
    padding-right: max(14px, env(safe-area-inset-right));
  }
  .compose-fab { right: calc(16px + env(safe-area-inset-right)); }
  .undo-bar { margin-left: env(safe-area-inset-left); margin-right: env(safe-area-inset-right); }
}

/* ---- the ⋮ gutter, re-derived ----
   The overflow button went from 40px to 44px for the target-size fix,
   which ate the 4px of clearance the 46px gutter used to leave. The
   date was measuring flush against it — the exact collision reported
   twice before. The gutter follows the button's width plus clearance,
   and is declared last so no later rule can take it away, at every
   density and width. */
.email-item,
body[data-density="compact"] .email-item {
  padding-right: calc(50px + env(safe-area-inset-right));
}

/* ============================================================
   Floating action dock at the end of an open message (v111)
   Small icons in a pill that sticks to the foot of the message while
   you read and settles at its end — the actions stay a thumb away
   without the slab of chrome that used to close every mail.
   Icons are 17px so it reads as light; the buttons underneath are
   still 44px, because a small icon is not the same as a small target.
   ============================================================ */
.msg-dock {
  position: sticky; bottom: calc(10px + env(safe-area-inset-bottom, 0px));
  z-index: 12; display: flex; justify-content: center;
  margin: 20px 0 6px; pointer-events: none;
}
.dock-pill {
  pointer-events: auto;
  display: inline-flex; align-items: center; gap: 2px;
  padding: 3px; border-radius: 16px;
  background: color-mix(in srgb, var(--bg-panel) 92%, transparent);
  border: 1px solid var(--border);
  box-shadow: 0 6px 22px rgba(0, 0, 0, 0.28);
  backdrop-filter: blur(9px); -webkit-backdrop-filter: blur(9px);
  max-width: 100%; overflow-x: auto; scrollbar-width: none;
}
.dock-pill::-webkit-scrollbar { display: none; }
.dock-btn {
  flex: none; width: 44px; height: 44px; border-radius: 50%;
  border: none; background: transparent; color: var(--text-dim);
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer; transition: background .15s, color .15s, transform .1s;
}
.dock-btn svg, .dock-btn .ic { width: 17px; height: 17px; margin: 0; }
.dock-btn:hover { background: var(--bg-hover); color: var(--text); }
.dock-btn:active { transform: scale(.9); }
.dock-btn.is-primary { background: var(--accent-strong); color: #fff; }
.dock-btn.is-primary:hover { background: var(--accent-strong); filter: brightness(1.08); color: #fff; }
.dock-btn.is-on { color: var(--accent); }
.dock-btn.danger:hover { background: var(--danger)1f; color: var(--danger); }

/* the history list belongs after the dock, not behind it */
.viewer-history { position: relative; z-index: 1; }

/* ============================================================
   v112 — two corrections
   ============================================================ */

/* ---- 1. pinch to zoom ----
   The viewport meta always allowed scaling, but `touch-action: pan-y` on the
   list and the open message told the browser to handle vertical panning ONLY,
   which silently swallowed the two-finger gesture on exactly the two surfaces
   worth zooming. Adding pinch-zoom hands that gesture back without giving up
   the horizontal swipe actions, which are still delivered to JS. */
.email-list, .viewer-body { touch-action: pan-y pinch-zoom; }
.viewer-content, .att-preview, .compose-body { touch-action: pan-y pinch-zoom; }

/* ---- 2. the dock is glass, not a banner ----
   It was reading as a slab because of the panel fill, the border and the
   shadow — not because of its size. Those go; what is left is the icons and
   just enough blur to keep them legible over text. The buttons stay 44px
   because a small icon and a small target are not the same thing. */
.dock-pill {
  background: color-mix(in srgb, var(--bg-panel) 45%, transparent);
  border: none;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.12);
  backdrop-filter: blur(14px) saturate(1.2);
  -webkit-backdrop-filter: blur(14px) saturate(1.2);
  padding: 2px;
  opacity: 0.86;
  transition: opacity .18s;
}
.dock-pill:hover, .dock-pill:focus-within { opacity: 1; }
.dock-btn svg, .dock-btn .ic { width: 16px; height: 16px; }
.msg-dock { margin: 14px 0 4px; }
/* the accent circle was the heaviest thing in it — a tint carries "primary"
   just as well at this size */
.dock-btn.is-primary {
  background: color-mix(in srgb, var(--accent) 22%, transparent);
  color: var(--accent);
}
.dock-btn.is-primary:hover {
  background: color-mix(in srgb, var(--accent) 34%, transparent);
  filter: none; color: var(--accent);
}

/* ---- v113: the dock was glass, but you could not read it ----
   Three things were fighting the icons at once: they were --text-dim
   (the faintest colour in the palette), 16px, and sitting on a fill of
   only 45% over arbitrary message content, so there was no stable
   ground behind them. The glass stays — still translucent, still
   blurred — but the fill is now dense enough to be a surface, and the
   icons are full-strength text colour at 18px with a slightly heavier
   stroke. */
.dock-pill {
  background: color-mix(in srgb, var(--bg-panel) 82%, transparent);
  border: 1px solid color-mix(in srgb, var(--border-strong) 55%, transparent);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.22);
  opacity: 1;
}
.dock-btn { color: var(--text); }
.dock-btn svg, .dock-btn .ic {
  width: 18px; height: 18px;
  stroke-width: 2.1;
}
.dock-btn:hover { background: var(--bg-hover); color: var(--text); }
/* Reply keeps a filled circle so the primary action still leads, and it is
   the accent that carries white text at AA rather than the display accent */
.dock-btn.is-primary { background: var(--accent-strong); color: #fff; }
.dock-btn.is-primary:hover { background: var(--accent-strong); filter: brightness(1.08); color: #fff; }
.dock-btn.is-primary svg { stroke-width: 2.2; }
.dock-btn.danger { color: var(--danger); }
.dock-btn.is-on { color: var(--accent); }

/* ============ diagnostics ============ */
.diag-out { margin-top: 10px; font-size: 13px; }
.diag-top { display: flex; gap: 14px; flex-wrap: wrap; padding: 8px 0 4px; color: var(--text-dim); }
.diag-top .is-bad b { color: var(--danger); }
.diag-top .is-ok b { color: #2e9e63; }
.diag-h { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--text-dim); margin: 14px 0 6px; }
.diag-row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  padding: 7px 0; border-bottom: 1px solid var(--border);
}
.diag-row code { font-size: 12px; overflow-wrap: anywhere; }
.diag-row span { color: var(--text-dim); font-size: 12px; flex: none; }
.diag-row.is-bad code { color: var(--danger); }
.diag-err { display: flex; flex-direction: column; gap: 2px; padding: 7px 0; border-bottom: 1px solid var(--border); }
.diag-when { font-size: 11px; color: var(--text-dim); }
.diag-msg { font-size: 12px; overflow-wrap: anywhere; }

/* ============================================================
   Update prompt
   The app used to purge its caches and reload itself the moment a new
   version appeared, which meant losing whatever was half-written. It
   now says the update is ready and waits to be told.
   ============================================================ */
.update-bar {
  position: fixed; z-index: 70;
  left: 50%; transform: translateX(-50%);
  bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  display: flex; align-items: center; gap: 10px;
  max-width: calc(100vw - 24px);
  padding: 8px 8px 8px 16px; border-radius: 16px;
  background: color-mix(in srgb, var(--bg-panel) 92%, transparent);
  border: 1px solid var(--border-strong);
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.3);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  /* NOT fadeUp: it ends at 'transform: none', which wipes the translateX(-50%)
     doing the centring and leaves the bar half its own width to the right.
     The centring has to travel through every keyframe. */
  animation: ub-rise 0.3s cubic-bezier(0.22, 1, 0.36, 1) both;
}
@keyframes ub-rise {
  from { opacity: 0; transform: translateX(-50%) translateY(12px); }
  to   { opacity: 1; transform: translateX(-50%); }
}
.update-bar .ub-text { font-size: 13px; color: var(--text); }
.update-bar .btn { min-height: 44px; padding: 0 14px; font-size: 13px; }
.update-bar .icon-btn { min-width: 44px; min-height: 44px; }
@media (max-width: 420px) {
  .update-bar { left: 12px; right: 12px; transform: none; max-width: none; }
  .update-bar .ub-text { flex: 1; min-width: 0; }
}

/* ============================================================
   v121 — a desktop is a different device, not a wide phone
   ------------------------------------------------------------
   Everything from the mobile passes (v103-v112) was applied to every
   width: 44px minimum targets, 16px form text, a thumb-height glass
   dock over the open message. On a phone that is correct and was
   measured to be. On a pointer device it is wrong for the same
   reason it was right there — a mouse hits a 28px target as reliably
   as a thumb hits a 44px one, so the 44px floor buys nothing and
   costs about a third of the vertical space on every screen.

   The lever is `pointer: fine`, not width alone: a 1280px tablet or a
   touchscreen laptop is still a finger, and gets the phone sizing.
   Width is kept in the query as well so a small pointer window (a
   side-by-side split) does not get desktop density it has no room for.

   `!important` appears below because the rules being corrected use it.
   Matching it is the honest way to say "this comes after"; the
   alternative is a specificity arms race that reads worse and breaks
   the next time either side is edited.
   ============================================================ */
@media (pointer: fine) and (min-width: 900px) {

  /* ---- controls at pointer density ---- */
  .icon-btn,
  .icon-btn.tb,
  .viewer-toolbar .icon-btn,
  .mm-ctl .icon-btn, .app-manage-actions .icon-btn,
  .tm-up, .tm-down, .sr-item .icon-btn {
    width: 32px !important; height: 32px !important;
    min-width: 32px !important; min-height: 32px !important;
  }
  .topbar > .icon-btn, .topbar .menu-btn {
    width: 34px !important; height: 34px !important;
    min-width: 34px !important; min-height: 34px !important;
  }
  .row-more { width: 30px !important; height: 30px !important; }

  .btn, .btn-ghost, .btn-primary, .auth-tab, .auth-alt, .cal-tab,
  .ub-undo, .smart-tab, .account-menu-item, .sheet-item, .sq-btn,
  .read-chip, .seg button, .range-tabs button, .smart-tabs button,
  .apps-manage-btn, .mm-state, .undo-bar .ub-undo, select {
    min-height: 32px !important;
  }
  .btn, .btn-ghost, .btn-primary { padding: 0 12px; font-size: 13px; }
  .bulk-all, .sr-check, .set-toggle, .set-toggle label, .fu-label {
    min-height: 32px !important;
  }
  .update-bar .btn { min-height: 32px !important; }
  .update-bar .icon-btn { min-width: 32px !important; min-height: 32px !important; }

  /* form text: 16px exists to stop iOS zooming a focused field. There is
     no such zoom with a pointer, and 16px in a settings column reads as
     a heading rather than a value. */
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
  select, textarea,
  .sr-fields select, .set-row select,
  .compose-row input, .compose-row select, .compose-body {
    font-size: 13px !important;
  }
  .searchbar input { padding: 7px 0; font-size: 13px; }

  /* ---- density: more of the mailbox on screen ---- */
  .topbar { padding: 8px 16px; }
  .email-item { padding: 7px 16px; }
  .list-toolbar { padding: 10px 16px 8px; }

  /* ---- the glass dock is a thumb affordance ----
     It floats above the message so a thumb can reach the actions without
     travelling to the top bar. A pointer has no reach cost, and every one
     of those seven actions is already in the viewer toolbar, so on desktop
     the dock is a second copy of a menu that is never out of reach. */
  .msg-dock { display: none !important; }

  /* ---- things a desktop app has and a phone does not ---- */
  /* the pointer should say what a thing does before it is clicked */
  .email-item, .folder-item, .ar-card { cursor: pointer; }
  /* a scrollbar that is visible is a position indicator, which a
     touch-styled overlay bar is not */
  .email-list, .viewer-content, .cal-agenda, .sidebar { scrollbar-width: thin; }
  /* keyboard focus must survive the density change */
  .btn:focus-visible, .icon-btn:focus-visible, .email-item:focus-visible {
    outline: 2px solid var(--accent); outline-offset: 1px;
  }
}

/* ---- desktop: right-click menu and sizable panes (v122) ---- */
.ctx-menu {
  position: fixed; z-index: 400; min-width: 208px; padding: 5px;
  background: var(--bg-panel); border: 1px solid var(--border-strong);
  border-radius: 10px; box-shadow: 0 12px 34px rgba(0, 0, 0, .34);
  display: flex; flex-direction: column; gap: 1px;
}
.ctx-item {
  display: block; width: 100%; text-align: left;
  border: none; background: transparent; color: var(--text);
  font-family: inherit; font-size: 13px; line-height: 1;
  padding: 8px 10px; border-radius: 6px; cursor: pointer; min-height: 30px;
}
.ctx-item:hover, .ctx-item:focus-visible { background: var(--bg-hover); outline: none; }
.ctx-item.danger:hover { background: var(--danger)1f; color: var(--danger); }
.ctx-sep { height: 1px; margin: 4px 6px; background: var(--border); }

/* the divider is 1px; the grab area is 5px, which is the difference between
   a resizable pane and one that is technically resizable */
.pane-resize { display: none; }
body.is-resizing { cursor: col-resize; user-select: none; }
@media (pointer: fine) and (min-width: 900px) {
  .sidebar, .email-list-pane { position: relative; }
  .pane-resize {
    display: block; position: absolute; top: 0; right: -3px; bottom: 0;
    width: 5px; cursor: col-resize; z-index: 30; background: transparent;
  }
  .pane-resize:hover, .pane-resize:focus-visible {
    background: var(--accent); opacity: .5; outline: none;
  }
  /* a picked row must read as picked without the phone's checkbox column */
  .email-item.picked { background: var(--bg-active); box-shadow: inset 3px 0 0 var(--accent); }
}

/* ============================================================
   v124 — the message list: one row design, both devices
   ------------------------------------------------------------
   The phone's row was decluttered and measured in an earlier pass; the
   desktop's never was, so it kept a third line carrying a "✓ read" chip that
   said the same thing on nine rows out of ten. The declutter was never
   phone-specific reasoning — it was just written inside a phone media query.
   It applies at every width now, and the avatar column below is shared, which
   is why this block is NOT scoped: scoping it was the first attempt, and it
   left the phone with no favicon at all and a stretched empty box where the
   avatar should have been. Measured, caught, unscoped.
   ============================================================ */

/* ---- 1. the declutter, at every width ----
   Read state is already carried by weight and colour (.email-item.read) and
   stays clickable from the hover actions and the right-click menu. The account
   is the coloured left edge, which says it in no space at all. */
.read-chip, .ei-account { display: none; }
.ei-badges { display: none; }
.ei-badges:has(.bk-tag), .ei-badges:has(.ei-brand), .ei-badges:has(svg.ic) {
  display: flex; flex-wrap: wrap; gap: 5px; align-items: center;
}
.email-item { border-left: 3px solid var(--accc, transparent); }
.email-item.selected { border-left-color: var(--accent); }

/* ---- 2. one chip, not four ----
   A row could show a booking tag, a brand pill, an account pill and a read
   chip: four shapes and four colour rules in one 12px strip. Colour now means
   exactly one thing — which account — and it lives on the left edge, so what
   is left can be quiet. */
.ei-badges .bk-tag, .ei-badges .ei-brand {
  font-size: 11px; font-weight: 600; line-height: 18px;
  border-radius: 10px; padding: 0 8px;
  border: 1px solid var(--border-strong);
  background: transparent; color: var(--text-dim);
}

/* ---- 3. the avatar as a column ----
   The favicon used to sit inline inside .ei-from, so it moved with the length
   of the sender's name and the list had no line to scan down. As a fixed
   column it gives the list the rhythm every fast mail client has. A monogram
   sits underneath always — most senders have no favicon, and a letter beats an
   empty square. The row's absolutely-positioned parts (⋮, hover actions, the
   select box) are unaffected by the grid. */
/* Two rows, not three. The third track was reserved for .ei-badges, which
   computes display:none on most rows — but a named grid area still creates its
   track, and `align-items: center` stretched all three equally to fill the
   66px that `contain-intrinsic-size` had reserved as a PLACEHOLDER. Measured on
   a Pixel 8 at 412px: three tracks of 20.66px, row height 91px, avatar sitting
   31px down. That is ~10 rows per screen where ~14 fit.

   The badges row is added back only when a row actually has badges, so it costs
   height on the rows that need it and nothing on the rest. */
.email-item {
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr);
  grid-template-areas: "av top" "av subject";
  grid-auto-rows: auto;
  column-gap: 10px; row-gap: 2px;
  align-items: start;
}
.email-item:has(.ei-badges > *) {
  grid-template-areas: "av top" "av subject" "av badges";
}
/* the avatar spans the text rows rather than being centred against a phantom
   third one, which is what made it hang below the sender name */
.email-item > .ei-av { align-self: center; }
.ei-av { grid-area: av; }
.ei-top { grid-area: top; }
.ei-subject { grid-area: subject; }
.ei-badges { grid-area: badges; }
.ei-av {
  position: relative; display: grid; place-items: center;
  width: 32px; height: 32px; flex: none;
  border-radius: 10px; overflow: hidden;
  background: color-mix(in srgb, var(--accc, var(--accent)) 22%, var(--bg-panel));
}
.ei-mono {
  font-size: 12px; font-weight: 700; letter-spacing: .02em;
  color: color-mix(in srgb, var(--accc, var(--accent)) 75%, var(--text));
  user-select: none;
}
/* the image covers the monogram rather than sitting beside it */
.ei-av .ei-fav {
  position: absolute; inset: 0; width: 100%; height: 100%;
  margin: 0; border-radius: 0; vertical-align: unset;
  object-fit: cover; background: var(--bg-panel);
}
.email-item.read .ei-av { opacity: .72; }
/* select mode puts a checkbox where the avatar is; one of them has to go */
.email-item.sel-mode .ei-av { visibility: hidden; }
/* the setting that already existed, now with something to switch off */
body[data-avatars="off"] .ei-av { display: none; }
body[data-avatars="off"] .email-item {
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas: "top" "subject" "badges";
}

/* two lines instead of three, so the row can be shorter without feeling tight.
   Desktop only: the phone's padding was measured against its own targets. */
@media (min-width: 641px) {
  .email-item { padding-top: 8px; padding-bottom: 8px; contain-intrinsic-size: auto 52px; }
}

/* ---- the avatar has to pay for its width on a phone ----
   Measured at 375px: a 32px avatar plus a 10px gutter plus the 44px ⋮ zone
   left 270px for the text, which wrapped the sender/date header onto a second
   line and pushed the row from 67px to 91px. A column that costs a third of
   the row height is not worth having. Smaller avatar, tighter gap, and the
   left padding it no longer needs. */
@media (max-width: 640px) {
  .email-item { column-gap: 8px; padding-left: 8px; }
  .ei-av { width: 28px; height: 28px; border-radius: 8px; }
  .ei-mono { font-size: 11px; }
  /* the header must never wrap: the date shrinks before the row grows */
  .ei-top { flex-wrap: nowrap; min-width: 0; }
  .ei-from { min-width: 0; flex: 1 1 auto; }
  .ei-date { flex: 0 0 auto; white-space: nowrap; }
}

/* ---- the brand mark ----
   Replaces the serif "Q" seal. A vector, so the same file is the 34px sidebar
   mark and the 512px home-screen icon with no second asset and no blur. The
   pulse the seal had is gone deliberately: a logo that breathes is a logo you
   notice instead of the mail. */
.logo-mark { width: 34px; height: 34px; flex: none; display: block; }

/* ---- a favicon that is not stretched ----
   The image was painted edge-to-edge over the tile, so a 16px favicon (which
   is most of them) was blown up 2-4x and looked soft. It now sits INSET on the
   tile at its own scale, the way a real mail client shows one, and the source
   is requested at 128px so a sharp original stays sharp. The monogram is
   hidden only once an image has actually loaded — .has-fav is set from the
   load event, because CSP blocks the inline handler this used to rely on. */
.ei-av .ei-fav {
  position: absolute; inset: 5px;
  width: calc(100% - 10px); height: calc(100% - 10px);
  object-fit: contain; border-radius: 3px; background: transparent;
}
.ei-av.has-fav { background: var(--bg-hover); }
.ei-av.has-fav .ei-mono { display: none; }
@media (max-width: 640px) { .ei-av .ei-fav { inset: 4px; width: calc(100% - 8px); height: calc(100% - 8px); } }

/* ---- attaching from inside the message window ----
   The paperclip still works, but the place people try to attach a file is the
   message they are writing, not a 44px icon among six controls below a long
   form. The whole compose window is a drop target and the body takes a paste;
   the button is now labelled so it is findable at all. */
.btn-attach { gap: 6px; }
/* The listeners sit on the backdrop so a drop near the window edge still
   counts, so the class lands on the backdrop too — the overlay is drawn on
   the inner panel. Getting this pair wrong is silent: the drop still works,
   nothing ever appears. */
.compose-modal { position: relative; }
.modal-backdrop.is-dropping .compose-modal::after {
  content: 'Drop files to attach';
  position: absolute; inset: 8px; z-index: 5;
  display: grid; place-items: center;
  font-size: 15px; font-weight: 600; color: var(--accent);
  background: color-mix(in srgb, var(--bg-panel) 88%, transparent);
  border: 2px dashed var(--accent); border-radius: 10px;
  pointer-events: none;
}

.compose-atts:empty { display: none; }
.compose-att-chip {
  display: inline-flex; align-items: center; gap: 6px;
  margin: 4px 6px 0 0; padding: 4px 6px 4px 10px;
  border: 1px solid var(--border-strong); border-radius: 20px;
  font-size: 13px; color: var(--text); max-width: 100%;
}
.compose-att-chip i { color: var(--text-dim); font-style: normal; font-size: 12px; }
.compose-att-chip .ca-x {
  border: none; background: transparent; color: var(--text-dim);
  cursor: pointer; font-size: 16px; line-height: 1;
  min-width: 28px; min-height: 28px; border-radius: 50%;
}
.compose-att-chip .ca-x:hover { background: var(--bg-hover); color: var(--accent); }

/* ---- attachments named by kind, not by filename ----
   "Q3-final-v2-REALLY-final.xlsx" tells you nothing at a glance and pushes the
   size off the chip. The kind and the weight are what you scan for; the name
   lives in the tooltip and is still what the file downloads as. */
.compose-att-chip .fk, .attachment-chip .fk {
  font-size: 10px; font-weight: 700; letter-spacing: .06em;
  padding: 2px 6px; border-radius: 6px;
  background: var(--accent-soft); color: var(--accent);
}
.compose-att-chip i, .attachment-chip i {
  font-style: normal; font-size: 12px; color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.attachment-chip { display: inline-flex; align-items: center; gap: 7px; }

/* ---- the sibling app's mark, in each app ---- */
.app-link { display: inline-flex; align-items: center; gap: 8px; }
.app-link img { display: block; flex: none; }

/* ---- the message body: neutral paper, and nothing else done to it ----
   Three attempts landed here. Inverting it in dark mode broke real mail.
   Dimming it with a filter washed it out. Both were the app imposing itself on
   a document it did not author. What is left does nothing to the message at
   all: no filter, no colour cast, no inversion. It sits on a NEUTRAL near-white
   card -- not pure white, which was the original complaint, and not a warm
   cream either, which read as a tint. Paper and ink. */
/* The sender's HTML sits on #f4f4f5 against a #f7f5f0 app ground — measured at
   1.01:1, i.e. pixel-indistinguishable. Anything the sender draws reads as part
   of Qmail, so a convincing fake "Qmail" dialog costs them nothing. The frame is
   sandboxed and script cannot run, but the VISUAL half of that boundary was
   missing. A real edge at 3:1 says where the app stops and the message starts.
   The paper colour itself stays: it was chosen for readability and is right. */
.viewer-html-frame, .viewer-text {
  background: #f4f4f5; border-radius: 8px;
  border: 1px solid var(--border-strong);
}
.viewer-text {
  color: #1b1b1d; padding: 14px 16px;
  white-space: pre-wrap; overflow-wrap: anywhere;
}

/* ============================================================
   One control system (v134) — the same pass Qalendar had
   ------------------------------------------------------------
   Measured at 375px, Quriou Mail was carrying SEVEN corner radii across its
   controls (0, 5, 6, 7, 8, 9, 10) and label sizes from 12 to 14 on buttons
   sitting in the same row. The 44px work from earlier passes held — heights
   were right — but nothing had ever made the shapes agree.

   The radius is 10px, which is Qalendar's, because the two apps now share a
   mark and should share a control language. Icon buttons keep their glyph
   size: folding them into the shared label size is exactly the regression
   that pass caught in the calendar, where arrows and the close cross dropped
   from 19px to 13px.
   ============================================================ */
:root { --ctl-radius: 10px; --ctl-label: 13px; }

.btn, .btn-ghost, .btn-primary, .icon-btn, .cal-tab, .auth-tab, .auth-alt,
.seg button, .range-tabs button, .smart-tabs button, .smart-tab, .sq-btn,
.sheet-item, .account-menu-item, .read-chip, .ub-undo, .row-more,
.apps-manage-btn, .mm-state, select, .sort-select, .view-select {
  border-radius: var(--ctl-radius);
}
/* labels: one size for anything that reads as a button */
.btn, .btn-ghost, .btn-primary, .cal-tab, .auth-tab, .auth-alt,
.seg button, .range-tabs button, .smart-tabs button, .smart-tab,
.sheet-item, .account-menu-item, .apps-manage-btn {
  font-size: var(--ctl-label);
}
/* width is a target too — these measured 29px and 9px wide */
.smart-tab, .sq-btn, .cal-tab, .auth-tab, .seg button { min-width: 44px; }

/* Text fields were the one group with no shape at all: a bare input measured
   0px radius against buttons at 6-10. The search field is deliberately
   excluded — it is a borderless field inside its own rounded shell, and
   rounding it again draws a box inside a box. */
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
textarea, select {
  border-radius: var(--ctl-radius);
}
.searchbar input { border-radius: 0; }

/* Text fields that draw their own box get a real height. Measured at 375px, a
   settings field was 22px tall — the browser default — against a 44px minimum
   every button meets. The transparent ones are excluded and keep their
   shell.s height: the search field and the compose rows are borderless inputs
   inside their own container, and giving them a box would draw a box in a box. */
input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]),
textarea, select {
  min-height: 44px;
}
.searchbar input, .compose-row input, .compose-body, textarea { min-height: 0; }
.searchbar input, .compose-row input { border-radius: 0; }

/* small labels stay small: a tag is not a control, and making it one would
   turn a glanceable strip into a row of buttons */
.bk-tag, .compose-att-chip .fk, .attachment-chip .fk, .ei-account { border-radius: 6px; }

/* ---- the maker's mark ----
   Quiet on purpose: a signature belongs at the edge of a thing, not in the
   middle of it. Full weight on the sign-in card, where a product introduces
   itself, and a smaller one resting beside the version in the footer. */
.by-line {
  font-size: 12px; color: var(--text-dim);
  letter-spacing: .08em; text-transform: uppercase; margin-top: 2px;
}
.by-line b { font-weight: 700; color: var(--text); letter-spacing: .12em; }
.by-line-sm { margin-left: auto; }
.by-line-sm b { font-weight: 600; color: var(--text-dim); }

/* ---- About ---- */
.about-line { font-size: 14px; color: var(--text); margin-bottom: 4px; }
.about-line b { font-weight: 700; }
.about-meta { font-size: 13px; color: var(--text-dim); font-variant-numeric: tabular-nums; }

/* ---- the maker's mark: QENTRA's own lockup ----
   Two files, not one recoloured: the brand ships a dark-ink version for light
   grounds and a reverse for dark ones, and a logo is the last thing that
   should be approximated with a filter. Both are in the page and the theme
   decides which is shown, so there is no flash of the wrong one while a
   script works out the theme. */
.by-line { display: flex; align-items: center; gap: 7px; }
.by-line > span { font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--text-dim); }
.qentra-logo { height: 17px; width: auto; display: block; }
.by-line-sm .qentra-logo { height: 13px; }
.by-line-sm > span { font-size: 10px; }
/* light is the default; dark wins where the theme says so */
.q-on-dark { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .q-on-light { display: none; }
  :root:not([data-theme="light"]) .q-on-dark { display: block; }
}
:root[data-theme="dark"] .q-on-light { display: none; }
:root[data-theme="dark"] .q-on-dark { display: block; }
:root[data-theme="light"] .q-on-light { display: block; }
:root[data-theme="light"] .q-on-dark { display: none; }

/* ============================================================
   TOUCH TARGETS FOR THE PHONE THIS IS ACTUALLY USED ON
   ============================================================
   Measured, not assumed. The access log says the device is a Pixel 8 on
   Android 14 / Chrome 148 -- a 412 x 915 CSS viewport. On Android the
   guidance is 48dp, not the 44px this app had settled on, which is Apple's
   number. Measuring all 36 controls at 412px: twenty-five sat at exactly 44,
   ten sat BELOW it, and one was 46. Nothing reached 48.

   The ten under 44 were not sloppiness so much as arithmetic: the floor was
   written as `.btn { min-height: 44px }` at specificity 0,1,0, so every
   `.tc-actions .btn { min-height: 32px }` at 0,2,0 beat it no matter where it
   appeared in the file. Raising the floor alone would have missed all ten
   again, so each is named here.

   Guarded on `pointer: coarse` so it applies to the phone and leaves the
   desktop layout -- which was deliberately made dense -- exactly as it was. */
@media (pointer: coarse) {

  /* the floor */
  .btn, .btn-ghost, .btn-primary, .icon-btn, .icon-btn.tb,
  .cal-tab, .auth-tab, .auth-alt, .smart-tab, .sq-btn, .sheet-item,
  .account-menu-item, .account-btn, .folder-item, .dock-btn, .viewer-fab,
  .apps-manage-btn, .compose-btn, .menu-btn, .ai-ask-btn, .danger-btn,
  .btn-attach, .ub-undo,
  .seg button, .range-tabs button, .smart-tabs button {
    min-height: 48px;
  }
  .icon-btn, .icon-btn.tb, .menu-btn, .viewer-fab,
  .seg button, .range-tabs button, .smart-tabs button,
  .cal-tab, .auth-tab, .smart-tab, .sq-btn {
    min-width: 48px;
  }

  /* the ten that a more specific rule was holding under the floor */
  .tc-actions .btn,
  .img-banner .btn,
  .mm-ctl .btn,
  .mm-ctl .icon-btn,
  .bulk-bar .btn,
  .push-banner .btn,
  .later-custom .btn,
  .sidebar .folder-item,
  .sidebar .account-menu-item,
  .sidebar .apps-manage-btn,
  .sidebar .compose-btn,
  .app-manage-actions .icon-btn,
  .sr-item .icon-btn,
  .cal-nav .icon-btn,
  .viewer-toolbar .icon-btn,
  .viewer-toolbar .icon-btn.tb,
  .event-actions .btn-ghost,
  .event-actions .btn-primary,
  .account-add-form .btn-ghost,
  .ai-chip, .ai-reply, .attachment-chip,
  .attachment-wrap .attachment-chip,
  .sheet-list .sheet-item, .sheet-quick .sq-btn {
    min-height: 48px;
  }
  .mm-ctl .icon-btn, .app-manage-actions .icon-btn, .sr-item .icon-btn,
  .cal-nav .icon-btn, .viewer-toolbar .icon-btn,
  .viewer-toolbar .icon-btn.tb {
    min-width: 48px; width: auto; height: auto;
  }

  /* The remove-attachment cross was 28px, inside a 29px chip: two overlapping
     targets in under thirty pixels, and the smaller of the two is the one that
     destroys work. Both go to the floor. */
  .compose-att-chip { min-height: 48px; padding: 4px 4px 4px 12px; }
  .compose-att-chip .ca-x { min-width: 44px; min-height: 44px; }

  /* Material's spacing is 8dp. Two pixels between two 30px controls was the
     likeliest source of a wrong tap anywhere in the app. */
  .mm-ctl { gap: 8px; }
  .tc-actions, .img-banner, .compose-att-list, .attachment-wrap { gap: 8px; }

  /* 12px control labels are below Android's guidance and were the reason some
     of these boxes were small in the first place */
  .btn, .btn-ghost, .btn-primary, .bulk-bar .btn, .tc-actions .btn,
  .img-banner .btn, .mm-ctl .btn, .push-banner .btn, .ai-chip,
  .compose-att-chip, .folder-item, .account-menu-item, .apps-manage-btn {
    font-size: 13px;
  }

  /* the update bar shrank itself to 32px under 420px wide -- which is exactly
     the width of this phone, so the one control that appears when something
     needs doing was the smallest on the screen */
  .update-bar .btn { min-height: 48px !important; }
  .update-bar .icon-btn { min-width: 48px !important; min-height: 48px !important; }
}

/* Four survived the block above, each beaten on specificity by a rule written
   earlier. Named at the specificity that actually wins, rather than raising
   the whole block to !important and losing the ability to see why. */
@media (pointer: coarse) {
  .topbar .menu-btn { min-height: 48px; min-width: 48px; }
  .viewer-toolbar .icon-btn,
  .viewer-toolbar .icon-btn.tb { min-height: 48px; height: auto; }
  /* this one was already !important, so it takes an !important to move */
  .sidebar .apps-manage-btn,
  .apps-manage-btn { min-height: 48px !important; font-size: 13px; }
  /* the cross now matches the chip it sits in, rather than being the smallest
     and most destructive target on the screen */
  .compose-att-chip .ca-x { min-width: 48px; min-height: 48px; }
}

/* `.viewer-toolbar .icon-btn { min-height: 44px !important }` from an earlier
   pass ties on specificity and wins on !important, so this one has to match it.
   And the two sidebar rows carry their own 12.5px, below Android's guidance. */
@media (pointer: coarse) {
  .viewer-toolbar .icon-btn,
  .viewer-toolbar .icon-btn.tb { min-height: 48px !important; }
  .sidebar .folder-item,
  .sidebar .account-menu-item { font-size: 13px; }
}

/* ============================================================
   THE TABLET / SPLIT-WINDOW GAP
   ============================================================
   The rule that hides the message list while reading lives inside
   `@media (max-width: 640px)`, and so does the off-canvas sidebar. Between
   641px and ~1000px the app therefore kept all three panes: measured live at
   768x1024 with a message open, sidebar 240 + list 320 + viewer 208 — and
   after the viewer's own 32px side padding that is 144px of text. That is iPad
   portrait, and any half-screen window on a desktop.

   Reading is the whole point of those widths, so below 1024px the list gets
   out of the way while a message is open, exactly as it does on a phone. */
@media (min-width: 641px) and (max-width: 1024px) {
  .content.viewing .email-list-pane { display: none; }
  .content.viewing .email-viewer-pane { flex: 1 1 auto; min-width: 0; }
}

/* --text-dim was tuned against --bg only (4.53:1). The selected row sits on
   --bg-active and the hovered row on --bg-hover, where the same colour
   measured 3.89:1 and 4.22:1 — so the row you have open and the row under the
   cursor were the two least legible rows in the list. The background already
   carries the state; the text does not need to be dimmed as well. */
.email-item.selected.read .ei-from,
.email-item.selected.read .ei-subject,
.email-item.picked.read .ei-from,
.email-item.picked.read .ei-subject { color: var(--text); }
@media (hover: hover) {
  .email-item:hover.read .ei-from,
  .email-item:hover.read .ei-subject { color: var(--text); }
}

/* white-on-accent at 3.30:1 in dark — these two segmented controls were missed
   by the pass that fixed the other six, because they sit at specificity 0,2,1 */
.range-tabs button.is-on,
.seg button.is-on { background: var(--accent-strong); }

/* ============================================================
   VISUAL SYSTEM — v147
   ============================================================
   From the measured audit. The finding underneath all of this: panels sat at
   1.09:1 against the page and default borders at 1.22:1, so grouping was
   invisible and the app compensated with heavy type — 22 font sizes and 37
   uses of 700-weight. Boundaries and weight are one problem, so they are
   fixed together. Touch targets (48dp) are already correct and untouched.

   Deliberately NOT repainting the surfaces: on a light ground the panel is
   already #ffffff and cannot go lighter, so separation has to come from a
   border that can actually be seen. That is a smaller, safer change than
   restating every background in the app.
   ============================================================ */
/* The light tokens at the top of this file are declared on
   `:root[data-theme="light"]` (specificity 0,2,0), so a plain `:root` here
   loses to them — which is exactly what happened on the first attempt: the dark
   overrides applied and the light ones silently did not. Match the specificity
   rather than reach for !important. */
:root, :root[data-theme="light"] {
  /* VIS-13 — a spacing ramp. Used by the rules below; adopting it everywhere
     is a separate, larger job. */
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 24px; --sp-6: 32px;

  /* VIS-02 — six steps, no half-pixels. Half-pixel sizes also fail to survive
     the zoom setting cleanly. */
  --fs-xs: 11px;   /* badges, timestamps */
  --fs-sm: 12px;   /* dense metadata */
  --fs-md: 13px;   /* control labels, body of lists */
  --fs-lg: 15px;   /* message subject, primary row text */
  --fs-xl: 18px;   /* section headings */
  --fs-2xl: 22px;  /* page titles */

  /* VIS-07 — four shapes with meaning: chip, control, card, pill. */
  --r-chip: 6px; --r-ctl: 10px; --r-card: 16px; --r-pill: 999px;

  /* VIS-01 — a border that is actually visible. 1.22:1 was decorative. */
  --border: #cdc6b6;
  /* VIS-04 — secondary text on a raised surface. --text-dim was tuned against
     the page only, so it measured 4.22:1 on a hovered row and 3.89:1 on a
     selected one: the two rows you interact with were the least readable. */
  --text-dim-raised: #5f5b50;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --border: #494339;
    --text-dim-raised: #a8a294;
  }
}
:root[data-theme="dark"] {
  --border: #494339;
  --text-dim-raised: #a8a294;
}

/* VIS-06 — in light theme --accent and --accent-strong were the SAME value,
   so a filled primary button and a text link carried identical weight. */
:root, :root[data-theme="light"] { --accent-strong: #0d4049; }

/* VIS-04 applied: raised rows use the raised token wherever dimmed text lands */
.email-item:hover .ei-date,
.email-item.selected .ei-date,
.email-item.picked .ei-date,
.email-item:hover .ei-badges,
.email-item.selected .ei-badges { color: var(--text-dim-raised); }

/* VIS-01 applied: panels state their edge instead of relying on fill */
.modal, .action-sheet, .sheet, .card, .tc-card, .stat-card {
  border: 1px solid var(--border);
}

/* ---- VIS-03: weight discipline ----
   700 was used 37 times and 400 three times, so bold was the default and
   emphasis had nothing to push against. 600 carries headings and unread mail;
   700 is reserved for the one thing that must win on a screen. Unread mail
   keeps the most weight in the list, because that is the whole job of the
   list. */
.login-card h1, .logo-text, .list-title, .ag-date,
.modal-header, .sheet-head, .set-block h3,
.viewer-subject, .tc-from, .stat-value {
  font-weight: 600;
}
.email-item.unread .ei-from,
.email-item.unread .ei-subject { font-weight: 600; }
.email-item.read .ei-from,
.email-item.read .ei-subject { font-weight: 400; }

/* ---- VIS-08: the 641–899px band ----
   Phone rules stop at 640 and desktop density starts at 900, so between them
   the sidebar stayed PINNED at 240px — on a 768px half-screen window that is a
   third of the width spent on navigation. The drawer behaviour already exists
   for phones; it simply never reached this band. */
@media (min-width: 641px) and (max-width: 899px) {
  .sidebar {
    position: fixed; top: 0; left: 0; bottom: 0; z-index: 60;
    width: 280px; max-width: 86vw;
    transform: translateX(-100%); transition: transform .22s ease;
    box-shadow: var(--shadow);
  }
  .sidebar.open { transform: translateX(0); }
  .menu-btn { display: inline-flex !important; }
  .content { margin-left: 0 !important; }
}
@media (prefers-reduced-motion: reduce) {
  @media (min-width: 641px) and (max-width: 899px) { .sidebar { transition: none; } }
}

/* ---- VIS-09: one floating button ----
   Smart Inbox and Compose both floated in the same corner, and one already had
   to hide on scroll to stop covering a chip. The topbar has carried a Smart
   Inbox button (#btn-smart-top) all along, so the FAB was a duplicate of a
   control that was already reachable. Compose stays: it is what people came
   to do. */
@media (pointer: coarse), (max-width: 899px) {
  .smart-fab { display: none !important; }
}
