/* ============================================
   Subscription Card
   ============================================ */
.subscription-card {
    margin-bottom: 24px;
}

.subscription-info {
    text-align: center;
}

.subscription-status {
    margin-bottom: 8px;
}

.plan-name {
    font-size: 20px;
    font-weight: 600;
    margin-left: 8px;
}

.subscription-period {
    color: var(--text-muted);
    font-size: 12px;
    margin-bottom: 16px;
}

.subscription-actions {
    display: flex;
    gap: 8px;
    justify-content: center;
}

/* ============================================
   Response Log
   ============================================ */
.response-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.response-item {
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    padding: 16px;
}

.response-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 12px;
}

.sender-info {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.response-time {
    font-size: 12px;
    color: var(--text-muted);
}

.response-preview {
    margin-bottom: 8px;
}

.preview-label {
    font-size: 11px;
    color: var(--text-muted);
    text-transform: uppercase;
    margin-bottom: 4px;
}

.preview-text {
    font-size: 13px;
    color: var(--text-secondary);
}

/* ============================================
   Email Detail
   ============================================ */
.email-detail {
    max-height: 60vh;
    overflow-y: auto;
}

.detail-section {
    margin-bottom: 20px;
}

.detail-section h4 {
    margin-bottom: 12px;
    color: var(--text-muted);
    font-size: 12px;
    text-transform: uppercase;
}

.detail-row {
    display: flex;
    gap: 12px;
    margin-bottom: 8px;
}

.detail-label {
    font-weight: 500;
    min-width: 60px;
}

.email-body {
    background: var(--bg-secondary);
    padding: 16px;
    border-radius: var(--border-radius);
    font-size: 13px;
    line-height: 1.6;
    white-space: pre-wrap;
}

/* ============================================
   Leads Page
   ============================================ */
.leads-layout {
    display: grid;
    grid-template-columns: 280px 1fr;
    gap: 24px;
}

.lists-sidebar .list-items {
    list-style: none;
}

.list-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 12px;
    border-radius: var(--border-radius);
    cursor: pointer;
}

/* This darkened the row to the page background on hover -- pointing at
   something made it recede. Hover lifts. */
.list-item:hover {
    background: var(--bg-hover);
}

.list-item.active {
    /* White on --primary (#7FA096) measures about 1.9:1 -- the selected row
       was the least readable thing on screen. The deep fill with bright text
       is the same treatment the active nav item uses. */
    background: var(--green-deep);
    box-shadow: inset 2px 0 0 var(--green-accent);
    color: var(--green-bright);
}

.list-item.active .list-count {
    color: rgba(255, 255, 255, 0.8);
}

.list-info {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.list-count {
    font-size: 12px;
    color: var(--text-muted);
}

/* ============================================
   Settings Page
   ============================================ */
.settings-tabs {
    display: flex;
    gap: 8px;
    margin-bottom: 24px;
}

.settings-tabs .tab-btn {
    padding: 10px 16px;
    border: 1px solid var(--border-color);
    background: var(--bg-primary);
    border-radius: var(--border-radius);
    font-weight: 500;
    cursor: pointer;
}

.settings-tabs .tab-btn.active {
    background: var(--primary);
    color: white;
    border-color: var(--primary);
}

.tab-content {
    display: none;
}

.tab-content.active {
    display: block;
}

.account-details {
    max-width: 400px;
}

.mailbox-list,
.template-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.mailbox-item,
.template-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 12px;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
}

.mailbox-info,
.template-info {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.mailbox-actions,
.template-actions {
    display: flex;
    gap: 8px;
}

/* ============================================
   Pagination
   ============================================ */
.pagination {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 16px;
    margin-top: 20px;
}

.page-info {
    font-size: 12px;
    color: var(--text-muted);
}

/* ============================================
   Empty States
   ============================================ */
.empty-state {
    text-align: center;
    padding: 48px 24px;
    color: var(--text-muted);
    background: var(--bg-tertiary);
    border: 1px dashed var(--border-dark);
    border-radius: var(--radius-lg);
}

.empty-state p {
    margin-bottom: 8px;
}

/* Every loading state in the app was the literal string "Loading ..." sitting
   in grey. Nothing moved, so a slow request was indistinguishable from a
   broken one -- which is most of what "brittle" means to someone using it.

   `loading` is used two different ways in this codebase and they need
   different treatment:

     <div class="loading">Loading…</div>   a placeholder standing in for
                                           content that has not arrived
     el.classList.add('loading')           a state added to an element that
                                           already has its own layout -- a
                                           stat card, a submit button

   [class="loading"] matches only the first: an element whose class attribute
   is exactly "loading". Laying out the second kind as a padded flex row is
   what stretched the dashboard's stat cards to twice their height. */
.loading {
    color: var(--text-muted);
}

[class="loading"] {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    padding: 32px 20px;
}

[class="loading"]::before,
.btn.loading::before {
    content: "";
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    border: 2px solid var(--border-dark);
    border-top-color: var(--green-accent);
    border-radius: 50%;
    animation: spin 0.7s linear infinite;
}

/* A submit button mid-request spins in place; setLoading() swaps its label. */
.btn.loading::before {
    border-top-color: currentColor;
}

/* A stat card carrying the loading state keeps its own shape -- only the
   figure it is waiting on dims. */
.stat-card.loading .stat-value {
    opacity: 0.35;
}

/* Skeleton placeholder for content that has a known shape. Give an element
   .skeleton and a height and it shimmers until real content replaces it. */
.skeleton {
    position: relative;
    overflow: hidden;
    background: var(--bg-tertiary);
    border-radius: var(--radius-md);
    /* Never let a placeholder show borrowed text. */
    color: transparent;
    user-select: none;
}

.skeleton::after {
    content: "";
    position: absolute;
    inset: 0;
    transform: translateX(-100%);
    background: linear-gradient(90deg,
        transparent, rgba(255, 255, 255, 0.05), transparent);
    animation: shimmer 1.4s var(--ease) infinite;
}

@keyframes shimmer {
    to { transform: translateX(100%); }
}

.error {
    color: var(--danger);
}

/* ============================================
   Toast Notifications
   ============================================ */
#toast-container {
    position: fixed;
    top: 20px;
    right: 20px;
    z-index: 9999;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* The base toast was `background: var(--text-primary)` with `color: white`
   -- near-white text on a near-white fill, i.e. unreadable for any toast
   whose type does not match one of the three below.

   The variants were solid saturated fills, which shout against a palette
   this muted. A dark surface with a coloured edge and coloured label carries
   the same meaning and belongs to the interface it appears in. */
.toast {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 12px 16px 12px 14px;
    border-radius: var(--radius-md);
    border: 1px solid var(--border-dark);
    border-left: 3px solid var(--toast-accent, var(--text-muted));
    background: var(--bg-primary);
    /* The message is always body text. Only the edge and the dot carry the
       type, via --toast-accent, so a success toast does not turn its own
       sentence green. */
    color: var(--text-primary);
    font-size: 14px;
    box-shadow: var(--elev-3);
    transform: translateX(120%);
    opacity: 0;
    transition: transform var(--slow) var(--ease),
                opacity var(--slow) var(--ease);
}

.toast.show {
    transform: translateX(0);
    opacity: 1;
}

/* A dot in the accent colour, so the type reads at a glance without the whole
   panel changing colour. */
.toast::before {
    content: "";
    width: 7px;
    height: 7px;
    flex-shrink: 0;
    border-radius: 50%;
    background: var(--toast-accent, var(--text-muted));
}

.toast-success { --toast-accent: var(--success); }
.toast-error   { --toast-accent: var(--danger); }
.toast-info    { --toast-accent: var(--green-accent); }

/* ============================================
   Utilities
   ============================================ */
.mb-0 { margin-bottom: 0; }
.mb-4 { margin-bottom: 16px; }
.mt-2 { margin-top: 8px; }
.mt-4 { margin-top: 16px; }

/* ============================================
   Responsive
   ============================================ */
@media (max-width: 768px) {
    .sidebar {
        transform: translateX(-100%);
    }

    .main-content {
        margin-left: 0;
    }

    .leads-layout {
        grid-template-columns: 1fr;
    }

    .form-row {
        flex-direction: column;
        gap: 0;
    }

    .stats-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

/* ============================================
   Mailboxes Page
   ============================================ */
.mailboxes-grid {
    display: grid;
    gap: 16px;
}

.mailbox-card {
    background: var(--bg-tertiary);
    border-radius: var(--border-radius);
    padding: 20px;
    border: 1px solid var(--border-color);
}

.mailbox-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    margin-bottom: 16px;
}

.mailbox-info h3 {
    margin: 0 0 4px 0;
    color: var(--text-primary);
    font-size: 16px;
}

.mailbox-provider {
    background: var(--bg-hover);
    padding: 4px 10px;
    border-radius: 12px;
    font-size: 12px;
    color: var(--text-secondary);
    text-transform: uppercase;
}

.mailbox-actions {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}

/* Knowledge Base Tabs */
.kb-tabs {
    display: flex;
    gap: 4px;
    margin-bottom: 20px;
    border-bottom: 1px solid var(--border-color);
    padding-bottom: 8px;
}

.kb-tab {
    background: transparent;
    border: none;
    color: var(--text-muted);
    padding: 8px 16px;
    cursor: pointer;
    border-radius: 6px 6px 0 0;
    transition: all 0.2s;
}

.kb-tab:hover {
    color: var(--text-primary);
    background: var(--bg-hover);
}

.kb-tab.active {
    color: var(--primary);
    background: var(--bg-tertiary);
    border-bottom: 2px solid var(--primary);
}

.kb-tab-content {
    display: none;
}

.kb-tab-content.active {
    display: block;
}

.kb-header {
    margin-bottom: 16px;
}

.kb-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.kb-item {
    background: var(--bg-primary);
    border-radius: var(--border-radius);
    padding: 16px;
    border: 1px solid var(--border-color);
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 16px;
}

.kb-item-content {
    flex: 1;
}

.kb-item .kb-label {
    font-weight: 600;
    color: var(--text-primary);
    margin-bottom: 4px;
}

.kb-item .kb-value {
    color: var(--text-secondary);
    font-size: 14px;
}

.kb-item-actions {
    display: flex;
    gap: 8px;
}

.system-prompt-section textarea {
    width: 100%;
    min-height: 200px;
    font-family: monospace;
    font-size: 13px;
    margin-bottom: 16px;
}

/* AI Provider Settings */
.ai-provider-settings {
    margin-top: 16px;
    padding-top: 16px;
    border-top: 1px solid var(--border-color);
}

.provider-settings {
    margin-top: 16px;
}

/* Modal Fullwidth */
.modal-fullwidth {
    max-width: 800px;
    width: 95%;
}

.modal-lg .modal-content {
    max-width: 900px;
}

/* ============================================
   Inbox Styles (Matches Chrome Extension)
   ============================================ */
.inbox-container {
    height: 100%;
    display: flex;
    flex-direction: column;
}

.inbox-header {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin-bottom: 16px;
}

.inbox-header-top {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
}

.inbox-header h3 {
    margin: 0;
    font-size: 18px;
    color: var(--text-primary);
}

.inbox-actions {
    display: flex;
    gap: 8px;
}

.inbox-btn {
    padding: 6px 12px;
    background: var(--bg-tertiary);
    border: 1px solid var(--forest-green);
    border-radius: 6px;
    cursor: pointer;
    transition: all 0.2s ease;
    font-size: 11px;
    font-weight: 600;
    color: var(--sage-green);
    white-space: nowrap;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.inbox-btn:hover {
    background: var(--bg-hover);
    border-color: var(--sage-green);
    color: var(--mint-green);
    transform: translateY(-1px);
}

.inbox-btn svg {
    width: 14px;
    height: 14px;
    stroke: currentColor;
}

.inbox-btn.refreshing svg {
    animation: spin 1s linear infinite;
}

@keyframes spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}

.mailbox-selector {
    padding: 10px 38px 10px 12px;
    /* background-color, not the `background` shorthand: the shorthand resets
       background-image and would erase the chevron drawn in components.css. */
    background-color: var(--bg-tertiary);
    border: 1px solid var(--border-dark);
    border-radius: var(--radius-md);
    font-size: 13px;
    color: var(--text-primary);
    cursor: pointer;
    width: 100%;
}

.mailbox-selector:hover {
    border-color: var(--green-mid);
}

.mailbox-selector:focus-visible {
    outline: none;
    border-color: var(--green-accent);
    box-shadow: var(--focus-ring);
}

.email-list {
    flex: 1;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.email-item {
    background: var(--bg-tertiary);
    border: 1px solid var(--border-color);
    border-radius: 6px;
    padding: 12px;
    cursor: pointer;
    transition: all 0.2s ease;
}

.email-item:hover {
    border-color: var(--sage-green);
    box-shadow: 0 2px 8px rgba(0,0,0,0.3);
    transform: translateY(-1px);
}

.email-item.unread {
    background: var(--bg-primary);
    border-left: 3px solid var(--mint-green);
}

.email-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    margin-bottom: 4px;
}

.email-from {
    font-weight: 600;
    color: var(--text-primary);
    font-size: 13px;
}

.email-item.unread .email-from {
    font-weight: 700;
}

.email-time {
    font-size: 11px;
    color: var(--text-muted);
}

.email-subject {
    font-size: 14px;
    font-weight: 500;
    color: var(--text-primary);
    margin-bottom: 4px;
}

.email-item.unread .email-subject {
    font-weight: 600;
}

.email-preview {
    font-size: 12px;
    color: var(--text-muted);
    line-height: 1.4;
    /* Keep every row the same height: clamp to two lines and never let a long
       unbroken token widen the list. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    overflow-wrap: anywhere;
}

/* Auto-Response Badge */
.auto-response-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-top: 8px;
    padding: 4px 10px;
    background: linear-gradient(135deg, var(--forest-green), var(--sage-green));
    /* --radius-sm, not the 12px card radius: on a 23px-tall chip a 12px
       radius is more than half the height, so it renders as an oval. */
    border-radius: var(--radius-sm);
    font-size: 11px;
    font-weight: 600;
    color: var(--mint-green);
    cursor: pointer;
}

.auto-response-badge:hover {
    opacity: 0.9;
}

.badge-icon {
    font-size: 12px;
}

.expand-icon {
    font-size: 10px;
    margin-left: 4px;
}

.ai-response-section {
    margin-top: 8px;
    padding: 10px;
    background: var(--bg-primary);
    border-radius: 6px;
    border-left: 2px solid var(--sage-green);
}

.ai-response-section.hidden {
    display: none;
}

.ai-response-preview {
    font-size: 12px;
    color: var(--text-secondary);
    line-height: 1.5;
}

/* Email Detail Modal */
.email-detail-modal-content {
    max-width: 880px;
    width: 95%;
    /* Column layout so the header and footer stay put and only the message
       scrolls -- previously the whole modal grew and the buttons drifted. */
    display: flex;
    flex-direction: column;
    max-height: 88vh;
}

.email-detail-header {
    min-width: 0;
    padding-right: 12px;
}

.email-detail-header h3 {
    margin: 0 0 6px 0;
    font-size: 17px;
    line-height: 1.35;
    color: var(--text-primary);
    overflow-wrap: anywhere;
}

.email-detail-meta {
    font-size: 12px;
    color: var(--text-muted);
}

.email-detail-body {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    /* Never scroll sideways; the frame constrains its own content. */
    overflow-x: hidden;
    background: var(--bg-secondary);
}

/* The message renders as a white sheet inside the dark chrome, the way a mail
   client shows one. Email HTML assumes a white page, so giving it one is what
   makes the fonts and colours read correctly. */
#emailDetailContent {
    margin-bottom: 16px;
}

