/* Inbox 3-pane layout — feature-scoped, imported only by InboxPage. Uses the
   global CSS variables so it stays consistent with the rest of the app. */

.inbox {
  display: grid;
  grid-template-columns: 320px 1fr 300px;
  /* Constrain the single row to the container height (minmax(0,...) lets the
     columns shrink below their content) so each pane scrolls internally
     instead of stretching the grid to content height and scrolling the window. */
  grid-template-rows: minmax(0, 1fr);
  gap: 0;
  height: calc(100dvh - var(--header-height) - (2 * var(--content-padding)));
  min-height: 480px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
}

/* --- Left: conversation list --- */
.conv-list {
  display: flex;
  flex-direction: column;
  border-right: 1px solid var(--color-border);
  min-width: 0;
  min-height: 0;
}

/* --- Filter bar -----------------------------------------------------------
   Two compact rows (search, then status + a Filters disclosure) instead of the
   four stacked rows this replaced, which cost ~230px of a 320px-wide column.
   A third row appears only when filters are actually applied. */

.conv-filterbar {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
  padding: var(--spacing-sm) var(--spacing-md);
  border-bottom: 1px solid var(--color-border);
}

.conv-search-wrap {
  position: relative;
  display: flex;
  align-items: center;
}

.conv-search-icon {
  position: absolute;
  left: 11px;
  color: var(--color-text-subtle);
  pointer-events: none;
}

.conv-search.form-control {
  /* Slightly tighter than a form input: this is a toolbar control, but still
     16px text so mobile Safari does not zoom on focus. */
  min-height: 40px;
  padding: 8px 34px;
  width: 100%;
}

/* The native search clear button would sit under ours. */
.conv-search::-webkit-search-cancel-button { display: none; }

.conv-search-clear {
  position: absolute;
  right: 4px;
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  background: none;
  border-radius: var(--radius-full);
  color: var(--color-text-muted);
}

.conv-search-clear:hover {
  background: var(--color-surface-hover);
  color: var(--color-text);
}

.conv-controls {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
}

/* Segmented Open / Resolved */
.conv-segmented {
  display: inline-flex;
  flex: 1;
  min-width: 0;
  padding: 3px;
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
}

.conv-seg {
  flex: 1;
  min-width: 0;
  min-height: 34px;
  padding: 6px 8px;
  border: none;
  background: none;
  border-radius: 6px;
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--color-text-muted);
  white-space: nowrap;
  transition: background var(--duration-fast) var(--ease-standard),
    color var(--duration-fast) var(--ease-standard);
}

.conv-seg:hover { color: var(--color-text); }

.conv-seg.is-active {
  background: var(--color-surface);
  color: var(--color-primary-active);
  box-shadow: var(--shadow-xs);
}

/* Filters disclosure */
.conv-filter-menu { position: relative; flex-shrink: 0; }

.conv-filter-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 40px;
  padding: 8px 12px;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--color-text-muted);
}

.conv-filter-btn:hover {
  background: var(--color-surface-hover);
  color: var(--color-text);
}

.conv-filter-btn.has-active {
  border-color: var(--color-primary);
  background: var(--color-primary-soft);
  color: var(--color-primary-active);
}

.conv-filter-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: var(--radius-full);
  background: var(--color-primary);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
}

.conv-filter-pop {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  width: 260px;
  max-width: 80vw;
  padding: var(--spacing-md);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  z-index: var(--z-sticky);
}

.conv-pop-check { min-height: 36px; padding: 0 0 var(--spacing-sm); }
.conv-pop-group { margin-bottom: var(--spacing-sm); }
.conv-pop-group .form-control { min-height: 38px; padding: 8px 12px; }

.conv-pop-footer {
  display: flex;
  justify-content: space-between;
  gap: var(--spacing-sm);
  padding-top: var(--spacing-sm);
  border-top: 1px solid var(--color-border);
}

/* Applied filters: wrapped, never clipped, each individually removable. */
.conv-active-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.conv-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: 28px;
  padding: 4px 8px 4px 10px;
  border: 1px solid var(--color-primary-soft-border);
  border-radius: var(--radius-full);
  background: var(--color-primary-soft);
  color: var(--color-info-text);
  font-size: var(--font-size-xs);
  font-weight: 600;
  max-width: 100%;
  overflow-wrap: anywhere;
}

.conv-chip:hover { background: #dbeafe; }

.conv-chip-clear {
  min-height: 28px;
  padding: 4px 8px;
  border: none;
  background: none;
  color: var(--color-text-muted);
  font-size: var(--font-size-xs);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.conv-chip-clear:hover { color: var(--color-text); }

.conv-list-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: var(--spacing-xs);
}

.conv-row {
  display: flex;
  gap: var(--spacing-sm);
  width: 100%;
  padding: 10px 12px;
  border: none;
  background: transparent;
  border-radius: var(--radius-sm);
  cursor: pointer;
  text-align: left;
}

.conv-row:hover {
  background: var(--color-bg);
}

.conv-row.is-active {
  background: var(--color-primary-soft);
  box-shadow: inset 3px 0 0 var(--color-primary);
}

/* Unread should be legible from the name alone, not only from the badge. */
.conv-row.is-unread .conv-name { font-weight: 700; }
.conv-row.is-unread .conv-preview { color: var(--color-text); font-weight: 500; }

.conv-avatar,
.contact-avatar-lg {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-full);
  background: var(--color-primary);
  color: #fff;
  font-weight: 700;
}

/* Must come after .conv-avatar: same specificity, so source order decides.
   All six clear 4.5:1 against the white initial. */
.conv-avatar-t0 { background: #2563eb; }
.conv-avatar-t1 { background: #7c3aed; }
.conv-avatar-t2 { background: #0f766e; }
.conv-avatar-t3 { background: #b45309; }
.conv-avatar-t4 { background: #be123c; }
.conv-avatar-t5 { background: #4338ca; }

.conv-main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.conv-top,
.conv-bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-sm);
}

.conv-name {
  font-weight: 600;
  color: var(--color-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.conv-time {
  font-size: 11px;
  color: var(--color-text-muted);
  white-space: nowrap;
}

.conv-preview {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.conv-badge {
  flex-shrink: 0;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: var(--radius-full);
  background: var(--color-primary);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.conv-load-more {
  display: block;
  margin: var(--spacing-sm) auto;
}

.conv-list-footer {
  padding: 8px var(--spacing-md);
  border-top: 1px solid var(--color-border);
  font-size: 11px;
  color: var(--color-text-muted);
}

/* --- Center: thread --- */
.thread {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
}

.thread-empty {
  align-items: center;
  justify-content: center;
}

.thread-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--spacing-sm) var(--spacing-md);
  border-bottom: 1px solid var(--color-border);
}

.thread-name {
  font-weight: 700;
}

.thread-sub {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* Green here is genuine WhatsApp state (the free-reply window is open), which
   is exactly what the palette reserves green for. */
.window-countdown {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--color-whatsapp-text);
  background: var(--color-whatsapp-soft);
  border: 1px solid #a7f3d0;
  padding: 5px 10px;
  border-radius: var(--radius-full);
  white-space: nowrap;
}

/* Under an hour the same control turns amber — an approaching deadline the
   user may want to act on, not an error. */
.window-countdown.is-urgent {
  color: var(--color-warning-text);
  background: var(--color-warning-soft);
  border-color: #fcd34d;
}

.window-closed-tag {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--color-warning-text);
  background: var(--color-warning-soft);
  border: 1px solid #fcd34d;
  padding: 5px 10px;
  border-radius: var(--radius-full);
  white-space: nowrap;
}

.thread-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: var(--spacing-md);
  background: #f7f9fa;
}

.thread-load-older {
  display: block;
  margin: 0 auto var(--spacing-md);
}

.msg-day-group {
  margin-bottom: var(--spacing-sm);
}

.msg-day-label {
  text-align: center;
  margin: var(--spacing-sm) 0;
  font-size: 11px;
  color: var(--color-text-muted);
}

.msg-row {
  display: flex;
  margin-bottom: 6px;
}

.msg-in {
  justify-content: flex-start;
}

.msg-out {
  justify-content: flex-end;
}

.msg-bubble {
  max-width: 68%;
  padding: 8px 10px;
  border-radius: var(--radius-md);
  background: var(--color-surface);
  box-shadow: var(--shadow-sm);
  word-wrap: break-word;
}

.msg-out .msg-bubble {
  background: #d9fdd3;
}

.msg-bubble.is-failed {
  background: #fee2e2;
}

/* Phase 8.2 — inbound button tap / list pick.
   Static badge, never clickable: it reports state, it is not an action. Paired
   with a visible word rather than colour alone, and neutral (not the blue of
   the outbound Template tag) so it reads as subordinate to the message text.
   nowrap keeps the label whole — it is fixed copy, so it can never overflow. */
.msg-reply-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  font-weight: 600;
  color: var(--color-text-muted);
  background: var(--gray-100);
  border-radius: var(--radius-full);
  padding: 1px 8px;
  margin-bottom: 4px;
  white-space: nowrap;
}

.msg-text {
  margin: 0;
  white-space: pre-wrap;
  font-size: var(--font-size-md);
  color: var(--color-text);
}

.msg-caption {
  margin-top: 4px;
}

.msg-link {
  color: var(--color-info);
  text-decoration: underline;
  word-break: break-all;
}

.msg-out .msg-link {
  color: var(--color-primary-active);
}

/* Link preview card (OpenGraph) */
.link-preview {
  display: block;
  max-width: 320px;
  margin-bottom: 6px;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: rgba(0, 0, 0, 0.05);
  border: 1px solid var(--color-border);
  text-decoration: none;
  color: inherit;
}

.link-preview-img {
  display: block;
  width: 100%;
  max-height: 180px;
  object-fit: cover;
}

.link-preview-body {
  padding: 6px 10px;
}

.link-preview-domain {
  font-size: 10px;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

.link-preview-title {
  font-weight: 600;
  font-size: var(--font-size-sm);
  color: var(--color-text);
  margin-top: 1px;
}

.link-preview-desc {
  font-size: 12px;
  color: var(--color-text-muted);
  margin-top: 2px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.msg-meta {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 4px;
  margin-top: 2px;
}

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

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

.tick-read {
  color: #34b7f1;
}

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

.msg-error {
  margin-top: 4px;
  font-size: 11px;
  color: var(--color-danger);
}

.msg-media {
  display: block;
  margin-bottom: 4px;
}

.msg-media-image {
  max-width: 260px;
  max-height: 260px;
  border-radius: var(--radius-sm);
}

.msg-media-video {
  max-width: 260px;
  border-radius: var(--radius-sm);
}

.msg-media-doc {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--color-primary);
  text-decoration: none;
  overflow-wrap: anywhere;
}

.msg-media-pending,
.msg-media-error {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  font-style: italic;
}

/* --- Composer --- */
.composer {
  position: relative;
  border-top: 1px solid var(--color-border);
  padding: var(--spacing-sm) var(--spacing-md);
  background: var(--color-surface);
}

/* Inline "/shortcut" canned-reply autocomplete — floats above the composer so
   it doesn't shift the chat layout. Reuses the .canned-item rows from team.css. */
.composer-autocomplete {
  position: absolute;
  left: var(--spacing-md);
  right: var(--spacing-md);
  bottom: calc(100% - var(--spacing-sm));
  max-height: 260px;
  overflow-y: auto;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  z-index: 20;
  padding: 4px;
}

.composer-autocomplete-hint {
  font-size: 11px;
  color: var(--color-text-muted);
  padding: 6px 8px;
}

.composer-autocomplete .canned-item.is-active {
  background: var(--color-bg);
}

.composer-row {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
}

.composer-input {
  flex: 1;
}

/* Icon-only composer controls. Full 44px hit box even though the glyph is
   20px — these sit close together above the keyboard on a phone. */
.composer-attach {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap-target);
  height: var(--tap-target);
  flex-shrink: 0;
  border: none;
  background: transparent;
  border-radius: var(--radius-sm);
  color: var(--color-text-muted);
  cursor: pointer;
  padding: 0;
}

.composer-attach:hover {
  background: var(--color-surface-hover);
  color: var(--color-primary);
}

/* Labeled template trigger in the open composer — discoverable (not a bare icon). */
.composer-tpl-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: var(--tap-target);
  border: 1px solid var(--color-border-strong);
  background: var(--color-surface);
  color: var(--color-primary);
  font-size: var(--font-size-sm);
  font-weight: 600;
  cursor: pointer;
  padding: 8px 14px;
  border-radius: var(--radius-full);
  white-space: nowrap;
  flex-shrink: 0;
}
.composer-tpl-btn:hover {
  background: var(--color-primary-soft);
}

.composer-file-input {
  display: none;
}

.composer-preview-name {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.composer-preview {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-sm);
  padding: 6px 10px;
  margin-bottom: var(--spacing-sm);
  background: var(--color-bg);
  border-radius: var(--radius-sm);
  font-size: var(--font-size-sm);
}

.composer-preview-remove {
  border: none;
  background: transparent;
  cursor: pointer;
  color: var(--color-text-muted);
}

.composer-error {
  margin-bottom: var(--spacing-sm);
  color: var(--color-danger);
  font-size: var(--font-size-sm);
}

.composer-closed {
  border-top: 1px solid var(--color-border);
  padding: var(--spacing-md);
  background: #fffbeb;
}

/* The 24h-window notice explains a WhatsApp rule the owner did not choose, so
   it reads as guidance rather than an error they caused. */
.composer-closed-text {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-sm);
  margin: 0;
  color: var(--color-warning-text);
  font-size: var(--font-size-sm);
  line-height: var(--line-height-base);
}

/* --- Right: contact panel --- */
.contact-panel {
  border-left: 1px solid var(--color-border);
  padding: var(--spacing-lg);
  min-height: 0;
  overflow-y: auto;
  text-align: center;
}

.contact-panel-empty {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

.contact-avatar-lg {
  width: 72px;
  height: 72px;
  font-size: 28px;
  margin: 0 auto var(--spacing-sm);
}

.contact-name {
  font-weight: 700;
  font-size: var(--font-size-lg);
}

.contact-phone {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  margin-bottom: var(--spacing-md);
}

.contact-section {
  text-align: left;
  border-top: 1px solid var(--color-border);
  padding-top: var(--spacing-md);
  margin-top: var(--spacing-md);
}

.contact-section-title {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
  margin-bottom: var(--spacing-sm);
}

.contact-details {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4px 12px;
  margin: 0;
  font-size: var(--font-size-sm);
}

.contact-details dt {
  color: var(--color-text-muted);
}

.contact-details dd {
  margin: 0;
  text-align: right;
  word-break: break-all;
}

.contact-placeholder-text {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  font-style: italic;
  margin: 0;
}

/* Narrow screens: collapse the contact panel; stack list over thread. */
@media (max-width: 1024px) {
  .inbox {
    grid-template-columns: 280px 1fr;
  }

  .contact-panel {
    display: none;
  }
}

@media (max-width: 640px) {
  .inbox {
    grid-template-columns: 1fr;
  }
}

/* =========================================================================
   Contact panel — collapsible sections
   -------------------------------------------------------------------------
   The panel is a dense ~320px column that now carries counts, campaigns,
   broadcasts, notes and a history rail, so everything below the header
   collapses. Density is bought with rhythm, not by shrinking text: the type
   floor stays at --font-size-xs (12px) and every header is a full 44px target,
   per the audience note in variables.css.
   ========================================================================= */

.panel-section {
  text-align: left;
  border-top: 1px solid var(--color-border);
}

/* The heading exists for document structure (h3 inside the panel's own
   hierarchy); all of its styling lives on the button it wraps. */
.panel-section-heading {
  margin: 0;
  font-size: inherit;
  font-weight: inherit;
}

.panel-section-head {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  width: 100%;
  /* Full tap target without padding the collapsed panel out of usefulness. */
  min-height: var(--tap-target);
  padding: var(--spacing-sm) var(--spacing-2xs);
  background: none;
  border: 0;
  border-radius: var(--radius-sm);
  color: var(--color-text);
  text-align: left;
  cursor: pointer;
  transition: background-color var(--duration-fast) var(--ease-standard);
}

.panel-section-head:hover {
  background: var(--color-surface-hover);
}

/* Never remove: keyboard users navigate this panel section by section. */
.panel-section-head:focus-visible {
  outline: var(--focus-outline);
  outline-offset: 2px;
}

.panel-section-chevron {
  flex: none;
  color: var(--color-text-subtle);
  transition: transform var(--duration-fast) var(--ease-standard);
}

.panel-section-chevron.is-open {
  transform: rotate(90deg);
}

.panel-section-title {
  /* min-width:0 lets the title shrink instead of shoving the count pill out of
     the row — the count is the part that must never wrap. */
  flex: 1;
  min-width: 0;
  font-size: var(--font-size-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
}

/* A state badge, not a chip: it reports a count and is never itself clickable.
   Hidden from assistive tech — PanelSection renders the same figure as a full
   phrase beside it. */
.panel-section-count {
  flex: none;
  min-width: 20px;
  padding: 0 var(--spacing-xs);
  border-radius: var(--radius-full);
  background: var(--color-surface-hover);
  color: var(--color-text-muted);
  font-size: var(--font-size-xs);
  font-variant-numeric: tabular-nums;
  line-height: 20px;
  text-align: center;
  white-space: nowrap;
}

.panel-section-body {
  padding: 0 var(--spacing-2xs) var(--spacing-md);
  font-size: var(--font-size-sm);
  line-height: var(--line-height-base);
}

/* A nested contact-section would draw a second divider immediately under the
   header it already sits beneath. */
.panel-section-body .contact-section {
  border-top: 0;
  padding-top: 0;
  margin-top: 0;
}

/* Figures in the Overview/Messages tables are read as a column, so they need
   tabular figures — Inter has them, and proportional digits make 11 vs 8 look
   like different indents. */
.panel-section-body .contact-details dd {
  font-variant-numeric: tabular-nums;
}

/* --- List rows (campaigns, broadcasts) --- */
.panel-list,
.panel-timeline {
  list-style: none;
  margin: 0;
  padding: 0;
}

.panel-list-item {
  padding: var(--spacing-sm) 0;
  border-bottom: 1px solid var(--color-border);
}

.panel-list-item:last-child {
  border-bottom: 0;
}

.panel-list-main {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--spacing-sm);
}

/* Wraps rather than truncates. A campaign name is the one thing that
   identifies the row, and an ellipsis with the full value only on hover is
   unreachable by keyboard and touch — so the name gets the extra line. */
.panel-list-title {
  min-width: 0;
  font-weight: 600;
  color: var(--color-text);
  overflow-wrap: anywhere;
}

.panel-list-meta {
  margin-top: var(--spacing-2xs);
  color: var(--color-text-muted);
  font-size: var(--font-size-xs);
  overflow-wrap: anywhere;
}

/* --- History rail --- */
.panel-timeline-item {
  position: relative;
  display: flex;
  gap: var(--spacing-sm);
  padding: 0 0 var(--spacing-md);
}

/* The connecting line, drawn behind the dots and stopped at the last item so
   the rail reads as a finished sequence rather than trailing off. */
.panel-timeline-item::before {
  content: '';
  position: absolute;
  top: var(--spacing-sm);
  bottom: 0;
  left: 3px;
  width: 2px;
  background: var(--color-border);
}

.panel-timeline-item:last-child {
  padding-bottom: 0;
}

.panel-timeline-item:last-child::before {
  display: none;
}

.panel-timeline-dot {
  position: relative;
  flex: none;
  width: 8px;
  height: 8px;
  margin-top: var(--spacing-sm);
  border-radius: var(--radius-full);
  background: var(--color-primary);
}

.panel-timeline-body {
  min-width: 0;
}

/* --- Notes --- */
.contact-note-form {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--spacing-sm);
  margin-bottom: var(--spacing-md);
}

.contact-note-form textarea {
  width: 100%;
  min-height: 64px;
  resize: vertical;
}

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

.contact-note {
  padding: var(--spacing-sm) 0;
  border-bottom: 1px solid var(--color-border);
}

.contact-note:last-child {
  border-bottom: 0;
}

.contact-note-body {
  margin: 0 0 var(--spacing-xs);
  color: var(--color-text);
  /* Agents paste order ids and links in here; let them reflow rather than
     stretch the panel into a horizontal scroll. */
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.contact-note-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-sm);
  color: var(--color-text-muted);
  font-size: var(--font-size-xs);
}

