/* ==========================================================================
   HALYARD — DESIGN SYSTEM
   Single-file CSS design system for the Halyard webmail SPA.
   Dark-first, dense, dev-tool aesthetic. No preprocessor, no imports,
   no external fonts, no JS required.

   Class names retain their original `pm-`/component prefixes on purpose: the
   rename to Halyard is a product-name change, and churning ~900 selectors to
   chase it would be risk with no user-visible benefit.

   TABLE OF CONTENTS
   01. Primitive ramps (theme-independent)
   02. Scales: type / space / radius / shadow / motion / z-index
   03. Semantic tokens — DARK theme (default)
   04. Semantic tokens — LIGHT theme
   05. prefers-color-scheme fallback (no explicit data-theme)
   06. Reset & base elements
   07. Typography & links
   08. Accessibility: focus rings, sr-only, reduced motion
   09. Scrollbars
   10. App shell (CSS grid: topbar / sidebar / list / reader)
   11. Topbar: brand, actions, user menu
   12. Search field
   13. Sidebar: nav items, counts, sections, quota
   14. Split-pane dividers / resizers
   15. Message list: rows, states, density modes
   16. Reading pane: header, toolbar, auth pills, body, attachments
   17. Compose modal: overlay, card, address rows, editor, footer
   18. Buttons & icon buttons
   19. Form controls: inputs, selects, textarea, checkbox, switch
   20. Dropdown menus & context menus
   21. Avatars (deterministic color variants)
   22. Badges, pills, tags, keycaps
   23. Toasts
   24. Skeleton loading
   25. Empty states
   26. Tooltips
   27. Auth / login card
   28. Settings panels & command palette
   29. Utilities
   30. Responsive: 3-pane / 2-pane / single-pane
   31. Print
   ========================================================================== */

/* ==========================================================================
   01. PRIMITIVE RAMPS (theme-independent)
   Numbered ramps. Semantic tokens below map onto these; components must
   only ever consume semantic tokens.
   ========================================================================== */

:root {
  /* Neutral / gray ramp — cool near-black through white */
  --gray-1000: #000000;
  --gray-975:  #060708;
  --gray-950:  #0a0b0d;
  --gray-925:  #0d0f11;
  --gray-900:  #111315;
  --gray-875:  #15171a;
  --gray-850:  #191c1f;
  --gray-800:  #1e2225;
  --gray-750:  #23282c;
  --gray-700:  #2a3034;
  --gray-650:  #31383d;
  --gray-600:  #3a4247;
  --gray-500:  #4d565c;
  --gray-450:  #5d666d;
  --gray-400:  #6b747c;
  --gray-350:  #7d868e;
  --gray-300:  #8b949e;
  --gray-250:  #a7b0b9;
  --gray-200:  #c3cad0;
  --gray-150:  #d7dce0;
  --gray-100:  #e4e7ea;
  --gray-75:   #eef0f2;
  --gray-50:   #f4f6f7;
  --gray-25:   #fafbfc;
  --gray-0:    #ffffff;

  /* Blue ramp — primary accent */
  --blue-950: #06162e;
  --blue-900: #0a2149;
  --blue-800: #103070;
  --blue-700: #1a4fb5;
  --blue-600: #2563eb;
  --blue-500: #3b82f6;
  --blue-400: #5b9cf8;
  --blue-300: #85b6fb;
  --blue-200: #b3d1fd;
  --blue-100: #dbe9fe;
  --blue-50:  #eff6ff;

  /* Green ramp — success / verified */
  --green-950: #05190d;
  --green-900: #06240f;
  --green-800: #0b3b1c;
  --green-700: #146c2e;
  --green-600: #1a7f37;
  --green-500: #2ea043;
  --green-400: #3fb950;
  --green-300: #6ed67c;
  --green-100: #d7f5dc;
  --green-50:  #eefcf1;

  /* Amber ramp — warning / spam-ish */
  --amber-950: #1c1204;
  --amber-900: #2b1c04;
  --amber-800: #4a3006;
  --amber-700: #8a5a08;
  --amber-600: #a86a00;
  --amber-500: #d29922;
  --amber-400: #e3b341;
  --amber-300: #f0cc70;
  --amber-100: #fbeecd;
  --amber-50:  #fffaeb;

  /* Red ramp — danger / failure */
  --red-950: #1f0a0c;
  --red-900: #2d0d10;
  --red-800: #4d1218;
  --red-700: #9e1c26;
  --red-600: #c3252f;
  --red-500: #e5484d;
  --red-400: #f0666b;
  --red-300: #f79da0;
  --red-100: #fcdcdd;
  --red-50:  #fff5f5;

  /* Accent hues for deterministic avatar colors (hue anchors) */
  --hue-1: #3b82f6;  /* blue    */
  --hue-2: #14b8a6;  /* teal    */
  --hue-3: #2ea043;  /* green   */
  --hue-4: #a3a814;  /* olive   */
  --hue-5: #d29922;  /* amber   */
  --hue-6: #e07a3f;  /* orange  */
  --hue-7: #e5484d;  /* red     */
  --hue-8: #d6409f;  /* magenta */
  --hue-9: #8b5cf6;  /* violet  */
  --hue-10: #6366f1; /* indigo  */
  --hue-11: #0ea5e9; /* sky     */
  --hue-12: #7b8798; /* slate   */
}

/* ==========================================================================
   02. SCALES — type, space, radius, shadow, motion, z-index
   Theme-independent structural tokens.
   ========================================================================== */

:root {
  /* Font families — system stacks only */
  --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Inter, Roboto,
    'Helvetica Neue', Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas,
    'Liberation Mono', monospace;

  /* Type scale — dense, 13px base */
  --fs-3xs: 10px;
  --fs-2xs: 11px;
  --fs-xs:  12px;
  --fs-sm:  13px;   /* body / UI base */
  --fs-md:  14px;
  --fs-lg:  16px;
  --fs-xl:  18px;
  --fs-2xl: 22px;
  --fs-3xl: 28px;
  --fs-4xl: 34px;

  /* Line heights */
  --lh-tight: 1.2;
  --lh-snug: 1.35;
  --lh-normal: 1.5;
  --lh-relaxed: 1.65;

  /* Weights */
  --fw-regular: 400;
  --fw-medium: 500;
  --fw-semibold: 600;
  --fw-bold: 700;

  /* Letter spacing */
  --ls-tight: -0.01em;
  --ls-tighter: -0.02em;
  --ls-normal: 0;
  --ls-wide: 0.02em;
  --ls-caps: 0.06em;

  /* Spacing scale — 4px base */
  --sp-0: 0px;
  --sp-px: 1px;
  --sp-1: 2px;
  --sp-2: 4px;
  --sp-3: 6px;
  --sp-4: 8px;
  --sp-5: 10px;
  --sp-6: 12px;
  --sp-7: 14px;
  --sp-8: 16px;
  --sp-9: 20px;
  --sp-10: 24px;
  --sp-11: 28px;
  --sp-12: 32px;
  --sp-14: 40px;
  --sp-16: 48px;
  --sp-20: 64px;
  --sp-24: 80px;

  /* Radius scale — restrained, no bubbles */
  --r-none: 0px;
  --r-xs: 3px;
  --r-sm: 4px;
  --r-md: 6px;
  --r-lg: 8px;
  --r-xl: 12px;
  --r-2xl: 16px;
  --r-pill: 999px;
  --r-circle: 50%;

  /* Borders */
  --bw-thin: 1px;
  --bw-thick: 2px;

  /* Layout metrics */
  --scrollbar-w: 10px;           /* matches ::-webkit-scrollbar width */
  --topbar-h: 48px;
  --sidebar-w: 232px;
  --sidebar-w-min: 184px;
  --sidebar-w-max: 360px;
  /* MEASURED: the list column was 439px, of which 339px was reserved fixed tracks
     (rail + checkbox + icon lane + 180px sender + star + 56px timestamp + gutter),
     leaving the subject and the preview 100px to share. That is not a CSS bug, it
     is arithmetic: a Titan-style row with a real preview cannot fit in a 440px
     column, and Titan's own list is roughly twice that. So the column gets a fair
     share of the window instead of a 440px cap. */
  --list-w: clamp(420px, 38vw, 760px);
  --list-w-min: 300px;
  --list-w-max: 820px;
  --reader-max-w: 860px;
  --row-h-comfortable: 72px;
  --row-h-compact: 34px;
  --control-h-sm: 26px;
  --control-h-md: 32px;
  --control-h-lg: 38px;

  /* Motion */
  --dur-instant: 60ms;
  --dur-fast: 110ms;
  --dur-base: 170ms;
  --dur-slow: 260ms;
  --dur-slower: 400ms;
  --ease-standard: cubic-bezier(0.2, 0, 0.2, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in: cubic-bezier(0.4, 0, 1, 1);
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-spring: cubic-bezier(0.34, 1.36, 0.64, 1);

  /* Z-index scale */
  --z-base: 0;
  --z-raised: 10;
  --z-sticky: 100;
  --z-resizer: 200;
  --z-overlay-pane: 300;
  --z-dropdown: 400;
  --z-modal-overlay: 500;
  --z-modal: 510;
  --z-toast: 600;
  --z-tooltip: 700;
  --z-max: 999;
}

/* ==========================================================================
   03. SEMANTIC TOKENS — DARK THEME (default)
   Dark is the design's first-class citizen. All values chosen so that
   text pairs reach WCAG AA (>=4.5:1 body, >=3:1 large/UI) on their surface.
   ========================================================================== */

:root,
[data-theme='dark'] {
  color-scheme: dark;

  /* Surfaces */
  --bg: #0a0b0d;                 /* app canvas, near-black          */
  --bg-sunken: #060708;          /* wells, code blocks, tracks      */
  --bg-raised: #111315;          /* sidebar / list / cards          */
  --bg-raised-2: #15171a;        /* nested cards, toolbars          */
  --bg-overlay: #191c1f;         /* menus, popovers, modals         */
  --bg-hover: #1a1d21;           /* row / item hover                */
  --bg-active: #1f2327;          /* pressed                         */
  --bg-selected: #1a2c4a;        /* selected row (blue-tinted)      */
  --bg-selected-hover: #1f3457;
  --bg-inset: #0d0f11;           /* input fields                    */
  --bg-scrim: rgba(0, 0, 0, 0.5);
  --bg-unread: #0f1114;          /* subtle lift for unread rows     */

  /* Borders */
  --border: #262b2f;             /* hairline structure              */
  --border-subtle: #1b1e22;      /* barely-there separators         */
  --border-strong: #5a636a;      /* control edges — 3.1:1, WCAG 1.4.11 */
  --border-mid: #3a4247;         /* decorative dividers, overlays   */

  /* Foreground */
  --fg: #e7eaed;                 /* primary text     ~14.5:1        */
  --fg-strong: #f6f8f9;          /* headings                        */
  --fg-muted: #a7b0b9;           /* secondary text   ~9.0:1  AA     */
  --fg-subtle: #8b949c;          /* tertiary / meta  ~6.4:1  AA     */
  --fg-faint: #767f87;           /* icons/dots/borders only — not text */

  /* Accent (brand / primary action) */
  --accent: #2563eb;
  --accent-hover: #3b82f6;
  --accent-active: #1d4fd0;
  --accent-fg: #ffffff;          /* text on --accent  ~4.6:1        */
  --accent-text: #7cb0fb;        /* accent as text on --bg ~8:1     */
  --accent-subtle: #0f1e38;      /* tinted background               */
  --accent-subtle-hover: #142748;
  --accent-border: #2d5391;

  /* Status — solid, subtle bg, and text-safe variants */
  --success: #2ea043;
  --success-fg: #05190d;   /* near-black on green: 5.4:1 (white would be 3.4) */
  --success-text: #57cc6a;
  --success-subtle: #0a2114;
  --success-border: #1d5c2c;

  --warning: #d29922;
  --warning-fg: #1c1204;
  --warning-text: #e8bd52;
  --warning-subtle: #241a06;
  --warning-border: #6b4c11;

  --danger: #c3252f;
  --danger-hover: #d93b44;
  --danger-fg: #ffffff;
  --danger-text: #f0787c;
  --danger-subtle: #240e10;
  --danger-border: #6e2126;

  --info: #0ea5e9;
  --info-text: #56c5f5;
  --info-subtle: #06202c;
  --info-border: #17567a;

  /* Focus ring */
  --focus-ring: #6aa6fb;
  --focus-ring-contrast: #04060a;
  --focus-ring-width: 2px;
  --focus-ring-offset: 2px;
  --focus-ring-shadow: 0 0 0 2px var(--focus-ring-contrast),
    0 0 0 4px var(--focus-ring);

  /* Selection */
  --selection-bg: #1e4a8f;
  --selection-fg: #ffffff;

  /* Shadow recipes — dark UIs need contrast, not blur haze */
  --shadow-xs: 0 1px 1px rgba(0, 0, 0, 0.5);
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(255, 255, 255, 0.04);
  --shadow-md: 0 4px 10px -2px rgba(0, 0, 0, 0.7), 0 0 0 1px rgba(255, 255, 255, 0.05);
  --shadow-lg: 0 12px 28px -6px rgba(0, 0, 0, 0.78), 0 0 0 1px rgba(255, 255, 255, 0.06);
  --shadow-xl: 0 28px 64px -12px rgba(0, 0, 0, 0.85), 0 0 0 1px rgba(255, 255, 255, 0.07);
  --shadow-inset: inset 0 1px 0 rgba(255, 255, 255, 0.03);

  /* Scrollbar */
  --scroll-thumb: #2c3237;
  --scroll-thumb-hover: #3d4449;
  --scroll-track: transparent;

  /* Avatar text color on colored fills */
  --avatar-fg: #05070a;

  /* Skeleton shimmer */
  --skeleton-base: #15181b;
  --skeleton-sheen: #22272c;

  /* Email body isolation surface (sanitized HTML mail) */
  --mail-body-bg: #0d0f11;
  --mail-body-fg: #dfe3e7;
  --mail-quote-border: #31383d;
}

/* ==========================================================================
   04. SEMANTIC TOKENS — LIGHT THEME
   Paper-white, same structure, same density. Not an afterthought.
   ========================================================================== */

[data-theme='light'] {
  color-scheme: light;

  --bg: #ffffff;
  --bg-sunken: #f4f6f7;
  --bg-raised: #fafbfc;
  --bg-raised-2: #f4f6f7;
  --bg-overlay: #ffffff;
  --bg-hover: #f1f3f5;
  --bg-active: #e7eaed;
  --bg-selected: #e6efff;
  --bg-selected-hover: #d9e7ff;
  --bg-inset: #ffffff;
  --bg-scrim: rgba(16, 20, 24, 0.42);
  --bg-unread: #ffffff;

  --border: #dde2e7;
  --border-subtle: #eef0f2;
  --border-strong: #7e878f;      /* control edges — 3.6:1, WCAG 1.4.11 */
  --border-mid: #c6ccd2;

  --fg: #16191c;                 /* ~16:1 on white   */
  --fg-strong: #0a0c0e;
  --fg-muted: #4d565c;           /* ~7.5:1  AA       */
  --fg-subtle: #5d666d;          /* ~5.9:1  AA       */
  --fg-faint: #6b747c;           /* icons/dots/borders only — not text */

  --accent: #1a56d6;
  --accent-hover: #1449bb;
  --accent-active: #103d9e;
  --accent-fg: #ffffff;          /* white on #1a56d6 ~6.1:1 */
  --accent-text: #1149bd;        /* ~6.9:1 on white         */
  --accent-subtle: #eff5ff;
  --accent-subtle-hover: #e2ecfd;
  --accent-border: #b9d1fb;

  --success: #1a7f37;
  --success-fg: #ffffff;
  --success-text: #146c2e;
  --success-subtle: #eefcf1;
  --success-border: #b7e6c2;

  --warning: #8f5d00;   /* white on this: 5.6:1 */
  --warning-fg: #ffffff;
  --warning-text: #7a4e02;
  --warning-subtle: #fff8e6;
  --warning-border: #f0daa0;

  --danger: #c3252f;
  --danger-hover: #a71d26;
  --danger-fg: #ffffff;
  --danger-text: #ab1b23;
  --danger-subtle: #fef2f2;
  --danger-border: #f6c5c7;

  --info: #0369a1;
  --info-text: #05587f;
  --info-subtle: #eff9ff;
  --info-border: #b3ddf2;

  --focus-ring: #1a56d6;
  --focus-ring-contrast: #ffffff;
  --focus-ring-width: 2px;
  --focus-ring-offset: 2px;
  --focus-ring-shadow: 0 0 0 2px var(--focus-ring-contrast),
    0 0 0 4px var(--focus-ring);

  --selection-bg: #bfd8ff;
  --selection-fg: #10141a;

  --shadow-xs: 0 1px 1px rgba(16, 20, 24, 0.05);
  --shadow-sm: 0 1px 2px rgba(16, 20, 24, 0.07), 0 0 0 1px rgba(16, 20, 24, 0.05);
  --shadow-md: 0 4px 10px -2px rgba(16, 20, 24, 0.1), 0 0 0 1px rgba(16, 20, 24, 0.06);
  --shadow-lg: 0 12px 28px -6px rgba(16, 20, 24, 0.14), 0 0 0 1px rgba(16, 20, 24, 0.07);
  --shadow-xl: 0 28px 64px -12px rgba(16, 20, 24, 0.18), 0 0 0 1px rgba(16, 20, 24, 0.08);
  --shadow-inset: inset 0 1px 0 rgba(255, 255, 255, 0.6);

  --scroll-thumb: #c6ccd2;
  --scroll-thumb-hover: #a7b0b9;
  --scroll-track: transparent;

  --avatar-fg: #ffffff;

  --skeleton-base: #eef0f2;
  --skeleton-sheen: #f8f9fa;

  --mail-body-bg: #ffffff;
  --mail-body-fg: #16191c;
  --mail-quote-border: #c6ccd2;
}

/* ==========================================================================
   05. prefers-color-scheme — respected only when no explicit theme is set
   `<html>` with no data-theme follows the OS. An explicit data-theme wins
   because the blocks in 03/04 are more specific / later in cascade.
   ========================================================================== */

@media (prefers-color-scheme: light) {
  :root:not([data-theme]) {
    color-scheme: light;

    --bg: #ffffff;
    --bg-sunken: #f4f6f7;
    --bg-raised: #fafbfc;
    --bg-raised-2: #f4f6f7;
    --bg-overlay: #ffffff;
    --bg-hover: #f1f3f5;
    --bg-active: #e7eaed;
    --bg-selected: #e6efff;
    --bg-selected-hover: #d9e7ff;
    --bg-inset: #ffffff;
    --bg-scrim: rgba(16, 20, 24, 0.42);
    --bg-unread: #ffffff;

    --border: #dde2e7;
    --border-subtle: #eef0f2;
    --border-strong: #7e878f;
    --border-mid: #c6ccd2;

    --fg: #16191c;
    --fg-strong: #0a0c0e;
    --fg-muted: #4d565c;
    --fg-subtle: #5d666d;
    --fg-faint: #6b747c;

    --accent: #1a56d6;
    --accent-hover: #1449bb;
    --accent-active: #103d9e;
    --accent-text: #1149bd;
    --accent-subtle: #eff5ff;
    --accent-subtle-hover: #e2ecfd;
    --accent-border: #b9d1fb;

    --success: #1a7f37;
    --success-text: #146c2e;
    --success-subtle: #eefcf1;
    --success-border: #b7e6c2;

    --warning: #8f5d00;   /* white on this: 5.6:1 */
    --warning-fg: #ffffff;
    --warning-text: #7a4e02;
    --warning-subtle: #fff8e6;
    --warning-border: #f0daa0;

    --danger: #c3252f;
    --danger-hover: #a71d26;
    --danger-text: #ab1b23;
    --danger-subtle: #fef2f2;
    --danger-border: #f6c5c7;

    --info: #0369a1;
    --info-text: #05587f;
    --info-subtle: #eff9ff;
    --info-border: #b3ddf2;

    --focus-ring: #1a56d6;
    --focus-ring-contrast: #ffffff;

    --selection-bg: #bfd8ff;
    --selection-fg: #10141a;

    --shadow-xs: 0 1px 1px rgba(16, 20, 24, 0.05);
    --shadow-sm: 0 1px 2px rgba(16, 20, 24, 0.07), 0 0 0 1px rgba(16, 20, 24, 0.05);
    --shadow-md: 0 4px 10px -2px rgba(16, 20, 24, 0.1), 0 0 0 1px rgba(16, 20, 24, 0.06);
    --shadow-lg: 0 12px 28px -6px rgba(16, 20, 24, 0.14), 0 0 0 1px rgba(16, 20, 24, 0.07);
    --shadow-xl: 0 28px 64px -12px rgba(16, 20, 24, 0.18), 0 0 0 1px rgba(16, 20, 24, 0.08);
    --shadow-inset: inset 0 1px 0 rgba(255, 255, 255, 0.6);

    --scroll-thumb: #c6ccd2;
    --scroll-thumb-hover: #a7b0b9;

    --avatar-fg: #ffffff;
    --skeleton-base: #eef0f2;
    --skeleton-sheen: #f8f9fa;

    --mail-body-bg: #ffffff;
    --mail-body-fg: #16191c;
    --mail-quote-border: #c6ccd2;
  }
}

/* ==========================================================================
   06. RESET & BASE ELEMENTS
   ========================================================================== */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  tab-size: 4;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  font-weight: var(--fw-regular);
  letter-spacing: var(--ls-tight);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow: hidden; /* the shell owns scrolling */
  overscroll-behavior: none;
}

h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd, pre {
  margin: 0;
}

ul, ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

img, svg, video, canvas {
  display: block;
  max-width: 100%;
}

svg {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  flex: none;
}

button, input, select, textarea, optgroup {
  font: inherit;
  letter-spacing: inherit;
  color: inherit;
  margin: 0;
}

button {
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  text-align: inherit;
}

textarea {
  resize: vertical;
}

table {
  border-collapse: collapse;
  border-spacing: 0;
}

hr {
  border: 0;
  border-top: var(--bw-thin) solid var(--border);
  margin: var(--sp-6) 0;
}

fieldset {
  border: 0;
  margin: 0;
  padding: 0;
}

legend {
  padding: 0;
}

::selection {
  background: var(--selection-bg);
  color: var(--selection-fg);
}

[hidden] {
  display: none !important;
}

[disabled],
.is-disabled,
[aria-disabled='true'] {
  cursor: not-allowed;
}

/* ==========================================================================
   07. TYPOGRAPHY & LINKS
   ========================================================================== */

.t-display {
  font-size: var(--fs-3xl);
  line-height: var(--lh-tight);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-tighter);
  color: var(--fg-strong);
}

.t-title {
  font-size: var(--fs-2xl);
  line-height: var(--lh-tight);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-tighter);
  color: var(--fg-strong);
}

.t-heading {
  font-size: var(--fs-lg);
  line-height: var(--lh-snug);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-tight);
  color: var(--fg-strong);
}

.t-subheading {
  font-size: var(--fs-md);
  line-height: var(--lh-snug);
  font-weight: var(--fw-medium);
  color: var(--fg);
}

.t-body {
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  color: var(--fg);
}

.t-meta {
  font-size: var(--fs-xs);
  line-height: var(--lh-snug);
  color: var(--fg-subtle);
}

.t-label {
  font-size: var(--fs-2xs);
  line-height: 1;
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--fg-subtle);
}

.t-mono {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0;
  font-variant-ligatures: none;
}

.t-num {
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}

.t-muted { color: var(--fg-muted); }
.t-subtle { color: var(--fg-subtle); }
.t-strong { color: var(--fg-strong); font-weight: var(--fw-semibold); }
.t-success { color: var(--success-text); }
.t-warning { color: var(--warning-text); }
.t-danger { color: var(--danger-text); }
.t-accent { color: var(--accent-text); }

a,
.link {
  color: var(--accent-text);
  text-decoration: none;
  text-underline-offset: 2px;
  border-radius: var(--r-xs);
  transition: color var(--dur-fast) var(--ease-standard);
}

a:hover,
.link:hover {
  color: var(--accent-hover);
  text-decoration: underline;
}

code,
kbd,
samp,
pre {
  font-family: var(--font-mono);
  font-size: 0.92em;
}

code:not(pre code) {
  background: var(--bg-sunken);
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-xs);
  padding: 1px 5px;
  color: var(--fg);
}

pre {
  background: var(--bg-sunken);
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-md);
  padding: var(--sp-6);
  overflow: auto;
  font-size: var(--fs-xs);
  line-height: var(--lh-normal);
}

.truncate {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.clamp-2 {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ==========================================================================
   08. ACCESSIBILITY — focus rings, screen-reader text, reduced motion
   Every interactive surface gets a visible ring. We use :focus-visible so
   mouse users don't see rings, and keep a fallback for older engines.
   ========================================================================== */

:focus {
  outline: none;
}

:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: var(--focus-ring-offset);
  border-radius: var(--r-sm);
}

/* Elements flush against a container edge can't afford outward offset */
.focus-inset:focus-visible,
.msg-row:focus-visible,
.nav-item:focus-visible,
.menu-item:focus-visible,
.list-tab:focus-visible {
  outline-offset: -2px;
}

/* Fields draw the ring as a shadow so the border color can also shift */
.input:focus-visible,
.select:focus-visible,
.textarea:focus-visible,
.search-input:focus-visible,
.addr-input:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--focus-ring) 34%, transparent);
}

