/* ===========================================================================
   StratWitCRM - Application styles

   Light theme. One stylesheet for the whole app, in this order:
     1. Tokens        2. Base       3. Layout shell
     4. Sidebar       5. Topbar     6. Cards and tables
     7. Badges        8. Forms      9. Empty states
    10. Login        11. Responsive
    12. Settings tiles   13. SMTP transcript   14. Email preview
    15. Rich text editor  16. Dry run breakdown  17. Readiness check
    18. Projects and tasks  19. Notifications  20. Board arrows and drag  16. Automation rule builder

   Colours: never hard-code an accent colour in a page. Use var(--accent),
   which header.php sets from the tenant's brand_color. That is what makes
   whitelabeling a one-field change.
   =========================================================================== */

/* --- 1. TOKENS ---------------------------------------------------------- */
:root {
    --accent:        #16558f;              /* overridden per tenant in header.php */
    --accent-tint:   color-mix(in srgb, var(--accent) 9%,  #ffffff);
    --accent-tint-2: color-mix(in srgb, var(--accent) 16%, #ffffff);
    --accent-ink:    color-mix(in srgb, var(--accent) 82%, #000000);

    --canvas:    #f4f6f8;
    --surface:   #ffffff;
    --line:      #e3e7ec;
    --line-soft: #eef1f5;

    --ink:   #101828;
    --ink-2: #475467;
    --muted: #98a2b3;

    --green: #067647;
    --amber: #b54708;
    --red:   #b42318;
    --blue:  #175cd3;
    --purple:#6941c6;
    --teal:  #0e7490;

    --radius:    10px;
    --radius-sm: 7px;
    --sidebar-w: 244px;
    --topbar-h:  60px;

    --shadow-sm: 0 1px 2px rgba(16, 24, 40, .05);
    --shadow-md: 0 4px 16px rgba(16, 24, 40, .08);

    --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

/* --- 2. BASE ------------------------------------------------------------ */
* { box-sizing: border-box; }

body {
    margin: 0;
    background: var(--canvas);
    color: var(--ink);
    font-family: var(--font);
    font-size: 14px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
}

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-ink); text-decoration: underline; }

/* Numbers line up in columns. Worth it in a CRM full of tables. */
.table td, .table th, .stat-value, .money { font-variant-numeric: tabular-nums; }

/* Lucide renders an <svg>; these classes size it consistently. */
.ico    { width: 18px; height: 18px; flex: 0 0 auto; stroke-width: 1.8; }
.ico-sm { width: 15px; height: 15px; }
.ico-lg { width: 22px; height: 22px; }

/* Visible keyboard focus everywhere. Do not remove. */
:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 4px;
}

/* --- 3. LAYOUT SHELL ---------------------------------------------------- */
.app-shell { display: flex; min-height: 100vh; }
.app-main  { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }

.page-content {
    flex: 1 1 auto;
    padding: 22px 26px 48px;
    max-width: 1560px;
    width: 100%;
}

/* Impersonation banner sits above everything. */
.impersonation-bar {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 18px;
    background: #7a2e0e;
    color: #fff;
    font-size: 13px;
}
.impersonation-bar strong { font-weight: 600; }
.impersonation-exit {
    margin-left: auto;
    color: #fff;
    border: 1px solid rgba(255,255,255,.45);
    border-radius: 6px;
    padding: 3px 11px;
    font-size: 12.5px;
    white-space: nowrap;
}
.impersonation-exit:hover { background: rgba(255,255,255,.14); color: #fff; text-decoration: none; }

/* --- 4. SIDEBAR --------------------------------------------------------- */
.sidebar {
    width: var(--sidebar-w);
    flex: 0 0 var(--sidebar-w);
    background: var(--surface);
    border-right: 1px solid var(--line);
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 0;
    height: 100vh;
    overflow-y: auto;
    z-index: 40;
}
.has-impersonation .sidebar { height: calc(100vh - 39px); }

/* Workspace identity block - the whitelabel surface */
.workspace {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 16px 16px 15px;
    border-bottom: 1px solid var(--line-soft);
    min-height: var(--topbar-h);
}
.workspace-mark {
    width: 32px; height: 32px;
    flex: 0 0 32px;
    border-radius: 8px;
    background: var(--accent);
    color: #fff;
    display: grid;
    place-items: center;
    font-size: 12px;
    font-weight: 650;
    letter-spacing: .02em;
}
.workspace-logo { width: 32px; height: 32px; border-radius: 8px; object-fit: contain; background: #fff; }
.workspace-meta { display: flex; flex-direction: column; min-width: 0; }
.workspace-name { font-weight: 600; font-size: 13.5px; color: var(--ink); line-height: 1.3; }
.workspace-type { font-size: 11px; color: var(--muted); }

.nav-tree { padding: 12px 10px 20px; flex: 1 1 auto; }

.nav-section {
    padding: 14px 8px 6px;
    font-size: 10.5px;
    font-weight: 650;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--muted);
}
.nav-section:first-child { padding-top: 4px; }

.nav-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    margin-bottom: 1px;
    border-radius: var(--radius-sm);
    color: var(--ink-2);
    font-size: 13.5px;
    font-weight: 500;
    position: relative;
}
.nav-item:hover { background: var(--line-soft); color: var(--ink); text-decoration: none; }
.nav-item .ico { color: var(--muted); }
.nav-item:hover .ico { color: var(--ink-2); }

/* Active item: tinted row plus a short accent rail on the left edge. */
.nav-item.active {
    background: var(--accent-tint);
    color: var(--accent-ink);
    font-weight: 600;
}
.nav-item.active .ico { color: var(--accent); }
.nav-item.active::before {
    content: "";
    position: absolute;
    left: -10px;
    top: 7px; bottom: 7px;
    width: 3px;
    border-radius: 0 3px 3px 0;
    background: var(--accent);
}

/* Modules that are not built yet */
.nav-item.is-pending { color: var(--muted); cursor: default; }
.nav-item.is-pending:hover { background: transparent; color: var(--muted); }
.nav-item.is-pending .ico { color: #c3cad4; }
.nav-tag {
    margin-left: auto;
    font-size: 9.5px;
    font-weight: 650;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--muted);
    background: var(--line-soft);
    border-radius: 4px;
    padding: 2px 6px;
}

.sidebar-foot {
    padding: 12px 18px;
    border-top: 1px solid var(--line-soft);
    display: flex;
    justify-content: space-between;
    font-size: 11px;
    color: var(--muted);
}
.sidebar-foot .version { font-variant-numeric: tabular-nums; }

.sidebar-backdrop { display: none; }

/* --- 5. TOPBAR ---------------------------------------------------------- */
.topbar {
    height: var(--topbar-h);
    flex: 0 0 var(--topbar-h);
    background: var(--surface);
    border-bottom: 1px solid var(--line);
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 0 26px;
    position: sticky;
    top: 0;
    z-index: 30;
}
.topbar-heading { min-width: 0; flex: 1 1 auto; }
/* The page title sat at 17px against a 14.5px card title - close enough that a
   page read as one flat plane with no obvious top. A proper step gives the eye
   somewhere to start without adding any chrome. */
.topbar-title {
    margin: 0;
    font-size: 19px;
    font-weight: 640;
    letter-spacing: -.015em;
    color: var(--ink);
    line-height: 1.25;
}
.topbar-subtitle { margin: 1px 0 0; font-size: 12.5px; color: var(--muted); }
.topbar-actions { display: flex; align-items: center; gap: 10px; margin-left: auto; }

.sidebar-toggle {
    display: none;
    background: none;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    padding: 6px;
    color: var(--ink-2);
}

.user-chip {
    display: flex;
    align-items: center;
    gap: 9px;
    background: none;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    padding: 5px 8px;
    color: var(--ink);
}
.user-chip:hover { background: var(--line-soft); }
.user-chip-text { display: flex; flex-direction: column; align-items: flex-start; line-height: 1.25; }
.user-chip-name { font-size: 13px; font-weight: 570; }
.user-chip-role { font-size: 11px; color: var(--muted); }

.avatar {
    width: 30px; height: 30px;
    flex: 0 0 30px;
    border-radius: 50%;
    background: var(--accent-tint-2);
    color: var(--accent-ink);
    display: grid;
    place-items: center;
    font-size: 11.5px;
    font-weight: 650;
}
.avatar-sm { width: 24px; height: 24px; flex-basis: 24px; font-size: 10px; }

.dropdown-menu { border-color: var(--line); box-shadow: var(--shadow-md); border-radius: var(--radius); font-size: 13.5px; }
.dropdown-item { display: flex; align-items: center; gap: 9px; padding: 7px 14px; }
.dropdown-header { font-size: 11.5px; color: var(--muted); }

/* --- 6. CARDS AND TABLES ------------------------------------------------ */
.card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    margin-bottom: 18px;
}
.card-header {
    background: transparent;
    border-bottom: 1px solid var(--line-soft);
    padding: 14px 18px;
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}
.card-header h2, .card-header h5, .card-header h6 {
    margin: 0;
    font-size: 14.5px;
    font-weight: 620;
}
.card-header .header-actions { margin-left: auto; display: flex; gap: 8px; align-items: center; }