.contact-note-author {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* Text button, but still a real pointer target (WCAG 2.2 target size). */
.panel-text-button {
  flex: none;
  min-height: 24px;
  padding: var(--spacing-2xs) var(--spacing-xs);
  margin-right: calc(var(--spacing-xs) * -1);
  background: none;
  border: 0;
  border-radius: var(--radius-xs);
  color: var(--color-danger);
  font-size: var(--font-size-xs);
  cursor: pointer;
}

.panel-text-button:hover {
  background: var(--color-danger-soft);
}

.panel-text-button:focus-visible {
  outline: var(--focus-outline);
  outline-offset: 1px;
}

/* Motion here is orientation (the chevron points where the section went), so
   it is the first thing to drop when the user asks for less of it. */
@media (prefers-reduced-motion: reduce) {
  .panel-section-head,
  .panel-section-chevron {
    transition: none;
  }
}
/* WhatsApp Connection feature — feature-scoped styles (imported only here). */

.wa-stack {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-lg);
}

.wa-method-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--spacing-md);
}

.wa-method-card {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--spacing-md);
  background: var(--color-surface);
}

.wa-method-card.is-active {
  border-color: var(--color-primary);
  box-shadow: var(--shadow-sm);
}

.wa-method-card.is-disabled {
  opacity: 0.6;
}

.wa-method-title {
  font-weight: 600;
  margin-bottom: var(--spacing-xs);
}

.wa-method-desc {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  margin-bottom: var(--spacing-sm);
}

.wa-steps {
  margin: 0 0 var(--spacing-md);
  padding-left: var(--spacing-lg);
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  line-height: 1.7;
}

.wa-copy-row {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
}

.wa-code {
  flex: 1;
  display: block;
  padding: var(--spacing-sm) var(--spacing-md);
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--font-size-sm);
  word-break: break-all;
}

/* Auto-pause banner. Sits above the card header because the tenant's sending
   has actually stopped — this is not a hint, it is the reason nothing is going
   out, and burying it in a detail row would let them miss it entirely. */
.connection-paused {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: var(--spacing-md);
  border-bottom: 1px solid var(--color-border);
  background: var(--color-danger-soft, rgba(220, 38, 38, 0.08));
  color: var(--color-text);
  font-size: var(--font-size-sm);
  line-height: 1.5;
}

.connection-paused strong {
  color: var(--color-danger);
}

/* Missing webhook fields. Warning-coloured rather than error: the connection
   works, but specific events will never arrive — a silent gap, not a failure. */
.wa-missing-fields {
  margin: var(--spacing-md) 0;
  padding: var(--spacing-md);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--color-warning, #d97706);
  border-radius: var(--radius-md);
  font-size: var(--font-size-sm);
  line-height: 1.5;
}

.wa-missing-fields ul {
  margin: var(--spacing-sm) 0;
  padding-left: var(--spacing-md);
}

.wa-missing-fields code {
  font-family: var(--font-mono, monospace);
}

.wa-fields-ok {
  margin: var(--spacing-md) 0;
  font-size: var(--font-size-sm);
  color: var(--color-success);
}
/* =========================================================================
   Design tokens — single source of truth for the whole SPA.

   Brand: deep "trust blue" primary on a navy shell. Deliberately NOT
   WhatsApp green: (a) Meta's brand guidelines don't allow a third-party tool
   to dress itself as WhatsApp, and (b) green is reserved here as a *semantic*
   colour for WhatsApp state (connected, delivered, window open) so it stays
   meaningful instead of decorative.

   Audience note: this product is used by non-technical small-business owners
   in India, often on mid-range phones. Base text is 16px, muted text still
   clears 4.5:1, and tap targets are 44px. Do not shrink these.
   ========================================================================= */

:root {
  /* ---- Brand -------------------------------------------------------- */
  --color-primary: #2563eb;
  --color-primary-hover: #1d4ed8;
  --color-primary-active: #1e40af;
  --color-primary-soft: #eff6ff;
  --color-primary-soft-border: #bfdbfe;
  --color-on-primary: #ffffff;

  /* Navy shell used by the sidebar / brand mark */
  --color-brand-navy: #0f1b33;
  --color-brand-navy-soft: #1a2a4a;

  /* ---- WhatsApp semantics (state only — never chrome) ---------------- */
  --color-whatsapp: #25d366;
  --color-whatsapp-deep: #128c7e;
  --color-whatsapp-soft: #e7f9ef;
  /* Text-safe green: --color-whatsapp-deep only reaches 3.78:1 on the soft
     background, under the 4.5:1 minimum. Use this for green text. */
  --color-whatsapp-text: #0b6b52;

  /* ---- Status ------------------------------------------------------- */
  --color-success: #15803d;
  --color-success-soft: #dcfce7;
  --color-success-text: #14532d;

  --color-warning: #b45309;
  --color-warning-soft: #fef3c7;
  --color-warning-text: #78350f;

  --color-danger: #dc2626;
  --color-danger-hover: #b91c1c;
  --color-danger-soft: #fee2e2;
  --color-danger-text: #991b1b;

  --color-info: #2563eb;
  --color-info-soft: #dbeafe;
  --color-info-text: #1e40af;

  /* ---- Neutrals (blue-tinted slate, harmonises with the brand) ------- */
  --gray-50: #f8fafc;
  --gray-100: #f1f5f9;
  --gray-200: #e2e8f0;
  --gray-300: #cbd5e1;
  --gray-400: #94a3b8;
  --gray-500: #64748b;
  --gray-600: #475569;
  --gray-700: #334155;
  --gray-800: #1e293b;
  --gray-900: #0f172a;

  /* ---- Semantic surfaces -------------------------------------------- */
  --color-bg: var(--gray-100);
  --color-surface: #ffffff;
  --color-surface-sunken: var(--gray-50);
  --color-surface-hover: var(--gray-100);
  --color-border: var(--gray-200);
  --color-border-strong: var(--gray-300);

  --color-text: var(--gray-900);
  --color-text-muted: var(--gray-600);   /* 7.5:1 on white */
  --color-text-subtle: var(--gray-500);  /* 4.8:1 — labels only, never body */

  /* Sidebar */
  --color-sidebar-bg: var(--color-brand-navy);
  --color-sidebar-text: #c7d2e4;
  --color-sidebar-text-strong: #ffffff;
  --color-sidebar-heading: #7d8db0;
  --color-sidebar-hover: rgba(255, 255, 255, 0.07);
  --color-sidebar-active: var(--color-primary);

  /* ---- Radii --------------------------------------------------------- */
  --radius-xs: 4px;
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-full: 999px;

  /* ---- Spacing (4pt rhythm) ------------------------------------------ */
  --spacing-2xs: 2px;
  --spacing-xs: 4px;
  --spacing-sm: 8px;
  --spacing-md: 16px;
  --spacing-lg: 24px;
  --spacing-xl: 32px;
  --spacing-2xl: 48px;

  /* ---- Typography ----------------------------------------------------- */
  /* Plus Jakarta Sans = friendly geometric headings (approachable, not
     corporate-cold). Inter = workhorse UI text, excellent at 14–16px with
     tabular figures. Noto Sans Devanagari keeps Hindi/Marathi contact names
     and message previews from falling back to a mismatched system font. */
  --font-sans: 'Inter', 'Noto Sans Devanagari', -apple-system, BlinkMacSystemFont,
    'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --font-display: 'Plus Jakarta Sans', var(--font-sans);
  --font-mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;

  --font-size-xs: 12px;
  --font-size-sm: 14px;
  --font-size-md: 16px;
  --font-size-lg: 18px;
  --font-size-xl: 22px;
  --font-size-2xl: 28px;

  --line-height-tight: 1.25;
  --line-height-base: 1.55;

  /* ---- Elevation ------------------------------------------------------ */
  --shadow-xs: 0 1px 2px rgba(15, 23, 42, 0.06);
  --shadow-sm: 0 1px 3px rgba(15, 23, 42, 0.08), 0 1px 2px rgba(15, 23, 42, 0.04);
  --shadow-md: 0 4px 12px rgba(15, 23, 42, 0.08);
  --shadow-lg: 0 12px 32px rgba(15, 23, 42, 0.14);

  /* ---- Focus (never remove — keyboard users depend on it) ------------- */
  --focus-ring: 0 0 0 3px rgba(37, 99, 235, 0.35);
  --focus-ring-danger: 0 0 0 3px rgba(220, 38, 38, 0.3);
  --focus-outline: 2px solid var(--color-primary);

  /* ---- Motion ---------------------------------------------------------- */
  --duration-fast: 120ms;
  --duration-base: 200ms;
  --duration-slow: 300ms;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);

  /* ---- Layering -------------------------------------------------------- */
  --z-sticky: 20;
  --z-drawer-scrim: 60;
  --z-drawer: 70;
  --z-modal: 100;
  --z-toast: 200;

  /* ---- Layout ---------------------------------------------------------- */
  --sidebar-width: 264px;
  /* Icon-rail width when the sidebar is collapsed: a 44px target plus gutters. */
  --sidebar-width-collapsed: 76px;
  --header-height: 64px;
  --tap-target: 44px;
  --content-max: 1280px;
  /* Padding around .app-content. Read by the inbox to size its full-height
     3-pane grid, so it must stay in sync with the breakpoint override. */
  --content-padding: var(--spacing-lg);
}

*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html,
body,
#root {
  height: 100%;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  font-family: var(--font-sans);
  font-size: var(--font-size-md);
  color: var(--color-text);
  background: var(--color-bg);
  line-height: var(--line-height-base);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* Numbers in tables, counters and timers must not jitter as they change. */
  font-variant-numeric: tabular-nums;
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  line-height: var(--line-height-tight);
  letter-spacing: -0.01em;
  font-weight: 700;
}

a {
  color: var(--color-primary);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

button {
  font-family: inherit;
  font-size: inherit;
  cursor: pointer;
  /* Removes the 300ms tap delay without disabling pinch-zoom. */
  touch-action: manipulation;
}

button:disabled {
  cursor: not-allowed;
}

input,
select,
textarea {
  font-family: inherit;
  font-size: inherit;
  color: inherit;
}

ul {
  list-style: none;
}

img,
svg {
  max-width: 100%;
}

svg {
  flex-shrink: 0;
}

/* One consistent, always-visible keyboard focus treatment. Pointer users
   never see it; keyboard users always do. */

:focus-visible {
  outline: var(--focus-outline);
  outline-offset: 2px;
  border-radius: var(--radius-xs);
}

:focus:not(:focus-visible) {
  outline: none;
}

/* Long URLs, webhook secrets, template IDs and pasted customer content must
   reflow instead of blowing out the layout. */

.wrap-anywhere {
  overflow-wrap: anywhere;
}

::selection {
  background: var(--color-primary-soft-border);
  color: var(--color-text);
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* Page-level headings. Kept deliberately large: the primary audience is
   non-technical, so scanability beats density. */

.page-title {
  font-family: var(--font-display);
  font-size: var(--font-size-xl);
  font-weight: 700;
  color: var(--color-text);
}

.page-subtitle {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  margin-top: 4px;
  max-width: 68ch;
}

.section-title {
  font-family: var(--font-display);
  font-size: var(--font-size-lg);
  font-weight: 700;
}

.stat-value {
  font-family: var(--font-display);
  font-size: var(--font-size-2xl);
  font-weight: 700;
  line-height: 1.1;
}

.stat-label {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  margin-top: 4px;
}

/* A one-line, plain-English explanation under a number or field. This is the
   main tool for making the product legible to non-technical owners — use it
   liberally instead of assuming the label is self-evident. */

.hint {
  color: var(--color-text-muted);
  font-size: var(--font-size-xs);
  line-height: 1.5;
}

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

.text-subtle { color: var(--color-text-subtle); }

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

.text-success { color: var(--color-success); }

.text-sm { font-size: var(--font-size-sm); }

.text-xs { font-size: var(--font-size-xs); }

.text-strong { font-weight: 600; }

.text-mono { font-family: var(--font-mono); font-size: var(--font-size-sm); }

/* Visually hidden but available to screen readers. */

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.flex { display: flex; }

.flex-center { display: flex; align-items: center; justify-content: center; }

.flex-between { display: flex; align-items: center; justify-content: space-between; }

.grid { display: grid; }

.gap-sm { gap: var(--spacing-sm); }

.gap-md { gap: var(--spacing-md); }

.gap-lg { gap: var(--spacing-lg); }

.page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: var(--spacing-lg);
  gap: var(--spacing-md);
}

.page-actions { display: flex; gap: var(--spacing-sm); }

.page-center {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-md);
  min-height: 60vh;
  text-align: center;
}