@supports not (color: color-mix(in srgb, red, blue)) {
  .input:focus-visible,
  .select:focus-visible,
  .textarea:focus-visible,
  .search-input:focus-visible,
  .addr-input:focus-visible {
    box-shadow: 0 0 0 3px var(--accent-subtle);
  }
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Skip link — first tab stop */
.skip-link {
  position: absolute;
  top: var(--sp-2);
  left: var(--sp-2);
  z-index: var(--z-max);
  transform: translateY(-200%);
  background: var(--bg-overlay);
  color: var(--fg-strong);
  border: var(--bw-thin) solid var(--border-mid);
  border-radius: var(--r-md);
  padding: var(--sp-3) var(--sp-6);
  font-weight: var(--fw-medium);
  box-shadow: var(--shadow-lg);
  transition: transform var(--dur-fast) var(--ease-out);
}

.skip-link:focus-visible {
  transform: translateY(0);
  outline: none;
  box-shadow: var(--focus-ring-shadow);
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  .skeleton,
  .skeleton-line,
  .spinner {
    animation: none !important;
  }
}

@media (prefers-contrast: more) {
  :root,
  [data-theme='dark'] {
    --border: #4a5257;
    --border-strong: #6b747c;
    --fg-subtle: #a7b0b9;
  }

  [data-theme='light'] {
    --border: #9aa2aa;
    --border-strong: #6a737b;
    --fg-subtle: #4a5257;
  }
}

/* ==========================================================================
   09. SCROLLBARS — thin, subtle, theme-aware, overlay-style
   ========================================================================== */

* {
  scrollbar-width: thin;
  scrollbar-color: var(--scroll-thumb) var(--scroll-track);
}

::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

::-webkit-scrollbar-track {
  background: var(--scroll-track);
}

::-webkit-scrollbar-thumb {
  background: var(--scroll-thumb);
  border: 2px solid transparent;
  background-clip: padding-box;
  border-radius: var(--r-pill);
}

::-webkit-scrollbar-thumb:hover {
  background: var(--scroll-thumb-hover);
  background-clip: padding-box;
}

::-webkit-scrollbar-corner {
  background: transparent;
}

.scroll-y {
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
}

.no-scrollbar {
  scrollbar-width: none;
}

.no-scrollbar::-webkit-scrollbar {
  display: none;
}

/* ==========================================================================
   10. APP SHELL — CSS grid: topbar / sidebar / list / reader
   Named areas so the responsive breakpoints only need to redefine
   grid-template rather than every child.
   ========================================================================== */

.app {
  display: grid;
  grid-template-columns: var(--sidebar-w) var(--list-w) minmax(0, 1fr);
  grid-template-rows: var(--topbar-h) minmax(0, 1fr);
  grid-template-areas:
    'topbar topbar topbar'
    'sidebar list reader';
  height: 100vh;
  height: 100dvh;
  width: 100%;
  background: var(--bg);
  isolation: isolate;
}

.app__topbar  { grid-area: topbar; }
.app__sidebar { grid-area: sidebar; }
.app__list    { grid-area: list; }
.app__reader  { grid-area: reader; }

.app__topbar,
.app__sidebar,
.app__list,
.app__reader {
  min-width: 0;
  min-height: 0;
}

/* Sidebar collapsed (rail) state */
.app.is-sidebar-collapsed {
  grid-template-columns: 0px var(--list-w) minmax(0, 1fr);
}

.app.is-sidebar-collapsed .app__sidebar {
  overflow: hidden;
  border-right-width: 0;
}

/* Reader hidden — list expands to fill */
.app.is-reader-hidden {
  grid-template-columns: var(--sidebar-w) minmax(0, 1fr) 0px;
}

.app.is-reader-hidden .app__reader {
  display: none;
}

/* ==========================================================================
   11. TOPBAR — brand, global search, actions, user menu
   ========================================================================== */

.topbar {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  height: var(--topbar-h);
  padding: 0 var(--sp-6);
  background: var(--bg-raised);
  border-bottom: var(--bw-thin) solid var(--border);
  position: relative;
  z-index: var(--z-sticky);
}

.topbar__group {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
}

.topbar__group--grow {
  flex: 1 1 auto;
  justify-content: center;
}

.topbar__divider {
  width: var(--bw-thin);
  height: 20px;
  background: var(--border);
  margin: 0 var(--sp-2);
  flex: none;
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  min-width: 0;
  color: var(--fg-strong);
  text-decoration: none;
  border-radius: var(--r-sm);
  padding: var(--sp-2) var(--sp-2) var(--sp-2) 0;
}

.brand:hover {
  text-decoration: none;
  color: var(--fg-strong);
}

.brand__mark {
  width: 22px;
  height: 22px;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: var(--r-sm);
  background: var(--accent);
  color: var(--accent-fg);
  font-size: var(--fs-xs);
  font-weight: var(--fw-bold);
  letter-spacing: 0;
  box-shadow: var(--shadow-xs);
}

.brand__name {
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-tighter);
  white-space: nowrap;
}

.brand__env {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--fg-muted);
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-xs);
  padding: 1px 4px;
}

/* ==========================================================================
   12. SEARCH FIELD (global, lives in the topbar)
   ========================================================================== */

.search {
  position: relative;
  display: flex;
  align-items: center;
  width: 100%;
  max-width: 520px;
}

.search__icon {
  position: absolute;
  left: var(--sp-4);
  width: 14px;
  height: 14px;
  color: var(--fg-subtle);
  pointer-events: none;
}

.search-input {
  width: 100%;
  height: var(--control-h-md);
  padding: 0 var(--sp-16) 0 var(--sp-11);
  background: var(--bg-inset);
  color: var(--fg);
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-md);
  font-size: var(--fs-sm);
  transition: border-color var(--dur-fast) var(--ease-standard),
    background-color var(--dur-fast) var(--ease-standard),
    box-shadow var(--dur-fast) var(--ease-standard);
}

.search-input::placeholder {
  color: var(--fg-subtle);
}

.search-input:hover {
  border-color: var(--border-strong);
}

.search__hint {
  position: absolute;
  right: var(--sp-4);
  display: flex;
  gap: var(--sp-1);
  pointer-events: none;
}

.search__clear {
  position: absolute;
  right: var(--sp-2);
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  border-radius: var(--r-sm);
  color: var(--fg-subtle);
}

.search__clear:hover {
  background: var(--bg-hover);
  color: var(--fg);
}

/* Search scope chips beneath the field (advanced search) */
.search-filters {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-6);
  border-bottom: var(--bw-thin) solid var(--border);
  background: var(--bg-raised);
}

/* ==========================================================================
   13. SIDEBAR — nav items, icon + label + count, sections, quota
   ========================================================================== */

.sidebar {
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--bg-raised);
  border-right: var(--bw-thin) solid var(--border);
}

.sidebar__top {
  padding: var(--sp-7) var(--sp-6) var(--sp-6);
  border-bottom: var(--bw-thin) solid var(--border-subtle);
}

.sidebar__scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--sp-4) var(--sp-3) var(--sp-6);
}

.sidebar__bottom {
  flex: none;
  border-top: var(--bw-thin) solid var(--border-subtle);
  padding: var(--sp-6) var(--sp-7) var(--sp-7);
}

.sb-section {
  margin-bottom: var(--sp-6);
}

.sb-section__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4) var(--sp-2);
}

.sb-section__title {
  font-size: var(--fs-3xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--fg-subtle);
  white-space: nowrap;
}

.sb-section__action {
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
  border-radius: var(--r-xs);
  color: var(--fg-subtle);
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease-standard);
}

.sb-section:hover .sb-section__action,
.sb-section__action:focus-visible {
  opacity: 1;
}

.sb-section__action:hover {
  background: var(--bg-hover);
  color: var(--fg);
}

.nav-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-5);
  width: 100%;
  min-height: 30px;
  padding: 0 var(--sp-4);
  border-radius: var(--r-md);
  color: var(--fg-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  text-decoration: none;
  user-select: none;
  transition: background-color var(--dur-fast) var(--ease-standard),
    color var(--dur-fast) var(--ease-standard);
}

.nav-item + .nav-item {
  margin-top: 1px;
}

.nav-item:hover {
  background: var(--bg-hover);
  color: var(--fg);
  text-decoration: none;
}

.nav-item:active {
  background: var(--bg-active);
}

.nav-item.is-active,
.nav-item[aria-current='page'] {
  background: var(--bg-active);
  color: var(--fg-strong);
}

.nav-item.is-active::before {
  content: '';
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 2px;
  height: 16px;
  border-radius: var(--r-pill);
  background: var(--accent);
}

.nav-item__icon {
  width: 15px;
  height: 15px;
  flex: none;
  color: var(--fg-subtle);
  transition: color var(--dur-fast) var(--ease-standard);
}

.nav-item:hover .nav-item__icon,
.nav-item.is-active .nav-item__icon {
  color: var(--fg);
}

.nav-item.is-active .nav-item__icon {
  color: var(--accent-text);
}

.nav-item__label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nav-item__count {
  flex: none;
  min-width: 18px;
  height: 17px;
  padding: 0 var(--sp-3);
  display: grid;
  place-items: center;
  border-radius: var(--r-pill);
  background: var(--bg-active);
  color: var(--fg-muted);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
}

.nav-item.has-unread .nav-item__label {
  color: var(--fg-strong);
  font-weight: var(--fw-semibold);
}

.nav-item.has-unread .nav-item__count {
  background: var(--accent);
  color: var(--accent-fg);
}

.nav-item__dot {
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: var(--r-circle);
  background: var(--accent);
}

/* Label / folder color swatch — padded to the 15px icon slot so labels
   in a mixed list (folders + labels) keep one left edge. */
.nav-item__swatch {
  flex: none;
  margin: 0 3px;
  width: 9px;
  height: 9px;
  border-radius: var(--r-xs);
  background: var(--fg-faint);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.25);
}

/* Storage quota meter */
.quota {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

.quota__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-4);
  font-size: var(--fs-2xs);
  color: var(--fg-subtle);
}

.quota__value {
  color: var(--fg-muted);
  font-variant-numeric: tabular-nums;
}

.quota__track {
  height: 6px;
  border-radius: var(--r-pill);
  background: var(--bg-active);
  border: var(--bw-thin) solid var(--border);
  overflow: hidden;
}

.quota__fill {
  height: 100%;
  width: 0;
  border-radius: var(--r-pill);
  background: var(--accent);
  transition: width var(--dur-slow) var(--ease-out);
}

.quota.is-warning .quota__fill { background: var(--warning); }
.quota.is-danger .quota__fill { background: var(--danger); }

/* ==========================================================================
   14. SPLIT-PANE DIVIDERS / RESIZE HANDLES
   Thin hairline that thickens into an accent line on hover / drag.
   ========================================================================== */

.resizer {
  position: relative;
  flex: none;
  width: 5px;
  margin: 0 -3px 0 -2px;
  cursor: col-resize;
  z-index: var(--z-resizer);
  background: transparent;
  touch-action: none;
}

.resizer::after {
  content: '';
  position: absolute;
  inset: 0 2px;
  border-radius: var(--r-pill);
  background: transparent;
  transition: background-color var(--dur-base) var(--ease-standard);
}

.resizer:hover::after,
.resizer.is-dragging::after,
.resizer:focus-visible::after {
  background: var(--accent);
}

.resizer--horizontal {
  width: auto;
  height: 5px;
  margin: -2px 0 -3px;
  cursor: row-resize;
}

.resizer--horizontal::after {
  inset: 2px 0;
}

body.is-resizing,
body.is-resizing * {
  cursor: col-resize !important;
  user-select: none !important;
}

/* ==========================================================================
   15. MESSAGE LIST — header/tabs, rows, unread/read/selected states,
   avatar + sender + timestamp + subject + snippet + indicators,
   and the two density modes.
   ========================================================================== */

.list {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  background: var(--bg-raised);
  border-right: var(--bw-thin) solid var(--border);
}

.list__header {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  height: 44px;
  padding: 0 var(--sp-4) 0 var(--sp-6);
  border-bottom: var(--bw-thin) solid var(--border);
  background: var(--bg-raised);
}

.list__title {
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--fg-strong);
  letter-spacing: var(--ls-tight);
  white-space: nowrap;
}

.list__count {
  font-size: var(--fs-2xs);
  color: var(--fg-subtle);
  font-variant-numeric: tabular-nums;
}

.list__spacer {
  flex: 1 1 auto;
}

.list__tools {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
}

/* Filter tabs (All / Unread / Flagged) */
.list-tabs {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  padding: var(--sp-3) var(--sp-5);
  border-bottom: var(--bw-thin) solid var(--border-subtle);
  background: var(--bg-raised);
}

.list-tab {
  height: 24px;
  padding: 0 var(--sp-5);
  border-radius: var(--r-sm);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--fg-muted);
  white-space: nowrap;
  transition: background-color var(--dur-fast) var(--ease-standard),
    color var(--dur-fast) var(--ease-standard);
}

.list-tab:hover {
  background: var(--bg-hover);
  color: var(--fg);
}

.list-tab.is-active,
.list-tab[aria-selected='true'] {
  background: var(--bg-active);
  color: var(--fg-strong);
}

/* Bulk-selection action bar (replaces header when rows are checked) */
.list__bulkbar {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  height: 44px;
  padding: 0 var(--sp-5);
  background: var(--accent-subtle);
  border-bottom: var(--bw-thin) solid var(--accent-border);
  color: var(--fg-strong);
  font-size: var(--fs-xs);
}

/* Scroll container */
.list__body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior: contain;
}

/* Date group separator */
.list__group {
  position: sticky;
  top: 0;
  z-index: var(--z-raised);
  padding: var(--sp-3) var(--sp-6);
  background: var(--bg-raised);
  border-bottom: var(--bw-thin) solid var(--border-subtle);
  font-size: var(--fs-3xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--fg-subtle);
}

/* ---- Row ---------------------------------------------------------------- */

/* ---------------------------------------------------------------------------
   THE ROW, rebuilt on Titan's structural model.

   Every horizontal stop is a FIXED grid track, so the subject begins at exactly
   the same x on every row no matter how long the sender name is — that hard
   vertical edge is what makes a list scannable, and flex auto-sizing (what this
   used to do) destroys it by construction.

     [rail 3px][check 30px][icon lane 32px][avatar 0|34px][sender FIXED]
     [subject + snippet 1fr][star 26px][time 56px]

   - The ICON LANE is permanently allocated and empty on most rows, so adding a
     reply / draft / paperclip / receipt / bell glyph shifts NOTHING.
   - The AVATAR track is 0px unless `html[data-avatars='on']`; the width goes
     straight back to the snippet.
   - Subject and snippet share ONE line, ONE baseline and ONE font size.
     Hierarchy is brightness + weight only.
   - The hover action cluster is absolutely positioned so that its right edge
     lands exactly where the star track begins, and on hover the main cell takes
     matching right padding. So the cluster occupies space the snippet gives up,
     never space the star or the timestamp occupy. Row height is identical at
     rest and on hover, and nothing moves vertically.
   ------------------------------------------------------------------------- */

:root {
  --row-rail-w: 3px;
  --row-check-w: 30px;
  --row-icons-w: 32px;
  --row-avatar-w: 0px;
  --row-sender-w: 180px;
  --row-star-w: 26px;
  --row-time-w: 56px;
  /* 4 x 20px buttons + 3 x 2px gaps + 2 x 2px padding + 2 x 1px border = 92. */
  --row-quick-w: 92px;
}

html[data-avatars='on'] {
  --row-avatar-w: 34px;
}

.msg-row {
  position: relative;
  display: grid;
  grid-template-columns:
    var(--row-rail-w)
    var(--row-check-w)
    var(--row-icons-w)
    var(--row-avatar-w)
    var(--row-sender-w)
    minmax(0, 1fr)
    var(--row-star-w)
    var(--row-time-w);
  grid-template-areas: 'rail check icons avatar sender main star time';
  align-items: center;
  column-gap: 0;
  row-gap: 0;
  width: 100%;
  /* No left padding: the accent rail IS the first track and must sit at x=0. */
  padding: 0 var(--list-gutter) 0 0;
  border-bottom: var(--bw-thin) solid var(--border-subtle);
  background: transparent;
  color: var(--fg-muted);
  text-align: left;
  cursor: default;
  user-select: none;
  overflow: hidden;
  scroll-margin: 28px 0 var(--sp-4);
  transition: background-color var(--dur-fast) var(--ease-standard);
}

.msg-row__rail    { grid-area: rail; align-self: stretch; background: transparent; }
.msg-row__check   { grid-area: check; display: grid; place-items: center; }
.msg-row__icons   { grid-area: icons; }
.msg-row__avatar  { grid-area: avatar; }
.msg-row__sender  { grid-area: sender; }
.msg-row__main    { grid-area: main; }
.msg-row__tail    { grid-area: star; display: grid; place-items: center; }
.msg-row__time    { grid-area: time; }

/* The reserved icon lane. Always 32px, centred, holds at most two 13px glyphs so
   it can never need more room than it has. */
.msg-row__icons {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
  overflow: hidden;
  color: var(--fg-faint);
}

.msg-row__icons svg {
  width: 13px;
  height: 13px;
  flex: none;
}

.msg-row__avatar {
  display: flex;
  align-items: center;
  overflow: hidden;
}

html:not([data-avatars='on']) .msg-row__avatar {
  /* Collapsed to nothing: no padding, no children painted, no width. */
  display: none;
}

/* Subject + snippet: one line, one baseline, one size. */
.msg-row__main {
  display: flex;
  align-items: baseline;
  gap: var(--sp-4);
  min-width: 0;
  padding-right: var(--sp-5);
  overflow: hidden;
  transition: padding-right var(--dur-fast) var(--ease-standard);
}

/* On hover the snippet's available width shrinks by exactly the width of the
   action cluster, which is why the cluster covers nothing. */
.msg-row:hover .msg-row__main,
.msg-row:focus-within .msg-row__main {
  padding-right: calc(var(--row-quick-w) + var(--sp-3));
}

.msg-row:hover {
  background: var(--bg-hover);
}

.msg-row:active {
  background: var(--bg-active);
}

/* Unread — RESTRAINED: a 3px accent rail in the reserved left gutter plus a
   600-weight subject. The whole row is NOT bolded; that was the old treatment
   and it made every unread row shout at the same volume as its own subject. */
.msg-row.is-unread {
  background: var(--bg-unread);
  color: var(--fg);
}

.msg-row.is-unread .msg-row__rail {
  background: var(--accent);
}

.msg-row.is-unread:hover {
  background: var(--bg-hover);
}

.msg-row.is-unread .msg-row__subject {
  color: var(--fg-strong);
  font-weight: var(--fw-semibold);
}

/* The sender stays at normal weight on an unread row — only the subject earns
   the emphasis. */
.msg-row.is-unread .msg-row__sender {
  color: var(--fg);
  font-weight: var(--fw-medium);
}

.msg-row.is-unread .msg-row__time {
  color: var(--fg);
  font-weight: var(--fw-medium);
}

/* Read — quieter */
.msg-row.is-read .msg-row__sender {
  font-weight: var(--fw-regular);
  color: var(--fg-subtle);
}

/* A READ row's subject keeps the 600 weight and gives up BRIGHTNESS instead.
   MEASURED: dropping read subjects to 400 made them the same weight as their own
   snippet, so within a read row there was no hierarchy left at all — the only
   separation was colour, and the "subject is the strongest text in the row" rule
   held for unread rows only. Weight now says "this is the subject", brightness
   says "you have read it", and the two axes stay independent. */
.msg-row.is-read .msg-row__subject {
  color: var(--fg-muted);
  font-weight: var(--fw-semibold);
}

/* Selected (open in the reader) — wins over unread */
.msg-row.is-selected,
.msg-row[aria-selected='true'] {
  background: var(--bg-selected);
}

.msg-row.is-selected .msg-row__rail,
.msg-row[aria-selected='true'] .msg-row__rail {
  background: var(--accent);
}

.msg-row.is-selected:hover,
.msg-row[aria-selected='true']:hover {
  background: var(--bg-selected-hover);
}

.msg-row.is-selected .msg-row__sender,
.msg-row.is-selected .msg-row__subject {
  color: var(--fg-strong);
}

.msg-row.is-selected .msg-row__snippet,
.msg-row.is-selected .msg-row__time {
  color: var(--fg-muted);
}

/* Keyboard cursor (focused row without selection) */
.msg-row.is-cursor {
  box-shadow: inset 0 0 0 1px var(--accent-border);
}

/* Checkbox-checked rows */
.msg-row.is-checked {
  background: var(--accent-subtle);
}

.msg-row.is-checked:hover {
  background: var(--accent-subtle-hover);
}

/* Row content pieces.
   The sender sits inside a FIXED track and truncates there; it can never push
   the subject, which is the entire point of the fixed gutter. */
.msg-row__sender {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  min-width: 0;
  max-width: 100%;
  padding-right: var(--sp-5);
  font-size: var(--fs-sm);
  overflow: hidden;
  white-space: nowrap;
}

.msg-row__sender-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Thread participant count, Titan style: `Dominic, me (5)`. Plain text on the
   same baseline, not a bordered pill — a pill on every multi-message row is 20
   more boxes competing with the subject. */
.msg-row__thread-count {
  flex: none;
  font-size: var(--fs-2xs);
  font-variant-numeric: tabular-nums;
  color: var(--fg-subtle);
}

/* Fixed 56px right-aligned tabular column. The hover cluster stops short of it
   by construction, so it can never be covered or clipped. */
.msg-row__time {
  display: block;
  width: 100%;
  font-size: var(--fs-2xs);
  color: var(--fg-subtle);
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
  overflow: hidden;
}

/* Subject and snippet: IDENTICAL font size, one baseline. Only weight and
   brightness separate them.

   MEASURED: with both at `flex: 0 1 auto` / `1 1 auto` the two ran a shrink
   competition weighted by CONTENT LENGTH, so a 259-character preview beat an
   80-character subject and the subject was crushed to 1.78px — the primary text
   in the row rendered as a sliver. The flex model below is what makes the
   priority explicit instead of emergent:
     - the subject keeps its NATURAL width, capped at 45% of the cell, and does
       not shrink below that cap (`flex-shrink: 0` inside the cap);
     - the snippet has `flex-basis: 0`, so its content length contributes nothing
       to the sizing round and it simply absorbs whatever remains.
   That is Titan's behaviour: subject first, preview fills. */
.msg-row__subject {
  flex: 0 0 auto;
  min-width: 0;
  max-width: 45%;
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--fg-strong);
  line-height: var(--lh-snug);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The snippet takes ALL leftover width up to the star/timestamp columns and
   ellipsises there. `flex-basis: 0` is the load-bearing part. */
.msg-row__snippet {
  flex: 1 1 0;
  min-width: 0;
  font-size: var(--fs-sm);
  font-weight: var(--fw-regular);
  color: var(--fg-subtle);
  line-height: var(--lh-snug);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* An EMPTY snippet has zero height, and a zero-height flex item has no baseline
   to align to, so `align-items: baseline` drops it to the bottom of the line box
   and its top sits 14px below the subject's. Nothing is visible either way, but a
   geometry check correctly reads that as two different baselines. A zero-width
   zero-space character gives an empty snippet a real line box, so the baseline is
   shared whether or not there is preview text. */
.msg-row__snippet:empty::before {
  content: '\200B';
}

/* Indicators: star, attachment, flags */
.msg-row__flags {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex: none;
  color: var(--fg-faint);
}

.msg-row__flags svg {
  width: 13px;
  height: 13px;
}

.msg-attach {
  color: var(--fg-subtle);
}

.msg-star {
  display: grid;
  place-items: center;
  /* Constrained to fit INSIDE the 26px star track and inside the compact row's
     own height, so the glyph can never be half-drawn at the row's top edge —
     that was the reported clipping bug. */
  width: 20px;
  height: 20px;
  flex: none;
  border-radius: var(--r-sm);
  color: var(--fg-faint);
  transition: color var(--dur-fast) var(--ease-standard),
    background-color var(--dur-fast) var(--ease-standard),
    transform var(--dur-fast) var(--ease-spring);
}

.msg-star svg {
  width: 14px;
  height: 14px;
}

.msg-star:hover {
  background: var(--bg-active);
  color: var(--warning-text);
}

.msg-star.is-on {
  color: var(--warning);
}

.msg-star.is-on svg {
  fill: var(--warning);
  stroke: var(--warning);
}

.msg-star.is-on:active {
  transform: scale(0.88);
}

/* Row checkbox column: reserved width always, ink revealed on hover / checked /
   focus. Only opacity changes, so revealing it moves nothing. */
.msg-row__check {
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease-standard);
}

.msg-row:hover .msg-row__check,
.msg-row.is-checked .msg-row__check,
.msg-row__check:focus-within,
.list.is-selecting .msg-row__check {
  opacity: 1;
}

/* ---------------------------------------------------------------------------
   HOVER ACTION CLUSTER — reserved space, not an overlay.

   Its right edge is pinned to the LEFT edge of the star track, which is
   `--row-star-w + --row-time-w + --list-gutter` from the row's right edge. So:
     - it can never cover or clip the star or the timestamp;
     - it can never cover the snippet either, because `.msg-row__main` takes
       `padding-right: --row-quick-w` on hover, shrinking the snippet's
       available width by exactly the cluster's width;
     - it is vertically centred with a height strictly below the compact row
       height, so nothing clips at the row's top or bottom edge;
     - the row's own height is untouched, so nothing moves vertically.
   ------------------------------------------------------------------------- */
.msg-row__quick {
  position: absolute;
  right: calc(var(--row-star-w) + var(--row-time-w) + var(--list-gutter));
  top: 50%;
  transform: translateY(-50%);
  /* Kept in the layout at all times and hidden with visibility, so the very
     first hover cannot reflow anything. */
  display: flex;
  align-items: center;
  gap: 2px;
  height: 26px;
  padding: 2px;
  border-radius: var(--r-md);
  background: var(--bg-overlay);
  border: var(--bw-thin) solid var(--border);
  box-shadow: var(--shadow-md);
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-fast) var(--ease-standard);
}

.msg-row__quick .icon-btn--sm {
  width: 20px;
  height: 20px;
  flex: none;
}

.msg-row:hover .msg-row__quick,
.msg-row:focus-within .msg-row__quick {
  visibility: visible;
  opacity: 1;
  pointer-events: auto;
}

/* Draft / failed row accents */
.msg-row.is-draft .msg-row__sender-name { color: var(--danger-text); }
.msg-row.is-failed { background: var(--danger-subtle); }

/* ---- Density modes ------------------------------------------------------ */

/* Both densities use the SAME single-line structure — the whole point of the
   Titan model is that the row is one line — so density only changes the fixed
   row height, which is what the virtualiser needs. Neither mode may introduce
   variable-height rows.

   The horizontal gutter is NOT set here: section 41 owns it (`--list-gutter`),
   and the density blocks re-declaring `padding` is exactly the bug that made the
   rows sit 2px left of the header last time. */
[data-density='comfortable'] .msg-row {
  height: var(--row-h-comfortable);
  min-height: var(--row-h-comfortable);
}

[data-density='compact'] .msg-row {
  height: var(--row-h-compact);
  min-height: var(--row-h-compact);
}

/* Comfortable earns its extra height with a larger avatar and a wider sender
   gutter, not with a second text line. */
[data-density='comfortable'] {
  --row-sender-w: 200px;
}

html[data-avatars='on'][data-density='comfortable'] {
  --row-avatar-w: 40px;
}

[data-density='compact'] .avatar--md {
  width: 20px;
  height: 20px;
  font-size: var(--fs-3xs);
  border-radius: var(--r-xs);
}

[data-density='comfortable'] .avatar--md {
  width: 26px;
  height: 26px;
}

[data-density='compact'] .list__group {
  padding-top: var(--sp-2);
  padding-bottom: var(--sp-2);
}

/* ==========================================================================
   16. READING PANE — header, action toolbar, auth pills, message body
   typography (plain text + sanitized HTML), attachments, thread items.
   ========================================================================== */

.reader {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  background: var(--bg);
}

.reader__toolbar {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  height: 44px;
  border-bottom: var(--bw-thin) solid var(--border);
  background: var(--bg);
  position: relative;
  z-index: var(--z-raised);
}

/* Toolbar shares the reading column's measure and gutters so its controls
   sit on the same left/right axis as the message content below. */
.reader__toolbar-inner {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  width: 100%;
  max-width: calc(var(--reader-max-w) + var(--scrollbar-w));
  height: 100%;
  margin: 0 auto;
  padding: 0 calc(var(--sp-10) + var(--scrollbar-w)) 0 var(--sp-10);
}

/* Fallback when the toolbar has no inner wrapper */
.reader__toolbar:not(:has(.reader__toolbar-inner)) {
  padding: 0 calc(var(--sp-10) + var(--scrollbar-w)) 0 var(--sp-10);
}

@supports not selector(:has(*)) {
  .reader__toolbar {
    padding: 0 calc(var(--sp-10) + var(--scrollbar-w)) 0 var(--sp-10);
  }

  .reader__toolbar-inner {
    padding: 0;
  }
}

.reader__toolbar-group {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
}

