/* ========================================================================
   2maXMail — Editorial Office Design System
   A refined, paper-and-ink aesthetic. Serif display, precise sans UI.
   ======================================================================== */

/* Fonts are vendored under /vendor/fonts — a self-hosted mail server must not
   depend on a third-party CDN being reachable to render its own UI. */
@import url('/vendor/fonts.css');

:root {
  /* Tells the browser which way its own chrome should render — form controls,
     scrollbars, the canvas behind the page. The dark palette flips it. */
  color-scheme: light;

  /* — Ink & paper — */
  --ink:         #1A1814;
  --ink-soft:    #2F2C26;
  --muted:       #736E65;
  --muted-soft:  #A8A296;

  /* — Surfaces — */
  --paper:       #F6F2EB;
  /* The wordmark is a fixed-colour raster: its letters are #401f0f, drawn to
     sit on a light ground. No dark background can carry that brown — lightening
     one moves it toward the letters' own luminance before it moves away
     (1.33:1 on --paper, 1.02:1 at #332E24). logo-dark.svg is the same artwork
     with only those letters recoloured; the envelope and X are untouched. */
  --logo-src: url('/img/logo.svg');
  --paper-deep:  #EEE9DF;
  --surface:     #FFFFFF;
  --surface-alt: #FBF9F4;
  /* Recessed panels — the settings sidebar, inset help blocks, the queue's
     diagnosis row. Seven places across three files asked for --surface-2 and
     nothing ever defined it, so every one of them rendered with no background
     at all. It is the same step down as --surface-alt; named separately
     because that is the name the markup already uses. */
  --surface-2:   var(--surface-alt);

  /* — On an inverted bar —
     A few surfaces paint themselves `background: var(--ink)` and write in
     --paper: the compose header, the toast, the chart tooltip. Their own
     secondary tints were literal rgba(246,242,235,…), which is paper — and so
     turns invisible the moment ink and paper swap. */
  --on-ink:       rgba(246,242,235,.7);
  --on-ink-faint: rgba(246,242,235,.5);
  --on-ink-wash:  rgba(246,242,235,.12);

  /* Hover wash for controls sitting on a tinted bar, where a token background
     would hide the tint underneath. Black on light, white on dark. */
  --wash:        rgba(0,0,0,.06);

  /* — Lines & dividers — */
  --line:        #E5E0D2;
  --line-soft:   #EEEADD;
  --line-strong: #C9C3B1;

  /* — Accent: brand orange (matches logo gradient) — */
  --accent:         #F07C3D;
  --accent-deep:    #C85E1F;
  --accent-soft:    #FCE7D6;
  --accent-hover:   #D86825;

  /* — Accent that has to carry text —
     The brand orange is a 2.74:1 pair with white, and the same 2.74:1 as text
     on the page. It stays exactly as it is for the logo, borders, dots and
     focus rings, where nothing has to be read off it. These three are for the
     places a word sits on or in the orange:
       --accent-fill  the button ground   (white label → 5.17:1)
       --on-accent    the label on it
       --accent-ink   accent-coloured text on the page (→ 4.63:1 on paper)
     Light darkens the orange and keeps a white label; dark keeps the brand
     orange and puts ink on it (6.65:1), because a dark page can afford it. */
  --accent-fill:    #B05217;
  --on-accent:      #FFFFFF;
  --accent-ink:     #B05217;

  /* — Signal: warm amber (flags, stars, OOO) — */
  --signal:         #F4A020;
  --signal-soft:    #FDEED1;

  /* — Status —
     Each has a soft tint for backgrounds and a deep shade for text on that
     tint. Only the base was defined before, so every chip, hover and badge
     that needed a wash mixed its own — six near-identical pinks for danger
     alone. */
  --success:      #2F7A4E;
  --success-soft: #E3EEE5;
  --success-deep: #3C6B4A;

  --warning:      #B37A0E;
  --warning-soft: #F7EBD0;

  --danger:       #9F2A2A;
  --danger-soft:  #F7E4E4;
  --danger-deep:  #9C3A26;

  --info:         #2A5C8C;
  --info-soft:    #DCE8F4;

  /* — Status washes written inline —
     admin-app, login and setup each hardcoded these pastels next to a token
     foreground; the pair only holds together while the tokens are dark. */
  --tint-danger:       #F7E8E8;
  --tint-danger-line:  #EBD0D0;
  --tint-success:      #E8F5EF;
  --tint-success-line: #9FCFB4;
  --tint-success-ink:  #1A5D3E;
  --tint-warn:         #FDF2D5;
  --tint-warn-ink:     #8A5A0C;
  --tint-alert:        #FFF3DE;
  --tint-alert-ink:    #8A5A00;

  /* — Chart series —
     Validated against the surface they sit on, per mode. See charts.js. */
  --chart-primary:   #1F5FA8;
  --chart-secondary: #C85E1F;
  --chart-danger:    #9F2A2A;

  /* — Note cards —
     Eight paper tints. They carry --ink text, so a dark palette needs its own
     set rather than an opacity trick over the light one. */
  --note-yellow: #FBF2CE;
  --note-sage:   #DDE7D8;
  --note-coral:  #F4D9CF;
  --note-sky:    #D8E3EE;
  --note-lilac:  #E4DBEA;
  --note-clay:   #EADFD1;
  --note-rose:   #F2DCDF;
  --note-paper:  #F1ECDF;
  --note-pin:    rgba(26,24,20,.45);

  /* — Type — */
  --font-display: 'Fraunces', 'Iowan Old Style', Georgia, serif;
  --font-ui:      'Manrope', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono:    'JetBrains Mono', ui-monospace, 'SFMono-Regular', monospace;

  /* — Type scale —
     The UI had grown 22 distinct font sizes, several of them a half-pixel
     apart and expressed inline. These eight are the sizes that carry a role;
     anything else drifted. Ratios are loose rather than a strict modular
     scale — the small end needs finer steps than the display end.

     Text size is a per-user preference, and --font-scale is the single value
     it moves: every step below is a multiple of it, so one attribute on
     <html> resizes everything that reads through the scale. */
  --font-scale: 1;
  --text-2xs:  calc(10.5px * var(--font-scale));   /* mono meta, keycaps */
  --text-xs:   calc(11.5px * var(--font-scale));   /* eyebrows, table headers, field labels */
  --text-sm:   calc(12.5px * var(--font-scale));   /* secondary and supporting copy */
  --text-base: calc(13.5px * var(--font-scale));   /* buttons, table cells — the UI default */
  --text-md:   calc(14.5px * var(--font-scale));   /* body and reading copy */
  --text-lg:   calc(17px * var(--font-scale));     /* card and dialog titles */
  --text-xl:   calc(22px * var(--font-scale));     /* panel titles */
  --text-2xl:  calc(26px * var(--font-scale));     /* sub-headings under a section title */

  /* — Spacing —
     A 4px base. Panels, dialogs and section heads all landed on their own
     near-miss values (20/22/24/26); these are the steps to reach for. */
  --space-1:  4px;
  --space-2:  8px;
  --space-3:  12px;
  --space-4:  16px;
  --space-5:  20px;
  --space-6:  24px;
  --space-8:  32px;
  --space-10: 40px;

  /* — Geometry — */
  --radius-xs: 3px;
  --radius-sm: 6px;
  --radius-md: 10px;
  --radius-lg: 16px;
  --radius-xl: 24px;

  /* — Motion — */
  --ease:      cubic-bezier(.22,.61,.36,1);
  --ease-out:  cubic-bezier(.16,1,.3,1);

  /* — Shadows: paper-like, not synthetic — */
  --shadow-sm: 0 1px 2px rgba(64,31,15,.05), 0 0 0 1px rgba(64,31,15,.04);
  --shadow-md: 0 2px 4px rgba(64,31,15,.06), 0 8px 24px rgba(64,31,15,.06);
  --shadow-lg: 0 10px 40px rgba(64,31,15,.09), 0 2px 8px rgba(64,31,15,.04);
  --shadow-pop: 0 20px 60px rgba(64,31,15,.15), 0 4px 16px rgba(64,31,15,.08);
}