/* =========================================================================
   App shell: sidebar + header + content.

   Desktop  (>=1024px): sidebar is a permanent column.
   Below that          : sidebar becomes an off-canvas drawer with a scrim,
                         opened from the hamburger in the header.
   Breakpoint overrides live in responsive.css.
   ========================================================================= */

.app-shell {
  display: flex;
  min-height: 100vh;
  min-height: 100dvh;
}

/* ---- Sidebar ------------------------------------------------------------ */

.app-sidebar {
  width: var(--sidebar-width);
  /* Width, not transform: the sidebar is in normal flow and the main column
     must reflow with it. This fires once per click, not per frame of a
     gesture, so the reflow cost is acceptable here. */
  transition: width var(--duration-base) var(--ease-standard);
  background: var(--color-sidebar-bg);
  color: var(--color-sidebar-text);
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100dvh;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.sidebar-brand {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  padding: var(--spacing-md);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  position: sticky;
  top: 0;
  background: var(--color-sidebar-bg);
  z-index: 1;
}

.brand-mark {
  display: inline-flex;
  color: var(--color-primary);
  flex-shrink: 0;
}

.sidebar-brand-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.3;
}

.sidebar-brand-name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--font-size-md);
  color: var(--color-sidebar-text-strong);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sidebar-brand-sub {
  font-size: var(--font-size-xs);
  color: var(--color-sidebar-heading);
}

/* Drawer-only control; hidden on desktop where the sidebar is permanent. */

.sidebar-close {
  display: none;
  margin-left: auto;
  background: none;
  border: none;
  color: var(--color-sidebar-text);
  width: var(--tap-target);
  height: var(--tap-target);
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-sm);
}

.sidebar-close:hover { background: var(--color-sidebar-hover); }

/* Desktop collapse toggle. Hidden on mobile, where the sidebar is a drawer and
   the header hamburger already opens it. */

.sidebar-collapse-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap-target);
  height: var(--tap-target);
  flex-shrink: 0;
  background: none;
  border: none;
  border-radius: var(--radius-sm);
  color: var(--color-sidebar-text);
  cursor: pointer;
}

.sidebar-collapse-btn:hover {
  background: var(--color-sidebar-hover);
  color: var(--color-sidebar-text-strong);
}

.sidebar-collapse-btn:focus-visible {
  outline: 2px solid #fff;
  outline-offset: -2px;
}

/* ---- Collapsed (icon rail) ---------------------------------------------- */

.app-sidebar.is-collapsed { width: var(--sidebar-width-collapsed); }

.app-sidebar.is-collapsed .sidebar-brand {
  justify-content: center;
  padding: var(--spacing-md) 0;
}

/* The mark and wordmark have no room at 76px; the toggle stays so the rail can
   always be reopened from the same place it was closed. */

.app-sidebar.is-collapsed .sidebar-brand-logo,
.app-sidebar.is-collapsed .sidebar-brand-text { display: none; }

.app-sidebar.is-collapsed .sidebar-nav { padding-left: 0; padding-right: 0; }

.app-sidebar.is-collapsed .sidebar-link {
  justify-content: center;
  padding: 10px 0;
  margin: 0 auto;
  width: var(--tap-target);
}

/* Visually hidden, NOT removed — this text is the link's accessible name, so
   deleting it would leave screen reader users with an unlabelled icon. */

.app-sidebar.is-collapsed .sidebar-link-label {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Heading text goes, but the element stays as a rule so the grouping the
   expanded sidebar establishes is still readable as separation. */

.app-sidebar.is-collapsed .sidebar-section-title {
  font-size: 0;
  padding: 0;
  margin: 0 auto var(--spacing-sm);
  width: 28px;
  height: 1px;
  background: rgba(255, 255, 255, 0.14);
}

/* Tooltip for the collapsed rail. position: fixed so it escapes the sidebar's
   scroll container; shown on hover AND keyboard focus (see Sidebar.jsx) so it
   is never a pointer-only affordance. */

.sidebar-tip {
  position: fixed;
  left: calc(var(--sidebar-width-collapsed) + 8px);
  transform: translateY(-50%);
  z-index: var(--z-drawer);
  background: var(--gray-900);
  color: #fff;
  padding: 7px 11px;
  border-radius: var(--radius-sm);
  font-size: var(--font-size-sm);
  font-weight: 600;
  white-space: nowrap;
  box-shadow: var(--shadow-md);
  pointer-events: none;
}

.sidebar-nav {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-lg);
  padding: var(--spacing-md) var(--spacing-sm) var(--spacing-xl);
}

.sidebar-section {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* Section headings are the whole point of the grouping — they tell an owner
   which part of the product they are in before they read any item. */

.sidebar-section-title {
  font-size: var(--font-size-xs);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-sidebar-heading);
  padding: 0 12px var(--spacing-xs);
}

.sidebar-link {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: var(--tap-target);
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  color: var(--color-sidebar-text);
  font-size: var(--font-size-sm);
  font-weight: 500;
  transition: background var(--duration-fast) var(--ease-standard),
    color var(--duration-fast) var(--ease-standard);
}

.sidebar-link:hover {
  background: var(--color-sidebar-hover);
  color: var(--color-sidebar-text-strong);
  text-decoration: none;
}

.sidebar-link-icon {
  color: var(--color-sidebar-heading);
  transition: color var(--duration-fast) var(--ease-standard);
}

.sidebar-link:hover .sidebar-link-icon { color: var(--color-sidebar-text-strong); }

.sidebar-link.is-active {
  background: var(--color-sidebar-active);
  color: #fff;
  font-weight: 600;
}

.sidebar-link.is-active .sidebar-link-icon { color: #fff; }

.sidebar-link-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sidebar-link:focus-visible {
  outline: 2px solid #fff;
  outline-offset: -2px;
}

/* Scrim behind the mobile drawer. */

.app-scrim {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.55);
  z-index: var(--z-drawer-scrim);
}

/* ---- Main column -------------------------------------------------------- */

.app-main {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.app-header {
  height: var(--header-height);
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  padding: 0 var(--spacing-md);
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
}

.header-menu-btn {
  display: none;
  width: var(--tap-target);
  height: var(--tap-target);
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  border-radius: var(--radius-sm);
  color: var(--color-text);
}

.header-menu-btn:hover { background: var(--color-surface-hover); }

.app-header-spacer { flex: 1; }

.app-header-user {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
}

/* Account dropdown */

.header-menu { position: relative; }

.header-avatar-btn {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  min-height: var(--tap-target);
  padding: 4px 8px 4px 4px;
  background: none;
  border: 1px solid transparent;
  border-radius: var(--radius-full);
  color: var(--color-text);
}

.header-avatar-btn:hover {
  background: var(--color-surface-hover);
  border-color: var(--color-border);
}

.header-avatar {
  width: 34px;
  height: 34px;
  border-radius: var(--radius-full);
  background: var(--color-primary-soft);
  color: var(--color-primary-active);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--font-size-xs);
  font-weight: 700;
  flex-shrink: 0;
}

.header-avatar-name {
  font-size: var(--font-size-sm);
  font-weight: 600;
  max-width: 14ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.header-avatar-caret { color: var(--color-text-subtle); }

.header-dropdown {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  min-width: 240px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  padding: var(--spacing-xs);
  z-index: var(--z-sticky);
}

.header-dropdown-identity {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--color-border);
  margin-bottom: var(--spacing-xs);
}

.header-dropdown-name { font-weight: 600; font-size: var(--font-size-sm); }

.header-dropdown-email { color: var(--color-text-muted); font-size: var(--font-size-xs); }

.header-dropdown-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: var(--tap-target);
  padding: 10px 12px;
  background: none;
  border: none;
  border-radius: var(--radius-sm);
  font-size: var(--font-size-sm);
  font-weight: 500;
  color: var(--color-text);
  text-align: left;
}

.header-dropdown-item:hover { background: var(--color-surface-hover); }

.header-dropdown-item.is-danger { color: var(--color-danger); }

.header-dropdown-item.is-danger:hover { background: var(--color-danger-soft); }

.app-content {
  padding: var(--content-padding);
  flex: 1;
  width: 100%;
  max-width: var(--content-max);
  margin: 0 auto;
}

/* The inbox is a full-bleed app surface: its 3-pane grid needs every pixel of
   width, so it opts out of the reading-width cap that suits normal pages. */

.app-content:has(> .inbox) {
  max-width: none;
}

/* ---- Auth shell --------------------------------------------------------- */

.auth-shell {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--spacing-lg) var(--spacing-md);
  background:
    radial-gradient(1000px 600px at 15% -10%, rgba(37, 99, 235, 0.35), transparent 60%),
    linear-gradient(160deg, var(--color-brand-navy), #1b2f57);
}

.auth-card {
  width: 100%;
  max-width: 440px;
  padding: var(--spacing-xl);
  box-shadow: var(--shadow-lg);
}

.auth-brand {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--font-size-md);
  margin-bottom: var(--spacing-lg);
}

.auth-title { font-size: var(--font-size-xl); }

.auth-subtitle {
  color: var(--color-text-muted);
  margin-top: var(--spacing-xs);
  margin-bottom: var(--spacing-lg);
  font-size: var(--font-size-sm);
}

.auth-footer {
  margin-top: var(--spacing-lg);
  padding-top: var(--spacing-md);
  border-top: 1px solid var(--color-border);
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  text-align: center;
}

/* ---- Small shared blocks ------------------------------------------------ */

.detail-list { display: flex; flex-direction: column; gap: var(--spacing-sm); }

.detail-row {
  display: flex;
  justify-content: space-between;
  gap: var(--spacing-md);
  padding: var(--spacing-sm) 0;
  border-bottom: 1px solid var(--color-border);
}

.detail-row:last-child { border-bottom: none; }

.detail-row dt { color: var(--color-text-muted); font-size: var(--font-size-sm); }

.detail-row dd { font-weight: 600; text-align: right; overflow-wrap: anywhere; }

.dashboard-cards { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }

/* Notification / sound permission banner */

.notif-nudge {
  display: flex;
  align-items: center;
  gap: var(--spacing-md);
  flex-wrap: wrap;
  margin: var(--spacing-md) var(--spacing-lg) 0;
  padding: 12px var(--spacing-md);
  background: var(--color-primary-soft);
  border: 1px solid var(--color-primary-soft-border);
  border-radius: var(--radius-md);
  font-size: var(--font-size-sm);
}

.notif-nudge-text {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  flex: 1;
  min-width: 240px;
  color: var(--color-info-text);
}

.notif-nudge-actions { display: flex; gap: var(--spacing-sm); }

.form-group {
  margin-bottom: var(--spacing-md);
}

/* Always a visible label. A placeholder is not a label — it disappears the
   moment someone starts typing, which is exactly when a hesitant user needs
   it most. */

.form-label {
  display: block;
  font-size: var(--font-size-sm);
  font-weight: 600;
  margin-bottom: 6px;
  color: var(--color-text);
}

.form-label-required::after {
  content: ' *';
  color: var(--color-danger);
  font-weight: 700;
}

.form-label-optional {
  font-weight: 400;
  color: var(--color-text-subtle);
  font-size: var(--font-size-xs);
  margin-left: 4px;
}

.form-control {
  width: 100%;
  /* 16px is deliberate: anything smaller makes iOS Safari zoom the page on
     focus, which feels like a bug to a non-technical user. */
  font-size: var(--font-size-md);
  min-height: var(--tap-target);
  padding: 11px 14px;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-text);
  transition: border-color var(--duration-fast) var(--ease-standard),
    box-shadow var(--duration-fast) var(--ease-standard);
}

.form-control::placeholder { color: var(--color-text-subtle); }

.form-control:hover:not(:disabled):not(:focus) { border-color: var(--color-text-subtle); }

.form-control:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: var(--focus-ring);
}

.form-control:disabled {
  background: var(--color-surface-sunken);
  color: var(--color-text-subtle);
  cursor: not-allowed;
}

/* Read-only is NOT disabled: the value still matters and stays readable. */

.form-control[readonly] {
  background: var(--color-surface-sunken);
  color: var(--color-text);
}

.form-control.is-invalid {
  border-color: var(--color-danger);
  background: #fffafa;
}

.form-control.is-invalid:focus { box-shadow: var(--focus-ring-danger); }

textarea.form-control {
  min-height: 96px;
  resize: vertical;
  line-height: var(--line-height-base);
}

select.form-control {
  appearance: none;
  padding-right: 40px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%23475569' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
}

/* Errors sit next to the field they belong to, with an icon so the message
   does not rely on red alone. */

.form-error {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  color: var(--color-danger-text);
  font-size: var(--font-size-xs);
  font-weight: 500;
  margin-top: 6px;
}

.form-helper {
  display: block;
  color: var(--color-text-muted);
  font-size: var(--font-size-xs);
  margin-top: 6px;
  line-height: 1.5;
}

/* Checkbox / radio rows get the full row as a tap target. */

.form-check {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  min-height: var(--tap-target);
  padding: 8px 0;
  cursor: pointer;
}

.form-check input[type='checkbox'],
.form-check input[type='radio'] {
  width: 20px;
  height: 20px;
  margin-top: 2px;
  accent-color: var(--color-primary);
  flex-shrink: 0;
  cursor: pointer;
}

.form-check-label { font-size: var(--font-size-sm); }

.form-fieldset {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--spacing-md);
  margin-bottom: var(--spacing-md);
}

.form-fieldset legend {
  font-size: var(--font-size-sm);
  font-weight: 700;
  padding: 0 6px;
}

/* =========================================================================
   Field rows.

   Every container that places fields side by side hits the same trap: each
   cell stacks its own label above its own control, so the moment one label
   wraps to a second line that cell's control drops below its neighbours —
   the "every second box is going down" effect.

   `align-items: end` bottom-aligns the cells, so the controls always sit on
   one line no matter how tall a label gets. Controls are the strong
   horizontal rule the eye tracks, so aligning those (rather than the labels)
   is what reads as tidy.

   Any new side-by-side field container must be added to this list.
   ========================================================================= */

.form-row,
.sources-form-row,
.sources-map-row,
.fb-field-body,
.seg-rule,
.modal-row {
  align-items: end;
}

/* Fields in a row own no bottom margin — the row's gap handles spacing. */

.form-row > .form-group,
.sources-form-row > .form-group,
.fb-field-body > .form-group,
.form-row > .tpl-field,
.sources-form-row > .tpl-field {
  margin-bottom: 0;
}

/* A control with no label above it still has to line up with ones that do,
   so it gets pushed to the bottom of the row like everything else. */

.form-row > .form-control,
.sources-map-row > .form-control,
.seg-rule > .form-control {
  align-self: end;
}

.form-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--spacing-md);
}

/* Inline notices inside forms */

.form-notice {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-sm);
  background: var(--color-success-soft);
  color: var(--color-success-text);
  border: 1px solid #a7f3d0;
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  font-size: var(--font-size-sm);
  margin-bottom: var(--spacing-md);
}

.form-notice-info {
  background: var(--color-primary-soft);
  color: var(--color-info-text);
  border-color: var(--color-primary-soft-border);
}

.form-notice-warning {
  background: var(--color-warning-soft);
  color: var(--color-warning-text);
  border-color: #fcd34d;
}

.otp-input {
  letter-spacing: 0.5em;
  text-align: center;
  font-size: var(--font-size-xl);
  font-weight: 600;
}

