/* Prompt: app styles. Proton Mail "Ebony"-inspired dark theme — deep ebony
   backgrounds with a violet primary accent, subtle borders, and tighter
   spacing. Overrides Bootstrap dark theme tokens to recolor the whole UI.
   Mail shell uses a 2-column layout: vertical mailboxes sidebar on the left,
   then the main pane (toolbar + message list + detail). Includes dirty-track
   input highlight and htmx indicator helper. */

:root[data-bs-theme="dark"] {
    /* Ebony palette — deep but breathing, faint violet undertone */
    --eb-bg:           #1A1824;
    --eb-bg-elevated:  #22202E;
    --eb-bg-sidebar:   #1E1C28;
    --eb-bg-hover:     #322F41;
    --eb-bg-active:    rgba(141, 116, 246, 0.18);

    --eb-border:        rgba(255, 255, 255, 0.08);
    --eb-border-strong: rgba(255, 255, 255, 0.14);

    --eb-text:        #FFFFFF;
    --eb-text-muted:  #C8C4D6;
    --eb-text-faint:  #8B869C;

    /* Proton signature violet — slightly deeper to read on black */
    --eb-primary:        #7C5CFF;
    --eb-primary-hover:  #9982FF;
    --eb-primary-soft:   rgba(124, 92, 255, 0.16);
    --eb-primary-glow:   rgba(124, 92, 255, 0.35);
    --eb-primary-faint:  rgba(141, 116, 246, 0.08);

    --eb-success:        #59B97C;
    --eb-warning:        #E5B33C;
    --eb-danger:         #E26D6D;
    --eb-info:           #6BB8E5;

    /* File-type accents — quiet, desaturated tints used only on attachment
       icons so a file's type reads at a glance without shouting. */
    --eb-file-pdf:    #E28C8C;
    --eb-file-image:  #5FC0A4;
    --eb-file-doc:    #6BB2E5;
    --eb-file-sheet:  #7CC069;
    --eb-file-slides: #E3B45C;
    --eb-file-media:  #BBA6E6;
    --eb-file-text:   #98A7BC;

    --eb-radius:         10px;
    --eb-radius-sm:      6px;

    /* Bootstrap variable overrides */
    --bs-body-bg:           var(--eb-bg);
    --bs-body-color:        var(--eb-text);
    --bs-body-secondary-bg: var(--eb-bg-elevated);
    --bs-body-tertiary-bg:  var(--eb-bg-sidebar);
    --bs-secondary-color:   var(--eb-text-muted);
    --bs-tertiary-color:    var(--eb-text-faint);
    --bs-border-color:           var(--eb-border-strong);
    --bs-border-color-translucent: var(--eb-border);
    --bs-link-color:        var(--eb-primary-hover);
    --bs-link-hover-color:  var(--eb-primary);
    --bs-primary:           var(--eb-primary);
    --bs-primary-rgb:       141, 116, 246;
}

/* ----- Blue theme override ----- */
:root[data-bs-theme="dark"][data-theme="blue"] {
    --eb-bg:           #10141C;
    --eb-bg-elevated:  #161B25;
    --eb-bg-sidebar:   #131720;
    --eb-bg-hover:     #222733;
    --eb-bg-active:    rgba(0, 115, 255, 0.18);

    --eb-text:        #FFFFFF;
    --eb-text-muted:  #D0D6E3;
    --eb-text-faint:  #9BA2AE;

    --eb-primary:        rgb(0, 115, 255);
    --eb-primary-hover:  #3B91FF;
    --eb-primary-soft:   rgba(0, 115, 255, 0.16);
    --eb-primary-glow:   rgba(0, 115, 255, 0.35);
    --eb-primary-faint:  rgba(0, 115, 255, 0.09);

    --eb-info:           #5AB0F0;

    --bs-primary-rgb:    0, 115, 255;
}

/* ----- OLED theme override ----- */
:root[data-bs-theme="dark"][data-theme="oled"] {
    --eb-bg:           #000000;
    --eb-bg-elevated:  #0C0A12;
    --eb-bg-sidebar:   #000000;
    --eb-bg-hover:     #1C1A26;
    --eb-bg-active:    rgba(124, 92, 255, 0.20);

    --eb-border:        rgba(255, 255, 255, 0.10);
    --eb-border-strong: rgba(255, 255, 255, 0.18);
}