/* ========================================================================
   Dark palette

   Same editorial character — warm charcoal rather than neutral grey, so the
   serif still reads as ink on paper rather than terminal green. The roles
   invert: `--paper` is now the darkest surface and `--surface` sits a step
   *above* it, because a card in the dark must catch light, not lose it.
   Every soft/deep pair swaps ends — a `-soft` becomes a deep tint to sit
   behind text, a `-deep` becomes the light foreground that goes on it.

   Two selectors carry the identical block:
     · the OS preference, unless the user has explicitly asked for light;
     · an explicit `data-theme="dark"`, which wins on a light OS.
   The explicit rule is second so it takes the tie on equal specificity.
   CSS has no way to share one declaration list across a media query and a
   plain selector, so the two must be edited together.
   ======================================================================== */

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --ink:         #F2EDE3;
    --ink-soft:    #D8D2C6;
    --muted:       #A39C8E;
    --muted-soft:  #7A7466;

    --paper:       #17150F;
    --logo-src: url('/img/logo-dark.svg');
    --paper-deep:  #272319;
    --surface:     #1E1B15;
    --surface-alt: #24211A;
    --surface-2:   var(--surface-alt);

    --on-ink:       rgba(26,24,20,.72);
    --on-ink-faint: rgba(26,24,20,.55);
    --on-ink-wash:  rgba(26,24,20,.12);
    --wash:         rgba(255,255,255,.08);

    --line:        #332E24;
    --line-soft:   #272319;
    --line-strong: #55503F;

    --accent:         #F07C3D;
    --accent-deep:    #F2A575;
    --accent-soft:    #3B2314;
    --accent-hover:   #F4925E;

    --accent-fill:    #F07C3D;
    --on-accent:      #17150F;
    --accent-ink:     #F2A575;

    --signal:         #F4A020;
    --signal-soft:    #3A2B0F;

    --success:      #5BAE7C;
    --success-soft: #1E3025;
    --success-deep: #8ECBA6;

    --warning:      #D8A33A;
    --warning-soft: #352A13;

    /* Light enough to read on the page, dark enough that .btn-danger keeps
       its white label legible. */
    --danger:       #D9605A;
    --danger-soft:  #3A211F;
    --danger-deep:  #EE9C97;

    --info:         #6EA8DC;
    --info-soft:    #1E2C3A;

    --tint-danger:       #3A211F;
    --tint-danger-line:  #5A302C;
    --tint-success:      #1E3025;
    --tint-success-line: #37503F;
    --tint-success-ink:  #8ECBA6;
    --tint-warn:         #352A13;
    --tint-warn-ink:     #D8A33A;
    --tint-alert:        #33280F;
    --tint-alert-ink:    #E0AE55;

    --chart-primary:   #3A7BC4;
    --chart-secondary: #C85E1F;
    --chart-danger:    #C9564E;

    --note-yellow: #37301A;
    --note-sage:   #223026;
    --note-coral:  #3A2820;
    --note-sky:    #1F2A36;
    --note-lilac:  #2B2436;
    --note-clay:   #332A1E;
    --note-rose:   #372329;
    --note-paper:  #2A2620;
    --note-pin:    rgba(242,237,227,.5);

    /* Warm brown shadows vanish on a dark page; these are cast in black. */
    --shadow-sm: 0 1px 2px rgba(0,0,0,.4), 0 0 0 1px rgba(0,0,0,.35);
    --shadow-md: 0 2px 4px rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.4);
    --shadow-lg: 0 10px 40px rgba(0,0,0,.5), 0 2px 8px rgba(0,0,0,.35);
    --shadow-pop: 0 20px 60px rgba(0,0,0,.6), 0 4px 16px rgba(0,0,0,.4);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;

  --ink:         #F2EDE3;
  --ink-soft:    #D8D2C6;
  --muted:       #A39C8E;
  --muted-soft:  #7A7466;

  --paper:       #17150F;
  --logo-src: url('/img/logo-dark.svg');
  --paper-deep:  #272319;
  --surface:     #1E1B15;
  --surface-alt: #24211A;
  --surface-2:   var(--surface-alt);

  --on-ink:       rgba(26,24,20,.72);
  --on-ink-faint: rgba(26,24,20,.55);
  --on-ink-wash:  rgba(26,24,20,.12);
  --wash:         rgba(255,255,255,.08);

  --line:        #332E24;
  --line-soft:   #272319;
  --line-strong: #55503F;

  --accent:         #F07C3D;
  --accent-deep:    #F2A575;
  --accent-soft:    #3B2314;
  --accent-hover:   #F4925E;

  --accent-fill:    #F07C3D;
  --on-accent:      #17150F;
  --accent-ink:     #F2A575;

  --signal:         #F4A020;
  --signal-soft:    #3A2B0F;

  --success:      #5BAE7C;
  --success-soft: #1E3025;
  --success-deep: #8ECBA6;

  --warning:      #D8A33A;
  --warning-soft: #352A13;

  --danger:       #D9605A;
  --danger-soft:  #3A211F;
  --danger-deep:  #EE9C97;

  --info:         #6EA8DC;
  --info-soft:    #1E2C3A;

  --tint-danger:       #3A211F;
  --tint-danger-line:  #5A302C;
  --tint-success:      #1E3025;
  --tint-success-line: #37503F;
  --tint-success-ink:  #8ECBA6;
  --tint-warn:         #352A13;
  --tint-warn-ink:     #D8A33A;
  --tint-alert:        #33280F;
  --tint-alert-ink:    #E0AE55;

  --chart-primary:   #3A7BC4;
  --chart-secondary: #C85E1F;
  --chart-danger:    #C9564E;

  --note-yellow: #37301A;
  --note-sage:   #223026;
  --note-coral:  #3A2820;
  --note-sky:    #1F2A36;
  --note-lilac:  #2B2436;
  --note-clay:   #332A1E;
  --note-rose:   #372329;
  --note-paper:  #2A2620;
  --note-pin:    rgba(242,237,227,.5);

  --shadow-sm: 0 1px 2px rgba(0,0,0,.4), 0 0 0 1px rgba(0,0,0,.35);
  --shadow-md: 0 2px 4px rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.4);
  --shadow-lg: 0 10px 40px rgba(0,0,0,.5), 0 2px 8px rgba(0,0,0,.35);
  --shadow-pop: 0 20px 60px rgba(0,0,0,.6), 0 4px 16px rgba(0,0,0,.4);
}