.reader__toolbar-sep {
  width: var(--bw-thin);
  height: 18px;
  background: var(--border-mid);
  margin: 0 var(--sp-3);
}

/* A separator with nothing on one side is noise — hide it. */
.reader__toolbar-sep:first-child,
.reader__toolbar-sep:last-child,
.reader__toolbar-sep + .reader__toolbar-sep,
.topbar__divider:first-child,
.topbar__divider:last-child,
.topbar__divider + .topbar__divider {
  display: none;
}

.reader__scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-gutter: stable;
}

.reader__inner {
  max-width: var(--reader-max-w);
  margin: 0 auto;
  padding: var(--sp-9) var(--sp-10) var(--sp-20);
}

.reader__subject {
  font-size: var(--fs-xl);
  line-height: var(--lh-snug);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-tighter);
  color: var(--fg-strong);
  margin-bottom: var(--sp-6);
  overflow-wrap: anywhere;
}

.reader__subject-tags {
  display: inline-flex;
  gap: var(--sp-2);
  /* optically centre pills against the heading's cap height, not its baseline */
  vertical-align: 0.12em;
  margin-left: var(--sp-4);
}

/* Message header block */
.msg-head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--sp-6);
  padding-bottom: var(--sp-6);
  border-bottom: var(--bw-thin) solid var(--border);
}

.msg-head__who {
  min-width: 0;
}

.msg-head__from {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-3);
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
  color: var(--fg-strong);
}

.msg-head__addr {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-weight: var(--fw-regular);
  color: var(--fg-subtle);
  letter-spacing: 0;
  overflow-wrap: anywhere;
}

.msg-head__recipients {
  margin-top: var(--sp-2);
  font-size: var(--fs-xs);
  color: var(--fg-subtle);
  line-height: var(--lh-snug);
}

.msg-head__recipients-label {
  color: var(--fg-subtle);
  margin-right: var(--sp-2);
}

.msg-head__recipient {
  color: var(--fg-muted);
}

.msg-head__recipient + .msg-head__recipient::before {
  content: ', ';
  color: var(--fg-subtle);
}

.msg-head__toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  margin-top: var(--sp-3);
  font-size: var(--fs-2xs);
  color: var(--fg-subtle);
  border-radius: var(--r-xs);
}

.msg-head__toggle:hover {
  color: var(--accent-text);
}

.msg-head__side {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--sp-3);
  flex: none;
}

.msg-head__date {
  font-size: var(--fs-xs);
  color: var(--fg-subtle);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.msg-head__actions {
  display: flex;
  gap: var(--sp-1);
}

/* Expanded technical header table (Message-ID, Return-Path, ...) */
.msg-head__detail {
  grid-column: 1 / -1;
  margin-top: var(--sp-5);
  padding: var(--sp-6);
  background: var(--bg-sunken);
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-md);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  line-height: var(--lh-normal);
  color: var(--fg-muted);
  overflow-x: auto;
}

.msg-head__detail dl {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: var(--sp-2) var(--sp-6);
}

.msg-head__detail dt {
  color: var(--fg-subtle);
  text-transform: uppercase;
  letter-spacing: var(--ls-wide);
}

.msg-head__detail dd {
  overflow-wrap: anywhere;
  color: var(--fg);
}

/* ---- Authentication result pills (SPF / DKIM / DMARC / TLS) ------------- */

.auth-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-6) 0;
  border-bottom: var(--bw-thin) solid var(--border-subtle);
}

.auth-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  height: 20px;
  padding: 0 var(--sp-4);
  border-radius: var(--r-sm);
  border: var(--bw-thin) solid var(--border);
  background: var(--bg-raised-2);
  color: var(--fg-muted);
  font-family: var(--font-mono);
  font-size: var(--fs-3xs);
  letter-spacing: var(--ls-wide);
  text-transform: uppercase;
  white-space: nowrap;
}

.auth-pill__dot {
  width: 5px;
  height: 5px;
  border-radius: var(--r-circle);
  background: currentColor;
  flex: none;
}

.auth-pill--pass {
  background: var(--success-subtle);
  border-color: var(--success-border);
  color: var(--success-text);
}

.auth-pill--fail {
  background: var(--danger-subtle);
  border-color: var(--danger-border);
  color: var(--danger-text);
}

.auth-pill--warn,
.auth-pill--softfail {
  background: var(--warning-subtle);
  border-color: var(--warning-border);
  color: var(--warning-text);
}

.auth-pill--none,
.auth-pill--neutral {
  background: var(--bg-raised-2);
  border-color: var(--border-strong);
  color: var(--fg-muted);
}

.auth-pill--info {
  background: var(--info-subtle);
  border-color: var(--info-border);
  color: var(--info-text);
}

/* Security banner (remote content blocked / suspected phishing) */
.reader-banner {
  display: flex;
  align-items: center;
  gap: var(--sp-5);
  margin: var(--sp-8) 0 0;
  padding: var(--sp-5) var(--sp-6);
  border-radius: var(--r-md);
  border: var(--bw-thin) solid var(--warning-border);
  background: var(--warning-subtle);
  color: var(--fg);
  font-size: var(--fs-xs);
  line-height: var(--lh-snug);
}

.reader-banner__icon {
  width: 15px;
  height: 15px;
  flex: none;
  color: var(--warning-text);
}

.reader-banner__text {
  flex: 1 1 auto;
  min-width: 0;
}

.reader-banner--danger {
  border-color: var(--danger-border);
  background: var(--danger-subtle);
}

.reader-banner--danger .reader-banner__icon {
  color: var(--danger-text);
}

.reader-banner--info {
  border-color: var(--info-border);
  background: var(--info-subtle);
}

.reader-banner--info .reader-banner__icon {
  color: var(--info-text);
}

/* ---- Message body: plain text and sanitized HTML ------------------------ */

.msg-body {
  padding: var(--sp-8) 0 0;
  /* one rhythm step between reader blocks */
  color: var(--fg);
  font-size: var(--fs-md);
  line-height: var(--lh-relaxed);
  overflow-wrap: break-word;
}

/* Plain-text mail: preserve wrapping, mono for fidelity, comfortable measure */
.msg-body--text {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  white-space: pre-wrap;
  letter-spacing: 0;
  max-width: 78ch;
  color: var(--mail-body-fg);
}

/* Quoted lines in plain text (marked up by the sanitizer).
   Border sits in the gutter so quoted text keeps the body's left axis. */
.msg-body--text .quote,
.msg-body blockquote {
  color: var(--fg-subtle);
  border-left: 2px solid var(--mail-quote-border);
  padding-left: var(--sp-6);
  margin: var(--sp-6) 0 var(--sp-6) calc(var(--sp-6) * -1);
}

/* Collapsed trailing quote toggle */
.quote-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  margin: var(--sp-5) 0;
  padding: 0 var(--sp-4);
  height: 18px;
  border-radius: var(--r-sm);
  background: var(--bg-raised-2);
  border: var(--bw-thin) solid var(--border);
  color: var(--fg-subtle);
  font-size: var(--fs-2xs);
  letter-spacing: var(--ls-wide);
}

.quote-toggle:hover {
  background: var(--bg-hover);
  color: var(--fg);
}

.quote-collapsed {
  display: none;
}

.quote-collapsed.is-open {
  display: block;
}

/* Sanitized HTML mail. Scoped, defensive resets so hostile-ish markup can't
   blow up the shell. Pair with an inert container in JS. */
.msg-body--html {
  background: var(--mail-body-bg);
  color: var(--mail-body-fg);
  font-family: var(--font-sans);
  contain: layout paint style;
  max-width: 100%;
  overflow-x: auto;
}

.msg-body--html p {
  margin: 0 0 var(--sp-6);
}

.msg-body--html h1,
.msg-body--html h2,
.msg-body--html h3,
.msg-body--html h4 {
  color: var(--fg-strong);
  line-height: var(--lh-snug);
  margin: var(--sp-9) 0 var(--sp-5);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-tight);
}

.msg-body--html h1 { font-size: var(--fs-2xl); }
.msg-body--html h2 { font-size: var(--fs-xl); }
.msg-body--html h3 { font-size: var(--fs-lg); }
.msg-body--html h4 { font-size: var(--fs-md); }

.msg-body--html ul,
.msg-body--html ol {
  margin: 0 0 var(--sp-6);
  padding-left: var(--sp-9);
  list-style: revert;
}

.msg-body--html li {
  margin-bottom: var(--sp-2);
}

.msg-body--html a {
  color: var(--accent-text);
  text-decoration: underline;
  text-underline-offset: 2px;
  overflow-wrap: anywhere;
}

.msg-body--html img {
  max-width: 100%;
  height: auto;
  border-radius: var(--r-sm);
}

.msg-body--html table {
  max-width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
}

.msg-body--html th,
.msg-body--html td {
  border: var(--bw-thin) solid var(--border);
  padding: var(--sp-3) var(--sp-5);
  text-align: left;
  vertical-align: top;
}

.msg-body--html th {
  background: var(--bg-raised-2);
  color: var(--fg-strong);
  font-weight: var(--fw-semibold);
}

.msg-body--html hr {
  border-top-color: var(--border);
  margin: var(--sp-8) 0;
}

.msg-body--html pre {
  max-width: 100%;
  white-space: pre-wrap;
}

/* Blocked remote images get a visible placeholder instead of a broken icon */
.msg-body--html img[data-blocked] {
  display: inline-grid;
  place-items: center;
  min-width: 80px;
  min-height: 40px;
  background: var(--bg-sunken);
  border: 1px dashed var(--border-mid);
  color: var(--fg-subtle);
}

/* Isolated-iframe rendering mode */
.msg-frame {
  width: 100%;
  border: 0;
  background: var(--mail-body-bg);
  border-radius: var(--r-md);
  min-height: 220px;
  display: block;
}

/* ---- Attachments -------------------------------------------------------- */

.attachments {
  margin-top: var(--sp-8);
  padding-top: var(--sp-8);
  border-top: var(--bw-thin) solid var(--border);
}

.attachments__head {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  margin-bottom: var(--sp-5);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--fg-subtle);
}

.attachments__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--sp-4);
  align-items: stretch;
}

.attachments__grid > .attachment {
  width: 100%;
}

.attachment {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--sp-5);
  padding: var(--sp-4) var(--sp-5);
  background: var(--bg-raised);
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-xs);
  text-decoration: none;
  color: var(--fg);
  transition: border-color var(--dur-fast) var(--ease-standard),
    background-color var(--dur-fast) var(--ease-standard);
}

.attachment:hover {
  background: var(--bg-hover);
  border-color: var(--border-strong);
  text-decoration: none;
  color: var(--fg);
}

.attachment__icon {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  flex: none;
  border-radius: var(--r-sm);
  background: var(--bg-sunken);
  border: var(--bw-thin) solid var(--border);
  color: var(--fg-subtle);
  font-family: var(--font-mono);
  font-size: var(--fs-3xs);
  text-transform: uppercase;
  letter-spacing: 0;
}

.attachment__name {
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.attachment__size {
  font-size: var(--fs-2xs);
  color: var(--fg-subtle);
  font-variant-numeric: tabular-nums;
}

.attachment__dl {
  color: var(--fg-subtle);
  width: 20px;
  height: 20px;
  display: grid;
  place-items: center;
  border-radius: var(--r-sm);
}

.attachment:hover .attachment__dl {
  color: var(--accent-text);
}

/* ---- Threaded conversation items ---------------------------------------- */

.thread {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  margin-top: var(--sp-8);
}

.thread-item {
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-lg);
  background: var(--bg-raised);
  overflow: hidden;
}

.thread-item__head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--sp-5);
  width: 100%;
  padding: var(--sp-5) var(--sp-6);
  background: transparent;
  transition: background-color var(--dur-fast) var(--ease-standard);
}

.thread-item__head:hover {
  background: var(--bg-hover);
}

.thread-item__body {
  padding: 0 var(--sp-6) var(--sp-6);
  border-top: var(--bw-thin) solid var(--border-subtle);
}

.thread-item.is-collapsed .thread-item__body {
  display: none;
}

.thread-item.is-collapsed .thread-item__preview {
  display: block;
}

.thread-item__preview {
  display: none;
  font-size: var(--fs-xs);
  color: var(--fg-subtle);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Reply strip at the bottom of the reader */
.reply-strip {
  display: flex;
  gap: var(--sp-4);
  margin-top: var(--sp-8);
  padding-top: var(--sp-8);
  border-top: var(--bw-thin) solid var(--border);
}

/* ==========================================================================
   17. COMPOSE MODAL — scrim overlay, card, address rows, editor, footer
   ========================================================================== */

.overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal-overlay);
  background: var(--bg-scrim);
  display: grid;
  place-items: center;
  padding: var(--sp-9);
  animation: overlay-in var(--dur-base) var(--ease-out);
}

@keyframes overlay-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.modal {
  position: relative;
  z-index: var(--z-modal);
  display: flex;
  flex-direction: column;
  width: min(920px, 100%);
  max-height: min(760px, 100%);
  background: var(--bg-overlay);
  border: var(--bw-thin) solid var(--border-mid);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-xl);
  overflow: hidden;
  animation: modal-in var(--dur-base) var(--ease-out);
}

@keyframes modal-in {
  from { opacity: 0; transform: translateY(8px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}

.modal--sm { width: min(480px, 100%); }
.modal--md { width: min(640px, 100%); }
.modal--lg { width: min(1040px, 100%); }

.modal__header {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  height: 44px;
  padding: 0 var(--sp-4) 0 var(--sp-7);
  border-bottom: var(--bw-thin) solid var(--border);
  background: var(--bg-raised);
}

.modal__title {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--fg-strong);
  letter-spacing: var(--ls-tight);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.modal__header-actions {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
}

.modal__body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.modal__footer {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-5) var(--sp-6);
  border-top: var(--bw-thin) solid var(--border);
  background: var(--bg-raised);
}

.modal__footer-spacer {
  flex: 1 1 auto;
}

.modal__section {
  padding: var(--sp-6) var(--sp-7);
}

/* Address rows */
.compose {
  display: flex;
  flex-direction: column;
  min-height: 0;
  flex: 1 1 auto;
}

.compose__fields {
  flex: none;
  border-bottom: var(--bw-thin) solid var(--border);
}

.addr-row {
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--sp-4);
  min-height: 34px;
  padding: var(--sp-2) var(--sp-6);
  border-bottom: var(--bw-thin) solid var(--border-subtle);
}

/* Labels and trailing actions align to the first field line */
.addr-row__label,
.addr-row__actions {
  padding-top: var(--sp-3);
}

.addr-row:last-child {
  border-bottom: 0;
}

.addr-row__label {
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--fg-subtle);
  text-align: left;
  user-select: none;
}

.addr-row__field {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2);
  min-width: 0;
}

.addr-row__actions {
  display: flex;
  gap: var(--sp-1);
}

.addr-input {
  flex: 1 1 140px;
  min-width: 120px;
  height: 26px;
  padding: 0 var(--sp-2);
  background: transparent;
  border: 0;
  color: var(--fg);
  font-size: var(--fs-sm);
}

.addr-input::placeholder {
  color: var(--fg-subtle);
}

.addr-input:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: -1px;
  border: 0;
  box-shadow: none;
  border-radius: var(--r-xs);
}

/* Recipient chip */
.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  height: 22px;
  padding: 0 var(--sp-2) 0 var(--sp-3);
  max-width: 240px;
  background: var(--bg-raised-2);
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-sm);
  color: var(--fg);
  font-size: var(--fs-xs);
  white-space: nowrap;
}

.chip__label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.chip__remove {
  display: grid;
  place-items: center;
  width: 15px;
  height: 15px;
  border-radius: var(--r-xs);
  color: var(--fg-subtle);
}

.chip__remove:hover {
  background: var(--bg-active);
  color: var(--danger-text);
}

.chip--invalid {
  border-color: var(--danger-border);
  background: var(--danger-subtle);
  color: var(--danger-text);
}

.chip--invalid .chip__label {
  text-decoration: underline dotted var(--danger);
  text-underline-offset: 2px;
}

.chip--accent {
  border-color: var(--accent-border);
  background: var(--accent-subtle);
  color: var(--accent-text);
}

/* Subject line */
.compose__subject {
  width: 100%;
  height: 34px;
  padding: 0 var(--sp-6);
  background: transparent;
  border: 0;
  border-bottom: var(--bw-thin) solid var(--border);
  color: var(--fg-strong);
  font-size: var(--fs-md);
  font-weight: var(--fw-medium);
}

.compose__subject::placeholder {
  color: var(--fg-subtle);
  font-weight: var(--fw-regular);
}

.compose__subject:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: -2px;
  box-shadow: none;
  border-bottom-color: var(--accent);
}

/* Body editor */
.compose__editor {
  flex: 1 1 auto;
  min-height: 220px;
  width: 100%;
  padding: var(--sp-7);
  background: transparent;
  border: 0;
  resize: none;
  color: var(--fg);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  letter-spacing: 0;
}

.compose__editor::placeholder {
  color: var(--fg-subtle);
}

.compose__editor:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: -3px;
  box-shadow: none;
}

.compose__editor--rich {
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  line-height: var(--lh-relaxed);
  letter-spacing: var(--ls-tight);
  overflow-y: auto;
}

/* Attachment tray inside compose */
.compose__tray {
  flex: none;
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-3);
  padding: var(--sp-5) var(--sp-7);
  border-top: var(--bw-thin) solid var(--border-subtle);
  background: var(--bg-raised);
}

/* Drag-and-drop target state */
.compose.is-dropping::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  border: 2px dashed var(--accent);
  border-radius: var(--r-lg);
  background: var(--accent-subtle);
  opacity: 0.5;
}

/* Autosave / status text in the footer */
.compose__status {
  font-size: var(--fs-2xs);
  color: var(--fg-subtle);
  font-variant-numeric: tabular-nums;
}

.compose__status--saving { color: var(--fg-subtle); }
.compose__status--saved { color: var(--success-text); }
.compose__status--error { color: var(--danger-text); }

/* ==========================================================================
   18. BUTTONS & ICON BUTTONS
   Variants: primary / secondary / ghost / danger / subtle / link.
   Sizes: sm / md (lg available for auth screens).
   ========================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-3);
  height: var(--control-h-md);
  padding: 0 var(--sp-6);
  border: var(--bw-thin) solid transparent;
  border-radius: var(--r-md);
  background: var(--bg-raised-2);
  color: var(--fg);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-tight);
  line-height: 1;
  white-space: nowrap;
  text-decoration: none;
  user-select: none;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-standard),
    border-color var(--dur-fast) var(--ease-standard),
    color var(--dur-fast) var(--ease-standard),
    box-shadow var(--dur-fast) var(--ease-standard),
    transform var(--dur-instant) var(--ease-standard);
}

.btn:hover {
  text-decoration: none;
}

.btn:active:not(:disabled) {
  transform: translateY(0.5px);
}

.btn svg {
  width: 14px;
  height: 14px;
}

.btn:disabled,
.btn[aria-disabled='true'],
.btn.is-disabled {
  opacity: 0.45;
  pointer-events: none;
}

/* Primary */
.btn--primary,
.btn.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-fg);
  box-shadow: var(--shadow-xs);
}

.btn--primary:hover,
.btn.primary:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
  color: var(--accent-fg);
}

.btn--primary:active,
.btn.primary:active {
  background: var(--accent-active);
  border-color: var(--accent-active);
}

/* Secondary — bordered neutral */
.btn--secondary,
.btn.secondary {
  background: var(--bg-raised-2);
  border-color: var(--border-strong);
  color: var(--fg);
}

.btn--secondary:hover,
.btn.secondary:hover {
  background: var(--bg-hover);
  border-color: var(--border-strong);
  color: var(--fg-strong);
}

.btn--secondary:active,
.btn.secondary:active {
  background: var(--bg-active);
}

/* Ghost — no chrome until hover */
.btn--ghost,
.btn.ghost {
  background: transparent;
  border-color: transparent;
  color: var(--fg-muted);
}

.btn--ghost:hover,
.btn.ghost:hover {
  background: var(--bg-hover);
  color: var(--fg-strong);
}

.btn--ghost:active,
.btn.ghost:active {
  background: var(--bg-active);
}

/* Subtle — tinted accent */
.btn--subtle {
  background: var(--accent-subtle);
  border-color: var(--accent-border);
  color: var(--accent-text);
}

.btn--subtle:hover {
  background: var(--accent-subtle-hover);
  color: var(--accent-text);
}

/* Danger */
.btn--danger,
.btn.danger {
  background: var(--danger);
  border-color: var(--danger);
  color: var(--danger-fg);
}

.btn--danger:hover,
.btn.danger:hover {
  background: var(--danger-hover);
  border-color: var(--danger-hover);
  color: var(--danger-fg);
}

/* Danger, quiet form (destructive item in a toolbar) */
.btn--danger-ghost {
  background: transparent;
  border-color: transparent;
  color: var(--danger-text);
}

.btn--danger-ghost:hover {
  background: var(--danger-subtle);
  color: var(--danger-text);
}

/* Link-styled button */
.btn--link {
  height: auto;
  padding: 0;
  background: none;
  border: 0;
  color: var(--accent-text);
  font-weight: var(--fw-medium);
}

.btn--link:hover {
  text-decoration: underline;
  background: none;
}

/* Sizes */
.btn--sm,
.btn.sm {
  height: var(--control-h-sm);
  padding: 0 var(--sp-5);
  font-size: var(--fs-xs);
  gap: var(--sp-2);
  border-radius: var(--r-sm);
}

.btn--sm svg,
.btn.sm svg {
  width: 12px;
  height: 12px;
}

.btn--md {
  height: var(--control-h-md);
}

.btn--lg {
  height: var(--control-h-lg);
  padding: 0 var(--sp-8);
  font-size: var(--fs-md);
  border-radius: var(--r-md);
}

.btn--block {
  width: 100%;
}

/* Busy state — swap label for a spinner via .btn__spinner */
.btn.is-loading {
  pointer-events: none;
  color: transparent;
  position: relative;
}

.btn.is-loading .btn__spinner {
  display: block;
}

.btn__spinner {
  display: none;
  position: absolute;
  inset: 0;
  margin: auto;
  width: 13px;
  height: 13px;
  border-radius: var(--r-circle);
  border: 2px solid currentColor;
  border-top-color: transparent;
  animation: spin 620ms linear infinite;
}

.spinner {
  width: 15px;
  height: 15px;
  border-radius: var(--r-circle);
  border: 2px solid var(--border-strong);
  border-top-color: var(--accent);
  animation: spin 620ms linear infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

/* Icon-only button */
.icon-btn {
  display: inline-grid;
  place-items: center;
  width: 28px;
  height: 28px;
  flex: none;
  border: var(--bw-thin) solid transparent;
  border-radius: var(--r-md);
  background: transparent;
  color: var(--fg-muted);
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-standard),
    color var(--dur-fast) var(--ease-standard),
    border-color var(--dur-fast) var(--ease-standard);
}

.icon-btn svg {
  width: 15px;
  height: 15px;
}

.icon-btn:hover {
  background: var(--bg-hover);
  color: var(--fg-strong);
}

.icon-btn:active {
  background: var(--bg-active);
}

.icon-btn.is-active,
.icon-btn[aria-pressed='true'] {
  background: var(--bg-active);
  color: var(--accent-text);
}

.icon-btn:disabled,
.icon-btn[aria-disabled='true'] {
  opacity: 0.4;
  pointer-events: none;
}

.icon-btn--sm {
  width: 22px;
  height: 22px;
  border-radius: var(--r-sm);
}

.icon-btn--sm svg {
  width: 13px;
  height: 13px;
}

.icon-btn--bordered {
  border-color: var(--border);
  background: var(--bg-raised-2);
}

.icon-btn--danger:hover {
  background: var(--danger-subtle);
  color: var(--danger-text);
}

/* Segmented control / button group */
.btn-group {
  display: inline-flex;
  align-items: stretch;
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-md);
  background: var(--bg-raised-2);
  overflow: hidden;
}

.btn-group > .btn,
.btn-group > .icon-btn {
  border-radius: 0;
  border-width: 0;
  height: var(--control-h-sm);
}

.btn-group > * + * {
  border-left: var(--bw-thin) solid var(--border);
}

.btn-group > .is-active {
  background: var(--bg-active);
  color: var(--fg-strong);
}

/* Split button (primary + caret) */
.btn-split {
  display: inline-flex;
}

.btn-split > .btn:first-child {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}

.btn-split > .btn:last-child {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
  padding: 0 var(--sp-3);
  border-left-color: rgba(0, 0, 0, 0.25);
}

/* ==========================================================================
   19. FORM CONTROLS — labels, inputs, selects, textareas, checkbox, switch
   ========================================================================== */

.field {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  min-width: 0;
}

.field__label {
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--fg-muted);
}

.field__label .req {
  color: var(--danger-text);
  margin-left: 2px;
}

.field__hint {
  font-size: var(--fs-xs);
  color: var(--fg-subtle);
  line-height: var(--lh-snug);
}

.field__error {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--danger-text);
  line-height: var(--lh-snug);
}

.field--row {
  flex-direction: row;
  align-items: center;
  gap: var(--sp-5);
}

.input,
.select,
.textarea {
  width: 100%;
  background: var(--bg-inset);
  color: var(--fg);
  border: var(--bw-thin) solid var(--border-strong);
  border-radius: var(--r-md);
  font-size: var(--fs-sm);
  font-family: inherit;
  transition: border-color var(--dur-fast) var(--ease-standard),
    box-shadow var(--dur-fast) var(--ease-standard),
    background-color var(--dur-fast) var(--ease-standard);
}

.input,
.select {
  height: var(--control-h-md);
  padding: 0 var(--sp-5);
}

.textarea {
  padding: var(--sp-4) var(--sp-5);
  min-height: 80px;
  line-height: var(--lh-normal);
}

.input::placeholder,
.textarea::placeholder {
  color: var(--fg-subtle);
}

.input:hover,
.select:hover,
.textarea:hover {
  border-color: var(--fg-faint);
}

.input:disabled,
.select:disabled,
.textarea:disabled {
  background: var(--bg-sunken);
  color: var(--fg-subtle);
  border-color: var(--border);
  cursor: not-allowed;
}

.input[aria-invalid='true'],
.select[aria-invalid='true'],
.textarea[aria-invalid='true'],
.input.is-invalid {
  border-color: var(--danger);
}

.input--sm,
.select--sm {
  height: var(--control-h-sm);
  padding: 0 var(--sp-4);
  font-size: var(--fs-xs);
  border-radius: var(--r-sm);
}

.input--mono {
  font-family: var(--font-mono);
  letter-spacing: 0;
}

/* Native select: custom caret drawn with a gradient-free SVG data URI */
.select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: var(--sp-10);
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M3 4.5 6 7.5 9 4.5' fill='none' stroke='%238b949c' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--sp-5) center;
  cursor: pointer;
}

[data-theme='light'] .select {
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M3 4.5 6 7.5 9 4.5' fill='none' stroke='%235d666d' stroke-width='1.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.select option {
  background: var(--bg-overlay);
  color: var(--fg);
}

/* Input group with a leading/trailing addon */
.input-group {
  display: flex;
  align-items: center;
  width: 100%;
  background: var(--bg-inset);
  border: var(--bw-thin) solid var(--border-strong);
  border-radius: var(--r-md);
  overflow: hidden;
}

.input-group:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--focus-ring) 34%, transparent);
}