.link-button {
  background: none;
  border: none;
  color: var(--color-primary);
  font-size: var(--font-size-sm);
  font-weight: 600;
  padding: 6px 0;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.link-button:hover { color: var(--color-primary-hover); }

/* Every button clears the 44px minimum touch target. The audience is
   phone-first and often not tech-confident — mis-taps are expensive here. */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-sm);
  min-height: var(--tap-target);
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--font-size-sm);
  line-height: 1.2;
  padding: 11px 18px;
  white-space: nowrap;
  transition: background var(--duration-fast) var(--ease-standard),
    border-color var(--duration-fast) var(--ease-standard),
    box-shadow var(--duration-fast) var(--ease-standard);
}

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

.btn:active:not(:disabled) { transform: translateY(1px); }

/* A 55%-opacity blue still reads as a live button that has gone wrong. Solid
   variants instead drop to flat grey, which is unambiguously "not available
   yet"; outline/ghost variants just fade, since they have no fill to lose. */

.btn:disabled {
  cursor: not-allowed;
  box-shadow: none;
}

.btn-primary:disabled,
.btn-danger:disabled,
.btn-whatsapp:disabled,
.btn-secondary:disabled {
  background: var(--gray-200);
  border-color: var(--gray-200);
  color: var(--color-text-muted);
}

.btn-outline:disabled,
.btn-ghost:disabled {
  opacity: 0.5;
}

.btn:disabled:active { transform: none; }

.btn-primary {
  background: var(--color-primary);
  color: var(--color-on-primary);
  box-shadow: var(--shadow-xs);
}

.btn-primary:hover:not(:disabled) { background: var(--color-primary-hover); }

.btn-primary:active:not(:disabled) { background: var(--color-primary-active); }

.btn-secondary {
  background: var(--color-primary-soft);
  color: var(--color-primary-active);
  border-color: var(--color-primary-soft-border);
}

.btn-secondary:hover:not(:disabled) { background: #dbeafe; }

.btn-outline {
  background: var(--color-surface);
  border-color: var(--color-border-strong);
  color: var(--color-text);
}

.btn-outline:hover:not(:disabled) {
  background: var(--color-surface-hover);
  border-color: var(--color-text-subtle);
}

.btn-ghost {
  background: transparent;
  color: var(--color-text-muted);
}

.btn-ghost:hover:not(:disabled) {
  background: var(--color-surface-hover);
  color: var(--color-text);
}

/* Destructive actions get the danger colour AND sit apart from primary
   actions in the markup — colour alone must never be the only signal. */

.btn-danger {
  background: var(--color-danger);
  color: #fff;
}

.btn-danger:hover:not(:disabled) { background: var(--color-danger-hover); }

.btn-danger:focus-visible { box-shadow: var(--focus-ring-danger); }

/* WhatsApp-specific affirmative actions (connect number, send test). Green is
   reserved for genuine WhatsApp state so it keeps its meaning. */

.btn-whatsapp {
  background: var(--color-whatsapp-deep);
  color: #fff;
}

.btn-whatsapp:hover:not(:disabled) { background: #0d7a6d; }

/* `sm` stays visually compact but keeps a 40px hit box on touch. */

.btn-sm {
  padding: 8px 14px;
  font-size: var(--font-size-sm);
  min-height: 40px;
}

.btn-md { padding: 11px 18px; }

.btn-lg {
  padding: 14px 24px;
  font-size: var(--font-size-md);
  min-height: 52px;
}

.btn-block { width: 100%; }

.btn-spinner {
  width: 15px;
  height: 15px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  opacity: 0.8;
  animation: spin 0.6s linear infinite;
}

/* Icon-only button. Always pair with aria-label — see Button/Icon usage. */

.btn-icon {
  width: var(--tap-target);
  height: var(--tap-target);
  min-height: var(--tap-target);
  padding: 0;
  border-radius: var(--radius-sm);
}

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

/* Shared "remove this row" control for repeatable rows (segment rules, source
   field mappings, form fields). Each of these had its own ad-hoc button —
   a bare glyph here, a bordered box there, a saturated red one elsewhere. */

.btn-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--color-text-subtle);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-standard),
    color var(--duration-fast) var(--ease-standard);
}

.btn-remove:hover {
  background: var(--color-danger-soft);
  color: var(--color-danger);
}

.btn-remove:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring-danger);
}

.btn-remove:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.btn-remove:disabled:hover {
  background: none;
  color: var(--color-text-subtle);
}

/* Reorder controls, sized to sit beside .btn-remove as one control group. */

.btn-move {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  padding: 0;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-text-muted);
  cursor: pointer;
}

.btn-move:hover:not(:disabled) {
  background: var(--color-surface-hover);
  color: var(--color-text);
}

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

.btn-move:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* Tables scroll inside their own container — the page body must never scroll
   sideways on a phone. */

.table-wrapper {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  padding: 0;
}

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--font-size-sm);
}

.table th,
.table td {
  text-align: left;
  padding: 14px 16px;
  border-bottom: 1px solid var(--color-border);
  vertical-align: middle;
}

.table-header th {
  font-size: var(--font-size-xs);
  font-weight: 700;
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  background: var(--color-surface-sunken);
  white-space: nowrap;
  position: sticky;
  top: 0;
  z-index: 1;
}

.table tbody tr:last-child td { border-bottom: none; }

.table-row {
  transition: background var(--duration-fast) var(--ease-standard);
}

.table-row:hover { background: var(--color-primary-soft); }

.table-primary-cell {
  font-weight: 600;
  color: var(--color-text);
}

/* Numeric columns line up and stay aligned as values change. */

.table-numeric {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.table-actions {
  text-align: right;
  white-space: nowrap;
}

.table-actions .btn + .btn { margin-left: var(--spacing-xs); }

.modal-overlay {
  position: fixed;
  inset: 0;
  /* Blur signals that the background is dismissible, not just decorated. */
  background: rgba(15, 23, 42, 0.5);
  backdrop-filter: blur(2px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--spacing-lg);
  z-index: var(--z-modal);
  animation: modal-fade var(--duration-base) var(--ease-out);
}

.modal-container {
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  width: 100%;
  max-width: 480px;
  box-shadow: var(--shadow-lg);
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  animation: modal-rise var(--duration-base) var(--ease-out);
}

.modal-lg { max-width: 720px; }

.modal-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--spacing-md);
  padding: var(--spacing-lg) var(--spacing-lg) var(--spacing-md);
  flex-shrink: 0;
}

.modal-title {
  font-family: var(--font-display);
  font-size: var(--font-size-lg);
  font-weight: 700;
}

.modal-subtitle {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  margin-top: 4px;
}

.modal-close {
  width: var(--tap-target);
  height: var(--tap-target);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  background: none;
  border: none;
  border-radius: var(--radius-sm);
  color: var(--color-text-muted);
  margin: -8px -8px 0 0;
}

.modal-close:hover {
  background: var(--color-surface-hover);
  color: var(--color-text);
}

.modal-body {
  padding: 0 var(--spacing-lg) var(--spacing-lg);
  overflow-y: auto;
  overscroll-behavior: contain;
  flex: 1;
}

/* Scroll shadows. Tall dialogs (source editor, form builder) previously just
   cut off at the footer with no hint that anything was below, which read as a
   broken layout. The `local` gradients mask the `scroll` ones at each end, so a
   shadow appears only on the side that actually has more content. */

.modal-body-scroll {
  background:
    linear-gradient(var(--color-surface) 30%, rgba(255, 255, 255, 0)) top / 100% 22px no-repeat local,
    linear-gradient(rgba(255, 255, 255, 0), var(--color-surface) 70%) bottom / 100% 22px no-repeat local,
    radial-gradient(farthest-side at 50% 0, rgba(15, 23, 42, 0.13), rgba(15, 23, 42, 0)) top / 100% 9px no-repeat scroll,
    radial-gradient(farthest-side at 50% 100%, rgba(15, 23, 42, 0.13), rgba(15, 23, 42, 0)) bottom / 100% 9px no-repeat scroll;
}

.modal-footer {
  padding: var(--spacing-md) var(--spacing-lg);
  border-top: 1px solid var(--color-border);
  background: var(--color-surface-sunken);
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
  display: flex;
  justify-content: flex-end;
  gap: var(--spacing-sm);
  flex-shrink: 0;
}

.confirm-message {
  color: var(--color-text);
  font-size: var(--font-size-md);
  line-height: var(--line-height-base);
}

/* Destructive confirmations lead with a warning icon so the consequence is
   visible before the button colour is. */

.confirm-danger {
  display: flex;
  gap: var(--spacing-md);
  align-items: flex-start;
}

.confirm-danger-icon {
  color: var(--color-danger);
  flex-shrink: 0;
  margin-top: 2px;
}

@keyframes modal-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes modal-rise {
  from { opacity: 0; transform: translateY(12px) scale(0.98); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}

/* ---- Shared dialog building blocks --------------------------------------
   Repeatable rows (segment rules, source field mappings) and the panels that
   hold them. Previously each modal rolled its own spacing and controls. */

.modal-panel {
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--spacing-md);
}

.modal-panel + .modal-panel { margin-top: var(--spacing-md); }

.modal-row {
  display: flex;
  /* end, not center: see the field-row note in forms.css. */
  align-items: end;
  gap: var(--spacing-sm);
  margin-bottom: var(--spacing-sm);
}

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

/* Let selects/inputs in a repeatable row shrink instead of overflowing. */

.modal-row > .form-control,
.modal-row > .form-group { flex: 1; min-width: 0; margin-bottom: 0; }

.modal-row-arrow {
  color: var(--color-text-subtle);
  flex-shrink: 0;
}

/* "+ Add rule" style control: clearly secondary to the dialog's Save action. */

.modal-add-row {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 100%;
  min-height: 40px;
  padding: 8px 14px;
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-primary);
  font-size: var(--font-size-sm);
  font-weight: 600;
  cursor: pointer;
}

.modal-add-row:hover {
  border-color: var(--color-primary);
  background: var(--color-primary-soft);
}

/* Result/summary line under a builder ("Matches 3 contacts right now"). */

.modal-result {
  margin-top: var(--spacing-sm);
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-md);
  padding: var(--spacing-md) var(--spacing-lg);
  border-bottom: 1px solid var(--color-border);
  font-family: var(--font-display);
  font-weight: 700;
  /* Was 13px uppercase muted — too small and too low-contrast to act as a
     heading. Card titles are now real headings at readable size. */
  font-size: var(--font-size-md);
  color: var(--color-text);
}

.card-header-hint {
  font-family: var(--font-sans);
  font-weight: 400;
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
}

.card-body { padding: var(--spacing-lg); }

.card-footer {
  padding: var(--spacing-md) var(--spacing-lg);
  border-top: 1px solid var(--color-border);
  background: var(--color-surface-sunken);
}

/* Card that is itself a link/button target. */

.card-interactive {
  display: block;
  width: 100%;
  text-align: left;
  transition: border-color var(--duration-fast) var(--ease-standard),
    box-shadow var(--duration-fast) var(--ease-standard);
}

.card-interactive:hover {
  border-color: var(--color-primary-soft-border);
  box-shadow: var(--shadow-md);
  text-decoration: none;
}

/* Sectioned page: a titled band with its own description. */

.section {
  margin-bottom: var(--spacing-xl);
}

.section-head {
  margin-bottom: var(--spacing-md);
}

.section-head .page-subtitle { margin-top: 2px; }

/* Status pills. Every variant pairs a colour with a distinct label (and, where
   it carries real meaning, an icon) — colour alone must never be the signal. */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 10px;
  border-radius: var(--radius-full);
  font-size: var(--font-size-xs);
  font-weight: 600;
  line-height: 1.4;
  white-space: nowrap;
  border: 1px solid transparent;
}

.badge-success {
  background: var(--color-success-soft);
  color: var(--color-success-text);
  border-color: #a7f3d0;
}

.badge-warning {
  background: var(--color-warning-soft);
  color: var(--color-warning-text);
  border-color: #fcd34d;
}

.badge-danger {
  background: var(--color-danger-soft);
  color: var(--color-danger-text);
  border-color: #fecaca;
}

.badge-info {
  background: var(--color-info-soft);
  color: var(--color-info-text);
  border-color: var(--color-primary-soft-border);
}

/* Neutral chip for an inactive/unknown state (not an error). Named -muted
   because that is what the ~10 existing usages already call it; it previously
   lived in contacts.css, far from the other badge variants. */

.badge-muted {
  background: var(--gray-100);
  color: var(--color-text-muted);
  border-color: var(--color-border);
}

/* Live WhatsApp state (connected, 24h window open). */

.badge-whatsapp {
  background: var(--color-whatsapp-soft);
  color: var(--color-whatsapp-text);
  border-color: #a7f3d0;
}

.badge-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}

/* ---- Loading ------------------------------------------------------------ */

.loader {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  color: var(--color-text-muted);
  padding: var(--spacing-lg);
  font-size: var(--font-size-sm);
}

.page-loader {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-md);
  min-height: 100vh;
  min-height: 100dvh;
  color: var(--color-text-muted);
}

.spinner {
  width: 22px;
  height: 22px;
  border: 3px solid var(--color-border);
  border-top-color: var(--color-primary);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}

/* Skeleton placeholders reserve the space real content will occupy, so the
   page does not jump when data lands. */

.skeleton {
  background: linear-gradient(90deg, var(--gray-200) 25%, var(--gray-100) 37%, var(--gray-200) 63%);
  background-size: 400% 100%;
  border-radius: var(--radius-sm);
  animation: skeleton-sheen 1.4s ease infinite;
}

.skeleton-line { height: 14px; margin-bottom: 10px; }

.skeleton-line:last-child { width: 60%; margin-bottom: 0; }

.skeleton-card { height: 108px; }

@keyframes skeleton-sheen {
  0% { background-position: 100% 50%; }
  100% { background-position: 0 50%; }
}

/* ---- Errors -------------------------------------------------------------- */

.error-message {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-sm);
  background: var(--color-danger-soft);
  color: var(--color-danger-text);
  border: 1px solid #fecaca;
  padding: 12px 14px;
  border-radius: var(--radius-sm);
  margin-bottom: var(--spacing-md);
  font-size: var(--font-size-sm);
}

.error-message-icon { flex-shrink: 0; margin-top: 1px; }

.error-message-text { flex: 1; overflow-wrap: anywhere; }

/* ---- Empty states -------------------------------------------------------- */

/* An empty state is a teaching moment, not a dead end: say what this screen is
   for and give the one action that fills it. */

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: var(--spacing-2xl) var(--spacing-lg);
  color: var(--color-text-muted);
}

.empty-state-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  border-radius: var(--radius-full);
  background: var(--color-primary-soft);
  color: var(--color-primary);
  margin-bottom: var(--spacing-md);
}

.empty-state-title {
  font-family: var(--font-display);
  font-size: var(--font-size-lg);
  font-weight: 700;
  color: var(--color-text);
}

.empty-state-description {
  margin-top: 6px;
  max-width: 46ch;
  font-size: var(--font-size-sm);
  line-height: var(--line-height-base);
}

.empty-state-action {
  margin-top: var(--spacing-lg);
  display: flex;
  gap: var(--spacing-sm);
  flex-wrap: wrap;
  justify-content: center;
}

/* Home: setup checklist + stat grid. */

/* ---- Setup checklist ---------------------------------------------------- */

.setup-card {
  margin-bottom: var(--spacing-xl);
  border-color: var(--color-primary-soft-border);
  padding: var(--spacing-lg);
}

.setup-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--spacing-md);
  flex-wrap: wrap;
}

.setup-title {
  font-family: var(--font-display);
  font-size: var(--font-size-lg);
  font-weight: 700;
}

.setup-sub {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  margin-top: 2px;
}

.setup-count {
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--color-primary-active);
  background: var(--color-primary-soft);
  border-radius: var(--radius-full);
  padding: 6px 12px;
  white-space: nowrap;
}

.setup-progress {
  height: 8px;
  border-radius: var(--radius-full);
  background: var(--gray-200);
  overflow: hidden;
  margin: var(--spacing-md) 0 var(--spacing-lg);
}

.setup-progress-fill {
  display: block;
  height: 100%;
  border-radius: var(--radius-full);
  background: var(--color-primary);
  transition: width var(--duration-slow) var(--ease-out);
}

.setup-steps {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-xs);
}

.setup-step {
  display: flex;
  align-items: center;
  gap: var(--spacing-md);
  padding: 14px;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
}