/* ——— Reset & baseline ——— */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
html { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
body {
  font-family: var(--font-ui);
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--paper);
  font-feature-settings: 'ss01' on, 'cv11' on;
  overflow: hidden;
}

button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: 0; padding: 0; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 2px; }

/* ——— Grain texture overlay: paper feel ——— */
.grain::before {
  content: '';
  position: absolute; inset: 0;
  pointer-events: none;
  opacity: .35;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.1 0 0 0 0 0.1 0 0 0 0 0.08 0 0 0 0.08 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
  background-size: 240px 240px;
}

/* ——— Typography utilities ——— */
.font-display { font-family: var(--font-display); font-weight: 400; letter-spacing: -.01em; }
.font-mono    { font-family: var(--font-mono); }

.display-1 { font-family: var(--font-display); font-size: clamp(48px, 7vw, 96px); line-height: 1; letter-spacing: -.02em; }
.display-2 { font-family: var(--font-display); font-size: clamp(32px, 4vw, 56px); line-height: 1.02; letter-spacing: -.015em; }
.display-3 { font-family: var(--font-display); font-size: clamp(24px, 2.5vw, 32px); line-height: 1.1; letter-spacing: -.01em; }

.eyebrow {
  font-family: var(--font-ui);
  font-size: var(--text-xs); font-weight: 500;
  text-transform: uppercase;
  letter-spacing: .14em;
  color: var(--muted);
}