.email-frame {
    display: block;
    width: 100%;
    min-height: 120px;
    border: 0;
    border-radius: 8px;
    background: #fff;
    box-shadow: var(--shadow-sm);
}

.email-plaintext {
    background: #fff;
    color: #1f2328;
    border-radius: 8px;
    padding: 20px;
    box-shadow: var(--shadow-sm);
    font-size: 14px;
    line-height: 1.65;
    /* Plain-text mail carries its own line breaks; keep them, and break long
       URLs rather than letting them widen the panel. */
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

#aiResponseSection {
    margin-top: 16px;
    padding: 16px;
    background: var(--bg-tertiary);
    border-radius: 8px;
    border-left: 3px solid var(--sage-green);
}

.ai-response-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 12px;
}

.ai-badge {
    background: var(--sage-green);
    color: var(--on-accent);
    padding: 4px 10px;
    border-radius: 12px;
    font-size: 11px;
    font-weight: 600;
}

.ai-response-content {
    color: var(--text-secondary);
    line-height: 1.6;
    font-size: 14px;
}

/* --- the reply composer ------------------------------------------------
   This textarea set width and height and NOTHING else. Every other field in
   the app is styled through `.form-group input, .form-group select,
   .form-group textarea`, and this one is not inside a .form-group -- so it
   fell all the way back to the browser default and rendered as a white box
   with a black border in the middle of a dark dialog.

   It is also docked here between the message and the footer, rather than
   living at the bottom of the scrolling body where it opened below the fold. */
.email-composer {
    display: grid;
    gap: 10px;
    flex-shrink: 0;
    padding: 16px 20px;
    background: var(--bg-tertiary);
    border-top: 1px solid var(--border-color);
}

.email-composer-to {
    font-size: 12px;
    color: var(--text-muted);
}

.email-composer-to strong {
    color: var(--text-primary);
    font-weight: 600;
}

#replyText {
    width: 100%;
    min-height: 96px;
    max-height: 40vh;
    padding: 11px 13px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-dark);
    border-radius: var(--radius-md);
    color: var(--text-primary);
    /* Without this a textarea uses the browser's monospace default, which is
       why the placeholder looked like code. */
    font: inherit;
    font-size: 14px;
    line-height: 1.6;
    resize: vertical;
    transition: border-color var(--fast) var(--ease),
                box-shadow var(--fast) var(--ease);
}

#replyText::placeholder { color: var(--text-muted); }

#replyText:focus {
    outline: none;
    /* A big field does not need a ring drawn around it as well -- the border
       lighting up is enough, and the ring was the "glowing line". */
    border-color: var(--green-accent);
    background: var(--bg-primary);
}

.reply-actions {
    display: flex;
    align-items: center;
    gap: 10px;
}

/* Send is the action; Cancel is the way out. Sizing them identically, as
   before, made the pair read as two equally weighted options. */
.reply-actions .btn-primary {
    padding: 9px 20px;
    font-size: 14px;
}

.reply-actions .btn-outline {
    padding: 9px 14px;
    background: transparent;
    border-color: transparent;
    color: var(--text-muted);
    font-size: 14px;
}

.reply-actions .btn-outline:hover:not(:disabled) {
    background: var(--bg-hover);
    border-color: transparent;
    color: var(--text-primary);
}

/* The hint takes the slack, pushing the actions to the right where the eye
   ends up after reading the message. */
.email-composer-hint {
    margin-right: auto;
    font-size: 12px;
    color: var(--text-muted);
}

/* --- the sender block --------------------------------------------------
   The header used to print the raw From header, quotes and angle brackets
   and all. Name, address and time are separate things and are laid out as
   such, with an avatar to anchor the row. */
.email-head { align-items: flex-start; gap: 16px; }

.email-head-main { min-width: 0; flex: 1; }

.email-head-main h3 {
    margin: 0 0 8px;
    font-size: 17px;
    line-height: 1.35;
    color: var(--text-primary);
    overflow-wrap: anywhere;
}

.email-sender {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
}

.email-sender .favatar { width: 30px; height: 30px; font-size: 12px; }

.email-sender-who {
    display: grid;
    min-width: 0;
    line-height: 1.35;
}

.email-sender-name {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.email-sender-address {
    font-size: 12px;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.email-sender-address:empty { display: none; }

.email-sender-when {
    margin-left: auto;
    padding-left: 12px;
    flex-shrink: 0;
    font-size: 12px;
    color: var(--text-muted);
}

/* The message sheet needs air around it; it was butting against the dialog
   edges, which is what made the white block look pasted on. */
.email-detail-body { padding: 18px 20px; }

/* Footer actions read left-to-right as secondary then primary, so the send
   path ends at the right-hand edge. */
.modal-footer .btn-outline:not(:last-child) { margin-left: auto; }

/* Standard indeterminate ring spinner. Keep this element EMPTY: text placed
   inside it rotates with the ring and spills out of the circle. When a caption
   is needed use .loading-state below. (`spin` is defined once, further up.) */
.loading-spinner {
    width: 40px;
    height: 40px;
    box-sizing: border-box;
    border: 3px solid var(--border-color);
    border-top-color: var(--primary);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
    margin: 40px auto;
}

/* Ring with a caption underneath. The caption is a SIBLING of the ring, so it
   stays still while only the ring turns. */
.loading-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 40px 20px;
    color: var(--text-muted);
}

.loading-state .loading-spinner {
    margin: 0;
}

/* Respect a reduced-motion preference by slowing the ring rather than
   freezing it, so it still reads as "busy". */
@media (prefers-reduced-motion: reduce) {
    .loading-spinner {
        animation-duration: 2.4s;
    }
}

.loading-spinner-sm {
    width: 20px;
    height: 20px;
    border-width: 2px;
    margin: 0;
    display: inline-block;
}

/* KB Subtabs in Settings */
.kb-subtabs {
    display: flex;
    gap: 4px;
    margin: 16px 0;
    border-bottom: 1px solid var(--border-color);
    padding-bottom: 8px;
}

.kb-subtab {
    background: transparent;
    border: none;
    color: var(--text-muted);
    padding: 8px 16px;
    cursor: pointer;
    border-radius: 6px 6px 0 0;
    font-size: 13px;
}

.kb-subtab:hover {
    color: var(--text-primary);
    background: var(--bg-hover);
}

.kb-subtab.active {
    color: var(--primary);
    background: var(--bg-tertiary);
    border-bottom: 2px solid var(--primary);
}

.kb-subtab-content {
    display: none;
}

.kb-subtab-content.active {
    display: block;
}

#system-prompt {
    width: 100%;
    min-height: 200px;
    font-family: monospace;
    font-size: 13px;
}

/* ============================================
   Settings Page - Chrome Extension Style
   ============================================ */
.settings-section {
    background: var(--bg-primary);
    border-radius: var(--border-radius);
    margin-bottom: 16px;
    border: 1px solid var(--border-color);
}

.section-header {
    padding: 16px 20px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    cursor: pointer;
}

.section-header h3 {
    margin: 0;
    font-size: 15px;
    font-weight: 600;
}

.section-header.collapsible:hover {
    background: var(--bg-hover);
}

.collapse-icon {
    font-size: 12px;
    color: var(--text-muted);
}

.section-content {
    padding: 16px 20px;
    border-top: 1px solid var(--border-color);
}

/* Mailbox List Header */
.mailbox-list-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 16px;
}

.mailbox-counter {
    display: flex;
    align-items: center;
    gap: 12px;
}

.mailbox-counter h4 {
    margin: 0;
    font-size: 14px;
    font-weight: 600;
}

.count-badge {
    font-size: 12px;
    color: var(--sage-green);
    padding: 4px 8px;
    background: rgba(92, 110, 104, 0.2);
    border-radius: 4px;
}

/* Mailbox Items - Each with KB and AI buttons */
.mailbox-items {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* A whole row is the target: on its own page the row opens the mailbox, so
   there is nothing else in it to aim at. */
.mailbox-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
    padding: 14px 16px;
    font-family: inherit;
    text-align: left;
    background: var(--bg-tertiary);
    border-radius: 6px;
    border: 1px solid var(--border-color);
    cursor: pointer;
    transition: border-color 0.15s, background 0.15s;
}

.mailbox-item:hover {
    border-color: var(--green-mid);
    background: var(--bg-hover);
}

.mailbox-item:focus-visible {
    outline: 2px solid var(--green-accent);
    outline-offset: 2px;
}

.mailbox-meta {
    display: flex;
    align-items: center;
    gap: 14px;
    font-size: 12px;
    color: var(--text-muted);
}

.mailbox-item:hover .mailbox-go { color: var(--green-bright); }

.mailbox-go { font-size: 15px; transition: color 0.15s; }

.mailbox-info {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.mailbox-name {
    font-weight: 600;
    font-size: 14px;
    color: var(--text-primary);
}

.mailbox-email {
    font-size: 12px;
    color: var(--text-muted);
}

.mailbox-actions {
    display: flex;
    gap: 8px;
}

.mailbox-actions .btn {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 6px 10px;
    font-size: 12px;
}

.mailbox-actions .btn svg {
    flex-shrink: 0;
}

/* KB Modal - Fixed Height for Stability */
.kb-modal .modal-content {
    max-width: 700px;
    height: 600px;
    max-height: 85vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.kb-modal .modal-header {
    flex-shrink: 0;
    padding: 20px 24px;
    background: linear-gradient(180deg, rgba(92, 110, 104, 0.08) 0%, transparent 100%);
    border-bottom: 1px solid var(--border-color);
}

.kb-modal .modal-header h3 {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 16px;
    font-weight: 600;
}

.kb-modal .modal-header h3::before {
    content: '';
    width: 8px;
    height: 8px;
    background: var(--primary);
    border-radius: 50%;
}

.kb-modal .modal-body {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    padding: 0;
}

/* KB Tabs - Pill Style */
.kb-tabs {
    display: flex;
    gap: 6px;
    padding: 16px 24px;
    background: var(--bg-secondary);
    border-bottom: 1px solid var(--border-color);
    flex-shrink: 0;
}

.kb-tab {
    flex: 1;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 8px;
    color: var(--text-muted);
    padding: 10px 16px;
    cursor: pointer;
    font-size: 13px;
    font-weight: 500;
    text-align: center;
    transition: all 0.2s ease;
}

.kb-tab:hover {
    background: var(--bg-hover);
    color: var(--text-primary);
}

.kb-tab.active {
    background: var(--primary);
    border-color: var(--primary);
    color: white;
    font-weight: 600;
}

/* Tab Content Container - Fixed Height */
.kb-tab-container {
    flex: 1;
    position: relative;
    overflow: hidden;
}

.kb-tab-content {
    display: none;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    overflow-y: auto;
    padding: 24px;
}

.kb-tab-content.active {
    display: block;
}

.kb-section {
    padding: 0;
}

.kb-section p.text-muted {
    margin-bottom: 16px;
    font-size: 13px;
    line-height: 1.5;
}

.kb-actions {
    display: flex;
    gap: 10px;
    margin-top: 16px;
}

.kb-header {
    margin-bottom: 16px;
}

.kb-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.kb-item {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    padding: 14px 16px;
    background: var(--bg-tertiary);
    border-radius: 10px;
    border: 1px solid var(--border-color);
    transition: all 0.2s ease;
}

.kb-item:hover {
    border-color: var(--border-on);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.kb-item-content {
    flex: 1;
    min-width: 0;
}

.kb-label {
    font-weight: 600;
    font-size: 13px;
    color: var(--text-primary);
    margin-bottom: 6px;
}

.kb-value {
    font-size: 12px;
    color: var(--text-muted);
    white-space: pre-wrap;
    word-break: break-word;
    line-height: 1.5;
}

.kb-item-actions {
    display: flex;
    gap: 6px;
    margin-left: 12px;
}

/* System Prompt Textarea */
.kb-modal #system-prompt {
    width: 100%;
    min-height: 200px;
    padding: 14px;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-color);
    border-radius: 10px;
    color: var(--text-primary);
    font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
    font-size: 13px;
    line-height: 1.6;
    resize: none;
    transition: border-color 0.2s ease;
}

.kb-modal #system-prompt:focus {
    outline: none;
    border-color: var(--primary);
}

/* Empty state for KB lists */
.kb-list:empty::after {
    content: 'No items yet. Click the button above to add one.';
    display: block;
    padding: 40px 20px;
    text-align: center;
    color: var(--text-muted);
    font-size: 13px;
    border: 2px dashed var(--border-color);
    border-radius: 10px;
}

/* .btn-icon now lives once, in components.css. */

/* Account Details */
.account-details {
    background: var(--bg-tertiary);
    padding: 16px;
    border-radius: 6px;
}

.detail-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
}

.detail-row:last-child {
    margin-bottom: 0;
}

.detail-label {
    font-weight: 600;
    color: var(--text-primary);
    min-width: 80px;
}

.account-actions {
    margin-top: 16px;
}

/* Template List */
.template-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.template-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 12px 16px;
    background: var(--bg-tertiary);
    border-radius: 6px;
    border: 1px solid var(--border-color);
}