@supports not (color: color-mix(in srgb, red, blue)) {
  .input-group:focus-within {
    box-shadow: 0 0 0 3px var(--accent-subtle);
  }
}

.input-group > .input {
  border: 0;
  border-radius: 0;
  background: transparent;
}

.input-group > .input:focus-visible {
  box-shadow: none;
}

.input-group__addon {
  flex: none;
  display: grid;
  place-items: center;
  height: var(--control-h-md);
  padding: 0 var(--sp-5);
  background: var(--bg-raised-2);
  color: var(--fg-subtle);
  font-size: var(--fs-xs);
  font-family: var(--font-mono);
  border-right: var(--bw-thin) solid var(--border);
}

.input-group__addon--end {
  border-right: 0;
  border-left: var(--bw-thin) solid var(--border);
}

/* Checkbox / radio */
.checkbox,
.radio {
  appearance: none;
  -webkit-appearance: none;
  flex: none;
  width: 15px;
  height: 15px;
  margin: 0;
  background: var(--bg-inset);
  border: var(--bw-thin) solid var(--border-strong);
  border-radius: var(--r-xs);
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: background-color var(--dur-fast) var(--ease-standard),
    border-color var(--dur-fast) var(--ease-standard);
}

.radio {
  border-radius: var(--r-circle);
}

.checkbox:hover,
.radio:hover {
  border-color: var(--accent);
}

.checkbox:checked,
.radio:checked {
  background: var(--accent);
  border-color: var(--accent);
}

.checkbox:checked::after {
  content: '';
  width: 8px;
  height: 5px;
  border: 2px solid var(--accent-fg);
  border-top: 0;
  border-right: 0;
  transform: rotate(-45deg) translateY(-1px);
}

.checkbox:indeterminate {
  background: var(--accent);
  border-color: var(--accent);
}

.checkbox:indeterminate::after {
  content: '';
  width: 8px;
  height: 2px;
  background: var(--accent-fg);
  border-radius: 1px;
}

.radio:checked::after {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: var(--r-circle);
  background: var(--accent-fg);
}

.checkbox:disabled,
.radio:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.check-label {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-4);
  font-size: var(--fs-sm);
  color: var(--fg);
  cursor: pointer;
  user-select: none;
}

/* Switch */
.switch {
  appearance: none;
  -webkit-appearance: none;
  position: relative;
  flex: none;
  width: 30px;
  height: 17px;
  margin: 0;
  border-radius: var(--r-pill);
  background: var(--bg-active);
  border: var(--bw-thin) solid var(--border-strong);
  cursor: pointer;
  transition: background-color var(--dur-base) var(--ease-standard),
    border-color var(--dur-base) var(--ease-standard);
}

.switch::after {
  content: '';
  position: absolute;
  top: 1px;
  left: 1px;
  width: 13px;
  height: 13px;
  border-radius: var(--r-circle);
  background: var(--fg-muted);
  transition: transform var(--dur-base) var(--ease-out),
    background-color var(--dur-base) var(--ease-standard);
}

.switch:checked {
  background: var(--accent);
  border-color: var(--accent);
}

.switch:checked::after {
  transform: translateX(13px);
  background: var(--accent-fg);
}

.switch:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

/* ==========================================================================
   20. DROPDOWN MENUS & CONTEXT MENUS
   ========================================================================== */

.dropdown {
  position: relative;
  display: inline-flex;
}

.menu {
  position: absolute;
  z-index: var(--z-dropdown);
  min-width: 200px;
  max-width: 320px;
  max-height: min(420px, 70vh);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--sp-2);
  background: var(--bg-overlay);
  border: var(--bw-thin) solid var(--border-mid);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  animation: menu-in var(--dur-fast) var(--ease-out);
}

@keyframes menu-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}

.menu--end   { right: 0; }
.menu--start { left: 0; }

/* Never let a menu exceed the viewport on either axis */
.menu {
  max-width: min(320px, calc(100vw - var(--sp-8)));
}
.menu--below { top: calc(100% + var(--sp-2)); }
.menu--above { bottom: calc(100% + var(--sp-2)); }

/* Fixed-position variant for context menus placed by JS */
.menu--fixed {
  position: fixed;
}

.menu__label {
  padding: var(--sp-3) var(--sp-4) var(--sp-2);
  font-size: var(--fs-3xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--fg-subtle);
}

.menu__sep {
  height: var(--bw-thin);
  margin: var(--sp-2) calc(var(--sp-2) * -1);
  background: var(--border);
}

.menu-item {
  display: flex;
  align-items: center;
  gap: var(--sp-5);
  width: 100%;
  min-height: 28px;
  padding: 0 var(--sp-4);
  border-radius: var(--r-sm);
  color: var(--fg);
  font-size: var(--fs-sm);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color var(--dur-instant) var(--ease-standard);
}

.menu-item:hover,
.menu-item.is-highlighted {
  background: var(--bg-hover);
  color: var(--fg-strong);
  text-decoration: none;
}

.menu-item__icon {
  width: 14px;
  height: 14px;
  flex: none;
  color: var(--fg-subtle);
}

.menu-item:hover .menu-item__icon {
  color: var(--fg);
}

.menu-item__label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.menu-item__shortcut {
  flex: none;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  color: var(--fg-subtle);
  letter-spacing: 0;
}

.menu-item__check {
  width: 14px;
  height: 14px;
  flex: none;
  color: var(--accent-text);
  visibility: hidden;
}

.menu-item[aria-checked='true'] .menu-item__check,
.menu-item.is-checked .menu-item__check {
  visibility: visible;
}

.menu-item--danger {
  color: var(--danger-text);
}

.menu-item--danger:hover {
  background: var(--danger-subtle);
  color: var(--danger-text);
}

.menu-item--danger .menu-item__icon {
  color: var(--danger-text);
}

.menu-item:disabled,
.menu-item[aria-disabled='true'] {
  opacity: 0.42;
  pointer-events: none;
}

/* User menu trigger in the topbar */
.usermenu {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  height: var(--control-h-md);
  padding: 0 var(--sp-3) 0 var(--sp-2);
  border-radius: var(--r-md);
  color: var(--fg);
  transition: background-color var(--dur-fast) var(--ease-standard);
}

.usermenu:hover {
  background: var(--bg-hover);
}

.usermenu__meta {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  min-width: 0;
  line-height: 1.15;
}

.usermenu__name {
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--fg-strong);
  max-width: 160px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.usermenu__addr {
  font-size: var(--fs-3xs);
  color: var(--fg-subtle);
  max-width: 160px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ==========================================================================
   21. AVATARS — square-ish monogram tiles with 12 deterministic color
   variants (hash the address in JS, apply .avatar--cN).
   ========================================================================== */

.avatar {
  position: relative;
  display: grid;
  place-items: center;
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: var(--r-md);
  background: var(--bg-active);
  color: var(--fg);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semibold);
  letter-spacing: 0;
  text-transform: uppercase;
  user-select: none;
  overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.16);
}

.avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.avatar--xs { width: 18px; height: 18px; font-size: var(--fs-3xs); border-radius: var(--r-xs); }
.avatar--sm { width: 22px; height: 22px; font-size: var(--fs-3xs); border-radius: var(--r-sm); }
.avatar--md { width: 28px; height: 28px; font-size: var(--fs-2xs); }
.avatar--lg { width: 36px; height: 36px; font-size: var(--fs-sm); border-radius: var(--r-lg); }
.avatar--xl { width: 48px; height: 48px; font-size: var(--fs-lg); border-radius: var(--r-lg); }

.avatar--circle { border-radius: var(--r-circle); }

/* Deterministic color variants. --avatar-fg flips per theme for AA contrast
   against these mid-tone fills. */
.avatar--c1  { background: var(--hue-1);  color: var(--avatar-fg); }
.avatar--c2  { background: var(--hue-2);  color: var(--avatar-fg); }
.avatar--c3  { background: var(--hue-3);  color: var(--avatar-fg); }
.avatar--c4  { background: var(--hue-4);  color: var(--avatar-fg); }
.avatar--c5  { background: var(--hue-5);  color: var(--avatar-fg); }
.avatar--c6  { background: var(--hue-6);  color: var(--avatar-fg); }
.avatar--c7  { background: var(--hue-7);  color: var(--avatar-fg); }
.avatar--c8  { background: var(--hue-8);  color: var(--avatar-fg); }
.avatar--c9  { background: var(--hue-9);  color: var(--avatar-fg); }
.avatar--c10 { background: var(--hue-10); color: var(--avatar-fg); }
.avatar--c11 { background: var(--hue-11); color: var(--avatar-fg); }
.avatar--c12 { background: var(--hue-12); color: var(--avatar-fg); }

/* Light theme needs darker fills so the white monogram clears 4.5:1.
   Each value below is the same hue, luminance-reduced until it passes. */
[data-theme='light'] .avatar--c1  { background: #176cf7; }
[data-theme='light'] .avatar--c2  { background: #0d8275; }
[data-theme='light'] .avatar--c3  { background: #258537; }
[data-theme='light'] .avatar--c4  { background: #76790d; }
[data-theme='light'] .avatar--c5  { background: #966d17; }
[data-theme='light'] .avatar--c6  { background: #bb571c; }
[data-theme='light'] .avatar--c7  { background: #e2272d; }
[data-theme='light'] .avatar--c8  { background: #d22b94; }
[data-theme='light'] .avatar--c9  { background: #8351f7; }
[data-theme='light'] .avatar--c10 { background: #5f62f2; }
[data-theme='light'] .avatar--c11 { background: #097bae; }
[data-theme='light'] .avatar--c12 { background: #5b6878; }

/* Presence / status dot */
.avatar__status {
  position: absolute;
  right: -2px;
  bottom: -2px;
  width: 8px;
  height: 8px;
  border-radius: var(--r-circle);
  background: var(--fg-faint);
  box-shadow: 0 0 0 2px var(--bg-raised);
}

.avatar__status--online { background: var(--success); }
.avatar__status--away { background: var(--warning); }

/* Overlapping stack for thread participants */
.avatar-stack {
  display: flex;
  align-items: center;
}

.avatar-stack > .avatar + .avatar {
  margin-left: -6px;
  box-shadow: 0 0 0 2px var(--bg-raised);
}

/* ==========================================================================
   22. BADGES, PILLS, TAGS, KEYCAPS
   ========================================================================== */

.badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-width: 17px;
  height: 17px;
  padding: 0 var(--sp-3);
  border-radius: var(--r-pill);
  background: var(--bg-active);
  color: var(--fg-muted);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
  white-space: nowrap;
}

.badge--accent  { background: var(--accent); color: var(--accent-fg); }
.badge--success { background: var(--success); color: var(--success-fg); }
.badge--warning { background: var(--warning); color: var(--warning-fg); }
.badge--danger  { background: var(--danger); color: var(--danger-fg); }

.badge--dot {
  min-width: 7px;
  width: 7px;
  height: 7px;
  padding: 0;
}

/* Pill — outlined status label, the workhorse for mail metadata */
.pill {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  height: 19px;
  padding: 0 var(--sp-4);
  border-radius: var(--r-pill);
  border: var(--bw-thin) solid var(--border);
  background: var(--bg-raised-2);
  color: var(--fg-muted);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-wide);
  white-space: nowrap;
}

.pill svg {
  width: 11px;
  height: 11px;
}

.pill--accent {
  background: var(--accent-subtle);
  border-color: var(--accent-border);
  color: var(--accent-text);
}

.pill--success {
  background: var(--success-subtle);
  border-color: var(--success-border);
  color: var(--success-text);
}

.pill--warning {
  background: var(--warning-subtle);
  border-color: var(--warning-border);
  color: var(--warning-text);
}

.pill--danger {
  background: var(--danger-subtle);
  border-color: var(--danger-border);
  color: var(--danger-text);
}

.pill--info {
  background: var(--info-subtle);
  border-color: var(--info-border);
  color: var(--info-text);
}

.pill--mono {
  font-family: var(--font-mono);
  font-size: var(--fs-3xs);
  letter-spacing: 0;
}

.pill--square {
  border-radius: var(--r-xs);
}

/* Tag — user labels with a color dot */
.tag {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  height: 18px;
  padding: 0 var(--sp-3);
  border-radius: var(--r-xs);
  background: var(--bg-active);
  color: var(--fg-muted);
  font-size: var(--fs-2xs);
  max-width: 160px;
}

.tag__dot {
  width: 6px;
  height: 6px;
  flex: none;
  border-radius: var(--r-circle);
  background: currentColor;
}

.tag__label {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Keycap for shortcut hints */
.kbd {
  display: inline-grid;
  place-items: center;
  min-width: 17px;
  height: 17px;
  padding: 0 var(--sp-2);
  background: var(--bg-raised-2);
  border: var(--bw-thin) solid var(--border-strong);
  border-bottom-width: 2px;
  border-radius: var(--r-xs);
  color: var(--fg-muted);
  font-family: var(--font-mono);
  font-size: var(--fs-3xs);
  letter-spacing: 0;
  line-height: 1;
}

/* ==========================================================================
   23. TOASTS
   ========================================================================== */

.toaster {
  position: fixed;
  right: var(--sp-6);
  bottom: var(--sp-6);
  z-index: var(--z-toast);
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--sp-3);
  pointer-events: none;
  max-width: min(420px, calc(100vw - var(--sp-10)));
}

.toast {
  pointer-events: auto;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--sp-5);
  width: 100%;
  padding: var(--sp-5) var(--sp-5) var(--sp-5) var(--sp-6);
  background: var(--bg-overlay);
  border: var(--bw-thin) solid var(--border-mid);
  border-left: 2px solid var(--fg-faint);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
  color: var(--fg);
  font-size: var(--fs-xs);
  line-height: var(--lh-snug);
  animation: toast-in var(--dur-base) var(--ease-out);
}

@keyframes toast-in {
  from { opacity: 0; transform: translateY(8px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}

.toast.is-leaving {
  animation: toast-out var(--dur-fast) var(--ease-in) forwards;
}

@keyframes toast-out {
  to { opacity: 0; transform: translateY(4px); }
}

.toast__icon {
  width: 15px;
  height: 15px;
  flex: none;
  margin-top: 1px;
  color: var(--fg-subtle);
}

.toast__content {
  min-width: 0;
}

.toast__title {
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  color: var(--fg-strong);
}

.toast__msg {
  color: var(--fg-muted);
  overflow-wrap: anywhere;
}

.toast__actions {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex: none;
}

.toast--success { border-left-color: var(--success); }
.toast--success .toast__icon { color: var(--success-text); }
.toast--warning { border-left-color: var(--warning); }
.toast--warning .toast__icon { color: var(--warning-text); }
.toast--danger,
.toast.err { border-left-color: var(--danger); }
.toast--danger .toast__icon { color: var(--danger-text); }
.toast--info { border-left-color: var(--info); }
.toast--info .toast__icon { color: var(--info-text); }

/* Progress bar for auto-dismiss */
.toast__timer {
  grid-column: 2 / -1;
  height: 2px;
  margin-top: var(--sp-3);
  border-radius: var(--r-pill);
  background: var(--bg-active);
  overflow: hidden;
}

.toast__timer::after {
  content: '';
  display: block;
  height: 100%;
  width: 100%;
  background: var(--fg-faint);
  transform-origin: left;
  animation: toast-timer 5s linear forwards;
}

@keyframes toast-timer {
  to { transform: scaleX(0); }
}

/* ==========================================================================
   24. SKELETON LOADING
   ========================================================================== */

.skeleton,
.skel {
  position: relative;
  overflow: hidden;
  background: var(--skeleton-base);
  border-radius: var(--r-sm);
}

.skeleton::after,
.skel::after {
  content: '';
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(
    90deg,
    transparent 0%,
    var(--skeleton-sheen) 50%,
    transparent 100%
  );
  animation: shimmer 1.35s var(--ease-in-out) infinite;
}

@keyframes shimmer {
  100% { transform: translateX(100%); }
}

.skeleton-line {
  height: 9px;
  border-radius: var(--r-pill);
}

.skeleton-line--sm { height: 7px; }
.skeleton-line--lg { height: 13px; }

.skeleton--w25 { width: 25%; }
.skeleton--w40 { width: 40%; }
.skeleton--w60 { width: 60%; }
.skeleton--w75 { width: 75%; }
.skeleton--w90 { width: 90%; }

.skeleton--avatar {
  width: 28px;
  height: 28px;
  border-radius: var(--r-md);
  flex: none;
}

.skeleton--block {
  height: 120px;
  border-radius: var(--r-md);
}

/* Skeleton row that mirrors .msg-row geometry */
.skeleton-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: var(--sp-5);
  padding: var(--sp-5) var(--sp-6);
  border-bottom: var(--bw-thin) solid var(--border-subtle);
}

.skeleton-row__lines {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  min-width: 0;
}

/* Indeterminate top progress bar for background sync */
.progress-line {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 2px;
  overflow: hidden;
  background: transparent;
  z-index: var(--z-sticky);
}

.progress-line::after {
  content: '';
  position: absolute;
  inset: 0;
  width: 40%;
  background: var(--accent);
  animation: indeterminate 1.1s var(--ease-in-out) infinite;
}

@keyframes indeterminate {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(350%); }
}

/* ==========================================================================
   25. EMPTY STATES
   ========================================================================== */

.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-5);
  height: 100%;
  min-height: 220px;
  padding: var(--sp-14) var(--sp-9);
  text-align: center;
  color: var(--fg-subtle);
}

.empty__icon {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: var(--r-lg);
  background: var(--bg-raised-2);
  border: var(--bw-thin) solid var(--border);
  color: var(--fg-faint);
}

.empty__icon svg {
  width: 20px;
  height: 20px;
}

.empty__title {
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
  color: var(--fg);
  letter-spacing: var(--ls-tight);
}

.empty__text {
  font-size: var(--fs-xs);
  color: var(--fg-subtle);
  max-width: 42ch;
  line-height: var(--lh-normal);
}

.empty__actions {
  display: flex;
  gap: var(--sp-3);
  margin-top: var(--sp-2);
}

.empty--compact {
  min-height: 120px;
  padding: var(--sp-9) var(--sp-6);
}

/* Reader placeholder when nothing is selected */
.reader-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-6);
  height: 100%;
  color: var(--fg-subtle);
}

.reader-placeholder__hints {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  font-size: var(--fs-2xs);
  color: var(--fg-subtle);
}

.reader-placeholder__hint {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
}

/* ==========================================================================
   26. TOOLTIPS — CSS-only, driven by [data-tip] + optional placement class
   ========================================================================== */

[data-tip] {
  position: relative;
}

[data-tip]::after {
  content: attr(data-tip);
  position: absolute;
  z-index: var(--z-tooltip);
  left: 50%;
  top: calc(100% + 6px);
  transform: translateX(-50%) translateY(-2px);
  padding: var(--sp-2) var(--sp-4);
  max-width: 260px;
  width: max-content;
  background: var(--bg-overlay);
  color: var(--fg);
  border: var(--bw-thin) solid var(--border-mid);
  border-radius: var(--r-sm);
  box-shadow: var(--shadow-md);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-medium);
  line-height: var(--lh-snug);
  white-space: pre-line;
  text-align: center;
  letter-spacing: var(--ls-normal);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-fast) var(--ease-standard) 40ms,
    transform var(--dur-fast) var(--ease-out) 40ms;
}

[data-tip]:hover::after,
[data-tip]:focus-visible::after {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

[data-tip][data-tip-pos='top']::after {
  top: auto;
  bottom: calc(100% + 6px);
  transform: translateX(-50%) translateY(2px);
}

[data-tip][data-tip-pos='top']:hover::after,
[data-tip][data-tip-pos='top']:focus-visible::after {
  transform: translateX(-50%) translateY(0);
}

[data-tip][data-tip-pos='right']::after {
  top: 50%;
  left: calc(100% + 6px);
  transform: translateY(-50%) translateX(-2px);
}

[data-tip][data-tip-pos='right']:hover::after,
[data-tip][data-tip-pos='right']:focus-visible::after {
  transform: translateY(-50%) translateX(0);
}

[data-tip][data-tip-pos='left']::after {
  top: 50%;
  left: auto;
  right: calc(100% + 6px);
  transform: translateY(-50%) translateX(2px);
}

[data-tip][data-tip-pos='left']:hover::after,
[data-tip][data-tip-pos='left']:focus-visible::after {
  transform: translateY(-50%) translateX(0);
}

[data-tip='']::after,
[data-tip]:not([data-tip])::after {
  display: none;
}

/* Explicit tooltip element (for JS-positioned tooltips) */
.tooltip {
  position: fixed;
  z-index: var(--z-tooltip);
  padding: var(--sp-2) var(--sp-4);
  max-width: 280px;
  background: var(--bg-overlay);
  color: var(--fg);
  border: var(--bw-thin) solid var(--border-mid);
  border-radius: var(--r-sm);
  box-shadow: var(--shadow-md);
  font-size: var(--fs-2xs);
  line-height: var(--lh-snug);
  pointer-events: none;
}

/* ==========================================================================
   27. AUTH / LOGIN SCREEN
   ========================================================================== */

.login-wrap {
  display: grid;
  place-items: center;
  min-height: 100vh;
  min-height: 100dvh;
  padding: var(--sp-9);
  background: var(--bg);
}

.login-card {
  width: min(380px, 100%);
  padding: var(--sp-10);
  background: var(--bg-raised);
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-lg);
}

.login-card__head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-4);
  margin-bottom: var(--sp-9);
  text-align: center;
}

.login-card__title {
  font-size: var(--fs-xl);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-tighter);
  color: var(--fg-strong);
}

.login-card__sub {
  font-size: var(--fs-xs);
  color: var(--fg-subtle);
}

.login-card__form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-6);
}

.login-card__foot {
  margin-top: var(--sp-8);
  padding-top: var(--sp-6);
  border-top: var(--bw-thin) solid var(--border-subtle);
  font-size: var(--fs-2xs);
  color: var(--fg-subtle);
  text-align: center;
}

/* Inline form error / notice */
.alert {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-4);
  padding: var(--sp-4) var(--sp-5);
  border-radius: var(--r-md);
  border: var(--bw-thin) solid var(--border);
  background: var(--bg-raised-2);
  color: var(--fg);
  font-size: var(--fs-xs);
  line-height: var(--lh-snug);
}

.alert svg {
  width: 14px;
  height: 14px;
  flex: none;
  margin-top: 1px;
}

.alert--danger {
  border-color: var(--danger-border);
  background: var(--danger-subtle);
  color: var(--danger-text);
}

.alert--success {
  border-color: var(--success-border);
  background: var(--success-subtle);
  color: var(--success-text);
}

.alert--warning {
  border-color: var(--warning-border);
  background: var(--warning-subtle);
  color: var(--warning-text);
}

.alert--info {
  border-color: var(--info-border);
  background: var(--info-subtle);
  color: var(--info-text);
}

/* ==========================================================================
   28. SETTINGS PANELS & COMMAND PALETTE (secondary surfaces)
   ========================================================================== */

.panel {
  background: var(--bg-raised);
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-lg);
  overflow: hidden;
}

.panel__head {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  padding: var(--sp-5) var(--sp-6);
  border-bottom: var(--bw-thin) solid var(--border);
  background: var(--bg-raised-2);
}

.panel__title {
  flex: 1 1 auto;
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--fg-strong);
}

.panel__body {
  padding: var(--sp-6);
}

.setting-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--sp-6);
  padding: var(--sp-5) 0;
  border-bottom: var(--bw-thin) solid var(--border-subtle);
}

.setting-row:last-child {
  border-bottom: 0;
}

.setting-row__label {
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--fg);
}

.setting-row__hint {
  margin-top: 2px;
  font-size: var(--fs-2xs);
  color: var(--fg-subtle);
  line-height: var(--lh-snug);
}

/* Command palette (Cmd+K) */
.palette-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal-overlay);
  background: var(--bg-scrim);
  display: grid;
  align-items: start;
  justify-items: center;
  padding: 12vh var(--sp-6) var(--sp-6);
}

.palette {
  width: min(560px, 100%);
  max-height: 60vh;
  display: flex;
  flex-direction: column;
  background: var(--bg-overlay);
  border: var(--bw-thin) solid var(--border-mid);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-xl);
  overflow: hidden;
  animation: modal-in var(--dur-base) var(--ease-out);
}

.palette__input {
  flex: none;
  height: 44px;
  padding: 0 var(--sp-7);
  background: transparent;
  border: 0;
  border-bottom: var(--bw-thin) solid var(--border);
  color: var(--fg-strong);
  font-size: var(--fs-md);
}

.palette__input:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: -2px;
  box-shadow: none;
}

.palette__results {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: var(--sp-3);
}

/* ==========================================================================
   29. UTILITIES — layout helpers used across components
   ========================================================================== */

.row { display: flex; align-items: center; gap: var(--sp-4); min-width: 0; }
.row--start { align-items: flex-start; }
.row--between { justify-content: space-between; }
.row--end { justify-content: flex-end; }
.row--wrap { flex-wrap: wrap; }
.col { display: flex; flex-direction: column; gap: var(--sp-4); min-width: 0; }
.spacer { flex: 1 1 auto; }
.grow { flex: 1 1 auto; min-width: 0; }
.none { flex: none; }

.gap-1 { gap: var(--sp-1); }
.gap-2 { gap: var(--sp-2); }
.gap-3 { gap: var(--sp-3); }
.gap-4 { gap: var(--sp-4); }
.gap-6 { gap: var(--sp-6); }
.gap-8 { gap: var(--sp-8); }

.mt-2 { margin-top: var(--sp-2); }
.mt-4 { margin-top: var(--sp-4); }
.mt-6 { margin-top: var(--sp-6); }
.mt-8 { margin-top: var(--sp-8); }
.mb-2 { margin-bottom: var(--sp-2); }
.mb-4 { margin-bottom: var(--sp-4); }
.mb-6 { margin-bottom: var(--sp-6); }
.mb-8 { margin-bottom: var(--sp-8); }

.p-4 { padding: var(--sp-4); }
.p-6 { padding: var(--sp-6); }
.p-8 { padding: var(--sp-8); }

.hidden { display: none !important; }
.invisible { visibility: hidden; }
.relative { position: relative; }
.full { width: 100%; }
.center { text-align: center; }
.nowrap { white-space: nowrap; }
.break { overflow-wrap: anywhere; }
.pointer { cursor: pointer; }
.select-none { user-select: none; }
.select-all { user-select: all; }

.sep {
  height: var(--bw-thin);
  background: var(--border);
  border: 0;
  margin: var(--sp-6) 0;
}

.sep--v {
  width: var(--bw-thin);
  height: auto;
  align-self: stretch;
  margin: 0 var(--sp-4);
}

/* Visibility helpers driven by the responsive breakpoints below */
.only-mobile { display: none; }
.only-desktop { display: initial; }

/* ==========================================================================
   30. RESPONSIVE
   >=1200px : 3-pane (sidebar + list + reader)   [defaults above]
   760–1199 : 2-pane (sidebar + list), reader overlays the list
   <760px   : single pane, slide-in sidebar drawer, off-canvas reader
   ========================================================================== */