/* A heading inside a card BODY rather than on a header strip.
 *
 * .card-title is Bootstrap's class and Bootstrap only sets its margin - the size
 * comes from whatever element it is on, so an <h2 class="card-title"> rendered
 * at the browser's default h2. Pages written after v0.9.1 used it and came out
 * with headings twice the size of every other page in the application, which is
 * what made them look like a different product.
 *
 * Matched to .card-header h2 so the two patterns are indistinguishable in size
 * and weight. The header strip is still the better choice where a card has a
 * heading and actions; this is for the rest. */
.card-body > .card-title,
.card-body > .d-flex > .card-title,
h2.card-title, h3.card-title {
    margin: 0 0 10px;
    font-size: 14.5px;
    font-weight: 620;
    color: var(--ink);
    letter-spacing: 0;
}
.card-body > .card-title:last-child,
h2.card-title.mb-0, h3.card-title.mb-0 { margin-bottom: 0; }
.card-body { padding: 18px; }
.card-body.p-0 { padding: 0; }

/* Stat cards */
.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(198px, 1fr));
    gap: 14px;
    margin-bottom: 18px;
}
.stat-card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    padding: 15px 16px;
    display: flex;
    align-items: flex-start;
    gap: 12px;
}
.stat-icon {
    width: 36px; height: 36px;
    flex: 0 0 36px;
    border-radius: 9px;
    display: grid;
    place-items: center;
    background: var(--accent-tint);
    color: var(--accent);
}
.stat-label { font-size: 11.5px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; color: var(--muted); }
.stat-value { font-size: 23px; font-weight: 650; letter-spacing: -.02em; line-height: 1.2; margin-top: 2px; }
/* Two names for one thing. .stat-hint came first, .stat-sub was written later
   and left its colour unset, so it inherited near-black ink - which meant a
   caption on the dashboard was darker than the same caption on reports and
   looked like emphasis rather than an accident. One rule, both names, because
   nine screens use the second one. */
.stat-hint, .stat-sub { font-size: 12px; color: var(--muted); margin-top: 2px; }

/* Tables */
.table { margin: 0; color: var(--ink); font-size: 13.5px; }
.table > :not(caption) > * > * { padding: 11px 18px; }
.table thead th {
    background: #fafbfc;
    border-bottom: 1px solid var(--line);
    font-size: 11px;
    font-weight: 650;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--muted);
    white-space: nowrap;
}
.table tbody td { border-bottom: 1px solid var(--line-soft); vertical-align: middle; }
.table tbody tr:last-child td { border-bottom: 0; }
.table-hover tbody tr:hover { background: #f8fafc; }
.table .row-title { font-weight: 570; color: var(--ink); }
.table .row-sub   { font-size: 12px; color: var(--muted); }
.table-actions { text-align: right; white-space: nowrap; }

.table-toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: 10px 12px;
    align-items: center;
    padding: 13px 18px;
    border-bottom: 1px solid var(--line-soft);
}

/* A filter bar can carry nine controls on the leads screen. Left to size
   themselves they shrink to their shortest option and sit shoulder to shoulder,
   which reads as one long smear of dropdowns. A floor on the width keeps each
   one legible and lets the row wrap onto a second line instead of squeezing.

   WIDTH:AUTO IS LOAD-BEARING. Bootstrap sets `width: 100%` on .form-select, so
   without this every control in a wrapping flex row takes a full line to itself
   and the filter bar swallows the screen. It used to be an inline style on each
   select; v1.0.2 removed those and did not put the width back here, which is
   exactly what happened. Do not delete it without setting a width some other
   way. */
.table-toolbar .form-select { width: auto; min-width: 158px; }
.table-toolbar .form-control[type="search"] { flex: 1 1 240px; max-width: 300px; }