.template-info {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.template-actions {
    display: flex;
    gap: 8px;
}

/* ============================================
   Document Upload Styles
   ============================================ */
.file-upload-area {
    border: 2px dashed var(--border-color);
    border-radius: var(--border-radius);
    padding: 32px;
    text-align: center;
    cursor: pointer;
    transition: all 0.2s ease;
    background: var(--bg-secondary);
}

.file-upload-area:hover,
.file-upload-area.drag-over {
    border-color: var(--border-on);
    background: var(--bg-hover);
}

.upload-placeholder {
    color: var(--text-muted);
}

.upload-placeholder svg {
    margin-bottom: 12px;
    opacity: 0.6;
}

.upload-placeholder p {
    margin: 8px 0 4px;
    color: var(--text-secondary);
}

.upload-placeholder small {
    color: var(--text-muted);
}

.upload-link {
    color: var(--primary);
    text-decoration: underline;
    cursor: pointer;
}

.upload-progress {
    padding: 16px 0;
}

.progress-bar {
    height: 6px;
    /* A track is a well, not a form field -- --bg-tertiary is already the
       token for that and themes it correctly in both directions. */
    background: var(--bg-tertiary);
    /* An empty track was invisible against the card, so a draft campaign at 0%
       had no bar at all and its row sat differently from every other row. */
    border: 1px solid var(--border-color);
    border-radius: 999px;
    overflow: hidden;
    margin-bottom: 10px;
}

.progress-fill {
    height: 100%;
    background: linear-gradient(90deg, var(--green-mid), var(--green-accent));
    border-radius: 999px;
    transition: width var(--slow) var(--ease);
    width: 0%;
}

#upload-status {
    color: var(--text-secondary);
    font-size: 13px;
}

/* Document item in KB list */
.doc-item .kb-item-content {
    display: flex;
    align-items: center;
    gap: 12px;
}

.doc-icon {
    font-size: 24px;
    flex-shrink: 0;
}

.doc-info {
    flex: 1;
    min-width: 0;
}

.doc-info .kb-label {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ============================================
   Campaign Card Styles
   ============================================ */
.campaign-card {
    /* --bg-secondary is the page background: these cards were DARKER than the
       panel holding them, so each read as a hole punched in the card rather
       than an object resting on it. --bg-tertiary is the raised list-row tone,
       which is what a card inside a card should be. */
    background: var(--bg-tertiary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    padding: 16px;
    margin-bottom: 12px;
    box-shadow: var(--elev-1);
    transition: border-color var(--fast) var(--ease),
                box-shadow var(--fast) var(--ease);
}

.campaign-card:hover {
    border-color: var(--green-mid);
    box-shadow: var(--elev-2);
}

.campaign-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    margin-bottom: 12px;
}

.campaign-info {
    display: flex;
    align-items: center;
    gap: 12px;
}

.campaign-name {
    font-size: 16px;
    font-weight: 600;
    color: var(--text-primary);
    margin: 0;
}

.campaign-status {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    padding: 3px 8px;
    border-radius: 4px;
}

.campaign-status.status-draft {
    background: rgba(151, 161, 155, 0.16);
    color: var(--text-muted);
}

.campaign-status.status-active {
    background: rgba(127, 160, 150, 0.2);
    color: var(--success);
}

.campaign-status.status-paused {
    background: rgba(212, 165, 116, 0.2);
    color: var(--warning);
}

.campaign-status.status-completed {
    background: rgba(127, 160, 150, 0.3);
    color: var(--primary-light);
}

.campaign-status.status-deleted {
    background: rgba(232, 139, 130, 0.2);
    color: var(--danger);
}

.campaign-actions {
    display: flex;
    gap: 8px;
}

.campaign-progress {
    margin-bottom: 12px;
}

.campaign-progress .progress-bar {
    height: 8px;
    background: var(--bg-tertiary);
    border-radius: 4px;
    overflow: hidden;
    margin-bottom: 8px;
}

.campaign-progress .progress-fill {
    height: 100%;
    background: var(--primary);
    border-radius: 4px;
    transition: width 0.3s ease;
}

.progress-stats {
    display: flex;
    gap: 16px;
    font-size: 13px;
    color: var(--text-secondary);
}

/* This line was three semantic colours at once -- green, amber and grey --
   for one row of neutral counts, so a healthy campaign looked like it was
   warning about something. Only a real failure earns a semantic colour; the
   rest is a reading hierarchy. */
.progress-stats .sent {
    color: var(--text-primary);
    font-weight: 600;
}

.progress-stats .pending {
    color: var(--text-secondary);
}

.progress-stats .failed {
    color: var(--danger);
}

/* Skipped is not a failure: they replied, bounced or unsubscribed first. */
.progress-stats .skipped {
    color: var(--text-secondary);
    cursor: help;
}

.progress-stats .total {
    color: var(--text-muted);
}

/* Two unrelated facts were butted together with a gap and nothing between
   them; the separator makes them read as a list rather than a run-on. */
.campaign-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 12px;
    font-size: 12px;
    color: var(--text-muted);
}

.campaign-meta > span + span::before {
    content: "·";
    margin-right: 12px;
    /* Punctuation, not a border. It borrowed --border-dark back when that was
       a bright control tone; that token is now a quiet edge, and a separator
       belongs on the text scale regardless. */
    color: var(--text-muted);
}

/* .btn-danger was defined HERE as well as in components.css. pages.css loads
   last, so this copy silently won and editing the component definition did
   nothing. There is now one definition, in components.css, where the rest of
   the button variants live. */

/* ============================================
   LEADS PAGE STYLES
   ============================================ */

.leads-page {
    padding: 24px;
}

.leads-page .page-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 24px;
}

.leads-page .page-header h1 {
    margin: 0;
    font-size: 24px;
    color: var(--text-primary);
}

/* Tab Navigation */
.leads-page .tab-nav {
    display: flex;
    gap: 0;
    margin-bottom: 20px;
    border-bottom: 1px solid var(--border-color);
}

.leads-page .tab-btn {
    padding: 12px 24px;
    border: none;
    background: transparent;
    color: var(--text-secondary);
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    transition: all 0.2s ease;
}

.leads-page .tab-btn:hover {
    color: var(--text-primary);
}

.leads-page .tab-btn.active {
    color: var(--primary);
    border-bottom-color: var(--primary);
}

/* Contacts Toolbar */
.contacts-toolbar {
    display: flex;
    gap: 12px;
    align-items: center;
    margin-bottom: 16px;
    flex-wrap: wrap;
}

.contacts-toolbar .search-input {
    flex: 1;
    min-width: 200px;
    padding: 10px 14px;
    border: 1px solid var(--border-color);
    border-radius: 6px;
    background: var(--bg-secondary);
    color: var(--text-primary);
    font-size: 14px;
}

.contacts-toolbar .search-input:focus {
    outline: none;
    border-color: var(--primary);
}

.contacts-toolbar .toolbar-actions {
    display: flex;
    gap: 8px;
}

/* Contacts Table */
/* .contacts-table now lives once, in components.css. */

.contacts-table .btn-icon {
    padding: 6px;
    background: transparent;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    border-radius: 4px;
    transition: all 0.2s ease;
}

.contacts-table .btn-icon:hover {
    background: var(--bg-hover);
    color: var(--primary);
}

/* Contact table cell content */
.contact-email {
    font-weight: 500;
    color: var(--text-primary);
}

.contact-name,
.contact-title {
    font-size: 12px;
    margin-top: 2px;
}

.contact-domain {
    font-weight: 500;
    color: var(--text-primary);
}

.contact-phone {
    color: var(--primary);
    text-decoration: none;
}

.contact-phone:hover {
    text-decoration: underline;
}

.contact-links {
    display: flex;
    gap: 8px;
    align-items: center;
}

.social-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 4px;
    color: var(--text-muted);
    transition: all 0.2s ease;
}

.social-link:hover {
    background: var(--bg-hover);
}

.social-link.linkedin {
    color: #0077b5;
}

.social-link.linkedin:hover {
    background: rgba(0, 119, 181, 0.1);
}

.social-link.twitter {
    color: #000000;
}

.social-link.twitter:hover {
    background: rgba(0, 0, 0, 0.1);
}

.social-link.facebook {
    color: #1877f2;
}

.social-link.facebook:hover {
    background: rgba(24, 119, 242, 0.1);
}

.social-link.instagram {
    color: #e4405f;
}

.social-link.instagram:hover {
    background: rgba(228, 64, 95, 0.1);
}

.social-link.youtube {
    color: #ff0000;
}

.social-link.youtube:hover {
    background: rgba(255, 0, 0, 0.1);
}

.social-link.website {
    color: var(--primary);
}

.social-link.website:hover {
    background: rgba(127, 160, 150, 0.15);
}

/* Lists Layout */
.lists-layout {
    display: grid;
    grid-template-columns: 280px 1fr;
    gap: 20px;
}

.lists-sidebar .card {
    position: sticky;
    top: 20px;
}

.list-items {
    list-style: none;
    margin: 0;
    padding: 0;
}

.list-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 12px;
    border-radius: 6px;
    cursor: pointer;
    transition: all 0.2s ease;
}

.list-item:hover {
    background: var(--bg-hover);
}

.list-item.active {
    background: rgba(127, 160, 150, 0.15);
    border-left: 3px solid var(--primary);
}

.list-info {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.list-name {
    font-weight: 500;
    color: var(--text-primary);
}

.list-count {
    font-size: 12px;
    color: var(--text-muted);
}

.list-actions {
    opacity: 0;
    transition: opacity 0.2s ease;
}

.list-item:hover .list-actions {
    opacity: 1;
}

/* Pagination */
.pagination-controls {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 16px;
    padding: 12px 0;
}

.pagination-info {
    font-size: 13px;
    color: var(--text-muted);
}

.pagination-buttons {
    display: flex;
    gap: 8px;
}

/* Responsive */
@media (max-width: 768px) {
    .lists-layout {
        grid-template-columns: 1fr;
    }

    .contacts-toolbar {
        flex-direction: column;
        align-items: stretch;
    }

    .contacts-toolbar .toolbar-actions {
        justify-content: flex-end;
    }
}

/* ============================================
   Admin
   ============================================ */
.admin-search {
    width: 260px;
    max-width: 45%;
    padding: 8px 12px;
    border: 1px solid var(--border-dark);
    border-radius: var(--border-radius);
    background: var(--bg-input);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 14px;
}

.admin-search:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px var(--sage-glow);
}

.admin-search::placeholder {
    color: var(--text-muted);
}

/* Keep row actions on one line and let .contacts-table-wrapper scroll,
   rather than wrapping them into a ragged stack. */
.admin-actions-col {
    width: 1%;
    white-space: nowrap;
}

.admin-row-actions {
    display: flex;
    gap: 6px;
    white-space: nowrap;
}

.admin-row-actions .btn {
    padding: 4px 10px;
}

.admin-danger:hover {
    border-color: var(--danger);
    color: var(--danger);
}

/* The "Admin" badge sits inline beside the email address, so it must not
   inherit the standalone spacing the status badges use in their own column. */
.admin-page .contacts-table .badge {
    margin-left: 8px;
    vertical-align: middle;
}

.admin-checkbox-row label {
    display: flex;
    align-items: center;
    gap: 8px;
    font-weight: 500;
    cursor: pointer;
}

.admin-checkbox-row input[type="checkbox"] {
    width: auto;
    margin: 0;
}

/* ============================================
   Settings — the account

   Three short sections that do not collapse. Collapsing existed because this
   page also carried a mailbox list and a template list; with those gone,
   folding away three forms only hides them.
   ============================================ */
.acct-sub {
    margin: 4px 0 0;
    max-width: 60ch;
    font-size: 13px;
    color: var(--text-muted);
}

.acct-form { max-width: 720px; }

.acct-note {
    margin: 6px 0 0;
    font-size: 12px;
    line-height: 1.5;
}

.acct-photo-row {
    display: flex;
    align-items: center;
    gap: 20px;
    margin-bottom: 24px;
    padding-bottom: 20px;
    border-bottom: 1px solid var(--border-color);
}

/* The same circle the Community draws, at a size worth looking at while you
   choose one. */
.acct-photo {
    display: grid;
    place-items: center;
    flex-shrink: 0;
    width: 84px;
    height: 84px;
    font-size: 26px;
    font-weight: 600;
    color: var(--green-bright);
    background: var(--green-deep);
    border-radius: 50%;
    overflow: hidden;
}

.acct-photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.acct-photo-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* The hint takes the whole second line rather than being squeezed beside the
   buttons. */
.acct-photo-actions .acct-note { flex-basis: 100%; margin: 0; }

.acct-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    margin: 4px 0 18px;
    font-size: 12px;
    color: var(--text-muted);
}

@media (max-width: 640px) {
    .acct-photo-row { flex-direction: column; align-items: flex-start; }
}

/* ============================================
   Templates — a library

   Was two lines and two buttons per row inside a settings section, which is
   adequate for three templates and useless for thirty. A card carries the
   opening of the body, because what you are doing on this page is
   recognising something you wrote weeks ago.
   ============================================ */
.templates-page { max-width: 1100px; }

.tpl-sub {
    margin: 4px 0 0;
    max-width: 60ch;
    font-size: 13px;
    color: var(--text-muted);
}

.tpl-search {
    width: 220px;
    padding: 7px 12px;
    font-size: 13px;
    font-family: inherit;
    color: var(--text-primary);
    background: var(--bg-input);
    border: 1px solid var(--border-color);
    border-radius: 999px;
}

.tpl-search:focus {
    outline: none;
    border-color: var(--green-accent);
    box-shadow: 0 0 0 3px var(--mint-glow);
}

.tpl-count {
    margin: 0 0 12px;
    font-size: 12px;
    color: var(--text-muted);
}

.tpl-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 12px;
}

.tpl-card {
    display: flex;
    flex-direction: column;
    padding: 16px;
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    transition: border-color 0.15s;
}

.tpl-card:hover { border-color: var(--green-mid); }

.tpl-card h3 {
    margin: 0 0 4px;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
}

.tpl-subject {
    margin: 0 0 8px;
    font-size: 13px;
    color: var(--text-secondary);
}