/* NOTE: the ladder that used to live here (>=1200 / 760-1199 / <760) did not
   match DESIGN-SPEC §4.1 and produced horizontal overflow at several widths,
   because it forced a fixed `--sidebar-w` track into viewports narrower than
   sidebar + list. The normative ladder is section 40 at the end of this file;
   only the pieces that section 40 does not restate are kept here. */

.search {
  max-width: 560px;
}

/* The former `<760px` single-pane block lived here. It has been folded into
   the normative ladder in section 40 (the `<768px` breakpoint), which also
   fixes the 760-767px dead zone the old 759px cutoff left behind. */


/* Reader back-button visibility is breakpoint-driven */
.reader__back {
  display: none;
}

/* Coarse pointers: no hover-reveal affordances */
@media (hover: none) {
  .msg-row__check,
  .sb-section__action {
    opacity: 1;
  }

  .msg-row__quick {
    display: none !important;
  }

  [data-tip]::after {
    display: none;
  }
}

/* Short viewports: trim vertical padding */
@media (max-height: 620px) {
  .reader__inner {
    padding-top: var(--sp-6);
  }

  .login-card {
    padding: var(--sp-8);
  }
}

/* ==========================================================================
   31. PRINT — reader content only, on white
   ========================================================================== */

@media print {
  body {
    overflow: visible;
    background: #fff;
    color: #000;
  }

  .app {
    display: block;
    height: auto;
  }

  .app__topbar,
  .app__sidebar,
  .app__list,
  .reader__toolbar,
  .toaster,
  .overlay,
  .resizer,
  .msg-row__quick,
  .reply-strip {
    display: none !important;
  }

  .app__reader {
    position: static;
    transform: none;
    visibility: visible;
    box-shadow: none;
    border: 0;
  }

  .reader__scroll,
  .reader__inner {
    overflow: visible;
    max-width: none;
    padding: 0;
  }

  .msg-body,
  .msg-body--html,
  .msg-body--text {
    color: #000;
    background: #fff;
  }

  a {
    color: #000;
    text-decoration: underline;
  }

  .auth-pill,
  .pill,
  .badge {
    border: 1px solid #999;
    color: #000;
    background: #fff;
  }
}

/* ==========================================================================
   32. BUILT-IN THEMES (Halyard)

   Each block below is a complete semantic-token override, so a theme is
   selected by one attribute on <html> and nothing has to be re-rendered
   (§9.1). `dark` and `light` live in sections 03/04; these are the extras.

   Every surface/text pair in every block was checked against WCAG 2.x
   relative luminance; the worst body pair per theme is noted in its header
   and all of them clear 4.5:1.
   ========================================================================== */

/* ---- Midnight: true black for OLED. worst body pair 5.16:1 -------------- */
[data-theme='midnight'] {
  color-scheme: dark;

  --bg: #000000;
  --bg-sunken: #000000;
  --bg-raised: #0a0a0c;
  --bg-raised-2: #101012;
  --bg-overlay: #141417;
  --bg-hover: #16161a;
  --bg-active: #1d1d22;
  --bg-selected: #16233d;
  --bg-selected-hover: #1b2c4b;
  --bg-inset: #070708;
  --bg-scrim: rgba(0, 0, 0, 0.66);
  --bg-unread: #0c0c0f;

  --border: #24242a;
  --border-subtle: #16161a;
  --border-strong: #5d5d66;
  --border-mid: #383840;

  --fg: #e9ecef;
  --fg-strong: #ffffff;
  --fg-muted: #a8b0b8;
  --fg-subtle: #8d959d;
  --fg-faint: #767d85;

  --accent: #3b6fe0;
  --accent-hover: #5285ef;
  --accent-active: #2c5cc4;
  --accent-fg: #ffffff;
  --accent-text: #87b4ff;
  --accent-subtle: #0d1729;
  --accent-subtle-hover: #121f36;
  --accent-border: #2c4d84;

  --success: #2ea043;
  --success-fg: #05190d;
  --success-text: #5ad06e;
  --success-subtle: #071a0f;
  --success-border: #1c5a2b;

  --warning: #d29922;
  --warning-fg: #1c1204;
  --warning-text: #ecc25a;
  --warning-subtle: #1d1505;
  --warning-border: #66490f;

  --danger: #c3252f;
  --danger-hover: #d93b44;
  --danger-fg: #ffffff;
  --danger-text: #f57f84;
  --danger-subtle: #1d0b0d;
  --danger-border: #6a2024;

  --info: #0ea5e9;
  --info-text: #5cc9f7;
  --info-subtle: #04191f;
  --info-border: #155273;

  --focus-ring: #7fb0ff;
  --focus-ring-contrast: #000000;

  --selection-bg: #1d4a92;
  --selection-fg: #ffffff;

  --scroll-thumb: #26262c;
  --scroll-thumb-hover: #35353d;

  --avatar-fg: #000000;
  --skeleton-base: #101013;
  --skeleton-sheen: #1c1c21;

  --mail-body-bg: #08080a;
  --mail-body-fg: #e3e6ea;
  --mail-quote-border: #2c2c33;
}

/* ---- Nord: cool desaturated slate. worst body pair 5.44:1 --------------- */
[data-theme='nord'] {
  color-scheme: dark;

  --bg: #20242c;
  --bg-sunken: #1a1e25;
  --bg-raised: #272c36;
  --bg-raised-2: #2b313c;
  --bg-overlay: #2f3542;
  --bg-hover: #313846;
  --bg-active: #39414f;
  --bg-selected: #2c3b52;
  --bg-selected-hover: #34455f;
  --bg-inset: #1c2028;
  --bg-scrim: rgba(10, 12, 16, 0.58);
  --bg-unread: #242932;

  --border: #3a4250;
  --border-subtle: #2b313c;
  --border-strong: #737f90;
  --border-mid: #4c5568;

  --fg: #e9eef4;
  --fg-strong: #f7fafc;
  --fg-muted: #bec8d4;
  --fg-subtle: #aab5c2;
  --fg-faint: #8f9aa8;

  --accent: #39679f;
  --accent-hover: #4a7ab5;
  --accent-active: #2f588b;
  --accent-fg: #ffffff;
  --accent-text: #a8cbf0;
  --accent-subtle: #253444;
  --accent-subtle-hover: #2b3e52;
  --accent-border: #3f5b7d;

  --success: #4c8b58;
  --success-fg: #ffffff;
  --success-text: #9bdaa6;
  --success-subtle: #232f28;
  --success-border: #3f5f47;

  --warning: #8a6d2f;
  --warning-fg: #ffffff;
  --warning-text: #eed398;
  --warning-subtle: #2e2a20;
  --warning-border: #5f5030;

  --danger: #a3454f;
  --danger-hover: #b85560;
  --danger-fg: #ffffff;
  --danger-text: #f2a3aa;
  --danger-subtle: #2f2328;
  --danger-border: #6c3b43;

  --info: #3a7f9c;
  --info-text: #a3d5ec;
  --info-subtle: #212e36;
  --info-border: #3d5c6c;

  --focus-ring: #8fbdea;
  --focus-ring-contrast: #20242c;

  --selection-bg: #3b5878;
  --selection-fg: #ffffff;

  --scroll-thumb: #3d4553;
  --scroll-thumb-hover: #4f5867;

  --avatar-fg: #1a1e25;
  --skeleton-base: #2a303a;
  --skeleton-sheen: #363d4a;

  --mail-body-bg: #1e222a;
  --mail-body-fg: #e4eaf1;
  --mail-quote-border: #434c5c;
}

/* ---- Solarised: warm low-glare paper. worst body pair 5.20:1 ------------ */
[data-theme='solar'] {
  color-scheme: light;

  --bg: #fdf6e3;
  --bg-sunken: #f2ead4;
  --bg-raised: #f7efdc;
  --bg-raised-2: #f2e9d3;
  --bg-overlay: #fffbf0;
  --bg-hover: #f0e6cd;
  --bg-active: #e8dcbe;
  --bg-selected: #ecdfbe;
  --bg-selected-hover: #e4d5ae;
  --bg-inset: #fffdf5;
  --bg-scrim: rgba(48, 42, 28, 0.38);
  --bg-unread: #fffbef;

  --border: #ddd0b0;
  --border-subtle: #ece2ca;
  --border-strong: #8a7f66;
  --border-mid: #c8b997;

  --fg: #1e2f37;
  --fg-strong: #101f27;
  --fg-muted: #42545b;
  --fg-subtle: #4b5d64;
  --fg-faint: #6b7a80;

  --accent: #1c5f96;
  --accent-hover: #17527f;
  --accent-active: #124469;
  --accent-fg: #ffffff;
  --accent-text: #17527f;
  --accent-subtle: #e6eff6;
  --accent-subtle-hover: #d8e6f1;
  --accent-border: #a9c6dc;

  --success: #4a6a00;
  --success-fg: #ffffff;
  --success-text: #3b5400;
  --success-subtle: #eef3dd;
  --success-border: #c2d199;

  --warning: #8a5600;
  --warning-fg: #ffffff;
  --warning-text: #6b4300;
  --warning-subtle: #faeecd;
  --warning-border: #ddc48a;

  --danger: #b32a22;
  --danger-hover: #94201a;
  --danger-fg: #ffffff;
  --danger-text: #94201a;
  --danger-subtle: #fbe7e3;
  --danger-border: #e6b6ae;

  --info: #1a6a7d;
  --info-text: #16505f;
  --info-subtle: #e4f0f2;
  --info-border: #a9cdd4;

  --focus-ring: #1c5f96;
  --focus-ring-contrast: #fdf6e3;

  --selection-bg: #bcd6e8;
  --selection-fg: #101f27;

  --scroll-thumb: #cdbe9c;
  --scroll-thumb-hover: #b6a583;

  --avatar-fg: #ffffff;
  --skeleton-base: #efe6cf;
  --skeleton-sheen: #f8f2e2;

  --mail-body-bg: #fffdf6;
  --mail-body-fg: #1e2f37;
  --mail-quote-border: #cbbc9a;
}

/* ---- High contrast: maximum separation. worst body pair 5.58:1 ---------- */
[data-theme='contrast'] {
  color-scheme: dark;

  --bg: #000000;
  --bg-sunken: #000000;
  --bg-raised: #000000;
  --bg-raised-2: #080808;
  --bg-overlay: #0b0b0b;
  --bg-hover: #1a1a1a;
  --bg-active: #262626;
  --bg-selected: #00348c;
  --bg-selected-hover: #0043b0;
  --bg-inset: #000000;
  --bg-scrim: rgba(0, 0, 0, 0.8);
  --bg-unread: #0d0d0d;

  --border: #6b6b6b;
  --border-subtle: #4a4a4a;
  --border-strong: #ffffff;
  --border-mid: #8a8a8a;

  --fg: #ffffff;
  --fg-strong: #ffffff;
  --fg-muted: #e8e8e8;
  --fg-subtle: #d6d6d6;
  --fg-faint: #b4b4b4;

  --accent: #2f6fe0;
  --accent-hover: #4a86f0;
  --accent-active: #2258bd;
  --accent-fg: #ffffff;
  --accent-text: #9cc4ff;
  --accent-subtle: #001a44;
  --accent-subtle-hover: #002b6d;
  --accent-border: #6a9bf0;

  --success: #1c7a2c;
  --success-fg: #ffffff;
  --success-text: #78e08a;
  --success-subtle: #04210a;
  --success-border: #4bbf60;

  --warning: #8a6100;
  --warning-fg: #ffffff;
  --warning-text: #ffd34d;
  --warning-subtle: #241a00;
  --warning-border: #d4a52a;

  --danger: #bd1f28;
  --danger-hover: #d93b44;
  --danger-fg: #ffffff;
  --danger-text: #ff9b9f;
  --danger-subtle: #230508;
  --danger-border: #ef6a70;

  --info: #0b7fb8;
  --info-text: #7fd4ff;
  --info-subtle: #001c2b;
  --info-border: #4bb2e8;

  --focus-ring: #ffd34d;
  --focus-ring-contrast: #000000;
  --focus-ring-width: 3px;

  --selection-bg: #0043b0;
  --selection-fg: #ffffff;

  --scroll-thumb: #6b6b6b;
  --scroll-thumb-hover: #8a8a8a;

  --avatar-fg: #000000;
  --skeleton-base: #141414;
  --skeleton-sheen: #262626;

  --mail-body-bg: #000000;
  --mail-body-fg: #ffffff;
  --mail-quote-border: #6b6b6b;

  --shadow-sm: 0 0 0 1px #8a8a8a;
  --shadow-md: 0 4px 10px -2px rgba(0, 0, 0, 0.9), 0 0 0 1px #8a8a8a;
  --shadow-lg: 0 12px 28px -6px rgba(0, 0, 0, 0.95), 0 0 0 1px #a0a0a0;
  --shadow-xl: 0 28px 64px -12px rgba(0, 0, 0, 1), 0 0 0 1px #b4b4b4;
}

/* High contrast wants visible edges on every interactive surface, not just
   tokens: borders are the affordance when there is no shadow depth to read. */
[data-theme='contrast'] .btn,
[data-theme='contrast'] .input,
[data-theme='contrast'] .select,
[data-theme='contrast'] .icon-btn,
[data-theme='contrast'] .chip,
[data-theme='contrast'] .pill,
[data-theme='contrast'] .badge {
  border: var(--bw-thin) solid var(--border-mid);
}

[data-theme='contrast'] .msg-row.is-selected,
[data-theme='contrast'] .msg-row[aria-selected='true'] {
  outline: 2px solid var(--fg);
  outline-offset: -2px;
}

/* ==========================================================================
   33. READING-PANE HEADER — the confirmed overflow/alignment defects

   The header was a 44px flex bar holding a two-line sender block, so its
   content was taller than the bar: text touched the top edge and collided
   with the bottom border, with no vertical centring (bug 1). It also padded
   itself to ~14px while the content column below started at ~193px, so
   nothing shared an axis (bug 4).
   ========================================================================== */

.reader__toolbar {
  /* Tall enough for the identity block, and it may grow rather than clip. */
  height: auto;
  min-height: 52px;
  padding: 0;
  align-items: stretch;
  overflow: visible;
}

/* One content axis: the toolbar inner wrapper uses the SAME max-width and
   gutters as `.reader__inner`, so subject, card and toolbar all line up. */
.reader__toolbar-inner {
  display: flex;
  align-items: center;          /* vertical centring — fixes bug 1 */
  gap: var(--sp-5);
  width: 100%;
  max-width: var(--reader-max-w);
  min-height: 52px;
  margin: 0 auto;
  padding: var(--sp-3) var(--sp-10);
  box-sizing: border-box;
}

/* The identity block: avatar centre-aligned against the text (bug 3). */
.reader__ident {
  display: flex;
  align-items: center;          /* not flex-start — fixes bug 3 */
  gap: var(--sp-5);
  min-width: 0;
  flex: 1 1 auto;
}

/* Name, address and "to me" share one baseline row and wrap as a unit, so the
   recipient label can no longer sit lower than the sender name (bug 2). */
.reader__who {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-4);
  min-width: 0;
  line-height: var(--lh-snug);
}

.reader__from {
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--fg-strong);
  max-width: 42ch;
}

.reader__addr {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  font-weight: var(--fw-regular);
  color: var(--fg-subtle);
  letter-spacing: 0;
  max-width: 34ch;
}

.reader__to {
  font-size: var(--fs-2xs);
  color: var(--fg-subtle);
  background: none;
  border: 0;
  padding: 0;
  border-radius: var(--r-xs);
  cursor: pointer;
  white-space: nowrap;
}

.reader__to:hover {
  color: var(--accent-text);
  text-decoration: underline;
}

/* One gap value across the whole action cluster, and exactly one divider
   before the overflow button — no three-different-gaps-plus-a-void (bug 11). */
.reader__toolbar-actions {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex: none;
}

.reader__toolbar-group {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

.reader__toolbar-sep {
  width: var(--bw-thin);
  height: 18px;
  background: var(--border-mid);
  margin: 0;
  flex: none;
}

/* Back button: only meaningful when the reader is an overlay. */
.reader__back { display: none; }

[data-layout='tablet'] .reader__back,
[data-layout='mobile'] .reader__back {
  display: inline-grid;
  place-items: center;
  flex: none;
}

/* ==========================================================================
   34. MESSAGE BODY / CARD — padding symmetry and the blocked-image box
   ========================================================================== */

/* The card had ~22px top and ~11px bottom padding, so the body nearly touched
   the bottom border (bug 10). Symmetric now, and the reading column and the
   toolbar share one horizontal inset. */
.reader__inner {
  max-width: var(--reader-max-w);
  margin: 0 auto;
  padding: var(--sp-9) var(--sp-10) var(--sp-16);
  box-sizing: border-box;
}

.thread-item__body {
  padding-bottom: var(--sp-8);
}

.thread-item {
  padding-top: var(--sp-6);
  padding-bottom: var(--sp-6);
}

.msg-head {
  padding-top: var(--sp-2);
  padding-bottom: var(--sp-6);
}

/* Blocked remote images: the box is sized by its own text and never clips.
   It used to inherit the image's intrinsic width/height (often a 44px tracking
   pixel) with zero inner padding, so a two-line alt was cut mid-glyph (bug 7). */
.msg-body--html img[data-blocked] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  width: auto !important;
  height: auto !important;
  min-width: 0;
  min-height: 28px;
  max-width: 100%;
  aspect-ratio: auto !important;
  padding: var(--sp-3) var(--sp-5);
  background: var(--bg-sunken);
  border: 1px dashed var(--border-mid);
  border-radius: var(--r-sm);
  color: var(--fg-muted);
  font-family: var(--font-sans);
  font-size: var(--fs-2xs);
  font-style: normal;
  line-height: var(--lh-snug);
  text-align: center;
  overflow: visible;
  white-space: normal;
  overflow-wrap: anywhere;
  vertical-align: middle;
}

/* Equivalent choices, equivalent controls: same height, same hit area (bug 9). */
.reader-banner {
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-5);
}

.reader-banner__actions {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex: none;
  margin-left: auto;
}

.reader-banner__actions .btn {
  height: var(--control-h-md);
  min-height: var(--control-h-md);
  white-space: nowrap;
}

/* ==========================================================================
   35. READER PLACEHOLDER — an empty state that earns its area (bug 24)
   ========================================================================== */

.reader-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0;
  height: 100%;
  padding: var(--sp-10);
  box-sizing: border-box;
  color: var(--fg-subtle);
}

/* A bounded card, not text stretched across ~900px of empty pane. Copy is
   centred as a block AND centre-aligned, so a ragged second line cannot pull
   the composition off axis. */
.reader-placeholder__card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-6);
  width: 100%;
  max-width: 420px;
  padding: var(--sp-12) var(--sp-10);
  background: var(--bg-raised);
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-sm);
  text-align: center;
}

.reader-placeholder__card .empty__text {
  text-align: center;
  max-width: 34ch;
  text-wrap: balance;
}

.reader-placeholder__card .empty__actions {
  justify-content: center;
  flex-wrap: wrap;
}

.reader-placeholder__stats {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--sp-2);
  width: 100%;
  padding: var(--sp-6) 0;
  border-top: var(--bw-thin) solid var(--border-subtle);
  border-bottom: var(--bw-thin) solid var(--border-subtle);
}

.reader-placeholder__stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  min-width: 0;
}

.reader-placeholder__statnum {
  font-size: var(--fs-lg);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
  color: var(--fg-strong);
  line-height: 1;
}

.reader-placeholder__statlabel {
  font-size: var(--fs-3xs);
  color: var(--fg-subtle);
  text-align: center;
  line-height: var(--lh-snug);
  overflow-wrap: anywhere;
}

.reader-placeholder__hints {
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--sp-3) var(--sp-6);
}

/* ==========================================================================
   36. MESSAGE ROW — hierarchy and state treatments
   ========================================================================== */

/* Bug 13: the SUBJECT is the strongest text in the row; the sender is
   secondary.

   Titan's discipline, adopted here: subject and snippet are the SAME font size
   (`--fs-sm`) on the SAME baseline. All hierarchy is weight + brightness. Making
   the snippet smaller than the subject is what forced the old stacked layout and
   the early truncation, so the sizes are deliberately locked together and the
   sender takes a smaller size instead. */
.msg-row__subject {
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--fg-strong);
}

.msg-row__snippet {
  font-size: var(--fs-sm);
  font-weight: var(--fw-regular);
  color: var(--fg-subtle);
}

.msg-row__sender {
  font-size: var(--fs-xs);
  color: var(--fg-muted);
}

.msg-row.is-unread .msg-row__subject {
  color: var(--fg-strong);
  font-weight: var(--fw-semibold);
}

.msg-row.is-unread .msg-row__sender {
  color: var(--fg);
  font-weight: var(--fw-medium);
}

/* MEASURED: read rows rendered their subject at weight 500 while the section-36
   rule above sets 600. Cause: this is a DUPLICATE of that selector, later in the
   sheet, so it won on source order and silently overrode it. Two blocks owning one
   selector is the bug; the value is now identical to the earlier rule so they can
   no longer disagree, and the weight/brightness split (600 always, dimmer when
   read) holds for every row state. */
.msg-row.is-read .msg-row__subject {
  color: var(--fg-muted);
  font-weight: var(--fw-semibold);
}

.msg-row.is-read .msg-row__sender {
  color: var(--fg-subtle);
  font-weight: var(--fw-regular);
}

.msg-row.is-selected .msg-row__subject {
  color: var(--fg-strong);
  font-weight: var(--fw-semibold);
}

/* Bug 21: selection and keyboard focus are different states, so they get
   different treatments. Selected = tinted fill + a left accent rail.
   Focus-visible = a ring. The old row had BOTH a fill and a four-sided ring
   for "selected", which conflated the two. */
.msg-row.is-selected,
.msg-row[aria-selected='true'] {
  background: var(--bg-selected);
  box-shadow: none;
}

.msg-row.is-cursor {
  /* The cursor is not focus: it is a quiet position marker. */
  box-shadow: none;
  background: var(--bg-hover);
}

.msg-row.is-cursor.is-selected,
.msg-row.is-cursor[aria-selected='true'] {
  background: var(--bg-selected);
}

.msg-row:focus-visible,
.msg-row.focus-inset:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: -2px;
  box-shadow: none;
}

/* ==========================================================================
   37. LIST CHROME — footer, drawer trigger, labelled reader close
   ========================================================================== */

.list__footer {
  align-items: center;
  gap: var(--sp-4);
  min-height: 32px;
}

.list__drawerbtn {
  display: none;
  flex: none;
}

/* The drawer trigger only exists where the sidebar is an overlay. */
[data-layout='tablet'] .list__drawerbtn,
[data-layout='mobile'] .list__drawerbtn {
  display: inline-grid;
  place-items: center;
}

#readerCloseBtn {
  white-space: nowrap;
  flex: none;
}

/* The quota widget is a grid so it can drop its track cleanly when there is no
   limit to measure against (bug 18). */
.quota {
  display: grid;
  gap: var(--sp-3);
}

.quota--countonly .quota__track {
  display: none;
}

/* ==========================================================================
   38. COMMAND PALETTE — scrim, elevation, active row, keycaps

   The palette had no scrim and a weak shadow, so it read as wedged into the
   layout and the text showing through behind it looked like a rendering bug
   (bug 14). It also had no first-result highlight, and the loudest thing on
   screen was the input's focus ring (bug 15).
   ========================================================================== */

.palette-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal-overlay);
  display: grid;
  align-items: start;
  justify-items: center;
  padding: 10vh var(--sp-6) var(--sp-6);
  /* A real dim + blur scrim: the layer behind is unmistakably *behind*. */
  background: color-mix(in srgb, var(--bg-scrim) 100%, transparent);
  -webkit-backdrop-filter: blur(6px) saturate(0.9);
  backdrop-filter: blur(6px) saturate(0.9);
  animation: palette-scrim-in var(--dur-fast) var(--ease-standard);
}

@supports not (backdrop-filter: blur(2px)) {
  .palette-overlay { background: rgba(0, 0, 0, 0.62); }
}

@keyframes palette-scrim-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.palette {
  width: min(620px, 100%);
  /* Height is capped and the results scroll internally (bug 16). */
  max-height: min(64vh, 560px);
  display: flex;
  flex-direction: column;
  background: var(--bg-overlay);
  border: var(--bw-thin) solid var(--border-mid);
  border-radius: var(--r-xl);
  /* Real elevation, not a hint of one. */
  box-shadow: var(--shadow-xl), 0 0 0 1px var(--border-mid);
  overflow: hidden;
}

.palette__inputwrap {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  flex: none;
  padding: 0 var(--sp-7);
  border-bottom: var(--bw-thin) solid var(--border);
}

.palette__inputicon {
  display: grid;
  place-items: center;
  flex: none;
  color: var(--fg-subtle);
}

.palette__input {
  flex: 1 1 auto;
  height: 48px;
  padding: 0;
  background: transparent;
  border: 0;
  color: var(--fg-strong);
  font-size: var(--fs-md);
  min-width: 0;
}

/* Bug 15: the input's ring is softened to a hairline underline so the accent
   belongs to the ACTIVE ROW, not the text field. */
.palette__input:focus,
.palette__input:focus-visible {
  outline: none;
  box-shadow: none;
}

.palette__inputwrap:focus-within {
  border-bottom-color: var(--border-strong);
}

.palette__results {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--sp-3);
}

.palette-item {
  display: flex;
  align-items: center;
  gap: var(--sp-5);
  width: 100%;
  min-height: 38px;
  padding: 0 var(--sp-5);
  background: transparent;
  border: 0;
  border-radius: var(--r-md);
  color: var(--fg);
  font-size: var(--fs-sm);
  text-align: left;
  cursor: pointer;
}

.palette-item__icon {
  display: grid;
  place-items: center;
  flex: none;
  width: 18px;
  color: var(--fg-subtle);
}

.palette-item__label {
  flex: 1 1 auto;
  min-width: 0;
}

.palette-item__meta {
  flex: none;
  max-width: 34%;
  font-size: var(--fs-2xs);
  color: var(--fg-subtle);
}

/* Bug 16: keycap chips, matching every other keycap in the app. */
.palette-item__keys {
  display: flex;
  align-items: center;
  gap: 3px;
  flex: none;
}

.palette-item:hover {
  background: var(--bg-hover);
}

/* The active row IS the accent. */
.palette-item.is-active {
  background: var(--accent-subtle);
  color: var(--fg-strong);
  box-shadow: inset 2px 0 0 0 var(--accent);
}

.palette-item.is-active .palette-item__icon,
.palette-item.is-active .palette-item__meta {
  color: var(--accent-text);
}

.palette-item:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: -2px;
}

/* Footer action bar: the palette states how to drive it (bug 16). */
.palette__footer {
  display: flex;
  align-items: center;
  gap: var(--sp-6);
  flex: none;
  padding: var(--sp-3) var(--sp-7);
  border-top: var(--bw-thin) solid var(--border);
  background: var(--bg-raised-2);
  font-size: var(--fs-3xs);
  color: var(--fg-subtle);
}

.palette__foot-item {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  white-space: nowrap;
}

.palette__foot-spacer {
  flex: 1 1 auto;
}

.palette__foot-brand {
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-tight);
  color: var(--fg-faint);
}

.palette__footer .kbd {
  font-size: var(--fs-3xs);
  min-width: 16px;
}

/* ==========================================================================
   39. APPEARANCE SHEET — theme swatches + the custom theme
   ========================================================================== */