/* --- 7. BADGES ---------------------------------------------------------- */
.badge-soft {
    display: inline-block;
    padding: 2.5px 9px;
    border-radius: 20px;
    font-size: 11.5px;
    font-weight: 600;
    line-height: 1.45;
    white-space: nowrap;
}
.badge-grey   { background: #f2f4f7; color: #475467; }
.badge-blue   { background: #eff6ff; color: var(--blue); }
.badge-green  { background: #ecfdf3; color: var(--green); }
.badge-red    { background: #fef3f2; color: var(--red); }
.badge-amber  { background: #fffaeb; color: var(--amber); }
.badge-purple { background: #f4f3ff; color: var(--purple); }
.badge-teal   { background: #ecfeff; color: var(--teal); }

/* Pipeline stage pill, tinted from an arbitrary hex via --stage */
.badge-stage {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 2.5px 10px;
    border-radius: 20px;
    font-size: 11.5px;
    font-weight: 600;
    background: color-mix(in srgb, var(--stage) 13%, #ffffff);
    color: color-mix(in srgb, var(--stage) 78%, #000000);
}
.badge-stage::before {
    content: "";
    width: 6px; height: 6px;
    border-radius: 50%;
    background: var(--stage);
}

/* Two pills that belong to one another - stage and its outcome. Wraps rather
   than overflowing, because an outcome comes from a voice agent and can be
   longer than anything a dropdown would have offered. */
.pill-pair {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 5px;
}

/* --- 8. FORMS AND BUTTONS ----------------------------------------------- */
.form-label { font-size: 12.5px; font-weight: 570; color: var(--ink-2); margin-bottom: 5px; }
.form-control, .form-select {
    border-color: var(--line);
    border-radius: var(--radius-sm);
    font-size: 13.5px;
    padding: 8px 11px;
    color: var(--ink);
}

/* Bootstrap draws a select's chevron as a BACKGROUND IMAGE pinned to the right
   edge, and reserves room for it with padding-right. The shorthand above resets
   that padding to 11px, so the longest option runs underneath the arrow - which
   is what made every filter bar in the application look cramped and misaligned.
   Put the space back. Applies to .form-select-sm too: same specificity, and this
   stylesheet loads after Bootstrap. */
.form-select { padding-right: 34px; }
.form-control:focus, .form-select:focus {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-tint);
}
.form-control::placeholder { color: #b6bec9; }
.form-text { font-size: 12px; color: var(--muted); }
.form-check-input:checked { background-color: var(--accent); border-color: var(--accent); }

.btn { border-radius: var(--radius-sm); font-size: 13.5px; font-weight: 550; padding: 8px 15px; display: inline-flex; align-items: center; gap: 7px; }
.btn-sm { font-size: 12.5px; padding: 5.5px 11px; }
.btn-primary { background: var(--accent); border-color: var(--accent); }
.btn-primary:hover, .btn-primary:focus { background: var(--accent-ink); border-color: var(--accent-ink); }
.btn-outline-secondary { border-color: var(--line); color: var(--ink-2); background: var(--surface); }
.btn-outline-secondary:hover { background: var(--line-soft); border-color: var(--line); color: var(--ink); }
.btn-icon { padding: 6px; border-radius: var(--radius-sm); line-height: 0; }

.alert { border: 1px solid var(--line); border-radius: var(--radius); font-size: 13.5px; padding: 11px 14px; }
.alert-success { background: #ecfdf3; border-color: #abefc6; color: #05603a; }
.alert-danger  { background: #fef3f2; border-color: #fecdca; color: #912018; }
.alert-warning { background: #fffaeb; border-color: #fedf89; color: #93370d; }
.alert-info    { background: #eff8ff; border-color: #b2ddff; color: #175cd3; }

.page-link { color: var(--ink-2); border-color: var(--line); font-size: 13px; }
.page-item.active .page-link { background: var(--accent); border-color: var(--accent); }
.page-link:hover { background: var(--line-soft); color: var(--ink); }

/* --- 9. EMPTY STATES ---------------------------------------------------- */
.empty-state { text-align: center; padding: 46px 24px; }
.empty-state-icon { width: 34px; height: 34px; color: var(--muted); stroke-width: 1.4; margin-bottom: 12px; }
.empty-state h6 { font-weight: 620; font-size: 14.5px; }
.empty-state p { max-width: 380px; margin-inline: auto; }

/* --- 10. LOGIN ---------------------------------------------------------- */
.auth-page {
    min-height: 100vh;
    display: grid;
    place-items: center;
    padding: 24px;
    background:
        radial-gradient(1100px 420px at 50% -12%, var(--accent-tint) 0%, transparent 62%),
        var(--canvas);
}
.auth-card {
    width: 100%;
    max-width: 396px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 14px;
    box-shadow: var(--shadow-md);
    padding: 30px 30px 26px;
}
.auth-brand { display: flex; align-items: center; gap: 11px; margin-bottom: 22px; }
.auth-brand .workspace-mark { width: 38px; height: 38px; flex-basis: 38px; border-radius: 10px; font-size: 14px; }
.auth-brand-name { font-size: 16px; font-weight: 650; letter-spacing: -.01em; }
.auth-brand-sub  { font-size: 12px; color: var(--muted); }
.auth-title { font-size: 19px; font-weight: 640; letter-spacing: -.015em; margin: 0 0 4px; }
.auth-sub   { font-size: 13px; color: var(--muted); margin: 0 0 20px; }
.auth-foot  { margin-top: 20px; padding-top: 15px; border-top: 1px solid var(--line-soft); font-size: 12px; color: var(--muted); text-align: center; }

/* --- 11. RESPONSIVE ----------------------------------------------------- */
@media (max-width: 991.98px) {
    .sidebar {
        position: fixed;
        top: 0; left: 0; bottom: 0;
        height: 100vh;
        transform: translateX(-100%);
        transition: transform .2s ease;
        box-shadow: var(--shadow-md);
    }
    .sidebar.is-open { transform: translateX(0); }

    .sidebar-backdrop {
        display: block;
        position: fixed;
        inset: 0;
        background: rgba(16,24,40,.42);
        opacity: 0;
        pointer-events: none;
        transition: opacity .2s ease;
        z-index: 39;
    }
    .sidebar-backdrop.is-open { opacity: 1; pointer-events: auto; }

    .sidebar-toggle { display: inline-flex; }
    .topbar { padding: 0 16px; }
    .page-content { padding: 16px 16px 40px; }
    .user-chip-text { display: none; }
}

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

/* Print: drop the chrome, keep the content */
@media print {
    .sidebar, .topbar, .impersonation-bar, .table-actions { display: none !important; }
    .page-content { padding: 0; }
    .card { border: 0; box-shadow: none; }
}

/* ===========================================================================
   12. KANBAN BOARD
   Horizontal scrolling row of fixed-width columns. Each column scrolls
   independently so a long column never stretches the page.
   =========================================================================== */
.kanban {
    display: flex;
    gap: 13px;
    align-items: flex-start;
    overflow-x: auto;
    padding-bottom: 14px;
    /* Pull the board out to the edges of the content area so the last column
       is not cut off by the page padding. */
    margin-inline: -26px;
    padding-inline: 26px;
    scroll-snap-type: x proximity;
}

.kb-col {
    flex: 0 0 274px;
    width: 274px;
    background: #eef1f4;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    display: flex;
    flex-direction: column;
    max-height: calc(100vh - 190px);
    min-height: 216px;
    scroll-snap-align: start;
}

.kb-col-head {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 10px 12px;
    border-bottom: 1px solid var(--line);
    font-size: 12.5px;
    font-weight: 620;
    color: var(--ink);
    position: sticky;
    top: 0;
    background: #eef1f4;
    border-radius: var(--radius) var(--radius) 0 0;
    z-index: 2;
}
.kb-col-dot {
    width: 8px; height: 8px;
    flex: 0 0 8px;
    border-radius: 50%;
    background: var(--stage, #94a3b8);
}
.kb-col-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kb-col-count {
    margin-left: auto;
    font-size: 11px;
    font-weight: 650;
    font-variant-numeric: tabular-nums;
    color: var(--ink-2);
    background: #ffffff;
    border: 1px solid var(--line);
    border-radius: 20px;
    padding: 1px 8px;
}
.kb-col-kind { color: var(--stage, #94a3b8); }

.kb-drop {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: 10px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    /* Generous, so an empty column is still an easy thing to drop onto. */
    min-height: 132px;
}

/* While dragging, the WHOLE column lights up - the pointer is often over the
   header or the Add lead link rather than the card list, and a target you
   cannot see is a target you cannot hit. */
.kb-col.is-target {
    background: var(--accent-tint);
    border-color: var(--accent);
    box-shadow: inset 0 0 0 1px var(--accent);
}
.kb-col.is-target .kb-col-head { background: var(--accent-tint); }
.kb-col.is-target .kb-drop {
    outline: 2px dashed var(--accent);
    outline-offset: -5px;
    border-radius: var(--radius-sm);
}

.kb-card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-sm);
    padding: 10px 11px;
    cursor: grab;
    transition: box-shadow .12s ease, transform .12s ease;
}
.kb-card:hover { box-shadow: 0 3px 10px rgba(16,24,40,.10); }
.kb-card:active { cursor: grabbing; }
.kb-card.is-dragging { opacity: .45; transform: rotate(1.2deg); }
.kb-card.is-saving { opacity: .6; pointer-events: none; }

.kb-card-title {
    display: block;
    font-size: 13.5px;
    font-weight: 600;
    color: var(--ink);
    line-height: 1.35;
    text-decoration: none;
    overflow-wrap: anywhere;
}
.kb-card-title:hover { color: var(--accent); text-decoration: none; }
/* The card is the drag handle, so the title must not show a text cursor and
   must not start a link-drag of its own (it also carries draggable="false"). */
.kb-card-title { cursor: inherit; -webkit-user-drag: none; }

.kb-card-fields {
    margin-top: 8px;
    padding-top: 7px;
    border-top: 1px solid var(--line-soft);
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.kb-card-field { display: flex; align-items: baseline; gap: 8px; font-size: 12px; line-height: 1.35; }
.kb-card-label {
    flex: 0 0 auto;
    max-width: 46%;
    color: var(--muted);
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: .03em;
    text-transform: uppercase;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.kb-card-value {
    margin-left: auto;
    text-align: right;
    color: var(--ink-2);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.kb-card-value a { color: var(--ink-2); }
.kb-card-value a:hover { color: var(--accent); }

.kb-empty {
    margin: 0;
    padding: 16px 8px;
    text-align: center;
    font-size: 12px;
    color: var(--muted);
    border: 1px dashed var(--line);
    border-radius: var(--radius-sm);
}

.kb-more, .kb-add {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    margin: 0 10px 10px;
    padding: 7px;
    background: transparent;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    color: var(--ink-2);
    font-size: 12.5px;
    font-weight: 550;
    text-decoration: none;
}
.kb-more:hover, .kb-add:hover { background: #ffffff; color: var(--ink); text-decoration: none; }
.kb-more:disabled { opacity: .6; }
.kb-add { color: var(--muted); border-style: dashed; }

/* ===========================================================================
   13. PIPELINE AND STAGE EDITORS
   =========================================================================== */
.stage-chain { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.stage-chain-arrow { color: #c3cad4; }

.stage-chip {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 4px 11px;
    border-radius: 20px;
    font-size: 12.5px;
    font-weight: 570;
    background: color-mix(in srgb, var(--stage) 12%, #ffffff);
    color: color-mix(in srgb, var(--stage) 80%, #000000);
    border: 1px solid color-mix(in srgb, var(--stage) 26%, #ffffff);
}
.stage-chip-count {
    font-variant-numeric: tabular-nums;
    font-size: 11px;
    font-weight: 650;
    background: #ffffff;
    border-radius: 20px;
    padding: 0 6px;
}

.stage-editor, .field-picker { display: flex; flex-direction: column; gap: 8px; }

.stage-row, .field-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px;
    background: #fafbfc;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
}
.stage-row.is-dragging, .field-row.is-dragging { opacity: .45; }
.stage-row .form-control-color { flex: 0 0 40px; width: 40px; padding: 3px; }
.stage-row input[type="text"] { flex: 1 1 auto; min-width: 110px; }

.field-row-label { flex: 1 1 auto; font-size: 13.5px; font-weight: 550; }

.stage-grip { cursor: grab; color: var(--muted); display: flex; padding: 2px; }
.stage-grip:active { cursor: grabbing; }

/* Stage buttons on the lead detail page - click one to move the lead */
.stage-picker { display: flex; flex-wrap: wrap; gap: 6px; }
.stage-step {
    padding: 6px 13px;
    border-radius: 20px;
    font-size: 12.5px;
    font-weight: 570;
    background: #ffffff;
    border: 1px solid var(--line);
    color: var(--ink-2);
}
.stage-step:hover:not(:disabled) {
    background: color-mix(in srgb, var(--stage) 12%, #ffffff);
    border-color: color-mix(in srgb, var(--stage) 40%, #ffffff);
    color: color-mix(in srgb, var(--stage) 80%, #000000);
}
.stage-step.is-current {
    background: var(--stage);
    border-color: var(--stage);
    color: #ffffff;
    cursor: default;
}
.stage-step:disabled { opacity: 1; }

/* ===========================================================================
   14. TIMELINE
   =========================================================================== */
.timeline { list-style: none; margin: 0; padding: 0; position: relative; }
.timeline::before {
    content: "";
    position: absolute;
    left: 13px;
    top: 8px;
    bottom: 8px;
    width: 1px;
    background: var(--line);
}
.timeline-item { display: flex; gap: 12px; padding-bottom: 16px; position: relative; }
.timeline-item:last-child { padding-bottom: 0; }
.timeline-dot {
    flex: 0 0 27px;
    width: 27px; height: 27px;
    border-radius: 50%;
    background: var(--surface);
    border: 1px solid var(--line);
    display: grid;
    place-items: center;
    color: var(--muted);
    z-index: 1;
}
.timeline-body { min-width: 0; padding-top: 3px; }
.timeline-text { font-size: 13.5px; color: var(--ink); }
.timeline-meta { font-size: 11.5px; color: var(--muted); margin-top: 1px; }
.timeline-changes {
    margin-top: 6px;
    padding: 7px 10px;
    background: #fafbfc;
    border: 1px solid var(--line-soft);
    border-radius: var(--radius-sm);
    font-size: 12px;
    display: flex;
    flex-direction: column;
    gap: 3px;
}

/* Choice-field checkbox group on the lead form */
.cf-multi {
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    padding: 8px 11px;
    max-height: 148px;
    overflow-y: auto;
}

/* Pills used for the lead / contact field switcher */
.nav-pills .nav-link { color: var(--ink-2); font-size: 13.5px; font-weight: 550; padding: 6px 14px; border-radius: var(--radius-sm); }
.nav-pills .nav-link:hover { background: var(--line-soft); }
.nav-pills .nav-link.active { background: var(--accent); color: #ffffff; }

@media (max-width: 991.98px) {
    .kanban { margin-inline: -16px; padding-inline: 16px; }
    .kb-col { flex-basis: 252px; width: 252px; max-height: none; }
}

/* ===========================================================================
   15. ACTIVITY STREAM
   The composer, the "things to do" block and the merged timeline on a lead.
   =========================================================================== */

/* Composer tabs sit flush in the card header */
.composer-tabs { border-bottom: 0; padding: 0 8px; gap: 2px; }
.composer-tabs .nav-link {
    display: flex;
    align-items: center;
    gap: 6px;
    border: 0;
    border-bottom: 2px solid transparent;
    border-radius: 0;
    padding: 12px 12px 10px;
    font-size: 13px;
    font-weight: 550;
    color: var(--ink-2);
    background: none;
}
.composer-tabs .nav-link:hover { color: var(--ink); background: none; }
.composer-tabs .nav-link.active {
    color: var(--accent);
    border-bottom-color: var(--accent);
    background: none;
}
.composer-tabs .nav-link .ico { color: currentColor; }

/* Nudge shown when a lead has nothing planned */
.next-action-nudge {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 13px 15px;
    background: #fffaeb;
    border: 1px solid #fedf89;
    border-radius: var(--radius-sm);
    font-size: 13.5px;
}
.next-action-nudge .ico { color: var(--amber); margin-top: 1px; }

/* Open action rows */
.action-row {
    display: flex;
    align-items: flex-start;
    gap: 11px;
    padding: 12px 18px;
    border-bottom: 1px solid var(--line-soft);
}
.action-row:last-child { border-bottom: 0; }
.action-row.is-overdue { background: #fffbfa; }

.action-icon {
    width: 28px; height: 28px;
    flex: 0 0 28px;
    border-radius: 7px;
    display: grid;
    place-items: center;
    background: var(--accent-tint);
    color: var(--accent);
}
.action-row.is-overdue .action-icon { background: #fef3f2; color: var(--red); }

.action-body { flex: 1 1 auto; min-width: 0; }
.action-title { font-size: 13.5px; font-weight: 570; color: var(--ink); }
.action-meta  { font-size: 12px; color: var(--muted); margin-top: 1px; }
.action-note  { font-size: 12.5px; color: var(--ink-2); margin-top: 5px; white-space: pre-wrap; }
.action-buttons { display: flex; gap: 5px; flex: 0 0 auto; }

/* Timeline dots tinted by what kind of entry it is */
.timeline-dot.tl-comment { background: var(--accent-tint);  color: var(--accent); border-color: transparent; }
.timeline-dot.tl-action  { background: #ecfdf3;             color: var(--green);  border-color: transparent; }
.timeline-dot.tl-email   { background: #eff8ff;             color: var(--blue);   border-color: transparent; }
.timeline-dot.tl-call    { background: #f4f3ff;             color: var(--purple); border-color: transparent; }

/* Comment body inside the timeline */
.comment-block { margin-top: 7px; }
.comment-text {
    padding: 10px 13px;
    background: #f8fafc;
    border: 1px solid var(--line-soft);
    border-radius: var(--radius-sm);
    font-size: 13.5px;
    color: var(--ink);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}
.comment-tools { display: flex; gap: 10px; margin-top: 5px; }

.btn-link-sm {
    background: none;
    border: 0;
    padding: 0;
    font-size: 12px;
    font-weight: 550;
    color: var(--muted);
}
.btn-link-sm:hover { color: var(--accent); text-decoration: underline; }
.btn-link-sm.text-danger:hover { color: var(--red) !important; }

.comment-editor { margin-top: 7px; }

/* Non-comment bodies, e.g. a call transcript */
.timeline-note {
    margin-top: 6px;
    padding: 9px 12px;
    background: #f8fafc;
    border: 1px solid var(--line-soft);
    border-radius: var(--radius-sm);
    font-size: 12.5px;
    line-height: 1.55;
    color: var(--ink-2);
}

/* The text of a quoted block. pre-wrap lives HERE rather than on the container,
   because the container also holds the little caption - and with pre-wrap on
   the parent, the newline and indentation between the two in the template were
   being rendered as real whitespace. That was the gap under the heading. */
.note-body {
    display: block;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* Leads list: flag for a lead with nothing planned */
.no-next-action {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 11.5px;
    font-weight: 600;
    color: var(--amber);
}

/* Stream filter tabs on the History card */
.stream-filters { display: flex; gap: 3px; flex-wrap: wrap; }
.stream-filter {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 11px;
    border-radius: 20px;
    font-size: 12.5px;
    font-weight: 550;
    color: var(--ink-2);
    text-decoration: none;
    border: 1px solid transparent;
}
.stream-filter:hover { background: var(--line-soft); color: var(--ink); text-decoration: none; }
.stream-filter.is-active {
    background: var(--accent-tint);
    border-color: color-mix(in srgb, var(--accent) 28%, #ffffff);
    color: var(--accent-ink);
}
.stream-filter-count {
    font-size: 10.5px;
    font-weight: 650;
    font-variant-numeric: tabular-nums;
    color: var(--muted);
    background: #ffffff;
    border-radius: 20px;
    padding: 0 6px;
}
.stream-filter.is-active .stream-filter-count { color: var(--accent); }

/* A lead with an action planned but no date on it yet */
.action-undated {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 11.5px;
    font-weight: 600;
    color: var(--blue);
}

/* Proportion bar under an outcome name on the dashboard */
.outcome-bar {
    margin-top: 5px;
    height: 4px;
    border-radius: 3px;
    background: var(--line-soft);
    overflow: hidden;
}
.outcome-bar::before {
    content: "";
    display: block;
    height: 100%;
    width: var(--pct, 0%);
    background: var(--accent);
    border-radius: 3px;
}

/* ===========================================================================
   16. CALL ENTRIES IN THE TIMELINE
   A call has three parts worth showing, in this order: what it produced, the
   recording, and only then the raw words. A transcript dumped in full pushes
   everything else off the screen, so it is collapsed and scrollable.
   =========================================================================== */
.call-entry { margin-top: 7px; }

.call-tags { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-bottom: 7px; }

.call-audio {
    display: block;
    width: 100%;
    max-width: 420px;
    height: 34px;
    margin-bottom: 4px;
}

.call-transcript { margin-top: 7px; }
.call-transcript > summary {
    cursor: pointer;
    font-size: 12px;
    font-weight: 550;
    color: var(--muted);
    list-style: none;
    display: inline-flex;
    align-items: center;
    gap: 5px;
}
.call-transcript > summary::before {
    content: "▸";
    font-size: 10px;
    transition: transform .12s ease;
}
.call-transcript[open] > summary::before { transform: rotate(90deg); }
.call-transcript > summary:hover { color: var(--accent); }
.call-transcript > summary::-webkit-details-marker { display: none; }

.call-transcript-body {
    margin-top: 7px;
    padding: 10px 12px;
    background: #f8fafc;
    border: 1px solid var(--line-soft);
    border-radius: var(--radius-sm);
    font-size: 12.5px;
    line-height: 1.55;
    color: var(--ink-2);
    /* Capped and scrollable: a five minute call is a lot of text, and it must
       not push the rest of the history off the page. */
    max-height: 300px;
    overflow-y: auto;
    overscroll-behavior: contain;
}

/* Small caption above a block of quoted text, so it is obvious what you are
   reading - a call summary, an agent note, a transcript. */
.note-label {
    display: block;
    font-size: 10px;
    font-weight: 650;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: 3px;
}


/* --- 12. SETTINGS TILES -------------------------------------------------- */
/* The signpost grid on modules/settings/index.php. A whole card is the link,
   so the click target is the tile rather than four words inside it. */
.setting-tile {
    display: flex;
    gap: 13px;
    height: 100%;
    padding: 16px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    color: var(--ink);
    text-decoration: none;
    transition: border-color .12s ease, box-shadow .12s ease;
}
.setting-tile:hover {
    border-color: color-mix(in srgb, var(--accent) 38%, var(--line));
    box-shadow: var(--shadow-md);
    color: var(--ink);
    text-decoration: none;
}

.setting-tile-icon {
    display: grid;
    place-items: center;
    flex: 0 0 auto;
    width: 36px;
    height: 36px;
    border-radius: var(--radius-sm);
    background: var(--accent-tint);
    color: var(--accent);
}

.setting-tile-body  { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.setting-tile-head  { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.setting-tile-label { font-weight: 600; font-size: 14px; }
.setting-tile-text  { font-size: 12.5px; color: var(--muted); line-height: 1.5; }


/* --- 13. SMTP TRANSCRIPT ------------------------------------------------- */
/* The SMTP conversation on Settings, Email. Monospace and scrollable, because
   the point of it is reading exactly which line the server objected to. */
.smtp-transcript > summary {
    cursor: pointer;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--ink-2);
    list-style: none;
    display: inline-flex;
    align-items: center;
    gap: 5px;
}
.smtp-transcript > summary::before {
    content: "▸";
    font-size: 10px;
    transition: transform .12s ease;
}
.smtp-transcript[open] > summary::before { transform: rotate(90deg); }
.smtp-transcript > summary:hover { color: var(--accent); }
.smtp-transcript > summary::-webkit-details-marker { display: none; }

.smtp-transcript-body {
    margin: 9px 0 0;
    padding: 12px 14px;
    background: #0f172a;                       /* dark, so it reads as a terminal */
    border-radius: var(--radius-sm);
    color: #e2e8f0;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 12px;
    line-height: 1.65;
    max-height: 340px;
    overflow: auto;
    overscroll-behavior: contain;
    /* Long server replies wrap instead of forcing the card sideways. */
    white-space: pre-wrap;
    word-break: break-word;
}


/* --- 14. EMAIL PREVIEW --------------------------------------------------- */
/* What the message will look like, on modules/leads/email.php. Framed like a
   sheet of paper so it is obviously the message and not more of the form. */
.email-preview-subject {
    font-weight: 620;
    font-size: 15px;
    padding-bottom: 10px;
    margin-bottom: 12px;
    border-bottom: 1px solid var(--line-soft);
}

.email-preview-body {
    padding: 16px 18px;
    background: #fcfcfd;
    border: 1px solid var(--line-soft);
    border-radius: var(--radius-sm);
    max-height: 460px;
    overflow-y: auto;
}


/* --- 15. CONTACT LINKS AND COPY FEEDBACK -------------------------------- */
/* A button that has to read as a link. Used by phone_link(), which is a button
   rather than an <a> because it goes nowhere - and a link that goes nowhere is
   a promise the page does not keep. */
.link-button {
    padding: 0;
    border: 0;
    background: none;
    color: var(--accent);
    font: inherit;
    cursor: pointer;
}
.link-button:hover { color: var(--accent-ink); text-decoration: underline; }

.copy-toast {
    position: fixed;
    left: 50%;
    bottom: 26px;
    z-index: 1080;
    transform: translate(-50%, 10px);
    padding: 9px 16px;
    background: var(--ink);
    color: #fff;
    border-radius: 999px;
    font-size: 13px;
    box-shadow: var(--shadow-md);
    opacity: 0;
    transition: opacity .18s ease, transform .18s ease;
    pointer-events: none;
}
.copy-toast.is-shown { opacity: 1; transform: translate(-50%, 0); }


/* --- 16. HTML EMAIL PREVIEW --------------------------------------------- */
/* The HTML preview renders inside a sandboxed iframe. The sandbox attribute is
   what actually stops script in a pasted template running inside the CRM -
   sanitise_email_html() tidies the markup, but a blocklist over HTML is not a
   wall on its own. Height is fixed with internal scrolling because a sandboxed
   frame cannot message its own height back out, and loosening the sandbox to
   let it would give away the thing that makes it safe. */
.email-preview-frame {
    width: 100%;
    height: 460px;
    border: 1px solid var(--line-soft);
    border-radius: var(--radius-sm);
    background: #fff;
}


/* --- 15. RICH TEXT EDITOR ------------------------------------------------ */
/* The HTML email editor. See assets/js/editor.js - the textarea is still the
   real form field; the surface is a contenteditable sitting in front of it. */
.rte {
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--surface);
    overflow: hidden;
}
.rte:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-tint); }

.rte-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 3px;
    padding: 6px 8px;
    background: #f8fafc;
    border-bottom: 1px solid var(--line-soft);
}

.rte-btn {
    min-width: 30px;
    height: 28px;
    padding: 0 7px;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--ink-2);
    font-size: 13px;
    line-height: 1;
    cursor: pointer;
}
.rte-btn:hover  { background: #fff; border-color: var(--line); color: var(--ink); }
.rte-btn.is-active { background: var(--accent-tint); border-color: var(--accent); color: var(--accent-ink); }

.rte-source-toggle { margin-left: auto; font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 11.5px; }

.rte-select {
    height: 28px;
    padding: 0 4px;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: #fff;
    color: var(--ink-2);
    font-size: 12px;
}

.rte-surface {
    min-height: 320px;
    max-height: 560px;
    overflow-y: auto;
    padding: 14px 16px;
    outline: none;
    font-size: 14px;
    line-height: 1.6;
}
/* Images pasted from a marketing template are often sized for a wide desktop
   client. Capping them here keeps the editor usable; it does NOT change what
   is sent, because this rule lives in the CRM stylesheet and never travels. */
.rte-surface img { max-width: 100%; height: auto; }

/* The source view. Same box, monospace, so switching does not feel like
   leaving the editor. */
textarea.rte-source {
    display: block;
    width: 100%;
    min-height: 320px;
    max-height: 560px;
    border: 0;
    padding: 14px 16px;
    outline: none;
    resize: vertical;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 12.5px;
    line-height: 1.6;
    color: var(--ink-2);
}


/* --- 16. AUTOMATION RULE BUILDER ----------------------------------------- */
/* The condition groups and action rows on modules/automations/form.php. */

.cond-group {
    position: relative;
    padding: 12px;
    margin-bottom: 10px;
    background: #f8fafc;
    border: 1px solid var(--line-soft);
    border-radius: var(--radius-sm);
}

/* The OR between groups. Sits on the group's top edge so the relationship
   between the boxes is visible without reading anything. */
.cond-or {
    position: absolute;
    top: -9px;
    left: 12px;
    padding: 1px 8px;
    background: var(--accent-tint);
    border-radius: 10px;
    color: var(--accent-ink);
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .06em;
}

.cond-row {
    display: flex;
    gap: 6px;
    align-items: center;
    margin-bottom: 6px;
}
.cond-row .cond-field    { flex: 0 0 30%; min-width: 130px; }
.cond-row .cond-operator { flex: 0 0 28%; min-width: 130px; }
.cond-row .cond-value    { flex: 1 1 auto; min-width: 90px; }

/* Rows within a group are ANDed. The word is in the gutter rather than on a
   line of its own, so a group of four conditions stays compact. */
.cond-row + .cond-row::before {
    content: "and";
    position: absolute;
    left: -2px;
    margin-left: -26px;
    color: var(--muted);
    font-size: 10.5px;
}

.action-row {
    padding: 12px;
    margin-bottom: 10px;
    background: #f8fafc;
    border: 1px solid var(--line-soft);
    border-radius: var(--radius-sm);
}

.action-head {
    display: flex;
    gap: 6px;
    align-items: center;
    margin-bottom: 8px;
}
/* min-width matters more than max-width here. flex: 1 1 auto lets the select
   shrink, and on a narrow action row it collapsed to about four characters -
   "Send an email" rendered as "Sen...". You cannot read what an action IS on
   the screen where automations are built, which reads as broken rather than
   plain. */
.action-head .action-type { flex: 1 1 auto; min-width: 170px; max-width: 260px; }
.action-head .action-remove { margin-left: auto; }

.action-settings { padding-left: 2px; }

@media (max-width: 640px) {
    .cond-row { flex-wrap: wrap; }
    .cond-row .cond-field,
    .cond-row .cond-operator { flex: 1 1 100%; }
}


/* --- 16. DRY RUN BREAKDOWN ----------------------------------------------- */
/* Per-condition rejection counts, shown when a dry run matches fewer leads
   than it checked. See modules/automations/form.php. */
.dry-blame {
    margin-top: 14px;
    padding: 12px 14px;
    background: #fffbeb;
    border: 1px solid #fde68a;
    border-radius: var(--radius-sm);
}
.dry-blame-head {
    font-size: 12.5px;
    font-weight: 600;
    color: #92400e;
    margin-bottom: 6px;
}
.dry-blame table { background: transparent; }
.dry-blame td { border-color: #fde68a; font-size: 13px; }


/* --- 17. READINESS CHECK ------------------------------------------------- */
/* modules/settings/readiness.php - the fix line under a failed check. */
.readiness-fix {
    margin-top: 6px;
    padding: 8px 10px;
    background: #f8fafc;
    border-left: 3px solid var(--accent);
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    font-size: 12.5px;
    line-height: 1.55;
    color: var(--ink-2);
}
.readiness-fix code { font-size: 12px; }


/* --- 18. PROJECTS AND TASKS ---------------------------------------------- */
/* A thin progress bar for a project's task completion. Deliberately not
   Bootstrap's .progress - that carries a height and background this design
   does not want, and overriding both is more CSS than writing two rules. */
.progress-slim {
    height: 5px;
    border-radius: 3px;
    background: var(--line-soft);
    overflow: hidden;
}
.progress-slim-fill {
    height: 100%;
    background: var(--accent);
    border-radius: 3px;
    transition: width .2s ease;
}

/* Comments on a task. */
.task-comment { padding: 12px 0; border-top: 1px solid var(--line-soft); }
.task-comment:first-of-type { border-top: 0; padding-top: 0; }

.task-comment-head {
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 12.5px;
    margin-bottom: 4px;
}
.task-comment-tools { margin-left: auto; display: flex; gap: 10px; }
.task-comment-tools .btn-link { text-decoration: none; font-size: 12.5px; }

.task-comment-body { font-size: 14px; line-height: 1.6; color: var(--ink); }

/* The "you are on somebody else's address" strip. Same geometry as the
   impersonation bar so the layout offset already accounts for it. */
.address-mismatch {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 8px 18px;
    background: #7c2d12;
    color: #fff;
    font-size: 13px;
    position: fixed;
    top: 0; left: 0; right: 0;
    z-index: 1040;
}

/* The bar that appears when rows are ticked. Sticky, because a selection made
   at the bottom of a long list should not need scrolling back up to act on. */
.bulk-bar {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    padding: 10px 14px;
    background: var(--accent-tint);
    border-bottom: 1px solid var(--line);
    position: sticky;
    top: 0;
    z-index: 5;
}
.bulk-count {
    font-size: 13px;
    font-weight: 600;
    color: var(--accent-ink);
    margin-right: 4px;
}
.bulk-bar .form-select-sm { min-width: 110px; }

/* Each control in the bar says what it sets. Without these the row read as
   three unlabelled dropdowns and a column of buttons, and the only way to know
   what "Normal" meant was to press the button next to it and find out. */
.bulk-label {
    font-size: 12px;
    font-weight: 600;
    color: var(--ink-2);
    margin: 0 -2px 0 4px;
    white-space: nowrap;
}

/* A form that has been submitted and is waiting for the server. Replaces the
   old habit of disabling the submit button, which stopped that button's name
   and value being posted - see initSubmitGuard() in assets/js/app.js. */
form.is-submitting {
    opacity: .6;
    pointer-events: none;
}


/* --- 19. NOTIFICATIONS ---------------------------------------------------- */
.bell {
    position: relative;
    display: grid;
    place-items: center;
    width: 34px;
    height: 34px;
    border-radius: var(--radius-sm);
    color: var(--ink-2);
    text-decoration: none;
    transition: background .12s ease, color .12s ease;
}
.bell:hover { background: var(--accent-tint); color: var(--accent); }
.bell.has-unread { color: var(--accent); }

.bell-count {
    position: absolute;
    top: 1px;
    right: 0;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 8px;
    background: #dc2626;
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
}

/* An unread row is tinted rather than badged - the whole line reads as new. */
.notice-row.is-unread { background: var(--accent-tint); }
.notice-row .row-sub { margin-top: 2px; }

/* A mention inside a comment. */
.mention {
    background: var(--accent-tint);
    color: var(--accent-ink);
    border-radius: 3px;
    padding: 0 3px;
    font-weight: 600;
}

/* The @ autocomplete under a comment box. Positioned relative to the field's
   container, so the container needs position:relative - both comment boxes sit
   inside a card body, which already has it. */
.mention-menu {
    position: absolute;
    z-index: 20;
    min-width: 200px;
    max-width: 320px;
    margin-top: -6px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-md);
    overflow: hidden;
}
.mention-item {
    display: block;
    width: 100%;
    padding: 7px 12px;
    border: 0;
    background: transparent;
    text-align: left;
    font-size: 13.5px;
    color: var(--ink);
    cursor: pointer;
}
.mention-item:hover,
.mention-item.is-active { background: var(--accent-tint); color: var(--accent-ink); }

/* The mention menu is absolutely positioned inside whichever card body holds
   the comment box. */
.card-body { position: relative; }


/* --- 20. BOARD: EDGE ARROWS, DRAG GHOST, TOUCH -------------------------- */
/* The board sits inside a wrapper so the arrows have something to anchor to. */
.kb-wrap { position: relative; }

.kb-nudge {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 6;
    width: 34px;
    height: 58px;
    display: grid;
    place-items: center;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--ink-2);
    box-shadow: var(--shadow-md);
    cursor: pointer;
    opacity: .82;
    transition: opacity .12s ease, color .12s ease;
}
.kb-nudge:hover { opacity: 1; color: var(--accent); }
.kb-nudge-left  { left: -8px; }
.kb-nudge-right { right: -8px; }

/* The card that follows the pointer. Fixed, so it is not clipped by the
   board's own overflow, and pointer-events:none so elementFromPoint sees the
   column underneath rather than the ghost. */
.kb-ghost {
    position: fixed;
    z-index: 1200;
    pointer-events: none;
    opacity: .93;
    transform: rotate(1.5deg);
    box-shadow: 0 12px 28px rgba(15, 23, 42, .22);
    cursor: grabbing;
}

.kb-card {
    cursor: grab;

    /* THE BROWSER DECIDES touch-action WHEN THE FINGER LANDS, not while the
       gesture is running. Setting it on the board once a drag has started -
       220ms later - is far too late: by then the browser has already committed
       to panning, and the moment the finger moves it takes the gesture, fires
       pointercancel, and the card drops back where it started.
    
       pan-y is the compromise that works. The browser keeps VERTICAL panning,
       so the page still scrolls normally with a finger anywhere, including on a
       card. HORIZONTAL is left to us, which is the direction a card travels
       between columns.
    
       The cost: you can no longer scroll the board sideways by swiping on a
       card. Swipe the gaps, the column headers, or use the arrows. */
    touch-action: pan-y;
}
.kb-card.is-dragging { opacity: .35; }

/* While a drag is running, stop the browser turning the gesture into a scroll
   or a text selection. Only during the drag - the board must still scroll
   normally with a finger the rest of the time. */
.kanban.is-dragging-board {
    touch-action: none;
    user-select: none;
    cursor: grabbing;

    /* SNAPPING OFF WHILE DRAGGING.
    
       The board snaps to column starts, which is right when you flick through
       it by hand. It is wrong while a card is being dragged: the auto-scroll
       nudges scrollLeft by a few pixels per frame, and the snap drags it
       straight back to the column it started in, so the board never moves.
    
       The edge arrows were unaffected because they jump a whole column and land
       exactly on a snap point - which is why they worked while holding a card
       at the edge did nothing. */
    scroll-snap-type: none;
}

/* A finger needs a bigger target than a mouse pointer. */
@media (pointer: coarse) {
    .kb-card { padding: 12px; }
    .kb-nudge { width: 40px; height: 68px; }
}

/* A page that opts out of the reading-width cap. The board uses it: every
   pixel of width is one less stage hidden off the right-hand edge. */
.page-content.is-wide { max-width: none; }

/* The on-screen "would not scroll" warning was removed in v0.8.8.4.
   It was a diagnostic for a bug that turned out to be the diagnostic itself:
   near the edge of the zone the scroll step is a fraction of a pixel, which
   does not move scrollLeft, which the check read as stuck. The scroll now
   carries its remainder between frames, so there is nothing left to report. */



/* --- 21. PROFILE PICTURES ------------------------------------------------ */
/* An uploaded picture replaces the initials block and has to match its shape
   exactly, or every row it appears in shifts. */
.avatar-img {
    padding: 0;
    object-fit: cover;
    background: var(--line-soft);
}

.avatar-lg {
    width: 72px;
    height: 72px;
    font-size: 22px;
    flex: 0 0 72px;
}


/* --- 22. CALLS ----------------------------------------------------------- */
/* The player on a logged call. preload="metadata" on the element itself - a
   small byte-range request for the file's header, not the whole recording -
   so a lead with thirty calls still does not fetch thirty full audio files on
   page load, but each player shows a real duration instead of 0:00 / 0:00
   before anyone has pressed play. (v0.9 shipped with preload="none", which
   has no metadata to show a duration from until playback starts.) */
.call-player {
    display: block;
    width: 100%;
    max-width: 340px;
    height: 34px;
    margin-top: 8px;
}

/* --- 23. DIALPAD (v0.9.2) ------------------------------------------------- */
/* The floating dialer. Fixed to the corner of every page, because a call can
   start from anywhere - a lead, the call log, or from nothing at all when
   somebody is reading a number off a business card.

   Hidden entirely (never rendered) for a workspace that cannot place calls, so
   there is no dead button to explain. See phone_link() and the guard in
   footer.php. */

.dial-fab {
    position: fixed;
    right: 22px;
    bottom: 22px;
    z-index: 1070;              /* over content, under the copy toast at 1080 */
    width: 52px;
    height: 52px;
    border: 0;
    border-radius: 50%;
    background: var(--accent);
    color: #fff;
    box-shadow: 0 6px 20px rgba(16, 24, 40, .22);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: transform .15s ease, background .15s ease;
}
.dial-fab:hover     { transform: scale(1.05); background: var(--accent-ink); }
.dial-fab svg       { width: 22px; height: 22px; }

/* Pulses while a call is live, so it is obvious the line is open even when the
   panel is closed and somebody has scrolled away. */
.dial-fab.is-live      { background: var(--green); animation: dial-pulse 1.7s infinite; }
@keyframes dial-pulse {
    0%   { box-shadow: 0 0 0 0   rgba(6, 118, 71, .45); }
    70%  { box-shadow: 0 0 0 14px rgba(6, 118, 71, 0); }
    100% { box-shadow: 0 0 0 0   rgba(6, 118, 71, 0); }
}

.dial-panel {
    position: fixed;
    right: 22px;
    bottom: 86px;
    z-index: 1070;
    width: 268px;
    padding: 16px;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: 14px;
    box-shadow: 0 12px 34px rgba(16, 24, 40, .18);
    display: none;
}
.dial-panel.is-open { display: block; }

.dial-caller {
    font-size: 12px;
    color: var(--ink-2);
    text-align: center;
    margin-bottom: 10px;
}
.dial-caller strong { color: var(--ink); }

.dial-display {
    width: 100%;
    height: 40px;
    margin-bottom: 10px;
    padding: 0 10px;
    border: 1px solid var(--line);
    border-radius: 8px;
    font-size: 17px;
    text-align: center;
    letter-spacing: .5px;
}

/* The status line. Always present so the panel does not jump in height when a
   call starts - a dialpad that resizes under the cursor loses you the button. */
.dial-status {
    min-height: 18px;
    margin-bottom: 10px;
    font-size: 12px;
    text-align: center;
    color: var(--ink-2);
}
.dial-status.is-error { color: var(--red); }
.dial-status.is-live  { color: var(--green); font-weight: 600; }

.dial-keys {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 6px;
    margin-bottom: 10px;
}
.dial-key {
    height: 42px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: #fff;
    font-size: 17px;
    color: var(--ink);
    cursor: pointer;
}
.dial-key:hover  { background: var(--accent-tint); border-color: var(--accent); }
.dial-key:active { background: var(--accent-tint-2); }

.dial-actions { display: flex; gap: 6px; }
.dial-action {
    flex: 1;
    height: 40px;
    border: 0;
    border-radius: 8px;
    font-size: 14px;
    font-weight: 600;
    color: #fff;
    cursor: pointer;
}
.dial-call   { background: var(--green); }
.dial-hangup { background: var(--red); }
.dial-action:disabled { opacity: .45; cursor: not-allowed; }

/* The little phone icon on a clickable number, from phone_link(). Sized down
   and nudged so it sits on the text baseline rather than pushing the row taller
   - these appear inside table cells. */
.dial-number-icon {
    width: 13px;
    height: 13px;
    margin-right: 4px;
    vertical-align: -2px;
}

/* The tones pressed during a call, shown on their own line rather than appended
   to the number being dialled - see sendTone() in dialpad.js for why.
   Monospace and letter-spaced because the question being asked is usually "did
   my customer ID go in right", and that means counting digits. */
.dial-keyed {
    margin-bottom: 10px;
    padding: 6px 8px;
    background: var(--line-soft);
    border-radius: 6px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 13px;
    letter-spacing: 1px;
    color: var(--ink);
    text-align: center;
    word-break: break-all;   /* a long account number wraps rather than overflows */
}

/* --- 24. CONTACT DETAIL ROWS (v0.9.4) ------------------------------------ */
/* A repeatable row on the lead form: value, label, primary, remove. Flex
   rather than a grid so the value takes whatever is left after the fixed-width
   controls, at any window size. */
.contact-row {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-bottom: 6px;
}
.contact-row .contact-value  { flex: 1 1 auto; min-width: 0; }
.contact-row .contact-label  { flex: 0 0 110px; }
.contact-row .contact-remove { flex: 0 0 auto; font-size: 20px; line-height: 1; padding: 0 6px; }

.contact-primary {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: 12px;
    color: var(--ink-2);
    white-space: nowrap;
    cursor: pointer;
}

/* On a lead's own page: the label sits next to the number rather than above
   it, so a lead with five numbers stays five lines rather than ten. */
.contact-tag {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 6px;
    border-radius: 999px;
    background: var(--line-soft);
    font-size: 11px;
    color: var(--ink-2);
    vertical-align: 1px;
}

/* --- 25. REPORTS (v0.9.7) ------------------------------------------------- */
/* A fixed height, because a canvas with no height collapses to nothing and a
   responsive chart inside a growing container can chase its own size and
   stretch on every redraw. */
.chart-holder {
    position: relative;
    height: 260px;
}

/* .stat-sub is defined with .stat-hint in section 6. The duplicate that used to
   live here set only size and margin, so it silently dropped the muted colour. */

/* --- 26. CALENDAR (v0.9.10) ---------------------------------------------- */
/* Seven equal columns. A grid rather than a table because the cells need to be
   a fixed height regardless of how much is in them - a table row grows to fit
   its tallest cell, so one busy day would stretch a whole week. */
.cal-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 1px;
    background: var(--line);
    border: 1px solid var(--line);
    border-radius: 8px;
    overflow: hidden;
}

.cal-heading {
    background: var(--bg-soft, #f8fafc);
    padding: 6px 8px;
    font-size: 11px;
    font-weight: 600;
    color: var(--ink-2);
    text-transform: uppercase;
    letter-spacing: .04em;
    text-align: center;
}

.cal-day {
    background: #fff;
    min-height: 96px;
    padding: 4px 5px 6px;
    overflow: hidden;
}

/* Days from the months either side. Present so the grid is always six full
   weeks, greyed so they do not read as part of this month. */
.cal-day-outside { background: #fbfcfd; }
.cal-day-outside .cal-day-number { color: var(--muted); }

.cal-day-today .cal-day-number {
    background: var(--accent);
    color: #fff;
    border-radius: 999px;
}

.cal-day-open { box-shadow: inset 0 0 0 2px var(--accent); }

.cal-day-number {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 22px;
    height: 22px;
    margin-bottom: 3px;
    font-size: 12px;
    color: var(--ink-2);
    text-decoration: none;
}
.cal-day-number:hover { background: var(--accent-tint); border-radius: 999px; }

.cal-item {
    display: block;
    margin-bottom: 2px;
    padding: 2px 5px;
    border-radius: 4px;
    background: var(--accent-tint);
    border-left: 3px solid var(--accent);
    font-size: 11px;
    line-height: 1.35;
    color: var(--ink);
    text-decoration: none;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.cal-item:hover { background: var(--accent-tint-2); }
.cal-item-time  { color: var(--ink-2); margin-right: 3px; }

/* A colour per kind, so a week of calls and meetings can be read at a glance
   rather than by opening each one. */
.cal-item-call    { border-left-color: #067647; background: rgba(6,118,71,.08); }
.cal-item-meeting { border-left-color: #6941c6; background: rgba(105,65,198,.08); }
.cal-item-email   { border-left-color: #b54708; background: rgba(181,71,8,.08); }

.cal-item-done { opacity: .55; text-decoration: line-through; }

.cal-more { display: block; font-size: 11px; color: var(--ink-2); padding-left: 5px; }

/* Below a phone's width a seven-column grid is unreadable, so the day numbers
   shrink and the items become dots rather than text. The detail panel under the
   grid is how the day is actually read on a small screen. */
@media (max-width: 640px) {
    .cal-day { min-height: 56px; }
    .cal-item { font-size: 0; padding: 3px; }
    .cal-item-time { font-size: 0; }
}

/* A table-shaped report can be wider than the card on a small screen. Scrolling
   the table rather than the page keeps the rest of the layout still. */
.table-scroll { overflow-x: auto; max-height: 420px; overflow-y: auto; }

/* --- 27. ZOOM (v0.9.11) --------------------------------------------------- */
/* The meeting details on an action row. Indented and tinted so it reads as
   belonging to the action above it rather than as a separate item. */
.zoom-box {
    margin-top: 6px;
    padding: 6px 8px;
    background: var(--accent-tint);
    border-left: 3px solid var(--accent);
    border-radius: 4px;
    font-size: 13px;
}
.zoom-box-failed {
    background: rgba(180, 35, 24, .06);
    border-left-color: var(--red);
}

/* ---------------------------------------------------------------------------
   THE ASSISTANT COMPOSER                                    (added in v1.7.0)

   Fixed to the bottom, where every chat people already use puts it. A box that
   scrolls away as the conversation grows means hunting for it after every
   answer.

   Left offset matches the sidebar so the box does not sit under it. The
   sidebar collapses below 992px, and so does this.
   --------------------------------------------------------------------------- */
.assistant-composer {
    position: fixed;
    bottom: 0;
    left: var(--sidebar-w);
    right: 0;
    padding: 12px 24px 16px;
    /* Fades the conversation out behind it rather than cutting it off with a
       hard edge, which reads as the page having ended. */
    background: linear-gradient(to bottom, transparent, var(--canvas) 28%);
    z-index: 20;
}

.assistant-composer .card {
    margin-bottom: 0;
}

/*
 * Matches the conversation column rather than the page.
 *
 * The layout is a Bootstrap row of col-lg-8 (the conversation) and col-lg-4
 * (the panels), inside the standard page padding. Two thirds of that, less the
 * gutter, puts the box under the messages instead of stretching across the
 * whole screen and up against the floating call button in the corner.
 */
.assistant-composer-inner {
    max-width: calc((100% - 24px) * 0.6667);
}

@media (max-width: 991.98px) {
    .assistant-composer {
        left: 0;
        padding: 10px 12px 12px;
    }
}