.tpl-preview {
    margin: 0 0 14px;
    font-size: 12px;
    line-height: 1.55;
    color: var(--text-muted);
    /* Three lines: enough to recognise it, short enough that a grid of them
       still scans. */
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* Pushed to the bottom so cards of different preview lengths still line up. */
.tpl-actions {
    display: flex;
    gap: 14px;
    margin-top: auto;
    font-size: 12px;
}

.tpl-actions button {
    padding: 0;
    font-size: 12px;
    font-family: inherit;
    font-weight: 500;
    color: var(--text-muted);
    background: none;
    border: 0;
    cursor: pointer;
}

.tpl-actions button:hover { color: var(--green-bright); }

.tpl-actions .tpl-danger:hover { color: var(--danger); }

.tpl-actions button:focus-visible {
    outline: 2px solid var(--green-accent);
    outline-offset: 3px;
    border-radius: 3px;
}

@media (max-width: 640px) {
    .tpl-search { width: 100%; }
}

/* ============================================
   Mailboxes — the page, not a settings section

   Was a collapsed block inside Settings whose rows opened a modal carrying
   five tabs. The tabs are still five; they are page tabs now, which is the
   difference between a dialog you dismiss and a screen you can link to.
   ============================================ */
.mailboxes-page { max-width: 900px; }

.mb-sub {
    margin: 4px 0 0;
    max-width: 60ch;
    font-size: 13px;
    color: var(--text-muted);
}

.mb-crumbs { margin-bottom: 14px; }

.mb-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-bottom: 20px;
    border-bottom: 1px solid var(--border-color);
}

.mb-tab {
    padding: 9px 14px;
    font-size: 13px;
    font-family: inherit;
    color: var(--text-secondary);
    background: none;
    border: 0;
    /* The underline is the marker, so an inactive tab carries a transparent
       one and the label does not shift when it lights up. */
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    cursor: pointer;
    transition: color 0.15s, border-color 0.15s;
}

.mb-tab:hover { color: var(--text-primary); }

.mb-tab.active {
    color: var(--green-bright);
    border-bottom-color: var(--green-accent);
}

.mb-tab:focus-visible {
    outline: 2px solid var(--green-accent);
    outline-offset: -2px;
}

/* Only the open tab is in the document flow. Panes are rebuilt on every
   navigation, so nothing stale is left behind a hidden one. */
.mb-pane { display: none; }
.mb-pane.active { display: block; }

.mb-panes .card { margin-bottom: 16px; }

.mb-panes .card:last-child { margin-bottom: 0; }

/* The panes were lifted out of the KB modal, where this wrapper supplied the
   padding. On a page the card already does. */
.kb-section-wrap .kb-section { padding: 0; }

/* ============================================
   Community — one feed, and conversations that branch

   What this replaced was three nested tables: categories with counter
   columns, opening onto topics with counter columns, opening onto posts in a
   numbered stack with a 168px author card down the left of every one. Every
   layer spent its width on numbers and its vertical space on chrome, and the
   text people had actually written lived in whatever was left.

   The measurements here follow from one decision: the column is for reading.
   The feed is capped near 800px because that is about 90 characters at this
   size, comments indent 14px a level rather than 40 so a deep branch still
   has a column to live in, and the only numbers left on a card are the
   comment count and the view count.
   ============================================ */
.forum { max-width: 820px; }

.feed-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 20px;
    flex-wrap: wrap;
    margin-bottom: 22px;
}

.feed-head h1 {
    margin: 0 0 4px;
    font-size: 24px;
    font-weight: 600;
    color: var(--text-primary);
}

.fmeta {
    margin: 0;
    font-size: 13px;
    color: var(--text-muted);
}

/* --- the composer ---------------------------------------------------------
   Shut, it is one line that looks like somewhere to type, because the first
   thing on a community page should be the invitation to write. The old
   version was a button that opened a modal whose first field was a dropdown
   of rooms to file yourself into before you were allowed to start. */
.fcompose {
    margin-bottom: 16px;
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
}

.fcompose-shut {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
}

.fcompose-open {
    flex: 1;
    min-width: 0;
    padding: 9px 14px;
    text-align: left;
    font-size: 14px;
    font-family: inherit;
    color: var(--text-muted);
    background: var(--bg-tertiary);
    border: 1px solid var(--border-color);
    border-radius: 999px;
    cursor: pointer;
    transition: border-color 0.15s, color 0.15s;
}

.fcompose-open:hover {
    border-color: var(--green-mid);
    color: var(--text-secondary);
}

.fcompose-open:focus-visible {
    outline: 2px solid var(--green-accent);
    outline-offset: 2px;
}

.fcompose-open-form { padding: 14px; display: grid; gap: 12px; }

.fcompose-row { display: flex; align-items: center; gap: 10px; }

.fcompose-title,
.fcompose-body {
    width: 100%;
    padding: 10px 12px;
    font-family: inherit;
    color: var(--text-primary);
    background: var(--bg-secondary);
    border: 1px solid var(--border-dark);
    border-radius: 6px;
}

.fcompose-title { font-size: 15px; font-weight: 600; }

.fcompose-body { font-size: 14px; line-height: 1.6; resize: vertical; }

.fcompose-title:focus,
.fcompose-body:focus {
    outline: none;
    border-color: var(--green-accent);
    box-shadow: 0 0 0 3px var(--mint-glow);
}

.fcompose-topics {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
}

.fcompose-label {
    margin-right: 4px;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
}

.fcompose-actions { display: flex; justify-content: flex-end; gap: 8px; }

/* --- filters, sort and search --------------------------------------------
   A topic is a filter over one feed, not a room you enter, so these are chips
   above the list rather than a table of destinations. */
.ftoolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    flex-wrap: wrap;
    margin-bottom: 14px;
}

.ftoolbar-left { display: flex; align-items: center; gap: 10px; min-width: 0; }

/* --- the topic filter ------------------------------------------------------
   One control instead of a chip per topic. The chips wrapped onto a second
   and third line as topics were added, pushing the sort, the search and the
   whole feed further down the page each time. */

.ftopic { position: relative; }

.ftopic-btn {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 5px 12px;
    font-size: 13px;
    font-family: inherit;
    color: var(--text-secondary);
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: 999px;
    cursor: pointer;
    white-space: nowrap;
    transition: border-color 0.15s, color 0.15s;
}

.ftopic-btn:hover { border-color: var(--green-mid); color: var(--text-primary); }

.ftopic-btn:focus-visible {
    outline: 2px solid var(--green-accent);
    outline-offset: 2px;
}

/* Filtered to something is a state worth seeing without opening the menu --
   which is the only reason folding the filters away is safe. */
.ftopic.filtered .ftopic-btn {
    color: var(--green-bright);
    background: var(--green-deep);
    border-color: var(--green-mid);
}

.ftopic-caret { transition: transform 0.15s ease; opacity: 0.7; }
.ftopic.open .ftopic-caret { transform: rotate(180deg); }

.ftopic-menu {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    z-index: 40;
    min-width: 190px;
    max-height: 320px;
    overflow-y: auto;
    padding: 5px;
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: 10px;
    box-shadow: var(--shadow-lg);
}

.ftopic-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    width: 100%;
    padding: 7px 10px;
    font-size: 13px;
    font-family: inherit;
    text-align: left;
    color: var(--text-secondary);
    background: transparent;
    border: 0;
    border-radius: 6px;
    cursor: pointer;
}

.ftopic-item:hover { background: var(--bg-tertiary); color: var(--text-primary); }

.ftopic-item.active { color: var(--green-bright); background: var(--green-deep); }

.ftopic-n {
    font-size: 11px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.ftopic-item.active .ftopic-n { color: var(--green-accent); }

.fchip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 12px;
    font-size: 13px;
    font-family: inherit;
    color: var(--text-secondary);
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: 999px;
    cursor: pointer;
    white-space: nowrap;
    transition: border-color 0.15s, color 0.15s, background 0.15s;
}

.fchip:hover { border-color: var(--green-mid); color: var(--text-primary); }

.fchip.active {
    color: var(--green-bright);
    background: var(--green-deep);
    border-color: var(--green-mid);
}

.fchip:focus-visible {
    outline: 2px solid var(--green-accent);
    outline-offset: 2px;
}

.fchip-sm { padding: 4px 10px; font-size: 12px; }

.fchip-n {
    font-size: 11px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.fchip.active .fchip-n { color: var(--green-accent); }

.fsorts {
    display: flex;
    padding: 2px;
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: 999px;
}

.fsort {
    padding: 4px 12px;
    font-size: 12px;
    font-family: inherit;
    color: var(--text-muted);
    background: transparent;
    border: 0;
    border-radius: 999px;
    cursor: pointer;
}

.fsort:hover { color: var(--text-primary); }

.fsort.active { color: var(--green-bright); background: var(--green-deep); }

.fsearch input {
    width: 180px;
    padding: 6px 12px;
    font-size: 13px;
    font-family: inherit;
    color: var(--text-primary);
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: 999px;
}

.fsearch input:focus {
    outline: none;
    border-color: var(--green-accent);
    box-shadow: 0 0 0 3px var(--mint-glow);
}

.fsearch-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 16px;
    padding: 10px 14px;
    font-size: 13px;
    color: var(--text-secondary);
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
}

.fclear {
    font-size: 13px;
    font-family: inherit;
    color: var(--green-accent);
    background: none;
    border: 0;
    cursor: pointer;
}

.fclear:hover { color: var(--green-bright); text-decoration: underline; }

/* --- the feed ------------------------------------------------------------ */
.ffeed { display: grid; gap: 10px; }

.fcard {
    padding: 14px 16px;
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    cursor: pointer;
    transition: border-color 0.15s, background 0.15s;
}

.fcard:hover { border-color: var(--green-mid); background: var(--bg-hover); }

.fcard:focus-visible {
    outline: 2px solid var(--green-accent);
    outline-offset: 2px;
}

.fcard-top {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 8px;
    font-size: 12px;
    color: var(--text-muted);
}

.fcard-by {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--text-secondary);
}

/* The dot between the byline and the timestamp is drawn rather than typed, so
   the badges that may or may not sit between them never leave one orphaned. */
.fcard-when::before { content: '·'; margin-right: 8px; color: var(--text-muted); }

.fcard-title {
    margin: 0 0 6px;
    font-size: 17px;
    font-weight: 600;
    line-height: 1.35;
    color: var(--text-primary);
}

.fcard:hover .fcard-title { color: var(--green-bright); }

.fcard-excerpt {
    margin: 0 0 10px;
    font-size: 14px;
    line-height: 1.55;
    color: var(--text-secondary);
    /* Three lines is enough to tell whether the post is for you, and short
       enough that ten of them still scan as a list. */
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.fcard-foot {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 16px;
    font-size: 12px;
    color: var(--text-muted);
}

.fcard-stat { display: inline-flex; align-items: center; gap: 6px; }

.fcard-stat svg { width: 14px; height: 14px; }

.fcard-last { color: var(--text-muted); }

.fmore { margin-top: 16px; text-align: center; }

/* --- a post and its comments --------------------------------------------- */
.fcrumbs {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-bottom: 16px;
}

.fback {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 10px;
    font-size: 13px;
    font-family: inherit;
    color: var(--text-secondary);
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: 999px;
    cursor: pointer;
}

.fback:hover { color: var(--green-bright); border-color: var(--green-mid); }

.fback:focus-visible {
    outline: 2px solid var(--green-accent);
    outline-offset: 2px;
}

.ftag {
    padding: 3px 10px;
    font-size: 12px;
    font-family: inherit;
    color: var(--green-bright);
    background: var(--green-deep);
    border: 1px solid transparent;
    border-radius: 999px;
    cursor: pointer;
}

.ftag:hover { border-color: var(--green-mid); }

.ftag:focus-visible {
    outline: 2px solid var(--green-accent);
    outline-offset: 2px;
}

.fpost-full {
    padding: 18px 20px;
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
}

.fpost-title {
    margin: 0 0 12px;
    font-size: 22px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--text-primary);
}

.fpost-body,
.fcomment-body {
    /* Written as plain text, so the line breaks somebody typed are the line
       breaks they meant. */
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    color: var(--text-primary);
}

.fpost-body { font-size: 15px; line-height: 1.7; }

.flink { color: var(--green-accent); }

.flink:hover { color: var(--green-bright); }

.fpost-edited { font-style: italic; color: var(--text-muted); }

.fpost-tools,
.fcomment-tools {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 14px;
    margin-top: 12px;
    font-size: 12px;
    color: var(--text-muted);
}

.fpost-tools button,
.fcomment-tools button {
    padding: 0;
    font-size: 12px;
    font-family: inherit;
    font-weight: 500;
    color: var(--text-muted);
    background: none;
    border: 0;
    cursor: pointer;
}

.fpost-tools button:hover,
.fcomment-tools button:hover { color: var(--green-bright); }

.fpost-danger:hover { color: var(--danger) !important; }

.fpost-tools button:focus-visible,
.fcomment-tools button:focus-visible {
    outline: 2px solid var(--green-accent);
    outline-offset: 3px;
    border-radius: 3px;
}

/* Comment controls stay out of the way until the comment is under the cursor
   or holds focus -- a tree of thirty comments should not be a tree of ninety
   buttons. Always visible to the keyboard, and on touch, where there is no
   hover to reveal them with. */
.fcomment-tools { opacity: 0.55; transition: opacity 0.15s; }

.fcomment:hover > .fcomment-main > .fcomment-tools,
.fcomment:focus-within > .fcomment-main > .fcomment-tools { opacity: 1; }

@media (hover: none) {
    .fcomment-tools { opacity: 1; }
}

.flocked {
    margin: 16px 0;
    padding: 12px 14px;
    font-size: 13px;
    color: var(--warning);
    background: rgba(210, 153, 34, 0.10);
    border: 1px solid rgba(210, 153, 34, 0.28);
    border-radius: var(--border-radius);
}

.fnote { margin: 0 0 14px; font-size: 13px; color: var(--text-muted); }

/* --- writing a comment --------------------------------------------------- */
.freply { display: flex; gap: 10px; }

.freply-root {
    margin: 18px 0 8px;
    padding: 14px;
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
}

.freply-nested { margin: 10px 0 4px; }

.freply-main { flex: 1; min-width: 0; display: grid; gap: 8px; }

.freply textarea,
.fedit input,
.fedit textarea {
    width: 100%;
    padding: 10px 12px;
    font-size: 14px;
    font-family: inherit;
    line-height: 1.6;
    color: var(--text-primary);
    background: var(--bg-secondary);
    border: 1px solid var(--border-dark);
    border-radius: 6px;
    resize: vertical;
}

.freply textarea:focus,
.fedit input:focus,
.fedit textarea:focus {
    outline: none;
    border-color: var(--green-accent);
    box-shadow: 0 0 0 3px var(--mint-glow);
}

.fedit { display: grid; gap: 8px; margin: 6px 0; }

.freply-actions,
.fedit-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
}

.freply-actions .fmeta { margin-right: auto; }