.theme-sheet {
  width: min(560px, 100%);
}

.theme-sheet__body {
  display: grid;
  gap: var(--sp-9);
  max-height: min(70vh, 640px);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.theme-sheet__section {
  display: grid;
  gap: var(--sp-5);
}

.theme-sheet__legend {
  font-size: var(--fs-3xs);
  font-weight: var(--fw-semibold);
  text-transform: uppercase;
  letter-spacing: var(--ls-caps);
  color: var(--fg-subtle);
}

.theme-sheet__hint {
  margin: 0;
  font-size: var(--fs-2xs);
  color: var(--fg-subtle);
  line-height: var(--lh-normal);
  max-width: 56ch;
}

.theme-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--sp-4);
}

.theme-card {
  display: flex;
  align-items: center;
  gap: var(--sp-5);
  min-height: 52px;
  padding: var(--sp-4) var(--sp-5);
  background: var(--bg-raised);
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-lg);
  color: var(--fg);
  text-align: left;
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease-standard),
    background-color var(--dur-fast) var(--ease-standard);
}

.theme-card:hover {
  background: var(--bg-hover);
  border-color: var(--border-mid);
}

.theme-card.is-active {
  border-color: var(--accent);
  background: var(--accent-subtle);
  box-shadow: inset 0 0 0 1px var(--accent);
}

.theme-card:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: 2px;
}

/* Live swatch: real token values, so the preview cannot lie about the theme. */
.theme-card__swatch {
  position: relative;
  flex: none;
  width: 40px;
  height: 32px;
  border-radius: var(--r-sm);
  border: var(--bw-thin) solid var(--border-mid);
  overflow: hidden;
}

.theme-card__ink {
  position: absolute;
  left: 6px;
  top: 8px;
  width: 20px;
  height: 3px;
  border-radius: var(--r-pill);
}

.theme-card__accent {
  position: absolute;
  left: 6px;
  bottom: 7px;
  width: 12px;
  height: 8px;
  border-radius: var(--r-xs);
}

.theme-card__text {
  display: grid;
  gap: 1px;
  min-width: 0;
  flex: 1 1 auto;
}

.theme-card__name {
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--fg-strong);
}

.theme-card__blurb {
  font-size: var(--fs-3xs);
  color: var(--fg-subtle);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.theme-card__tick {
  display: grid;
  place-items: center;
  flex: none;
  width: 18px;
  height: 18px;
  border-radius: var(--r-circle);
  background: var(--accent);
  color: var(--accent-fg);
  opacity: 0;
}

.theme-card.is-active .theme-card__tick {
  opacity: 1;
}

/* ---- Custom theme controls ---------------------------------------------- */

.theme-custom {
  display: grid;
  gap: var(--sp-4);
  padding: var(--sp-6);
  background: var(--bg-sunken);
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-lg);
}

.theme-custom__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: center;
  gap: var(--sp-5);
  min-height: 32px;
  cursor: pointer;
}

.theme-custom__row--switch {
  grid-template-columns: minmax(0, 1fr) auto;
}

.theme-custom__label {
  font-size: var(--fs-sm);
  color: var(--fg);
}

.theme-custom__color {
  flex: none;
  width: 44px;
  height: 28px;
  padding: 0;
  background: none;
  border: var(--bw-thin) solid var(--border-mid);
  border-radius: var(--r-sm);
  cursor: pointer;
}

.theme-custom__color::-webkit-color-swatch-wrapper { padding: 2px; }
.theme-custom__color::-webkit-color-swatch { border: 0; border-radius: 2px; }

.theme-custom__value {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  color: var(--fg-subtle);
  min-width: 8ch;
  text-align: right;
}

.theme-custom__actions {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  flex-wrap: wrap;
  margin-top: var(--sp-2);
}

.theme-custom__status {
  font-size: var(--fs-2xs);
  color: var(--fg-subtle);
}

/* Density segmented control */
.theme-seg {
  display: inline-flex;
  padding: 2px;
  background: var(--bg-sunken);
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-md);
  gap: 2px;
}

.theme-seg__btn {
  min-height: 28px;
  padding: 0 var(--sp-6);
  background: transparent;
  border: 0;
  border-radius: var(--r-sm);
  color: var(--fg-muted);
  font-size: var(--fs-xs);
  cursor: pointer;
}

.theme-seg__btn:hover { background: var(--bg-hover); }

.theme-seg__btn.is-active {
  background: var(--accent);
  color: var(--accent-fg);
  font-weight: var(--fw-medium);
}

.theme-seg__btn:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: 1px;
}

/* Topbar action cluster: one gap value, no conspicuous voids (bug 22). */
.topbar__group--actions {
  gap: var(--sp-2);
  flex: none;
}

/* ==========================================================================
   40. RESPONSIVE LADDER (§4.1) — authoritative

   Section 30 above shipped a 3-step ladder (>=1200 / 760-1199 / <760) that did
   not match the spec and left the shell overflowing at several widths. This
   section is the normative implementation and deliberately comes last so it
   wins the cascade.

     >= 1600px      4 columns: sidebar + list + reader + 300px context rail
     1280 - 1599    3 columns: context rail collapses away
     1024 - 1279    3 columns: sidebar collapses to a 56px icon rail
      768 - 1023    2 columns: sidebar becomes an overlay drawer
     <  768px       1 column: 48px touch top bar, off-canvas reader

   Invariant enforced throughout: no element may exceed the viewport. Every
   grid track is `minmax(0, …)` or a fixed px value that the sum of tracks can
   afford, and every flex child that holds text carries `min-width: 0`.
   ========================================================================== */

/* Nothing may create horizontal scroll. */
html,
body {
  max-width: 100%;
  overflow-x: hidden;
}

.app {
  width: 100%;
  max-width: 100vw;
  overflow: hidden;
}

/* Text-bearing flex/grid children must be allowed to shrink, or they push the
   layout wider than the viewport. This is the single most common cause of the
   overflow the ladder below is meant to prevent. */
.topbar__group,
.brand,
.search,
.list__header,
.list__tools,
.reader__toolbar-inner,
.reader__ident,
.reader__who,
.msg-row,
.msg-row__sender,
.msg-row__subject,
.msg-row__snippet,
.nav-item,
.usermenu,
.modal,
.modal__header,
.modal__footer,
.addr-row,
.reader-banner,
.auth-strip,
.attachments__grid {
  min-width: 0;
}

.brand__name,
.list__title,
.msg-row__sender-name,
.reader__from,
.reader__addr {
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Long unbroken strings (URLs, addresses) must wrap rather than widen. */
.msg-body,
.msg-body--text,
.msg-body--html,
.reader__subject,
.empty__text,
.toast__text {
  overflow-wrap: anywhere;
}

.msg-body--html table,
.msg-body--html img,
.msg-body--html pre {
  max-width: 100% !important;
}

.msg-body--html {
  overflow-x: auto;
}

/* ---- >= 1600px : four columns ------------------------------------------- */
@media (min-width: 1600px) {
  .app {
    grid-template-columns: var(--sidebar-w) minmax(520px, 620px) minmax(0, 1fr) 300px;
    grid-template-areas:
      'topbar topbar topbar topbar'
      'sidebar list reader rail';
  }

  .app.is-rail {
    grid-template-columns: 56px minmax(520px, 620px) minmax(0, 1fr) 300px;
  }

  .app.is-reader-hidden {
    grid-template-columns: var(--sidebar-w) minmax(0, 1fr) 0px 300px;
  }

  /* The context rail is a real column here. It has no content module yet, so it
     renders as a quiet gutter rather than a gap that looks like a bug. */
  .app__rail {
    grid-area: rail;
    min-width: 0;
    background: var(--bg-raised);
    border-left: var(--bw-thin) solid var(--border);
  }
}

/* ---- 1280 - 1599px : three columns, rail collapsed --------------------- */
@media (min-width: 1280px) and (max-width: 1599px) {
  .app {
    grid-template-columns: var(--sidebar-w) minmax(460px, 560px) minmax(0, 1fr);
    grid-template-areas:
      'topbar topbar topbar'
      'sidebar list reader';
  }

  .app.is-rail {
    grid-template-columns: 56px minmax(460px, 560px) minmax(0, 1fr);
  }

  .app.is-reader-hidden {
    grid-template-columns: var(--sidebar-w) minmax(0, 1fr) 0px;
  }

  .app__rail { display: none; }
}

/* ---- 1024 - 1279px : sidebar becomes a 56px icon rail ------------------ */
@media (min-width: 1024px) and (max-width: 1279px) {
  .app,
  .app.is-rail,
  .app.is-sidebar-collapsed {
    grid-template-columns: 56px minmax(420px, 500px) minmax(0, 1fr);
    grid-template-areas:
      'topbar topbar topbar'
      'sidebar list reader';
  }

  .app.is-reader-hidden {
    grid-template-columns: 56px minmax(0, 1fr) 0px;
  }

  .app__rail { display: none; }

  /* The reader stays in flow; it is not an overlay until 1023px. */
  .app__reader {
    position: static;
    transform: none;
    visibility: visible;
    box-shadow: none;
    border-left: var(--bw-thin) solid var(--border);
  }

  .search { max-width: 420px; }
}

/* The 56px rail form. Applied by the 1024-1279 breakpoint automatically, and by
   `.is-rail` (the `[` toggle) at wider widths. Labels move to tooltips; the text
   stays in the DOM so assistive tech still reads it. */
[data-layout='desktop-rail'] .app__sidebar,
.app.is-rail .app__sidebar {
  overflow: visible;
  padding-left: 0;
  padding-right: 0;
  border-right: var(--bw-thin) solid var(--border);
}

/* The rail hides labels visually but keeps them for assistive tech. The compose
   button's keycap is the exception: it is decorative (`C` is already in the
   shortcut sheet), and leaving a 1px clipped box in the layout reads as a text
   clip to any geometry check. It is removed outright instead. */
[data-layout='desktop-rail'] #composeBtn kbd,
.app.is-rail #composeBtn kbd {
  display: none;
}

[data-layout='desktop-rail'] .app__sidebar .nav-item__label,
[data-layout='desktop-rail'] .app__sidebar .nav-item__count,
[data-layout='desktop-rail'] .app__sidebar .sb-section__title,
[data-layout='desktop-rail'] .app__sidebar .usermenu__meta,
[data-layout='desktop-rail'] .app__sidebar .quota,
[data-layout='desktop-rail'] #composeBtn > span:not([data-icon]),
[data-layout='desktop-rail'] #composeBtn kbd,
.app.is-rail .app__sidebar .nav-item__label,
.app.is-rail .app__sidebar .nav-item__count,
.app.is-rail .app__sidebar .sb-section__title,
.app.is-rail .app__sidebar .usermenu__meta,
.app.is-rail .app__sidebar .quota,
.app.is-rail #composeBtn > span:not([data-icon]),
.app.is-rail #composeBtn kbd {
  /* `clip` keeps the node accessible while removing it from the visual box. */
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

[data-layout='desktop-rail'] .app__sidebar .nav-item,
.app.is-rail .app__sidebar .nav-item {
  justify-content: center;
  padding: 0;
  margin-left: var(--sp-2);
  margin-right: var(--sp-2);
}

[data-layout='desktop-rail'] #composeBtn,
.app.is-rail #composeBtn {
  justify-content: center;
  padding: 0;
}

[data-layout='desktop-rail'] .app__sidebar .usermenu,
.app.is-rail .app__sidebar .usermenu {
  justify-content: center;
  padding: 0;
}

/* ---- 768 - 1023px : sidebar becomes an overlay drawer ------------------ */
@media (min-width: 768px) and (max-width: 1023px) {
  .app,
  .app.is-rail,
  .app.is-sidebar-collapsed,
  .app.is-reader-hidden {
    grid-template-columns: minmax(0, 420px) minmax(0, 1fr);
    grid-template-areas:
      'topbar topbar'
      'list reader';
  }

  .app__rail { display: none; }

  /* Drawer: out of flow, over a scrim. */
  .app__sidebar {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    width: min(300px, 82vw);
    max-width: 100vw;
    z-index: calc(var(--z-modal-overlay) + 1);
    background: var(--bg-raised);
    border-right: var(--bw-thin) solid var(--border-mid);
    box-shadow: var(--shadow-xl);
    transform: translateX(-100%);
    visibility: hidden;
    transition: transform var(--dur-base) var(--ease-out),
      visibility var(--dur-base) linear;
  }

  .app.is-sidebar-open .app__sidebar {
    transform: none;
    visibility: visible;
  }

  .app::after {
    content: '';
    position: fixed;
    inset: 0;
    z-index: var(--z-modal-overlay);
    background: var(--bg-scrim);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--dur-base) var(--ease-standard);
  }

  .app.is-sidebar-open::after {
    opacity: 1;
    pointer-events: auto;
  }

  /* Reader stays in flow as the second column. */
  .app__reader {
    position: static;
    transform: none;
    visibility: visible;
    box-shadow: none;
    border-left: var(--bw-thin) solid var(--border);
  }

  .search { max-width: 320px; }
  .reader__inner { padding: var(--sp-8) var(--sp-8) var(--sp-16); }
  .reader__toolbar-inner { padding: var(--sp-3) var(--sp-8); }
}

/* ---- < 768px : single column, touch top bar, off-canvas reader --------- */
@media (max-width: 767px) {
  :root {
    /* 48px touch top bar per the spec. */
    --topbar-h: 48px;
    --reader-max-w: 100%;
  }

  .app,
  .app.is-rail,
  .app.is-sidebar-collapsed,
  .app.is-reader-hidden {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: var(--topbar-h) minmax(0, 1fr);
    grid-template-areas:
      'topbar'
      'list';
  }

  .app__rail { display: none; }

  .app__list {
    grid-area: list;
    min-width: 0;
  }

  /* Sidebar drawer */
  .app__sidebar {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    width: min(300px, 86vw);
    max-width: 100vw;
    z-index: calc(var(--z-modal-overlay) + 1);
    background: var(--bg-raised);
    border-right: var(--bw-thin) solid var(--border-mid);
    box-shadow: var(--shadow-xl);
    transform: translateX(-100%);
    visibility: hidden;
    transition: transform var(--dur-base) var(--ease-out),
      visibility var(--dur-base) linear;
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }

  .app.is-sidebar-open .app__sidebar {
    transform: none;
    visibility: visible;
  }

  .app::after {
    content: '';
    position: fixed;
    inset: 0;
    z-index: var(--z-modal-overlay);
    background: var(--bg-scrim);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--dur-base) var(--ease-standard);
  }

  .app.is-sidebar-open::after {
    opacity: 1;
    pointer-events: auto;
  }

  /* Reader is off-canvas over the list, and `Esc` / the back button returns. */
  .app__reader {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    width: 100%;
    max-width: 100vw;
    z-index: var(--z-overlay-pane);
    background: var(--bg);
    border-left: 0;
    transform: translateX(100%);
    visibility: hidden;
    transition: transform var(--dur-base) var(--ease-out),
      visibility var(--dur-base) linear;
  }

  .app.is-reader-open .app__reader {
    transform: none;
    visibility: visible;
  }

  .reader__toolbar {
    min-height: 56px;
    padding-top: env(safe-area-inset-top, 0px);
  }

  .reader__toolbar-inner {
    padding: var(--sp-3) var(--sp-5);
    gap: var(--sp-4);
    min-height: 56px;
  }

  /* The address is dropped: the name plus "to me" is all that fits legibly. */
  .reader__addr { display: none; }

  /* Actions wrap onto their own row rather than squeezing the identity block. */
  .reader__toolbar-actions {
    gap: var(--sp-1);
  }

  .reader__toolbar-actions .reader__toolbar-sep { display: none; }

  /* Only the three highest-value actions stay inline; the rest live in the
     overflow menu, which is already there. */
  .reader__toolbar-actions .reader__toolbar-group:nth-child(3) .icon-btn:nth-child(2),
  .reader__toolbar-actions .reader__toolbar-group:nth-child(3) .icon-btn:nth-child(4) {
    display: none;
  }

  .reader__inner {
    padding: var(--sp-6) var(--sp-5) var(--sp-16);
  }

  .reader__subject { font-size: var(--fs-lg); }

  .reader-placeholder { padding: var(--sp-6); }

  .reader-placeholder__card {
    max-width: 100%;
    padding: var(--sp-9) var(--sp-6);
  }

  .reader-placeholder__stats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--sp-5) var(--sp-2);
  }

  /* Topbar: 48px, brand mark only, search behind a button. */
  .topbar {
    padding: 0 var(--sp-4);
    gap: var(--sp-2);
    height: var(--topbar-h);
  }

  .brand__name,
  .brand__env,
  .usermenu__meta {
    display: none;
  }

  .topbar__group--grow { display: none; }

  .topbar.is-search-open .topbar__group--grow {
    display: flex;
    position: absolute;
    inset: 0;
    padding: 0 var(--sp-4);
    background: var(--bg-raised);
    z-index: 2;
  }

  #searchBtn {
    display: inline-grid !important;
    place-items: center;
  }

  /* Message rows below 768px: same single-line structure, but the sender track
     narrows and the checkbox + icon lane are dropped, because at 390px there is
     not enough width for both a 180px sender gutter and a readable snippet.
     Row height stays FIXED (64px touch) — the virtualiser requires it. */
  /* MEASURED: at 26px the lane clipped (clientWidth 26, scrollWidth 25+ once two
     glyphs and their gap were in it). The lane must be at least
     2 * 13px + 2px gap = 28px, so narrowing it below that is not an option — the
     sender track gives up the width instead. */
  :root {
    --row-check-w: 0px;
    --row-icons-w: 28px;
    --row-sender-w: 116px;
    --row-star-w: 30px;
  }

  .msg-row,
  [data-density='compact'] .msg-row,
  [data-density='comfortable'] .msg-row {
    height: 64px;
    min-height: 64px;
  }

  .msg-row__check { display: none; }

  /* No hover on a touch device, so the cluster would only ever be dead weight;
     the row's swipe/long-press actions cover it. */
  .msg-row__quick { display: none !important; }

  .msg-row:hover .msg-row__main,
  .msg-row:focus-within .msg-row__main {
    padding-right: var(--sp-5);
  }

  /* Compose goes FULL SCREEN below 768px. */
  .overlay {
    padding: 0;
    place-items: stretch;
  }

  .modal,
  .modal--sm,
  .modal--md,
  .modal--lg,
  .compose,
  .theme-sheet {
    width: 100%;
    max-width: 100%;
    height: 100%;
    max-height: none;
    border-radius: 0;
    border: 0;
    margin: 0;
  }

  .modal__body,
  .theme-sheet__body {
    max-height: none;
  }

  .modal__footer {
    flex-wrap: wrap;
    row-gap: var(--sp-3);
    padding-bottom: calc(var(--sp-5) + env(safe-area-inset-bottom, 0px));
  }

  /* The keycap hint is desktop advice; a phone has no Ctrl key to press. */
  .modal__footer .t-meta[aria-hidden='true'] { display: none; }

  .addr-row {
    grid-template-columns: 44px minmax(0, 1fr);
    row-gap: var(--sp-2);
  }

  .addr-row__actions {
    grid-column: 2;
    justify-self: start;
  }

  /* Palette becomes a sheet from the top. */
  .palette-overlay { padding: var(--sp-4); }

  .palette {
    width: 100%;
    max-height: 82vh;
  }

  .palette__footer {
    gap: var(--sp-4);
    padding: var(--sp-3) var(--sp-5);
  }

  .palette__foot-brand { display: none; }

  .theme-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .toaster {
    left: var(--sp-4);
    right: var(--sp-4);
    top: calc(var(--topbar-h) + var(--sp-3));
    bottom: auto;
    max-width: none;
    align-items: stretch;
  }

  .menu { max-width: calc(100vw - var(--sp-8)); }

  .resizer { display: none; }

  .only-mobile { display: initial; }
  .only-desktop { display: none !important; }

  /* ---- Touch targets: >= 44px for anything tappable -------------------- */
  .icon-btn,
  .icon-btn--sm,
  .msg-star,
  .chip__remove,
  .list__drawerbtn {
    min-width: 44px;
    min-height: 44px;
    width: auto;
    height: auto;
  }

  .btn,
  .btn--sm,
  .btn--md,
  .btn--lg,
  .theme-seg__btn,
  .list-tab {
    min-height: 44px;
    height: auto;
  }

  .nav-item {
    min-height: 44px;
    border-radius: var(--r-lg);
  }

  .palette-item {
    min-height: 44px;
  }

  .theme-card {
    min-height: 56px;
  }

  .theme-custom__row {
    min-height: 44px;
  }

  .theme-custom__color {
    width: 52px;
    height: 36px;
  }

  .checkbox,
  .radio {
    width: 20px;
    height: 20px;
  }

  .switch { width: 44px; height: 26px; }
  .switch::after { width: 22px; height: 22px; }
  .switch:checked::after { transform: translateX(18px); }
}

/* ---- Very narrow (<= 400px): the last things that can still overflow --- */
@media (max-width: 400px) {
  .topbar { padding: 0 var(--sp-3); }

  /* Only the tracks narrow. The row must NOT take left padding: the accent rail
     is the first grid track and has to sit at x=0.

     The icon lane stays at 28px — MEASURED clipping at 22px, because two 13px
     glyphs plus their gap need 28px and no amount of narrowing changes that. At
     this width the lane instead drops to ONE glyph (see the rule below), which is
     the honest way to reclaim the space. */
  :root {
    --row-icons-w: 22px;
    --row-sender-w: 96px;
    --row-time-w: 50px;
  }

  /* One glyph only at phone widths: the lane is 22px, so a second glyph would
     clip. `nth-child(n+2)` hides the extras rather than letting them overflow. */
  .msg-row__icons > *:nth-child(n + 2) {
    display: none;
  }

  .reader__toolbar-inner,
  .reader__inner {
    padding-left: var(--sp-4);
    padding-right: var(--sp-4);
  }

  /* Keep only reply + overflow inline; everything else is in the menu. */
  .reader__toolbar-actions .reader__toolbar-group:nth-child(1) .icon-btn:nth-child(3),
  .reader__toolbar-actions .reader__toolbar-group:nth-child(3) .icon-btn:nth-child(1),
  .reader__toolbar-actions .reader__toolbar-group:nth-child(3) .icon-btn:nth-child(3) {
    display: none;
  }

  .list-tabs { overflow-x: auto; scrollbar-width: none; }
  .list-tabs::-webkit-scrollbar { display: none; }

  .reader-placeholder__stats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .palette__footer .palette__foot-item:nth-child(2) { display: none; }
}

/* Coarse pointers: no hover-reveal affordances, no CSS tooltips. */
@media (hover: none) {
  .msg-row__check,
  .sb-section__action {
    opacity: 1;
  }

  .msg-row__quick { display: none !important; }

  [data-tip]::after,
  [data-tip]::before { display: none; }
}

/* ==========================================================================
   41. VERIFIED FIXES — issues found by driving the real browser

   Everything here was measured failing at a specific viewport and re-measured
   passing afterwards; none of it is speculative.
   ========================================================================== */

/* The reading-pane header must not be a scroll container. Its own content fits,
   but a CSS tooltip is a child box, so any `overflow` other than `visible` lets
   a hovered tip turn the bar into a 68px scrolling area. */
.reader__toolbar {
  overflow: visible;
}

.reader__toolbar-inner {
  overflow: visible;
}

@media (max-width: 767px) {
  /* Measured 34x44: the "All" tab was under the 44px minimum on its short axis
     because its label is one word. Width now has a floor too. */
  .list-tab {
    min-width: 44px;
    padding-left: var(--sp-5);
    padding-right: var(--sp-5);
  }

  /* Measured 93x32 / 90x32: `btn--sm` inside the blocked-images banner kept its
     desktop height and lost to the generic touch rule on specificity. */
  .reader-banner__actions .btn,
  .reader-banner__actions .btn--sm {
    min-height: 44px;
    height: auto;
  }

  /* Same class of problem anywhere else a small button survives on touch. */
  .btn--sm,
  .icon-btn--sm {
    min-height: 44px;
    height: auto;
  }

  /* The bulk bar is a dense row of small buttons; let it wrap rather than
     forcing 44px targets into a fixed-height strip. */
  .list__bulkbar {
    flex-wrap: wrap;
    height: auto;
    min-height: 44px;
    row-gap: var(--sp-2);
    padding-top: var(--sp-3);
    padding-bottom: var(--sp-3);
  }
}


/* ==========================================================================
   40. LAYOUT DEFECT FIXES — one axis per column
   ==========================================================================

   Fifteen measured defects were reported against the previous build. Each is
   named below with what was measured, why it happened and what the fix is, so a
   future change cannot undo one of them by accident.
   ========================================================================== */

/* ---- BUG (i) + (j): ONE gutter in the sidebar column --------------------
   Measured: "New message" spanned x 12-217 while nav-item backgrounds spanned
   8-222. Two different insets in one 240px column, because `.sidebar__top` used
   `--sp-6` (12px) horizontally and `.sidebar__scroll` used `--sp-3` (6px) plus
   the nav item's own `--sp-4` (8px). Both now derive from ONE token, so the
   compose button and every nav row share an edge.

   BUG (j): the active accent bar was `left: 0` — flush with the row's own
   background box but OUTSIDE its 6px corner radius, so it read as breaking out
   of the row. It is now inset by the radius and clipped by it.               */

.sidebar {
  /* The single horizontal inset for everything in this column. */
  --sb-gutter: var(--sp-6);
}

.sidebar__top {
  padding: var(--sp-7) var(--sb-gutter) var(--sp-6);
}

.sidebar__scroll {
  /* Zero horizontal padding here: the gutter belongs to the rows, so a nav row's
     hover/active background can reach the same edge as the compose button rather
     than being inset by a parent's padding as well as its own. */
  padding: var(--sp-4) var(--sb-gutter) var(--sp-6);
}

.sidebar__bottom {
  padding: var(--sp-6) var(--sb-gutter) var(--sp-7);
}

.sb-section__header {
  /* Section labels sit on the same axis as the rows beneath them. */
  padding-left: var(--sp-4);
  padding-right: var(--sp-2);
}

.nav-item {
  /* The row spans the full gutter-to-gutter width; its text is inset by its own
     padding, which is the ONLY inset applied to it. */
  padding-left: var(--sp-4);
  padding-right: var(--sp-3);
}

.nav-item.is-active::before {
  /* Inside the rounded row, not flush with x=0 (bug (j)). */
  left: 3px;
  height: 14px;
  width: 2px;
}

/* Label rows carry a colour swatch instead of an outline glyph. */
.nav-item__swatch {
  flex: none;
  width: 9px;
  height: 9px;
  margin-left: 3px;
  margin-right: 3px;
  border-radius: 2px;
  background: var(--accent);
  box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.18);
}

/* ---- BUG (a): the account email is a real, visible line -----------------
   Measured: #menuEmail clientWidth 1, scrollWidth 122. It was `.sr-only`,
   which clips to a 1x1 box — so a geometry sweep correctly reported clipped
   content, and the address was ALSO already rendered by the button above it.
   It is now a visible, truncating caption owned by the account block.        */