/* Roles that were being written inline, each at two or three sizes. Naming
   them once is what keeps the next screen consistent with this one. */

/* Supporting text: hints, counts, timestamps, the line under a title. */
.meta { font-size: var(--text-sm); color: var(--muted); }
.meta-sm { font-size: var(--text-xs); color: var(--muted); }

/* Machine-readable values — keys, hostnames, hashes, sizes. */
.mono { font-family: var(--font-mono); font-size: var(--text-sm); }
.mono-sm { font-family: var(--font-mono); font-size: var(--text-2xs); }
.mono-break { word-break: break-all; }

/* Serif titles inside a panel or card, below the page's own <h1>. */
.panel-title {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 600;
  letter-spacing: -.01em;
}
.panel-title-sm { font-size: var(--text-lg); }

/* Dialog headings — serif, regular weight, sitting under an eyebrow. */
.dlg-title {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  margin-top: var(--space-1);
}

/* The accent full stop that ends every section heading. */
.stop { color: var(--accent); font-style: italic; }

/* Centred "nothing here yet" copy inside a panel. */
.empty-note {
  padding: var(--space-10);
  text-align: center;
  color: var(--muted);
  font-size: var(--text-base);
}

/* ——— Buttons ——— */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 38px; padding: 0 16px;
  border-radius: var(--radius-sm);
  font-weight: 500; font-size: var(--text-base);
  letter-spacing: -.005em;
  transition: all .18s var(--ease);
  white-space: nowrap;
  border: 1px solid transparent;
}
.btn svg { width: 16px; height: 16px; stroke-width: 1.5; flex: none; }