/* Exactly one step is highlighted at a time: the next thing to do. */

.setup-step.is-next {
  background: var(--color-primary-soft);
  border-color: var(--color-primary-soft-border);
}

.setup-step-marker {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  flex-shrink: 0;
  border-radius: var(--radius-full);
  border: 2px solid var(--color-border-strong);
  color: var(--color-text-muted);
  font-size: var(--font-size-xs);
  font-weight: 700;
}

.setup-step.is-next .setup-step-marker {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

.setup-step.is-done .setup-step-marker {
  background: var(--color-success);
  border-color: var(--color-success);
  color: #fff;
}

.setup-step-body { flex: 1; min-width: 0; }

.setup-step-title {
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--color-text);
}

.setup-step.is-done .setup-step-title {
  color: var(--color-text-muted);
}

.setup-step-desc {
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
  margin-top: 3px;
  line-height: 1.5;
  max-width: 62ch;
}

.setup-step-cta,
.setup-step-badge { flex-shrink: 0; }

.setup-step-cta:hover { text-decoration: none; }

/* ---- Stat cards --------------------------------------------------------- */

/* 200px min lets all five cards sit on one row at desktop width and fall to
   2-up on a phone, instead of stranding a lone card on its own line. */

.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--spacing-md);
}

.stat-card {
  padding: var(--spacing-md);
  display: flex;
  flex-direction: column;
  gap: 2px;
  border-left: 3px solid var(--color-border-strong);
}

.stat-card-top {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  margin-bottom: var(--spacing-xs);
}

.stat-card-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: var(--radius-sm);
  background: var(--gray-100);
  color: var(--color-text-muted);
  flex-shrink: 0;
}

.stat-card-label {
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--color-text);
}

/* Tone tints the accent bar and icon only — the number itself stays high
   contrast, and every card still carries its own text label. */

.stat-card-info { border-left-color: var(--color-primary); }

.stat-card-info .stat-card-icon { background: var(--color-primary-soft); color: var(--color-primary); }

.stat-card-warning { border-left-color: var(--color-warning); }

.stat-card-warning .stat-card-icon { background: var(--color-warning-soft); color: var(--color-warning); }

.stat-card-danger { border-left-color: var(--color-danger); }

.stat-card-danger .stat-card-icon { background: var(--color-danger-soft); color: var(--color-danger); }

.stat-card-success { border-left-color: var(--color-success); }

.stat-card-success .stat-card-icon { background: var(--color-success-soft); color: var(--color-success); }

@media (max-width: 640px) {
  .setup-step {
    flex-wrap: wrap;
    row-gap: var(--spacing-sm);
  }

  .setup-step-cta { width: 100%; }
}

/* Phase 4 (Team) UI: presence, notifications nudge, conversation filters,
   assignment, and canned messages. Uses the shared CSS variables. */

/* .text-muted is a shared utility — see typography.css. */

/* --- Presence toggle (header) --- */

.presence {
  position: relative;
}

.presence-trigger {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: var(--tap-target);
  padding: 8px 12px;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-full);
  background: var(--color-surface);
  cursor: pointer;
  font-size: var(--font-size-sm);
  font-weight: 500;
  color: var(--color-text);
}

.presence-trigger:hover {
  background: var(--color-surface-hover);
}

.presence-caret {
  color: var(--color-text-subtle);
}

.presence-dot {
  width: 9px;
  height: 9px;
  border-radius: var(--radius-full);
  background: var(--color-text-muted);
  flex: 0 0 auto;
}

.presence-dot-online {
  background: var(--color-success);
}

.presence-dot-away {
  background: var(--color-warning);
}

.presence-dot-offline {
  background: var(--color-text-muted);
}

.presence-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  min-width: 180px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  padding: 4px;
  z-index: 30;
}

.presence-menu-item {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  width: 100%;
  min-height: var(--tap-target);
  padding: 10px 12px;
  border: none;
  background: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: var(--font-size-sm);
  color: var(--color-text);
  text-align: left;
}

.presence-menu-item:hover {
  background: var(--color-surface-hover);
}

.presence-menu-item.is-current {
  font-weight: 600;
}

/* Notification nudge banner styles live in layout.css. */

/* --- Conversation filters + assignee tag --- */

.conv-filters {
  display: flex;
  gap: var(--spacing-xs);
  padding: 0 var(--spacing-md) var(--spacing-sm);
}

.conv-filter {
  flex: 1;
  padding: 6px 8px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  cursor: pointer;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

.conv-filter.is-active {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: #fff;
}

.conv-assignee {
  display: inline-block;
  margin-top: 2px;
  font-size: 11px;
  color: var(--color-text-muted);
}

.conv-assignee.is-unassigned {
  color: var(--color-warning);
}

/* --- Reassign control (contact panel) --- */

.reassign-current {
  font-size: var(--font-size-sm);
  font-weight: 600;
  margin-bottom: var(--spacing-sm);
}

.reassign-select {
  width: 100%;
}

/* --- Settings toggles --- */

.settings-toggle {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  padding: 6px 0;
  font-size: var(--font-size-sm);
  cursor: pointer;
}

/* --- Composer takeover / claim states --- */

.composer-locked {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-md);
  padding: var(--spacing-md) var(--spacing-lg);
  border-top: 1px solid var(--color-border);
  background: var(--color-bg);
  font-size: var(--font-size-sm);
}

.composer-locked-text {
  font-weight: 600;
  color: var(--color-text);
}

.composer-locked-hint {
  color: var(--color-text-muted);
}

.composer-hint {
  padding: 4px var(--spacing-md);
  font-size: 12px;
  color: var(--color-text-muted);
}

/* --- Canned message picker (composer) --- */

.canned-picker {
  position: relative;
  display: inline-flex;
}

.canned-pop {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 0;
  width: 320px;
  max-width: 80vw;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  padding: var(--spacing-sm);
  z-index: 30;
}

.canned-search {
  margin-bottom: var(--spacing-sm);
}

.canned-pop-list {
  max-height: 260px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.canned-empty {
  padding: var(--spacing-md);
  text-align: center;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

.canned-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 10px;
  border: none;
  background: none;
  border-radius: var(--radius-sm);
  cursor: pointer;
  text-align: left;
}

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

.canned-item-title {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--color-text);
}

.canned-item-shortcut {
  font-weight: 400;
  font-size: 11px;
  color: var(--color-text-muted);
  background: var(--color-bg);
  padding: 1px 6px;
  border-radius: var(--radius-sm);
}

.canned-item-body {
  font-size: 12px;
  color: var(--color-text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Phase 5: labels, priority and the CRM overview dashboard. */

/* --- Labels --- */

.label-chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-xs);
  margin-top: var(--spacing-xs);
}

.label-chip {
  --label-color: var(--color-text-muted);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border-radius: var(--radius-full);
  font-size: 12px;
  font-weight: 600;
  color: var(--label-color);
  background: color-mix(in srgb, var(--label-color) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--label-color) 35%, transparent);
}

.label-dot {
  --label-color: var(--color-text-muted);
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--label-color);
  flex: 0 0 auto;
}

.label-chip-count {
  margin-left: 4px;
  padding-left: 6px;
  border-left: 1px solid color-mix(in srgb, var(--label-color) 35%, transparent);
  opacity: 0.85;
}

/* Label picker inside the ContactPanel */

.label-picker {
  margin-top: var(--spacing-sm);
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.label-option {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: var(--font-size-sm);
  cursor: pointer;
}

/* Colour swatches in the label form */

.color-swatches {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-sm);
}

.color-swatch {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 2px solid transparent;
  cursor: pointer;
  padding: 0;
}

.color-swatch.is-selected {
  border-color: var(--color-text);
  box-shadow: 0 0 0 2px var(--color-surface), 0 0 0 4px var(--color-text);
}

/* --- Priority --- */

.priority-chip {
  display: inline-block;
  padding: 3px 10px;
  border-radius: var(--radius-full);
  font-size: 12px;
  font-weight: 600;
  border: 1px solid transparent;
}

.priority-chip-sm {
  padding: 1px 7px;
  font-size: 11px;
}

.priority-low { background: #f3f4f6; color: #4b5563; border-color: #e5e7eb; }

.priority-normal { background: #dbeafe; color: #1e40af; border-color: #bfdbfe; }

.priority-high { background: #fef3c7; color: #92400e; border-color: #fde68a; }

.priority-urgent { background: #fee2e2; color: #991b1b; border-color: #fecaca; }

.priority-select { max-width: 100%; }

/* --- Conversation-list tag filter row --- */

.conv-tag-filters {
  display: flex;
  gap: var(--spacing-sm);
  padding: 0 var(--spacing-md) var(--spacing-sm);
}

.conv-tag-filter {
  flex: 1 1 0;
  min-width: 0;
  font-size: var(--font-size-sm);
  padding: 5px 8px;
}

/* --- Conversation-list row tags --- */

.conv-tags {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 5px;
  margin-top: 4px;
}

.conv-label-dot {
  --label-color: var(--color-text-muted);
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--label-color);
}

/* --- CRM overview dashboard (stat cards live in dashboard.css) --- */

.crm-columns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--spacing-lg);
  margin-bottom: var(--spacing-lg);
}

.crm-bar-row {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  margin-bottom: var(--spacing-sm);
}

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

.crm-agent-name {
  flex: 0 0 120px;
  font-size: var(--font-size-sm);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.crm-bar-track {
  flex: 1 1 auto;
  height: 10px;
  background: var(--color-bg);
  border-radius: var(--radius-full);
  overflow: hidden;
}

.crm-bar-fill {
  display: block;
  height: 100%;
  border-radius: var(--radius-full);
  background: var(--color-primary);
  min-width: 2px;
  transition: width 0.2s ease;
}

.crm-bar-fill-agent { background: var(--color-primary); }

.crm-bar-fill.priority-low { background: #9ca3af; }

.crm-bar-fill.priority-normal { background: #3b82f6; }

.crm-bar-fill.priority-high { background: #f59e0b; }

.crm-bar-fill.priority-urgent { background: #ef4444; }

.crm-bar-count {
  flex: 0 0 auto;
  min-width: 24px;
  text-align: right;
  font-weight: 600;
  font-size: var(--font-size-sm);
}

@media (max-width: 768px) {
  .crm-columns { grid-template-columns: 1fr; }
}

/* Contacts (Phase 6) — list toolbar, marketing consent switch, eligibility. */

.contacts-toolbar {
  display: flex;
  gap: var(--spacing-sm);
  margin-bottom: var(--spacing-md);
  flex-wrap: wrap;
}

.contacts-toolbar .form-control {
  margin: 0;
}

.contacts-toolbar input[type='search'] {
  flex: 1 1 260px;
}

.contacts-toolbar select {
  flex: 0 0 auto;
  min-width: 180px;
}

.contacts-loadmore {
  display: flex;
  justify-content: center;
  margin-top: var(--spacing-md);
}

/* Name + phone stacked in a table cell. */

.contact-cell {
  display: flex;
  flex-direction: column;
  line-height: 1.3;
}

.contact-cell-name {
  font-weight: 600;
  color: var(--color-text);
}

.contact-cell-phone {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* .badge-muted is a shared badge variant — see badges.css. */

/* List + segment chips in the contacts table (wraps for multiple memberships). */

.contact-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  max-width: 260px;
}

/* --- Marketing opt-in switch --- */

.optin {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-sm);
}

.optin-compact {
  gap: 0;
}

.switch {
  position: relative;
  flex: 0 0 auto;
  width: 40px;
  height: 22px;
  border-radius: var(--radius-full);
  border: none;
  background: var(--color-border);
  cursor: pointer;
  transition: background 0.15s ease;
  padding: 0;
}

.switch-on {
  background: var(--color-success);
}

.switch:disabled {
  cursor: not-allowed;
  opacity: 0.6;
}

.switch-knob {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 18px;
  height: 18px;
  border-radius: var(--radius-full);
  background: #fff;
  box-shadow: var(--shadow-sm);
  transition: transform 0.15s ease;
}

.switch-on .switch-knob {
  transform: translateX(18px);
}

.optin-label {
  display: flex;
  flex-direction: column;
  font-size: var(--font-size-sm);
  color: var(--color-text);
}

.optin-note {
  color: var(--color-text-muted);
}

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

/* Eligibility chip sits to the right of the marketing section title (modifier
   only — the base .contact-section-title styling lives in inbox.css). */

.contact-section-title-inline {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-sm);
}

/* Row actions stay on one line, right-aligned. */

.table-actions {
  display: flex;
  gap: 4px;
  justify-content: flex-end;
}

/* --- Add / edit contact --- */

.contact-list-picker {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-sm);
}

.contact-list-option {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px var(--spacing-sm);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  font-size: var(--font-size-sm);
  cursor: pointer;
}

.contact-list-option input {
  margin: 0;
}

/* --- CSV import wizard --- */

.import-hint {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  margin-bottom: var(--spacing-md);
}

.import-upload .form-control {
  margin-bottom: var(--spacing-sm);
}

/* The sample file sits below the picker, not above it: someone with a file
   ready should not have to read past an offer they do not need. */

.import-sample-file {
  margin-top: var(--spacing-md);
  padding-top: var(--spacing-md);
  border-top: 1px solid var(--color-border);
}

/* The sample link is a <a> wearing .btn — the global anchor hover underline
   would otherwise strike through a button face. */

.import-sample-file .btn:hover {
  text-decoration: none;
}

.import-sample-file .import-hint {
  margin-top: var(--spacing-sm);
  margin-bottom: 0;
}

.import-sample-file code {
  font-family: var(--font-mono, monospace);
  padding: 0 4px;
  border-radius: var(--radius-sm);
  background: var(--color-surface-alt, var(--color-border));
}

.import-map-table td {
  vertical-align: middle;
}

.import-map-table .form-control {
  margin: 0;
  min-width: 200px;
}

/* Sample values are data, not prose — monospace stops a stray number from
   being misread as a formatted phone. */

.import-sample {
  font-family: var(--font-mono, monospace);
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  word-break: break-all;
}

.import-warning {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--font-size-sm);
  color: var(--color-warning, var(--color-danger));
  margin-bottom: var(--spacing-md);
}

/* The declaration is the one thing on this step that must not be skimmed past,
   so it gets a boxed, full-width treatment rather than a bare checkbox. */

.import-declaration {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-sm);
  padding: var(--spacing-md);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface-alt, var(--color-surface));
  font-size: var(--font-size-sm);
  line-height: 1.5;
  cursor: pointer;
}

.import-declaration input {
  margin-top: 2px;
  flex: 0 0 auto;
}

.import-running {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-md);
  padding: var(--spacing-lg) 0;
}

.import-stats {
  display: flex;
  gap: var(--spacing-lg);
  margin-bottom: var(--spacing-md);
}

.import-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 84px;
  padding: var(--spacing-md);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}

.import-stat-value {
  font-size: var(--font-size-xl, 1.5rem);
  font-weight: 700;
  color: var(--color-text);
}

.import-stat-label {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

.import-stat-bad .import-stat-value {
  color: var(--color-danger);
}

/* A locked opt-out: the contact turned marketing off themselves, so the switch
   is not merely disabled but permanently unavailable to the tenant. Uses
   not-allowed rather than the usual dimmed-disabled look so it reads as "this
   is not yours to change" instead of "try again later". */

.switch-locked {
  cursor: not-allowed;
  opacity: 1;
  background: var(--color-border);
  box-shadow: inset 0 0 0 2px var(--color-danger-soft, var(--color-border));
}

.switch-locked:disabled {
  opacity: 1;
}

/* --- Contact attribute registry (Settings) ---------------------------------
   The tenant's own contact fields. Keys are rendered as code so a tenant can
   see at a glance that the key is a machine identifier they'll paste into a
   template, distinct from the human label above it. */

.attr-key {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: var(--font-size-sm);
  padding: 2px 6px;
  border-radius: var(--radius-sm);
  background: var(--color-surface-muted, var(--color-border));
  color: var(--color-text-muted);
}

.settings-intro {
  margin-bottom: var(--spacing-md);
}

.form-static {
  margin: 0;
}

/* An inline switch inside a table cell: same control, no label text beside it
   (the column heading is the label). */

.settings-toggle-inline {
  padding: 0;
  justify-content: center;
}

.attr-undeclared {
  margin-top: var(--spacing-lg);
  padding-top: var(--spacing-md);
  border-top: 1px solid var(--color-border);
}

.attr-undeclared-keys {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-sm);
  margin-top: var(--spacing-sm);
}