/* The button's second line is a role hint, not a repeat of the address. */
.usermenu__role {
  font-size: var(--fs-3xs);
  color: var(--fg-subtle);
  max-width: 160px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.usermenu__email {
  display: block;
  max-width: 100%;
  min-width: 0;
  /* Sits INSIDE the account block's visual grouping rather than as loose text
     below its border: it is the button's caption, so it shares the button's text
     column exactly. The 34px inset is the button's own left padding plus the
     small avatar plus its gap, so the address starts on the same axis as the name
     above it — visual review caught it starting further left than that column. */
  margin-top: var(--sp-1);
  padding: 0 var(--sp-4) 0 34px;
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  line-height: var(--lh-snug);
  letter-spacing: 0;
  color: var(--fg-subtle);
  /* Truncation, not clipping: scrollWidth stays <= clientWidth. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* In the 56px icon rail there is no room for it, and hiding it with clip-path
   would leave a box a geometry sweep counts as clipped. `display:none` removes
   it from layout entirely. */
[data-layout='desktop-rail'] .usermenu__email,
.app.is-rail .usermenu__email {
  display: none;
}

/* MEASURED at 1024px: `span.usermenu__name scrollH=14 clientH=0` and the same for
   `.usermenu__addr`. The rail collapses `.usermenu__meta` with
   `width:1px; height:1px; clip-path: inset(50%)`, which is the standard sr-only
   recipe — but the CHILDREN keep their own layout boxes inside that 1px parent,
   so each one reports 14px of content in a 0px box. That is a genuine
   clipped-content reading, not a false positive: the text is unreachable.
   The children are removed from layout; the parent keeps the accessible name.  */
[data-layout='desktop-rail'] .app__sidebar .usermenu__meta > *,
.app.is-rail .app__sidebar .usermenu__meta > * {
  display: none;
}

/* Same class of problem for the collapsed compose button's label and keycap: the
   parent is clipped to 1px but its children still measure their own content. */
[data-layout='desktop-rail'] .app__sidebar .nav-item__label,
[data-layout='desktop-rail'] .app__sidebar .nav-item__count,
[data-layout='desktop-rail'] .app__sidebar .sb-section__title,
.app.is-rail .app__sidebar .nav-item__label,
.app.is-rail .app__sidebar .nav-item__count,
.app.is-rail .app__sidebar .sb-section__title {
  /* These hold only a single text node, so clipping the element itself is safe:
     there is no child box to measure. Overflow stays hidden and the 1px box is
     reported as having 1px of content, which is consistent. */
  max-width: 1px;
}

/* ---- BUG (k): Ctrl/K chips on the optical centre of the placeholder -----
   Measured: the chips sat ~2px above the placeholder's optical centre. Cause:
   `.search__hint` was absolutely positioned with `align-items` inherited from a
   flex parent it was not actually a child of for layout purposes, so it centred
   on the input's BOX rather than its text baseline. Anchoring it to the vertical
   centre with a transform puts it on the same optical line as the placeholder. */

.search__hint {
  top: 50%;
  transform: translateY(-50%);
  align-items: center;
  /* Nudge for the keycap's own 1px bottom border, which shifts its optical
     centre down relative to its box. */
  margin-top: -0.5px;
}

.search__clear {
  top: 50%;
  transform: translateY(-50%);
}

/* ---- BUG (m): the search field is centred on the CONTENT area -----------
   Measured: the field was centred on the viewport, not on the list+reader
   columns, because `.topbar__group--grow` is `justify-content:center` inside a
   flex row whose left group (brand) and right group (actions) have different
   widths. Centring on the viewport therefore does NOT centre it on the content.
   Fixed by giving the search a max-width and letting the grow group align it to
   the start of the content axis instead of the viewport's centre.            */

.topbar__group--grow {
  /* Start-aligned: the field's left edge lands on the content column's axis
     rather than floating at a viewport-relative centre. */
  justify-content: flex-start;
  padding-left: var(--sp-4);
}

@media (min-width: 1024px) {
  .topbar__group--grow {
    /* The sidebar is 240px and the brand group occupies the left of the bar, so
       the remaining offset needed to reach the content axis is small and
       explicit rather than emergent. */
    padding-left: var(--sp-2);
  }
}

/* ---- BUG (l): three left edges in the message-list column ----------------
   Measured: the list header started at one inset, the filter tabs at another,
   and the rows at a third. All three now read the SAME token.               */

.list {
  --list-gutter: var(--sp-6);
}

.list__header {
  padding: 0 var(--sp-4) 0 var(--list-gutter);
}

.list-tabs,
.list__footer {
  padding: var(--sp-3) var(--list-gutter);
}

.list__bulkbar {
  padding: 0 var(--list-gutter);
}

.search-filters,
.search-scope {
  padding: var(--sp-3) var(--list-gutter);
}

/* MEASURED: [244, 244, 242] — the rows sat 2px left of the header and the tabs.
   Cause: the density blocks set their OWN horizontal padding
   (`[data-density='compact'] .msg-row { padding: var(--sp-1) var(--sp-5) }`,
   i.e. 10px), which is later in the sheet and more specific than a plain
   `.msg-row` rule, so `--list-gutter` never applied to a row. The density modes
   own VERTICAL rhythm only; the horizontal gutter belongs to the column.

   SUPERSEDED by the Titan row rebuild: the row is now an 8-track grid whose
   FIRST track is the 3px unread rail, which must sit at x=0 with no padding in
   front of it. The gutter is therefore expressed as the checkbox/icon tracks on
   the left and `padding-right` on the right, and the column alignment that this
   rule was protecting is now enforced by the fixed tracks themselves and
   asserted numerically by the harness. */
.msg-row,
[data-density='compact'] .msg-row,
[data-density='comfortable'] .msg-row {
  padding-left: 0;
  padding-right: var(--list-gutter);
}

.list__group {
  padding-left: var(--list-gutter);
  padding-right: var(--list-gutter);
}

/* Turbo-search scope strip. */
.search-scope {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  border-bottom: var(--bw-thin) solid var(--border-subtle);
  background: var(--accent-subtle);
  color: var(--fg-muted);
  font-size: var(--fs-2xs);
  line-height: var(--lh-snug);
}

/* ---- BUG (e) + (f): ONE content axis in the reader ----------------------
   Measured: three right edges — header divider ~1525, banner border ~1531,
   card border ~1546. Cause: the toolbar reserved `--scrollbar-w` on the right
   while `.reader__inner` did not, and the blocked-images banner was rendered
   INSIDE a message card (so it inherited the card's padding as well as the
   reading column's). The banner is now hoisted onto the reading axis by
   `renderReader`, and both wrappers use one width and one padding pair.

   BUG (f): the subject heading's optical left edge sat ~14px inside the card
   gutter. An 18px semibold face with `--ls-tighter` has real left side-bearing,
   so matching padding boxes does NOT match optical edges. `.reader__head`
   applies the optical correction in one place.                              */

.reader__toolbar-inner,
.reader__inner {
  width: 100%;
  max-width: var(--reader-max-w);
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--sp-10);
  padding-right: var(--sp-10);
  box-sizing: border-box;
}

/* MEASURED: with symmetric padding on both wrappers the two right edges were
   still 5px apart (toolbar 1568, reading column 1563). Cause: `.reader__scroll`
   sets `scrollbar-gutter: stable`, which narrows its CONTENT box by the scrollbar
   width. `.reader__inner` centres itself with auto margins inside that narrowed
   box, so its centre — and therefore both its edges — shift left by HALF the
   gutter. Padding on the inner wrapper cannot fix that: the offset comes from the
   centring, not the inset.

   So the toolbar reserves the SAME gutter on its own container. Both wrappers then
   auto-centre inside identically-sized boxes and land on one axis. */
.reader__toolbar {
  box-sizing: border-box;
  padding-right: var(--scrollbar-w);
}

.reader__toolbar-inner {
  padding-left: var(--sp-10);
  padding-right: var(--sp-10);
}

.reader__toolbar:not(:has(.reader__toolbar-inner)) {
  padding: 0 var(--sp-10);
}

@supports not selector(:has(*)) {
  .reader__toolbar {
    padding: 0 var(--sp-10);
  }
}

.reader__inner {
  padding-top: var(--sp-9);
  padding-bottom: var(--sp-16);
}

/* Optical alignment for the subject heading (bug (f)). The heading's glyphs sit
   ~0.06em inside its box at this size and weight, so the wrapper pulls it left
   by that amount and the heading's first stem lands on the card border's axis. */
.reader__head {
  margin-bottom: var(--sp-6);
}

.reader__head .reader__subject {
  margin-bottom: 0;
  margin-left: -0.06em;
}

/* The banner is a sibling of the card stack now, on the reading axis. */
.reader__inner > .reader-banner {
  margin: 0 0 var(--sp-8);
}

/* ---- BUG (h): the banner's right inset matches its left ------------------
   Measured: "Always allow" sat ~8px from the banner border against a 16px inset
   on the left. Cause: `.reader-banner` padded itself with `--sp-6` (12px) while
   its `__actions` child used `margin-left:auto` and the buttons' own optical
   edge added no compensation, so the right gap measured smaller than the left
   text inset. Symmetric padding plus an explicit gap fixes it.              */

/* MEASURED after the first pass: left inset 48px, right inset 17px. The 48 was
   not the banner's padding at all — it was the padding PLUS the 15px icon PLUS the
   flex gap, because the measurement anchors on `.reader-banner__text`. The real
   defect was the right inset (17px against a 16px padding, so the button did sit
   ~1px inside) combined with a much larger left gap than the design intends.

   Fix: the banner is a 3-column grid, not a flex row. The icon gets its own
   track, the text starts on a predictable axis, and the action group ends exactly
   at the padding edge — so left text inset and right button inset are both
   `--sp-8` and cannot drift when the icon size changes. */
.reader-banner {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--sp-5) var(--sp-6);
  padding: var(--sp-5) var(--sp-8);
}

.reader-banner__icon {
  grid-column: 1;
}

.reader-banner__text {
  grid-column: 2;
}

.reader-banner__actions {
  grid-column: 3;
  gap: var(--sp-4);
  /* The grid track ends at the padding edge; no auto margin, no optical fudge. */
  margin-left: 0;
  margin-right: 0;
}

/* Below ~560px the three tracks cannot coexist: the actions wrap to their own
   row rather than squeezing the message to a couple of words per line. */
@media (max-width: 560px) {
  .reader-banner {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .reader-banner__actions {
    grid-column: 1 / -1;
    justify-content: flex-start;
  }
}

/* ---- BUG (g): no trailing divider in the reader toolbar ------------------
   `renderReaderToolbar` now prunes separators structurally (a separator is only
   kept between two non-empty groups), because the old `:last-child` guard could
   not match: the separator was the last child of `.reader__toolbar-actions`, not
   of the flex container the rule targeted. These rules are the belt to that
   braces, covering the wrapper case too.                                    */

.reader__toolbar-actions > .reader__toolbar-sep:first-child,
.reader__toolbar-actions > .reader__toolbar-sep:last-child,
.reader__toolbar-actions > .reader__toolbar-sep + .reader__toolbar-sep,
.reader__toolbar-actions > .reader__toolbar-group:empty,
.reader__toolbar-actions > .reader__toolbar-group:empty + .reader__toolbar-sep {
  display: none;
}

/* ---- BUG (d): the blocked-media placeholder is a real box ----------------
   Measured: the wrapper collapsed to the alt text's line-height and cropped it,
   and showed an unthemed near-white band.

   ROOT CAUSE, which the previous fix missed: a REPLACED element (<img>) with no
   resource renders only its alt text and cannot be sized by its content. No
   amount of padding on an <img> produces a box that grows to fit two lines of
   alt text, and the browser's own broken-image chrome is not themeable. The
   sanitiser now REPLACES the element with a <span>, which is an ordinary flow
   box — so the rules below actually apply.                                  */

.msg-body--html .blocked-media,
.blocked-media {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  box-sizing: border-box;
  /* Reserved dimensions: never zero-height, never wider than the column. */
  min-height: 40px;
  min-width: 120px;
  max-width: 100%;
  padding: var(--sp-4) var(--sp-6);
  margin: var(--sp-2) 0;
  /* Dark-theme aware: tokens, not the browser's broken-image styling. */
  background: var(--bg-sunken);
  border: 1px dashed var(--border-mid);
  border-radius: var(--r-md);
  color: var(--fg-muted);
  font-family: var(--font-sans);
  font-size: var(--fs-2xs);
  font-style: normal;
  line-height: var(--lh-snug);
  text-align: left;
  /* Overflow visible, and the text wraps instead of being cut. */
  overflow: visible;
  white-space: normal;
  overflow-wrap: anywhere;
  vertical-align: middle;
}

.blocked-media__glyph {
  flex: none;
  font-size: var(--fs-md);
  line-height: 1;
  color: var(--fg-subtle);
}

.blocked-media__text {
  min-width: 0;
  /* Two lines of alt text fit; a third is truncated rather than cropped
     mid-glyph. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Any <img data-blocked> that survives (an older cached render) gets the same
   treatment as far as an <img> can, so nothing falls back to the white band. */
.msg-body--html img[data-blocked] {
  min-height: 40px;
  min-width: 120px;
  padding: var(--sp-4) var(--sp-6);
  background: var(--bg-sunken);
  border: 1px dashed var(--border-mid);
  border-radius: var(--r-md);
  color: var(--fg-muted);
  font-size: var(--fs-2xs);
  font-style: normal;
  object-fit: contain;
}

/* ---- BUG (n): unread counts on every nav row ---------------------------- */

.nav-item__count {
  /* Tabular so a 2-digit and a 3-digit count keep the same right edge. */
  font-variant-numeric: tabular-nums;
  margin-left: auto;
}

/* ---- Label chips in list rows ------------------------------------------- */

/* Label chips ride in the main cell between the subject and the snippet, on the
   same baseline. `flex: none` + `nowrap` so they never wrap the row into a second
   line — the virtualiser requires a fixed height. */
.msg-row__labels {
  display: inline-flex;
  flex: none;
  flex-wrap: nowrap;
  align-items: center;
  gap: var(--sp-2);
  max-width: 30%;
  overflow: hidden;
}

.label-chip {
  display: inline-flex;
  align-items: center;
  height: 15px;
  padding: 0 var(--sp-3);
  border-radius: var(--r-pill);
  /* The chip's colour comes from the label's own metadata via a custom property,
     so one rule serves every label. */
  background: color-mix(in srgb, var(--chip, var(--accent)) 22%, transparent);
  border: var(--bw-thin) solid color-mix(in srgb, var(--chip, var(--accent)) 45%, transparent);
  color: var(--fg-strong);
  font-size: var(--fs-3xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps);
  white-space: nowrap;
  max-width: 14ch;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* `color-mix` is not universal; a solid fallback keeps chips legible without it. */
@supports not (background: color-mix(in srgb, red 20%, transparent)) {
  .label-chip {
    background: var(--bg-active);
    border-color: var(--border-mid);
  }
}

.label-swatch {
  flex: none;
  width: 14px;
  height: 14px;
  border-radius: var(--r-sm);
  box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.2);
}

/* ---- Avatar images (the "how do I set my icon" answer) ------------------- */

.avatar--image {
  padding: 0;
  overflow: hidden;
  background: var(--bg-inset);
}

.avatar__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  border-radius: inherit;
}


/* ==========================================================================
   41. SETTINGS SHEET
   ========================================================================== */

.settings {
  /* Taller than the default modal: these panes have real content, and a 760px
     cap forced the receipts table into a nested scroller. */
  width: min(1080px, 100%);
  max-height: min(88vh, 900px);
}

/* MEASURED DEFECT: the sheet's bottom-left corner was glitched — the nav
   column's `--bg-raised` fill painted square right through the modal's 12px
   `border-radius`, leaving a mismatched grey strip where the rounded corner
   should be.

   Root cause: `.modal { overflow: hidden }` clips DESCENDANT overflow, but the
   nav is a grid child whose own background box extends to the grid area's square
   edge; with the body as the last flex child there was nothing between it and the
   rounded corner to mask it. Two fixes, both needed:
     1. the body gets its own `overflow: hidden` so it clips its children's
        backgrounds to ITS box, and
     2. the sticky footer now occupies the bottom edge, so the rounded corner is
        drawn by the footer's own background rather than by the nav's.
   Belt-and-braces: the nav's bottom corner is rounded to match, which keeps the
   corner correct even in the panes-only layout below 900px where the footer is
   the only thing under the nav. */
.settings__body {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-columns: 232px minmax(0, 1fr);
  overflow: hidden;
}

/* Sticky footer, always visible below the scrolling pane. Its presence is what
   stops the add-identity form from clipping at the sheet's bottom edge: the pane
   is now a bounded scroll region rather than content that simply runs out of
   modal. */
.settings__footer {
  position: sticky;
  bottom: 0;
  z-index: 1;
  /* Matches the modal's own radius so the sheet's bottom corners are drawn by
     this element, which is what repairs the glitched corner. */
  border-bottom-left-radius: var(--r-xl);
  border-bottom-right-radius: var(--r-xl);
}

.settings__savehint {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--fg-subtle);
  font-size: var(--fs-2xs);
}

.settings__nav {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--sp-5) var(--sp-4);
  background: var(--bg-raised);
  border-right: var(--bw-thin) solid var(--border);
}

.settings-tab {
  display: flex;
  align-items: center;
  gap: var(--sp-5);
  width: 100%;
  min-height: 32px;
  padding: 0 var(--sp-5);
  border-radius: var(--r-md);
  color: var(--fg-muted);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  text-align: left;
  transition: background-color var(--dur-fast) var(--ease-standard),
    color var(--dur-fast) var(--ease-standard);
}

.settings-tab:hover {
  background: var(--bg-hover);
  color: var(--fg);
}

.settings-tab.is-active {
  background: var(--bg-active);
  color: var(--fg-strong);
}

.settings-tab.is-active .settings-tab__icon {
  color: var(--accent-text);
}

.settings-tab__icon {
  flex: none;
  width: 15px;
  height: 15px;
  color: var(--fg-subtle);
}

.settings-tab__label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.settings__pane {
  min-width: 0;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--sp-9) var(--sp-10) var(--sp-12);
}

/* The `.settings__caps` header pill was REMOVED from index.html — it was a
   developer diagnostic in shipping chrome. The rule is kept because nothing else
   uses it and deleting a whole block risks a brace slip in a 214KB sheet; it now
   matches nothing. The information moved to the Advanced pane.
   DEAD RULE — no element carries this class. */
.settings__caps {
  display: inline-flex;
  align-items: center;
  max-width: 34ch;
  height: 20px;
  padding: 0 var(--sp-4);
  border-radius: var(--r-pill);
  background: var(--bg-active);
  border: var(--bw-thin) solid var(--border);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--fg-muted);
  font-size: var(--fs-3xs);
  letter-spacing: var(--ls-caps);
  flex: none;
  /* Its own breathing room from the dismiss target. Visual review still read 18px
     as "crowded" against the header's own 8px right padding, so the gap is now
     larger than the padding it sits next to and the chip cannot look glued to X. */
  margin-right: var(--sp-9);
}

/* Narrow sheets drop it: the panes state their own capability caveats inline, so
   this is a convenience, not the only place the information exists. */
@media (max-width: 900px) {
  .settings__caps { display: none; }
}

/* ---- pane building blocks ----------------------------------------------- */

.settings-section {
  margin-bottom: var(--sp-12);
}

.settings-section:last-child {
  margin-bottom: 0;
}

.settings-section__title {
  margin: 0 0 var(--sp-3);
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-tight);
  color: var(--fg-strong);
}

.settings-section__hint {
  margin: 0 0 var(--sp-7);
  max-width: 72ch;
  font-size: var(--fs-xs);
  line-height: var(--lh-relaxed);
  color: var(--fg-muted);
}

.settings-section__inner {
  margin-bottom: var(--sp-8);
}

.settings-field {
  display: grid;
  grid-template-columns: 200px minmax(0, 1fr);
  align-items: center;
  gap: var(--sp-4) var(--sp-8);
  padding: var(--sp-4) 0;
  border-bottom: var(--bw-thin) solid var(--border-subtle);
}

.settings-field:last-child {
  border-bottom: 0;
}

.settings-field__label {
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--fg);
  line-height: var(--lh-snug);
}

.settings-field__control {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  min-width: 0;
  flex-wrap: wrap;
}

.settings-field__control > .input,
.settings-field__control > .select,
.settings-field__control > .textarea {
  flex: 1 1 240px;
  min-width: 0;
}

.settings-field__control > .textarea {
  flex-basis: 100%;
}

.settings-field__hint {
  grid-column: 2;
  max-width: 72ch;
  font-size: var(--fs-2xs);
  line-height: var(--lh-relaxed);
  color: var(--fg-subtle);
}

.settings-inline {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  flex-wrap: wrap;
  min-width: 0;
  flex: 1 1 100%;
}

.settings-inline > .input {
  flex: 1 1 200px;
  min-width: 0;
}

.settings-actions {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  flex-wrap: wrap;
  margin-top: var(--sp-6);
}

.settings-card {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-6) var(--sp-7);
  margin-bottom: var(--sp-5);
  background: var(--bg-raised);
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-lg);
}

.settings-card--row {
  flex-direction: row;
  align-items: center;
  gap: var(--sp-5);
  flex-wrap: wrap;
}

.settings-card--row > .input {
  flex: 1 1 180px;
  min-width: 0;
}

.settings-card__head {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  min-width: 0;
}

.settings-card__title {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--fg-strong);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.settings-card__meta {
  font-size: var(--fs-2xs);
  color: var(--fg-subtle);
  line-height: var(--lh-relaxed);
  overflow-wrap: anywhere;
}

.settings-card__body {
  margin: 0;
  padding: var(--sp-4) var(--sp-5);
  max-height: 120px;
  overflow: auto;
  background: var(--bg-inset);
  border-radius: var(--r-sm);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  line-height: var(--lh-relaxed);
  color: var(--fg-muted);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.settings-editor {
  display: flex;
  flex-direction: column;
  padding: var(--sp-7);
  margin-top: var(--sp-6);
  background: var(--bg-inset);
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-lg);
}

.settings-editor__title {
  margin: 0 0 var(--sp-5);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--fg-strong);
}

.settings-editor__status {
  font-size: var(--fs-2xs);
  color: var(--fg-muted);
  line-height: var(--lh-relaxed);
  overflow-wrap: anywhere;
  max-width: 68ch;
}

.settings-empty {
  padding: var(--sp-10) var(--sp-8);
  text-align: center;
  background: var(--bg-inset);
  border: var(--bw-thin) dashed var(--border-mid);
  border-radius: var(--r-lg);
}

.settings-empty__title {
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--fg-strong);
  margin-bottom: var(--sp-2);
}

.settings-empty__text {
  font-size: var(--fs-xs);
  color: var(--fg-muted);
  line-height: var(--lh-relaxed);
  max-width: 52ch;
  margin: 0 auto;
}

.settings-switch {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-5);
  padding: var(--sp-5) 0;
  cursor: pointer;
}

.settings-switch__text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.settings-switch__label {
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--fg-strong);
}

.settings-switch__hint {
  font-size: var(--fs-2xs);
  line-height: var(--lh-relaxed);
  color: var(--fg-subtle);
  max-width: 68ch;
}

.settings-rowactions {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
}

.settings-code {
  margin: var(--sp-6) 0 0;
  padding: var(--sp-6);
  max-height: 320px;
  overflow: auto;
  background: var(--bg-sunken);
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-md);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  line-height: var(--lh-relaxed);
  color: var(--fg-muted);
  white-space: pre;
}

.settings-details {
  margin-top: var(--sp-6);
}

.settings-details summary {
  cursor: pointer;
  font-size: var(--fs-xs);
  color: var(--fg-muted);
}

.settings-loading {
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
  padding: var(--sp-8) 0;
}

.skeleton--line {
  height: 12px;
  border-radius: var(--r-sm);
  background: var(--bg-active);
}

.skeleton--short {
  width: 40%;
}

/* ---- data tables --------------------------------------------------------- */

.settings-table-wrap {
  /* Only this element scrolls horizontally, and only when it must: a wide table
     must never widen the sheet or the document. */
  max-width: 100%;
  overflow-x: auto;
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-lg);
  background: var(--bg-raised);
}

.settings-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-xs);
}

.settings-table th {
  position: sticky;
  top: 0;
  z-index: 1;
  padding: var(--sp-4) var(--sp-6);
  background: var(--bg-raised);
  border-bottom: var(--bw-thin) solid var(--border);
  text-align: left;
  font-size: var(--fs-3xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--fg-subtle);
  white-space: nowrap;
}

.settings-table td {
  padding: var(--sp-4) var(--sp-6);
  border-bottom: var(--bw-thin) solid var(--border-subtle);
  color: var(--fg);
  vertical-align: middle;
  max-width: 34ch;
  overflow-wrap: anywhere;
}

.settings-table tbody tr:last-child td {
  border-bottom: 0;
}

.settings-table tbody tr:hover {
  background: var(--bg-hover);
}

/* ---- account card ------------------------------------------------------- */

.settings-idcard {
  display: flex;
  align-items: center;
  gap: var(--sp-7);
  padding: var(--sp-7);
  background: var(--bg-raised);
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-lg);
}

.settings-idcard__avatar {
  flex: none;
}

.settings-idcard__meta {
  min-width: 0;
}

.settings-idcard__name {
  font-size: var(--fs-md);
  font-weight: var(--fw-semibold);
  color: var(--fg-strong);
}

.settings-idcard__addr {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--fg-muted);
  letter-spacing: 0;
  overflow-wrap: anywhere;
}

.settings-idcard__sub {
  margin-top: var(--sp-2);
  font-size: var(--fs-3xs);
  color: var(--fg-subtle);
}

.settings-avatar-preview {
  display: flex;
  align-items: center;
  gap: var(--sp-6);
  margin-top: var(--sp-5);
}

.settings-avatar-preview__img {
  width: 64px;
  height: 64px;
  border-radius: var(--r-lg);
  object-fit: cover;
  border: var(--bw-thin) solid var(--border);
  display: block;
}

/* ---- import guide ------------------------------------------------------- */

.settings-guide {
  padding: var(--sp-7);
  margin-bottom: var(--sp-7);
  background: var(--bg-inset);
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-lg);
}

.settings-guide__title {
  margin: 0 0 var(--sp-5);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--fg-strong);
}

/* MEASURED by visual review: the steps rendered as indented lines with no visible
   markers, because `display:flex` on an <ol> removes the list-item layout that
   draws them. It IS a real <ol> (so assistive tech reads it as an ordered list),
   but the numbers were invisible. A counter draws them back without giving up the
   flex gap. */
.settings-guide__steps {
  margin: 0;
  padding-left: 0;
  list-style: none;
  counter-reset: guide-step;
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  font-size: var(--fs-xs);
  line-height: var(--lh-relaxed);
  color: var(--fg-muted);
}

.settings-guide__steps li {
  counter-increment: guide-step;
  display: grid;
  grid-template-columns: 22px minmax(0, 1fr);
  gap: var(--sp-4);
  max-width: 82ch;
}

.settings-guide__steps li::before {
  content: counter(guide-step);
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
  border-radius: var(--r-pill);
  background: var(--bg-active);
  color: var(--fg-strong);
  font-size: var(--fs-3xs);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
}

/* ---- Styled file picker -------------------------------------------------- */