.btn-primary { background: var(--ink); color: var(--paper); }
.btn-primary:hover { background: var(--accent-fill); color: var(--on-accent); }

.btn-accent { background: var(--accent-fill); color: var(--on-accent); }
.btn-accent:hover { filter: brightness(1.08); }

.btn-ghost { color: var(--ink); }
.btn-ghost:hover { background: var(--paper-deep); }

.btn-outline { border-color: var(--line-strong); color: var(--ink); background: var(--surface); }
.btn-outline:hover { border-color: var(--ink); background: var(--paper-deep); }

.btn-danger { background: var(--danger); color: #fff; }
.btn-danger:hover { filter: brightness(.95); }

.btn-sm { height: 30px; padding: 0 12px; font-size: var(--text-sm); }
.btn-sm svg { width: 14px; height: 14px; }
.btn-icon { width: 34px; padding: 0; }

/* ——— Inputs ——— */
.field {
  display: flex; flex-direction: column; gap: 6px;
}
.field-label {
  font-size: var(--text-sm); font-weight: 500;
  color: var(--muted); letter-spacing: .02em;
}
.input, .select, .textarea {
  width: 100%;
  height: 40px; padding: 0 12px;
  border: 1px solid var(--line-strong);
  background: var(--surface);
  border-radius: var(--radius-sm);
  transition: border-color .16s var(--ease), box-shadow .16s var(--ease);
  color: var(--ink);
}
.textarea { height: auto; padding: 10px 12px; resize: vertical; min-height: 80px; line-height: 1.55; }
.input:hover, .select:hover, .textarea:hover { border-color: var(--ink-soft); }
.input:focus, .select:focus, .textarea:focus {
  outline: 0;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
/* --muted-soft is 2.27:1 on paper — decorative only. Placeholder is text. */
.input::placeholder, .textarea::placeholder { color: var(--muted); }

/* Ghost input (no chrome) */
.input-ghost {
  border: 0; background: transparent; padding: 0;
  height: auto;
}
.input-ghost:focus { box-shadow: none; }

/* ——— Chips, Tags ——— */
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  height: 22px; padding: 0 8px;
  font-size: var(--text-xs); font-weight: 500;
  border-radius: 999px;
  background: var(--paper-deep);
  color: var(--ink-soft);
  letter-spacing: .01em;
}
/* Doubled class on purpose. app.css redefines a base `.chip` further down the
   cascade, and at equal specificity the later file won — so every one of these
   modifiers lost its colour and the admin UI rendered "All records ✓" and
   "No key" as the same neutral pill. .chip.chip-x outranks the bare .chip
   whichever order the stylesheets load in. */
.chip.chip-accent { background: var(--accent-soft); color: var(--accent-ink); }
.chip.chip-signal { background: var(--signal-soft); color: var(--signal); }
.chip.chip-danger { background: var(--danger-soft); color: var(--danger); }
.chip.chip-warning { background: var(--warning-soft); color: var(--warning); }
.chip.chip-info   { background: var(--info-soft); color: var(--info); }

/* ——— Cards / Panels ——— */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.card-padded { padding: 24px; }
.card-sep { border-top: 1px solid var(--line-soft); }

/* ——— Scrollbar ——— */
.scroll::-webkit-scrollbar { width: 10px; height: 10px; }
.scroll::-webkit-scrollbar-track { background: transparent; }
.scroll::-webkit-scrollbar-thumb {
  background: transparent; border-radius: 999px;
  border: 3px solid transparent; background-clip: padding-box;
}
.scroll:hover::-webkit-scrollbar-thumb { background: var(--line-strong); background-clip: padding-box; border: 3px solid transparent; }
.scroll::-webkit-scrollbar-thumb:hover { background: var(--muted-soft); background-clip: padding-box; border: 3px solid transparent; }

/* ——— Avatars ——— */
.avatar {
  flex: none;
  width: 36px; height: 36px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display);
  font-size: 17px;
  color: var(--ink);
  background: var(--paper-deep);
  border: 1px solid var(--line);
  letter-spacing: -.02em;
  user-select: none;
}
.avatar-sm { width: 28px; height: 28px; font-size: 14px; }
.avatar-lg { width: 48px; height: 48px; font-size: 22px; }