/* --- the comment tree -----------------------------------------------------
   Nesting is structural: a reply is rendered inside the comment it answers,
   so one class steps it in and the rail down the left spans the whole branch
   because it is drawn by the parent.

   14px a level, not 40. Six levels of a generous indent leaves a phone with
   no column at all, which is how threaded boards end up unreadable exactly
   where the argument got interesting. */
.fcomments { margin-top: 20px; }

.fcomment { position: relative; padding: 6px 0 6px 18px; }

.fcomment-in { margin-left: 14px; }

/* The rail is the collapse control, which is why it is a button and why it is
   the full height of the branch: it is the target you reach for when you have
   read enough of one sub-thread, and it is exactly as tall as what it hides. */
.frail {
    position: absolute;
    left: 4px;
    top: 26px;
    bottom: 6px;
    width: 2px;
    padding: 0;
    background: var(--border-color);
    border: 0;
    border-radius: 2px;
    cursor: pointer;
}

/* A 2px line is not a hit target. This widens the clickable area to 14px
   without moving the line. */
.frail::before {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: -6px;
    right: -6px;
}

.frail:hover { background: var(--green-accent); }

.frail:focus-visible {
    outline: 2px solid var(--green-accent);
    outline-offset: 2px;
}

.fcomment-main { min-width: 0; }

.fcomment-bar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 4px;
    font-size: 12px;
    color: var(--text-muted);
}

.fcomment-who { font-weight: 600; color: var(--text-secondary); }

.fcomment-gone { font-style: italic; color: var(--text-muted); }

.fcomment-body { font-size: 14px; line-height: 1.65; }

.fcomment-folded { padding-top: 4px; padding-bottom: 4px; }

.fcomment-unfold {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 3px 10px 3px 8px;
    font-size: 12px;
    font-family: inherit;
    color: var(--text-secondary);
    background: var(--bg-tertiary);
    border: 1px solid var(--border-color);
    border-radius: 999px;
    cursor: pointer;
}

.fcomment-unfold:hover { border-color: var(--green-mid); color: var(--text-primary); }

.fcomment-unfold span[aria-hidden] {
    font-weight: 700;
    color: var(--green-accent);
}

/* A comment that was just posted, so the eye finds it in a long tree. Fades
   rather than sticking: it answers "where did it go", then gets out of it. */
.fcomment-new > .fcomment-main { animation: fcomment-land 2.4s ease-out; }

@keyframes fcomment-land {
    0%, 40% { background: var(--green-deep); box-shadow: 0 0 0 6px var(--green-deep); }
    100% { background: transparent; box-shadow: 0 0 0 6px transparent; }
}

@media (prefers-reduced-motion: reduce) {
    .fcomment-new > .fcomment-main { animation: none; }
}

/* --- avatars and badges --------------------------------------------------- */
.favatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    font-size: 12px;
    font-weight: 600;
    color: hsl(var(--avatar-hue, 150) 45% 88%);
    background: hsl(var(--avatar-hue, 150) 30% 24%);
    border-radius: 50%;
    user-select: none;
}

.favatar-sm { width: 20px; height: 20px; font-size: 9px; }

/* A photo fills the same circle the initials tile occupies, so a thread of
   mixed members keeps one baseline. object-fit because the server squares
   these, but a cached older one may not be. */
.favatar-img {
    object-fit: cover;
    background: var(--bg-tertiary);
}

.fbadge {
    display: inline-flex;
    align-items: center;
    padding: 2px 7px;
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    border-radius: 4px;
}

.fbadge-pin { background: var(--green-deep); color: var(--green-bright); }
.fbadge-lock { background: rgba(210, 153, 34, 0.16); color: var(--warning); }

/* "Team" means the same thing as the badge in support -- somebody who works
   here, not a member who posts a lot. */
.fbadge-staff { background: rgba(88, 166, 255, 0.16); color: var(--info); }

/* --- narrow screens ------------------------------------------------------- */
@media (max-width: 640px) {
    .feed-head { gap: 12px; }
    .ftoolbar { align-items: stretch; }
    .ftoolbar-right { justify-content: space-between; }
    .fsearch input { width: 100%; }
    .fsearch { flex: 1; }

    /* The indent has to give way before the text does. */
    .fcomment { padding-left: 12px; }
    .fcomment-in { margin-left: 6px; }
    .frail { left: 2px; }

    .fcard-last { display: none; }
}

/* ============================================
   Guides — the reference articles as documentation

   Same rows as the feed reads, opposite side of is_article. The measure is
   capped near 70 characters and each article names the one before and after
   it, because they were written in an order.

   Navigation is a strip of section anchors across the top rather than a rail
   of titles down the side. Twenty-one links in a 250px column is a table of
   contents for a book; this is three sections of task-sized pages, and the
   contents page already lists every one of them with its summary. The rail
   spent a quarter of the width repeating that.
   ============================================ */
.guides { max-width: 1120px; }

/* --- the anchor bar ------------------------------------------------------
   Sticky, because it is how you move between sections and scrolling is how
   you use this page. */
.gbar {
    position: sticky;
    top: var(--topbar-height);
    z-index: 5;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 26px;
    padding: 10px 0;
    background: var(--bg-secondary);
    border-bottom: 1px solid var(--border-color);
}

.ganchor {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 6px 13px;
    font-size: 13px;
    font-family: inherit;
    color: var(--text-secondary);
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: 999px;
    cursor: pointer;
    white-space: nowrap;
    transition: border-color 0.15s, color 0.15s, background 0.15s;
}

.ganchor:hover { border-color: var(--green-mid); color: var(--text-primary); }

.ganchor.active {
    color: var(--green-bright);
    background: var(--green-deep);
    border-color: var(--green-mid);
}

.ganchor:focus-visible {
    outline: 2px solid var(--green-accent);
    outline-offset: 2px;
}

.ganchor-n {
    font-size: 11px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.ganchor.active .ganchor-n { color: var(--green-accent); }

.gfilter {
    margin-left: auto;
    width: 170px;
    padding: 6px 12px;
    font-size: 13px;
    font-family: inherit;
    color: var(--text-primary);
    background: var(--bg-input);
    border: 1px solid var(--border-color);
    border-radius: 999px;
}

.gfilter:focus {
    outline: none;
    border-color: var(--green-accent);
    box-shadow: 0 0 0 3px var(--mint-glow);
}

/* --- the contents page ---------------------------------------------------- */
.ghero { margin-bottom: 30px; }

.ghero h1 {
    margin: 0 0 8px;
    font-size: 28px;
    font-weight: 600;
    color: var(--text-primary);
}

.ghero p {
    margin: 0;
    max-width: 60ch;
    font-size: 15px;
    line-height: 1.6;
    color: var(--text-secondary);
}

.gsection { margin-bottom: 32px; }

.gsection-head { margin-bottom: 12px; }

.gsection-head h2 {
    margin: 0 0 3px;
    font-size: 15px;
    font-weight: 600;
    color: var(--text-primary);
}

.gsection-head p { margin: 0; font-size: 13px; color: var(--text-muted); }

.gcards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    gap: 10px;
}

.gcard {
    display: block;
    padding: 14px 16px;
    text-align: left;
    font-family: inherit;
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    cursor: pointer;
    transition: border-color 0.15s, background 0.15s;
}

.gcard:hover { border-color: var(--green-mid); background: var(--bg-hover); }

.gcard:focus-visible {
    outline: 2px solid var(--green-accent);
    outline-offset: 2px;
}

.gcard h3 {
    margin: 0 0 6px;
    font-size: 14px;
    font-weight: 600;
    line-height: 1.35;
    color: var(--text-primary);
}

.gcard:hover h3 { color: var(--green-bright); }

.gcard p {
    margin: 0 0 8px;
    font-size: 13px;
    line-height: 1.5;
    color: var(--text-secondary);
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.gcard-meta { font-size: 11px; color: var(--text-muted); }

/* --- one guide ------------------------------------------------------------ */
.garticle { max-width: 72ch; }

.garticle-head {
    margin-bottom: 26px;
    padding-bottom: 18px;
    border-bottom: 1px solid var(--border-color);
}

.garticle-head h1 {
    margin: 0 0 10px;
    font-size: 30px;
    font-weight: 600;
    line-height: 1.2;
    letter-spacing: -0.01em;
    color: var(--text-primary);
}

.garticle-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 14px;
    margin: 0;
    font-size: 13px;
    color: var(--text-muted);
}

.glink {
    font-size: 13px;
    font-family: inherit;
    color: var(--green-accent);
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
}

.glink:hover { color: var(--green-bright); text-decoration: underline; }

/* The body is generated by render() in pages/guides.js, which turns the
   plain-text convention the articles are written in -- ALL-CAPS headings,
   hand-aligned blocks, numbered steps -- into these elements. */
.gbody { font-size: 15px; line-height: 1.75; color: var(--text-secondary); }

.gbody h2 {
    margin: 32px 0 10px;
    font-size: 13px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--green-bright);
}

.gbody h2:first-child { margin-top: 0; }

.gbody p { margin: 0 0 16px; }

.gbody ul,
.gbody ol { margin: 0 0 18px; padding-left: 22px; }

.gbody li { margin-bottom: 7px; }

.gbody li::marker { color: var(--green-accent); }

/* Blocks the author aligned by hand: DNS records, host and port tables, the
   fields of a form in the order they appear on screen. The alignment is the
   information, so it is preserved and the block scrolls rather than wraps. */
.gblock {
    margin: 0 0 18px;
    padding: 14px 16px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 13px;
    line-height: 1.65;
    color: var(--text-primary);
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-left: 2px solid var(--green-mid);
    border-radius: 6px;
    overflow-x: auto;
    white-space: pre;
}

.gfoot {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    margin-top: 40px;
    padding-top: 20px;
    border-top: 1px solid var(--border-color);
}

.gstep {
    flex: 0 1 46%;
    display: grid;
    gap: 4px;
    padding: 12px 14px;
    text-align: left;
    font-family: inherit;
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    cursor: pointer;
    transition: border-color 0.15s, background 0.15s;
}

.gstep-next { text-align: right; }

.gstep:hover { border-color: var(--green-mid); background: var(--bg-hover); }

.gstep:focus-visible {
    outline: 2px solid var(--green-accent);
    outline-offset: 2px;
}

.gstep-dir { font-size: 11px; color: var(--text-muted); }

.gstep-title {
    font-size: 13px;
    font-weight: 600;
    line-height: 1.35;
    color: var(--text-primary);
}

.gstep:hover .gstep-title { color: var(--green-bright); }

@media (max-width: 900px) {
    /* The anchor bar wraps by itself, so there is nothing to collapse. The
       filter goes full width on its own row rather than being squeezed
       against the last pill. */
    .gfilter { margin-left: 0; width: 100%; }

    .garticle-head h1 { font-size: 24px; }

    .gfoot { flex-direction: column; }

    .gstep, .gstep-next { flex: 1 1 auto; text-align: left; }
}

/* ============================================
   Refer & Earn
   ============================================ */
.referrals-page .page-header { align-items: flex-start; }

.ref-sub {
    margin: 4px 0 0;
    font-size: 13px;
    color: var(--text-muted);
}

.ref-link-card { margin-bottom: 20px; }

.ref-link-card label {
    display: block;
    margin-bottom: 8px;
    font-weight: 500;
    color: var(--text-primary);
}

.ref-link-row {
    display: flex;
    gap: 10px;
    align-items: stretch;
}