/* MEASURED DEFECT: the profile-image control was a raw `<input type="file">`.
   Restyling the `::file-selector-button` (the block below) fixes the colours but
   CANNOT fix the real problem: the browser renders both the button label and the
   "no file chosen" text in the OS LOCALE, so an English UI printed the Czech
   "Vybrat soubor / Soubor nevybrán" inside the settings sheet. There is no CSS or
   attribute that changes that text.

   So the native input is now `display: none` and used only to open the dialog;
   everything visible is our own markup. */
.filepick {
  display: flex;
  align-items: center;
  gap: var(--sp-5);
  min-width: 0;
}

/* MEASURED: this input still rendered (computed `display: flex`). Cause: the
   legacy `.settings__pane input[type='file']` rule below is a two-part selector
   and therefore MORE SPECIFIC than a single class, so it won a `display` fight
   with `.filepick__input`. `!important` is the correct tool here rather than
   escalating the selector: the intent is absolute — this element must never be
   painted, in any pane, under any later rule. */
.filepick__input {
  display: none !important;
}

.filepick__name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--fg-subtle);
  font-size: var(--fs-xs);
  font-style: italic;
}

.filepick__name.is-set {
  color: var(--fg);
  font-style: normal;
  font-variant-numeric: tabular-nums;
}

/* Identity name cell: label plus an optional Default badge on one baseline. */
.settings-identity__name {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-4);
  min-width: 0;
}

/* An inline code run for a diagnostic value, sized to sit in a settings hint
   rather than as a full-width pre block. */
.settings-code--inline {
  display: inline-block;
  margin: 0;
  padding: 1px var(--sp-3);
  max-height: none;
  overflow: visible;
  font-size: var(--fs-2xs);
}

.settings-idcard__diag {
  margin-top: var(--sp-3);
}

.settings-idcard__diagbody {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--sp-3);
  padding-top: var(--sp-3);
}

/* LEGACY: the restyled native input. Retained for any file input elsewhere in the
   panes, but the profile-image control no longer uses one. */
.settings-field__control input[type='file'],
.settings__pane input[type='file'] {
  /* MEASURED: the styled button rendered taller than its container and clipped at
     the top edge. Cause: `::file-selector-button` keeps the UA's own line-height
     while the container was sized from the smaller `--fs-xs` text. Explicit
     `line-height` on both, plus `height: auto` and matching vertical padding, lets
     the container grow to the button rather than cropping it. */
  display: inline-flex;
  align-items: center;
  height: auto;
  min-height: 34px;
  padding: var(--sp-2) var(--sp-4);
  font-size: var(--fs-xs);
  line-height: 1.4;
  color: var(--fg-muted);
  background: var(--bg-inset);
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-md);
  cursor: pointer;
  box-sizing: border-box;
}

.settings__pane input[type='file']::file-selector-button {
  margin-right: var(--sp-5);
  height: 24px;
  line-height: 1.4;
  padding: 0 var(--sp-6);
  background: var(--bg-active);
  color: var(--fg-strong);
  border: var(--bw-thin) solid var(--border-mid);
  border-radius: var(--r-sm);
  font-family: inherit;
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  cursor: pointer;
}

.settings__pane input[type='file']::file-selector-button:hover {
  background: var(--bg-hover);
  border-color: var(--border-strong);
}

.settings-progress {
  margin: var(--sp-7) 0;
}

.progress {
  height: 6px;
  border-radius: var(--r-pill);
  background: var(--bg-active);
  overflow: hidden;
}

.progress__fill {
  height: 100%;
  width: 0%;
  border-radius: var(--r-pill);
  background: var(--accent);
  transition: width var(--dur-base) var(--ease-standard);
}

.progress__label {
  margin-bottom: var(--sp-3);
  font-size: var(--fs-2xs);
  font-variant-numeric: tabular-nums;
  color: var(--fg-muted);
}

.import-errors {
  margin-top: var(--sp-6);
}

.import-errors__list {
  margin: 0;
  padding: 0;
  list-style: none;
  max-height: 220px;
  overflow-y: auto;
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-md);
}

.import-errors__item {
  display: flex;
  gap: var(--sp-4);
  padding: var(--sp-3) var(--sp-5);
  border-bottom: var(--bw-thin) solid var(--border-subtle);
  font-size: var(--fs-2xs);
  line-height: var(--lh-relaxed);
  color: var(--danger-text, var(--fg-muted));
  overflow-wrap: anywhere;
}

.import-errors__item:last-child {
  border-bottom: 0;
}

.import-errors__idx {
  flex: none;
  font-family: var(--font-mono);
  color: var(--fg-subtle);
}

/* ---- receipts ----------------------------------------------------------- */

.receipt-totals {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
  gap: var(--sp-4);
  margin: var(--sp-7) 0;
  padding: var(--sp-6);
  background: var(--bg-raised);
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-lg);
}

.receipt-total {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  min-width: 0;
}

.receipt-total__num {
  font-size: var(--fs-lg);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
  color: var(--fg-strong);
  line-height: 1;
}

.receipt-total__label {
  font-size: var(--fs-3xs);
  color: var(--fg-subtle);
  text-align: center;
  line-height: var(--lh-snug);
}

.receipt-state {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  font-size: var(--fs-2xs);
  white-space: nowrap;
}

.receipt-state--read {
  color: var(--success-text, var(--accent-text));
}

.receipt-state--none {
  color: var(--fg-subtle);
}

/* ---- filters builder ---------------------------------------------------- */

.filter-list {
  display: flex;
  flex-direction: column;
  gap: var(--sp-6);
}

.filter-card {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding: var(--sp-7);
  background: var(--bg-raised);
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-lg);
}

.filter-card__head {
  display: flex;
  align-items: center;
  gap: var(--sp-5);
}

.filter-card__name {
  flex: 1 1 auto;
  min-width: 0;
  font-weight: var(--fw-semibold);
}

.filter-card__legend {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  font-size: var(--fs-3xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--fg-subtle);
}

/* The AND/OR combinator now sits in its OWN row that shares the condition grid,
   so it starts on the same first-column axis as every `From` select below it and
   ends inside the same reserved remove-button track. Visual review found it
   inline with the WHEN label, which pushed it ~25px right of the column it was
   meant to head. */
.filter-cond--match {
  /* Same track structure as a condition row, but the combinator spans the three
     control columns: it is one decision about the whole group, not a field triple. */
  padding-left: var(--sp-5);
  border-left: 2px solid var(--border-mid);
  margin-bottom: var(--sp-2);
}

.filter-cond--match > .select {
  grid-column: 1 / 4;
  justify-self: start;
  width: auto;
  min-width: 200px;
  max-width: 260px;
}

/* Same reservation for the rule-name row, so the name field, the combinator and
   the condition controls all stop on one axis. */
.filter-card__head {
  padding-right: 0;
}

.filter-conds,
.filter-actions {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  align-items: flex-start;
  padding-left: var(--sp-5);
  border-left: 2px solid var(--border-mid);
}

/* Visual review flagged three different right edges in one stack: the rule-name
   input, the WHEN combinator and the condition rows all ended at different x. A
   flex row with `flex-wrap` and per-child basis values cannot guarantee a shared
   right edge, so the condition rows are a GRID with a fixed remove-button track.
   Every row's controls and its × now land on the same two axes. */
.filter-cond {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.4fr) 28px;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  min-width: 0;
}

.filter-cond > .select,
.filter-cond > .input {
  min-width: 0;
  max-width: none;
  width: 100%;
}

/* A hidden control (the operator/value pair vanishes for a boolean condition)
   must not leave a gap that shifts the row's other columns. */
.filter-cond > [hidden] {
  display: none !important;
}

.filter-cond > .btn {
  justify-self: end;
  width: 28px;
  min-width: 28px;
  padding: 0;
}

/* The THEN rows have three controls, not four (type + one of mailbox/label, plus
   the remove button), so a shared 4-track grid would leave a hole. They get their
   own 3-track grid whose LAST track is the same 28px remove column, which is the
   axis that has to match — visual review found the action row's × sitting ~30px
   inboard of the condition rows'. */
.filter-actions .filter-cond {
  grid-template-columns: minmax(0, 1fr) minmax(0, 2.4fr) 28px;
}

/* The name field and the combinator share the rows' right edge, minus the
   remove-button track, so the whole card reads as one aligned stack. */
.filter-card__head,
.filter-card__legend {
  padding-right: 0;
}

.filter-card__head .filter-card__name {
  min-width: 0;
}

/* The conditions and actions groups have the same inset and the same measure, so
   the card presents ONE content column rather than several. */
.filter-conds,
.filter-actions {
  width: 100%;
}

@media (max-width: 720px) {
  .filter-actions .filter-cond {
    grid-template-columns: minmax(0, 1fr) 28px;
  }
}

@media (max-width: 720px) {
  .filter-cond {
    /* Two rows rather than four squeezed columns. */
    grid-template-columns: minmax(0, 1fr) 28px;
  }

  .filter-cond > .select:first-child {
    grid-column: 1 / -1;
  }
}

/* ---- tasks -------------------------------------------------------------- */

.task-row {
  display: flex;
  align-items: center;
  gap: var(--sp-5);
  padding: var(--sp-5) var(--sp-6);
  margin-bottom: var(--sp-3);
  background: var(--bg-raised);
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-md);
}

.task-row.is-done .task-row__title {
  text-decoration: line-through;
  color: var(--fg-subtle);
}

.task-row__meta {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.task-row__title {
  font-size: var(--fs-sm);
  color: var(--fg-strong);
  overflow-wrap: anywhere;
}

.task-row__sub {
  font-size: var(--fs-2xs);
  color: var(--fg-subtle);
  overflow-wrap: anywhere;
}

/* ---- narrow settings --------------------------------------------------- */

@media (max-width: 900px) {
  .settings__body {
    /* One column: a 232px rail plus content does not fit, and a horizontally
       scrolling settings sheet would be a defect, not a layout. */
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
  }

  .settings__nav {
    flex-direction: row;
    /* MEASURED at 390px: `button.settings-tab right=396` — a tab's box extended
       6px past the viewport. An `overflow-x: auto` scroller does NOT clip its
       children's bounding rects for a geometry sweep, and more importantly a
       13-tab horizontal scroller at 390px is a bad way to navigate settings on a
       phone anyway: the user has to scroll a strip to find a pane.

       So below 640px the nav WRAPS into a grid instead of scrolling. Every tab is
       visible, nothing extends past the viewport, and there is no hidden
       horizontal scroll for the user to discover. */
    flex-wrap: wrap;
    overflow-x: hidden;
    overflow-y: auto;
    max-height: 30vh;
    border-right: 0;
    border-bottom: var(--bw-thin) solid var(--border);
    padding: var(--sp-4);
    gap: var(--sp-2);
  }

  .settings-tab {
    flex: 0 1 auto;
    width: auto;
    /* `min-width: 0` plus ellipsis so a long label shrinks rather than pushing the
       row wider than its container. */
    min-width: 0;
    max-width: 100%;
    white-space: nowrap;
  }

  .settings-tab__label {
    white-space: nowrap;
  }

  .settings__pane {
    padding: var(--sp-7) var(--sp-7) var(--sp-10);
  }

  .settings-field {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--sp-3);
  }

  .settings-field__hint {
    grid-column: 1;
  }
}


/* ==========================================================================
   42. RICH TEXT COMPOSER — format bar, editable surface, HTML source view
   ========================================================================== */

.fmt-bar {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  /* Wraps rather than overflowing: at 390px there is no honest way to fit 20
     controls on one line, and a horizontally scrolling toolbar inside a modal is
     worse than two rows. */
  flex-wrap: wrap;
  row-gap: var(--sp-2);
  min-height: 36px;
  padding: var(--sp-3) var(--sp-6);
  background: var(--bg-raised);
  border-top: var(--bw-thin) solid var(--border);
  border-bottom: var(--bw-thin) solid var(--border);
}

.fmt-bar__group {
  display: flex;
  align-items: center;
  gap: 1px;
}

.fmt-bar__sep {
  flex: none;
  width: var(--bw-thin);
  height: 18px;
  margin: 0 var(--sp-2);
  background: var(--border-mid);
}

/* Same rule as the reader toolbar: a separator with nothing beside it is noise. */
.fmt-bar__sep:first-child,
.fmt-bar__sep:last-child,
.fmt-bar__sep + .fmt-bar__sep {
  display: none;
}

.fmt-bar__spacer {
  flex: 1 1 auto;
}

.fmt-bar__block {
  min-width: 128px;
}

.fmt-btn {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  flex: none;
  border-radius: var(--r-sm);
  color: var(--fg-muted);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  line-height: 1;
  transition: background-color var(--dur-fast) var(--ease-standard),
    color var(--dur-fast) var(--ease-standard);
}

.fmt-btn:hover:not(:disabled) {
  background: var(--bg-hover);
  color: var(--fg-strong);
}

.fmt-btn[aria-pressed='true'],
.fmt-btn.is-on {
  background: var(--accent-subtle);
  color: var(--accent-text);
}

.fmt-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.fmt-btn strong,
.fmt-btn em,
.fmt-btn u,
.fmt-btn s {
  font-size: var(--fs-sm);
}

/* Colour pickers: a native `input[type=color]` is an unstyleable 40x24 swatch in
   most engines, so it is made invisible and a themed swatch is drawn over it. The
   input keeps the click target, so no JS is needed to open the picker. */
.fmt-color {
  position: relative;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: var(--r-sm);
  cursor: pointer;
  overflow: hidden;
}

.fmt-color:hover {
  background: var(--bg-hover);
}

.fmt-color input[type='color'] {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  opacity: 0;
  cursor: pointer;
}

.fmt-color__swatch {
  pointer-events: none;
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  color: var(--fg-muted);
  /* The underline IS the colour affordance. */
  border-bottom: 2px solid currentColor;
  line-height: 1.1;
}

.fmt-color--hl .fmt-color__swatch {
  color: var(--warning-text, var(--fg-muted));
}

/* ---- the editable surface ------------------------------------------------ */

.compose__editor--rich {
  flex: 1 1 auto;
  min-height: 220px;
  max-height: 46vh;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--sp-7);
  background: transparent;
  border: 0;
  color: var(--fg);
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  line-height: var(--lh-relaxed);
  letter-spacing: var(--ls-tight);
  outline: none;
  /* Long pasted URLs must wrap, not widen the modal. */
  overflow-wrap: anywhere;
}

.compose__editor--rich:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: -3px;
}

/* `:empty` is unreliable on a contenteditable: browsers leave a stray <br>
   behind. `syncPlaceholder()` sets `.is-empty` from the text content instead. */
.compose__editor--rich.is-empty::before {
  content: attr(data-placeholder);
  color: var(--fg-subtle);
  pointer-events: none;
  display: block;
}

.compose__editor--rich.is-dropping {
  background: var(--accent-subtle);
  box-shadow: inset 0 0 0 2px var(--accent);
}

/* Content styling INSIDE the editor. These are also the shapes the recipient
   sees, so they are conservative: tags a mail client will not strip. */
.compose__editor--rich > *:first-child { margin-top: 0; }

.compose__editor--rich h1,
.compose__editor--rich h2,
.compose__editor--rich h3 {
  margin: var(--sp-7) 0 var(--sp-4);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  color: var(--fg-strong);
}

.compose__editor--rich h1 { font-size: var(--fs-xl); }
.compose__editor--rich h2 { font-size: var(--fs-lg); }
.compose__editor--rich h3 { font-size: var(--fs-md); }

.compose__editor--rich p,
.compose__editor--rich div {
  margin: 0 0 var(--sp-3);
}

.compose__editor--rich ul,
.compose__editor--rich ol {
  margin: var(--sp-4) 0;
  padding-left: var(--sp-11);
}

.compose__editor--rich li {
  margin-bottom: var(--sp-2);
}

.compose__editor--rich blockquote {
  margin: var(--sp-5) 0;
  padding: var(--sp-2) 0 var(--sp-2) var(--sp-6);
  border-left: 2px solid var(--border-mid);
  color: var(--fg-muted);
}

.compose__editor--rich pre {
  margin: var(--sp-5) 0;
  padding: var(--sp-5) var(--sp-6);
  background: var(--bg-inset);
  border-radius: var(--r-md);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  line-height: var(--lh-relaxed);
  white-space: pre-wrap;
  overflow-x: auto;
}

.compose__editor--rich code {
  padding: 1px 4px;
  background: var(--bg-inset);
  border-radius: var(--r-xs);
  font-family: var(--font-mono);
  font-size: 0.92em;
}

.compose__editor--rich pre code {
  padding: 0;
  background: none;
}

.compose__editor--rich a {
  color: var(--accent-text);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.compose__editor--rich hr {
  margin: var(--sp-7) 0;
  border: 0;
  border-top: var(--bw-thin) solid var(--border);
}

.compose__editor--rich img {
  max-width: 100%;
  height: auto;
  border-radius: var(--r-sm);
}

.compose__editor--rich table {
  border-collapse: collapse;
  max-width: 100%;
}

.compose__editor--rich td,
.compose__editor--rich th {
  padding: var(--sp-3) var(--sp-5);
  border: var(--bw-thin) solid var(--border);
}

/* Quoted originals and signatures inside a reply. */
.compose__editor--rich .hal-quote-head {
  margin-top: var(--sp-7);
  font-size: var(--fs-xs);
  color: var(--fg-subtle);
}

.compose__editor--rich .hal-quote {
  margin-top: var(--sp-3);
  padding-left: var(--sp-6);
  border-left: 2px solid var(--border-mid);
  color: var(--fg-muted);
  font-size: var(--fs-sm);
}

.compose__editor--rich .hal-signature {
  color: var(--fg-muted);
  font-size: var(--fs-sm);
}

/* ---- the HTML source surface -------------------------------------------- */

.compose__source {
  flex: 1 1 auto;
  min-height: 220px;
  max-height: 46vh;
  width: 100%;
  padding: var(--sp-7);
  background: var(--bg-sunken);
  border: 0;
  resize: none;
  color: var(--fg);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  line-height: var(--lh-relaxed);
  letter-spacing: 0;
  tab-size: 2;
  overflow: auto;
  white-space: pre;
}

.compose__source:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring);
  outline-offset: -3px;
}

.compose__sourcenote {
  flex: none;
  padding: var(--sp-4) var(--sp-7);
  background: var(--warning-subtle);
  border-top: var(--bw-thin) solid var(--warning-border);
  color: var(--fg-muted);
  font-size: var(--fs-2xs);
  line-height: var(--lh-relaxed);
}

/* Small screens: the composer is the whole viewport, so the editor gets the
   remaining height rather than a fixed 46vh cap that would leave dead space. */
@media (max-width: 767px) {
  /* MEASURED at 390x844: the body input was ~130px tall with ~310px of empty page
     behind the modal. On a phone the composer IS the screen, so it takes the
     viewport and gives the leftover height to the editor rather than leaving a
     third of the display unused. */
  /* `#composeOverlay` is targeted by id as well as by `:has()`, because `:has()`
     is not universal and this rule is load-bearing for the layout rather than
     cosmetic — falling back to a centred 46vh card would restore the defect. */
  #composeOverlay,
  .overlay:has(.compose) {
    padding: 0;
    place-items: stretch;
  }

  .modal.compose {
    width: 100%;
    max-width: 100%;
    height: 100%;
    max-height: 100%;
    border-radius: 0;
    border-left: 0;
    border-right: 0;
  }

  .compose__fields {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
  }

  .compose__editor--rich,
  .compose__source {
    /* `flex: 1` inside a column flex parent that itself grew to the viewport: the
       editor absorbs every pixel the header rows do not need. */
    flex: 1 1 auto;
    max-height: none;
    min-height: 160px;
  }

  /* Bigger touch targets: 26px icon buttons are below the 44px guidance, and the
     format bar is the densest cluster in the app. */
  .fmt-btn,
  .fmt-color {
    width: 34px;
    height: 34px;
  }

  .fmt-bar__sep {
    margin: 0 var(--sp-1);
  }

  .fmt-bar {
    padding: var(--sp-3) var(--sp-5);
  }

  /* At this width the bar is already two rows; the block-format select is the
     one control that can afford to go full-width and read clearly. */
  .fmt-bar__block {
    min-width: 0;
    flex: 1 1 100%;
  }
}

/* A `select--xs` size exists for dense builder rows. */
.select--xs {
  height: 26px;
  padding: 0 var(--sp-8) 0 var(--sp-4);
  font-size: var(--fs-xs);
}

.textarea--sm {
  min-height: 76px;
  padding: var(--sp-4) var(--sp-5);
  font-size: var(--fs-xs);
  line-height: var(--lh-relaxed);
}

/* ==========================================================================
   43. FINAL OVERFLOW GUARDS for the surfaces added above
   ========================================================================== */

.settings,
.settings__body,
.settings__nav,
.settings__pane,
.settings-field,
.settings-field__control,
.settings-card,
.filter-card,
.filter-cond,
.task-row,
.receipt-totals,
.fmt-bar,
.fmt-bar__group,
.compose__editor--rich,
.compose__source {
  min-width: 0;
}

.settings__pane pre,
.settings__pane table {
  max-width: 100%;
}

/* Nothing in these panes may create a document-level scrollbar. */
.settings-code,
.settings-card__body {
  max-width: 100%;
  overflow-wrap: anywhere;
}

/* ==========================================================================
   SELECT-ALL, CONFIRMATION DIALOG, MCP PANE
   Appended last so these rules win over the base component styles they extend
   without needing `!important` anywhere.
   ========================================================================== */

/* ---- Tri-state select-all in the list header ---------------------------- */
/* The header is a fixed 44px flex row. The wrapper is sized to the SAME 32px
   track the row checkbox occupies so the header box sits on the same x as every
   row's box — a select-all that does not line up with what it selects reads as
   unrelated chrome. */
.list__selectall {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  min-width: 18px;
}

.list__selectall .checkbox {
  margin: 0;
}

/* ---- Bulk bar: keep every control inside the viewport -------------------- */
/* MEASURED at 768px: two buttons ended at x=806 and x=861 in a 768px viewport.
   Cause: the bar gained a Move button and a select-all escalation link, and
   eleven controls do not fit one 44px row once the list column narrows.

   Horizontal scrolling was the first attempt and it is the WRONG fix: the
   container clips the buttons visually but their boxes still sit outside the
   viewport, which is exactly the defect being measured — an action the user
   cannot see or reach. So the bar wraps below 900px instead. Its height changes
   with the wrap, which §6.5 avoids on the desktop swap, but at these widths the
   bar and the header are never both candidates for the same 44px strip, and an
   unreachable Delete button is the worse of the two problems.

   Above 900px nothing changes: the bar stays one fixed 44px row. */
.list__bulkbar > .badge,
.list__bulkbar > .btn {
  flex: none;
}

@media (max-width: 900px) {
  .list__bulkbar {
    flex-wrap: wrap;
    height: auto;
    min-height: 44px;
    row-gap: var(--sp-2);
    padding-top: var(--sp-3);
    padding-bottom: var(--sp-3);
  }

  /* The spacer would otherwise eat a whole wrapped line. */
  .list__bulkbar > .list__spacer {
    flex-basis: 100%;
    height: 0;
  }
}

#bulkSelectQuery {
  white-space: nowrap;
  text-align: left;
}

/* ---- Confirmation dialog ------------------------------------------------- */
.confirm__body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding: var(--sp-7);
}

.confirm__text {
  margin: 0;
  font-size: var(--fs-sm);
  line-height: var(--lh-relaxed);
  color: var(--fg-strong);
  overflow-wrap: anywhere;
}

.confirm__note {
  margin: 0;
  padding: var(--sp-4) var(--sp-5);
  background: var(--danger-subtle, var(--bg-inset));
  border-left: 2px solid var(--danger);
  border-radius: var(--r-sm);
  font-size: var(--fs-2xs);
  line-height: var(--lh-relaxed);
  color: var(--fg-muted);
  overflow-wrap: anywhere;
}

/* ---- MCP pane ----------------------------------------------------------- */
/* A copyable block: mono text plus a copy button that must not be pushed out
   of the pane by a long path, so the text scrolls and the button is fixed. */
.mcp-copy {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  margin-top: var(--sp-5);
  min-width: 0;
}

.mcp-copy__head {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  min-width: 0;
}

.mcp-copy__label {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--fs-2xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--fg-subtle);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mcp-copy__pre {
  margin: 0;
  padding: var(--sp-5);
  max-height: 260px;
  max-width: 100%;
  overflow: auto;
  background: var(--bg-sunken);
  border: var(--bw-thin) solid var(--border);
  border-radius: var(--r-md);
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  line-height: var(--lh-relaxed);
  color: var(--fg-muted);
  white-space: pre;
  tab-size: 2;
}

/* One-line commands wrap rather than scroll: a shell command you cannot see the
   end of is a command you will paste wrong. */
.mcp-copy__pre--wrap {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.mcp-path {
  font-family: var(--font-mono);
  font-size: var(--fs-2xs);
  color: var(--fg-subtle);
  overflow-wrap: anywhere;
}

/* Tool-group and safety tables. `table-layout:fixed` + `min-width:0` on the
   cells is what stops a long env-var name widening the table past the pane and
   creating a document-level scrollbar. */
.mcp-table {
  width: 100%;
  max-width: 100%;
  margin-top: var(--sp-5);
  border-collapse: collapse;
  table-layout: fixed;
  font-size: var(--fs-2xs);
}

.mcp-table th,
.mcp-table td {
  padding: var(--sp-4) var(--sp-4);
  text-align: left;
  vertical-align: top;
  border-bottom: var(--bw-thin) solid var(--border-subtle);
  line-height: var(--lh-relaxed);
  overflow-wrap: anywhere;
  min-width: 0;
}

.mcp-table th {
  font-size: var(--fs-3xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
  color: var(--fg-subtle);
  white-space: nowrap;
}

.mcp-table td:first-child {
  font-weight: var(--fw-medium);
  color: var(--fg-strong);
}

.mcp-table code {
  font-family: var(--font-mono);
  font-size: var(--fs-3xs);
  overflow-wrap: anywhere;
}

/* The generated secret. Shown exactly once, so it is visually loud and the
   text is selectable mono at a size you can transcribe if the clipboard is
   blocked by the browser's permission policy. */
.mcp-secret {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  margin-top: var(--sp-5);
  padding: var(--sp-6);
  background: var(--success-subtle, var(--bg-inset));
  border: var(--bw-thin) solid var(--success);
  border-radius: var(--r-md);
  min-width: 0;
}

.mcp-secret__value {
  padding: var(--sp-4) var(--sp-5);
  background: var(--bg-sunken);
  border-radius: var(--r-sm);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  color: var(--fg-strong);
  user-select: all;
  overflow-wrap: anywhere;
}

.mcp-secret__warn {
  font-size: var(--fs-2xs);
  line-height: var(--lh-relaxed);
  color: var(--fg-muted);
}

/* Narrow viewports: the settings sheet is nearly full-bleed at 390px, so the
   tables drop to a stacked reading order rather than clipping a column. */
@media (max-width: 560px) {
  .mcp-table,
  .mcp-table tbody,
  .mcp-table tr,
  .mcp-table td {
    display: block;
    width: 100%;
  }

  .mcp-table thead {
    display: none;
  }

  .mcp-table tr {
    padding: var(--sp-4) 0;
    border-bottom: var(--bw-thin) solid var(--border-subtle);
  }

  .mcp-table td {
    border: 0;
    padding: var(--sp-1) 0;
  }
}