body {
    background: var(--eb-bg);
    color: var(--eb-text);
    font-family: -apple-system, BlinkMacSystemFont, "Inter", "Segoe UI", Roboto,
        "Helvetica Neue", Arial, sans-serif;
    font-size: 14px;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* ----- Navbar / top bar ----- */

.navbar.bg-body-tertiary {
    background-color: var(--eb-bg-sidebar) !important;
    border-bottom: 1px solid var(--eb-border) !important;
    backdrop-filter: blur(8px);
}

.navbar-brand {
    color: var(--eb-primary) !important;
    font-weight: 600;
    letter-spacing: .2px;
    display: inline-flex;
    align-items: center;
    gap: .4rem;
}

.navbar .nav-link {
    color: var(--eb-text-muted) !important;
    border-radius: var(--eb-radius-sm);
    padding: .35rem .75rem !important;
    transition: background-color .15s, color .15s;
    display: inline-flex;
    align-items: center;
    gap: .4rem;
}

.navbar .nav-link:hover {
    background-color: var(--eb-bg-hover);
    color: var(--eb-text) !important;
}

.navbar .nav-link.active {
    background-color: var(--eb-primary-soft);
    color: var(--eb-primary-hover) !important;
}

/* ----- Buttons ----- */

.btn {
    border-radius: var(--eb-radius-sm);
    font-weight: 500;
    padding: .35rem .75rem;
    transition: background-color .15s, border-color .15s, color .15s;
    display: inline-flex;
    align-items: center;
    gap: .35rem;
}

.btn-sm {
    padding: .25rem .55rem;
    font-size: .8125rem;
}

.btn-primary {
    background-image: linear-gradient(180deg, var(--eb-primary-hover) 0%, var(--eb-primary) 100%);
    background-color: var(--eb-primary);
    border-color: var(--eb-primary);
    color: #fff;
}
.btn-primary:hover, .btn-primary:focus {
    background-image: linear-gradient(180deg, var(--eb-primary-hover) 0%, var(--eb-primary-hover) 100%);
    background-color: var(--eb-primary-hover);
    border-color: var(--eb-primary-hover);
    color: #fff;
}

.btn-success {
    background-image: linear-gradient(180deg, #6cc18a 0%, var(--eb-success) 100%);
}
.btn-warning {
    background-image: linear-gradient(180deg, #efc14d 0%, var(--eb-warning) 100%);
}
.btn-danger {
    background-image: linear-gradient(180deg, #ea8585 0%, var(--eb-danger) 100%);
}

.btn-outline-secondary {
    color: var(--eb-text-muted);
    border-color: var(--eb-border-strong);
    background: transparent;
}
.btn-outline-secondary:hover, .btn-outline-secondary:focus {
    background-color: var(--eb-bg-hover);
    border-color: var(--eb-border-strong);
    color: var(--eb-text);
}

.btn-secondary {
    background: var(--eb-bg-hover);
    border-color: var(--eb-border-strong);
    color: var(--eb-text);
}
.btn-secondary:hover {
    background: var(--eb-bg-elevated);
    border-color: var(--eb-border-strong);
    color: var(--eb-text);
}

.btn-outline-light {
    color: var(--eb-text);
    border-color: var(--eb-border-strong);
}
.btn-outline-light:hover {
    background-color: var(--eb-bg-hover);
    color: var(--eb-text);
    border-color: var(--eb-border-strong);
}

.btn-success { background-color: var(--eb-success); border-color: var(--eb-success); }
.btn-success:hover { background-color: #6cc18a; border-color: #6cc18a; }
.btn-warning { background-color: var(--eb-warning); border-color: var(--eb-warning); color: #1a1500; }
.btn-warning:hover { background-color: #efc14d; border-color: #efc14d; color: #1a1500; }
.btn-danger { background-color: var(--eb-danger); border-color: var(--eb-danger); }

.btn-outline-info     { color: var(--eb-info);    border-color: rgba(107, 184, 229, 0.4); }
.btn-outline-info:hover { background-color: rgba(107, 184, 229, 0.12); color: var(--eb-info); }
.btn-outline-success  { color: var(--eb-success); border-color: rgba(89, 185, 124, 0.4); }
.btn-outline-success:hover { background-color: rgba(89, 185, 124, 0.12); color: var(--eb-success); }
.btn-outline-warning  { color: var(--eb-warning); border-color: rgba(229, 179, 60, 0.4); }
.btn-outline-warning:hover { background-color: rgba(229, 179, 60, 0.12); color: var(--eb-warning); }
.btn-outline-danger   { color: var(--eb-danger);  border-color: rgba(226, 109, 109, 0.4); }
.btn-outline-danger:hover { background-color: rgba(226, 109, 109, 0.12); color: var(--eb-danger); }

.btn-warning.active,
.btn-warning:focus {
    box-shadow: 0 0 0 0.2rem rgba(229, 179, 60, 0.25);
}

/* ----- Forms ----- */

.form-control,
.form-select {
    background-color: var(--eb-bg-elevated);
    border: 1px solid var(--eb-border-strong);
    color: var(--eb-text);
    border-radius: var(--eb-radius-sm);
}
.form-control:focus,
.form-select:focus {
    background-color: var(--eb-bg-elevated);
    border-color: var(--eb-primary);
    color: var(--eb-text);
    box-shadow: 0 0 0 0.2rem var(--eb-primary-soft);
}
.form-control::placeholder { color: var(--eb-text-faint); }

.input-group-text {
    background-color: var(--eb-bg-elevated);
    border: 1px solid var(--eb-border-strong);
    color: var(--eb-text-muted);
}

.form-check-input {
    background-color: var(--eb-bg-elevated);
    border-color: var(--eb-border-strong);
}
.form-check-input:checked {
    background-color: var(--eb-primary);
    border-color: var(--eb-primary);
}
.form-check-input:focus { box-shadow: 0 0 0 0.2rem var(--eb-primary-soft); }

input.is-dirty,
select.is-dirty,
textarea.is-dirty,
.form-check-input.is-dirty {
    border-color: var(--eb-warning) !important;
    box-shadow: 0 0 0 0.2rem rgba(229, 179, 60, 0.18) !important;
}

/* ----- Cards ----- */

.card {
    background-color: var(--eb-bg-elevated);
    border: 1px solid var(--eb-border);
    border-radius: var(--eb-radius);
}
.card.bg-body-tertiary { background-color: var(--eb-bg-elevated) !important; }

/* ----- Tables ----- */

.table {
    --bs-table-bg: transparent;
    --bs-table-color: var(--eb-text);
    --bs-table-border-color: var(--eb-border);
    --bs-table-hover-bg: var(--eb-bg-hover);
    --bs-table-hover-color: var(--eb-text);
    --bs-table-striped-bg: rgba(255, 255, 255, 0.02);
    --bs-table-active-bg: var(--eb-primary-soft);
    --bs-table-active-color: var(--eb-text);
    color: var(--eb-text);
}
.table.table-dark {
    --bs-table-bg: transparent;
    --bs-table-color: var(--eb-text);
    --bs-table-border-color: var(--eb-border);
    --bs-table-hover-bg: var(--eb-bg-hover);
    background-color: transparent;
}
.table > :not(caption) > * > * {
    background-color: transparent;
    color: inherit;
    border-bottom-color: var(--eb-border);
}
.table thead th {
    color: var(--eb-text-muted);
    font-weight: 500;
    font-size: .78rem;
    text-transform: uppercase;
    letter-spacing: .04em;
    border-bottom-color: var(--eb-border-strong);
}

/* ----- Badges ----- */

.badge {
    font-weight: 500;
    border-radius: 999px;
    padding: .25em .55em;
    letter-spacing: .01em;
}
.badge.bg-primary {
    background-color: var(--eb-primary-soft) !important;
    color: var(--eb-primary-hover) !important;
    border: 1px solid var(--eb-primary-soft);
}
.badge.bg-secondary {
    background-color: var(--eb-bg-hover) !important;
    color: var(--eb-text-muted);
}
.badge.bg-info-subtle {
    background-color: rgba(107, 184, 229, 0.14) !important;
    color: var(--eb-info) !important;
    border-color: rgba(107, 184, 229, 0.3) !important;
}
.badge.bg-danger { background-color: var(--eb-danger) !important; }

/* ----- Modals ----- */

.modal-content {
    background-color: var(--eb-bg-elevated);
    border: 1px solid var(--eb-border-strong);
    border-radius: var(--eb-radius);
}
.modal-header, .modal-footer {
    border-color: var(--eb-border);
}

/* Compose modal sized to 90% of the viewport so the editor has room to breathe.
   Bootstrap's .modal-dialog has its own responsive max-widths (e.g. .modal-xl
   maxes at 1140px), so we override with !important to win the cascade at all
   viewport sizes. */
#composeModal .modal-dialog {
    max-width: 90vw !important;
    width: 90vw !important;
    height: 90vh;
    margin: 5vh auto;
}
#composeModal .modal-content {
    height: 100%;
    display: flex;
    flex-direction: column;
}
#composeModal .modal-body {
    overflow-y: auto;
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
}
#composeModal #composeModalBody {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}
#composeModal .compose-form {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}
#composeModal .compose-form .compose-editor-card {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-height: 0;
}
#composeModal .compose-form .compose-editor-card .compose-toolbar {
    flex: 0 0 auto;
}
#composeModal .compose-form .compose-editor {
    flex: 1 1 auto;
    min-height: 0;
    max-height: none;
}

/* Minimized drafts rendered as a tree-view nested beneath the Drafts mailbox
   row. .local-draft-tree is the parent container that draws the vertical
   "trunk" (a left border). Each .local-draft-row uses ::before to render the
   horizontal elbow connector into that trunk so the rows visually hang off
   it like a file-tree. */
.local-draft-tree {
    position: relative;
    margin: .15rem 0 .25rem 1.1rem;
    padding-left: .85rem;
    border-left: 1px solid var(--eb-border-strong);
}
.local-draft-row {
    position: relative;
    display: flex;
    align-items: center;
    padding: .15rem .15rem .15rem .55rem;
    margin: .1rem 0;
    font-size: .8rem;
    color: var(--eb-text-muted);
    border-radius: var(--eb-radius-sm);
}
.local-draft-row::before {
    /* Elbow connector: a short horizontal line from the trunk to the row. */
    content: "";
    position: absolute;
    left: -0.85rem;
    top: 50%;
    width: .8rem;
    height: 0;
    border-top: 1px solid var(--eb-border-strong);
}
.local-draft-row:hover {
    background: var(--eb-bg-hover);
}
.local-draft-link {
    color: var(--eb-text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.local-draft-row:hover .local-draft-link {
    color: var(--eb-text);
}
.local-draft-discard {
    margin-left: .35rem;
    padding: 0 .25rem;
    color: var(--eb-text-faint);
    cursor: pointer;
    flex-shrink: 0;
}
.local-draft-discard:hover {
    color: var(--eb-danger);
}

/* ----- Text colors ----- */

.text-secondary { color: var(--eb-text-muted) !important; }
.link-light { color: var(--eb-text) !important; }
.link-light:hover { color: var(--eb-primary-hover) !important; }
code {
    color: var(--eb-primary-hover);
    background-color: var(--eb-primary-faint);
    padding: .1em .35em;
    border-radius: 4px;
    font-size: .85em;
}

/* ----- HTMX indicator ----- */

.htmx-indicator { display: none; }
.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator { display: inline-block; }
.htmx-request .htmx-indicator-hide { display: none; }

/* ----- Mail layout ----- */

.mail-shell {
    display: grid;
    grid-template-columns: minmax(220px, 260px) 1fr;
    height: calc(100vh - 56px - 1.5rem);
    overflow: hidden;
    gap: 0;
    border-radius: var(--eb-radius);
    border: 1px solid var(--eb-border);
    background: var(--eb-bg-elevated);
}

.mail-shell.mailboxes-collapsed {
    grid-template-columns: 1fr;
}

.mail-shell.mailboxes-collapsed > .mail-mailboxes-bar {
    display: none !important;
}

.mail-mailboxes-bar {
    background: var(--eb-bg-sidebar);
    overflow-y: auto;
    min-height: 0;
    scrollbar-width: thin;
    border-right: 1px solid var(--eb-border) !important;
    padding: .75rem !important;
}

.mail-mailboxes-bar .text-uppercase {
    color: var(--eb-text-faint) !important;
    font-size: .7rem !important;
    letter-spacing: .08em;
    font-weight: 600;
    padding: 0 .25rem;
}

/* Mailbox links — Proton-style flat rows with rounded selection */
.mail-mailboxes-bar .btn {
    background: transparent;
    border: 0;
    border-radius: var(--eb-radius-sm);
    padding: .4rem .6rem;
    font-size: .85rem;
    color: var(--eb-text-muted);
    text-align: left;
    justify-content: flex-start;
    line-height: 1.25;
}
.mail-mailboxes-bar .btn:hover {
    background: var(--eb-bg-hover);
    color: var(--eb-text);
}
.mail-mailboxes-bar .btn.btn-primary {
    background: var(--eb-primary-soft);
    color: var(--eb-primary-hover);
    border: 0;
    font-weight: 500;
}
.mail-mailboxes-bar .btn.btn-primary:hover {
    background: var(--eb-primary-soft);
    color: var(--eb-primary-hover);
}
.mail-mailboxes-bar .btn small.text-secondary {
    color: var(--eb-text-faint) !important;
    font-size: .68rem;
    letter-spacing: 0;
}
.mail-mailboxes-bar .badge.bg-primary {
    background: var(--eb-primary-soft) !important;
    color: var(--eb-primary-hover) !important;
    font-size: .68rem;
    padding: .2em .5em;
}
.mailbox-link i {
    color: var(--eb-text-faint);
    font-size: 1rem;
    width: 1.1rem;
    text-align: center;
    flex-shrink: 0;
}
.mail-mailboxes-bar .btn.btn-primary .mailbox-link-icon,
.mail-mailboxes-bar .btn.btn-primary i {
    color: var(--eb-primary-hover);
}

.mail-main {
    display: grid;
    --split-pct: 40;
    grid-template-rows:
        auto auto auto
        minmax(0, calc(var(--split-pct) * 1%))
        auto
        minmax(0, calc((100 - var(--split-pct)) * 1%));
    overflow: hidden;
    min-width: 0;
    background: var(--eb-bg);
}

.mail-splitter {
    height: 6px;
    cursor: row-resize;
    background: transparent;
    border-top: 1px solid var(--eb-border);
    border-bottom: 1px solid var(--eb-border);
}
.mail-splitter:hover,
.mail-splitter:focus-visible {
    background: var(--eb-border);
    outline: none;
}

@media (max-width: 767.98px) {
    .mail-splitter { display: none; }
}

.mail-toolbar {
    background: var(--eb-bg-sidebar);
    border-bottom: 1px solid var(--eb-border) !important;
    padding: .6rem .75rem !important;
}

.mail-list-pane,
.mail-detail-pane {
    overflow-y: auto;
    overflow-x: hidden;
    min-height: 0;
    min-width: 0;
}

.mail-list-pane:focus,
.mail-list-pane:focus-visible {
    outline: none;
}

.message-table { table-layout: fixed; width: 100%; }
.message-table td { word-break: break-word; }
.message-table > tbody > tr > td { border-bottom: 1px solid var(--eb-border); }

.message-table .message-checkbox-col { width: 38px; }
.message-checkbox-cell {
    width: 38px;
    padding: .55rem .35rem .55rem .9rem;
    vertical-align: middle;
    text-align: center;
}
.message-checkbox { cursor: pointer; }

.message-table .message-direction-col { width: 22px; }
.message-direction-cell {
    width: 22px;
    padding: .55rem 0;
    vertical-align: middle;
    text-align: center;
    line-height: 1;
}
.message-direction-icon {
    font-size: .9rem;
    color: var(--eb-text-faint);
}
.message-direction-sent { color: var(--eb-primary, #0d6efd); }
.message-direction-received { color: var(--eb-text-faint); }

.message-table .message-toggle-col { width: 26px; }
.message-toggle-cell {
    width: 26px;
    padding: .55rem 0 .55rem .15rem;
    vertical-align: middle;
    text-align: right;
}
.message-row > .message-row-cell { padding-left: .35rem; }
.message-toggle-seen-btn {
    color: var(--bs-secondary-color, #adb5bd);
    text-decoration: none;
    line-height: 1;
    width: 22px;
    height: 22px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.message-toggle-seen-btn:hover { color: var(--bs-primary, #0d6efd); }
tr.message-row.unread .message-toggle-seen-btn { color: var(--bs-primary, #0d6efd); }
/* htmx adds .htmx-request to the trigger during in-flight requests — swap the
   envelope icon for a spinner so the user sees the toggle is working. */
.message-toggle-seen-btn .toggle-spinner { display: none; }
.message-toggle-seen-btn.htmx-request .bi { display: none; }
.message-toggle-seen-btn.htmx-request .toggle-spinner { display: inline-block; }
.message-detail-actions .toggle-spinner { display: none; }
.message-detail-actions .btn.htmx-request .bi { display: none; }
.message-detail-actions .btn.htmx-request .toggle-spinner { display: inline-block; }

/* Bulk-action toolbar (above the message list when a row is selected). */
.mail-bulk-toolbar {
    background: var(--eb-bg-elevated);
    border-color: var(--eb-border) !important;
    min-height: 0;
    font-size: .8rem;
}
.mail-bulk-toolbar .btn-sm {
    padding: .15rem .5rem;
    font-size: .78rem;
}
.mail-bulk-toolbar .form-check-input {
    width: .85rem;
    height: .85rem;
}
.mail-bulk-toolbar .vr {
    align-self: stretch;
    color: var(--eb-border-strong);
}

.mail-detail-pane {
    border-top: 1px solid var(--eb-border-strong);
    background: var(--eb-bg-elevated);
}

/* ----- Message rows ----- */

.message-row {
    cursor: pointer;
    color: #D7D3E5;
    font-weight: 400;
    transition: background-color .12s;
}
.message-row:hover { background-color: var(--eb-bg-hover); }
.message-row.unread { color: #FFFFFF; }
.message-row.unread .message-from { font-weight: 600; color: #FFFFFF; }
.message-row.unread .message-subject { font-weight: 600; color: var(--eb-primary-hover); }

.message-row.table-active,
.message-row.table-active:hover {
    background-color: var(--eb-primary-soft) !important;
    color: var(--eb-text) !important;
    box-shadow: inset 3px 0 0 var(--eb-primary);
}

.message-row-cell { padding: .55rem .9rem; }
.message-from { max-width: 60%; }
.message-subject { max-width: 90%; }
/* Retained for the filter-results preview (app/views/filters/results_rows.html),
   which still uses .message-snippet. The message list no longer renders it. */
.message-snippet {
    font-size: .78rem;
    color: var(--eb-text-faint) !important;
}
.message-attach-icon {
    flex-shrink: 0;
    color: var(--eb-text-faint);
}
/* Duplicate-account chips on a collapsed All-mail row. Restrained neutral
   treatment — the violet accent is reserved for actions/selection. */
.message-account-badge {
    font-size: .66rem;
    font-weight: 600;
    line-height: 1;
    letter-spacing: .02em;
    padding: .12rem .4rem;
    border-radius: 999px;
    background: var(--eb-bg-hover);
    color: var(--eb-text-muted);
    border: 1px solid var(--eb-border);
    text-transform: lowercase;
    white-space: nowrap;
}
.message-date { font-size: .72rem; color: var(--eb-text-faint) !important; }

/* ----- Message detail ----- */

.message-html-frame {
    width: 100%;
    min-height: 50vh;
    background: #fff;
    border: 0;
    border-radius: var(--eb-radius-sm);
    display: block;
    overflow: hidden;
}

.message-text {
    white-space: pre-wrap;
    word-wrap: break-word;
    color: var(--eb-text);
    background: transparent;
}

.message-detail-card { color: var(--eb-text); }
.message-detail-subject { color: var(--eb-text); font-weight: 600; }
.message-detail-from { font-weight: 600; color: var(--eb-text); }
.message-detail-meta i { color: var(--eb-text-faint); }

/* ----- Attachments ----- */

.attachments-head {
    display: flex;
    align-items: center;
    gap: .4rem;
    margin-bottom: .5rem;
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--eb-text-faint);
}
.attachments-head .attachments-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.2rem;
    height: 1.2rem;
    padding: 0 .35rem;
    border-radius: 999px;
    background: var(--eb-bg-elevated);
    border: 1px solid var(--eb-border);
    color: var(--eb-text-muted);
    font-size: .68rem;
    letter-spacing: 0;
}

/* Content-hugging chips (sorted server-side by file type then name). Each chip
   is a self-contained clickable surface: type-tinted icon, name, muted size sat
   right beside it — so there are no whitespace rivers and the region reads as a
   real component. Chips wrap and pack densely without eating the viewport. */
.attachment-chips {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
}
.attachment-chip {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    max-width: 100%;
    padding: .35rem .6rem;
    background: var(--eb-bg-elevated);
    border: 1px solid var(--eb-border);
    border-radius: 8px;
    color: var(--eb-text-muted);
    text-decoration: none;
    line-height: 1.2;
    transition: border-color .15s ease, background-color .15s ease,
                transform .15s ease, box-shadow .15s ease;
}
.attachment-chip:hover,
.attachment-chip:focus-visible {
    background: var(--eb-bg-hover);
    border-color: var(--eb-primary);
    color: var(--eb-text);
    transform: translateY(-1px);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.28);
    outline: none;
}
.attachment-chip-icon {
    flex: 0 0 auto;
    display: inline-flex;
    font-size: 1.05rem;
    color: var(--eb-text-faint);
}
/* Type tint — the only colour, a quiet signal of the file's kind. */
.attachment-chip-icon .bi-file-earmark-pdf { color: var(--eb-file-pdf); }
.attachment-chip-icon .bi-file-earmark-image { color: var(--eb-file-image); }
.attachment-chip-icon .bi-file-earmark-word { color: var(--eb-file-doc); }
.attachment-chip-icon .bi-file-earmark-spreadsheet { color: var(--eb-file-sheet); }
.attachment-chip-icon .bi-file-earmark-slides { color: var(--eb-file-slides); }
.attachment-chip-icon .bi-file-earmark-zip,
.attachment-chip-icon .bi-file-earmark-music,
.attachment-chip-icon .bi-file-earmark-play { color: var(--eb-file-media); }
.attachment-chip-icon .bi-file-earmark-text,
.attachment-chip-icon .bi-file-earmark-code { color: var(--eb-file-text); }
.attachment-chip-name {
    min-width: 0;
    max-width: 20rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 500;
}
.attachment-chip-size {
    flex: 0 0 auto;
    color: var(--eb-text-faint);
    font-size: .78rem;
    font-variant-numeric: tabular-nums;
}
@media (prefers-reduced-motion: reduce) {
    .attachment-chip { transition: border-color .15s ease, background-color .15s ease; }
    .attachment-chip:hover,
    .attachment-chip:focus-visible { transform: none; box-shadow: none; }
}

/* ----- Mailbox order modal ----- */

.mailbox-order-list {
    border: 1px solid var(--eb-border);
    border-radius: var(--eb-radius);
    background: var(--eb-bg);
    padding: .25rem;
    max-height: 60vh;
    overflow-y: auto;
}
.mailbox-order-item {
    padding: .5rem .75rem;
    border-radius: var(--eb-radius-sm);
    background: var(--eb-bg-elevated);
    margin-bottom: .25rem;
    cursor: grab;
    user-select: none;
    border: 1px solid transparent;
    transition: border-color .12s, background-color .12s;
}
.mailbox-order-item:last-child { margin-bottom: 0; }
.mailbox-order-item:hover { background: var(--eb-bg-hover); }
.mailbox-order-item:active,
.mailbox-order-item.is-dragging {
    cursor: grabbing;
    opacity: .55;
}
.mailbox-order-item.is-drop-target {
    border-color: var(--eb-primary);
    background: var(--eb-primary-soft);
}
.mailbox-order-grip {
    color: var(--eb-text-faint);
    font-size: 1.1rem;
    cursor: grab;
}

.mailbox-order-cog {
    padding: .15rem .35rem;
    border: 0;
    background: transparent;
    color: var(--eb-text-faint);
}
.mailbox-order-cog:hover {
    background: var(--eb-bg-hover);
    color: var(--eb-text);
    border-color: transparent;
}

/* ----- Scrollbars (webkit) ----- */

.mail-mailboxes-bar::-webkit-scrollbar,
.mail-list-pane::-webkit-scrollbar,
.mail-detail-pane::-webkit-scrollbar { width: 8px; height: 8px; }
.mail-mailboxes-bar::-webkit-scrollbar-thumb,
.mail-list-pane::-webkit-scrollbar-thumb,
.mail-detail-pane::-webkit-scrollbar-thumb {
    background: var(--eb-border-strong);
    border-radius: 4px;
}
.mail-mailboxes-bar::-webkit-scrollbar-thumb:hover,
.mail-list-pane::-webkit-scrollbar-thumb:hover,
.mail-detail-pane::-webkit-scrollbar-thumb:hover {
    background: var(--eb-text-faint);
}

/* ----- Mobile (<768px) -----
   Drawer + stack pattern:
   - Shell collapses to one full-width column.
   - Mailboxes become an off-canvas drawer toggled by .mobile-show-drawer.
   - Detail pane covers the list pane when .mobile-show-detail is set.
   - Bulk-select and the Compose toolbar button are hidden.
   - A FAB replaces the toolbar Compose button.
   - Top navbar's non-mail tabs are hidden (re-exposed in the settings modal). */

/* FAB lives outside the media query so the markup is harmless on desktop
   (hidden via .d-md-none on the element itself). */
.mail-compose-fab {
    position: fixed;
    right: 1rem;
    bottom: 1rem;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    z-index: 1040;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 1.4rem;
    box-shadow: 0 8px 24px rgba(0,0,0,.5), 0 0 0 1px rgba(255,255,255,.04);
}
.mail-compose-fab i { margin: 0; }

/* Scrim element sits between drawer and content; activated by .mobile-show-drawer */
.mobile-drawer-scrim {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    z-index: 1045;
}

@media (max-width: 767.98px) {
    /* Page chrome: tighter container so content reaches the edges. */
    main.container-fluid { padding: 0 !important; }
    .navbar.bg-body-tertiary { padding-left: .5rem; padding-right: .5rem; }
    .navbar .nav-link { padding: .35rem .55rem !important; }
    .navbar .nav-link .nav-link-label { display: none; }
    .activity-indicator { padding: .15rem .5rem; }
    .activity-indicator .activity-count { min-width: .9em; }

    /* Shell: single column, full viewport height. The list pane is the
       scroll container so the infinite-scroll script keeps working.
       Use flexbox so the toolbar + filter rows sit above a single
       flex-1 scrollable list pane. */
    .mail-shell {
        display: block;
        height: calc(100vh - 48px);
        overflow: hidden;
        border: 0;
        border-radius: 0;
        background: var(--eb-bg);
        position: relative;
    }
    .mail-main {
        display: flex;
        flex-direction: column;
        height: 100%;
        grid-template-rows: none;
    }
    .mail-main > .mail-toolbar,
    .mail-main > #filtersBar,
    .mail-main > #searchHelpPanel {
        flex: 0 0 auto;
    }

    /* Mailboxes as off-canvas drawer. Slides in from the left, fixed full
       height, transform-based so it animates and doesn't reflow content. */
    .mail-mailboxes-bar {
        position: fixed;
        top: 48px;
        left: 0;
        bottom: 0;
        width: 84vw;
        max-width: 320px;
        z-index: 1050;
        transform: translateX(-100%);
        transition: transform .22s ease;
        border-right: 1px solid var(--eb-border-strong) !important;
        border-bottom: 0 !important;
        overflow-y: auto;
        background: var(--eb-bg-sidebar);
    }
    .mail-shell.mobile-show-drawer .mail-mailboxes-bar {
        transform: translateX(0);
    }
    .mail-shell.mobile-show-drawer .mobile-drawer-scrim {
        display: block;
    }

    /* List pane is the only flex-grow child, taking remaining space. */
    .mail-list-pane {
        flex: 1 1 auto;
        min-height: 0;
        overflow-y: auto;
        overflow-x: hidden;
    }

    /* Detail pane covers the whole shell when .mobile-show-detail is set.
       Fixed-position so it sits on top of the toolbar + list at navbar height. */
    .mail-detail-pane {
        position: fixed;
        top: 48px;
        left: 0;
        right: 0;
        bottom: 0;
        background: var(--eb-bg-elevated);
        border-top: 0;
        overflow-y: auto;
        transform: translateX(100%);
        transition: transform .22s ease;
        z-index: 1040;
    }
    .mail-shell.mobile-show-detail .mail-detail-pane {
        transform: translateX(0);
    }
    /* Hide the FAB while reading a message — its compose icon would be
       visually confusable with reply, and the detail view has its own
       reply/forward buttons. */
    .mail-shell.mobile-show-detail ~ .mail-compose-fab {
        display: none !important;
    }

    /* Toolbar reflow: search input on its own row. */
    .mail-toolbar {
        padding: .5rem .5rem !important;
        gap: .35rem .5rem !important;
    }
    .mail-toolbar #mailFiltersForm {
        order: 10;
        flex: 1 0 100% !important;
    }
    .mail-toolbar #mailFiltersForm .input-group { width: 100%; }
    /* Hide the Compose button on mobile. */
    .mail-toolbar .btn-primary[onclick*="compose:open"] { display: none !important; }

    /* Hide folder count badge (folder name stays). */
    .mail-toolbar .badge.bg-secondary.rounded-pill { display: none; }

    /* Bulk toolbar + per-row checkbox column hidden on mobile. The hidden
       checkbox col still leaves a phantom gap under table-layout:fixed, so
       widen the main col to 100% to soak up the remaining row width. */
    .mail-bulk-toolbar { display: none !important; }
    .message-table .message-checkbox-col { width: 0 !important; display: none !important; }
    .message-checkbox-cell { display: none !important; }
    .message-table colgroup col:last-child { width: 100%; }
    .message-table .message-row-cell { width: 100%; }

    /* Larger touch targets on rows. */
    .message-row-cell {
        padding: .65rem .75rem;
        min-height: 56px;
    }
    .message-from { font-size: .95rem; max-width: 100%; }
    .message-subject { font-size: .92rem; max-width: 100%; }
    .message-snippet { font-size: .8rem; }
    .message-direction-cell { padding-left: .35rem; }
    .message-toggle-cell { padding-right: .35rem; }

    /* Mobile detail header — sticky back button at the top of the detail pane. */
    .mobile-detail-header {
        display: flex;
        align-items: center;
        gap: .5rem;
        position: sticky;
        top: 0;
        z-index: 2;
        padding: .5rem .75rem;
        background: var(--eb-bg-sidebar);
        border-bottom: 1px solid var(--eb-border);
    }
    .mobile-detail-header .mobile-back-btn {
        font-size: 1.1rem;
        padding: .3rem .5rem;
    }
    .mobile-detail-header .mobile-detail-subject {
        font-size: .9rem;
        font-weight: 500;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        flex: 1 1 auto;
        color: var(--eb-text);
    }

    /* Detail card padding tighter on phone. */
    .message-detail-card { padding: 1rem !important; }
    .message-detail-card h4 { font-size: 1.1rem; }
    .message-html-frame { min-height: 30vh; }

    /* Detail action buttons: show icon + label on mobile (matches desktop).
       Two equal-width groups stacked vertically, with each button flexing to
       share the row width so the labels remain readable. */
    .message-detail-actions { gap: .4rem !important; }
    .message-detail-actions .btn-group { width: 100%; }
    .message-detail-actions .btn-group.ms-auto { width: 100%; margin-left: 0 !important; }
    .message-detail-actions .btn-group .btn { flex: 1 1 0; }
    .message-detail-actions .btn {
        padding: .4rem .5rem;
        font-size: .8rem;
    }

    /* Compose modal: full-screen on phone. Wins the !important cascade. */
    #composeModal .modal-dialog {
        max-width: 100vw !important;
        width: 100vw !important;
        height: 100vh !important;
        margin: 0 !important;
    }
    #composeModal .modal-content {
        border-radius: 0;
        border: 0;
        height: 100vh;
    }
    #composeModal .modal-header { padding: .5rem .75rem; }
    .compose-form .compose-editor { max-height: none; }

    /* Filter panel rows: stack and widen value inputs. */
    .filter-row .filter-value { flex: 1 1 auto; width: auto !important; min-width: 0; }
    #filtersBar .filter-rows { gap: .4rem !important; }

    /* Drawer header inside the mailboxes bar — make the title row a closeable
       header so the user can dismiss the drawer when ready. */
    .mail-mailboxes-bar .mailbox-drawer-close {
        display: inline-flex !important;
    }

    /* ----- Swipe gestures on message rows (mobile only) ----- */

    /* The row becomes the positioning context so absolutely-positioned
       backdrop divs (injected on touchstart) cover the whole row. */
    .message-row.is-swipe-armed,
    .message-row.is-swiping,
    .message-row.is-swipe-pending { position: relative; }
    .message-row.is-swiping { overflow: hidden; }

    /* Cells translate as one. The opaque row background hides the backdrop
       until the user actually swipes. */
    .message-row.is-swiping > td,
    .message-row.is-swipe-confirming > td {
        transform: translateX(var(--swipe-dx, 0));
        background: var(--eb-bg);
        position: relative;
        z-index: 1;
    }
    .message-row.is-swipe-animating > td {
        transition: transform 190ms cubic-bezier(0.22, 1, 0.36, 1);
    }
    .message-row.is-swipe-confirming { position: relative; overflow: hidden; }

    /* Backdrops sit behind the cells, revealed as the row translates. */
    .message-swipe-backdrop {
        position: absolute;
        top: 0; bottom: 0;
        width: 100%;
        display: flex;
        align-items: center;
        padding: 0 1.1rem;
        color: #fff;
        font-size: 1.3rem;
        z-index: 0;
        pointer-events: none;
        opacity: 0;
    }
    /* Retoned to the --eb tokens so the swipe cue matches the queued-action
       palette (danger for trash, violet for read/unread) and tracks themes. */
    .message-swipe-backdrop.archive {
        right: 0;
        justify-content: flex-end;
        background: var(--eb-danger);
    }
    .message-swipe-backdrop.toggle-seen {
        left: 0;
        justify-content: flex-start;
        background: var(--eb-primary);
    }
    /* The icon rides in a soft circular chip that grows with the swipe
       (--swipe-progress, set by the gesture handler: 0 at rest, 1 at the
       commit threshold) and gains a ring once armed past that threshold —
       a calm, tactile "release to act" cue rather than a flat fade-in. */
    .message-swipe-backdrop i {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 2.5rem;
        height: 2.5rem;
        border-radius: 50%;
        background: rgba(0, 0, 0, 0.16);
        transform: scale(calc(0.8 + 0.24 * var(--swipe-progress, 0)));
        box-shadow: 0 0 0 0 rgba(255, 255, 255, 0);
        transition: box-shadow 160ms ease;
    }
    .message-row.is-swipe-armed .message-swipe-backdrop i {
        box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.20);
    }
    /* Only show the backdrop matching the active swipe direction — both
       overlap at full width, so without this the later-appended one would
       cover the other and the icon would never be visible. */
    .message-row[data-swipe-dir="left"].is-swiping .message-swipe-backdrop.archive,
    .message-row[data-swipe-dir="left"].is-swipe-confirming .message-swipe-backdrop.archive,
    .message-row[data-swipe-dir="right"].is-swiping .message-swipe-backdrop.toggle-seen { opacity: 1; }

    /* Confirm-mode buttons that replace the plain archive icon once the user
       releases past the threshold. They need pointer-events back on so taps
       reach them through the otherwise-non-interactive backdrop. */
    .message-swipe-confirm-actions {
        display: flex;
        gap: .5rem;
        pointer-events: auto;
    }
    .message-swipe-confirm-actions .btn {
        --bs-btn-padding-y: .35rem;
        --bs-btn-padding-x: .65rem;
        --bs-btn-font-size: 1rem;
        border: 1px solid rgba(255,255,255,.6);
        color: #fff;
        background: rgba(0,0,0,.18);
    }
    .message-swipe-confirm-actions .btn:hover,
    .message-swipe-confirm-actions .btn:focus { background: rgba(0,0,0,.32); color: #fff; }

    /* Pending state: while the action's HTMX request is in flight the row is
       dimmed, disabled, and shows a small spinner badge. */
    .message-row.is-swipe-pending { opacity: 0.5; pointer-events: none; }
    .message-row.is-swipe-pending::after {
        content: "";
        position: absolute;
        top: 50%;
        right: .9rem;
        width: 1rem;
        height: 1rem;
        margin-top: -.5rem;
        border: 2px solid currentColor;
        border-right-color: transparent;
        border-radius: 50%;
        animation: message-swipe-spin .75s linear infinite;
        z-index: 3;
    }
}

@keyframes message-swipe-spin { to { transform: rotate(360deg); } }

/* Hide the in-drawer close button on desktop (rendered by sidebar.html). */
.mail-mailboxes-bar .mailbox-drawer-close { display: none; }

/* Prompt: composer styles — modernized layout for the new compose form.
   Editor card has a subtle ebony surface with the toolbar across the top. */
.compose-form .compose-editor-card {
    background: var(--eb-bg-elevated);
    border: 1px solid var(--eb-border-strong);
    border-radius: var(--eb-radius);
    overflow: hidden;
}
.compose-form .compose-toolbar {
    background: var(--eb-bg-sidebar);
    border-bottom: 1px solid var(--eb-border) !important;
}
.compose-form .compose-toolbar .btn {
    --bs-btn-padding-x: .5rem;
    --bs-btn-padding-y: .25rem;
    --bs-btn-font-size: .875rem;
    border-color: transparent;
    color: var(--eb-text-muted);
}
.compose-form .compose-toolbar .btn:hover {
    background: var(--eb-bg-hover);
    color: var(--eb-text);
}
/* WYSIWYG: editor renders on a white surface with dark text so the author
   sees the message exactly as the recipient will. Color scheme is forced to
   light so any user-pasted CSS variables resolve against light defaults. */
.compose-form .compose-editor {
    min-height: 240px;
    max-height: 50vh;
    overflow-y: auto;
    padding: .75rem 1rem;
    color: #212529;
    background: #ffffff;
    color-scheme: light;
    outline: none;
    line-height: 1.45;
}
.compose-form .compose-editor:empty:before {
    content: attr(data-placeholder);
    color: #adb5bd;
}
.compose-form .compose-editor img { max-width: 100%; height: auto; }
.compose-form .compose-editor blockquote {
    border-left: 3px solid #ced4da;
    padding-left: .75em;
    color: #495057;
    margin: .5em 0;
}
.compose-form .compose-editor a { color: #0d6efd; }

/* Signature editor — same WYSIWYG light surface so authoring matches the
   email rendering. */
.signature-editor-card {
    border: 1px solid var(--eb-border-strong);
    border-radius: var(--eb-radius);
    overflow: hidden;
}
.signature-editor {
    min-height: 8em;
    padding: .75rem 1rem;
    color: #212529 !important;
    background: #ffffff !important;
    color-scheme: light;
    outline: none;
    line-height: 1.45;
    border: 0;
}
.signature-editor:empty:before {
    content: attr(data-placeholder);
    color: #adb5bd;
}
.signature-editor img { max-width: 100%; height: auto; }
.signature-editor a { color: #0d6efd; }
.signature-preview {
    color: #212529 !important;
    background: #ffffff;
    border: 1px solid #dee2e6;
    border-radius: .25rem;
    padding: .5rem .75rem;
    color-scheme: light;
}
.signature-preview a { color: #0d6efd; }

.compose-form .compose-recipients-row { position: relative; }
.compose-form .compose-autocomplete {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 1080;
}
.compose-form .compose-autocomplete-list {
    background: var(--eb-bg-elevated);
    border: 1px solid var(--eb-border-strong);
    border-radius: var(--eb-radius-sm);
    box-shadow: 0 8px 28px rgba(0,0,0,0.45);
    max-height: 220px;
    overflow-y: auto;
}
.compose-form .compose-autocomplete-item {
    padding: .35rem .75rem;
    cursor: pointer;
    color: var(--eb-text);
    border-bottom: 1px solid var(--eb-border);
}
.compose-form .compose-autocomplete-item:last-child { border-bottom: 0; }
.compose-form .compose-autocomplete-item:hover {
    background: var(--eb-bg-hover);
}

#composeAttachList .badge {
    background: var(--eb-bg-elevated);
    border: 1px solid var(--eb-border) !important;
    color: var(--eb-text-muted) !important;
    padding: .35rem .55rem;
    font-weight: 400;
}

/* Tighter spacing between leading icon and label inside compose input-group
   prefixes (From / To / Subject). */
.compose-form .input-group-text i.bi {
    margin-right: .4rem;
}

/* Compact compose modal header — narrower vertical padding and smaller title
   so reply/forward views feel tighter. */
#composeModal .modal-header {
    padding: .4rem .75rem;
}
#composeModal .modal-header .modal-title {
    font-size: .95rem;
    font-weight: 500;
}
#composeModal .modal-header .btn-sm,
#composeModal .modal-header .btn-close {
    padding: .15rem .35rem;
    font-size: .8rem;
}

/* Close-confirm popover anchored to the X button. */
#composeCloseConfirm {
    position: absolute;
    top: 100%;
    right: .5rem;
    margin-top: .25rem;
    background: var(--eb-bg-elevated);
    border: 1px solid var(--eb-border-strong);
    border-radius: var(--eb-radius-sm);
    box-shadow: 0 8px 28px rgba(0,0,0,0.45);
    padding: .5rem;
    z-index: 1090;
    display: none;
    min-width: 180px;
}
#composeCloseConfirm.show { display: block; }
#composeCloseConfirm .ccc-msg {
    color: var(--eb-text-muted);
    font-size: .8rem;
    margin-bottom: .4rem;
}
#composeCloseConfirm .ccc-actions {
    display: flex;
    gap: .35rem;
    justify-content: flex-end;
}

.message-detail-actions .btn { font-size: .825rem; }

.picker-table img { object-fit: cover; }

/* Saved filters list — readable per-condition rows */
.filter-conditions { line-height: 1.5; }
.filter-group {
    border-left: 2px solid rgba(255,255,255,.12);
    padding: .15rem 0 .15rem .6rem;
    margin: .1rem 0;
}
.filter-group-sep {
    margin: .25rem 0 .25rem .15rem;
}
.filter-condition {
    display: grid;
    grid-template-columns: 2.5rem 4.5rem auto 1fr;
    gap: .4rem;
    align-items: baseline;
    padding: .1rem 0;
}
.filter-cond-conn,
.filter-cond-conn-spacer {
    justify-self: start;
    font-size: .65rem;
}
.filter-cond-conn-spacer { display: inline-block; }
.filter-field {
    color: #9ec5fe;
    font-weight: 600;
    text-transform: lowercase;
}
.filter-op {
    color: var(--eb-text-muted, #adb5bd);
    font-style: italic;
    font-size: .85em;
}
.filter-value {
    color: #f8f9fa;
    background: rgba(255,255,255,.06);
    padding: 0 .35rem;
    border-radius: .2rem;
    word-break: break-word;
    min-width: 0;
    overflow-wrap: anywhere;
}

/* Saved filters — card layout on mobile. The table is unworkable on narrow
   viewports because the value column gets crushed and wraps letter-by-letter. */
@media (max-width: 767.98px) {
    .filter-list-table thead { display: none; }
    .filter-list-table,
    .filter-list-table tbody,
    .filter-list-table tr,
    .filter-list-table td {
        display: block;
        width: 100%;
    }
    .filter-list-table tr {
        border: 1px solid rgba(255,255,255,.12);
        border-radius: .5rem;
        padding: .65rem .75rem;
        margin-bottom: .65rem;
        background: rgba(255,255,255,.02);
    }
    .filter-list-table td {
        border: 0 !important;
        padding: .2rem 0;
        text-align: left !important;
    }
    .filter-cell-name { margin-bottom: .35rem; }
    .filter-cell-conditions { padding-top: .15rem !important; }
    .filter-cell-actions { text-align: left !important; margin-top: .55rem; }
    .filter-cell-actions .d-inline-flex { display: flex !important; justify-content: flex-start !important; }
    /* Icon-only action buttons on narrow screens to save horizontal space. */
    .filter-cell-actions .btn-action .btn-label { display: none; }
    .filter-cell-actions .btn-action { padding: .25rem .5rem; }
    /* Page header buttons: shrink to icons on mobile so they don't overflow. */
    .filters-page-header .btn-sm-icon .btn-label { display: none; }
    .filters-page-header .btn-sm-icon { padding: .375rem .55rem; }
    .filter-condition {
        display: flex;
        flex-wrap: wrap;
        gap: .25rem .4rem;
    }
    .filter-cond-conn-spacer { display: none; }
    .filter-value { flex: 1 1 8rem; }
    .filter-group { padding-left: .4rem; }
}

/* Pressed-state for the subject toggle uses the same warm warning treatment as
   the attachments/unread filter buttons so they look like one row of toggles. */
#toggleSubject[aria-pressed="true"] { color: var(--bs-warning, #ffc107); }
#toggleSubject[aria-pressed="false"] { color: var(--bs-secondary-color, #adb5bd); }

/* Desktop viewer padding override — the template applies Bootstrap p-4
   (1.5rem) which leaves too much empty chrome around the iframe. Mobile keeps
   the existing override in the @media block. */
@media (min-width: 768px) {
    .message-detail-card.p-4 {
        padding: 0.6rem 0.85rem !important;
    }
    .message-detail-card .message-detail-meta { margin-bottom: 0.5rem !important; }
    .message-detail-card h4.message-detail-subject { margin-bottom: 0.5rem !important; font-size: 1.15rem; }
}

/* Image-attachment hover preview. Only image items carry .attachment-item-img,
   which anchors the popover; the preview is always in the DOM and toggled purely
   by CSS on hover / keyboard focus. */
.attachment-preview {
    display: none;
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    z-index: 1050;
    padding: 4px;
    background: var(--eb-bg-elevated);
    border: 1px solid var(--eb-border-strong);
    border-radius: var(--eb-radius-sm);
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.5);
    pointer-events: none;
}
.attachment-preview img {
    max-width: 320px;
    max-height: 320px;
    display: block;
    border-radius: 3px;
}
.attachment-chip-img:hover .attachment-preview,
.attachment-chip-img:focus-within .attachment-preview {
    display: block;
}

/* Activity queue indicator — two-segment pill in the navbar. Sync segment
   spins its icon while syncs are running; either segment dims to ~45%
   opacity when its count is zero. The whole pill is a single <a> to
   /queue. */
.activity-indicator {
    gap: 4px;
    padding: 2px 10px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 14px;
    color: var(--bs-light, #d7dae0);
    font-variant-numeric: tabular-nums;
    font-size: .85rem;
    line-height: 1.4;
    transition: background-color .15s ease;
}
.activity-indicator:hover { background: rgba(255, 255, 255, 0.10); color: #fff; }
.activity-indicator .activity-seg {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 1px 4px;
}
.activity-indicator .activity-seg.is-zero { opacity: .45; }
.activity-indicator .activity-seg.sync.is-active { color: #6fb1ff; }
.activity-indicator .activity-seg.actions.is-active { color: #ffd166; }
.activity-indicator .activity-divider {
    display: inline-block;
    width: 1px;
    height: 14px;
    background: rgba(255, 255, 255, 0.18);
    margin: 0 2px;
}
.activity-indicator .spin { display: inline-block; animation: activity-spin 1.4s linear infinite; }
@keyframes activity-spin { from { transform: rotate(0deg) } to { transform: rotate(360deg) } }

/* Queued-action row states. The row enters pending while the worker
   commits to IMAP; trash actions terminate as a greyed-out "ghost" row
   so the list doesn't reflow when many rows are deleted.

   Visual: a faint accent wash marks the whole row in-flight, plus a slim
   indeterminate progress line gliding along the bottom of the content cell.
   The accent reflects the action — violet for read/unread, danger for trash,
   warning for spam, muted while settling.

   NOTE: the line is painted as a background-image strip on the cell, NOT a
   positioned ::before on the <tr>. A pseudo-element (or position:relative) on
   a table row injects an anonymous table-cell that breaks table-layout:fixed —
   the real cells get a phantom 5th column and the content shifts. A background
   layer is invisible to layout, so the row grid stays intact. */
.message-row.row-pending > td {
    background-color: var(--eb-primary-faint);
    transition: background-color .2s ease;
}
.message-row.row-pending[data-pending-action="trash"] > td,
.message-row.row-pending[data-pending-status="expunging"] > td {
    background-color: rgba(226, 109, 109, 0.09);
}
.message-row.row-pending[data-pending-action="spam"] > td {
    background-color: rgba(229, 179, 60, 0.09);
}
.message-row.row-pending[data-pending-status="applied"] > td,
.message-row.row-pending[data-pending-status="already_in_target"] > td {
    background-color: rgba(139, 134, 156, 0.07);
}

/* The indeterminate progress line: a short accent segment glides across the
   bottom of the content cell. Layered over the faint wash; no positioning or
   pseudo-element, so table-layout:fixed is untouched. */
.message-row.row-pending > .message-row-cell {
    background-image: linear-gradient(90deg,
        transparent 0%,
        var(--eb-primary) 40%,
        var(--eb-primary-hover) 50%,
        var(--eb-primary) 60%,
        transparent 100%);
    background-repeat: no-repeat;
    background-size: 45% 2px;
    background-position: -45% 100%;
    animation: row-pending-progress 1.15s cubic-bezier(0.45, 0, 0.55, 1) infinite;
}
.message-row.row-pending[data-pending-action="trash"] > .message-row-cell,
.message-row.row-pending[data-pending-status="expunging"] > .message-row-cell {
    background-image: linear-gradient(90deg, transparent 0%, var(--eb-danger) 50%, transparent 100%);
}
.message-row.row-pending[data-pending-action="spam"] > .message-row-cell {
    background-image: linear-gradient(90deg, transparent 0%, var(--eb-warning) 50%, transparent 100%);
}
.message-row.row-pending[data-pending-status="applied"] > .message-row-cell,
.message-row.row-pending[data-pending-status="already_in_target"] > .message-row-cell {
    background-image: linear-gradient(90deg, transparent 0%, var(--eb-text-faint) 50%, transparent 100%);
    animation-duration: .85s;
}
@keyframes row-pending-progress {
    0%   { background-position: -45% 100%; }
    100% { background-position: 145% 100%; }
}

/* Inline spinner shown in the action column of a server-rendered pending
   row, reinforcing which row is working alongside the bottom progress line. */
.message-toggle-pending {
    display: inline-block;
    width: 1rem;
    height: 1rem;
    border: 2px solid var(--eb-primary);
    border-right-color: transparent;
    border-radius: 50%;
    animation: message-swipe-spin .7s linear infinite;
    vertical-align: middle;
}
.message-row.row-pending[data-pending-action="trash"] .message-toggle-pending,
.message-row.row-pending[data-pending-status="expunging"] .message-toggle-pending {
    border-color: var(--eb-danger);
    border-right-color: transparent;
}
.message-row.row-pending[data-pending-action="spam"] .message-toggle-pending {
    border-color: var(--eb-warning);
    border-right-color: transparent;
}
.message-row.row-pending[data-pending-status="applied"] .message-toggle-pending,
.message-row.row-pending[data-pending-status="already_in_target"] .message-toggle-pending {
    border-color: var(--eb-text-faint);
    border-right-color: transparent;
}
.message-row.row-ghost {
    opacity: 0.5;
    background: var(--bs-secondary-bg-subtle);
    cursor: default;
}
.message-row.row-ghost td { pointer-events: none; }
.message-row.row-ghost .message-ghost-icon { color: var(--bs-secondary); }
.message-row.row-ghost.row-ghost-kept {
    opacity: 0.65;
    pointer-events: auto;
}
.message-row.row-ghost.row-ghost-kept td { pointer-events: auto; }
.message-row.row-failed { background: var(--bs-danger-bg-subtle); }
.message-pending-pill, .message-failed-pill { font-size: 0.7rem; }

/* Staged-action row states. A row awaiting flush gets a faint accent wash
   (much lighter than the in-flight tint) plus a single muted status glyph in
   the action column. Review/apply/cancel live in the Staged panel, so the row
   itself stays clean — no per-row confirm controls. Colors track the --eb-*
   tokens so the cue adapts across the violet/blue/oled themes. */
.message-row.row-staged > td {
    background-color: rgba(139, 134, 156, 0.07);
}
.message-row.row-staged-trash > td {
    background-color: rgba(226, 109, 109, 0.10);
}
.message-row.row-staged-spam > td {
    background-color: rgba(229, 179, 60, 0.10);
}
.message-row.row-staged-mark_read > td {
    background-color: rgba(107, 184, 229, 0.09);
}
.message-row.row-staged-mark_unread > td {
    background-color: rgba(139, 134, 156, 0.07);
}
.message-staged-status {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 1rem;
    line-height: 1;
    color: var(--eb-text-faint);
}
.message-row.row-staged-trash .message-staged-status { color: var(--eb-danger); }
.message-row.row-staged-spam .message-staged-status { color: var(--eb-warning); }
.message-row.row-staged-mark_read .message-staged-status { color: var(--eb-info); }
.message-row.row-staged-mark_unread .message-staged-status { color: var(--eb-text-muted); }

@media (prefers-reduced-motion: reduce) {
    .message-row.row-pending > .message-row-cell {
        animation: none;
        background-image: linear-gradient(90deg, var(--eb-primary), var(--eb-primary));
        background-size: 100% 2px;
        background-position: 0 100%;
    }
    .message-row.row-pending[data-pending-action="trash"] > .message-row-cell,
    .message-row.row-pending[data-pending-status="expunging"] > .message-row-cell {
        background-image: linear-gradient(90deg, var(--eb-danger), var(--eb-danger));
    }
    .message-row.row-pending[data-pending-action="spam"] > .message-row-cell {
        background-image: linear-gradient(90deg, var(--eb-warning), var(--eb-warning));
    }
    .message-toggle-pending {
        animation: none;
        border-right-color: var(--eb-primary);
    }
    /* Swipe chip: drop the ring transition; the scale still tracks the finger
       (direct manipulation, not decorative motion). */
    .message-swipe-backdrop i { transition: none; }
}

/* ----- Invoices page ----- */

/* Attachment viewer iframe: tall window on desktop; fills the fullscreen modal
   on phones (see the mobile block below). */
.invoice-attachment-frame {
    display: block;
    width: 100%;
    height: 80vh;
    border: 0;
    background: var(--eb-bg);
}

/* On touch input, the row source icons (envelope / paperclip / unlink) need real
   tap targets. Keyed off pointer type, not screen width, so touch laptops get it
   too. The cell stays nowrap; targets sit on one comfortable row. */
@media (pointer: coarse) {
    .invoice-sources a,
    .invoice-sources button {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-width: 2.75rem;
        min-height: 2.75rem;
        vertical-align: middle;
    }
    .invoice-sources a + a,
    .invoice-sources a + .badge,
    .invoice-sources button { margin-left: .25rem; }
}

@media (max-width: 767.98px) {
    /* main.container-fluid drops to 0 padding on phones, so give the invoices
       content its own breathing room back. */
    .invoices-page { padding: 0 .75rem; }

    /* Fullscreen attachment modal: let the iframe grow to fill the sheet so PDFs
       and images use the whole screen instead of a fixed 80vh window. */
    #invoiceAttachmentModal .modal-content { height: 100%; }
    #invoiceAttachmentModal .modal-body { display: flex; min-height: 0; }
    .invoice-attachment-frame { height: 100%; flex: 1 1 auto; }
}