/* Attribute values on the Contacts table + contact panel. Narrow and truncated:
   an attribute can hold anything, and one long value must not push the action
   column off the screen. */

.contact-attr-cell {
  max-width: 180px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A declared attribute in the inbox contact panel: label above its box, so the
   agent reads the human name and never has to know the underlying key. */

.cf-field {
  display: block;
  margin-bottom: var(--spacing-sm);
}

.cf-field-label {
  display: block;
  margin-bottom: 4px;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* Attribute inputs on the add/edit contact dialog, two per row on a wide
   dialog so a tenant with several attributes doesn't get an endless column. */

.contact-attr-fields {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 0 var(--spacing-md);
}

/* Templates: the catalogue screen, the composer picker modal, the template
   message tag, and the Phase 7.1 builder (steps, editors, live preview). */

/* --- Status / category badges (shared by the screen + picker) --- */

.tpl-badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: var(--radius-full);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
  white-space: nowrap;
}

.tpl-status.is-approved { background: #dcfce7; color: #166534; }

.tpl-status.is-pending { background: #fef3c7; color: #92400e; }

.tpl-status.is-rejected { background: #fee2e2; color: #991b1b; }

.tpl-status.is-paused { background: #e5e7eb; color: #374151; }

.tpl-cat.is-marketing { background: #ede9fe; color: #5b21b6; }

.tpl-cat.is-utility { background: #e0f2fe; color: #075985; }

.tpl-cat.is-auth { background: #f1f5f9; color: #334155; }

.tpl-name {
  font-weight: 600;
  color: var(--color-text);
}

.tpl-preview-text {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  margin-top: 2px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.tpl-named-tag {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  border-radius: var(--radius-full);
  font-size: 11px;
  font-weight: 600;
  background: #f1f5f9;
  color: #475569;
}

.tpl-load-more {
  display: flex;
  justify-content: center;
  margin-top: var(--spacing-md);
}

/* --- Composer picker modal --- */

.tpl-picker-list {
  margin-top: var(--spacing-sm);
  max-height: 340px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-xs);
}

.tpl-picker-empty {
  padding: var(--spacing-md);
  text-align: center;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

.tpl-picker-item {
  display: flex;
  flex-direction: column;
  gap: 4px;
  width: 100%;
  text-align: left;
  padding: var(--spacing-sm) var(--spacing-md);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  cursor: pointer;
}

.tpl-picker-item:hover:not(:disabled) { border-color: var(--color-primary); }

.tpl-picker-item:disabled { opacity: 0.6; cursor: not-allowed; }

.tpl-picker-item-head {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
}

.tpl-picker-lang {
  margin-left: auto;
  font-size: 12px;
  color: var(--color-text-muted);
}

.tpl-picker-block {
  font-size: 12px;
  color: var(--color-danger);
}

/* --- Fill-variables step --- */

.tpl-fill { display: flex; flex-direction: column; gap: var(--spacing-md); }

.tpl-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-bottom: var(--spacing-md);
}

/* Matches .form-label exactly — these are field labels like any other, and
   having them muted+lighter made the broadcast/template dialogs look like a
   different product to the source/form dialogs. */

.tpl-field-label {
  display: block;
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--color-text);
  margin-bottom: 6px;
}

.tpl-preview-box {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: #f0f7f4;
  padding: var(--spacing-md);
}

.tpl-preview-title {
  font-size: 12px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
  margin-bottom: var(--spacing-sm);
}

.tpl-preview-header { font-weight: 600; margin: 0 0 var(--spacing-xs); white-space: pre-wrap; }

.tpl-preview-body { margin: 0; white-space: pre-wrap; }

.tpl-preview-footer {
  margin: var(--spacing-xs) 0 0;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  white-space: pre-wrap;
}

/* --- Closed-window composer: template CTA sits under the notice --- */

.composer-closed {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--spacing-sm);
}

/* --- Template message tag on the bubble --- */

.msg-template-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  font-weight: 600;
  color: var(--color-info-text);
  background: var(--color-primary-soft);
  border-radius: var(--radius-full);
  padding: 1px 8px;
  margin-bottom: 4px;
}

/* ==========================================================================
   Phase 7.1 — the template builder
   ========================================================================== */

.page-header-actions {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  flex-wrap: wrap;
}

/* --- List additions: row actions, rejection reason, post-submit note --- */

.tpl-row-actions {
  white-space: nowrap;
  text-align: right;
}

.tpl-row-actions .btn { margin-left: var(--spacing-2xs); }

/* The reason WhatsApp gave, on the row itself — a red chip alone tells the
   tenant nothing they can act on. */

.tpl-reject-reason {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin-top: 6px;
  padding: 6px var(--spacing-sm);
  border-radius: var(--radius-sm);
  background: var(--color-danger-soft);
  color: var(--color-danger-text);
  font-size: var(--font-size-xs);
  line-height: 1.5;
  max-width: 46ch;
}

.tpl-reject-reason svg { flex-shrink: 0; margin-top: 1px; }

.tpl-flash {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  padding: var(--spacing-sm) var(--spacing-md);
  margin-bottom: var(--spacing-md);
  border: 1px solid var(--color-success-soft);
  border-radius: var(--radius-md);
  background: var(--color-success-soft);
  color: var(--color-success-text);
}

.tpl-flash p { margin: 0; flex: 1; }

.tpl-flash-close {
  border: 0;
  background: none;
  color: inherit;
  cursor: pointer;
  padding: 4px;
  border-radius: var(--radius-xs);
  display: inline-flex;
}

.tpl-flash-close:hover { background: rgba(0, 0, 0, 0.06); }

/* --- Step rail --- */

.tpl-steps {
  display: flex;
  gap: var(--spacing-xs);
  list-style: none;
  margin: 0 0 var(--spacing-md);
  padding: 0;
  flex-wrap: wrap;
}

.tpl-steps-item button {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-sm);
  padding: var(--spacing-sm) var(--spacing-md);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  background: var(--color-surface);
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  font-weight: 600;
  cursor: pointer;
}

.tpl-steps-item button:disabled { cursor: default; }

.tpl-steps-item.is-current button {
  border-color: var(--color-primary);
  color: var(--color-primary);
  background: var(--color-primary-soft);
}

.tpl-steps-item.is-done button { color: var(--color-success-text); cursor: pointer; }

.tpl-steps-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: var(--radius-full);
  background: var(--color-surface-hover);
  font-size: var(--font-size-xs);
}

.tpl-steps-item.is-current .tpl-steps-num { background: var(--color-primary); color: var(--color-on-primary); }

.tpl-steps-item.is-done .tpl-steps-num { background: var(--color-success-soft); color: var(--color-success-text); }

/* --- Two-column layout: form left, live preview pinned right --- */

.tpl-builder-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 340px;
  gap: var(--spacing-lg);
  align-items: start;
}

.tpl-builder-form { padding: var(--spacing-lg); }

.tpl-builder-preview { position: sticky; top: var(--spacing-md); }

.tpl-builder-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--spacing-sm);
  margin-top: var(--spacing-lg);
  padding-top: var(--spacing-md);
  border-top: 1px solid var(--color-border);
}

.tpl-step { display: flex; flex-direction: column; gap: var(--spacing-xl); }

.tpl-section { display: flex; flex-direction: column; gap: var(--spacing-sm); }

.tpl-section-head { margin-bottom: var(--spacing-2xs); }

.tpl-section-title {
  font-size: var(--font-size-md);
  font-weight: 600;
  color: var(--color-text);
  margin: 0;
}

.tpl-section-hint {
  margin: 4px 0 0;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  line-height: 1.5;
}

.tpl-optional {
  font-size: var(--font-size-xs);
  font-weight: 500;
  color: var(--color-text-subtle);
  margin-left: 6px;
}

.tpl-note {
  margin: 0;
  padding: var(--spacing-sm) var(--spacing-md);
  border-radius: var(--radius-sm);
  background: var(--color-surface-sunken);
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  line-height: 1.5;
}

.tpl-counter {
  align-self: flex-end;
  font-size: var(--font-size-xs);
  color: var(--color-text-subtle);
}

.tpl-field-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--spacing-md);
}

.tpl-field-hint {
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
  line-height: 1.5;
}

.tpl-inline-field { display: flex; align-items: center; gap: var(--spacing-sm); }

.tpl-inline-field .form-control { max-width: 110px; }

/* --- Purpose cards: the decision that drives everything downstream --- */

.tpl-category-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--spacing-sm);
}

.tpl-category,
.tpl-choice {
  display: flex;
  flex-direction: column;
  gap: 4px;
  text-align: left;
  padding: var(--spacing-md);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  cursor: pointer;
}

.tpl-category:hover:not(:disabled),
.tpl-choice:hover:not(:disabled) { border-color: var(--color-border-strong); }

.tpl-category.is-selected,
.tpl-choice.is-selected {
  border-color: var(--color-primary);
  background: var(--color-primary-soft);
  box-shadow: inset 0 0 0 1px var(--color-primary);
}

.tpl-category:disabled,
.tpl-choice:disabled { opacity: 0.6; cursor: not-allowed; }

/* WhatsApp's own word for the category leads; our plain-English gloss sits
   under it in the muted label role. */

.tpl-category-name,
.tpl-choice-label { font-weight: 600; color: var(--color-text); }

.tpl-category-name { font-size: var(--font-size-md); }

.tpl-category-label {
  font-weight: 600;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  margin-bottom: 2px;
}

.tpl-category-hint,
.tpl-choice-hint {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  line-height: 1.5;
}

.tpl-category-detail {
  font-size: var(--font-size-xs);
  color: var(--color-text-subtle);
  line-height: 1.5;
  margin-top: 2px;
}

.tpl-choice-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--spacing-xs);
}

.tpl-choice { padding: var(--spacing-sm) var(--spacing-md); }

/* --- Body editor --- */

.tpl-toolbar {
  display: flex;
  align-items: center;
  gap: var(--spacing-2xs);
  flex-wrap: wrap;
}

.tpl-tool {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-width: 32px;
  height: 32px;
  padding: 0 var(--spacing-sm);
  justify-content: center;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-text);
  cursor: pointer;
  font-size: var(--font-size-sm);
}

.tpl-tool:hover { background: var(--color-surface-hover); }

.tpl-tool-bold { font-weight: 700; }

.tpl-tool-italic { font-style: italic; }

.tpl-tool-strike { text-decoration: line-through; }

.tpl-tool-var { margin-left: auto; font-weight: 600; color: var(--color-primary); }

.tpl-textarea {
  min-height: 160px;
  resize: vertical;
  line-height: 1.6;
  font-family: inherit;
}

.tpl-footer-group { margin-top: var(--spacing-md); }

.tpl-format-toggle {
  display: flex;
  align-items: center;
  gap: var(--spacing-md);
  flex-wrap: wrap;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

.tpl-radio { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }

/* --- Example values: the field that decides whether a template gets approved --- */

.tpl-samples {
  margin-top: var(--spacing-sm);
  padding: var(--spacing-md);
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-md);
  background: var(--color-surface-sunken);
}

.tpl-samples-title {
  margin: 0 0 var(--spacing-sm);
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--color-text);
}

.tpl-samples-hint {
  display: block;
  font-weight: 400;
  color: var(--color-text-muted);
  margin-top: 2px;
}

.tpl-samples-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--spacing-sm);
}

.tpl-sample { display: flex; flex-direction: column; gap: 4px; }

.tpl-sample-token {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: var(--font-size-xs);
  color: var(--color-primary);
  font-weight: 600;
}

/* --- Media upload --- */

.tpl-upload {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--spacing-sm);
  padding: var(--spacing-md);
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-md);
  background: var(--color-surface-sunken);
}

.tpl-upload-input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }

.tpl-upload-ok {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--font-size-sm);
  color: var(--color-success-text);
  font-weight: 600;
}

.tpl-upload-hint { font-size: var(--font-size-sm); color: var(--color-text-muted); }

.tpl-upload-error { margin: 0; font-size: var(--font-size-sm); color: var(--color-danger-text); }

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

.tpl-button-row {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--spacing-md);
  background: var(--color-surface);
}

.tpl-button-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-sm);
  margin-bottom: var(--spacing-sm);
}

.tpl-button-type { font-weight: 600; font-size: var(--font-size-sm); }

.tpl-button-actions { display: flex; gap: var(--spacing-2xs); }

.tpl-button-fields {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--spacing-md);
}

.tpl-button-fields .tpl-field { margin-bottom: 0; }

.tpl-add-menu {
  display: grid;
  gap: var(--spacing-xs);
  padding: var(--spacing-sm);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface-sunken);
}

.tpl-add-option {
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-align: left;
  padding: var(--spacing-sm) var(--spacing-md);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  cursor: pointer;
}

.tpl-add-option:hover:not(:disabled) { border-color: var(--color-primary); }

.tpl-add-option:disabled { opacity: 0.55; cursor: not-allowed; }

.tpl-add-option-label { font-weight: 600; }

.tpl-add-option-hint { font-size: var(--font-size-xs); color: var(--color-text-muted); }

.tpl-add-cancel {
  border: 0;
  background: none;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  cursor: pointer;
  padding: var(--spacing-xs);
  justify-self: start;
}

/* --- Authentication options --- */

.tpl-switch {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-sm);
  cursor: pointer;
}

.tpl-switch input { margin-top: 3px; }

.tpl-switch-label { display: block; font-weight: 600; }

.tpl-switch-hint {
  display: block;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

.tpl-auth-app {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
  padding: var(--spacing-md);
  border-radius: var(--radius-md);
  background: var(--color-surface-sunken);
}

/* --- Findings: errors block, warnings only advise --- */

.tpl-findings {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--spacing-md);
  background: var(--color-surface);
}

.tpl-findings-title {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0 0 var(--spacing-sm);
  font-weight: 600;
}

.tpl-findings-list { margin: 0; padding-left: var(--spacing-lg); display: grid; gap: 6px; }

.tpl-findings-list li { line-height: 1.55; }

.tpl-findings-list li.is-error { color: var(--color-danger-text); }

.tpl-findings-list li.is-warning { color: var(--color-warning-text); }

.tpl-finding {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-sm);
  padding: var(--spacing-md);
  border-radius: var(--radius-md);
}

.tpl-finding.is-ok { background: var(--color-success-soft); color: var(--color-success-text); }

.tpl-finding-title { margin: 0; font-weight: 600; }

.tpl-finding-body { margin: 2px 0 0; font-size: var(--font-size-sm); }

.tpl-step-errors {
  margin: var(--spacing-md) 0 0;
  padding: var(--spacing-sm) var(--spacing-md) var(--spacing-sm) var(--spacing-xl);
  border-radius: var(--radius-md);
  background: var(--color-danger-soft);
  color: var(--color-danger-text);
  display: grid;
  gap: 4px;
}

.tpl-locked {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  padding: var(--spacing-md);
  margin-bottom: var(--spacing-md);
  border-radius: var(--radius-md);
  background: var(--color-warning-soft);
  color: var(--color-warning-text);
}

.tpl-locked p { margin: 0; }

.tpl-summary { margin: 0; display: grid; gap: 6px; }

.tpl-summary-row {
  display: flex;
  justify-content: space-between;
  gap: var(--spacing-md);
  padding: 6px 0;
  border-bottom: 1px solid var(--color-border);
}

.tpl-summary-row dt { color: var(--color-text-muted); }

.tpl-summary-row dd { margin: 0; font-weight: 600; text-align: right; }

/* --- The live WhatsApp bubble --- */

.tpl-preview-canvas {
  padding: var(--spacing-md);
  border-radius: var(--radius-md);
  /* WhatsApp's own chat ground, so the bubble reads the way it will on a
     phone rather than floating on our app surface. */
  background: #e5ded8;
  min-height: 180px;
  display: flex;
  align-items: flex-start;
}

.tpl-preview-empty {
  margin: auto;
  color: #6b6259;
  font-size: var(--font-size-sm);
  text-align: center;
}