.ref-link-row input {
    flex: 1 1 auto;
    min-width: 0;
    padding: 10px 12px;
    background: var(--bg-input);
    border: 1px solid var(--border-dark);
    border-radius: var(--radius-md);
    color: var(--text-primary);
    font: inherit;
    font-size: 14px;
    /* The link is the thing to copy, so it reads as data rather than prose. */
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

.ref-link-row input:focus {
    outline: none;
    border-color: var(--green-accent);
    box-shadow: var(--focus-ring);
}

.ref-terms {
    margin: 12px 0 0;
    font-size: 13px;
    line-height: 1.6;
    color: var(--text-muted);
}

.ref-terms strong { color: var(--green-bright); }

.ref-funnel { margin-bottom: 20px; }

/* The conversion rate sits with its step rather than in its own tile: the
   number is the count, the percentage is context for it. */
.ref-rate {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 6px;
    border-radius: var(--radius-sm);
    background: var(--green-deep);
    color: var(--green-bright);
    font-size: 11px;
    font-weight: 600;
}

.ref-balances {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 16px;
    padding-bottom: 18px;
    margin-bottom: 18px;
    border-bottom: 1px solid var(--border-color);
}

.ref-balances strong {
    display: block;
    font-size: 22px;
    font-weight: 650;
    letter-spacing: -0.02em;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.ref-balances span {
    font-size: 12px;
    color: var(--text-muted);
}

.ref-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

.ref-payout-details {
    margin-top: 20px;
    padding-top: 18px;
    border-top: 1px solid var(--border-color);
}

.ref-owed {
    font-size: 12px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

/* Referral and payout lifecycle states, reusing the badge shape. */
.status-converted, .status-paid {
    background: rgba(63, 185, 80, 0.16);
    color: var(--success);
}

.status-requested, .status-claimed {
    background: rgba(210, 153, 34, 0.16);
    color: var(--warning);
}

.status-churned, .status-rejected, .status-suspended {
    background: rgba(248, 81, 73, 0.14);
    color: var(--danger);
}

@media (max-width: 640px) {
    .ref-link-row { flex-direction: column; }
}

/* ============================================
   Activity rail — the inbox feed on the right

   Mirrors the left nav: fixed, full height, always present. It slides rather
   than appears, and the main column's right margin animates with it, so
   opening the rail does not make the page jump.
   ============================================ */
/* Hidden until there is a session to have an inbox in. navigate() adds
   .signed-in to <body>; without this the toggle floated over the login page. */
body:not(.signed-in) #rail-toggle,
body:not(.signed-in) .topbar,
body:not(.signed-in) .activity-rail { display: none; }

/* The inbox-feed button lives in the header bar now. It used to be
   position: fixed over the page, which meant it sat on top of whatever you
   scrolled past. See .topbar below. */

/* Unread count. Absolute on the toggle so it reads at a glance with the rail
   shut, which is the only time it matters. A rounded rectangle on the app's
   own scale -- 999px made it an oval, which matches nothing else here. */
.rail-count {
    position: absolute;
    top: -6px;
    right: -6px;
    display: grid;
    place-items: center;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: var(--radius-xs);
    background: var(--green-accent);
    color: var(--on-accent);
    font-size: 10px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

:root { --rail-width: 320px; }

.activity-rail {
    position: fixed;
    top: 0;
    right: 0;
    z-index: 110;
    display: flex;
    flex-direction: column;
    width: var(--rail-width);
    height: 100vh;
    background: var(--bg-primary);
    border-left: 1px solid var(--border-color);
    box-shadow: var(--elev-3);
    /* Off-screen, not hidden: it slides, and a transform animates without
       forcing layout on the rest of the page. */
    transform: translateX(100%);
    transition: transform var(--slow) var(--ease);
}

.rail-open .activity-rail { transform: translateX(0); }

/* The content column gives up the space instead of sliding under the rail. */
.main-content {
    transition: margin-right var(--slow) var(--ease);
}

.rail-open .main-content { margin-right: var(--rail-width); }

.rail-head {
    display: grid;
    gap: 10px;
    padding: 16px;
    border-bottom: 1px solid var(--border-color);
    flex-shrink: 0;
}

.rail-head-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}

.rail-head-top h2 {
    margin: 0;
    font-size: 15px;
    color: var(--text-primary);
}

.rail-head-actions { display: flex; gap: 2px; }

.rail-head-actions .btn-icon { font-size: 16px; line-height: 1; }

/* While a check is in flight the refresh button becomes a spinner -- the
   same ring the list shows under "Checking mail...", so one operation does
   not have two different loading indicators on screen at once.

   Spinning the refresh glyph itself was the obvious thing and the wrong one:
   two arrows chasing each other read as a decoration rather than as work in
   progress, and at 15px they smear into a grey ring anyway. */
.spinner-ring {
    display: none;
    width: 13px;
    height: 13px;
    border: 2px solid var(--border-dark);
    border-top-color: var(--green-accent);
    border-radius: 50%;
    animation: spin 0.7s linear infinite;
}

#rail-refresh.spinning svg { display: none; }
#rail-refresh.spinning .spinner-ring { display: block; }

/* Nothing to press while it is already checking. */
#rail-refresh.spinning { cursor: default; }

@media (prefers-reduced-motion: reduce) {
    .spinner-ring { animation-duration: 2.4s; }
}

.rail-filter {
    width: 100%;
    padding: 7px 34px 7px 10px;
    background-color: var(--bg-tertiary);
    border: 1px solid var(--border-dark);
    border-radius: var(--radius-md);
    color: var(--text-primary);
    font: inherit;
    font-size: 13px;
    cursor: pointer;
}

.rail-filter:focus-visible {
    outline: none;
    border-color: var(--green-accent);
    box-shadow: var(--focus-ring);
}

.rail-stamp {
    font-size: 11px;
    color: var(--text-muted);
}

.rail-list {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: 8px;
}

.rail-item {
    display: grid;
    gap: 3px;
    width: 100%;
    padding: 10px 11px;
    margin-bottom: 4px;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    text-align: left;
    font: inherit;
    color: var(--text-secondary);
    cursor: pointer;
    transition: background-color var(--fast) var(--ease),
                border-color var(--fast) var(--ease);
}

.rail-item:hover {
    background: var(--bg-hover);
    border-color: var(--border-color);
}

.rail-item:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
}

/* Unread: a faint outline around the whole tile, plus the raised background
   and heavier text. The row already carries a 1px transparent border, so this
   only colours it -- nothing moves, and the accent sits around the tile rather
   than as a bar down one edge. */
.rail-item.unread {
    background: var(--bg-tertiary);
    border-color: var(--border-on);
}

.rail-item.unread .rail-from,
.rail-item.unread .rail-subject { color: var(--text-primary); font-weight: 600; }

.rail-item-top {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
}

.rail-from {
    font-size: 13px;
    font-weight: 500;
    color: var(--text-secondary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.rail-time {
    flex-shrink: 0;
    font-size: 11px;
    color: var(--text-muted);
}

.rail-subject,
.rail-preview,
.rail-box {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The badge is inline-flex so its pill hugs the label rather than stretching
   the full width of the row. */
.rail-box { display: inline-block; }

.rail-subject { font-size: 13px; color: var(--text-secondary); }
.rail-preview { font-size: 12px; color: var(--text-muted); }

/* Which mailbox this arrived in. Always shown, even with one mailbox
   configured -- a feed that only labels itself sometimes is worse than one
   that always does.

   A badge rather than another line of small text: as plain text it sat in the
   same visual register as the preview above it and read as more of the
   message, which is exactly what made it easy to miss. */
.rail-box {
    justify-self: start;
    max-width: 100%;
    margin-top: 5px;
    padding: 1px 5px;
    /* A rectangle with the corner just knocked off, to match the cards it
       sits inside. Radius has to be read against the element's own height,
       not as an absolute number: the card is 8px on ~90px, about 9% of its
       height, while 5px on a 16px badge is over 30% -- the same scale token
       produces a card on one and a lozenge on the other. 3px here is ~19%,
       which is the first value that actually reads as square. */
    border-radius: var(--radius-xs);
    /* Light fill, dark text -- the inversion the primary button uses, because
       on a dark rail the badge has to be the light thing to be found at a
       glance. No border: a second, lighter outline around an already-light
       fill reads as a glow rather than an edge. */
    background: var(--green-accent);
    border: 0;
    color: var(--on-accent);
    font-size: 9px;
    font-weight: 700;
    letter-spacing: 0.02em;
    line-height: 1.5;
    text-transform: uppercase;
}

.rail-empty,
.rail-loading {
    padding: 28px 16px;
    text-align: center;
    font-size: 13px;
    color: var(--text-muted);
}

.rail-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 9px;
}

/* Same ring as the refresh button, so the two never drift apart. */
.rail-loading .spinner-ring { display: block; }

/* On a narrow screen the rail covers the page rather than squeezing it, and
   the main column keeps its full width underneath. */
@media (max-width: 1100px) {
    :root { --rail-width: 300px; }
    .rail-open .main-content { margin-right: 0; }
}

@media (max-width: 560px) {
    :root { --rail-width: 100vw; }
    .rail-open .rail-toggle { right: 18px; }
}

/* ============================================
   Sequence editor

   A campaign is an order of events over days, so it is drawn as a timeline:
   numbered markers down a rail, one card per email. The previous version was
   a stack of identical grey boxes with the timing buried in a sentence, and
   nothing about it said "these happen one after another".
   ============================================ */
.modal-xl { max-width: 820px; }
.modal-xl .modal-content { max-width: 820px; }

.seq-head h3 { margin: 0; }

.seq-sub {
    margin: 3px 0 0;
    font-size: 12px;
    color: var(--text-muted);
}

.seq-body {
    display: grid;
    gap: 18px;
    max-height: min(72vh, 760px);
    overflow-y: auto;
}

/* Where the people in this campaign ended up. Figures, not a sentence:
   "48 replied" is what anyone opening this screen came to find. */
.seq-outcomes {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

.seq-outcome {
    display: grid;
    gap: 1px;
    flex: 1 1 110px;
    padding: 10px 13px;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
}

.seq-outcome b {
    font-size: 19px;
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
}

.seq-outcome span { font-size: 11px; color: var(--text-muted); }

.seq-timeline {
    display: grid;
    gap: 14px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.seq-step {
    display: grid;
    grid-template-columns: 30px 1fr;
    gap: 14px;
}

/* The rail: a numbered dot with a line running to the next one. Drawn on the
   marker rather than between cards so it cannot fall out of alignment when a
   card grows. */
.seq-marker {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
}

.seq-dot {
    display: grid;
    place-items: center;
    width: 28px;
    height: 28px;
    flex-shrink: 0;
    border-radius: 50%;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-color);
    color: var(--text-secondary);
    font-size: 12px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

/* The opening email always sends; every follow-up is conditional. Marking the
   first one out keeps that difference visible while scrolling. */
.seq-step:first-child .seq-dot {
    background: var(--green-accent);
    border-color: var(--green-bright);
    color: var(--on-accent);
}

.seq-marker::after {
    content: '';
    flex: 1;
    width: 1px;
    background: var(--border-color);
}

.seq-step:last-child .seq-marker::after { display: none; }

.seq-card {
    display: grid;
    gap: 12px;
    padding: 15px 17px;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
}

.seq-card-top {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
}

.seq-titles { display: grid; gap: 2px; }
.seq-titles h4 { margin: 0; font-size: 14px; }

.seq-timing {
    font-size: 12px;
    color: var(--text-muted);
}

.seq-remove {
    display: grid;
    place-items: center;
    width: 26px;
    height: 26px;
    flex-shrink: 0;
    padding: 0;
    background: none;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    color: var(--text-muted);
    cursor: pointer;
    transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}

.seq-remove:hover {
    color: var(--danger);
    border-color: var(--danger);
}

/* The two rules that decide when this email goes out, on one line, reading as
   a sentence: "Wait [3] days / Send this one [to everyone still in it]". */
.seq-rules {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    padding: 11px 13px;
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
}

.seq-rule {
    display: grid;
    gap: 5px;
    flex: 0 0 auto;
}

.seq-rule-wide { flex: 1 1 300px; }

.seq-rule-label {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.seq-days {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: 13px;
    color: var(--text-secondary);
}

.seq-days input {
    width: 62px;
    padding: 7px 9px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-dark);
    border-radius: var(--radius-sm);
    color: var(--text-primary);
    font: inherit;
    font-size: 13px;
    text-align: center;
}

.seq-rule select {
    width: 100%;
    padding: 7px 30px 7px 10px;
    background-color: var(--bg-secondary);
    border: 1px solid var(--border-dark);
    border-radius: var(--radius-sm);
    color: var(--text-primary);
    font: inherit;
    font-size: 13px;
}

.seq-note {
    margin: -4px 0 0;
    font-size: 12px;
    line-height: 1.5;
    color: var(--text-muted);
}

.seq-fields { display: grid; gap: 9px; }

.seq-subject,
.seq-message {
    width: 100%;
    padding: 10px 12px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-dark);
    border-radius: var(--radius-md);
    color: var(--text-primary);
    font: inherit;
    font-size: 14px;
    line-height: 1.65;
    resize: vertical;
}

.seq-subject { font-weight: 600; }

.seq-subject:focus,
.seq-message:focus,
.seq-days input:focus,
.seq-rule select:focus {
    outline: none;
    border-color: var(--green-accent);
    box-shadow: var(--focus-ring);
}

.seq-stats {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    padding-top: 10px;
    border-top: 1px solid var(--border-color);
    font-size: 12px;
    color: var(--text-muted);
}

.seq-stats b {
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}

.seq-add {
    justify-self: start;
    display: inline-flex;
    align-items: center;
    gap: 7px;
    /* Dashed, because it adds something rather than confirming something --
       the same reason an "add row" control is never the primary button. */
    border-style: dashed;
}

.seq-footer {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
}

.seq-footer-actions {
    display: flex;
    gap: 8px;
    margin-left: auto;
}

.seq-hint {
    flex: 1 1 260px;
    font-size: 12px;
    line-height: 1.5;
    color: var(--text-muted);
}

/* Shown when editing a campaign that has already sent mail. */
.form-note {
    margin-bottom: 16px;
    padding: 11px 14px;
    background: var(--green-deep);
    border: 1px solid var(--green-accent);
    border-radius: var(--radius-md);
    font-size: 12px;
    line-height: 1.55;
    color: var(--text-secondary);
}

.campaign-done {
    align-self: center;
    font-size: 12px;
    color: var(--text-muted);
}

@media (max-width: 620px) {
    .seq-step { grid-template-columns: 22px 1fr; gap: 10px; }
    .seq-dot { width: 22px; height: 22px; font-size: 11px; }
    .seq-rules { flex-direction: column; }
    .seq-footer-actions { margin-left: 0; width: 100%; }
    .seq-footer-actions .btn { flex: 1; }
}

/* ============================================
   Support
   ============================================ */

.support-list {
    display: grid;
    gap: 4px;
    align-content: start;
    padding: 8px;
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
}

.support-item {
    display: grid;
    gap: 2px;
    width: 100%;
    padding: 10px 11px;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    text-align: left;
    font: inherit;
    cursor: pointer;
    transition: background-color var(--fast) var(--ease);
}

.support-item:hover { background: var(--bg-hover); }

.support-item.active {
    background: var(--green-deep);
    border-color: var(--green-mid);
}

.support-item.unread .support-item-subject { color: var(--green-bright); }

.support-item-subject {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.support-none {
    padding: 20px 12px;
    font-size: 13px;
    color: var(--text-muted);
    text-align: center;
}

.support-thread {
    display: flex;
    flex-direction: column;
    min-height: 60vh;
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    overflow: hidden;
}

.support-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    padding: 16px 20px;
    border-bottom: 1px solid var(--border-color);
}

.support-head h2 { margin: 0 0 3px; font-size: 16px; }

.support-messages {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: 18px 20px;
    display: grid;
    gap: 14px;
    align-content: start;
}

.support-msg {
    max-width: 78%;
    padding: 11px 14px;
    border-radius: var(--radius-lg);
    background: var(--bg-tertiary);
}

/* The member's own messages sit on the right, the way every chat does, so the
   direction of the conversation is readable without labels. */
.support-msg-user {
    justify-self: end;
    background: var(--green-deep);
}

/* AI and human answers stay distinguishable -- passing a generated reply off
   as staff is the fastest way to lose somebody's trust when they are already
   frustrated -- but the BADGE is what says which is which, and it says so in
   words. The two bars this replaces were a green and a bright blue stripe
   down the left of each message: the blue belonged to no part of this
   palette, and neither told you anything the label above it did not.

   A quiet difference in surface is enough to group them at a glance. */
.support-msg-ai { background: var(--bg-tertiary); }

.support-msg-admin {
    background: var(--green-deep);
    box-shadow: inset 0 0 0 1px var(--border-color);
}

.support-msg-head {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 5px;
}

.support-who {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-primary);
}

.support-badge {
    padding: 1px 7px;
    border-radius: var(--radius-sm);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.support-badge-ai {
    background: var(--green-deep);
    color: var(--green-bright);
}

/* Both badges live in the brand ramp. The admin one was #58A6FF on a blue
   wash, which is the only blue anywhere in this product. */
.support-badge-admin {
    background: var(--green-accent);
    color: var(--on-accent);
}

.support-msg-body {
    font-size: 14px;
    line-height: 1.6;
    color: var(--text-primary);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.support-composer {
    display: flex;
    gap: 10px;
    align-items: flex-end;
    padding: 14px 20px;
    border-top: 1px solid var(--border-color);
    background: var(--bg-tertiary);
}

.support-composer textarea {
    flex: 1 1 auto;
    padding: 10px 12px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-dark);
    border-radius: var(--radius-md);
    color: var(--text-primary);
    font: inherit;
    font-size: 14px;
    line-height: 1.6;
    resize: vertical;
}

.support-composer textarea:focus {
    outline: none;
    border-color: var(--green-accent);
    box-shadow: var(--focus-ring);
}




@media (max-width: 900px) {
    .support-layout { grid-template-columns: 1fr; }
    .support-list { max-height: 200px; overflow-y: auto; }
}

/* The provider's published rates for the selected model. Shown, not edited:
   these are not a setting, and typing them by hand would only let the
   recorded cost drift away from the real invoice. */
.ai-rates {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 16px;
    padding: 12px 14px;
    margin-bottom: 16px;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    font-size: 12px;
    color: var(--text-muted);
}

.ai-rate b {
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
}

.ai-rate-note {
    margin-left: auto;
    font-style: italic;
}

/* ============================================
   Support chat (member side)

   One surface. Messages fill the panel, the composer is pinned to the bottom
   and is always there. The first version was a two-pane mail client with the
   input floating in the middle of an empty box, which is not how anyone
   expects to talk to a support assistant.

   The .support-* classes above are still used by the ADMIN side, which really
   is a queue beside a conversation, so they stay.
   ============================================ */



/* The history rail earns its space only once there is history. */
.chat:has(.chat-history:not([hidden])) { grid-template-columns: 230px 1fr; }

/* An author `display` beats the user-agent's `[hidden] { display: none }`, so
   setting .hidden on this element did nothing and an empty rail rendered above
   the chat. This puts the attribute back in charge. */







.chat-history-item.active { background: var(--green-deep); border-color: var(--green-mid); }
.chat-history-item.unread .chat-history-subject { color: var(--green-bright); }













/* The message area is the only thing that scrolls. */





/* A readable column rather than the full width of the panel: prose set across
   1200px is hard to track back from at the end of a line. */


.chat-turn { display: grid; gap: 5px; justify-items: start; }
.chat-turn-user { justify-items: end; }

.chat-meta {
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 11px;
    color: var(--text-muted);
}

.chat-who { font-weight: 600; color: var(--text-secondary); }

.chat-badge {
    padding: 1px 6px;
    border-radius: var(--radius-sm);
    font-size: 9px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}

/* AI and a human never share a treatment. */
.chat-badge-ai { background: var(--green-deep); color: var(--green-bright); }
/* The member-facing equivalent, same reasoning: a filled brand badge for a
   person, a quieter one for the assistant, and no blue. */
.chat-badge-admin { background: var(--green-accent); color: var(--on-accent); }

.chat-bubble {
    max-width: 88%;
    padding: 11px 15px;
    border-radius: 14px;
    background: var(--bg-tertiary);
    color: var(--text-primary);
    font-size: 14px;
    line-height: 1.65;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.chat-turn-user .chat-bubble {
    background: var(--green-deep);
    border-bottom-right-radius: 4px;
}

.chat-turn-ai .chat-bubble,
.chat-turn-admin .chat-bubble { border-bottom-left-radius: 4px; }

/* Three dots while the answer is being written. Without it the chat looks
   like it swallowed the message. */
.chat-thinking { display: flex; gap: 5px; align-items: center; padding: 15px; }

.chat-thinking span {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--text-muted);
    animation: chat-dot 1.2s var(--ease) infinite;
}

.chat-thinking span:nth-child(2) { animation-delay: 0.15s; }
.chat-thinking span:nth-child(3) { animation-delay: 0.3s; }

@keyframes chat-dot {
    0%, 60%, 100% { opacity: 0.25; transform: translateY(0); }
    30% { opacity: 1; transform: translateY(-3px); }
}












/* Pinned to the bottom, always. */
















/* The admin side really IS a queue beside a conversation, so it keeps the
   two-pane shape the member side just lost. */
.support-admin {
    display: grid;
    grid-template-columns: 280px 1fr;
    gap: 16px;
    align-items: start;
}

.support-admin .support-thread { min-height: 420px; }
.support-admin .support-list { max-height: 420px; overflow-y: auto; }
.support-head-actions { display: flex; gap: 8px; flex-shrink: 0; }

@media (max-width: 900px) {
    .chat:has(.chat-history:not([hidden])) { grid-template-columns: 1fr; }

    .support-admin { grid-template-columns: 1fr; }
}

/* ============================================
   Admin: community articles and test members
   ============================================ */
.admin-head-actions { display: flex; gap: 8px; }

.admin-note {
    margin: 0 0 14px;
    font-size: 12px;
    line-height: 1.65;
    color: var(--text-muted);
}

.admin-note code {
    padding: 1px 5px;
    background: var(--bg-tertiary);
    border-radius: var(--radius-sm);
    font-size: 11px;
    color: var(--green-bright);
}

.admin-note strong { color: var(--text-secondary); }

.admin-result {
    padding: 10px 13px;
    border-radius: var(--radius-md);
    font-size: 13px;
}

.admin-result.ok {
    background: rgba(127, 160, 150, 0.14);
    border: 1px solid var(--green-accent);
    color: var(--green-bright);
}

.admin-result.bad {
    background: rgba(220, 90, 90, 0.12);
    border: 1px solid rgba(220, 90, 90, 0.5);
    color: #F3B0B0;
}

/* A wide table inside a card scrolls itself rather than pushing the page
   sideways. */
.table-scroll {
    max-height: 460px;
    overflow: auto;
}

.persona-voice,
.persona-focus,
.persona-cap {
    width: 100%;
    padding: 6px 8px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-dark);
    border-radius: var(--radius-sm);
    color: var(--text-primary);
    font: inherit;
    font-size: 12px;
    line-height: 1.5;
    resize: vertical;
}

.persona-cap { width: 64px; text-align: center; }

.persona-voice:focus,
.persona-focus:focus,
.persona-cap:focus {
    outline: none;
    border-color: var(--green-accent);
    box-shadow: var(--focus-ring);
}

.persona-toggle { display: inline-flex; cursor: pointer; }
.persona-toggle input { width: 16px; height: 16px; cursor: pointer; }

/* Each row saves on its own as you leave a field, so it has to say so --
   otherwise there is no way to tell an edit was kept. */
tr.saving { opacity: 0.55; }

tr.saved td:first-child {
    box-shadow: inset 3px 0 0 var(--green-accent);
    transition: box-shadow var(--slow) var(--ease);
}

.small { font-size: 11px; }

/* ============================================
   Community: how big the room is

   Top right of the Community header. Numbers first, labels under them --
   the figure is what anybody glances up for; "members" is only there to say
   what the figure counts.
   ============================================ */
.fcommunity-stats {
    display: flex;
    align-items: stretch;
    gap: 0;
    flex-shrink: 0;
    background: var(--bg-primary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    overflow: hidden;
}

.fcommunity-stats[hidden] { display: none; }

.fstat {
    display: grid;
    gap: 1px;
    justify-items: center;
    min-width: 74px;
    padding: 9px 14px;
}

/* Hairlines between rather than around each, so it reads as one object. */
.fstat + .fstat { border-left: 1px solid var(--border-color); }

.fstat b {
    font-size: 17px;
    font-weight: 600;
    line-height: 1.15;
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
}

.fstat span {
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--text-muted);
}

@media (max-width: 700px) {
    /* The member count is the one worth keeping when there is no room. */
    .fstat + .fstat { display: none; }
}

/* The admin users pager sits inside a card whose body already has padding,
   so it does not need the leading margin the leads-page one carries. */
/* The users table scrolls inside its own box instead of running the length
   of the page.

   .contacts-table-wrapper deliberately keeps overflow-y: visible -- the leads
   page needs that so nothing inside a cell gets clipped -- so this is a
   modifier rather than a change to the shared rule.

   The height is set to leave a row half-visible at the bottom on purpose. A
   list that ends exactly on a row boundary looks finished; a sliver of the
   next one is the cheapest possible way to say "there is more, scroll". */
.admin-users-scroll {
    max-height: 540px;
    overflow-y: auto;
}

/* Column headings stay put while the rows move under them. Without an opaque
   background the rows show through as they pass beneath, and without the
   z-index the cell borders draw over the top of it. */
.admin-users-scroll thead th {
    position: sticky;
    top: 0;
    z-index: 2;
    background: var(--bg-tertiary);
}

/* border-bottom on a sticky cell scrolls away with the table, so the rule
   under the header is drawn as a shadow instead. */
.admin-users-scroll thead th {
    box-shadow: inset 0 -1px 0 var(--border-color);
}

/* THE TABLE FITS ITS BOX.
   
   It was overflowing by 272px at 1440px wide, so reading a user meant
   dragging a horizontal scrollbar -- on a desktop, with room to spare.
   
   Two causes: .contacts-table carries min-width: 920px and every cell is
   white-space: nowrap, so the columns sized themselves to their longest
   content and the table grew past its container instead of sharing out the
   width it had.
   
   table-layout: fixed makes the widths below authoritative rather than
   advisory, so no amount of content can push the table wider. Long values
   ellipsis instead, with the full text on the tooltip. */
@media (min-width: 1000px) {
    .admin-users-scroll { overflow-x: hidden; }

    .admin-users-scroll .contacts-table {
        min-width: 0;
        width: 100%;
        table-layout: fixed;
    }

    /* Percentages for the text columns; the actions column is fixed, because
       buttons do not compress and clipping one is worse than any amount of
       truncated company name. */
    .admin-users-scroll th:nth-child(1) { width: 23%; }   /* Email      */
    .admin-users-scroll th:nth-child(2) { width: 13%; }   /* Name       */
    .admin-users-scroll th:nth-child(3) { width: 15%; }   /* Company    */
    .admin-users-scroll th:nth-child(4) { width: 8%;  }   /* Plan       */
    .admin-users-scroll th:nth-child(5) { width: 9%;  }   /* Status     */
    .admin-users-scroll th:nth-child(6) { width: 10%; }   /* Created    */
    .admin-users-scroll th:nth-child(7) { width: 10%; }   /* Last login */
    .admin-users-scroll th:nth-child(8) { width: 196px; } /* Actions    */

    /* With a fixed layout, anything too long is clipped rather than widening
       its column -- so it needs somewhere to go. */
    .admin-users-scroll td,
    .admin-users-scroll th {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        padding: 12px 10px;
    }

    /* The email cell holds two things -- the address and, sometimes, an Admin
       badge -- so the truncation has to happen on the address itself. Putting
       overflow on the cell just clipped the text mid-character with no
       ellipsis to show it had been cut. The full address is on the tooltip. */
    .admin-users-scroll td:first-child .admin-user-cell {
        display: flex;
        max-width: 100%;
    }

    .admin-users-scroll .admin-user-email {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        min-width: 0;
    }

    .admin-users-scroll td:first-child .badge { flex-shrink: 0; }

    .admin-users-scroll .admin-row-actions {
        display: flex;
        gap: 5px;
        overflow: visible;
    }

    .admin-users-scroll .admin-row-actions .btn {
        padding: 5px 9px;
        font-size: 12px;
    }
}

/* Below that, the columns genuinely do not fit and dragging sideways is the
   honest answer. */
@media (max-width: 999px) {
    .admin-users-scroll { overflow-x: auto; }
}

.admin-users-count {
    padding: 12px 2px 0;
    margin-top: 12px;
    border-top: 1px solid var(--border-color);
    font-size: 12px;
    color: var(--text-muted);
}

/* Email and the Admin badge on one line. The badge was wrapping underneath,
   which made every admin's row 20px taller than the rest of the table. */
.admin-user-cell {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    white-space: nowrap;
}

/* Refreshing something that is already on screen.
   A thin bar along the top of the view instead of replacing the content with
   a spinner: switching sort or topic is usually a couple of hundred
   milliseconds against a cached answer, and blanking the page for that loses
   the reader's place to say nothing new. */
#forum-view { position: relative; }

#forum-view.fbusy::before {
    content: '';
    position: absolute;
    top: -6px;
    left: 0;
    right: 0;
    height: 2px;
    border-radius: 2px;
    background: linear-gradient(90deg,
        transparent, var(--green-accent), transparent);
    background-size: 40% 100%;
    background-repeat: no-repeat;
    animation: fbusy-slide 0.9s ease-in-out infinite;
    z-index: 5;
}

@keyframes fbusy-slide {
    0%   { background-position: -40% 0; }
    100% { background-position: 140% 0; }
}

/* Nothing moves while it refreshes -- the content stays exactly where it is,
   which is the whole point. Motion is reserved for readers who want it. */
@media (prefers-reduced-motion: reduce) {
    #forum-view.fbusy::before { animation: none; background-position: 50% 0; }
}

/* ------------------------------------------------------------ invitation */
.invite-container { max-width: 440px; }
.invite-title { font-size: 20px; margin: 0 0 8px; text-align: center; }
.invite-title b { color: var(--primary); }
.invite-sub { text-align: center; margin: 0 0 22px; line-height: 1.5; }
.invite-dead { text-align: center; }
.invite-dead h2 { margin: 0 0 8px; font-size: 18px; }
.invite-dead p { margin: 0 0 18px; line-height: 1.5; }

/* --------------------------------------------------------- access (members) */
.members-list { display: flex; flex-direction: column; gap: 8px; margin-top: 14px; }
.member-row {
    display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
    padding: 10px 12px;
    border: 1px solid var(--border-color); border-radius: var(--border-radius);
    background: var(--bg-primary);
}
.member-row.is-pending { border-style: dashed; }
.member-who { flex: 1; min-width: 180px; }
.member-who b { display: block; font-size: 13px; overflow: hidden; text-overflow: ellipsis; }
.member-who span { font-size: 12px; color: var(--text-muted); }
.member-row select { font-size: 13px; padding: 4px 8px; }
.member-actions { display: flex; align-items: center; gap: 6px; }
.member-invite { display: flex; gap: 8px; flex-wrap: wrap; align-items: flex-end; margin-top: 10px; }
.member-invite .form-group { margin: 0; flex: 1; min-width: 200px; }
.member-invite .form-group.is-role { flex: 0 0 auto; min-width: 150px; }
.member-link {
    margin-top: 10px; padding: 10px 12px; font-size: 12px;
    background: var(--bg-secondary); border-radius: var(--border-radius);
}
.member-link-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; color: var(--text-muted); }
.member-link-url {
    width: 100%; padding: 8px 10px; font-family: var(--font-mono, ui-monospace, monospace); font-size: 12px;
    color: var(--text-primary); background: var(--bg-input); border: 1px solid var(--border-dark); border-radius: var(--radius-md);
}
/* The role picker sits outside a .form-group, which is where selects get
   their field styling; give it the same look, one size down. */
.member-row select {
    padding: 6px 30px 6px 10px; font-size: 13px; font-family: inherit;
    color: var(--text-primary); background-color: var(--bg-input);
    border: 1px solid var(--border-dark); border-radius: var(--radius-md);
    background-position: right 10px center;
}

/* ----------------------------------------------------------- website pages */
.site-scan { display: flex; gap: 8px; align-items: flex-end; flex-wrap: wrap; margin-bottom: 12px; }
.site-scan .form-group { flex: 1; min-width: 220px; margin: 0; }
.site-add { padding: 12px; margin-bottom: 12px; border: 1px dashed var(--border-color); border-radius: var(--border-radius); }
.site-add .form-group { margin-bottom: 10px; }
.site-found {
    margin: 0 0 14px; padding: 12px;
    border: 1px solid var(--border-color); border-radius: var(--border-radius);
    background: var(--bg-secondary);
}
.site-found-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.site-found-head .spacer { flex: 1; }
.site-found-list { max-height: 320px; overflow-y: auto; display: flex; flex-direction: column; gap: 2px; }
.site-page { display: flex; align-items: center; gap: 8px; padding: 4px 6px; border-radius: 4px; font-size: 13px; cursor: pointer; }
.site-page:hover { background: var(--bg-primary); }
.site-page span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.site-page.is-known { color: var(--text-muted); }
.site-page em { font-style: normal; font-size: 11px; color: var(--text-muted); }
.site-found-foot { display: flex; align-items: center; gap: 12px; margin-top: 10px; }
.link-item .kb-item-content { min-width: 0; }
.link-item .link-url { display: block; font-size: 12px; color: var(--primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin: 2px 0 6px; }
.link-item .link-note { width: 100%; font-size: 13px; padding: 6px 8px; margin-bottom: 6px; }
.link-item .link-meta { font-size: 12px; line-height: 1.4; }
.link-item .link-when { white-space: nowrap; }
.link-item.is-bad .link-meta { color: var(--error, #c0392b); }

/* ---------------------------------------------------------- agent mailboxes */
.mb-rows { display: flex; flex-direction: column; gap: 8px; margin-top: 14px; }
.mb-row {
    padding: 10px 12px; border: 1px solid var(--border-color); border-radius: var(--border-radius); background: var(--bg-secondary);
}
.mb-main { display: grid; grid-template-columns: minmax(200px, 1.3fr) minmax(160px, 1fr) auto auto; gap: 12px; align-items: center; }
.mb-row.is-resting .mb-main { opacity: 0.75; }
.mb-row-who { min-width: 0; }
.mb-row-who b { display: block; font-size: 13.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mb-issue .mb-target {
    font-size: 13px; padding: 6px 8px; border: 1px solid var(--border-color); border-radius: 6px;
    background: var(--bg-primary); color: var(--text-primary);
}
.mb-issue .mb-target:focus { outline: none; border-color: var(--border-on); }

/* "Signs as": the saved name as a quiet chip; a field only while changing it. */
.mb-sign { display: flex; align-items: center; gap: 8px; min-width: 0; font-size: 13px; }
.mb-sign-label { color: var(--text-muted); white-space: nowrap; }
.mb-sign-value {
    display: inline-flex; align-items: center; gap: 6px; max-width: 100%; min-width: 0;
    padding: 5px 11px; border: 1px solid var(--border-color); border-radius: 999px;
    background: var(--bg-primary); color: var(--text-primary); font: inherit; font-weight: 600; font-size: 13px;
    cursor: pointer; text-align: left; transition: border-color .15s ease, background .15s ease;
}
.mb-sign-value:hover { border-color: var(--border-on); }
.mb-sign-value:focus { outline: none; }
.mb-sign-value:focus-visible { border-color: var(--border-on); box-shadow: 0 0 0 3px color-mix(in srgb, var(--green-accent) 14%, transparent); }
.mb-sign-value.is-inherited .mb-sign-name { font-weight: 500; color: var(--text-secondary); }
.mb-sign-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mb-sign-hint { font-size: 11px; font-weight: 500; color: var(--text-muted); white-space: nowrap; }
.mb-sign-value.is-saved { border-color: var(--border-on); background: color-mix(in srgb, var(--green-accent) 10%, var(--bg-primary)); }
.mb-sign-value.is-saved::after { content: '✓'; color: var(--green-accent); font-weight: 700; }
.mb-sign.is-editing .mb-sign-value { display: none; }
.mb-sign-form { display: flex; align-items: center; gap: 6px; min-width: 0; flex: 1; }
.mb-sign-form[hidden] { display: none; }
.mb-sign-form input {
    flex: 1; min-width: 0; font: inherit; font-size: 13px; padding: 5px 10px; border: 1px solid var(--border-on); border-radius: 999px;
    background: var(--bg-primary); color: var(--text-primary);
}
.mb-sign-form input:focus { outline: none; border-color: var(--border-on); box-shadow: 0 0 0 3px color-mix(in srgb, var(--green-accent) 14%, transparent); }
.mb-sign-form .btn-sm { padding: 5px 12px; }
.mb-rest { display: flex; align-items: center; gap: 6px; font-size: 13px; white-space: nowrap; cursor: pointer; }
.mb-row-actions { display: flex; gap: 4px; }
@media (max-width: 720px) { .mb-main { grid-template-columns: 1fr; } }

/* The second line: health, warm-up, DNS, and the list of things to fix. */
.mb-health {
    display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; margin-top: 10px; padding-top: 10px;
    border-top: 1px dashed var(--border-color); font-size: 13px;
}
.mb-score { font-weight: 600; font-size: 12.5px; padding: 3px 9px; border-radius: 999px; white-space: nowrap; border: 1px solid transparent; }
.mb-score.is-good { color: var(--success); background: color-mix(in srgb, var(--success) 14%, transparent); }
.mb-score.is-warning { color: var(--warning); background: color-mix(in srgb, var(--warning) 18%, transparent); }
.mb-score.is-bad { color: var(--danger); background: color-mix(in srgb, var(--danger) 14%, transparent); }
.mb-score.is-unchecked { color: var(--text-muted); border-color: var(--border-color); }
.mb-warm { font-size: 13px; }
.mb-dns-row { display: inline-flex; gap: 6px; }
.mb-dns { font-size: 11.5px; font-weight: 600; letter-spacing: .02em; padding: 2px 7px; border-radius: 6px; border: 1px solid var(--border-color); color: var(--text-muted); cursor: default; }
.mb-dns.is-pass { color: var(--success); border-color: color-mix(in srgb, var(--success) 40%, transparent); }
.mb-dns.is-missing { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 40%, transparent); }
.mb-health-actions { margin-left: auto; display: inline-flex; gap: 4px; }
.mb-health-actions .btn-icon.is-on { background: var(--bg-tertiary); }
.mb-issues { flex-basis: 100%; display: flex; flex-direction: column; gap: 6px; margin-top: 4px; }
.mb-issues[hidden] { display: none; }
.mb-issue { padding: 8px 10px; border-radius: 8px; font-size: 13px; line-height: 1.45; border-left: 3px solid var(--border-color); background: var(--bg-primary); }
.mb-issue.is-bad { border-left-color: var(--danger); }
.mb-issue.is-warn { border-left-color: var(--warning); }
.mb-issue.is-info { border-left-color: var(--border-color); color: var(--text-muted); }
.mb-issue .mb-target { width: 64px; padding: 2px 6px; }

/* ------------------------------------------------- admin: community clock */
.admin-community { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px; padding: 12px 14px; margin-bottom: 14px;
    border: 1px solid var(--border-color); border-radius: var(--border-radius); background: var(--bg-tertiary); font-size: 13px; }
.admin-community .switch { margin: 0; }
.admin-community-rate { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.admin-community-rate .form-control { width: 64px; padding: 4px 8px; font-size: 13px; }
.admin-community .admin-head-actions { margin-left: auto; display: inline-flex; gap: 6px; }

/* ------------------------------------------------------ chat: nudge video */
.chat-video-row { display: flex; gap: 14px; align-items: flex-start; }
.chat-video-preview { position: relative; flex: none; width: 320px; aspect-ratio: 16 / 9; border-radius: 10px; overflow: hidden; background: #000; }
.chat-video-preview video, .chat-video-preview iframe { display: block; width: 100%; height: 100%; border: 0; }
.chat-video-kind { position: absolute; left: 6px; top: 6px; padding: 2px 7px; border-radius: 6px; background: rgba(0,0,0,.6); color: #fff; font-size: 11px; font-weight: 600; pointer-events: none; }
.chat-video-fields { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.chat-video-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.chat-video-actions .chat-video-size { width: auto; padding: 5px 28px 5px 10px; font-size: 13px; }
.chat-video-actions [hidden] { display: none !important; }
@media (max-width: 900px) { .chat-video-row { flex-direction: column; } .chat-video-preview { width: 100%; } }

/* --------------------------------------------- chat: the site blocks us */
.chat-csp-warning { margin: 0 0 18px; padding: 12px 14px; border-radius: 10px; border: 1px solid color-mix(in srgb, var(--warning) 45%, var(--border-color));
    background: color-mix(in srgb, var(--warning) 10%, var(--bg-primary)); font-size: 13.5px; line-height: 1.5; }
.chat-csp-warning[hidden] { display: none; }
.chat-csp-warning b { display: block; margin-bottom: 2px; }
.chat-csp-line { margin: 8px 0; padding: 8px 10px; border-radius: 6px; background: var(--bg-tertiary); font-size: 12.5px; white-space: pre-wrap; word-break: break-all; user-select: all; }

/* ------------------------------------------------ chat: check my site */
.chat-check-row { display: flex; gap: 8px; }
.chat-check-row .form-control { flex: 1; }
.chat-check-result { margin-top: 10px; padding: 12px 14px; border-radius: 10px; border: 1px solid var(--border-color); background: var(--bg-tertiary); font-size: 13.5px; line-height: 1.5; }
.chat-check-result[hidden] { display: none; }
.chat-check-result.is-bad { border-color: color-mix(in srgb, var(--warning) 45%, var(--border-color)); background: color-mix(in srgb, var(--warning) 10%, var(--bg-primary)); }
.chat-check-result.is-ok { border-color: color-mix(in srgb, var(--success) 40%, var(--border-color)); background: color-mix(in srgb, var(--success) 8%, var(--bg-primary)); }
.chat-check-result p { margin: 0 0 6px; }
.chat-check-result p:last-child { margin-bottom: 0; }
.chat-check-ok { color: var(--success); font-weight: 600; }
.chat-check-note { color: var(--text-muted); }

/* ------------------------------------------------------- the activity feed */
.feed-filters { display: inline-flex; gap: 4px; flex-wrap: wrap; }
.feed-filter {
    padding: 4px 11px; font: inherit; font-size: 12.5px; border-radius: 999px; cursor: pointer;
    border: 1px solid var(--border-color); background: transparent; color: var(--text-secondary);
}
.feed-filter:hover { border-color: var(--border-on); color: var(--text-primary); }
.feed-filter.is-on { border-color: var(--border-on); background: var(--bg-tertiary); color: var(--text-primary); font-weight: 600; }
.feed { list-style: none; margin: 0; padding: 0; }
.feed-row {
    display: grid; grid-template-columns: 26px 1fr auto; align-items: start; gap: 10px;
    padding: 10px 2px; border-bottom: 1px solid var(--border-color);
}
.feed-row:last-child { border-bottom: 0; }
.feed-ic { display: flex; align-items: center; justify-content: center; width: 26px; height: 26px; border-radius: 50%;
    background: var(--bg-tertiary); color: var(--text-muted); flex: none; }
.feed-ic svg { width: 14px; height: 14px; }
.feed-row.is-in .feed-ic { color: var(--green-accent); background: color-mix(in srgb, var(--green-accent) 12%, transparent); }
.feed-row.is-goal .feed-ic { color: var(--success); background: color-mix(in srgb, var(--success) 14%, transparent); }
.feed-body { min-width: 0; }
.feed-what { display: block; font-size: 13.5px; line-height: 1.45; }
.feed-what code { font-size: 12.5px; padding: 1px 5px; border-radius: 4px; background: var(--bg-tertiary); }
.feed-snip { display: block; margin-top: 2px; font-size: 12.5px; color: var(--text-muted);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.feed-meta { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--text-muted); white-space: nowrap; }
.feed-chan { padding: 1px 7px; border-radius: 999px; background: var(--bg-tertiary); font-size: 11px; font-weight: 600; }
/* The feed scrolls inside its own box: endless, without an endless page. */
.feed-scroll {
    max-height: min(58vh, 560px); overflow-y: auto; overscroll-behavior: contain;
    /* The last row fades at the edge, so "there is more below" reads even
       where the browser paints no scrollbar (phones, and macOS by default). */
    -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 28px), transparent);
    mask-image: linear-gradient(to bottom, #000 calc(100% - 28px), transparent);
}
.feed-scroll.is-end { -webkit-mask-image: none; mask-image: none; }
.feed-end { min-height: 8px; padding: 12px 0 2px; text-align: center; font-size: 12.5px; color: var(--text-muted); }
.feed-row.is-new { animation: feed-in .5s ease; }
@keyframes feed-in { from { opacity: 0; transform: translateY(-6px); } to { opacity: 1; transform: none; } }
@media (max-width: 640px) {
    .feed-row { grid-template-columns: 24px 1fr; }
    .feed-meta { grid-column: 2; margin-top: 2px; }
    .feed-scroll { max-height: 62vh; }
    /* Title over the filters, and the filters in one swipeable line rather
       than wrapping around the title. */
    .card-header:has(.feed-filters) { flex-direction: column; align-items: stretch; gap: 10px; }
    .feed-filters { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; margin: 0 -2px; padding: 0 2px 2px; }
    .feed-filters::-webkit-scrollbar { display: none; }
    .feed-filter { flex: none; }
}

/* The stats sit under Quick Actions now, so they need the gap a card
   would have given them. */
.dashboard-page .card + .stats-grid { margin-top: 20px; }

/* Admin: the per-plan commission amounts, side by side. */
.aff-plan-row { display: flex; gap: 10px; }
.aff-plan { flex: 1; display: flex; align-items: center; gap: 8px; margin: 0; font-size: 13px; color: var(--text-secondary); }
.aff-plan span { flex: none; }
.aff-plan input { width: 100%; }