/* Deterministic avatar tints (paper-like) */
.avatar[data-tint="0"] { background: #ECE0D1; color: #6B4E26; }
.avatar[data-tint="1"] { background: #D9E7DA; color: #2A5C3A; }
.avatar[data-tint="2"] { background: #E0D8E8; color: #4F3B70; }
.avatar[data-tint="3"] { background: #E5DFD1; color: #6B5A26; }
.avatar[data-tint="4"] { background: #DCE4EE; color: #2F4E74; }
.avatar[data-tint="5"] { background: #EFDCD6; color: #8A3D2A; }
.avatar[data-tint="6"] { background: #D7E4E4; color: #2F5F5F; }
.avatar[data-tint="7"] { background: #EADFD1; color: #6B4820; }

/* ——— Rule / hairline ——— */
.rule { height: 1px; background: var(--line); width: 100%; }
.rule-soft { background: var(--line-soft); }

/* ——— Toast ——— */
.toast {
  position: fixed; bottom: 24px; left: 50%;
  transform: translateX(-50%);
  background: var(--ink); color: var(--paper);
  padding: 10px 18px; border-radius: 999px;
  font-size: var(--text-base); font-weight: 500;
  box-shadow: var(--shadow-pop);
  z-index: 9999;
  animation: toast-in .3s var(--ease-out);
}
@keyframes toast-in { from { opacity: 0; transform: translate(-50%, 12px); } to { opacity: 1; transform: translate(-50%, 0); } }

/* The stack the toasts actually live in. The .toast rule above still carries
   the fixed position for anything raised outside it; inside, position is the
   stack's job and each toast is an ordinary block in a column. */
.toast-stack {
  position: fixed; bottom: 24px; left: 50%;
  transform: translateX(-50%);
  z-index: 9999;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  pointer-events: none;
}
.toast-stack > .toast {
  position: static; left: auto; bottom: auto; transform: none;
  pointer-events: auto;
  animation: toast-in-stacked .3s var(--ease-out);
}
@keyframes toast-in-stacked { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }

/* A toast that can be acted on — Undo, so far. Inside the pill rather than
   beside it: the action belongs to that message, and a toast that has already
   started fading is not something to chase across the screen. */
.toast-with-action { display: inline-flex; align-items: center; gap: 14px; padding-right: 8px; }
.toast-action {
  background: none; border: 0; cursor: pointer;
  color: var(--accent); font: inherit; font-weight: 600;
  padding: 4px 10px; border-radius: 999px;
}
.toast-action:hover { background: rgba(255,255,255,.12); }

/* ——— Dialog / Modal ——— */
.dlg-backdrop {
  position: fixed; inset: 0;
  background: rgba(26,24,20,.32);
  backdrop-filter: blur(4px);
  z-index: 100;
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  animation: fade .18s var(--ease-out);
}
.dlg {
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-pop);
  width: 100%; max-width: 520px;
  max-height: 90vh;
  display: flex; flex-direction: column;
  animation: pop .24s var(--ease-out);
}
.dlg-lg { max-width: 720px; }
.dlg-xl { max-width: 1040px; }
.dlg-header { padding: 20px 24px 12px; border-bottom: 1px solid var(--line-soft); }
.dlg-body { padding: 20px 24px; overflow-y: auto; }
.dlg-footer { padding: 14px 24px; border-top: 1px solid var(--line-soft); display: flex; justify-content: flex-end; gap: 10px; }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes pop { from { opacity: 0; transform: scale(.96) translateY(8px); } to { opacity: 1; transform: scale(1) translateY(0); } }

/* ——— Tables ——— */
.tbl { width: 100%; border-collapse: collapse; font-size: var(--text-base); }
.tbl thead th {
  text-align: left;
  font-weight: 500;
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: .1em;
  color: var(--muted);
  padding: 12px 16px;
  background: var(--surface-alt);
  border-bottom: 1px solid var(--line);
  position: sticky; top: 0;
}
.tbl tbody td {
  padding: 14px 16px;
  border-bottom: 1px solid var(--line-soft);
  color: var(--ink);
  vertical-align: middle;
}
.tbl tbody tr:hover td { background: var(--surface-alt); }
.tbl tbody tr:last-child td { border-bottom: 0; }

/* ——— Loading spinner ——— */
.spinner {
  width: 16px; height: 16px;
  border: 2px solid var(--line);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ——— Text selection ——— */
::selection { background: var(--accent-soft); color: var(--accent-deep); }

/* ——— Focus ring for keyboard users ——— */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
button:focus:not(:focus-visible) { outline: none; }

/* ========================================================================
   Per-user appearance
   Set from webmail Settings → Appearance, stored on the user's account and
   applied as data-* attributes on <html>. Each block overrides only the
   custom properties named in :root above — nothing here styles a component,
   so the rest of the system picks the change up for free.
   ======================================================================== */

/* Text size. Three steps, not a free-form number: the scale below moves
   every --text-* token together, so the ratios stay intact. */
:root[data-font-size="small"] { --font-scale: .92; }
:root[data-font-size="large"] { --font-scale: 1.12; }

/* Accent. Four alternatives to the brand orange, each overriding exactly the
   four --accent-* properties. Orange has no block of its own: leaving the
   default in place means whatever :root says is the accent stays the accent.
   Deliberately last in the file so the user's choice outranks any earlier
   block that also touches --accent-*. */
:root[data-accent="teal"] {
  --accent:       #2E8C8C;
  --accent-deep:  #1D5C59;
  --accent-soft:  #DCEBE9;
  --accent-hover: #25736F;
}
:root[data-accent="indigo"] {
  --accent:       #5560C4;
  --accent-deep:  #38408C;
  --accent-soft:  #E3E5F7;
  --accent-hover: #4650A8;
}
:root[data-accent="plum"] {
  --accent:       #9B4A80;
  --accent-deep:  #6E355A;
  --accent-soft:  #F2E1EC;
  --accent-hover: #833E6C;
}
:root[data-accent="moss"] {
  --accent:       #5E8B45;
  --accent-deep:  #3F5F2F;
  --accent-soft:  #E4EDDC;
  --accent-hover: #4D7439;
}

/* An accent block above is light-tuned and, being last in the file, outranks
   the dark palette — so on dark, --accent-soft would land as a pale mint or
   lilac wash behind dark-mode ink. Re-derive the three context-sensitive
   tokens from whichever --accent the choice set, using the same relationships
   the hand-tuned dark orange encodes (deep and hover lift toward white, soft
   sinks into the page). Orange is excluded: it already has those values.
   Specificity here is (0,3,0) against the accent blocks' (0,2,0), so this wins
   on merit rather than on source order. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):not([data-accent="orange"]) {
    --accent-deep:  color-mix(in srgb, var(--accent) 65%, #FFFFFF);
    --accent-hover: color-mix(in srgb, var(--accent) 80%, #FFFFFF);
    --accent-soft:  color-mix(in srgb, var(--accent) 18%, #17150F);
  }
}
:root[data-theme="dark"]:not([data-accent="orange"]) {
  --accent-deep:  color-mix(in srgb, var(--accent) 65%, #FFFFFF);
  --accent-hover: color-mix(in srgb, var(--accent) 80%, #FFFFFF);
  --accent-soft:  color-mix(in srgb, var(--accent) 18%, #17150F);
}