.tpl-preview-bubble {
  position: relative;
  width: 100%;
  background: var(--color-surface);
  border-radius: 8px;
  padding: 7px 9px 6px;
  box-shadow: 0 1px 1px rgba(11, 20, 26, 0.13);
  font-size: var(--font-size-sm);
  line-height: 1.45;
  word-break: break-word;
}

.tpl-preview-bubble .tpl-preview-header { font-weight: 700; margin-bottom: 4px; }

.tpl-preview-bubble .tpl-preview-body { white-space: pre-wrap; }

.tpl-preview-bubble .tpl-preview-body code {
  font-family: var(--font-mono, ui-monospace, monospace);
  background: var(--color-surface-sunken);
  padding: 0 3px;
  border-radius: var(--radius-xs);
}

.tpl-preview-bubble .tpl-preview-footer {
  margin-top: 5px;
  font-size: var(--font-size-xs);
  color: var(--color-text-subtle);
}

.tpl-preview-time {
  text-align: right;
  font-size: 11px;
  color: var(--color-text-subtle);
  margin-top: 2px;
}

.tpl-preview-image {
  display: block;
  width: 100%;
  max-height: 180px;
  object-fit: cover;
  border-radius: 6px;
  margin-bottom: 6px;
}

.tpl-preview-placeholder,
.tpl-preview-doc {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 96px;
  margin-bottom: 6px;
  border-radius: 6px;
  background: var(--color-surface-sunken);
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

.tpl-preview-doc { height: 52px; justify-content: flex-start; padding: 0 var(--spacing-sm); }

/* WhatsApp separates buttons with hairlines and centres them in brand blue. */

.tpl-preview-buttons { margin: 6px -9px -6px; }

.tpl-preview-button {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 9px;
  border-top: 1px solid var(--color-border);
  color: #00a5f4;
  font-size: var(--font-size-sm);
  font-weight: 500;
}

.tpl-preview-note {
  margin: var(--spacing-sm) 0 0;
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
  line-height: 1.5;
}

@media (max-width: 900px) {
  .tpl-builder-grid { grid-template-columns: minmax(0, 1fr); }
  /* Below the form the preview no longer needs to follow the scroll. */
  .tpl-builder-preview { position: static; order: -1; }
  .tpl-builder-form { padding: var(--spacing-md); }
}

/* The header notification bell (Phase 7.2): trigger, unread badge and the
   dropdown panel. */

.notif {
  position: relative;
  display: flex;
  align-items: center;
}

.notif-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 40px keeps it on the 44px-ish touch target the header uses elsewhere. */
  width: 40px;
  height: 40px;
  border: 1px solid transparent;
  border-radius: var(--radius-full);
  background: none;
  color: var(--color-text-muted);
  cursor: pointer;
}

.notif-btn:hover { background: var(--color-surface-hover); color: var(--color-text); }

.notif-btn:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }

.notif-badge {
  position: absolute;
  top: 2px;
  right: 2px;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: var(--radius-full);
  background: var(--color-danger);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  line-height: 18px;
  text-align: center;
  /* Lifts the badge off the bell so the count stays readable on hover. */
  box-shadow: 0 0 0 2px var(--color-surface);
}

.notif-panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  width: min(380px, calc(100vw - 32px));
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg, 0 10px 30px rgba(15, 23, 42, 0.16));
  z-index: 60;
  overflow: hidden;
}

.notif-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-sm);
  padding: var(--spacing-sm) var(--spacing-md);
  border-bottom: 1px solid var(--color-border);
}

.notif-panel-title { font-weight: 600; }

.notif-mark-all {
  border: 0;
  background: none;
  color: var(--color-primary);
  font-size: var(--font-size-sm);
  font-weight: 600;
  cursor: pointer;
  padding: 4px;
  border-radius: var(--radius-xs);
}

.notif-mark-all:hover { background: var(--color-primary-soft); }

.notif-list {
  max-height: min(60vh, 460px);
  overflow-y: auto;
}

.notif-empty {
  margin: 0;
  padding: var(--spacing-lg) var(--spacing-md);
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  text-align: center;
  line-height: 1.55;
}

.notif-item {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-sm);
  width: 100%;
  padding: var(--spacing-sm) var(--spacing-md);
  border: 0;
  border-bottom: 1px solid var(--color-border);
  background: none;
  text-align: left;
  cursor: pointer;
}

.notif-item:last-child { border-bottom: 0; }

.notif-item:hover { background: var(--color-surface-hover); }

.notif-item.is-unread { background: var(--color-primary-soft); }

.notif-item.is-unread:hover { background: var(--color-primary-soft-border); }

/* Severity colours the icon only — a wash of red across a whole row makes the
   panel unreadable when several land at once. */

.notif-item-icon {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-full);
  background: var(--color-surface-sunken);
  color: var(--color-text-muted);
}

.notif-item.is-success .notif-item-icon { background: var(--color-success-soft); color: var(--color-success-text); }

.notif-item.is-warning .notif-item-icon { background: var(--color-warning-soft); color: var(--color-warning-text); }

.notif-item.is-danger .notif-item-icon { background: var(--color-danger-soft); color: var(--color-danger-text); }

.notif-item.is-info .notif-item-icon { background: var(--color-info-soft); color: var(--color-info-text); }

.notif-item-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  flex: 1;
}

.notif-item-title {
  font-weight: 600;
  font-size: var(--font-size-sm);
  color: var(--color-text);
}

.notif-item-body {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  line-height: 1.5;
}

.notif-item-time {
  font-size: var(--font-size-xs);
  color: var(--color-text-subtle);
}

.notif-item-dot {
  flex-shrink: 0;
  width: 8px;
  height: 8px;
  margin-top: 6px;
  border-radius: var(--radius-full);
  background: var(--color-primary);
}

@media (max-width: 560px) {
  /* Anchored to the viewport rather than the button, which sits close to the
     right edge on a phone. */
  .notif-panel {
    position: fixed;
    top: 56px;
    right: var(--spacing-sm);
    left: var(--spacing-sm);
    width: auto;
  }
}

/* Broadcasts (Phase 8): list, create wizard, and delivery report. */

.bc-link {
  background: none;
  border: none;
  padding: 0;
  color: var(--color-primary);
  font-weight: 600;
  cursor: pointer;
}

.bc-link:hover { text-decoration: underline; }

.bc-actions {
  display: flex;
  gap: var(--spacing-xs);
  justify-content: flex-end;
}

/* Status badge */

.bc-badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: var(--radius-full);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}

.bc-badge.is-draft { background: #e5e7eb; color: #374151; }

.bc-badge.is-scheduled { background: #dbeafe; color: #1e40af; }

.bc-badge.is-sending { background: #fef3c7; color: #92400e; }

.bc-badge.is-completed { background: #dcfce7; color: #166534; }

.bc-badge.is-cancelled { background: #fee2e2; color: #991b1b; }

/* Auto-paused to protect the number. Deliberately NOT the cancelled red — this
   one resumes by itself once the quality rating recovers, and colouring it like
   a cancellation would read as "your campaign is dead". */

.bc-badge.is-paused { background: #ffedd5; color: #9a3412; }

/* Create wizard */

.bc-form { display: flex; flex-direction: column; gap: var(--spacing-md); }

/* Inline rate control: "[20] messages every [30] seconds". Baseline-aligned so
   the numbers sit on the same line as the words, and wraps as a unit on narrow
   screens rather than letting one field drop out of line. */

.bc-rate {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}

.bc-rate-num {
  width: 84px;
  flex: 0 0 auto;
  text-align: center;
}

.bc-rate-text {
  font-size: var(--font-size-sm);
  color: var(--color-text);
  white-space: nowrap;
}

.bc-hint { font-size: var(--font-size-sm); color: var(--color-text-muted); margin-top: 4px; }

.bc-audience-note {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-sm);
  background: var(--color-primary-soft);
  border: 1px solid var(--color-primary-soft-border);
  border-radius: var(--radius-md);
  padding: var(--spacing-sm) var(--spacing-md);
  font-size: var(--font-size-sm);
  color: var(--color-info-text);
  line-height: var(--line-height-base);
}

/* Detail / report */

.bc-detail { display: flex; flex-direction: column; gap: var(--spacing-md); }

.bc-detail-head { display: flex; align-items: center; gap: var(--spacing-sm); }

.bc-detail-tpl { color: var(--color-text-muted); font-size: var(--font-size-sm); }

.bc-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--spacing-sm); }

.bc-stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: var(--spacing-sm);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}

.bc-stat-n { font-size: var(--font-size-lg); font-weight: 700; }

.bc-stat-n.bc-ok { color: var(--color-success); }

.bc-stat-n.bc-bad { color: var(--color-danger); }

.bc-stat-l { font-size: 11px; color: var(--color-text-muted); text-transform: uppercase; letter-spacing: 0.03em; }

.bc-recip-filter { display: flex; gap: var(--spacing-xs); flex-wrap: wrap; }

.bc-recip-badge {
  display: inline-block;
  padding: 1px 8px;
  border-radius: var(--radius-full);
  font-size: 11px;
  font-weight: 600;
  text-transform: capitalize;
}

.bc-recip-badge.is-sent { background: #dcfce7; color: #166534; }

.bc-recip-badge.is-failed { background: #fee2e2; color: #991b1b; }

.bc-recip-badge.is-skipped { background: #fef3c7; color: #92400e; }

.bc-recip-badge.is-pending { background: #e5e7eb; color: #374151; }

.bc-recip-detail { color: var(--color-text-muted); font-size: var(--font-size-sm); }

.bc-empty { text-align: center; color: var(--color-text-muted); padding: var(--spacing-md); }

/* Lists & Segments (acquisition Phase A) + custom fields + variable chips. */

/* --- Tabs --- */

.lists-tabs {
  display: flex;
  gap: var(--spacing-xs);
  border-bottom: 1px solid var(--color-border);
  margin-bottom: var(--spacing-md);
}

.lists-tab {
  padding: var(--spacing-sm) var(--spacing-md);
  border: none;
  background: none;
  cursor: pointer;
  color: var(--color-text-muted);
  font-size: var(--font-size-md);
  border-bottom: 2px solid transparent;
}

.lists-tab.is-active {
  color: var(--color-primary);
  border-bottom-color: var(--color-primary);
  font-weight: 600;
}

/* --- Editor / members forms --- */

.lists-form {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
}

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

.lists-empty {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  padding: var(--spacing-sm) 0;
}

.lists-members { display: flex; flex-direction: column; gap: var(--spacing-lg); }

.lists-members-add { display: flex; flex-direction: column; gap: var(--spacing-sm); }

.lists-search-results,
.lists-members-list { display: flex; flex-direction: column; gap: var(--spacing-xs); }

.lists-search-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-sm);
  padding: var(--spacing-sm);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
}

.lists-loadmore { padding-top: var(--spacing-sm); }

/* --- Segment builder --- */

.seg-builder {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
  padding: var(--spacing-md);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg);
}

.seg-combinator {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

.seg-inline { width: auto; display: inline-block; }

.seg-rule {
  display: grid;
  grid-template-columns: 1.3fr 1fr 1.3fr auto;
  gap: var(--spacing-sm);
  /* end, not center: see the field-row note in forms.css. */
  align-items: end;
}

.seg-novalue { display: block; }

.seg-remove {
  border: none;
  background: none;
  cursor: pointer;
  font-size: var(--font-size-lg);
  color: var(--color-text-muted);
  line-height: 1;
}

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

.seg-preview {
  margin-top: var(--spacing-sm);
  font-size: var(--font-size-sm);
  color: var(--color-text);
}

/* --- Custom fields editor (contact panel) --- */

.cf-empty { color: var(--color-text-muted); font-size: var(--font-size-sm); }

.cf-edit-link {
  border: none;
  background: none;
  cursor: pointer;
  color: var(--color-primary);
  font-size: var(--font-size-sm);
}

.cf-editor { display: flex; flex-direction: column; gap: var(--spacing-sm); }

.cf-row {
  display: grid;
  grid-template-columns: 1fr 1fr auto;
  gap: var(--spacing-xs);
  align-items: center;
}

.cf-actions { display: flex; gap: var(--spacing-sm); justify-content: flex-end; }

.contact-lists { display: flex; flex-wrap: wrap; gap: var(--spacing-xs); }

/* --- Variable chips (template pickers) --- */

.var-chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--spacing-xs);
  margin-top: var(--spacing-xs);
}

.var-chips-label { font-size: var(--font-size-sm); color: var(--color-text-muted); }

.var-chip {
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  border-radius: var(--radius-full);
  padding: 2px var(--spacing-sm);
  font-size: var(--font-size-sm);
  cursor: pointer;
  color: var(--color-primary);
}

.var-chip:hover { background: var(--color-bg); }

/* --- Broadcast audience block --- */

.bc-audience { display: flex; flex-direction: column; gap: var(--spacing-sm); }

/* Sources (acquisition Phase B) — intake channels, credentials, test panel. */

.sources-form {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
}

.sources-form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--spacing-md);
}

.form-hint {
  margin: var(--spacing-xs) 0 0;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

.form-hint code,
.sources-secret code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.85em;
  background: var(--color-bg);
  padding: 0 4px;
  border-radius: var(--radius-sm);
}

.composer-error {
  padding: var(--spacing-sm) var(--spacing-md);
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--color-danger) 12%, transparent);
  color: var(--color-danger);
  font-size: var(--font-size-sm);
}

/* --- Field mapping editor --- */

.sources-map {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
  margin-bottom: var(--spacing-sm);
}

.sources-map-row {
  display: grid;
  grid-template-columns: 1fr auto 1.2fr 1.4fr auto;
  /* end, not center: see the field-row note in forms.css. */
  align-items: end;
  gap: var(--spacing-sm);
}

.sources-map-arrow {
  color: var(--color-text-muted);
}

.sources-map-spacer {
  display: block;
}

.sources-toggle {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  font-size: var(--font-size-sm);
  cursor: pointer;
}

.sources-type {
  text-transform: uppercase;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  letter-spacing: 0.04em;
}

/* --- Credentials (one-time secret) modal --- */

.sources-secret {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
}

.sources-warn {
  padding: var(--spacing-sm) var(--spacing-md);
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--color-warning) 15%, transparent);
  color: var(--color-text);
  font-size: var(--font-size-sm);
  border: 1px solid color-mix(in srgb, var(--color-warning) 40%, transparent);
}

.sources-copy {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
}

.sources-copy code {
  flex: 1;
  overflow-x: auto;
  white-space: nowrap;
  padding: var(--spacing-sm);
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
}

.sources-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

.sources-snippet {
  margin: 0;
  padding: var(--spacing-md);
  background: var(--color-sidebar-bg);
  color: var(--color-sidebar-text);
  border-radius: var(--radius-md);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--font-size-sm);
  overflow-x: auto;
  white-space: pre;
}

/* --- Test panel --- */

.sources-test {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
}

.sources-preview {
  padding: var(--spacing-md);
}

.sources-preview h4 {
  margin: 0 0 var(--spacing-sm);
}

.sources-preview-grid {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: var(--spacing-xs) var(--spacing-md);
  margin: 0;
  font-size: var(--font-size-sm);
}

.sources-preview-grid dt {
  color: var(--color-text-muted);
}

.sources-preview-grid dd {
  margin: 0;
}

.sources-bad {
  color: var(--color-danger);
}

@media (max-width: 640px) {
  .sources-form-row {
    grid-template-columns: 1fr;
  }
  .sources-map-row {
    grid-template-columns: 1fr auto 1fr auto;
  }
}

/* Acquisition Phase C — form builder + embed UI. Reuses the common form
   controls, badges, and buttons; adds the two-pane builder, field cards, live
   preview, and the embed tabs. */

/* The builder + embed modals are wider than the default 440px dialog. */

.modal-container:has(.form-builder),
.modal-container:has(.form-embed) {
  max-width: 920px;
}

.form-builder { display: flex; flex-direction: column; gap: var(--spacing-lg); }

.form-builder-top {
  display: flex; align-items: flex-end; gap: var(--spacing-lg);
}

.form-builder-top .form-group { flex: 1; margin: 0; }

.form-builder-grid {
  display: grid; grid-template-columns: 1.4fr 1fr; gap: var(--spacing-lg);
  align-items: start;
}

/* --- Palette --- */

.form-builder-palette { margin-bottom: var(--spacing-md); }

.form-builder-palette-btns {
  display: flex; flex-wrap: wrap; gap: var(--spacing-sm); margin-top: var(--spacing-xs);
}

/* .fb-palette-icon removed — field-type icons are SVG now (see Icon.jsx). */

/* --- Canvas / field cards --- */

.form-builder-canvas { display: flex; flex-direction: column; gap: var(--spacing-sm); }

.fb-field-card {
  border: 1px solid var(--color-border); border-radius: var(--radius-md);
  background: var(--color-surface); padding: var(--spacing-sm) var(--spacing-md);
}

.fb-field-head {
  display: flex; align-items: center; gap: var(--spacing-sm); margin-bottom: var(--spacing-sm);
}

.fb-drag {
  display: inline-flex;
  align-items: center;
  cursor: grab;
  color: var(--color-text-subtle);
  user-select: none;
}

.fb-drag:active { cursor: grabbing; }

.fb-field-move { margin-left: auto; display: flex; gap: 4px; }

.fb-field-body {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--spacing-sm);
}

.fb-field-body .form-group { margin: 0; }

.fb-span2 { grid-column: 1 / -1; }

/* --- Live preview --- */

.form-builder-preview {
  position: sticky; top: 0;
  border: 1px dashed var(--color-border); border-radius: var(--radius-md);
  padding: var(--spacing-md); background: var(--color-bg);
}

.wa-form-preview { display: flex; flex-direction: column; gap: var(--spacing-sm); margin-top: var(--spacing-sm); }

.wa-form-preview .wa-field { display: flex; flex-direction: column; gap: 4px; position: relative; }

.wa-form-preview .wa-field label { font-size: var(--font-size-sm); font-weight: 600; }

.wa-preview-key {
  position: absolute; top: 0; right: 0; font-size: 11px; color: var(--color-text-muted);
  font-family: monospace;
}

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

.wa-consent-check { display: flex; align-items: flex-start; gap: 6px; font-size: var(--font-size-sm); }

.wa-form-submit {
  align-self: flex-start; padding: 8px 18px; border: 0; border-radius: var(--radius-sm);
  background: var(--color-primary); color: #fff; font-weight: 600; cursor: default;
}

/* --- Sections below the two panes --- */

.form-builder-section {
  border-top: 1px solid var(--color-border); padding-top: var(--spacing-md);
}

.form-builder-section-title {
  font-size: var(--font-size-md); font-weight: 700; margin: 0 0 var(--spacing-sm);
}

/* --- Embed modal --- */

.form-embed-tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--color-border); margin-bottom: var(--spacing-md); }

.form-embed-tab {
  padding: 8px 14px; border: 0; background: transparent; cursor: pointer;
  font-size: var(--font-size-sm); font-weight: 600; color: var(--color-text-muted);
  border-bottom: 2px solid transparent;
}

.form-embed-tab.is-active { color: var(--color-primary); border-bottom-color: var(--color-primary); }

.form-embed-code { position: relative; }

.form-embed-copy { position: absolute; top: 8px; right: 8px; z-index: 1; }

.form-embed .sources-snippet { max-height: 420px; overflow: auto; }

@media (max-width: 720px) {
  .form-builder-grid { grid-template-columns: 1fr; }
  .fb-field-body { grid-template-columns: 1fr; }
  .form-builder-preview { position: static; }
}

/* Acquisition Phase D — campaigns, analytics, and outbound webhooks. */

/* Widen the modal for the step builder (mirrors forms-builder). */

.modal-container:has(.campaign-form) {
  max-width: 760px;
  width: 92vw;
}

.campaign-form,
.campaign-test,
.campaign-enroll,
.webhook-form {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
}

.campaign-form-row {
  display: flex;
  gap: var(--spacing-md);
  align-items: flex-end;
}

.campaign-form-row > .form-group { flex: 1; }

.campaign-quiet-sep { padding-bottom: 10px; color: var(--color-text-muted); }

.campaign-steps {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
}

.campaign-steps-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.campaign-step {
  padding: var(--spacing-md);
  border: 1px solid var(--color-border);
}

.campaign-step-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: var(--spacing-sm);
}

.campaign-step-num { font-weight: 600; }

.campaign-step-actions {
  display: flex;
  gap: var(--spacing-xs);
  align-items: center;
}

.campaign-step-active {
  display: inline-flex;
  gap: 4px;
  align-items: center;
  font-size: var(--font-size-sm);
}

.campaign-step-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--spacing-sm);
  margin-bottom: var(--spacing-sm);
}

.campaign-var-section-label {
  font-size: var(--font-size-xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
  margin: 6px 0 2px;
}

.campaign-var-row {
  display: flex;
  gap: var(--spacing-sm);
  align-items: center;
  margin-bottom: 4px;
}

.campaign-var-token {
  font-family: var(--font-mono, monospace);
  font-size: var(--font-size-sm);
  min-width: 120px;
  color: var(--color-text-muted);
}

.campaign-var-auto {
  font-size: var(--font-size-sm);
  color: var(--color-success, #166534);
}

.campaign-var-row .form-control { flex: 1; }

.campaign-warning {
  background: #fef3c7;
  color: #92400e;
  border-radius: var(--radius-sm);
  padding: var(--spacing-sm);
  font-size: var(--font-size-sm);
}

/* Test + enroll contact picker */

.campaign-test-results {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 220px;
  overflow-y: auto;
}

.campaign-test-result {
  display: flex;
  justify-content: space-between;
  align-items: center;
  text-align: left;
  padding: var(--spacing-sm);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface, #fff);
  cursor: pointer;
}

.campaign-test-result:hover { background: var(--color-surface-hover, #f8fafc); }

.campaign-test-result.is-selected { border-color: var(--color-primary, #2563eb); }

.campaign-test-selected {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: var(--spacing-sm);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
}

/* Members / enrollments */

.campaign-members { display: flex; flex-direction: column; gap: var(--spacing-md); }

.campaign-backfill {
  background: var(--color-surface-hover, #f1f5f9);
  padding: var(--spacing-sm);
  border-radius: var(--radius-sm);
}

.campaign-members-list { display: flex; flex-direction: column; gap: 2px; max-height: 340px; overflow-y: auto; }

.campaign-member-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: var(--spacing-sm);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
}

.campaign-member-actions {
  display: inline-flex;
  gap: var(--spacing-sm);
  align-items: center;
}

.lists-campaign-chip { margin-right: 4px; }

/* Analytics */

.analytics-filters { display: flex; gap: var(--spacing-md); align-items: flex-end; }

.analytics-skips { display: flex; flex-wrap: wrap; gap: 4px; }

/* Webhooks */

.webhook-events {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 4px;
}

.webhook-event {
  display: inline-flex;
  gap: 6px;
  align-items: center;
  font-size: var(--font-size-sm);
}

.webhook-url {
  font-family: var(--font-mono, monospace);
  font-size: var(--font-size-sm);
  max-width: 320px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.webhook-secret-value {
  display: flex;
  gap: var(--spacing-sm);
  align-items: center;
  background: var(--color-surface-hover, #f1f5f9);
  padding: var(--spacing-sm);
  border-radius: var(--radius-sm);
  word-break: break-all;
}

.webhook-secret-recipe pre {
  background: var(--color-surface-hover, #f1f5f9);
  padding: var(--spacing-sm);
  border-radius: var(--radius-sm);
  font-size: var(--font-size-xs);
  overflow-x: auto;
}

/* =========================================================================
   Settings — section nav, in-page tabs, and the shared form furniture.

   Settings was one page of eight stacked cards; it is now one sub-page per
   concern (see features/Settings/settingsSections.js), with tabs inside the
   sections that still hold several panels. Both levels exist for the same
   reason: a settings screen people scroll for a minute is a settings screen
   people stop reading.
   ========================================================================= */

/* Forms read badly at the full 1280px content width — a "Claim window
   (seconds)" box a metre wide is harder to parse, not easier. Settings keeps
   its own comfortable measure and stays left-aligned with the page heading. */

.settings-page {
  max-width: 960px;
}

/* ---- Section nav (one entry per Settings sub-page) --------------------- */

.settings-nav {
  display: flex;
  gap: var(--spacing-xs);
  padding: var(--spacing-xs);
  margin-bottom: var(--spacing-lg);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-xs);
  /* On a phone the strip scrolls sideways rather than wrapping into a block
     that pushes the actual settings below the fold. */
  overflow-x: auto;
  scrollbar-width: none;
}

.settings-nav::-webkit-scrollbar {
  display: none;
}

.settings-nav-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-sm);
  flex: 1 0 auto;
  min-height: var(--tap-target);
  padding: 0 var(--spacing-md);
  border-radius: var(--radius-sm);
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--color-text-muted);
  white-space: nowrap;
  transition:
    background var(--duration-fast) var(--ease-standard),
    color var(--duration-fast) var(--ease-standard);
}

.settings-nav-link:hover {
  background: var(--color-surface-hover);
  color: var(--color-text);
  text-decoration: none;
}

/* The current section is marked three ways — fill, weight and NavLink's
   aria-current — so it never rests on colour alone. */

.settings-nav-link.is-active,
.settings-nav-link.is-active:hover {
  background: var(--color-primary-soft);
  color: var(--color-primary);
  font-weight: 700;
}

/* ---- Section heading --------------------------------------------------- */

.settings-section-head {
  margin-bottom: var(--spacing-md);
}

.settings-section-title {
  font-size: var(--font-size-lg);
}

.settings-section-desc {
  margin-top: var(--spacing-2xs);
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  max-width: 70ch;
}

/* Cards inside a section: the page owns the rhythm, not the card. */

.settings-stack {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-lg);
}

.settings-stack:focus {
  outline: none;
}

/* ---- Tabs inside a section --------------------------------------------- */

.settings-tabs {
  display: flex;
  gap: var(--spacing-lg);
  border-bottom: 1px solid var(--color-border);
  overflow-x: auto;
  scrollbar-width: none;
}

.settings-tabs::-webkit-scrollbar {
  display: none;
}

.settings-tab {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-sm);
  min-height: var(--tap-target);
  padding: 0 var(--spacing-2xs);
  background: none;
  border: none;
  /* Sits on the strip's own border so the indicator reads as one line. */
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--color-text-muted);
  white-space: nowrap;
  transition: color var(--duration-fast) var(--ease-standard);
}

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

.settings-tab[aria-selected='true'] {
  color: var(--color-primary);
  border-bottom-color: var(--color-primary);
  font-weight: 700;
}

.settings-tab-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  padding: 0 6px;
  border-radius: var(--radius-full);
  background: var(--color-surface-hover);
  color: var(--color-text-muted);
  font-size: var(--font-size-xs);
  font-weight: 600;
}

.settings-tab[aria-selected='true'] .settings-tab-count {
  background: var(--color-primary-soft);
  color: var(--color-primary);
}

/* ---- Form furniture ---------------------------------------------------- */

/* Short, unrelated controls sit two-up on a desktop and collapse to one
   column on a phone, so a five-field panel is a screenful rather than a
   five-screen scroll. */

.settings-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 0 var(--spacing-lg);
  align-items: start;
}

/* A field whose answer is a small number or a time: a full-width box invites
   a paragraph. */

.settings-field-narrow .form-control {
  max-width: 240px;
}

.settings-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--spacing-md);
  margin-top: var(--spacing-lg);
  padding-top: var(--spacing-md);
  border-top: 1px solid var(--color-border);
}

.settings-actions-note {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-xs);
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

.settings-actions-note.is-saved {
  color: var(--color-success);
}

/* Secondary links in the save row belong at the far end, away from Save. */

.settings-actions-aside {
  margin-left: auto;
}

/* Business hours is seven near-identical rows: the default table padding on
   top of a 44px time input makes it the one panel that still scrolls. Tighten
   the cell padding — the inputs themselves keep their full tap height. */

.settings-hours-table th,
.settings-hours-table td {
  padding: var(--spacing-xs) var(--spacing-md);
}

.settings-hours-table td .form-control {
  min-width: 120px;
}

/* The open/closed checkbox is the whole cell's job — give it a real tap
   target instead of a 13px box floating in a wide column. */

.settings-hours-open {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--tap-target);
  min-height: var(--tap-target);
  cursor: pointer;
}

/* A long reply preview in a rules table truncates rather than forcing the
   table wider than the panel. */

.settings-cell-clamp {
  max-width: 280px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

@media (max-width: 640px) {
  .settings-nav-link {
    /* Below the fold on a phone, equal-width tabs squeeze the labels; let each
       take its natural width and scroll instead. */
    flex: 0 0 auto;
  }

  .settings-actions-aside {
    margin-left: 0;
  }

  .settings-cell-clamp {
    max-width: 180px;
  }
}

/* =========================================================================
   Breakpoints: 1024 (sidebar becomes a drawer) and 640 (phone).

   The previous rule collapsed the sidebar to a 64px icon-only rail on phones,
   which left unlabelled icons — unusable for someone who does not already know
   the product. Below 1024px the sidebar is now a proper drawer with full
   labels, opened from the header.
   ========================================================================= */

@media (max-width: 1023px) {
  .app-sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    z-index: var(--z-drawer);
    width: min(86vw, var(--sidebar-width));
    transform: translateX(-100%);
    /* transform only: the desktop width transition must not run while the
       drawer slides, or the two animate against each other. */
    transition: transform var(--duration-base) var(--ease-out);
    box-shadow: var(--shadow-lg);
  }

  .app-sidebar.is-open { transform: translateX(0); }

  .sidebar-close { display: inline-flex; }
  .header-menu-btn { display: inline-flex; }

  /* Collapsing is a desktop affordance. Below this width the sidebar is an
     overlay drawer that is either fully open with labels or fully off-screen,
     so a persisted collapse must not leak in and produce an unlabelled rail. */
  .sidebar-collapse-btn { display: none; }

  .app-sidebar.is-collapsed { width: min(86vw, var(--sidebar-width)); }
  .app-sidebar.is-collapsed .sidebar-brand { justify-content: flex-start; padding: var(--spacing-md); }
  .app-sidebar.is-collapsed .sidebar-brand-logo,
  .app-sidebar.is-collapsed .sidebar-brand-text { display: flex; }
  .app-sidebar.is-collapsed .sidebar-nav {
    padding-left: var(--spacing-sm);
    padding-right: var(--spacing-sm);
  }
  .app-sidebar.is-collapsed .sidebar-link {
    justify-content: flex-start;
    padding: 10px 12px;
    margin: 0;
    width: auto;
  }
  .app-sidebar.is-collapsed .sidebar-link-label {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    overflow: hidden;
    clip: auto;
    white-space: nowrap;
  }
  .app-sidebar.is-collapsed .sidebar-section-title {
    font-size: var(--font-size-xs);
    padding: 0 12px var(--spacing-xs);
    margin: 0;
    width: auto;
    height: auto;
    background: none;
  }
  .sidebar-tip { display: none; }

  /* Also shrinks the inbox height calc, which reads this token. */
  .app-shell { --content-padding: var(--spacing-md); }
  .notif-nudge { margin: var(--spacing-md) var(--spacing-md) 0; }
}

@media (max-width: 640px) {
  .app-header { padding: 0 var(--spacing-sm); }

  /* Keep the avatar; drop the name so presence + account still fit. */
  .header-avatar-name,
  .header-avatar-caret { display: none; }

  .page-header {
    flex-direction: column;
    align-items: stretch;
  }

  .page-actions { flex-wrap: wrap; }

  /* Full-width actions are easier to hit than a cramped row of small buttons. */
  .page-actions .btn { flex: 1 1 auto; }

  .modal-overlay { padding: 0; align-items: flex-end; }

  .modal-container {
    max-width: none;
    max-height: 92vh;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  }

  .modal-footer { flex-direction: column-reverse; }
  .modal-footer .btn { width: 100%; }

  .auth-card { padding: var(--spacing-lg); }
}

/* Respect users who ask the OS to reduce motion: the drawer snaps instead of
   sliding. (The global reduced-motion rule in reset.css already zeroes the
   duration; this keeps the intent explicit at the component level.) */

@media (prefers-reduced-motion: reduce) {
  .app-sidebar { transition: none; }
}
