/* =========================================================================
   Design tokens — single source of truth for the whole SPA.

   Brand: the Wazigo navy shell, a deep "trust blue" for everything the user
   can press, and the logo's forest green for brand expression only.

   THREE colours, three jobs — keep them apart:
     --color-primary        blue   = interactive. Buttons, links, active nav,
                                     focus. If you can click it, it is blue.
     --color-whatsapp       mint   = WhatsApp STATE. Connected, delivered,
                                     24h window open. Never decoration.
     --color-brand-green    forest = WHO WE ARE. The mark, the sign-in
                                     backdrop. Never a control, never state.

   Why blue still owns the buttons even though the logo is green (owner
   decision, 2026-08-26): green already means "delivered / connected" in this
   product, and a green Send button sitting beside a green delivered tick
   teaches the user that green means nothing in particular. Blue also reads as
   "serious business software" to the Indian SMB audience — Razorpay, Paytm,
   Khatabook. Meta's brand guidelines separately discourage a third-party tool
   dressing itself as WhatsApp.

   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. This is the Wazigo logo's
     own navy — the same #0f1b33 the marketing site uses, so app and site
     match without anyone having to remember two values. */
  --color-brand-navy: #0f1b33;
  --color-brand-navy-soft: #1a2a4a;

  /* ---- Wazigo green (BRAND expression only — never a CTA, never state)
     Sampled from the official logo gradient. Read the next block before
     using any of these: this is the second green in the system and the two
     are kept apart on purpose.

     Brand green is a deep FOREST/emerald; WhatsApp green below is a light
     MINT. They are different hues, not two shades of one colour, which is
     what lets both live in the same UI without "green" losing its meaning.

     Use for: the brand mark, the sign-in backdrop, brand illustration.
     Do NOT use for: buttons, links, active nav, focus rings (those stay
     --color-primary blue), or for connected/delivered/window-open state
     (that stays --color-whatsapp). */
  --color-brand-green: #08b74f;       /* vivid mid-gradient — fills on dark only, 2.7:1 on white */
  --color-brand-green-bright: #22d366; /* the gradient's light end — mark and backdrop only, never text */
  --color-brand-green-deep: #05803f;  /* 5.0:1 on white — safe for text and icons */
  --color-brand-green-dark: #00603a;  /* 7.7:1 on white — the gradient's dark end */
  --color-brand-green-soft: #d8f8de;  /* tint for brand surfaces */

  /* ---- 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;

  /* ---- Chart series -------------------------------------------------
     Identity, not state. Two fixed slots, assigned once and never cycled:
     slot 1 = messages we sent, slot 2 = messages customers sent. A filter
     must never repaint them, and neither may borrow a status colour — a
     teal bar means "from a customer", not "healthy".

     The pair is validated for colour-vision deficiency (OKLab ΔE 20.7
     deutan / 22.6 normal against the white card). Its tritan separation is
     6.4, which is only legal alongside a second, non-colour channel — hence
     the fixed stacking order, the 2px surface gap between segments, the
     legend, and the table view under every chart. Do not drop those. */
  --chart-1: #2563eb;
  --chart-1-soft: #dbeafe;
  --chart-2: #0d9488;
  --chart-2-soft: #ccfbf1;
  /* Gridlines and axis rules: one step off the surface, hairline, solid. */
  --chart-grid: var(--gray-200);

  /* ---- 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; }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); }
.mt-lg { margin-top: var(--spacing-lg); }

.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);
  flex-wrap: wrap;
}

.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;
}

.page-header > div:first-child { flex: 1 1 auto; min-width: 0; }
.page-header-actions, .page-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-sm); }
.page-header .page-subtitle { margin-top: 6px; }
.page-header + .page-subtitle:has(.number-chip) { margin: -8px 0 20px; }
/* =========================================================================
   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;
}

.number-workspace-picker {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-xs);
  padding: var(--spacing-xs) var(--spacing-sm) var(--spacing-sm);
}

.number-workspace-picker .form-control { min-width: 0; font-size: var(--font-size-xs); }
.number-workspace-empty { font-size: var(--font-size-xs); padding: var(--spacing-sm); }
.number-identity-fields { border: 0; padding: 0; min-width: 0; }
.number-workspace-compact { padding: var(--spacing-sm) 0; max-width: 360px; }

@media (min-width: 1024px) {
  .number-workspace-compact { display: none; }
}

/* ---- Brand mark --------------------------------------------------------- */

/* The mark carries its own brand gradient (see BrandMark.jsx) — it must not
   inherit a theme colour, which is why no `color` is set here. */
.brand-mark {
  display: inline-flex;
  flex-shrink: 0;
}

/* On a dark surface, lift the floor of the mark's gradient.
   The logo's own dark end (#00603a) is only 2.23:1 against the navy sidebar,
   so the speech-bubble tail and the bottom of the ring sink into the
   background and the mark reads as clipped. #089a49 is 4.68:1 there, well
   past the 3:1 minimum for non-text.

   This works by re-declaring the brand tokens on the element: the SVG's
   gradient stops are `var(--color-brand-green-*)`, so they pick this up and
   there is still only ONE copy of the artwork. Put this class on the mark
   anywhere it sits on navy. */
.brand-mark-on-dark {
  --color-brand-green-dark: #089a49;
  --color-brand-green: #17c95c;
}

/* 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);
}

/* "Chat with support" — opens WhatsApp; sits beside the bell. */
.header-support-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-xs);
  min-height: 40px;
  padding: 0 var(--spacing-sm);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  color: var(--color-text);
  font-size: var(--font-size-sm);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}

.header-support-btn:hover { background: var(--color-surface-hover); }
.header-support-btn:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }

/* 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-phone { 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);
  /* Navy ground with the logo's green lifting off the top right — the same
     direction the mark's plane travels. Brand expression, not a control, so
     green is right here where it would be wrong on a button. Nothing on this
     screen is read against the glow: the form sits on a white card. */
  background:
    radial-gradient(900px 620px at 88% -12%, rgba(34, 211, 102, 0.30), transparent 62%),
    radial-gradient(760px 520px at 6% 108%, rgba(8, 183, 79, 0.18), transparent 60%),
    linear-gradient(160deg, var(--color-brand-navy), #16294a);
}

.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);
}

/* The OAuth handoff's status line. The spinner is held back for half a second
   (useOAuthContinue) because this screen usually forwards faster than that, and
   a spinner that appears and vanishes reads as a fault rather than as progress.
   It keeps its space either way, so nothing moves when it does appear. */
.auth-status {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  min-height: 22px;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

.auth-status .spinner {
  flex: none;
  visibility: hidden;
}

.auth-status.is-working .spinner { visibility: visible; }

/* The reason Wazigo gave for suspending a workspace (WorkspaceUnavailablePage). */
.auth-reason {
  background: var(--color-warning-soft);
  color: var(--color-warning-text);
  border-radius: var(--radius-sm);
  padding: 12px var(--spacing-md);
  margin: var(--spacing-md) 0;
  font-size: var(--font-size-sm);
  text-align: left;
}

.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)); }

/* App-wide alarm bar: a fault that is losing customer messages right now.
   Danger tokens, not warning — this is not "keep an eye on it", it is data
   being dropped — and it carries an icon and words as well as the colour, so
   it does not depend on colour alone to be understood. */
.app-alert {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-md);
  flex-wrap: wrap;
  margin: var(--spacing-md) var(--spacing-lg) 0;
  padding: 12px var(--spacing-md);
  background: var(--color-danger-soft);
  border: 1px solid var(--color-danger);
  /* Thicker on the leading edge only, matching .dash-warning, so the two read
     as the same kind of object at different volumes. */
  border-left-width: 3px;
  border-radius: var(--radius-md);
  color: var(--color-danger-text);
}

.app-alert > svg { flex-shrink: 0; margin-top: 2px; color: var(--color-danger); }

.app-alert-body { flex: 1; min-width: 240px; }

.app-alert-body strong { display: block; font-weight: 700; }

.app-alert-body p {
  font-size: var(--font-size-sm);
  line-height: 1.55;
  margin-top: 2px;
  /* Kept to a readable measure on a wide desktop rather than running the full
     width of the shell. */
  max-width: 78ch;
  overflow-wrap: anywhere;
}

.app-alert .btn { flex-shrink: 0; }

/* Two actions, and only ever two: the fix, and putting the reminder away.
   Wrapping together keeps them as one block when the shell narrows, rather
   than the secondary one falling under the text it does not belong to. */
.app-alert-actions {
  display: flex;
  gap: var(--spacing-sm);
  flex-shrink: 0;
  flex-wrap: wrap;
  align-items: flex-start;
}

/* A refusal from the server, under the words it answers. */
.app-alert-note {
  margin-top: var(--spacing-sm);
  font-weight: 600;
}

/* The same bar, after the tenant says they have fixed it. Neutral rather than
   green: nothing has been confirmed by WhatsApp, and green here would claim it
   had. Colour is not the signal either way — the tick and the sentence are. */
.app-alert-done {
  background: var(--color-primary-soft);
  border-color: var(--color-primary-soft-border);
  color: var(--color-info-text);
}

.app-alert-done > svg { color: currentColor; }

/* Same bar, softer tokens — for a warning that has not yet cost anybody a
   message (80/95% of a usage cap, a grace period ending soon). The 100% hard
   stop and a failed payment stay on the base .app-alert (danger) above: those
   are actively blocking something right now, not "keep an eye on it". */
.app-alert-warning {
  background: var(--color-warning-soft);
  border-color: var(--color-warning);
  color: var(--color-warning-text);
}

.app-alert-warning > svg { color: var(--color-warning); }

/* 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); }
/* Shopify's embedded account connection uses the shared form/card system. */
.shopify-page { max-width: 720px; margin: 0 auto; padding: var(--spacing-lg); }
.shopify-page .card-body > *, .shopify-page form { margin-bottom: var(--spacing-md); }

.settings-directory { display: flex; flex-wrap: wrap; gap: var(--spacing-md); margin-bottom: var(--spacing-lg); }
.settings-directory-link { display: flex; flex-direction: column; gap: 8px; padding: var(--spacing-lg); flex: 1 1 230px; color: var(--color-text); text-decoration: none; }
.settings-directory-link span { font-size: 13px; color: var(--color-text-muted); }
.settings-directory-link:hover, .settings-directory-link:focus-visible { outline: 2px solid var(--color-primary); }
@media (max-width: 600px) { .settings-directory-link { flex-basis: 100%; } }

.dashboard-details { margin-bottom: var(--spacing-lg); }
.dashboard-details > summary { cursor: pointer; margin-bottom: var(--spacing-md); }

[hidden] { display: none !important; }

.settings-directory { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 250px), 1fr)); }
.settings-directory-link { position: relative; padding: 22px 44px 22px 22px; box-shadow: var(--shadow-xs); transition: border-color var(--duration-fast), box-shadow var(--duration-fast); }
.settings-directory-link::after { content: '→'; position: absolute; right: 20px; top: 22px; color: var(--color-primary); }
.settings-directory-link:hover { border-color: var(--color-primary); box-shadow: var(--shadow-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); }

/* A linked Send API campaign whose template Meta has stopped. Sits beside the
   campaign name in the list rather than replacing it — the tenant needs to know
   WHICH campaign broke, not just that something did. */
.form-link-warn { margin-left: var(--spacing-xs); }

/* --- Password field with a reveal toggle -------------------------------- */

/* The button sits INSIDE the input's box rather than beside it, so the field
   keeps the same width as every other one on the form — a password input that
   is visibly shorter than the email above it reads as a rendering fault. */
.password-field {
  position: relative;
}

.password-field__input {
  /* Room for the toggle. Without this the last characters of a revealed
     password run underneath it. */
  padding-right: 44px;
}

.password-field__toggle {
  position: absolute;
  /* Aligns to the input, not the form group: the label and helper text are
     part of the group and would drag this off-centre. */
  top: 30px;
  right: 1px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border: none;
  background: none;
  color: var(--color-text-muted);
  cursor: pointer;
  border-radius: var(--radius-sm);
}

.password-field__toggle:hover {
  color: var(--color-text);
}

.password-field__toggle:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: -2px;
}

.commerce-page .page-header { align-items: flex-start; }
.commerce-page .workspace-settings-nav { margin-bottom: 24px; }
.commerce-provider .card-body { display: flex; flex-direction: column; gap: 16px; padding: 24px; }
.commerce-provider-heading { display: flex; align-items: center; gap: 16px; }
.commerce-provider-heading h2 { margin: 0; font-size: 21px; }
.commerce-provider-icon { display: grid; place-items: center; width: 56px; height: 56px; border-radius: 15px; background: #ecf7d9; color: #629b18; flex-shrink: 0; }
.commerce-provider-woocommerce .commerce-provider-icon { background: #f3e8ff; color: #8850b8; }
.commerce-provider p { margin: 0; }
.commerce-provider .flex { flex-wrap: wrap; }
.commerce-provider-store { display: flex; flex-direction: column; align-items: flex-start; gap: 7px; overflow-wrap: anywhere; }
.commerce-provider-store strong { font-size: 16px; }
.commerce-provider-store .badge { margin-bottom: 3px; }
.commerce-store-list .card-header { justify-content: flex-start; }
.commerce-store-list .table { table-layout: auto; min-width: 880px; }
.commerce-store-list th:first-child { width: 20%; min-width: 160px; }
.commerce-store-list th:nth-child(4) { width: 28%; }
.commerce-store-list td { vertical-align: top; }
.commerce-store-list td:first-child strong { display: block; margin-bottom: 6px; }
.commerce-store-list td:last-child .flex { flex-wrap: wrap; gap: 6px; min-width: 190px; }
.commerce-store-list td .text-muted { margin-top: 6px; font-size: 13px; overflow-wrap: anywhere; }
.commerce-store-list .badge { white-space: normal; }
.commerce-store-list .btn-danger { color: var(--color-danger); background: transparent; border: 1px solid currentColor; }
@media (max-width: 767px) {
  .commerce-page > .grid { grid-template-columns: 1fr; }
  .commerce-provider .card-body { padding: 20px; }
  .commerce-store-list .table, .commerce-store-list tbody, .commerce-store-list tr, .commerce-store-list td { display: block; width: 100%; min-width: 0; }
  .commerce-store-list thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .commerce-store-list tr { padding: 12px 0; border-bottom: 1px solid var(--color-border); }
  .commerce-store-list td { border: 0; padding: 10px 0; }
  .commerce-store-list td::before { display: block; font-size: 12px; font-weight: 600; color: var(--color-text-muted); margin-bottom: 6px; }
  .commerce-store-list td:nth-child(1)::before { content: 'Store'; }
  .commerce-store-list td:nth-child(2)::before { content: 'Sending number'; }
  .commerce-store-list td:nth-child(3)::before { content: 'Platform'; }
  .commerce-store-list td:nth-child(4)::before { content: 'Order updates'; }
  .commerce-store-list td:nth-child(5)::before { content: 'Actions'; }
}
.commerce-message-preview {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.commerce-order-preview {
  display: block;
}

/* The status sentence under a connected store on the Online Stores cards. */
.commerce-card-note {
  display: block;
  margin-top: var(--spacing-xs);
}

/* The latest order's result on a store row of the Online Stores list. */
.commerce-latest {
  margin-top: var(--spacing-xs);
}

.commerce-order-preview p {
  margin: 12px 0 0;
}
.commerce-logo-woo { position: relative; padding: 3px 5px 6px; border-radius: 5px; color: #fff; background: #8850b8; font-size: 18px; font-weight: 800; letter-spacing: -1px; font-style: italic; }
.commerce-logo-woo::after { content: ''; position: absolute; left: 9px; bottom: -5px; border-left: 6px solid transparent; border-right: 1px solid transparent; border-top: 7px solid #8850b8; }
.commerce-activity { min-width: 0; }
.commerce-activity .table { table-layout: fixed; width: 100%; }
.commerce-activity .table th:first-child { width: 30%; }
.commerce-activity .table th:nth-child(2) { width: 20%; }
.commerce-activity .table th:last-child { width: 50%; }
.commerce-activity .table td { white-space: normal; overflow-wrap: anywhere; font-size: 12px; vertical-align: top; line-height: 1.6; }
.commerce-activity .number-chip { margin-top: 8px; max-width: 100%; }
.commerce-activity details { margin-top: 10px; }
.commerce-activity summary { cursor: pointer; color: var(--color-primary); }
.commerce-activity .commerce-message-preview { white-space: pre-wrap; overflow-wrap: anywhere; padding: 12px; border-radius: 10px; background: #e5f8df; color: var(--color-text); }
@media (max-width: 640px) {
  .commerce-activity .table, .commerce-activity tbody, .commerce-activity tr, .commerce-activity .table td { display: block; width: 100%; }
  .commerce-activity thead { display: none; }
  .commerce-activity tr { padding: 16px; margin-bottom: 14px; border: 1px solid var(--color-border); border-radius: 10px; }
  .commerce-activity .table td { padding: 6px 0; border: 0; }
  .commerce-activity td::before { display: block; color: var(--color-text-muted); font-size: 11px; margin-bottom: 4px; }
  .commerce-activity td:nth-child(1)::before { content: 'Order'; }
  .commerce-activity td:nth-child(2)::before { content: 'Update'; }
  .commerce-activity td:nth-child(3)::before { content: 'Result'; }
  .commerce-activity td > .number-chip { display: flex; width: fit-content; margin: 6px 0; }
}
/* 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); }

/* Action dialogs use existing focus/escape behavior and escape table clipping. */
.row-actions { display: inline-flex; flex-wrap: nowrap; align-items: center; gap: 4px; }
.row-action-sheet { display: grid; gap: 10px; }
.row-action-sheet .btn { width: 100%; justify-content: flex-start; white-space: normal; text-align: left; }
.table-wrapper { scrollbar-width: thin; scrollbar-color: var(--color-border-strong) var(--color-surface-sunken); }
.table-wrapper:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 3px; }
.table td { overflow-wrap: anywhere; }
/* These two daily tables expose every cell as a labelled record on phones.
   One DOM means one handler, one keyboard path and no duplicate dialog. */
@media (max-width: 760px) {
  .ch-table .table, .tpl-table .table { display: block; }
  .ch-table .table thead, .tpl-table .table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .ch-table .table tbody, .tpl-table .table tbody { display: block; }
  .ch-table .table tr, .tpl-table .table tr { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); padding: 16px; gap: 12px; border-bottom: 1px solid var(--color-border); }
  .ch-table .table td, .tpl-table .table td { display: block; min-width: 0; padding: 0; border: 0; white-space: normal; }
  .ch-table .table td::before, .tpl-table .table td::before { content: attr(data-label); display: block; margin-bottom: 5px; color: var(--color-text-muted); font-size: 12px; font-weight: 600; }
  .ch-table .table td:first-child, .tpl-table .table td:first-child,
  .ch-table .table td:last-child, .tpl-table .table td:last-child { grid-column: 1 / -1; }
}

@media (max-width: 760px) {
  .responsive-records .table, .responsive-records .table tbody { display: block; }
  .responsive-records .table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .responsive-records .table tr { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); padding: 16px; gap: 12px; border-bottom: 1px solid var(--color-border); }
  .responsive-records .table td { display: block; min-width: 0; padding: 0; border: 0; white-space: normal; }
  .responsive-records .table td::before { content: attr(data-label); display: block; margin-bottom: 5px; color: var(--color-text-muted); font-size: 12px; font-weight: 600; }
  .responsive-records .table td:first-child, .responsive-records .table td:last-child { grid-column: 1 / -1; }
}

/* A long catalogue may still scroll, but its management control stays visible. */
@media (min-width: 761px) {
  .table:has(th[aria-label="Actions"]) th:last-child,
  .table:has(th[aria-label="Actions"]) td:last-child { position: sticky; right: 0; background: var(--color-surface); box-shadow: -4px 0 8px -6px var(--color-border-strong); z-index: 1; }
  .table:has(th[aria-label="Actions"]) th:last-child { background: var(--color-surface-sunken); z-index: 2; }
}

.row-action-sheet .btn-danger-outline { color: var(--color-danger); background: var(--color-surface); border: 1px solid var(--color-border); }
.row-action-sheet .btn-danger-outline:hover { background: var(--color-danger-soft); }
.row-action-sheet .btn-danger-outline:focus-visible { box-shadow: var(--focus-ring-danger); }
.row-action-sheet .row-action-danger { color: var(--color-danger); }
.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;
}

/* --- WhatsApp number chip (multi-number, MN) ---------------------------
   IDENTITY, not state. Deliberately the neutral of the set: --color-whatsapp
   already means "connected / delivered / window open" in this product and
   --color-primary means "you can press this", and a number chip is neither. It
   answers "which of our numbers is this?" and nothing more.

   Gray-600 on gray-100 clears 7:1, so the label stays readable at 11-12px. The
   text is allowed to ellipsize because a tenant may type up to 60 characters
   into `label`; it is never the ONLY place that value appears (the number
   filter and the composer both spell it out in full) and it keeps its own
   title, so nothing is recoverable by hover alone. */
.number-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  max-width: 100%;
  min-width: 0;
  padding: 2px 8px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  background: var(--gray-100);
  color: var(--color-text-muted);
  font-size: var(--font-size-xs);
  font-weight: 500;
  line-height: 1.5;
}

/* The icon must not shrink away while the label does. */
.number-chip > .icon {
  flex: 0 0 auto;
  color: var(--color-text-subtle);
}

.number-chip-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Dense variant for the conversation-list rows, where the chip shares a
   wrapping rail with the priority chip and the label dots. No tap target of its
   own: the whole row is the button, and this is a <span> on purpose. */
.number-chip-sm {
  padding: 1px 6px;
  font-size: 11px;
  max-width: 60%;
}
.number-color-dot {
  display: inline-block;
  width: 0.7rem;
  height: 0.7rem;
  margin-right: 0.4rem;
  border-radius: 50%;
  flex-shrink: 0;
  vertical-align: middle;
}

.number-chip .number-color-dot { margin-right: 0; }
.number-color-picker { margin: 0; padding: 0; border: 0; }
.number-color-options { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.number-color-option {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.45rem 0.65rem;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.number-color-option:has(input:checked) { border-color: var(--color-primary); }
.number-color-option:has(input:focus-visible) { outline: 2px solid var(--color-primary); outline-offset: 2px; }
.number-color-option .number-color-dot { margin-right: 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; }

/* The ErrorBoundary's default screen. It replaces the WHOLE tree — shell
   included — so it fills the viewport on its own rather than relying on
   .app-shell, and it is kept to one reading-width panel so the explanation
   and its two exits read as a single unit on a phone or a wide desktop. */
.error-boundary {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  min-height: 100dvh;
  padding: var(--spacing-lg) var(--spacing-md);
  background: var(--color-bg);
}

.error-boundary-panel {
  width: 100%;
  max-width: 480px;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
}

.error-boundary-panel .error-message { margin-bottom: 0; }
.error-boundary-panel .page-actions { flex-wrap: wrap; }
/* Focus lands here on mount (see ErrorBoundary.jsx); a heading with tabindex
   -1 needs no visible ring of its own — the ring belongs on the controls. */
.error-boundary-panel .page-title:focus { outline: none; }

/* ---- 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(min(100%, 150px), 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); }

/* ---- Number-needs-attention banner -------------------------------------- */

/* Leads the page when WhatsApp has throttled, restricted or stopped the
   number. Warning tone rather than danger: sending is held, not lost. */
.dash-warning {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-md);
  padding: var(--spacing-md) var(--spacing-lg);
  margin-bottom: var(--spacing-lg);
  border: 1px solid var(--color-warning);
  border-left-width: 3px;
  border-radius: var(--radius-md);
  background: var(--color-warning-soft);
  color: var(--color-warning-text);
}

.dash-warning > svg { flex-shrink: 0; margin-top: 2px; color: var(--color-warning); }
.dash-warning > div { flex: 1; min-width: 0; }
.dash-warning strong { display: block; font-weight: 700; }

.dash-warning p {
  font-size: var(--font-size-sm);
  line-height: 1.55;
  margin-top: 2px;
  max-width: 72ch;
}

.dash-warning .btn { flex-shrink: 0; background: var(--color-surface); }

/* ---- Two-up row: the wide chart beside a narrow readout ----------------- */

.dash-split {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
  gap: var(--spacing-lg);
  align-items: start;
}

/* ---- Chart furniture shared by the widgets on this page ----------------- */

.chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-md);
  list-style: none;
}

.chart-legend li {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--font-size-sm);
  /* Never the series colour: a legend label is text and wears text ink. The
     swatch beside it is what carries the identity. */
  color: var(--color-text-muted);
}

.chart-legend b {
  font-weight: 700;
  color: var(--color-text);
  font-variant-numeric: tabular-nums;
}

.chart-key {
  width: 10px;
  height: 10px;
  border-radius: 3px;
  flex-shrink: 0;
}

.chart-key-1 { background: var(--chart-1); }
.chart-key-2 { background: var(--chart-2); }

/* The table view. A tooltip may enhance a chart; it may never be the only
   way to read a value. */
.chart-table { margin-top: var(--spacing-md); }

.chart-table > summary {
  cursor: pointer;
  font-size: var(--font-size-sm);
  color: var(--color-primary);
  padding: var(--spacing-sm) 0;
}

.chart-table > summary:focus-visible { outline: var(--focus-outline); outline-offset: 2px; }
.chart-table .table { font-variant-numeric: tabular-nums; }
.chart-table .table th[scope='row'] { font-weight: 500; white-space: nowrap; }

/* ---- Message activity: 14 stacked columns ------------------------------- */

.activity-summary {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--spacing-md);
  margin-bottom: var(--spacing-lg);
}

.activity-figure { display: flex; align-items: baseline; gap: var(--spacing-sm); }

/* Proportional figures, not tabular: at this size equal-width digits make a
   number like 121 read loose. */
.activity-figure-value {
  font-family: var(--font-display);
  font-size: var(--font-size-2xl);
  font-weight: 700;
  line-height: 1;
}

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

.activity-plot {
  position: relative;
  height: 180px;
  /* The y-axis labels get a lane of their own. Sat over the plot they would
     occlude the first column the moment it grew tall. */
  --axis-gutter: 32px;
}

/* Gridlines: hairline, solid, one step off the surface. Never dashed — a
   dashed rule reads as a threshold when it is only a grid. */
.activity-grid {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.activity-grid span {
  position: absolute;
  left: var(--axis-gutter);
  right: 0;
  bottom: var(--tick);
  border-top: 1px solid var(--chart-grid);
}

.activity-grid i {
  position: absolute;
  right: calc(100% + 8px);
  top: -0.65em;
  font-style: normal;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--color-text-subtle);
  white-space: nowrap;
}

.activity-cols {
  position: absolute;
  inset: 0 0 0 var(--axis-gutter);
  display: flex;
  align-items: flex-end;
  gap: 4px;
}

.activity-col {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  height: 100%;
  display: flex;
  align-items: flex-end;
  padding: 0;
  background: none;
  border: 0;
  border-radius: var(--radius-xs);
  cursor: pointer;
}

.activity-col:hover,
.activity-col:focus-visible { background: var(--color-surface-hover); }
.activity-col:focus-visible { outline: var(--focus-outline); outline-offset: 1px; }

.activity-stack {
  display: flex;
  flex-direction: column;
  width: 100%;
  /* An empty day still shows a hairline on the baseline, so "nothing happened"
     and "the chart is broken" do not look the same. */
  min-height: 2px;
  background: var(--color-border);
  border-radius: 0 0 2px 2px;
  gap: 2px;                 /* the surface gap that separates the two series */
}

.activity-seg { display: block; min-height: 3px; }
/* Rounded at the data end, square at the baseline. */
.activity-seg:first-child { border-radius: var(--radius-xs) var(--radius-xs) 0 0; }
.activity-seg-1 { background: var(--chart-1); }
.activity-seg-2 { background: var(--chart-2); }

.activity-tip {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  z-index: var(--z-sticky);
  display: flex;
  flex-direction: column;
  gap: 3px;
  width: max-content;
  max-width: 200px;
  padding: var(--spacing-sm) 10px;
  border-radius: var(--radius-sm);
  background: var(--gray-900);
  color: #fff;
  font-size: var(--font-size-xs);
  line-height: 1.45;
  text-align: left;
  box-shadow: var(--shadow-md);
  pointer-events: none;
}

.activity-tip b { font-weight: 700; }
.activity-tip span { display: inline-flex; align-items: center; gap: 6px; }
.activity-tip .chart-key { width: 8px; height: 8px; }

/* Keep the first and last tooltips inside the card, which clips its overflow. */
.activity-col:first-child .activity-tip { left: 0; transform: none; }
.activity-col:last-child .activity-tip { left: auto; right: 0; transform: none; }

.activity-axis {
  display: flex;
  gap: 4px;
  margin-top: var(--spacing-sm);
  /* Matches the plot's gutter so each label stays under its own column. */
  padding-left: 32px;
}

.activity-axis span {
  flex: 1 1 0;
  min-width: 0;
  text-align: center;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--color-text-subtle);
}

.activity-axis span.is-today {
  color: var(--color-text);
  font-weight: 600;
  font-variant-numeric: normal;
}

.activity-range {
  margin-top: var(--spacing-sm);
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
}

/* ---- Delivery breakdown -------------------------------------------------- */

.meter {
  display: flex;
  gap: 2px;                 /* surface gap, not a border, separates segments */
  height: 12px;
  border-radius: var(--radius-full);
  overflow: hidden;
  background: var(--color-border);
}

.meter-seg { display: block; min-width: 3px; }
.meter-seg-success { background: var(--color-success); }
.meter-seg-neutral { background: var(--gray-400); }
.meter-seg-danger { background: var(--color-danger); }

.delivery-rows {
  list-style: none;
  margin-top: var(--spacing-md);
  display: flex;
  flex-direction: column;
}

.delivery-row {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-sm);
  padding: 10px 0;
  border-bottom: 1px solid var(--color-border);
}

.delivery-row:last-child { border-bottom: 0; }
/* Colour is never the only signal: every row also carries an icon and a word. */
.delivery-row > svg { flex-shrink: 0; margin-top: 1px; }
.delivery-row-success > svg { color: var(--color-success); }
.delivery-row-neutral > svg { color: var(--color-text-subtle); }
.delivery-row-danger > svg { color: var(--color-danger); }

.delivery-row-label {
  flex: 1;
  min-width: 0;
  font-size: var(--font-size-sm);
}

.delivery-row-label em {
  display: block;
  font-style: normal;
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
  line-height: 1.5;
  margin-top: 2px;
}

.delivery-row-value {
  flex-shrink: 0;
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.delivery-row-value small {
  font-weight: 500;
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
}

.delivery-read {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-sm);
  margin-top: var(--spacing-md);
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--color-surface-sunken);
  font-size: var(--font-size-sm);
  line-height: 1.5;
  color: var(--color-text-muted);
}

.delivery-read > svg { flex-shrink: 0; margin-top: 2px; color: var(--color-success); }
.delivery-read strong { color: var(--color-text); }

/* ---- Module cards -------------------------------------------------------- */

/* 320px keeps four figures on two comfortable rows; below that the grid drops
   to one column rather than squeezing a label onto three lines. */
.module-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: var(--spacing-lg);
}

.module-card {
  display: flex;
  flex-direction: column;
  padding: var(--spacing-lg);
}

.module-card.is-alert { border-color: var(--color-warning); }

.module-head {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  margin-bottom: var(--spacing-md);
}

.module-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  border-radius: var(--radius-sm);
  background: var(--color-primary-soft);
  color: var(--color-primary);
}

.module-title {
  flex: 1;
  min-width: 0;
  font-family: var(--font-display);
  font-size: var(--font-size-md);
  font-weight: 700;
}

.module-link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  flex-shrink: 0;
  font-size: var(--font-size-sm);
  font-weight: 600;
  white-space: nowrap;
  /* 44px tap target without pushing the header taller. */
  padding: 12px 4px;
  margin: -12px -4px;
}

.module-metrics {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--spacing-sm) var(--spacing-md);
  margin-bottom: var(--spacing-md);
}

.module-metric {
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--color-surface-sunken);
  border-left: 2px solid var(--color-border-strong);
}

.module-metric dt {
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
  line-height: 1.35;
}

.module-metric dd {
  font-family: var(--font-display);
  font-size: var(--font-size-xl);
  font-weight: 700;
  line-height: 1.2;
  margin-top: 2px;
}

.module-metric.is-good { border-left-color: var(--color-success); }
.module-metric.is-bad { border-left-color: var(--color-danger); }
.module-metric.is-quiet { border-left-color: var(--color-text-subtle); }

/* Label/value pairs where the value is a word or a badge, not a number. */
.module-facts { margin-bottom: var(--spacing-md); }

.module-facts > div {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-md);
  padding: 10px 0;
  border-bottom: 1px solid var(--color-border);
}

.module-facts > div:last-child { border-bottom: 0; }
.module-facts dt { font-size: var(--font-size-sm); color: var(--color-text-muted); }
.module-facts dd { font-size: var(--font-size-sm); font-weight: 600; text-align: right; }

/* One row per WhatsApp number (multi-number, MN.8). A list rather than more
   label/value pairs: with three numbers the same three labels would repeat nine
   times, and what the owner is scanning for is the one row that is not healthy. */
.module-numbers {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
  margin: 0 0 var(--spacing-md);
  padding: 0;
  list-style: none;
}

.module-numbers > li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-sm);
  padding-bottom: var(--spacing-sm);
  border-bottom: 1px solid var(--color-border);
}

.module-numbers > li:last-child { border-bottom: 0; padding-bottom: 0; }

.module-number-name {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-sm);
  min-width: 0;
  font-size: var(--font-size-sm);
  font-weight: 600;
  overflow-wrap: anywhere;
}

.module-number-meta {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--spacing-sm);
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

.module-note {
  margin-top: auto;
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
  line-height: 1.55;
}

.module-alert {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-sm);
  margin-top: auto;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--color-warning-soft);
  color: var(--color-warning-text);
  font-size: var(--font-size-xs);
  line-height: 1.55;
}

.module-alert > svg { flex-shrink: 0; margin-top: 1px; color: var(--color-warning); }

/* ---- Responsive ---------------------------------------------------------- */

@media (max-width: 1024px) {
  .dash-split { grid-template-columns: 1fr; }
}

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

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

  .dash-warning { flex-wrap: wrap; }
  .dash-warning .btn { width: 100%; }

  /* Fourteen labels will not fit on a phone; every other one still reads as a
     scale, and the tooltip and the table carry the exact days. "Today" is
     wider than its slot, so its neighbour goes too — otherwise the two words
     sit on top of each other. */
  .activity-axis span:nth-child(even):not(.is-today),
  .activity-axis span:nth-last-child(2) { visibility: hidden; }

  .module-grid { grid-template-columns: 1fr; }
}

/* --- "Set a password" offer --------------------------------------------- */

/* Deliberately quieter than .dash-warning: a neutral surface and the brand
   blue, never the warning amber. This is an offer, and styling it as an alert
   would tell a tenant something is wrong when nothing is. */
.password-prompt {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-md);
  padding: var(--spacing-md) var(--spacing-lg);
  margin-bottom: var(--spacing-lg);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}

.password-prompt__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-full);
  background: var(--color-primary-soft);
  color: var(--color-primary);
}

.password-prompt__body {
  flex: 1 1 260px;
}

.password-prompt__title {
  margin: 0 0 2px;
  font-size: var(--font-size-md);
  font-weight: 600;
  color: var(--color-text);
}

.password-prompt__text {
  margin: 0;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

.password-prompt__actions {
  display: flex;
  align-items: center;
  gap: var(--spacing-md);
  flex: none;
}

/* Stacked on a phone, with the actions full width — the two-column row puts
   "No thanks" off the edge at 375px. */
@media (max-width: 640px) {
  .password-prompt {
    flex-wrap: wrap;
  }

  .password-prompt__actions {
    width: 100%;
    justify-content: flex-start;
  }
}

/* The checklist's right-hand cluster: the count, and the way into the guided
   wizard. Wraps under the heading on a phone rather than squeezing the title
   to a couple of words. */
.setup-head-aside {
  display: flex;
  align-items: center;
  gap: var(--spacing-md);
  flex-wrap: wrap;
}

.dash-workspaces {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: 20px;
}

.dash-workspace {
  display: flex;
  flex-direction: column;
  gap: 20px;
  padding: 24px;
}

.dash-workspace h3 { margin: 0 0 6px; }
.dash-workspace p { margin: 0; }
.dash-workspace .btn { margin-top: auto; white-space: normal; }

.dash-workspace-metrics {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
  margin: 0;
}

.dash-workspace-metrics dt { color: var(--text-muted); font-size: 13px; }
.dash-workspace-metrics dd { margin: 4px 0 0; font-size: 24px; font-weight: 700; }

@media (max-width: 600px) { .stat-grid > :last-child:nth-child(odd) { grid-column: 1 / -1; } }
.overview-summary { display: grid; gap: 20px; }
.overview-setup { border: 1px solid var(--color-border); border-radius: 12px; background: var(--color-surface); margin-bottom: 18px; }
.overview-setup > summary { cursor: pointer; padding: 14px 18px; font-size: 13px; font-weight: 600; }
.overview-setup > summary > span { float: right; color: var(--color-primary); font-size: 12px; }
.overview-setup .setup-checklist { margin: 0; }
.overview-kpis { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; }
.overview-kpi { display: flex; align-items: flex-start; gap: 14px; padding: 22px 18px; }
.overview-kpi-icon { display: flex; align-items: center; justify-content: center; width: 48px; height: 48px; flex-shrink: 0; background: #eaf2ff; color: #2164f3; border-radius: 50%; }
.overview-kpi.is-danger .overview-kpi-icon { background: #ffebed; color: #f33d4c; }
.overview-kpi h2 { font-size: 13px; margin: 0 0 12px; font-weight: 600; }
.overview-kpi strong { display: block; font-size: 28px; font-weight: 750; line-height: 1.2; }
.overview-kpi p { font-size: 12px; color: var(--color-text-muted); margin: 10px 0 0; }
.overview-charts { display: grid; grid-template-columns: minmax(0, 1.8fr) minmax(280px, 1fr); gap: 20px; }
.overview-summary .card-header { font-size: 16px; align-items: flex-start; flex-wrap: wrap; gap: 8px; }
.overview-summary .card-header-hint { font-size: 12px; font-weight: 400; }
.overview-summary .activity-plot { height: 200px; }
.overview-lower { display: grid; grid-template-columns: 1fr 1fr 1.2fr; gap: 20px; }
.overview-workspace-ranking { display: grid; gap: 0; }
.overview-workspace-ranking > a { display: flex; align-items: center; gap: 10px; color: var(--color-text); border-bottom: 1px solid var(--color-border); padding: 12px 0; font-size: 13px; text-decoration: none; }
.overview-workspace-ranking > a:last-child { border-bottom: 0; }
.overview-workspace-ranking > a > b { margin-left: auto; font-variant-numeric: tabular-nums; }
.overview-workspace-ranking small, .overview-comparison small { display: block; color: var(--color-text-muted); font-size: 11px; margin-top: 4px; }
.overview-workspace-avatar, .overview-team-avatar { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; width: 34px; height: 34px; color: #fff; border-radius: 50%; }
.overview-team-avatar { width: 27px; height: 27px; background: #e7f0ff; color: #2862c9; margin-right: 8px; font-size: 12px; }
.overview-status { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 20px; }
.overview-status-ring { display: grid; place-items: center; width: 144px; height: 144px; border-radius: 50%; background: conic-gradient(#3176ff 0 var(--open-share), #10b981 var(--open-share) 100%); }
.overview-status-ring > span { display: flex; flex-direction: column; align-items: center; justify-content: center; width: 112px; height: 112px; border-radius: 50%; background: var(--color-surface); }
.overview-status-ring strong { font-size: 23px; }
.overview-status-ring small { font-size: 11px; color: var(--color-text-muted); }
.overview-status dl { margin: 0; min-width: 120px; flex: 1; font-size: 12px; }
.overview-status dl > div { display: flex; justify-content: space-between; gap: 12px; padding: 8px 0; }
.overview-status dt { display: flex; align-items: center; gap: 6px; }
.overview-status dd { margin: 0; font-weight: 600; }
.overview-status dt i { width: 9px; height: 9px; border-radius: 50%; background: #3176ff; }
.overview-status dt .is-resolved { background: #10b981; }
.overview-status > a { width: 100%; font-size: 12px; }
.overview-team table, .overview-comparison table { width: 100%; border-collapse: collapse; font-size: 12px; }
.overview-team th, .overview-comparison th { background: var(--color-surface-sunken); color: var(--color-text-muted); font-size: 10px; text-transform: uppercase; font-weight: 600; text-align: left; }
.overview-team th, .overview-team td, .overview-comparison th, .overview-comparison td { padding: 12px 10px; border-bottom: 1px solid var(--color-border); }
.overview-team td:last-child { text-align: right; font-variant-numeric: tabular-nums; }
.overview-comparison { overflow-x: auto; }
.overview-comparison td:not(:first-child) { font-variant-numeric: tabular-nums; }
.overview-summary > .section { margin: 0; }
.overview-chat-details { padding: 16px 20px; }
.overview-chat-details summary { cursor: pointer; font-size: 14px; font-weight: 600; }
.overview-chat-details h3 { font-size: 14px; }
.overview-chat-details dl { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; }
.overview-chat-details dt { font-size: 12px; color: var(--color-text-muted); }
.overview-chat-details dd { margin: 6px 0 0; font-size: 20px; font-weight: 600; }
@media (max-width: 1250px) {
  .overview-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .overview-lower { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .overview-lower > :last-child { grid-column: 1 / -1; }
}
@media (max-width: 850px) {
  .overview-chat-details dl { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .overview-charts, .overview-lower { grid-template-columns: minmax(0, 1fr); }
  .overview-kpi { padding: 16px 12px; gap: 9px; }
  .overview-kpi-icon { width: 34px; height: 34px; }
  .overview-kpi-icon svg { width: 20px; }
  .overview-kpi h2 { font-size: 12px; }
  .overview-kpi strong { font-size: 24px; }
  .overview-comparison table, .overview-comparison tbody, .overview-comparison tr, .overview-comparison td { display: block; }
  .overview-comparison thead { display: none; }
  .overview-comparison tr { padding: 12px; border-bottom: 1px solid var(--color-border); }
  .overview-comparison td { display: flex; justify-content: space-between; gap: 16px; padding: 7px 0; border: 0; }
  .overview-comparison td::before { content: attr(data-label); color: var(--color-text-muted); }
  .overview-comparison td:first-child { font-size: 14px; margin-bottom: 8px; }
  .overview-comparison td:first-child::before { display: none; }
}
/* 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%;
}

/* --- Editable name row (Settings → General) ---
   Field and Save on one line, the button bottom-aligned with the input rather
   than with the label above it. Below 480px they stack, because a 40px-wide
   input beside a button is not a form anyone can type in. */
.name-field {
  display: flex;
  align-items: flex-end;
  gap: var(--spacing-sm);
}

.name-field > .form-group {
  flex: 1 1 auto;
  min-width: 0;
  /* The row owns the spacing under it; the field's own margin would push the
     button out of line with the input it belongs to. */
  margin-bottom: 0;
}

.name-field > .btn {
  flex: 0 0 auto;
  margin-bottom: 2px;
}

/* Reserves its line whether or not there is anything to say, so confirming a
   save never nudges the rest of the card downwards. */
.name-field__status {
  min-height: 1.25rem;
  margin: var(--spacing-2xs) 0 var(--spacing-md);
  font-size: var(--font-size-sm);
  color: var(--color-success);
}

/* Business type and industry: the selects stack, the Save sits under them. */
.business-profile-settings .form-helper {
  display: block;
  margin-bottom: var(--spacing-sm);
}

.business-profile-actions .name-field__status {
  margin-bottom: var(--spacing-md);
}

@media (max-width: 480px) {
  .name-field {
    flex-direction: column;
    align-items: stretch;
  }

  .name-field > .btn {
    margin-bottom: 0;
  }
}

/* --- 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;
}

/* --- "Replying from <number>" (multi-number, MN) -----------------------
   A statement, never a picker: a reply always leaves from the number the
   customer wrote to. Sits above the composer row, in the same muted 12px as
   .composer-hint beside it, so two lines can stack without either shouting. */
.composer-from {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0;
  padding: 4px var(--spacing-md) 0;
  font-size: 12px;
  color: var(--color-text-muted);
}

/* --- Teammate number access (multi-number, MN) -------------------------
   Wraps rather than scrolls, and each row keeps a full-height 44px target so
   the checkbox is reachable on a phone. Two-per-row on a wide modal, one on a
   narrow one — the label is a tenant-typed name and must not be clipped. */
.team-number-checks {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-xs) var(--spacing-md);
  margin-bottom: var(--spacing-xs);
}

.team-number-checks > .form-check {
  flex: 1 1 200px;
  min-width: 0;
  min-height: var(--tap-target);
}

/* The access list is prose, not a code value: let it wrap in the cell rather
   than stretch the roster into a horizontal scroll. */
.team-numbers-cell {
  max-width: 220px;
  overflow-wrap: anywhere;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}
/* 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. */

.customer-summary { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 12px; margin-bottom: 20px; }
.customer-summary-card { padding: 16px; }
.customer-summary-card > div { display: flex; align-items: center; gap: 10px; font-size: 12px; font-weight: 600; min-height: 40px; }
.customer-summary-card > strong { display: block; margin: 12px 0 4px; font-size: 27px; line-height: 1.2; }
.customer-summary-card > small { color: var(--color-text-muted); font-size: 11px; }
.customer-summary-icon { display: grid; place-items: center; flex-shrink: 0; width: 36px; height: 36px; border-radius: 10px; color: #334155; background: #edf2f7; }
.customer-summary-1 .customer-summary-icon { color: #079b65; background: #dcf9ec; }
.customer-summary-2 .customer-summary-icon { color: #7c3aed; background: #f1e5ff; }
.customer-summary-3 .customer-summary-icon { color: #2563eb; background: #e6efff; }
.customer-summary-4 .customer-summary-icon { color: #e14566; background: #ffe8ee; }
.customers-page .contacts-toolbar { padding: 16px; align-items: center; }
.customers-page .contacts-toolbar input[type='search'] { width: auto; min-width: 0; }
.customers-page .contacts-toolbar select { width: 240px; }
:root[data-look="v2"] .customers-page .wz-drawer { background: var(--color-surface); }
:root[data-look="v2"] .customers-page .page-header { align-items: flex-start; }
.customers-page .table { min-width: 900px; }
.customer-name-cell { display: flex; align-items: center; gap: 10px; min-width: 180px; }
.customer-avatar { display: inline-grid; place-items: center; width: 38px; height: 38px; border-radius: 50%; background: #e9e2ff; color: #6d36df; font-weight: 700; flex-shrink: 0; }
.customers-page tr:nth-child(3n+2) .customer-avatar { color: #cf3b59; background: #ffe3eb; }
.customers-page tr:nth-child(3n+3) .customer-avatar { color: #1d63c3; background: #dfecff; }
.customers-page .table-actions { flex-wrap: nowrap; }
.customer-detail-profile { text-align: center; padding: 8px 0 24px; }
.customer-detail-profile .customer-avatar { width: 72px; height: 72px; font-size: 25px; }
.customer-detail-profile h2 { margin: 12px 0 6px; font-size: 19px; }
.customer-detail-profile p { margin: 0 0 10px; }
.customer-detail-section { border-top: 1px solid var(--color-border); padding: 20px 0; }
.customer-detail-section h3 { margin: 0 0 16px; font-size: 14px; }
.customer-detail-heading { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.customer-detail-fields { display: grid; grid-template-columns: 110px minmax(0, 1fr); gap: 14px; margin: 0; font-size: 13px; }
.customer-detail-field { display: contents; }
.customer-detail-fields dt { color: var(--color-text-muted); }
.customer-detail-fields dd { margin: 0; overflow-wrap: anywhere; }
@media (max-width: 1100px) {
  .customer-summary { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 767px) {
  .customer-summary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .customer-summary-card { padding: 12px; }
  .customer-summary-card:last-child { grid-column: 1 / -1; }
  .customers-page .table { min-width: 0; }
  .customers-page .contacts-toolbar select { width: 100%; }
}
.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 row that DID import but lost something. Amber rather than red because the
   contact is in the book — and never amber alone: the block below it carries an
   icon and the word "warning", since colour cannot be the only signal. */
.import-stat-warn .import-stat-value {
  color: var(--color-warning);
}

.import-warnings {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
  margin-top: var(--spacing-md);
}

/* .import-warning is shared with the mapping step, where it sits above a
   control; here it heads a block, so it aligns to the top of a wrapped line
   instead of centring the icon against two lines of text. */
.import-warnings .import-warning {
  align-items: flex-start;
  margin-bottom: 0;
}

.import-warnings .import-warning svg {
  flex: 0 0 auto;
  margin-top: 2px;
}

/* 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; }

/* --- Quality rating (@C4) ---
   WhatsApp's verdict on a template, shown under the status pill.

   Deliberately NOT a third pill: two pills already sit in that row, and a
   third would make the alarming case (At risk) read as one more label rather
   than the one thing to act on. A dot plus the word carries the meaning —
   colour is never the only signal — and every colour here is a status token,
   never --color-whatsapp or --color-brand-green, which mean "connected" and
   "us" in this product. */
/* Stacked under the status pill, not beside it: the Status column would
   otherwise be sized by the widest "Approved  Quality: Needs watching" pair on
   the page, and the Name cell is already two lines tall so the second line
   costs no row height.
   ⚠️ The stacking is done with a block-level flex on the CHILD. Making the
   `<td>` itself `display: flex` drops it out of `table-cell` and the cell stops
   sharing the row's height — the pills then float free of their own row
   borders, which is what it looked like on the first try. */
.tpl-quality {
  display: flex;
  width: fit-content;
  align-items: center;
  gap: 5px;
  margin-top: 4px;
  font-size: var(--font-size-xs);
  font-weight: 600;
  line-height: 1.4;
  white-space: nowrap;
}
.tpl-quality-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
  flex-shrink: 0;
}
.tpl-quality.is-good { color: var(--color-success-text); }
.tpl-quality.is-watch { color: var(--color-warning-text); }
.tpl-quality.is-risk { color: var(--color-danger-text); }
.tpl-quality.is-unknown { color: var(--color-text-muted); }

.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); }
}

/* Coexistence origin tags on a message bubble (§12 / Coexistence).
   Same shape as .msg-template-tag so a thread reads as one system; the colour
   differs only to separate "a human on their phone" from "before your time",
   and each tag carries an icon and words so colour is never load-bearing. */
.msg-origin-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  max-width: 100%;
  min-width: 0;
  white-space: nowrap;
  font-size: 11px;
  font-weight: 600;
  border-radius: var(--radius-full);
  padding: 1px 8px;
  margin-bottom: 4px;
}

/* Both origin tags are NEUTRAL, and deliberately so.
   The first attempt painted "From the app" green, which failed twice: the
   outbound bubble is itself green (#d9fdd3), so a #dcfce7 pill on it was
   invisible — and green in this product means status, which provenance is not.
   A surface pill with a border reads on the green outbound bubble and the white
   inbound one alike, and the two tags are told apart by icon and words rather
   than by colour, which is what makes them survive greyscale too. */
.msg-origin-tag {
  color: var(--color-text-muted, var(--gray-600));
  /* A tinted fill, not white. White read fine on the green outbound bubble and
     vanished on the white inbound one — the tag has to sit on BOTH, and only a
     browser test over an inbound bubble caught it. Grey separates from white
     and from green alike. */
  background: var(--gray-100, #f3f4f6);
  border: 1px solid var(--color-border);
}

.tpl-library-drafts {
  padding: var(--spacing-md);
  margin-bottom: var(--spacing-md);
}

.tpl-library-drafts summary { cursor: pointer; min-height: 28px; font-weight: 600; font-size: 14px; }
.tpl-library-drafts[open] summary { margin-bottom: 12px; }
.tpl-library-drafts > p { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.tpl-shared-notice { font-size: 13px; margin-bottom: 16px; padding: 10px 14px; }
.tpl-toolbar { display: flex; gap: 12px; align-items: center; }
.tpl-toolbar input { flex: 1 1 260px; width: auto; }
.tpl-toolbar select { flex: 0 1 200px; width: auto; }
.tpl-row-actions { white-space: nowrap; }
.tpl-row-actions > .btn { vertical-align: middle; }
.tpl-table td:first-child { min-width: 180px; }
@media (max-width: 600px) { .tpl-toolbar select { flex: 1 1 180px; } .tpl-table td:first-child { min-width: 0; } }

/* Shared starter catalogue: wording is public; customer copies remain private. */
.tpl-catalogue-tabs { display: flex; flex-wrap: wrap; gap: 10px; margin: 22px 0; }
.tpl-catalogue-layout { display: grid; grid-template-columns: 180px minmax(0, 1fr); gap: 18px; margin-top: 20px; }
.tpl-catalogue-main { min-width: 0; }
.tpl-catalogue-categories { align-self: start; padding: 12px; }
.tpl-catalogue-categories h3 { font-size: 14px; margin: 4px 6px 12px; }
.tpl-catalogue-categories button { display: flex; width: 100%; align-items: center; justify-content: space-between; gap: 8px; text-align: left; padding: 10px 8px; border: 0; background: transparent; border-radius: 7px; font-size: 12px; color: var(--color-text-muted); cursor: pointer; }
.tpl-catalogue-categories button.is-active { background: var(--color-primary-soft); color: var(--color-primary); font-weight: 600; }
.tpl-catalogue-categories button > span:last-child { flex-shrink: 0; padding: 2px 5px; background: var(--color-surface-sunken); border-radius: 4px; }
.tpl-catalogue-main .tpl-catalogue-filters { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr); margin-top: 0; }
.message-templates-page .tpl-catalogue-intro { padding: 18px 22px; background: var(--color-primary-soft); }
.message-templates-page .tpl-catalogue-intro h2 { font-size: 19px; margin: 4px 0; }
.message-templates-page .tpl-catalogue-intro p { max-width: none; font-size: 14px; }
.message-templates-page .tpl-catalogue-card { padding: 14px; }
.message-templates-page .tpl-catalogue-card h3 { font-size: 15px; }
.message-templates-page .tpl-catalogue-body { font-size: 13px; }
.message-templates-page .tpl-catalogue-actions { flex-wrap: nowrap; gap: 6px; }
.message-templates-page .tpl-catalogue-actions .btn { font-size: 12px; padding: 8px 10px; }
.tpl-summary { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 12px; margin: 18px 0; }
.tpl-summary-card { display: flex; align-items: center; gap: 12px; padding: 16px; }
.tpl-summary-card > span { display: inline-flex; color: var(--color-primary); }
.tpl-summary-card strong { font-size: 21px; }
.tpl-summary-card p { font-size: 12px; color: var(--color-text-muted); margin: 4px 0 0; }
.message-templates-page .tpl-preview-text { -webkit-line-clamp: 1; }
.message-templates-page .tpl-name { text-align: left; }
.tpl-detail-preview dl { display: flex; flex-wrap: wrap; gap: 10px 16px; margin: 0 0 18px; font-size: 13px; }
.tpl-detail-preview dt { color: var(--color-text-muted); }
.tpl-detail-preview dd { margin: 0 12px 0 0; }
.tpl-category > .icon { color: var(--color-primary); margin-bottom: 14px; }
.tpl-step .tpl-note { background: var(--color-primary-soft); color: var(--color-primary); padding: 14px 16px; border-radius: 8px; }
.tpl-builder-preview { padding: 20px; border: 1px solid var(--color-border); border-radius: 12px; background: var(--color-surface); }
.tpl-builder-preview .tpl-preview-canvas { min-height: 430px; }
.tpl-builder-preview .tpl-preview-empty { background: var(--color-surface); border-radius: 10px; padding: 20px; box-shadow: var(--shadow-sm); }
.saved-content-tabs { display: flex; flex-wrap: wrap; gap: 12px; margin: 24px 0 18px; }
.saved-content-toolbar { display: grid; grid-template-columns: minmax(200px, 2fr) repeat(3, minmax(0, 1fr)); gap: 12px; margin-bottom: 20px; }
.saved-content-wording { margin: 6px 0 0; max-width: 38ch; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--color-text-muted); font-size: 13px; }
.saved-content-type { display: inline-flex; align-items: center; gap: 8px; color: var(--color-primary); background: var(--color-primary-soft); border-radius: 8px; padding: 7px 10px; font-size: 13px; }
.saved-content-table td:last-child { white-space: nowrap; }
.saved-content-pagination, .saved-content-pagination > div { display: flex; align-items: center; gap: 12px; }
.saved-content-pagination { justify-content: space-between; margin-top: 20px; font-size: 13px; color: var(--color-text-muted); }
@media (min-width: 1400px) { .message-templates-page .tpl-catalogue-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; } }
@media (max-width: 1000px) {
  .tpl-summary { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .saved-content-toolbar { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 700px) {
  .tpl-builder-preview { order: 0; }
  .tpl-builder-preview .tpl-preview-canvas { min-height: 280px; }
  .tpl-catalogue-layout { grid-template-columns: 1fr; }
  .tpl-catalogue-categories { display: flex; gap: 6px; overflow-x: auto; }
  .tpl-catalogue-categories h3 { display: none; }
  .tpl-catalogue-categories button { width: auto; flex-shrink: 0; max-width: 200px; }
  .tpl-catalogue-main .tpl-catalogue-filters { grid-template-columns: 1fr; }
  .tpl-summary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .saved-content-toolbar { grid-template-columns: 1fr; }
  .saved-content-wording { max-width: 100%; }
  .saved-content-pagination { flex-direction: column; align-items: flex-start; }
  .saved-content-tabs { gap: 8px; }
  .saved-content-tabs .btn { font-size: 12px; }
}
.tpl-catalogue-intro { display: flex; align-items: center; justify-content: space-between; gap: 24px; padding: 28px; border: 1px solid #cddcf5; border-radius: 16px; background: linear-gradient(120deg, #eef4ff, #f0faf7); margin-bottom: 14px; }
.tpl-catalogue-intro h2 { margin: 8px 0; font-size: 26px; }
.tpl-catalogue-intro p { max-width: 640px; margin: 0; line-height: 1.6; }
.tpl-catalogue-eyebrow { font-size: 12px; font-weight: 700; letter-spacing: .08em; color: #2455a4; }
.tpl-catalogue-filters { display: grid; grid-template-columns: 2fr 1fr 1.4fr 1fr; gap: 14px; margin-top: 24px; }
.tpl-catalogue-filters label { display: grid; gap: 7px; font-size: 13px; font-weight: 600; min-width: 0; }
.tpl-catalogue-count { display: flex; justify-content: space-between; align-items: center; margin: 14px 0; }
.tpl-catalogue-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; }
.tpl-catalogue-card { padding: 22px; display: flex; flex-direction: column; min-width: 0; }
.tpl-catalogue-tags { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-size: 12px; }
.tpl-catalogue-industry { font-size: 12px; color: #64748b; margin: 18px 0 6px; }
.tpl-catalogue-card h3 { font-size: 18px; line-height: 1.4; margin: 0 0 12px; }
.tpl-catalogue-body { font-size: 14px; line-height: 1.65; margin: 0 0 16px; color: #475569; display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }
.tpl-catalogue-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: auto; padding-top: 16px; }
.tpl-catalogue-message { padding: 20px; margin: 20px 0; background: #eff8f1; border: 1px solid #cfe5d5; border-radius: 14px; line-height: 1.7; overflow-wrap: anywhere; }
.tpl-catalogue-media { background: #dfebe3; padding: 30px 10px; text-align: center; border-radius: 8px; color: #466354; }
.tpl-catalogue-preview-buttons { display: grid; gap: 8px; border-top: 1px solid #cfe5d5; padding-top: 14px; text-align: center; color: #2455a4; }
.tpl-catalogue-empty { padding: 32px; text-align: center; }
@media (max-width: 1100px) { .tpl-catalogue-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } .tpl-catalogue-filters { grid-template-columns: 1fr 1fr; } }
@media (max-width: 600px) { .tpl-catalogue-grid, .tpl-catalogue-filters { grid-template-columns: 1fr; } .tpl-catalogue-intro { display: block; padding: 20px; } .tpl-catalogue-intro .badge { display: inline-block; margin-top: 16px; } }
/* 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); }
.modal-container:has(.bc-campaign-builder) { max-width: 1180px; }
.bc-campaign-builder .bc-edit-fields { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); gap: 24px; }
.bc-edit-main, .bc-preview-side { display: flex; flex-direction: column; gap: 20px; min-width: 0; }
.bc-preview-side { align-self: start; }
.bc-campaign-builder .bc-who-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.bc-campaign-builder .bc-who-card:last-child { grid-column: 1 / -1; }
.bc-variable-panel { display: flex; flex-direction: column; gap: 14px; padding: 20px; border: 1px solid var(--color-border); border-radius: 10px; }
.bc-variable-panel h3 { margin: 0; font-size: 16px; }
@media (max-width: 800px) {
  .bc-campaign-builder .bc-edit-fields { grid-template-columns: 1fr; }
}
@media (max-width: 480px) {
  .bc-campaign-builder .bc-who-grid { grid-template-columns: 1fr; }
}
/* 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); }

/* Five outcomes, not four: skipped is its own column. auto-fit keeps them on
   one row on desktop and wraps to two on a phone rather than crushing the
   numbers. */
.bc-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(92px, 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); }
/* Excluded on purpose — never the danger red. A skipped recipient is the
   compliance rules working, not a failure the tenant has to chase. */
.bc-stat-n.bc-muted { color: var(--color-text-muted); }
.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); }

/* ---------------------------------------------------------------------------
 * Phase 8.1 — "Who should get this?"
 *
 * A real radio group styled as cards. The input stays in the DOM (only visually
 * hidden) rather than being replaced by divs with onClick, so arrow-key
 * navigation, the checked state and the group name all work without being
 * re-implemented — and :has() drives the selected styling off the actual state
 * rather than a parallel React copy of it.
 * ------------------------------------------------------------------------- */
.bc-audience {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
}

.bc-who {
  border: 0;
  padding: 0;
  margin: 0;
}

.bc-who-grid {
  display: grid;
  /* Wraps from 3 columns to 2 to 1 on its own — no breakpoint needed. */
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: var(--spacing-sm);
  margin-top: var(--spacing-xs);
}

.bc-who-card {
  position: relative;
  display: block;
  cursor: pointer;
}

/* Hidden from sight, not from the keyboard or the accessibility tree.
   Clipped to 1px rather than sized 0×0: a zero-size radio is treated as not
   rendered, and the browser then skips it during arrow-key navigation of the
   group — the selection simply refuses to move. Verified in the browser. */
.bc-who-input {
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
  clip-path: inset(50%);
  pointer-events: none;
}

.bc-who-body {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas:
    'icon label'
    'hint hint';
  align-items: center;
  gap: var(--spacing-xs) var(--spacing-sm);
  height: 100%;
  padding: var(--spacing-sm) var(--spacing-md);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  transition: border-color 120ms ease, background-color 120ms ease;
}

.bc-who-card:hover .bc-who-body {
  border-color: var(--color-primary);
}

.bc-who-input:checked + .bc-who-body {
  border-color: var(--color-primary);
  background: color-mix(in srgb, var(--color-primary) 8%, transparent);
  /* A second ring rather than a thicker border: a border-width change would
     move the card's contents by a pixel on every selection. */
  box-shadow: inset 0 0 0 1px var(--color-primary);
}

/* Keyboard focus must be visible even though the input itself is not. */
.bc-who-input:focus-visible + .bc-who-body {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

.bc-who-icon {
  grid-area: icon;
  color: var(--color-primary);
}

.bc-who-label {
  grid-area: label;
  font-weight: 600;
  font-size: var(--font-size-sm);
}

.bc-who-hint {
  grid-area: hint;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* --- CSV audience: file summary + column mapping --- */
.bc-csv {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
}

.bc-csv-summary {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* Fixed layout so the three columns keep the widths below instead of being
   sized by their content — the target dropdown is the one column that must
   never truncate, since it is the answer the tenant is here to check. */
.bc-csv-table {
  table-layout: fixed;
  width: 100%;
}

.bc-csv-table th,
.bc-csv-table td {
  vertical-align: middle;
}

.bc-csv-header {
  width: 28%;
  font-weight: 600;
  /* A pasted header can be arbitrarily long; wrap rather than widen the table. */
  overflow-wrap: anywhere;
}

.bc-csv-sample {
  width: 20%;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  overflow-wrap: anywhere;
}

.bc-csv-target {
  width: 52%;
}

/* The select is the widest thing in its cell and must be allowed to be. A
   native select silently truncates its own label, so every pixel of default
   padding here is a pixel of "Message {{coupon" instead of "{{coupon}}". */
.bc-csv-target .form-control {
  width: 100%;
  min-width: 0;
  padding-inline: var(--spacing-xs);
}

.bc-csv-declare {
  align-items: flex-start;
}

.bc-file-chosen {
  color: var(--color-text);
}

@media (prefers-reduced-motion: reduce) {
  .bc-who-body {
    transition: none;
  }
}

/* --- Retrying the failed recipients of a finished broadcast --- */

.bc-retry {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-md);
  flex-wrap: wrap;
  margin-top: var(--spacing-md);
  padding: var(--spacing-sm) var(--spacing-md);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--color-danger);
  border-radius: var(--radius-md);
  background: var(--color-surface-alt, var(--color-surface));
}

.bc-retry-text {
  font-size: var(--font-size-sm);
  color: var(--color-text);
  min-width: 0;
}

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

.bc-retry-error {
  margin-top: var(--spacing-sm);
  font-size: var(--font-size-sm);
  color: var(--color-danger);
}

/* Shared status vocabulary for the unified Campaigns screen (Phase 8.2 IA).
   Three lifecycles are shown in one column, so they resolve to one set of
   words server-side (App\Support\CampaignKind) and one set of colours here.
   The old per-broadcast names above stay for the delivery report, which still
   speaks the raw broadcast lifecycle. */
.bc-badge.is-live { background: var(--color-warning-soft); color: var(--color-warning-text); }
.bc-badge.is-done { background: var(--color-success-soft); color: var(--color-success-text); }
.bc-badge.is-stopped { background: var(--color-danger-soft); color: var(--color-danger-text); }

/* ---------------------------------------------------------------------------
   Broadcast delivery report — who actually received a broadcast.

   ⚠️ THE STATE COLOURS ARE THE POINT OF THIS SCREEN. "No receipt" must never
   read as a success: Meta accepted the message and has confirmed nothing, and
   colouring that green is exactly the mistake the page was built to correct.
   Green is reserved for delivered and read; an unconfirmed send is amber and an
   accepted-then-bounced one is red. Every badge also carries its own word, so
   the meaning survives without colour (WCAG 1.4.1).
--------------------------------------------------------------------------- */

.report-back {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-bottom: 8px;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  text-decoration: none;
}

.report-back:hover { color: var(--color-primary); }

.report-stats {
  display: grid;
  /* Wraps down to two tiles on a phone rather than shrinking the figures. */
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 12px;
  margin-bottom: 16px;
}

.report-stat {
  padding: 14px 16px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-left: 3px solid var(--color-border-strong);
  border-radius: var(--radius-md);
}

.report-stat.is-good { border-left-color: var(--color-success); }
.report-stat.is-warn { border-left-color: var(--color-warning); }
.report-stat.is-bad { border-left-color: var(--color-danger); }

.report-stat-value {
  font-size: var(--font-size-2xl);
  font-weight: 700;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  color: var(--color-text);
}

.report-stat-label {
  margin-top: 2px;
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--color-text);
}

.report-stat-hint {
  margin-top: 2px;
  font-size: var(--font-size-xs);
  color: var(--color-text-subtle);
}

.report-note {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin-bottom: 16px;
  padding: 12px 14px;
  background: var(--color-warning-soft);
  border: 1px solid var(--color-warning);
  border-radius: var(--radius-md);
  color: var(--color-warning-text);
  font-size: var(--font-size-sm);
  line-height: 1.5;
}

.report-note svg { flex: none; margin-top: 2px; }

.report-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--color-border);
}

/* Numbers are scanned down the column for the odd one out, so they have to
   line up — proportional figures make a wrong country code hard to spot. */
.report-phone {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: var(--color-text-muted);
}

.report-detail {
  max-width: 320px;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  /* Meta's reasons are sentences, not labels: wrap them rather than truncate,
     since the reason is the thing the admin came here to read. */
  overflow-wrap: anywhere;
}

.report-action-col { white-space: nowrap; }

.report-more {
  display: flex;
  justify-content: center;
  padding: 12px;
}

.delivery-badge {
  display: inline-block;
  padding: 3px 10px;
  border-radius: var(--radius-full);
  font-size: var(--font-size-xs);
  font-weight: 600;
  white-space: nowrap;
  border: 1px solid transparent;
}

.delivery-badge.is-read {
  background: var(--color-success-soft);
  color: var(--color-success-text);
  border-color: var(--color-success);
}

.delivery-badge.is-delivered {
  background: var(--color-whatsapp-soft);
  color: var(--color-whatsapp-text);
  border-color: var(--color-whatsapp-deep);
}

/* Amber, not green — accepted is not arrived. */
.delivery-badge.is-sent {
  background: var(--color-warning-soft);
  color: var(--color-warning-text);
  border-color: var(--color-warning);
}

.delivery-badge.is-undelivered,
.delivery-badge.is-failed {
  background: var(--color-danger-soft);
  color: var(--color-danger-text);
  border-color: var(--color-danger);
}

.delivery-badge.is-skipped,
.delivery-badge.is-pending {
  background: var(--gray-100);
  color: var(--color-text-muted);
  border-color: var(--color-border-strong);
}

@media (max-width: 640px) {
  .report-detail { max-width: 200px; }
}

.bc-report-link {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
  margin: 12px 0;
  font-size: var(--font-size-sm);
}

.bc-report-link-hint { color: var(--color-text-subtle); }

.bc-recip-phone {
  font-variant-numeric: tabular-nums;
  font-size: var(--font-size-xs);
  color: var(--color-text-subtle);
}
/* Campaign review keeps the sender and sending details readable on phones. */
.bc-edit-fields { border: 0; padding: 0; margin: 0; min-width: 0; display: grid; gap: 16px; }
.bc-review-facts { display: grid; grid-template-columns: minmax(100px, 1fr) minmax(0, 2fr); gap: 12px 16px; }
.bc-review-facts dt { font-weight: 600; }
.bc-review-facts dd { margin: 0; overflow-wrap: anywhere; }
.bc-review-facts .page-subtitle { margin: 0; }
.bc-send-review { display: grid; gap: 12px; }
@media (max-width: 480px) {
  .bc-review-facts { grid-template-columns: 1fr; gap: 4px; }
  .bc-review-facts dd { margin-bottom: 12px; }
}
/* Lists & Segments (acquisition Phase A) + custom fields + variable chips. */

/* --- Tabs --- */
.groups-summary { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; margin: 20px 0; }
.groups-summary-card { padding: 20px; }
.groups-summary-card > div { display: flex; align-items: center; gap: 12px; }
.groups-summary-card h2 { font-size: 13px; margin: 0; }
.groups-summary-card strong { display: block; font-size: 28px; margin-top: 12px; }
.groups-summary-card p { font-size: 12px; color: var(--color-text-muted); margin: 6px 0 0; }
.groups-summary-icon, .group-row-icon { display: inline-grid; place-items: center; flex-shrink: 0; background: #e7efff; color: #2563eb; border-radius: 10px; width: 38px; height: 38px; }
.groups-summary-card:nth-child(2) .groups-summary-icon { background: #e0f8ec; color: #079b65; }
.groups-summary-card:nth-child(3) .groups-summary-icon { background: #f1e5ff; color: #7c3aed; }
.groups-toolbar { display: flex; gap: 12px; padding: 16px; margin-bottom: 16px; align-items: center; }
.groups-toolbar input { flex: 1; min-width: 0; }
.groups-toolbar select { width: 220px; }
.group-name-cell { display: flex; align-items: center; gap: 10px; min-width: 150px; }
.group-row-icon { width: 32px; height: 32px; border-radius: 8px; }
.customer-groups-page tr:nth-child(3n+2) .group-row-icon { background: #fff4db; color: #b7790a; }
.customer-groups-page tr:nth-child(3n+3) .group-row-icon { background: #f1e5ff; color: #7c3aed; }
.customer-groups-page .table th:first-child { width: 23%; }
.customer-groups-page .table th:nth-child(2) { width: 30%; }
:root[data-look="v2"] .customer-groups-page .page-header { align-items: flex-start; }
@media (max-width: 767px) {
  .groups-summary { grid-template-columns: 1fr; gap: 10px; }
  .groups-summary-card { padding: 16px; }
  .groups-toolbar { flex-wrap: wrap; }
  .groups-toolbar input, .groups-toolbar select { width: 100%; flex-basis: 100%; }
}
.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-total { padding: 16px; border-radius: 12px; background: #f2f6ff; display: flex; flex-direction: column; gap: 4px; }
.lists-members-total strong { font-size: 24px; }
.lists-members-total span { color: var(--color-text-muted); font-size: 12px; }
.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); }

/* Give the number identity its own row so labels and phone numbers remain visible. */
.seg-rule-number {
  grid-template-columns: minmax(0, 1fr) 110px 28px;
}
.seg-rule-number .seg-number-value {
  grid-column: 1 / -1;
  grid-row: 2;
}
.seg-rule-number .btn-remove {
  grid-column: 3;
  grid-row: 1;
}
@media (max-width: 600px) {
  .seg-rule, .seg-rule-number { grid-template-columns: minmax(0, 1fr) 32px; padding: 12px; background: var(--color-surface); border: 1px solid var(--color-border); border-radius: 10px; }
  .seg-rule > .form-control { grid-column: 1; width: 100%; }
  .seg-rule .btn-remove, .seg-rule-number .btn-remove { grid-column: 2; grid-row: 1; }
  .seg-rule-number .seg-number-value { grid-column: 1; grid-row: auto; }
  .seg-novalue { display: none; }
}
/* Sources (acquisition Phase B) — intake channels, credentials, test panel. */

.integrations-section {
  margin-bottom: var(--spacing-lg);
  padding: var(--spacing-lg);
}

.integrations-section h2 {
  margin: 0 0 var(--spacing-md);
  font-size: var(--font-size-lg);
}

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

.modal-container:has(.sources-editor) { max-width: 1120px; }
.sources-editor-grid { display: grid; grid-template-columns: 180px minmax(0, 1fr) minmax(0, 1.15fr); gap: 24px; }
.sources-editor-grid h3 { margin: 0; font-size: 16px; }
.sources-setup-guide { padding: 18px; border-radius: 10px; background: var(--color-primary-soft); color: var(--color-primary); align-self: start; }
.sources-setup-icon { display: inline-flex; margin-bottom: 12px; }
.sources-setup-guide p, .sources-setup-guide ol { margin: 12px 0 0; font-size: 13px; line-height: 1.6; }
.sources-setup-guide ol { padding-left: 16px; }
.sources-details { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.sources-details .sources-form-row { grid-template-columns: 1fr; }
.sources-mapping-panel { padding: 20px; background: var(--color-surface-sunken); border: 1px solid var(--color-border); border-radius: 10px; min-width: 0; align-self: start; }
.sources-mapping-panel > .form-hint { margin: 8px 0 18px; }
.sources-mapping-panel .sources-map-row { grid-template-columns: minmax(0, 1fr) 14px minmax(0, 1.2fr) 24px; align-items: center; }
.sources-map-row > [aria-label^="Custom field key"] { grid-column: 1 / 4; grid-row: 2; }
.sources-mapping-panel .btn-remove { grid-column: 4; grid-row: 1; }
.sources-mapping-panel .modal-add-row { width: 100%; justify-content: center; border-style: dashed; }
.sources-toolbar { display: flex; gap: 12px; align-items: center; padding: 16px; margin: 20px 0; }
.sources-toolbar input { flex: 1; min-width: 0; }
.sources-toolbar select { width: 180px; }
.source-name-cell { display: flex; gap: 12px; align-items: center; }
.source-name-cell > span { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; width: 38px; height: 38px; border-radius: 9px; background: var(--color-primary-soft); color: var(--color-primary); }
.source-name-cell .bc-link { text-align: left; }
@media (max-width: 1000px) {
  .sources-editor-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); }
  .sources-setup-guide { grid-column: 1 / -1; }
  .sources-setup-guide ol { display: flex; flex-wrap: wrap; gap: 10px 28px; }
}
@media (max-width: 640px) {
  .sources-editor-grid { grid-template-columns: 1fr; gap: 20px; }
  .sources-setup-guide { display: none; }
  .sources-toolbar { flex-wrap: wrap; }
  .sources-toolbar input { flex-basis: 100%; }
  .sources-toolbar select { flex: 1; }
  .sources-mapping-panel { padding: 14px; }
  .sources-mapping-panel .sources-map-row { grid-template-columns: minmax(0, 1fr) 24px; padding: 10px; border: 1px solid var(--color-border); border-radius: 8px; background: var(--color-surface); }
  .sources-mapping-panel .sources-map-arrow { display: none; }
  .sources-mapping-panel .sources-map-row input, .sources-mapping-panel .sources-map-row select { grid-column: 1; grid-row: auto; }
  .sources-mapping-panel .btn-remove { grid-column: 2; grid-row: 1; }
}

.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);
}

/* =========================================================================
   Intake activity — the source event log (@I18).

   Read top-down: verdict, then reasons, then the raw list. Colour carries the
   verdict only in the failing direction: red where submissions are being lost,
   plain surface where they are not. Deliberately NO green — in this product
   green means WhatsApp state (connected / delivered / window open), never
   "this went well" (see variables.css), and a green health pill here would be
   the fourth meaning of the same colour.
   ========================================================================= */
.intake-activity {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
}

.intake-verdict,
.intake-test-result {
  display: flex;
  gap: var(--spacing-sm);
  align-items: flex-start;
  padding: var(--spacing-md);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface-sunken);
}

.intake-verdict-icon {
  flex: 0 0 auto;
  margin-top: 2px;
  color: var(--color-text-muted);
}

.intake-verdict-bad,
.intake-test-bad {
  background: var(--color-danger-soft);
  border-color: var(--color-danger);
}

.intake-verdict-bad .intake-verdict-icon,
.intake-test-bad .intake-verdict-icon {
  color: var(--color-danger-text);
}

.intake-verdict-title {
  margin: 0;
  font-weight: 700;
  font-size: var(--font-size-md);
}

.intake-verdict-detail {
  margin: var(--spacing-2xs) 0 0;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  line-height: var(--line-height-base);
}

/* --- Grouped failure reasons: the actual answer to "why?" --- */
.intake-reasons {
  padding: var(--spacing-md);
}

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

.intake-reason-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
}

.intake-reason {
  display: flex;
  gap: var(--spacing-sm);
  align-items: baseline;
}

.intake-reason-count {
  flex: 0 0 auto;
  min-width: 40px;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  color: var(--color-danger-text);
}

.intake-reason-text {
  font-size: var(--font-size-sm);
  overflow-wrap: anywhere;
}

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

/* --- Outcome filters --- */
.intake-filters {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-sm);
}

.intake-chip {
  min-height: 36px;
  padding: 6px 12px;
  border: 1px solid var(--color-border-strong);
  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;
}

.intake-chip:hover {
  background: var(--color-surface-hover);
}

.intake-chip.is-active {
  background: var(--color-primary-soft);
  border-color: var(--color-primary);
  color: var(--color-primary-active);
}

.intake-chip-count {
  font-variant-numeric: tabular-nums;
  color: var(--color-text-subtle);
}

.intake-chip.is-active .intake-chip-count {
  color: inherit;
}

/* --- The attempts themselves --- */
.intake-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
}

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

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

.intake-row-who {
  flex: 1 1 160px;
  min-width: 0;
  font-weight: 600;
  overflow-wrap: anywhere;
}

.intake-row-time {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  font-variant-numeric: tabular-nums;
}

.intake-row-error {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-xs);
  margin: var(--spacing-sm) 0 0;
  color: var(--color-danger-text);
  font-size: var(--font-size-sm);
  overflow-wrap: anywhere;
}

.intake-row-payload {
  margin-top: var(--spacing-sm);
}

.intake-payload {
  margin: var(--spacing-xs) 0 0;
  padding: var(--spacing-sm);
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  font-size: var(--font-size-xs);
  max-height: 220px;
  overflow: auto;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.intake-none {
  margin: 0;
}

.intake-test-body {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
  min-width: 0;
}

@media (max-width: 640px) {
  .sources-form-row {
    grid-template-columns: 1fr;
  }
  .sources-map-row {
    grid-template-columns: 1fr auto 1fr auto;
  }
}
/*
 * Credentials and code snippets — the surfaces that hand a developer something
 * to paste (Send API keys, signing secrets, cURL samples). Shared rather than
 * per-feature: the intake API (Phase B) and the Send API (Phase 8.1A) present
 * the identical thing, and two copies would drift.
 */

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

.copy-field-value {
  flex: 1;
  min-width: 0;
  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);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--font-size-sm);
}

.code-block {
  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);
  /* A wrapped shell command is a broken shell command. */
  overflow-x: auto;
  white-space: pre;
}

/* Keyboard users scroll this box with the arrow keys, so it is focusable and
   must show where focus is. */
.code-block:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/* A one-time credential the user cannot recover if they navigate away. */
.credential-warning {
  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);
}

/* A textarea the user types code/JSON into (test panels). */
.code-input {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--font-size-sm);
}
/* Send API (Phase 8.1A) — the developer-integration screen. */

.send-api-form,
.send-api-secret {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
}

.modal-container:has(.send-api-campaign-builder) { max-width: 1080px; }
.send-api-builder-columns { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); gap: 24px; }
.send-api-builder-details, .send-api-builder-preview { display: flex; flex-direction: column; gap: 20px; min-width: 0; }
.send-api-builder-preview { align-self: start; }
.send-api-builder-details fieldset.tpl-field { border: 1px solid var(--color-border); padding: 16px; border-radius: 10px; min-width: 0; }
.send-api-builder-summary { padding: 20px; border: 1px solid var(--color-border); border-radius: 10px; }
.send-api-builder-summary h3 { font-size: 16px; margin: 0 0 12px; }
.send-api-builder-summary p { font-size: 13px; line-height: 1.6; color: var(--color-text-muted); }
.send-api-builder-summary dl { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin: 18px 0; font-size: 13px; }
.send-api-builder-summary dt { color: var(--color-text-muted); }
.send-api-builder-summary dd { margin: 0; overflow-wrap: anywhere; }
@media (max-width: 760px) { .send-api-builder-columns { grid-template-columns: 1fr; } }

/* --- Variable map: {{token}} ← the key your backend sends --- */
.send-api-map {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--spacing-md);
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
}

.send-api-map-row {
  display: grid;
  /* The token side gets the wider share: it is fixed copy we cannot shorten,
     while the input beside it is happy at any width. */
  grid-template-columns: minmax(0, 1.4fr) auto minmax(0, 1fr);
  align-items: center;
  gap: var(--spacing-sm);
}

.send-api-map-token code {
  /* A long token still has to wrap rather than push the input off the row —
     but break between words, so a name only splits mid-token when there is
     genuinely nowhere else to go. */
  overflow-wrap: break-word;
  word-break: normal;
}

.send-api-map-arrow {
  color: var(--color-text-muted);
}

/* A variable the product fills in itself — shown, not editable, so nobody
   wonders why one row has no input. */
.send-api-map-auto {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  font-style: italic;
}

.send-api-map-field {
  display: block;
  min-width: 0;
}

/* --- Test preview --- */
.send-api-preview-heading {
  margin: var(--spacing-md) 0 var(--spacing-sm);
}

.send-api-values {
  margin: 0;
  padding-left: var(--spacing-lg);
  font-size: var(--font-size-sm);
}

/* --- Recent-calls log --- */
.send-api-mono {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--font-size-sm);
}

/* Caller-chosen ids can be arbitrarily long; cap the column and let the rest
   wrap instead of forcing the table into a horizontal scroll. */
.send-api-key-cell,
.send-api-detail {
  max-width: 22ch;
  overflow-wrap: anywhere;
}

@media (max-width: 640px) {
  .send-api-map-row {
    grid-template-columns: 1fr;
    gap: var(--spacing-xs);
  }
  .send-api-map-arrow {
    display: none;
  }
}

/* Signup forms linked to a Send API campaign (2026-08-27). Checkboxes rather
   than a multi-select: a tenant has a handful of forms, and ctrl-click to
   deselect is a trap people lose work to. */
.sa-forms {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-2xs);
  max-height: 200px;
  overflow-y: auto;
}

.sa-form-row {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  /* Comfortably past the 24px pointer-target minimum. */
  padding: 8px var(--spacing-sm);
  border-radius: var(--radius-xs);
  cursor: pointer;
}
.sa-form-row:hover { background: var(--color-surface-hover); }
.sa-form-row:focus-within { outline: var(--focus-outline); outline-offset: -2px; }

.sa-form-name { flex: 1; min-width: 0; overflow-wrap: anywhere; }

.sa-form-note {
  flex: 0 0 auto;
  font-size: 0.75rem;
  color: var(--color-text-subtle);
}

/* Seven columns and five actions overflow this table at common widths, and
   `.card`'s `overflow: hidden` beats `.table-wrapper`'s own `overflow-x: auto`
   — so "Rotate key" sat past the clip with no way to reach it. Restored for
   this table only, rather than reordering the global stylesheets and changing
   every other card in the app. */
.table-wrapper.sa-table { overflow-x: 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;
}

.forms-summary { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; margin: 20px 0; }
.forms-summary-card { padding: 20px; }
.forms-summary-card > div { display: flex; gap: 12px; align-items: center; color: #2563eb; }
.forms-summary-card h2 { font-size: 13px; color: var(--color-text); margin: 0; }
.forms-summary-card strong { display: block; font-size: 28px; margin-top: 14px; }
.forms-summary-card:nth-child(2) > div { color: #7c3aed; }
.forms-summary-card:nth-child(3) > div { color: #079b65; }
.forms-summary-card:nth-child(4) > div { color: #c87508; }
.forms-toolbar { display: flex; align-items: center; gap: 16px; padding: 16px; margin-bottom: 16px; }
.forms-toolbar > input { width: auto; min-width: 0; flex: 1; }
.forms-status-filters { display: flex; flex-wrap: wrap; gap: 6px; }
.signup-form-name { display: flex; align-items: center; gap: 12px; min-width: 150px; }
.signup-form-name > span { display: grid; place-items: center; width: 40px; height: 40px; flex-shrink: 0; border-radius: 12px; background: #e7efff; color: #2563eb; }
:root[data-look="v2"] .signup-forms-page .page-header { align-items: flex-start; }
.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);
}
.form-preview-phone { max-width: 330px; margin: 16px auto 0; border: 7px solid #243044; border-radius: 36px; padding: 12px 16px 24px; background: #fff; box-shadow: 0 8px 20px #15253e1c; }
.form-preview-camera { width: 76px; height: 16px; background: #243044; border-radius: 14px; margin: 0 auto 22px; }
.form-preview-phone h3 { font-size: 16px; text-align: center; margin: 0 0 20px; overflow-wrap: anywhere; }
.form-preview-phone .wa-preview-key { display: none; }
.form-preview-phone .wa-form-submit { width: 100%; background: #059c68; min-height: 42px; border-radius: 10px; margin-top: 8px; }
.form-preview-phone .wa-form-preview { gap: 14px; }
.form-preview-phone .form-control:disabled { opacity: 1; background: #f8faff; }
.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; }

/* --- Test modal: the tenant's own form, filled in here (@I18) --- */
.form-test { display: flex; flex-direction: column; gap: var(--spacing-md); }
.form-test-hidden { color: var(--color-text-subtle); font-weight: 400; }
.form-test-consent { margin: 0; }
.form-test-check {
  display: flex; align-items: flex-start; gap: var(--spacing-sm);
  font-size: var(--font-size-sm); cursor: pointer; min-height: var(--tap-target);
}
.form-test-check input { margin-top: 3px; }

@media (max-width: 720px) {
  .forms-summary { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  .forms-summary-card { padding: 16px; }
  .forms-toolbar { flex-direction: column; align-items: stretch; }
  .forms-toolbar > input { width: 100%; }
  .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; }
.modal-container:has(.campaign-sequence-builder) { max-width: 1400px; width: 96vw; }
.campaign-builder-columns { display: grid; grid-template-columns: minmax(240px, .85fr) minmax(340px, 1.15fr) minmax(260px, .85fr); gap: 24px; }
.campaign-builder-columns h3 { margin: 0; font-size: 16px; }
.campaign-setup-panel { display: flex; flex-direction: column; gap: 16px; min-width: 0; }
.campaign-setup-panel .campaign-form-row { flex-direction: column; align-items: stretch; }
.campaign-setup-panel .campaign-form-row > .form-group { min-width: 100px; }
.campaign-sequence-preview { padding: 16px; background: var(--color-surface-sunken); border: 1px solid var(--color-border); border-radius: 10px; min-width: 0; align-self: start; }
.campaign-preview-panel { padding: 20px; background: var(--color-surface-sunken); border: 1px solid var(--color-border); border-radius: 10px; }
.campaign-preview-panel > h3 { margin: 0 0 14px; font-size: 16px; }
.campaign-preview-meta { display: flex; flex-direction: column; gap: 4px; margin-bottom: 12px; overflow-wrap: anywhere; }
.campaign-preview-meta span { font-size: 12px; color: var(--color-text-muted); }
.campaign-message-empty { padding: 30px 16px; border: 1px dashed var(--color-border); border-radius: 8px; color: var(--color-text-muted); font-size: 14px; text-align: center; margin-top: 14px; }
.campaign-phone-preview { border: 6px solid var(--color-text); border-radius: 28px; overflow: hidden; margin-top: 18px; padding: 12px; background: var(--color-surface); }
.campaign-phone-header { font-size: 14px; font-weight: 700; padding: 8px 0 16px; text-align: center; overflow-wrap: anywhere; }
.campaign-sequence-message + .campaign-sequence-message { margin-top: 20px; }
.campaign-sequence-label { text-align: center; font-size: 12px; color: var(--color-text-muted); margin-bottom: 10px; }
.campaign-step-index { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: 50%; background: var(--color-primary); color: #fff; margin-right: 6px; }
.campaign-sequence-builder .campaign-step { border-radius: 10px; overflow: visible; }
.campaign-sequence-builder .campaign-step-head { flex-wrap: wrap; gap: 12px; }
.campaign-sequence-builder .campaign-step-actions { flex-wrap: wrap; }
.campaign-sequence-builder .campaign-step-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.campaign-sequence-builder .campaign-steps { min-width: 0; }
.campaign-sequence-builder .campaign-steps-head { gap: 10px; }
.campaign-sequence-builder .campaign-var-row { flex-wrap: wrap; }
@media (max-width: 1150px) {
  .campaign-builder-columns { grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); }
  .campaign-sequence-preview { grid-column: 1 / -1; }
  .campaign-phone-preview { max-width: 360px; margin-inline: auto; }
}
@media (max-width: 700px) {
  .campaign-builder-columns { grid-template-columns: 1fr; }
  .campaign-sequence-preview { grid-column: auto; }
  .campaign-sequence-builder .campaign-step-grid { grid-template-columns: 1fr; }
}
.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 */
/* Five controls now, so it wraps rather than squeezing them: a date input that
   has been narrowed to nothing is unusable on a phone. */
.reports-page .page-header { align-items: flex-start; gap: 16px; }
.reports-page { min-width: 0; }
.reports-page > .card, .reports-page > section { margin-bottom: 20px; min-width: 0; scroll-margin-top: 100px; }
.reports-page .analytics-filters { padding: 18px 0; }
.reports-page .analytics-filters > .number-chip { align-self: center; }
.reports-page .table-wrapper { max-width: 100%; overflow-x: auto; }
.reports-page .table th { white-space: nowrap; }
.reports-tabs { display: flex; gap: 22px; border-bottom: 1px solid var(--color-border); overflow-x: auto; }
.reports-tabs a { padding: 14px 6px; color: var(--color-text-muted); text-decoration: none; white-space: nowrap; }
.reports-tabs a:first-child { color: var(--color-primary); border-bottom: 2px solid var(--color-primary); }
.reports-export { position: relative; flex-shrink: 0; }
.reports-export summary { list-style: none; cursor: pointer; }
.reports-export summary::after { content: '⌄'; margin-left: 12px; }
.reports-export__menu { position: absolute; z-index: 20; right: 0; top: 48px; min-width: 210px; padding: 8px; display: grid; gap: 4px; background: var(--color-surface); border: 1px solid var(--color-border); border-radius: 10px; box-shadow: var(--shadow-md); }
.reports-kpis { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 14px; margin: 20px 0 14px; }
.reports-kpi { display: flex; gap: 12px; padding: 18px 14px; margin: 0; }
.reports-kpi__icon { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; width: 40px; height: 40px; border-radius: 50%; background: color-mix(in srgb, var(--report-tone) 10%, white); color: var(--report-tone); }
.reports-kpi--blue { --report-tone: #1672f3; }
.reports-kpi--green { --report-tone: #17a15b; }
.reports-kpi--purple { --report-tone: #8548dd; }
.reports-kpi--red { --report-tone: #e34257; }
.reports-kpi__label, .reports-kpi small { display: block; font-size: 11px; color: var(--color-text-muted); }
.reports-kpi strong { display: block; font-size: 25px; margin: 7px 0; }
.reports-overview-grid { display: grid; grid-template-columns: 1.15fr 1fr; gap: 16px; }
.reports-overview-grid > .card { min-width: 0; margin: 0; }
.reports-funnel { display: grid; gap: 17px; margin-top: 24px; }
.reports-funnel__row { display: grid; grid-template-columns: 130px minmax(0, 1fr) 45px 48px; align-items: center; gap: 12px; font-size: 12px; }
.reports-funnel__track { height: 19px; background: var(--color-bg); border-radius: 3px; overflow: hidden; }
.reports-funnel__fill { display: block; height: 100%; background: var(--report-tone); }
.reports-response { display: grid; gap: 8px; font-size: 12px; color: var(--color-text-muted); }
.reports-response > strong { color: var(--color-text); font-size: 28px; }
.reports-conversations { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin: 22px 0; }
.reports-conversations strong, .reports-conversations span { display: block; }
.reports-conversations strong { font-size: 23px; margin-bottom: 5px; }
.reports-conversations span { color: var(--color-text-muted); font-size: 12px; }
@media (max-width: 1200px) { .reports-kpis { grid-template-columns: repeat(3, minmax(0, 1fr)); } .reports-overview-grid { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 600px) { .reports-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; } .reports-kpi { padding: 14px 10px; gap: 8px; } .reports-kpi__icon { width: 30px; height: 30px; } .reports-funnel__row { grid-template-columns: 90px minmax(0, 1fr) 32px 40px; gap: 6px; font-size: 11px; } .reports-page .analytics-filters .form-group { flex: 1; min-width: 140px; } }
.analytics-number-filter {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-sm) var(--spacing-md);
  flex-basis: 100%;
  border: 0;
  padding: 0;
  min-width: 0;
}
.analytics-number-filter label { display: inline-flex; align-items: center; gap: var(--spacing-xs); }
.analytics-number-filter legend { margin-bottom: var(--spacing-sm); }
.analytics-filters { display: flex; flex-wrap: wrap; gap: var(--spacing-md); align-items: flex-end; }
.analytics-filters .form-group { margin-bottom: 0; min-width: 150px; }

/* What the figures below are actually counting. role="status" on the element
   announces it when it changes, without moving focus off the select the tenant
   is still using. */
.analytics-active-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--spacing-sm);
  margin-bottom: var(--spacing-md);
  padding: 10px 14px;
  background: var(--color-primary-soft, #eff6ff);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}
.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;
}

/* ==========================================================================
   The unified Campaigns screen (Phase 8.2 IA) — `ch-` = campaign hub.
   One screen over one-time broadcasts, automated drips and Send API
   campaigns, replacing three sidebar entries.
   ========================================================================== */

/* --- Type picker: step 1 of every campaign ------------------------------- */
.ch-types { display: flex; flex-direction: column; gap: var(--spacing-sm); }

.ch-type-card {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-md);
  width: 100%;
  padding: var(--spacing-md);
  text-align: left;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.ch-type-card:hover { border-color: var(--color-primary); background: var(--color-primary-soft); }
.ch-type-card:focus-visible { outline: var(--focus-outline); outline-offset: 2px; }

.ch-type-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-sm);
  background: var(--color-primary-soft);
  color: var(--color-primary);
}
.ch-type-card:hover .ch-type-icon { background: var(--color-surface); }

.ch-type-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.ch-type-label { font-weight: 600; color: var(--color-text); }
/* Not decoration: the subtitle is what makes "From your system" mean something
   to a shop owner. See CampaignTypePicker's docblock. */
.ch-type-sub { font-size: 0.875rem; color: var(--color-text-muted); }
.ch-type-example { font-size: 0.8125rem; color: var(--color-text-subtle); }
.ch-type-chevron { flex: 0 0 auto; align-self: center; color: var(--color-text-subtle); }

/* --- Toolbar: view toggle + filters -------------------------------------- */
.ch-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-md);
  margin-bottom: var(--spacing-md);
}

.ch-views {
  display: inline-flex;
  padding: 3px;
  gap: 2px;
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
}
.ch-view-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-xs);
  /* 8px block padding + 16px line box clears the 24px web target minimum and
     stays comfortable on a touch screen. */
  padding: 8px 14px;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--color-text-muted);
  background: transparent;
  border: 0;
  border-radius: var(--radius-xs);
  cursor: pointer;
}
.ch-view-btn:focus-visible { outline: var(--focus-outline); outline-offset: 1px; }
.ch-view-btn.is-active {
  color: var(--color-text);
  background: var(--color-surface);
  box-shadow: 0 1px 2px rgb(0 0 0 / 8%);
}

/* Wraps rather than clipping — a filter row that hides its own controls at a
   narrow width is worse than one that takes two lines. */
.ch-filters { display: flex; flex-wrap: wrap; align-items: center; gap: var(--spacing-sm); }

.ch-search { position: relative; display: flex; align-items: center; }
.ch-search .icon {
  position: absolute;
  left: 10px;
  color: var(--color-text-subtle);
  pointer-events: none;
}
.ch-search .form-control { padding-left: 34px; min-width: 220px; }

.ch-select { width: auto; min-width: 168px; }

/* --- List ---------------------------------------------------------------- */
.ch-kind {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-xs);
  white-space: nowrap;
  color: var(--color-text-muted);
}
.ch-template {
  display: block;
  font-size: 0.8125rem;
  color: var(--color-text-subtle);
}
.ch-failed { color: var(--color-danger-text); }
.ch-skipped { color: var(--color-text-subtle); }

/* --- Calendar ------------------------------------------------------------ */
.ch-calendar { padding: var(--spacing-md); }

.ch-cal-head {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-md);
  margin-bottom: var(--spacing-sm);
}
.ch-cal-title { font-size: 1.125rem; font-weight: 600; margin: 0; min-width: 168px; text-align: center; }
.ch-cal-prev { transform: rotate(180deg); }

/* The calendar shows one-time campaigns only, and says so rather than looking
   complete while omitting two of the three kinds. */
.ch-cal-scope {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-sm);
  padding: var(--spacing-sm) var(--spacing-md);
  margin-bottom: var(--spacing-md);
  font-size: 0.8125rem;
  color: var(--color-text-muted);
  background: var(--color-surface-sunken);
  border-radius: var(--radius-sm);
}
.ch-cal-scope .icon { flex: 0 0 auto; margin-top: 1px; }

.ch-cal-grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 1px;
  background: var(--color-border);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.ch-cal-weekday {
  padding: var(--spacing-xs) var(--spacing-sm);
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-subtle);
  background: var(--color-surface-sunken);
  text-align: center;
}

.ch-cal-cell {
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* Reserves the row height so a month with one busy day doesn't make every
     other row collapse — and so switching months doesn't shift the layout. */
  min-height: 96px;
  padding: var(--spacing-xs);
  background: var(--color-surface);
}
.ch-cal-cell.is-empty { background: var(--color-surface-sunken); }
.ch-cal-cell.is-today { box-shadow: inset 0 0 0 2px var(--color-primary); }

.ch-cal-daynum { font-size: 0.75rem; font-weight: 600; color: var(--color-text-muted); }
.ch-cal-cell.is-today .ch-cal-daynum { color: var(--color-primary); }

.ch-cal-entry {
  display: flex;
  flex-direction: column;
  width: 100%;
  padding: 3px 6px;
  text-align: left;
  font-size: 0.75rem;
  border: 0;
  border-left: 3px solid currentcolor;
  border-radius: var(--radius-xs);
  cursor: pointer;
}
.ch-cal-entry:focus-visible { outline: var(--focus-outline); outline-offset: 1px; }
.ch-cal-entry-time { font-weight: 600; opacity: 0.85; }
.ch-cal-entry-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.ch-cal-entry.is-draft { background: var(--gray-100); color: var(--gray-700); }
.ch-cal-entry.is-scheduled { background: var(--color-primary-soft); color: var(--color-primary-active); }
.ch-cal-entry.is-live,
.ch-cal-entry.is-paused { background: var(--color-warning-soft); color: var(--color-warning-text); }
.ch-cal-entry.is-done { background: var(--color-success-soft); color: var(--color-success-text); }
.ch-cal-entry.is-stopped { background: var(--color-danger-soft); color: var(--color-danger-text); }

/* An operable disclosure, never a silent trim. */
.ch-cal-more {
  padding: 2px 6px;
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--color-primary);
  background: transparent;
  border: 0;
  border-radius: var(--radius-xs);
  text-align: left;
  cursor: pointer;
}
.ch-cal-more:hover { background: var(--color-surface-hover); }
.ch-cal-more:focus-visible { outline: var(--focus-outline); outline-offset: 1px; }

.ch-cal-empty {
  margin-top: var(--spacing-md);
  text-align: center;
  color: var(--color-text-muted);
}

@media (max-width: 768px) {
  .ch-toolbar { flex-direction: column; align-items: stretch; }
  .ch-search .form-control { min-width: 0; width: 100%; }
  .ch-search { flex: 1 1 100%; }
  /* A seven-column month cannot shrink below legibility, so it scrolls inside
     its own container rather than forcing the page sideways. */
  .ch-calendar { overflow-x: auto; }
  .ch-cal-grid { min-width: 640px; }
}

/* The merged table carries seven columns and, on an automated row, five
   actions. `.card` sets `overflow: hidden`, which beats `.table-wrapper`'s own
   `overflow-x: auto` and leaves a wide table no choice but to squeeze its
   columns — every cell wrapping to two or three lines. Restored here for this
   table only rather than by reordering the global stylesheets, which would
   change every other card in the app. */
.table-wrapper.ch-table { overflow-x: auto; }

/* These read as single facts — "142 messages sent · 3 failed", "30 Aug",
   a person's name — and wrapping them mid-phrase costs more vertical space
   than the horizontal scroll it saves. The Name column stays wrappable, so
   it is the one that gives. */
.ch-table .ch-nowrap { white-space: nowrap; }
.ch-table td:first-child { min-width: 180px; }

/* The actions WRAP rather than scroll. An automated row carries five of them,
   and pushing the table wide enough to fit them on one line put View, Send and
   Cancel off the right edge behind a horizontal scrollbar — hiding the primary
   action of every other row to keep a secondary one visible on this one. Two
   short lines of buttons in a narrow column costs a little height on drip rows
   only, and nothing is hidden. */
.ch-table .bc-actions { flex-wrap: wrap; max-width: 300px; row-gap: var(--spacing-xs); }

/* The name is a <button>, which centres its text by default — invisible until
   a long name wraps in this column and then reads as a stray indent. */
.ch-table td:first-child .bc-link { text-align: left; }

.ch-table .table { table-layout: fixed; min-width: 900px; }
.ch-table .table th:first-child { width: 29%; }
.ch-table .table th:nth-child(2) { width: 18%; }
.ch-table .table th:nth-child(3) { width: 10%; }
.ch-table .table th:nth-child(4) { width: 15%; }
.ch-table .table th:nth-child(5) { width: 15%; }
.ch-table .table th:last-child { width: 13%; }
.ch-table .ch-nowrap { white-space: normal; }
.ch-table .bc-actions { display: table-cell; }
.ch-table .ch-kind { flex-wrap: nowrap; }
.ch-table .bc-link { overflow-wrap: anywhere; }
@media (max-width: 760px) {
  .ch-table .table { table-layout: auto; min-width: 0; }
  .ch-table .table td:first-child { min-width: 0; }
  .ch-table .bc-actions { display: flex; max-width: none; }
}

.ch-table .table-header th { white-space: normal; }
.ch-table .ch-kind { display: inline-flex; white-space: nowrap; }
.ch-table .ch-kind svg { vertical-align: middle; margin-right: 4px; }
.ch-table .row-actions .btn { padding-inline: 10px; }

.campaigns-page > .number-work-header { margin-bottom: 18px; }
.ch-cal-scope { border: 1px solid var(--color-border); background: var(--color-primary-soft); padding: 16px 20px; line-height: 1.6; }
.ch-cal-scope .icon { color: var(--color-primary); }
.ch-cal-head { margin-bottom: 16px; }
.ch-cal-title { font-size: 20px; font-weight: 700; }
.ch-cal-cell { min-height: 108px; }
.ch-cal-entry { padding: 6px 8px; }
@media (max-width: 600px) {
  .ch-cal-title { min-width: 130px; font-size: 17px; }
  .ch-cal-head { gap: 8px; }
  .ch-cal-scope { padding: 14px; }
}
.reports-page--account .analytics-filters { padding: 16px; background: var(--color-surface); border: 1px solid var(--color-border); border-radius: 12px; }
.reports-workspace-filter { position: relative; flex: 1 0 100%; }
.reports-workspace-filter > summary { cursor: pointer; width: fit-content; min-width: 240px; font-size: 13px; }
.reports-workspace-filter[open] { z-index: 3; }
.reports-workspace-filter .analytics-number-filter { position: absolute; top: 100%; left: 0; min-width: 300px; max-width: min(600px, 100%); max-height: 300px; overflow-y: auto; display: grid; gap: 12px; padding: 16px; margin: 6px 0 0; border: 1px solid var(--color-border); border-radius: 10px; background: var(--color-surface); box-shadow: var(--shadow-md); }
.reports-workspace-filter legend { font-size: 12px; }
.reports-workspace-filter .analytics-number-filter label { min-width: 0; flex-wrap: wrap; }
.reports-workspace-filter .analytics-number-filter .number-chip { max-width: calc(100% - 24px); }
.workspace-report-grid { display: grid; grid-template-columns: 1.15fr 1fr; gap: 16px; margin: 18px 0; }
.workspace-report-grid > .card { min-width: 0; }
.workspace-report-grid .card-header { font-size: 16px; }
.workspace-report-legend { display: flex; flex-wrap: wrap; gap: 16px; font-size: 11px; margin: 14px 0 28px; }
.workspace-report-legend > span { display: flex; align-items: center; gap: 5px; }
.workspace-report-legend i { width: 9px; height: 9px; border-radius: 2px; }
.workspace-report-legend .is-chats, .workspace-report-bar.is-chats { background: #1260f6; }
.workspace-report-legend .is-sent, .workspace-report-bar.is-sent { background: #8ebcfc; }
.workspace-report-bars { display: flex; align-items: flex-start; justify-content: space-around; gap: 10px; }
.workspace-report-group { flex: 1; min-width: 0; text-align: center; }
.workspace-report-pair { display: flex; align-items: flex-end; justify-content: center; gap: 4px; height: 160px; margin-bottom: 14px; border-bottom: 1px solid var(--color-border); }
.workspace-report-bar { position: relative; width: 28px; max-width: 42%; border-radius: 3px 3px 0 0; }
.workspace-report-bar > span:first-child { position: absolute; bottom: calc(100% + 4px); left: 50%; transform: translateX(-50%); font-size: 9px; font-weight: 600; }
.workspace-report-group .number-chip { max-width: 100%; white-space: normal; text-align: center; font-size: 10px; }
.workspace-report-group > small { display: block; color: var(--color-text-muted); margin-top: 4px; font-size: 10px; }
.workspace-report-comparison .card-body { padding-top: 8px; padding-bottom: 8px; }
.workspace-report-comparison .table { width: 100%; min-width: 0; table-layout: fixed; }
.workspace-report-comparison th:first-child { width: 34%; }
.workspace-report-comparison .number-chip { max-width: 100%; white-space: normal; font-size: 10px; }
.workspace-report-comparison .number-chip-text { white-space: normal; overflow-wrap: anywhere; }
.workspace-report-comparison .table th, .workspace-report-comparison .table td { white-space: normal; overflow-wrap: anywhere; }
.workspace-report-comparison .table th { padding: 10px 6px; font-size: 10px; white-space: nowrap; overflow-wrap: normal; }
.workspace-report-comparison th { font-size: 9px; padding: 10px 7px; }
.workspace-report-comparison td { font-size: 11px; padding: 14px 7px; font-variant-numeric: tabular-nums; }
.reports-number-details { margin: 16px 0; padding: 16px; background: var(--color-surface); border: 1px solid var(--color-border); border-radius: 12px; }
.reports-number-details > summary { cursor: pointer; font-size: 13px; font-weight: 600; }
.reports-number-details[open] > summary { margin-bottom: 16px; }
@media (max-width: 1200px) { .workspace-report-grid { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 600px) {
  .reports-workspace-filter > summary { width: 100%; min-width: 0; }
  .reports-workspace-filter .analytics-number-filter { min-width: 0; width: 100%; max-width: none; }
  .workspace-report-bars { flex-wrap: wrap; gap: 24px 12px; }
  .workspace-report-group { flex: 0 0 calc(50% - 6px); }
  .workspace-report-pair { height: 130px; }
  .workspace-report-comparison table, .workspace-report-comparison tbody, .workspace-report-comparison tfoot, .workspace-report-comparison tr { display: block; }
  .workspace-report-comparison thead { display: none; }
  .workspace-report-comparison tr { padding: 12px; border-bottom: 1px solid var(--color-border); }
  .workspace-report-comparison td, .workspace-report-comparison tfoot th { display: flex; justify-content: space-between; gap: 12px; padding: 7px 0; border: 0; }
  .workspace-report-comparison td::before { content: attr(data-label); color: var(--color-text-muted); }
  .workspace-report-comparison td:first-child::before { display: none; }
}
/* ============================================================================
   Chatbots (Phase 12) — the script builder.

   COLOUR RULE: a step's colour answers exactly one question — does it wait for
   the customer to reply? That is the property worth encoding, because it is what
   decides whether the 24-hour window matters at the next step. Colour is never
   used for "category", and it is never the only signal: a waiting step also
   carries a visible "Waits for a reply" marker, since colour alone excludes
   anyone who cannot separate these hues.

   The three tones follow Wati's builder, which gets this right where AiSensy's
   does not: send-and-continue warm, waits-for-reply amber, logic blue.
   ========================================================================== */

.chatbots-page {
  --tone-talk: #be4b5c;
  --tone-talk-soft: #fdf2f3;
  --tone-talk-border: #f5cdd2;

  --tone-ask: var(--color-warning);
  --tone-ask-soft: var(--color-warning-soft);
  --tone-ask-border: #fcd9a0;

  --tone-logic: var(--color-info-text);
  --tone-logic-soft: var(--color-info-soft);
  --tone-logic-border: #bfdbfe;

  --tone-action: var(--gray-600);
  --tone-action-soft: var(--gray-100);
  --tone-action-border: var(--gray-300);
}

/* ---- List page ---------------------------------------------------------- */

.chatbot-list {
  display: grid;
  gap: var(--spacing-md);
}

.chatbot-row {
  display: flex;
  align-items: center;
  gap: var(--spacing-md);
  padding: var(--spacing-md);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}

.chatbot-row__main {
  flex: 1;
  min-width: 0;
}

.chatbot-row__name {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--color-text);
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  flex-wrap: wrap;
}

.chatbot-row__meta {
  font-size: 0.8125rem;
  color: var(--color-text-muted);
  margin-top: var(--spacing-2xs);
  overflow-wrap: anywhere;
}

.chatbot-row__actions {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
  flex-shrink: 0;
}

.chatbot-list.card { display: block; overflow: hidden; }
.chatbot-list.card > .chatbot-row { border: 0; border-bottom: 1px solid var(--color-border); border-radius: 0; padding: 18px 22px; }
.chatbot-list.card > .chatbot-row:last-child { border-bottom: 0; }
.chatbot-list.card > .form-notice { margin: 16px; }
.chatbot-row__icon { width: 42px; height: 42px; border-radius: 10px; flex-shrink: 0; display: inline-flex; justify-content: center; align-items: center; color: #7041c5; background: #f1eaff; }
.chatbot-row__icon--first_message { color: var(--color-primary); background: var(--color-primary-soft); }
.chatbot-row__icon--outside_hours { color: var(--color-warning-text); background: var(--color-warning-soft); }
.chatbot-row__updated { flex-shrink: 0; color: var(--color-text-muted); font-size: 12px; }
.chatbot-list-toolbar { display: flex; gap: 12px; margin: 18px 0; }
.chatbot-list-toolbar input { flex: 1; min-width: 0; }
.chatbot-list-toolbar select { width: 210px; }
.chatbot-name-count { display: block; text-align: right; font-size: 12px; color: var(--color-text-muted); margin-top: 6px; }
.builder__body.builder__body--steps { grid-template-columns: minmax(200px, .8fr) minmax(290px, 1.1fr) minmax(260px, 1fr); }
.builder__preview-panel { padding: 18px; border: 1px solid var(--color-border); border-radius: 12px; background: var(--color-surface); min-width: 0; align-self: start; }
.builder__preview-panel h2 { font-size: 16px; margin: 0 0 8px; }
.builder__preview-panel .test-panel { margin-top: 16px; max-height: none; }
.modal-container:has(.test-panel) .test-panel { max-height: none; }
.modal-container:has(.test-panel) { overflow: hidden; }
.modal-container:has(.test-panel) .test-thread { max-height: 380px; flex: none; }
.builder__preview-panel .test-thread { background: #ece7df; border-radius: 12px; min-height: 280px; max-height: 380px; flex: none; }
.builder__preview-panel .test-real__row { flex-wrap: wrap; }
.builder__preview-panel .test-real__row .form-control { min-width: 0; width: 100%; }
.step-card__icon { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; width: 34px; height: 34px; border-radius: 8px; background: var(--color-surface); color: var(--color-primary); }
.step-card--talk .step-card__icon { background: var(--tone-talk-soft); color: var(--tone-talk); }
.step-card--ask .step-card__icon { background: var(--tone-ask-soft); color: var(--tone-ask); }
.step-card--logic .step-card__icon { background: var(--tone-logic-soft); color: var(--tone-logic); }
.map__legend { display: flex; flex-wrap: wrap; gap: 16px; margin-top: 24px; padding: 16px; border-top: 1px solid var(--color-border); font-size: 12px; }
.map__legend > span { display: inline-flex; align-items: center; gap: 7px; }
.map__legend-dot { width: 12px; height: 12px; border-radius: 4px; border: 1px solid var(--color-border); }
.map__legend-dot.map__node--talk { background: var(--tone-talk); border-color: var(--tone-talk); }
.map__legend-dot.map__node--ask { background: var(--tone-ask); border-color: var(--tone-ask); }
.map__legend-dot.map__node--logic { background: var(--tone-logic); border-color: var(--tone-logic); }
.map__legend-dot.map__node--action { background: var(--tone-action); border-color: var(--tone-action); }
@media (max-width: 1200px) {
  .builder__body.builder__body--steps { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .builder__preview-panel { grid-column: 1 / -1; }
  .chatbot-row__updated { display: none; }
}
@media (max-width: 760px) {
  .chatbots-page .builder__bar { position: static; }
  .builder__body.builder__body--steps { grid-template-columns: minmax(0, 1fr); }
  .builder__preview-panel { grid-column: auto; }
  .chatbot-list-toolbar { flex-wrap: wrap; }
  .chatbot-list-toolbar input { flex-basis: 100%; }
  .chatbot-list-toolbar select { flex: 1; }
  .chatbot-list.card > .chatbot-row { flex-wrap: wrap; padding: 16px; }
  .chatbot-row__main { flex-basis: calc(100% - 60px); }
  .chatbot-row__actions { margin-left: auto; }
}

/* ---- Builder shell ------------------------------------------------------ */

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

.builder__bar {
  display: flex;
  align-items: center;
  gap: var(--spacing-md);
  flex-wrap: wrap;
  padding: var(--spacing-md);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  position: sticky;
  top: 0;
  z-index: 20;
}

.builder__title {
  flex: 1;
  min-width: 180px;
}

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

.builder__tabs {
  display: flex;
  gap: var(--spacing-xs);
  border-bottom: 1px solid var(--color-border);
}

.builder__tab {
  appearance: none;
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  padding: var(--spacing-sm) var(--spacing-md);
  font: inherit;
  font-weight: 500;
  color: var(--color-text-muted);
  cursor: pointer;
  /* 44px min touch target */
  min-height: 44px;
}

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

.builder__tab[aria-selected='true'] {
  color: var(--color-primary);
  border-bottom-color: var(--color-primary);
}

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

@media (max-width: 1024px) {
  .builder__body {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ---- The script (Steps view) -------------------------------------------- */

.script {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
  min-width: 0;
}

.script__trigger {
  padding: var(--spacing-md);
  background: var(--color-primary-soft);
  border: 1px solid var(--color-primary-soft-border);
  border-radius: var(--radius-md);
}

.script__trigger-label {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-primary-active);
  display: flex;
  align-items: center;
  gap: var(--spacing-xs);
}

/* Each nesting level is one branch deeper. The rail makes the nesting legible
   without anybody drawing a line. */
.script__row {
  position: relative;
  padding-left: calc(var(--depth, 0) * 20px);
  min-width: 0;
}

.script__branch-label {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-xs);
  margin: var(--spacing-sm) 0 var(--spacing-2xs);
  padding: 2px var(--spacing-sm);
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-text-muted);
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
}

.script__branch-label--fallback {
  color: var(--color-warning-text);
  background: var(--color-warning-soft);
  border-color: var(--tone-ask-border);
}

/* ---- Step card ---------------------------------------------------------- */

.step-card {
  display: flex;
  gap: var(--spacing-sm);
  width: 100%;
  text-align: left;
  padding: var(--spacing-sm) var(--spacing-md);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-left: 4px solid var(--tone-action);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font: inherit;
  color: inherit;
  min-height: 44px;
  align-items: flex-start;
  transition: border-color 120ms ease, background-color 120ms ease;
}

.step-card:hover {
  background: var(--color-surface-hover);
}

.step-card[aria-current='true'] {
  border-color: var(--color-primary);
  border-left-color: var(--color-primary);
  background: var(--color-primary-soft);
}

.step-card--talk { border-left-color: var(--tone-talk); }
.step-card--ask { border-left-color: var(--tone-ask); }
.step-card--logic { border-left-color: var(--tone-logic); }
.step-card--action { border-left-color: var(--tone-action); }

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

.step-card__kind {
  display: flex;
  align-items: center;
  gap: var(--spacing-xs);
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-text-muted);
  flex-wrap: wrap;
}

.step-card__text {
  margin-top: var(--spacing-2xs);
  color: var(--color-text);
  overflow-wrap: anywhere;
}

.step-card__text--empty {
  color: var(--color-text-subtle);
  font-style: italic;
}

/* The non-colour half of "does this wait?". Never remove this in favour of the
   border tone alone. */
.waits-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 1px var(--spacing-sm);
  font-size: 0.6875rem;
  font-weight: 600;
  border-radius: var(--radius-full);
  background: var(--tone-ask-soft);
  color: var(--color-warning-text);
  border: 1px solid var(--tone-ask-border);
}

.step-card__problem {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-danger-text);
}

/* ---- Add-next control --------------------------------------------------- */

/* You add the next step FROM the previous step, never from a palette you then
   have to connect. Dragging and wiring is two skills; "what happens next" is
   none. */
.add-next {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-xs);
  margin: var(--spacing-xs) 0;
  padding: var(--spacing-xs) var(--spacing-sm);
  min-height: 36px;
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--color-primary);
  background: none;
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

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

/* ---- Step picker -------------------------------------------------------- */

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

.picker__group-title {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-text-subtle);
  margin-bottom: var(--spacing-sm);
}

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

/* Wati's palette cards read "Send a message / With no response required from
   visitor". AiSensy's read "Text Buttons". The subtitle is the difference
   between understanding and guessing, so it is not optional. */
.picker__item {
  display: block;
  text-align: left;
  padding: var(--spacing-sm) var(--spacing-md);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-left: 4px solid var(--tone-action);
  border-radius: var(--radius-sm);
  cursor: pointer;
  font: inherit;
  min-height: 44px;
}

.picker__item:hover {
  background: var(--color-surface-hover);
  border-color: var(--color-border-strong);
}

.picker__item--talk { border-left-color: var(--tone-talk); }
.picker__item--ask { border-left-color: var(--tone-ask); }
.picker__item--logic { border-left-color: var(--tone-logic); }
.picker__item--action { border-left-color: var(--tone-action); }

.picker__item-label {
  font-weight: 600;
  color: var(--color-text);
  display: flex;
  align-items: center;
  gap: var(--spacing-xs);
}

/* Pin the (i) to the trailing edge, away from the middle of the card.
   Sitting immediately after the label put it wherever that label happened to
   end — which, for a card this size, was almost exactly the centre. The tip's
   own 4px hit expansion then covered the point a cursor naturally lands on, so
   clicking the middle of "Send a message" opened the tooltip instead of adding
   the step, and the palette looked like it did nothing at all. At the trailing
   edge it is in the same place on every card and collides with nothing. */
.picker__item-label .info-tip,
.step-card__kind .info-tip {
  margin-left: auto;
}

.picker__item-sub {
  font-size: 0.8125rem;
  color: var(--color-text-muted);
  margin-top: 2px;
}

/* ---- Inspector (edit one step) ------------------------------------------ */

.inspector {
  position: sticky;
  top: 88px;
  padding: var(--spacing-md);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  max-height: calc(100vh - 120px);
  overflow-y: auto;
}

.inspector__empty {
  color: var(--color-text-muted);
  font-size: 0.875rem;
}

.inspector__title {
  font-family: var(--font-display);
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: var(--spacing-xs);
  margin-bottom: var(--spacing-xs);
}

.inspector__help {
  font-size: 0.8125rem;
  color: var(--color-text-muted);
  margin-bottom: var(--spacing-md);
  line-height: 1.55;
}

.choice-row {
  display: flex;
  gap: var(--spacing-sm);
  align-items: flex-start;
  margin-bottom: var(--spacing-sm);
}

.choice-row__input {
  flex: 1;
  min-width: 0;
}

/* ---- Info tip ----------------------------------------------------------- */

.info-tip {
  position: relative;
  display: inline-flex;
}

/* A real button, not a hover target: hover alone is invisible on a phone and
   unreachable by keyboard, and this product is used on phones. */
.info-tip__button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  padding: 0;
  border-radius: var(--radius-full);
  border: 1px solid var(--color-border-strong);
  background: var(--color-surface);
  color: var(--color-text-muted);
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  cursor: help;
}

.info-tip__button::after {
  /* Expands the hit area to 24px without moving anything around it. */
  content: '';
  position: absolute;
  inset: -4px;
}

.info-tip__button:hover,
.info-tip__button:focus-visible {
  border-color: var(--color-primary);
  color: var(--color-primary);
}

.info-tip__bubble {
  position: absolute;
  z-index: 60;
  top: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  width: max-content;
  max-width: 280px;
  padding: var(--spacing-sm) var(--spacing-md);
  background: var(--color-brand-navy);
  color: #ffffff;
  font-size: 0.8125rem;
  font-weight: 400;
  line-height: 1.5;
  border-radius: var(--radius-sm);
  box-shadow: 0 6px 20px rgba(15, 27, 51, 0.25);
  text-align: left;
  white-space: normal;
}

@media (max-width: 640px) {
  .info-tip__bubble {
    position: fixed;
    left: var(--spacing-md);
    right: var(--spacing-md);
    transform: none;
    max-width: none;
    width: auto;
  }
}

/* ---- Variable picker ---------------------------------------------------- */

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

.var-chip {
  padding: 2px var(--spacing-sm);
  min-height: 28px;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  cursor: pointer;
  color: var(--color-text-muted);
}

.var-chip:hover {
  border-color: var(--color-primary);
  color: var(--color-primary);
  background: var(--color-primary-soft);
}

/* ---- Problems panel ----------------------------------------------------- */

.problems {
  display: grid;
  gap: var(--spacing-xs);
  margin-bottom: var(--spacing-md);
}

.problem {
  display: flex;
  gap: var(--spacing-sm);
  align-items: flex-start;
  padding: var(--spacing-sm) var(--spacing-md);
  border-radius: var(--radius-sm);
  font-size: 0.875rem;
  border: 1px solid transparent;
  text-align: left;
  width: 100%;
  font-family: inherit;
  cursor: pointer;
  background: none;
}

.problem--error {
  background: var(--color-danger-soft);
  border-color: #fca5a5;
  color: var(--color-danger-text);
}

.problem--warning {
  background: var(--color-warning-soft);
  border-color: var(--tone-ask-border);
  color: var(--color-warning-text);
}

/* ---- Map view ----------------------------------------------------------- */

.map {
  padding: var(--spacing-lg);
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow-x: auto;
}

.map__col {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
  align-items: flex-start;
  min-width: min-content;
}

.map__node {
  display: inline-flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--spacing-sm) var(--spacing-md);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-left: 4px solid var(--tone-action);
  border-radius: var(--radius-sm);
  max-width: 320px;
  min-width: 200px;
}

.map__node--talk { border-left-color: var(--tone-talk); }
.map__node--ask { border-left-color: var(--tone-ask); }
.map__node--logic { border-left-color: var(--tone-logic); }
.map__node--action { border-left-color: var(--tone-action); }

.map__kind {
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-subtle);
}

.map__text {
  font-size: 0.875rem;
  color: var(--color-text);
  overflow-wrap: anywhere;
}

.map__connector {
  margin-left: 20px;
  padding-left: var(--spacing-md);
  border-left: 2px dashed var(--color-border-strong);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
  padding-top: var(--spacing-xs);
  padding-bottom: var(--spacing-xs);
}

.map__edge-label {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--color-text-muted);
  margin-bottom: 2px;
}

/* ---- Test panel --------------------------------------------------------- */

.test-panel {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
  max-height: 420px;
}

.test-thread {
  flex: 1;
  overflow-y: auto;
  padding: var(--spacing-md);
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
  min-height: 220px;
}

.test-bubble {
  max-width: 78%;
  padding: var(--spacing-sm) var(--spacing-md);
  border-radius: var(--radius-md);
  font-size: 0.875rem;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.test-bubble--bot {
  align-self: flex-start;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-bottom-left-radius: var(--radius-xs);
}

.test-bubble--customer {
  align-self: flex-end;
  background: var(--color-whatsapp-soft);
  border: 1px solid #b7e8cd;
  color: var(--color-whatsapp-text);
  border-bottom-right-radius: var(--radius-xs);
}

.test-bubble--note {
  align-self: center;
  background: var(--color-warning-soft);
  border: 1px solid var(--tone-ask-border);
  color: var(--color-warning-text);
  font-size: 0.8125rem;
  max-width: 100%;
}

.test-choices {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-xs);
}

@media (prefers-reduced-motion: reduce) {
  .step-card {
    transition: none;
  }
}

/* ---- Save / publish banner ---------------------------------------------- */

/* The house system has no generic .alert, so the builder carries its own. Kept
   inside .chatbots-page so it cannot leak into other screens' styling. */
.chatbot-banner {
  padding: var(--spacing-sm) var(--spacing-md);
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  font-size: 0.875rem;
}

.chatbot-banner--success {
  background: var(--color-success-soft);
  border-color: #a7e3bd;
  color: var(--color-success-text);
}

.chatbot-banner--error {
  background: var(--color-danger-soft);
  border-color: #fca5a5;
  color: var(--color-danger-text);
}

/* ---- Trigger panel ------------------------------------------------------ */

.script__trigger-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-sm);
  flex-wrap: wrap;
}

/* A chatbot with no starting words can never run, so it reads as a problem
   rather than as a neutral statement of fact. */
.script__trigger-missing {
  color: var(--color-warning-text);
}

.link-button {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  font-weight: 600;
  color: var(--color-primary);
  text-decoration: underline;
  cursor: pointer;
}

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

/* ==========================================================================
   Canvas — the script as boxes and lines (Phase 12 v2)

   ⚠️ THE CARD METRICS HERE MIRROR canvasLayout.js AND MUST MATCH IT.
   The connectors are hand-drawn SVG whose endpoints are computed, not measured,
   so that a line never lags a frame behind the card it is attached to during a
   drag. CARD_W / CARD_HEAD_H / CARD_BODY_H / BRANCH_H live in that file; the
   heights below are applied inline from it, and only what cannot be inlined
   (colour, borders, states) lives here.
   ========================================================================== */

.canvas {
  display: flex;
  flex-direction: column;
  min-height: 0;
  gap: var(--spacing-sm);
  /* ⚠️ min-width: 0 is load-bearing. A grid item defaults to min-width: auto,
     so without this the canvas is sized by its widest content — a 1700px
     surface — and pushes the whole PAGE into horizontal scroll. The sideways
     scrolling belongs to .canvas__stage and nowhere else. */
  min-width: 0;
}

.canvas--empty {
  padding: var(--spacing-xl);
  text-align: center;
}

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

.canvas__hint {
  margin: 0;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

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

/* The scrolling viewport. A canvas is the one place in this product where
   horizontal scrolling is correct rather than a bug — it is bounded to this
   box, so the page itself never scrolls sideways. */
.canvas__stage {
  position: relative;
  overflow: auto;
  background: var(--color-surface-sunken);
  background-image: radial-gradient(var(--gray-300) 1px, transparent 1px);
  background-size: 20px 20px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  min-height: 60vh;
  max-height: 70vh;
}

/* While a connection is half-made, every card is a target. */
.canvas__stage.is-linking .canvas__card {
  cursor: crosshair;
}

.canvas__surface {
  position: relative;
}

.canvas__wires {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.canvas__wire {
  fill: none;
  /* --gray-500, not the border colour. A connector is MEANINGFUL graphics — it
     is the only thing telling you what leads where — so it needs 3:1 against
     the stage, and the usual border grey manages about 1.5:1 on this near-white
     background. It looked tasteful and was unreadable. */
  stroke: var(--gray-500);
  stroke-width: 2;
}

/* The catch-all branch is drawn dashed. It is the path nobody planned for, and
   reading it as "the exception" at a glance is the difference between spotting
   a dead end and not. */
.canvas__wire--fallback {
  stroke-dasharray: 5 4;
}

.canvas__card {
  position: absolute;
  display: flex;
  flex-direction: column;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  /* The tone is a thick left edge rather than a fill, so the message text keeps
     its full contrast against white in every family. */
  border-left: 4px solid var(--tone-action);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-sm);
  cursor: grab;
  user-select: none;
}

.canvas__card.is-dragging {
  cursor: grabbing;
  box-shadow: var(--shadow-lg);
  /* Above its neighbours while moving, or it slides underneath them. */
  z-index: 2;
}

.canvas__card.is-selected {
  border-color: var(--color-primary);
  box-shadow: 0 0 0 2px var(--color-primary-soft-border);
}

.canvas__card.has-problem {
  border-color: var(--color-danger);
}

/* Colour answers ONE question — does this step wait for the customer? Nothing
   else in this view is coloured, and every waiting card also says so in words. */
.canvas__card--talk { border-left-color: var(--tone-talk); }
.canvas__card--ask { border-left-color: var(--tone-ask); }
.canvas__card--logic { border-left-color: var(--tone-logic); }
.canvas__card--action { border-left-color: var(--tone-action); }

.canvas__card-head {
  display: flex;
  align-items: center;
  gap: var(--spacing-xs);
  width: 100%;
  padding: 0 var(--spacing-sm);
  background: none;
  border: 0;
  border-bottom: 1px solid var(--color-border);
  font: inherit;
  text-align: left;
  cursor: inherit;
}

.canvas__card-head:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: -2px;
}

.canvas__kind {
  font-size: var(--font-size-xs);
  font-weight: 600;
  color: var(--color-text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.canvas__waits {
  flex-shrink: 0;
  padding: 1px var(--spacing-xs);
  border-radius: var(--radius-full);
  background: var(--tone-ask-soft);
  border: 1px solid var(--tone-ask-border);
  color: var(--color-warning-text);
  font-size: 10px;
  white-space: nowrap;
}

.canvas__start {
  flex-shrink: 0;
  margin-left: auto;
  padding: 1px var(--spacing-xs);
  border-radius: var(--radius-full);
  background: var(--color-primary-soft);
  border: 1px solid var(--color-primary-soft-border);
  color: var(--color-primary-active);
  font-size: 10px;
}

/* The real message, clamped to two lines. Fixed height is what lets the
   connector maths know where the branch rows start without measuring. */
.canvas__body {
  padding: var(--spacing-xs) var(--spacing-sm);
  font-size: var(--font-size-sm);
  color: var(--color-text);
  line-height: 1.4;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow-wrap: anywhere;
}

/* One row per branch, "Anything else" included — the catch-all is part of the
   step rather than something you must remember to add, which is what stops a
   chatbot dead-ending on an unexpected reply. */
.canvas__branch {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--spacing-xs);
  padding: 0 var(--spacing-xs) 0 var(--spacing-sm);
  border-top: 1px solid var(--color-border);
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
}

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

.canvas__branch-actions {
  display: flex;
  align-items: center;
  gap: var(--spacing-2xs);
  flex-shrink: 0;
}

.canvas__branch-add {
  background: none;
  border: 0;
  padding: var(--spacing-2xs) var(--spacing-xs);
  border-radius: var(--radius-xs);
  color: var(--color-primary);
  font-size: var(--font-size-xs);
  cursor: pointer;
}

.canvas__branch-add:hover {
  background: var(--color-primary-soft);
}

/* The port sits ON the card's right edge, which is exactly where the connector
   maths draws the line from. It is a real button, because clicking it is the
   keyboard-and-single-pointer way to rewire a branch — WCAG 2.2 requires one,
   and dragging a wire cannot be the only road. */
.canvas__port {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  margin-right: -13px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--color-surface);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-full);
  color: var(--color-text-subtle);
  font-size: 10px;
  line-height: 1;
  cursor: pointer;
}

.canvas__port.is-wired {
  color: var(--color-primary);
  border-color: var(--color-primary-soft-border);
}

.canvas__port:hover,
.canvas__port:focus-visible {
  border-color: var(--color-primary);
  color: var(--color-primary);
  outline: none;
}

.canvas__port:focus-visible {
  box-shadow: 0 0 0 2px var(--color-primary-soft-border);
}

.canvas__problem {
  position: absolute;
  top: -8px;
  right: -8px;
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-full);
  background: var(--color-danger);
  color: #fff;
  font-size: var(--font-size-xs);
  font-weight: 700;
}

@media (prefers-reduced-motion: no-preference) {
  .canvas__card {
    transition: box-shadow 120ms ease, border-color 120ms ease;
  }
}

/* Canvas with nothing selected: no inspector, so the drawing gets the lot. */
.builder__body--wide {
  grid-template-columns: minmax(0, 1fr);
}

/* ---- "A robot is handling this chat" (inbox thread header) --------------- */

.chatbot-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-xs);
  padding: var(--spacing-2xs) var(--spacing-sm);
  border-radius: var(--radius-full);
  /* The waiting tone, because that is what a running chatbot usually is: parked
     on a question. Same colour language as the builder, so the two screens read
     as one feature. */
  background: var(--tone-ask-soft);
  border: 1px solid var(--tone-ask-border);
  color: var(--color-warning-text);
  font-size: var(--font-size-xs);
  white-space: nowrap;
}

.chatbot-chip__text {
  overflow: hidden;
  text-overflow: ellipsis;
  /* The name gives way, never the state — see the component. */
  max-width: 18ch;
}

.chatbot-chip__state {
  flex-shrink: 0;
  font-weight: 600;
}

.chatbot-chip__take {
  background: none;
  border: 0;
  padding: var(--spacing-2xs) var(--spacing-xs);
  border-radius: var(--radius-xs);
  color: var(--color-warning-text);
  font-size: var(--font-size-xs);
  font-weight: 600;
  text-decoration: underline;
  cursor: pointer;
}

.chatbot-chip__take:disabled {
  opacity: 0.6;
  cursor: default;
}

/* ---- Test on a real phone ------------------------------------------------ */

.test-real {
  margin-top: var(--spacing-md);
  padding-top: var(--spacing-md);
  border-top: 1px solid var(--color-border);
}

.test-real__row {
  display: flex;
  gap: var(--spacing-sm);
  align-items: flex-start;
  margin-top: var(--spacing-sm);
}

.test-real__row .form-control {
  flex: 1;
  min-width: 0;
}

/* ---- The Examples gallery ------------------------------------------------ */

.examples__filters {
  display: flex;
  gap: var(--spacing-md);
  margin: var(--spacing-md) 0;
  flex-wrap: wrap;
}

.examples__filter {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-2xs);
  min-width: 160px;
}

.examples__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
}

.examples__item {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--spacing-md);
  padding: var(--spacing-md);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
}

.examples__main {
  min-width: 0;
}

.examples__name {
  margin: 0;
  font-size: var(--font-size-md);
}

.examples__desc {
  margin: var(--spacing-2xs) 0 0;
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

.examples__meta {
  margin: var(--spacing-xs) 0 0;
  color: var(--color-text-subtle);
  font-size: var(--font-size-xs);
}

/* What the example cannot know — your order system, your price list. Said in
   the warning tone before the copy, so it reads as an expectation rather than
   as the publish-time error it would otherwise become. */
.examples__needs {
  margin: var(--spacing-xs) 0 0;
  padding: var(--spacing-2xs) var(--spacing-sm);
  border-radius: var(--radius-xs);
  background: var(--color-warning-soft);
  color: var(--color-warning-text);
  font-size: var(--font-size-xs);
}

.examples__item .btn {
  flex-shrink: 0;
}

.examples__foot {
  display: flex;
  justify-content: flex-end;
  margin-top: var(--spacing-md);
}


/* ---- Routing health ------------------------------------------------------
   Why customers are (or are not) reaching a chatbot. Collapsed by default: the
   list screen is mostly opened to click Edit, and a month of decisions counted
   on every visit is a query nobody asked for.

   ⚠️ No green anywhere in here. Green is real WhatsApp state across the whole
   product — connected, delivered — and a metric tinted green reads as a status
   rather than a number. Tone is blue / amber / red only, and it tints the
   accent bar, never the number. */

.routing {
  margin-top: var(--spacing-md);
  padding: var(--spacing-lg);
}

.routing__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--spacing-md);
  flex-wrap: wrap;
  margin-bottom: var(--spacing-sm);
}

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

/* Narrow enough not to look like a text field, wide enough for "Last 90 days"
   without truncating — a period control that clips its own longest option is
   read as broken. */
.routing__period {
  width: auto;
  min-width: 140px;
}

.routing__scope {
  margin: 0 0 var(--spacing-md);
}

.routing__sub {
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--color-text);
  margin: var(--spacing-lg) 0 var(--spacing-sm);
}

/* The sentence under each number. It is the reason this panel is usable by
   somebody who has never seen an analytics screen, so it stays legible rather
   than shrinking to fit — the cards grow instead. */
.routing__metric-hint {
  margin: var(--spacing-xs) 0 0;
  font-size: var(--font-size-xs);
}

@media (max-width: 640px) {
  .routing {
    padding: var(--spacing-md);
  }

  .routing__head-actions {
    width: 100%;
  }

  .routing__period {
    flex: 1;
  }
}

/* ---- Understanding customers (Phase 12 Part B) --------------------------- */

/*
   ⚠️ NO GREEN ANYWHERE IN HERE. Green is reserved product-wide for real
   WhatsApp state — connected, delivered — so a usage bar that turned green
   at 10% would read as "everything is fine with your number", which is a
   different claim entirely. The meter runs neutral → amber → red, and every
   state also says what it means in words, because colour alone excludes
   anyone who cannot separate these hues.
*/

.chatbots-page .ai-panel { padding: 24px; margin-top: 16px; }
.chatbots-page .ai-panel__lede { font-size: 14px; line-height: 1.65; }
@media (max-width: 640px) { .chatbots-page .ai-panel { padding: 16px; } }

.ai-panel__lede {
  margin: 0 0 var(--spacing-md);
  color: var(--color-text-muted);
  max-width: 62ch; /* Readable measure — this is prose, not a data row. */
}

.ai-panel__unavailable {
  margin: 0 0 var(--spacing-md);
  padding: var(--spacing-sm) var(--spacing-md);
  border-radius: var(--radius-md);
  background: var(--color-info-soft);
  color: var(--color-info-text);
  border: 1px solid #bfdbfe;
}

.ai-block {
  display: grid;
  gap: var(--spacing-md);
  margin-bottom: var(--spacing-lg);
}

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

.ai-switch__text {
  flex: 1 1 auto;
  min-width: 0; /* Lets the hint wrap instead of forcing the row wider. */
}

/* ---- The meter ----------------------------------------------------------- */

.ai-usage {
  padding: var(--spacing-md);
  border: 1px solid var(--gray-200);
  border-left: 3px solid var(--gray-400);
  border-radius: var(--radius-md);
  background: var(--gray-50, #f8fafc);
  margin-bottom: var(--spacing-lg);
}

.ai-usage--low {
  border-left-color: var(--color-warning);
  background: var(--color-warning-soft);
}

.ai-usage--gone {
  border-left-color: var(--color-danger);
  background: var(--color-danger-soft);
}

.ai-usage__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--spacing-sm);
  margin-bottom: var(--spacing-sm);
}

.ai-usage__title {
  margin: 0;
  font-size: var(--font-size-md);
  font-weight: 600;
}

.ai-usage__pct {
  /* Tabular figures: the percentage changes on refresh and must not shuffle
     the layout beside it. */
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}

.ai-usage__bar {
  height: 8px;
  border-radius: 999px;
  background: var(--gray-200);
  overflow: hidden;
}

.ai-usage__fill {
  display: block;
  height: 100%;
  background: var(--gray-500);
  /* Width only, and only on a bar — cheap, and it never reflows anything
     around it. Respected below for anyone who asked for less motion. */
  transition: width 300ms ease-out;
}

.ai-usage--low .ai-usage__fill { background: var(--color-warning); }
.ai-usage--gone .ai-usage__fill { background: var(--color-danger); }

.ai-usage__line {
  margin: var(--spacing-sm) 0 0;
  font-variant-numeric: tabular-nums;
  color: var(--color-text-muted);
}

.ai-usage__note {
  margin: var(--spacing-sm) 0 0;
}

/* ---- Buying more units (11.11) ------------------------------------------ */

/* Separated from the meter above it by a rule, not by a gap: the meter states a
   fact and this asks for money, and running them together made the Buy button
   look like part of the reading. */
.ai-topup {
  margin-top: var(--spacing-md);
  padding-top: var(--spacing-md);
  border-top: 1px solid var(--gray-200);
}

/* The packs reuse `.opt-row` — the radio-card this stylesheet already has, with
   its 44px hit area and its `:has(input:checked)` tint. Only the two things
   that differ are set here: the price sits opposite the size on one line, and
   the body has to be able to shrink so a long estimate wraps rather than
   pushing the price off the card. */
.ai-topup__packs {
  margin-bottom: var(--spacing-sm);
}

.opt-row__body {
  flex: 1 1 auto;
  min-width: 0;
}

.ai-topup .opt-row__label {
  justify-content: space-between;
  width: 100%;
  gap: var(--spacing-md);
}

.ai-topup__price {
  /* Tabular figures: four prices stacked in a column must line up on the
     decimal, and the column must not shuffle when one of them changes. */
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  white-space: nowrap;
}

/* A disabled fieldset is the whole refusal — the cards, the radios and the
   labels all stop responding together, which is what `disabled` on a
   <fieldset> is for. The reduced opacity is the second, visible half; the
   sentence beside it is the third, and is the only one that says why. */
.ai-topup__packs:disabled {
  opacity: 0.55;
}

.ai-topup__packs:disabled .opt-row {
  cursor: not-allowed;
}

.ai-topup__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-sm);
  margin-top: var(--spacing-sm);
}

.ai-topup__note {
  margin: var(--spacing-sm) 0 0;
  color: var(--color-text-muted);
}

/* ⚠️ NOT GREEN. Green is live WhatsApp state everywhere in this product
   (connected, delivered) and a green panel here would read as a connection
   status rather than as a receipt. The done state is the brand accent plus the
   words, and the words carry it on their own. */
.ai-topup__note--done {
  color: var(--color-text);
  border-left: 3px solid var(--color-primary);
  padding-left: var(--spacing-sm);
}

.ai-topup__note--bad {
  color: var(--color-danger);
}

.ai-topup__list {
  margin: var(--spacing-xs) 0 0;
  padding-left: var(--spacing-lg);
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

/* ---- The instruction field ---------------------------------------------- */

.instruction-foot {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--spacing-sm);
}

.instruction-foot .form-hint {
  flex: 1 1 auto;
  margin: 0;
}

.instruction-count {
  flex: 0 0 auto;
  font-size: var(--font-size-sm);
  font-variant-numeric: tabular-nums; /* The count must not jiggle as it grows. */
  color: var(--color-text-muted);
}

/* Amber, not red: too short is an unfinished sentence, not an error. Nothing
   has gone wrong and nothing is blocked — the field is optional. */
.instruction-count--short { color: var(--color-warning); }
.instruction-count--long { color: var(--color-danger); }

.instruction-warning {
  margin: var(--spacing-sm) 0 0;
  padding: var(--spacing-sm) var(--spacing-md);
  border-radius: var(--radius-md);
  background: var(--color-warning-soft);
  color: var(--color-warning-text);
  border: 1px solid #fcd9a0;
}

.ai-log {
  margin-top: var(--spacing-md);
}

.ai-log__empty {
  padding: var(--spacing-lg);
  text-align: center;
  color: var(--color-text-muted);
}

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

@media (max-width: 640px) {
  .ai-switch {
    /* The switch drops below its label rather than squeezing the text into a
       two-word column. */
    flex-direction: column;
    align-items: flex-start;
  }

  .ai-usage__buy {
    flex-direction: column;
    align-items: stretch;
  }
}

@media (prefers-reduced-motion: reduce) {
  .ai-usage__fill { transition: none; }
}

/* ---- Settings dialog: option rows, chips, units -------------------------- */

/* A fieldset with the browser's own border and inset padding removed. The
   legend stays a real <legend> so the group has a name a screen reader reads
   before the first radio — six unnamed radios in a dialog is a list of things
   with no question above it. */
.settings-fieldset {
  border: 0;
  padding: 0;
  margin: 0 0 var(--spacing-md);
}

.settings-fieldset > .form-label {
  padding: 0;
  margin-bottom: var(--spacing-sm);
}

/* One choice, as a card rather than a bare radio.
   Six triggers each carrying a sentence of explanation is a lot of undivided
   text; the card gives each option its own edge, and the whole row is the hit
   area, which a 13px radio dot is not (44px minimum). */
.opt-row {
  display: flex;
  gap: var(--spacing-sm);
  align-items: flex-start;
  min-height: 44px;
  padding: var(--spacing-sm) var(--spacing-md);
  margin-bottom: var(--spacing-xs);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  cursor: pointer;
}

.opt-row:hover {
  border-color: var(--color-border-strong);
  background: var(--color-surface-hover);
}

/* Selection is ALREADY carried by the native radio; this is a second, redundant
   signal, never the only one — so a browser without :has() loses nothing that
   matters. */
.opt-row:has(input:checked) {
  border-color: var(--color-primary);
  background: var(--color-primary-soft);
}

.opt-row input[type='radio'] {
  margin-top: 3px;
  flex: none;
}

.opt-row__label {
  display: flex;
  align-items: center;
  gap: var(--spacing-xs);
  color: var(--color-text);
}

.opt-row__sub {
  display: block;
  margin: 2px 0 0;
}

/* A note that belongs to the choice above it, not to a field of its own. */
.settings-note {
  margin: calc(var(--spacing-xs) * -1) 0 var(--spacing-md);
}

/* Chips the tenant has already added — keywords, button ids. Not `.var-picker`,
   which is a palette of things to INSERT; these are values already chosen, so
   the chip is not a button and only its ✕ is. */
.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-xs);
  margin-bottom: var(--spacing-sm);
}

.chip-row__chip {
  font-family: inherit;
  font-size: 0.8125rem;
  cursor: default;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.chip-row__chip:hover {
  border-color: var(--color-border);
  color: var(--color-text-muted);
  background: var(--color-surface-sunken);
}

.chip-row__remove {
  border: 0;
  background: none;
  cursor: pointer;
  color: inherit;
  font-size: 0.875rem;
  line-height: 1;
  padding: 4px;
  margin: -4px -4px -4px 0;
}

.chip-row__remove:hover {
  color: var(--color-danger);
}

.chip-input {
  display: flex;
  gap: var(--spacing-sm);
}

/* A number that means minutes or days does not need a full-width box, and a
   full-width one reads as though a long value were expected. */
.form-control--narrow {
  max-width: 9rem;
}

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

.field-unit {
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
}

/* A step that exists in the catalogue but cannot be built yet (the reserved
   Part C slot). Dimmed AND badged "Coming later" — the dimming alone would be
   colour carrying the whole message, and dimming is also what a merely
   unselected card could look like. `default` rather than `not-allowed`: nothing
   here is forbidden, it simply is not built. */
.picker__item--unavailable {
  opacity: 0.55;
  cursor: default;
  background: var(--color-surface-sunken);
}

.picker__item--unavailable:hover {
  background: var(--color-surface-sunken);
  border-color: var(--color-border);
}

/* ---- Understanding customers: the read-only half ------------------------ */

/* What a supervisor sees where an admin gets three controls. A definition list,
   not a disabled form: the values are facts here, and nothing on screen should
   look like something that could be pressed. */
.ai-block--readonly {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface-sunken);
  padding: var(--spacing-md);
}

.ai-readonly__note {
  margin: 0 0 var(--spacing-md);
  color: var(--color-text-muted);
  font-size: var(--font-size-sm);
  line-height: 1.55;
}

.ai-readonly {
  display: grid;
  gap: var(--spacing-sm);
  margin: 0;
}

.ai-readonly__row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-xs) var(--spacing-md);
  justify-content: space-between;
  align-items: baseline;
}

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

.ai-readonly__row dd {
  margin: 0;
  font-weight: 600;
  color: var(--color-text);
}

/* A chatbot on the list that genuinely cannot fire — no starting words, no
   message shape, no button ids. Same warning text colour as the builder's
   `.script__trigger-missing`, so "unfinished" looks the same on both screens.
   The tone is never the only signal: the sentence names what is missing. */
.chatbot-row__meta--incomplete {
  color: var(--color-warning-text);
}
.modal-container:has(.chatbot-create-wizard) { width: 96vw; max-width: 1040px; }
.chatbot-create-progress { display: flex; gap: 6px; list-style: none; margin: 0 0 24px; padding: 0 0 10px; overflow-x: auto; }
.chatbot-create-progress li { flex: 1; min-width: 120px; }
.chatbot-create-progress button { display: flex; align-items: center; gap: 7px; min-height: 44px; padding: 6px 4px; width: 100%; background: transparent; border: 0; font-size: 11px; color: var(--color-text-muted); cursor: pointer; text-align: left; }
.chatbot-create-progress button > span { display: grid; place-items: center; width: 25px; height: 25px; border: 1px solid var(--color-border); border-radius: 50%; font-size: 12px; flex-shrink: 0; }
.chatbot-create-progress button[aria-current='step'] { color: var(--color-primary); font-weight: 600; }
.chatbot-create-progress button[aria-current='step'] > span { background: var(--color-primary); border-color: var(--color-primary); color: #fff; }
.chatbot-create-progress button:disabled { cursor: default; opacity: .6; }
.chatbot-create-title { margin: 0 0 18px; font-size: 19px; }
.chatbot-create-title:focus { outline: none; }
.chatbot-create-panel { min-width: 0; }
.chatbot-create-panel[hidden] { display: none; }
.chatbot-create-note { display: flex; gap: 12px; padding: 18px; margin-bottom: 24px; border: 1px solid var(--color-primary-soft-border); background: var(--color-primary-soft); border-radius: 10px; }
.chatbot-create-note > svg { color: var(--color-primary); flex-shrink: 0; }
.chatbot-create-note strong { font-size: 14px; }
.chatbot-create-note p, .chatbot-create-shared { font-size: 12px; line-height: 1.6; color: var(--color-text-muted); margin: 6px 0 0; }
.chatbot-create-shared { margin: 0 0 16px; padding: 12px 14px; border-radius: 8px; background: var(--color-surface-sunken); }
.chatbot-create-panel > .card { margin: 0; }
.chatbot-create-panel > .ai-panel { padding: 24px; }
.chatbot-create-panel .ai-panel__lede { font-size: 14px; line-height: 1.65; }
.chatbot-create-review { display: grid; grid-template-columns: 1.5fr 1fr; gap: 20px; }
.chatbot-create-review section { border: 1px solid var(--color-border); border-radius: 12px; padding: 4px 20px; }
.chatbot-create-review dl { margin: 0; }
.chatbot-create-review dl > div { display: grid; grid-template-columns: 1fr 1.5fr; gap: 16px; padding: 18px 0; border-bottom: 1px solid var(--color-border); }
.chatbot-create-review dl > div:last-child { border: 0; }
.chatbot-create-review dt { font-size: 12px; color: var(--color-text-muted); }
.chatbot-create-review dd { margin: 0; font-size: 13px; overflow-wrap: anywhere; }
.chatbot-create-review aside { padding: 20px; border-radius: 12px; background: var(--color-primary-soft); border: 1px solid var(--color-primary-soft-border); }
.chatbot-create-review h3 { font-size: 16px; margin: 0 0 12px; }
.chatbot-create-review p { font-size: 13px; line-height: 1.6; color: var(--color-text-muted); }
.chatbot-create-footer { width: 100%; display: flex; align-items: center; gap: 14px; }
.chatbot-create-footer > span { font-size: 12px; color: var(--color-text-muted); }
.chatbot-create-footer-actions { margin-left: auto; display: flex; gap: 8px; }
@media (max-width: 640px) {
  .modal-container:has(.chatbot-create-wizard) { width: 100%; }
  .chatbot-create-review { grid-template-columns: minmax(0, 1fr); }
  .chatbot-create-review dl > div { grid-template-columns: minmax(0, 1fr); gap: 6px; }
  .chatbot-create-panel > .ai-panel { padding: 16px; }
  .chatbot-create-footer { flex-wrap: wrap; gap: 10px; }
  .chatbot-create-footer > .btn { width: auto; }
  .chatbot-create-footer > span { margin-left: auto; }
  .chatbot-create-footer-actions { width: 100%; }
  .chatbot-create-footer-actions .btn { flex: 1; width: 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;
}

/* ---- The way out when there is no section nav -------------------------- */

/* Shown only when the tab strip cannot be (one section — see
   SettingsLayout.jsx). It sits above the H1 rather than beside it, so it reads
   as "you came from here" rather than as an action on this page. */
.settings-back {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-2xs);
  margin-bottom: var(--spacing-sm);
  /* Comfortably past the 24px pointer-target minimum without needing a box
     drawn around a plain text link. */
  padding: var(--spacing-2xs) 0;
  font-size: var(--font-size-sm);
  font-weight: 500;
  color: var(--color-text-muted);
  text-decoration: none;
}

.settings-back:hover,
.settings-back:focus-visible {
  color: var(--color-primary);
}

/* ---- 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: thin;
}

.settings-nav::-webkit-scrollbar { height: 6px; }

.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: thin;
}

.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;
  }
}

/* The day name is a row header, so it is a <th> — give it the weight a header
   deserves without the all-caps treatment the column headers get. */
.settings-hours-day {
  font-weight: 600;
  color: var(--color-text);
  text-align: left;
  white-space: nowrap;
}

/* "Open"/"Closed" beside the box, not just the box. Reading a word is faster
   than working out what an unticked checkbox in a column called "Open?" means,
   and it is the difference between a state anyone can read and one you have to
   infer from a tick. */
.settings-hours-open {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: var(--spacing-sm);
  width: auto;
  min-height: var(--tap-target);
  cursor: pointer;
}

.settings-hours-open-text {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* --- Settings → AI assistants (Phase 13) ------------------------------- */

/* The MCP address a tenant pastes into Claude or ChatGPT. Deliberately a
   separate rule from the WhatsApp screen's .wa-copy-row rather than a reuse of
   it: that one lives in the WhatsApp feature's own stylesheet, and reaching
   across for it would make this screen render unstyled the day that file stops
   being loaded here. Two short rules is a better trade than that coupling. */
.settings-copy-row {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
}

.settings-copy-value {
  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);
  /* A URL has no spaces to wrap at, so without this it forces the card wider
     than the viewport on a phone. */
  word-break: break-all;
}

/* The per-client setup steps under the address. `.hint` sets the muted colour
   and size; this only restores the list marker the reset removes. */
.settings-steps {
  margin: var(--spacing-md) 0 0;
  padding-left: var(--spacing-lg);
  list-style: disc;
}

.settings-steps li + li {
  margin-top: 6px;
}

/* The explanation under the AI-assistants toggle. `.hint` carries no margin by
   design — it is meant as one line under a field — so two stacked hints read as
   a single run-on paragraph. This one sits under a toggle and needs the gap. */
.settings-toggle-hint {
  margin-top: var(--spacing-sm);
}

/* --- Email address + its verification state ----------------------------- */

.email-field__state {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--spacing-sm);
  /* Pulled up under the input's helper text so the badge reads as belonging to
     the field above it rather than starting a new row of its own. */
  margin-top: calc(var(--spacing-xs) * -1);
  margin-bottom: var(--spacing-md);
}

/* The "we cannot send email yet" line is a full sentence, not a chip, so it
   needs to wrap rather than stretch the row. */
.email-field__state .form-helper {
  flex: 1 1 260px;
  margin: 0;
}

/* A card that opens with a line of explanation before its first field.
   `.form-helper` is built to sit UNDER an input with no bottom margin, so
   reused as an intro it leaves the first label crowded against it. */
.card-intro {
  margin: 0 0 var(--spacing-lg);
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
  max-width: 68ch;
}

.settings-nav { flex-wrap: wrap; overflow: visible; }
.settings-nav-link { min-width: 0; }
.builder__tabs { flex-wrap: wrap; gap: 4px; }
.builder__tab { min-height: 44px; white-space: normal; }
.settings-back { min-height: 44px; }

.settings-tabs { flex-wrap: wrap; overflow: visible; gap: 4px; }
.settings-tab { white-space: normal; }

.workspace-settings-page { max-width: none; }
.workspace-settings-nav { display: flex; gap: 12px; margin-bottom: 24px; overflow-x: auto; border-bottom: 1px solid var(--color-border); scrollbar-width: thin; }
.workspace-settings-link { display: inline-flex; align-items: center; gap: 8px; flex: 0 0 auto; min-height: 48px; padding: 8px 12px; border-bottom: 2px solid transparent; color: var(--color-text-muted); font-size: 14px; white-space: nowrap; }
.workspace-settings-link:hover { color: var(--color-primary); text-decoration: none; }
.workspace-settings-link.is-active { border-bottom-color: var(--color-primary); color: var(--color-primary); font-weight: 600; }
.workspace-settings-columns { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); gap: 20px; align-items: start; }
.workspace-settings-columns > * { min-width: 0; }
.workspace-settings-columns .card-header { margin: 0; font-size: 16px; }
.workspace-settings-columns .meta-billing-guide { padding: 20px; margin: 0; border: 0; font-size: 14px; }
.workspace-settings-columns .detail-row { gap: 16px; padding: 12px 0; }
.workspace-settings-columns .number-color-options { gap: 8px; }
.workspace-settings-columns .number-color-option { padding: 8px; font-size: 13px; }
.settings-with-aside { grid-template-columns: minmax(0, 2.2fr) minmax(260px, 1fr); }
.settings-with-aside aside { font-size: 14px; }
.settings-with-aside aside .card-header { display: flex; gap: 10px; align-items: center; justify-content: flex-start; }
.settings-numbered { counter-reset: settings-section; }
.settings-numbered > .card > .card-header { display: flex; align-items: center; justify-content: flex-start; gap: 12px; }
.settings-numbered > .card > .card-header .btn { margin-left: auto; }
.settings-numbered > .card > .card-header::before { counter-increment: settings-section; content: counter(settings-section); display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; flex: none; border-radius: 50%; background: var(--color-primary); color: white; font-size: 12px; }
.settings-info-callout { display: flex; align-items: flex-start; gap: 10px; margin-top: 16px; padding: 14px; border-radius: 8px; background: var(--color-primary-soft); color: var(--color-info-text); }
.settings-info-callout .icon { flex: none; margin-top: 2px; }
.settings-info-callout p { margin: 0; }
.settings-tip-list { list-style: disc; padding-left: 18px; margin: 0; }
.settings-tip-list li + li { margin-top: 8px; }
.workspace-settings-page .settings-grid { grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); }
.workspace-settings-page .settings-toggle input[type='checkbox'],
.workspace-settings-page .settings-hours-open input[type='checkbox'] { appearance: none; width: 36px; height: 21px; flex: none; border: 1px solid var(--color-border-strong); border-radius: 999px; background: var(--gray-300); position: relative; cursor: pointer; }
.workspace-settings-page .settings-toggle input[type='checkbox']::before,
.workspace-settings-page .settings-hours-open input[type='checkbox']::before { content: ''; position: absolute; left: 2px; top: 2px; width: 15px; height: 15px; border-radius: 50%; background: white; box-shadow: var(--shadow-xs); transition: transform 120ms ease; }
.workspace-settings-page .settings-toggle input[type='checkbox']:checked,
.workspace-settings-page .settings-hours-open input[type='checkbox']:checked { background: var(--color-primary); border-color: var(--color-primary); }
.workspace-settings-page .settings-toggle input[type='checkbox']:checked::before,
.workspace-settings-page .settings-hours-open input[type='checkbox']:checked::before { transform: translateX(15px); }
.workspace-settings-page input[type='checkbox']:focus-visible { outline: var(--focus-outline); outline-offset: 3px; }
.workspace-settings-page input[type='checkbox']:disabled { opacity: 0.5; cursor: not-allowed; }
.workspace-settings-page .settings-toggle { display: flex; align-items: center; gap: 10px; min-height: 44px; }
.workspace-settings-page .btn-danger { background: transparent; border-color: var(--color-border); color: var(--color-danger); }
.workspace-settings-page .btn-danger:hover { background: var(--color-danger-soft); }
.workspace-settings-page .settings-hours-table td .form-control { min-width: 105px; }
.workspace-settings-page .detail-row dd { font-size: 14px; font-weight: 500; text-align: left; }
.workspace-settings-page .card-body { padding: 20px; }
.workspace-settings-page .card-header { padding: 14px 20px; }
.workspace-settings-page .form-group { margin-bottom: 16px; }
:root[data-look="v2"] .settings-hours-table .settings-hours-day { text-transform: none; font-size: 14px; letter-spacing: normal; background: none; }
@media (max-width: 640px) {
  .workspace-settings-page .settings-hours-table,
  .workspace-settings-page .settings-hours-table tbody { display: block; }
  .workspace-settings-page .settings-hours-table thead { display: none; }
  .workspace-settings-page .settings-hours-table tr { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; padding: 12px 0; border-bottom: 1px solid var(--color-border); }
  .workspace-settings-page .settings-hours-table th,
  .workspace-settings-page .settings-hours-table td { padding: 0; border: 0; min-width: 0; }
  .workspace-settings-page .settings-hours-table .settings-hours-day { align-self: center; }
  .workspace-settings-page .settings-hours-table td:nth-child(3)::before,
  .workspace-settings-page .settings-hours-table td:nth-child(4)::before { display: block; font-size: 12px; color: var(--color-text-muted); margin-bottom: 4px; }
  .workspace-settings-page .settings-hours-table td:nth-child(3)::before { content: 'Opens'; }
  .workspace-settings-page .settings-hours-table td:nth-child(4)::before { content: 'Closes'; }
  .workspace-settings-page .settings-hours-table .form-control { width: 100%; min-width: 0; }
}
@media (max-width: 1100px) {
  .workspace-settings-columns { grid-template-columns: minmax(0, 1fr); }
}
/* Phase 11.9 — Settings → Billing: the usage meter, the savings receipt and
   the plan chooser. Common classes (.card, .detail-list, .form-notice,
   .badge, .settings-grid) do the heavy lifting; what is here is the meter bar,
   the plan grid and the checkout panel, none of which exist elsewhere. */

/* ---- Usage meter -------------------------------------------------------- */
.billing-meter {
  margin-bottom: var(--spacing-md);
}

.billing-meter-figures {
  display: flex;
  align-items: baseline;
  gap: var(--spacing-sm);
  margin-bottom: var(--spacing-xs);
  /* Tabular figures: the used count changes on reload and must not shift the
     layout of the sentence around it. */
  font-variant-numeric: tabular-nums;
}

.billing-meter-used {
  font-size: var(--font-size-2xl);
  font-weight: 700;
  color: var(--color-text);
}

.billing-meter-of {
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

.billing-meter-track {
  height: 10px;
  border-radius: var(--radius-full);
  background: var(--gray-200);
  overflow: hidden;
}

.billing-meter-track-uncapped {
  /* Diagonal hatch reads as "open-ended" rather than "full" at a glance —
     colour is never the only signal that there is no cap here. */
  background-image: repeating-linear-gradient(
    45deg, var(--color-primary-soft), var(--color-primary-soft) 6px, var(--gray-100) 6px, var(--gray-100) 12px
  );
}

.billing-meter-fill {
  height: 100%;
  border-radius: var(--radius-full);
  transition: width 0.3s ease;
}

.billing-meter-fill-ok { background: var(--color-primary); }
.billing-meter-fill-warning { background: var(--color-warning); }
.billing-meter-fill-danger { background: var(--color-danger); }

.billing-category-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--spacing-sm);
  margin-top: var(--spacing-md);
}

.billing-category-tile {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--spacing-sm) var(--spacing-md);
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}

.billing-category-value {
  font-size: var(--font-size-lg);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.billing-category-label {
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
}

/* ---- Savings receipt ----------------------------------------------------- */
.billing-receipt-lines {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-xs);
  margin: 0 0 var(--spacing-md);
  padding-left: 1.2em;
}

.billing-receipt-lines li { font-size: var(--font-size-sm); }

.billing-rates-disclosure {
  margin-top: var(--spacing-md);
}

.billing-rates-disclosure summary {
  cursor: pointer;
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--color-primary);
}

.billing-rate-table { margin-top: var(--spacing-sm); }

.billing-rate-table-title {
  font-size: var(--font-size-xs);
  font-weight: 600;
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

/* ---- Plan chooser --------------------------------------------------------- */
.billing-period-toggle {
  display: inline-flex;
  padding: 3px;
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-full);
  margin-bottom: var(--spacing-lg);
}

.billing-period-option {
  padding: 8px 18px;
  border: none;
  background: none;
  border-radius: var(--radius-full);
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--color-text-muted);
  cursor: pointer;
  min-height: 36px;
}

.billing-period-option.is-active {
  background: var(--color-surface);
  color: var(--color-primary);
  box-shadow: var(--shadow-xs);
}

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

.billing-plan-tile {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
  padding: var(--spacing-lg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}

.billing-plan-tile.is-chosen {
  border-color: var(--color-primary);
  box-shadow: var(--shadow-md);
}

/* The plan this workspace already has. Quieter than `.is-chosen`, not louder:
   it is a statement of fact, not the thing to press. The tinted surface is
   what separates it from the offers beside it; the badge inside it is what
   says so in words, because colour alone must never be the signal.

   ⚠️ TWO TINTS, AND THEY MUST MATCH THEIR BADGE. Green is a CONFIRMED state
   in this product (see variables.css) — painting a plan green while its
   mandate is still registering says "you are on this" a day or more before it
   is true. Success for the plan that is actually running, info for the one
   the bank has not confirmed, each beside the badge of the same tone. */
.billing-plan-tile.is-success {
  border-color: var(--color-success);
  background: var(--color-success-soft);
}

.billing-plan-tile.is-info {
  border-color: var(--color-info);
  background: var(--color-info-soft);
}

.billing-plan-tile-head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--spacing-xs);
}

.billing-plan-tile-head h3 {
  /* The head is a flex column with its own gap — a bottom margin here would
     add to it rather than replace it. */
  margin: 0;
  font-size: var(--font-size-lg);
}

.billing-plan-price {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--spacing-xs);
  font-variant-numeric: tabular-nums;
}

.billing-plan-amount {
  font-size: var(--font-size-2xl);
  font-weight: 700;
}

.billing-plan-price-note {
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
}

.billing-plan-was {
  font-size: var(--font-size-sm);
  color: var(--color-text-subtle);
  text-decoration: line-through;
}

.billing-plan-features {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

.billing-plan-terms {
  font-size: var(--font-size-xs);
  color: var(--color-text-subtle);
  margin: 0;
}

.billing-enterprise-note {
  margin-top: var(--spacing-lg);
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* ---- Checkout panel -------------------------------------------------------- */
.billing-checkout-panel {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
  padding-top: var(--spacing-sm);
  border-top: 1px solid var(--color-border);
}

.billing-method-picker {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
  border: none;
  padding: 0;
  margin: 0;
}

.billing-method-picker legend {
  font-size: var(--font-size-sm);
  font-weight: 600;
  margin-bottom: var(--spacing-xs);
  padding: 0;
}

.billing-bank-form {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
}

/* ---- Auto-upgrade (11.6) --------------------------------------------------- */
.billing-auto-upgrade-attempt {
  margin-top: var(--spacing-sm);
  padding-top: var(--spacing-sm);
  border-top: 1px solid var(--color-border);
}

/* ---- Cancel (11.9c) ------------------------------------------------------- */
/* Exactly one of these renders inside the card at a time (cancelled notice, or
   the cancel form) — no sibling divider rule needed since the pause section
   this shared it with was removed 2026-09-09. */
.billing-cancel-section {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-sm);
}

/* ---- Invoices (11.5) ---------------------------------------------------- */
/* The table itself is the shared `.table` system (tables.css): six columns in
   a `.table-wrapper` that scrolls sideways on its own so the page never does.
   What is here is only what that system has no opinion about. */

.billing-invoice-number {
  /* An invoice number is read digit by digit against a bank statement, so the
     digits are tabular and the string never wraps mid-number. */
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

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

/* ⚠️ NOTHING IN THIS TABLE WRAPS. At 390px the wrapper scrolls sideways on its
   own (that is what `.table-wrapper` is for), and a cell that wraps instead
   makes the row two lines tall while STILL not fitting — the worst of both.
   A date, an amount and a period are each read as one token anyway. */
.billing-invoice-period,
.billing-invoice-date,
.billing-invoice-amount {
  white-space: nowrap;
}

.billing-invoice-loadmore {
  display: flex;
  justify-content: center;
  padding-top: var(--spacing-md);
}

.meta-billing-guide {
  margin: 16px 0;
  padding: 16px;
  border: 1px solid var(--border-color, #e5e7eb);
  border-radius: 10px;
  font-size: 14px;
  line-height: 1.6;
}

.meta-billing-guide summary {
  cursor: pointer;
  font-weight: 600;
}

.meta-billing-guide p {
  margin: 12px 0;
}

.msg-delivery-pricing {
  margin-right: auto;
  font-size: 11px;
  line-height: 1.3;
  color: var(--color-text-muted);
}

.billing-launch-label {
  align-self: flex-start;
  padding: 3px 8px;
  border-radius: 6px;
  background: #e7f6eb;
  color: #206738;
  font-size: 12px;
  font-weight: 600;
}
/* Message-credit packs share the same catalogue across payment providers. */
.message-credit-picker fieldset {
  border: 0;
  padding: 0;
  margin: 0;
  min-width: 0;
}

.message-credit-picker legend {
  font-weight: 600;
  margin-bottom: 12px;
}

.message-credit-packs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
  gap: 10px;
}

.message-credit-pack {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px;
  border: 1px solid var(--color-border);
  border-radius: 10px;
  cursor: pointer;
}

.message-credit-pack.is-selected {
  border-color: var(--color-primary);
  background: var(--color-primary-soft);
}

.message-credit-pack input {
  flex-shrink: 0;
  accent-color: var(--color-primary);
}

.message-credit-pack > span:nth-child(2) {
  display: grid;
  gap: 4px;
  flex: 1;
}

.message-credit-discount {
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}

.message-credit-quantity {
  margin-top: 18px;
}

.message-credit-quantity > label {
  display: block;
  font-weight: 600;
  margin-bottom: 8px;
}

.message-credit-quantity input {
  width: 130px;
}

.message-credit-quantity p {
  font-size: 13px;
  margin-top: 8px;
}

.message-credit-total {
  margin-top: 16px;
}
.billing-summary { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; margin: 20px 0; }
.settings-page:has(.billing-summary) { max-width: none; }
:root[data-look='v2'] .settings-page:has(.billing-summary) .page-header { align-items: flex-start; text-align: left; }
.settings-page:has(.billing-summary) .settings-stack { gap: 20px; }
.billing-summary .billing-summary__icon { color: var(--color-primary); }
.billing-dashboard__aside .detail-row { grid-template-columns: minmax(0, 1fr) auto; gap: 10px; }
.billing-dashboard__aside .detail-row dd { overflow-wrap: normal; max-width: 140px; }
.billing-provider-details { margin-top: 14px; font-size: 13px; }
.billing-provider-details summary { cursor: pointer; color: var(--color-primary); padding: 8px 0; }
.billing-dashboard__main .billing-plan-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.billing-dashboard__main .billing-plan-tile { padding: 14px; }
.billing-dashboard__main .billing-plan-terms { font-size: 11px; }
.billing-dashboard__main .billing-plan-tile .btn { width: 100%; white-space: normal; }
@media (max-width: 760px) { .billing-dashboard__main .billing-plan-grid { grid-template-columns: minmax(0, 1fr); } }
.billing-summary__item { display: flex; align-items: flex-start; gap: 12px; padding: 20px 16px; margin: 0; min-width: 0; }
.billing-summary__item > div { min-width: 0; }
.billing-summary__icon { display: inline-flex; justify-content: center; align-items: center; flex-shrink: 0; width: 38px; height: 38px; background: var(--color-primary-soft); color: var(--color-primary); border-radius: 50%; }
.billing-summary__item span, .billing-summary__item small { font-size: 12px; color: var(--color-text-muted); }
.billing-summary__item strong { display: block; font-size: 21px; margin: 8px 0; overflow-wrap: anywhere; }
.billing-summary__item small { display: block; }
.billing-summary__track { height: 5px; background: var(--color-primary-soft); border-radius: 10px; margin: 10px 0; overflow: hidden; }
.billing-summary__track > span { display: block; height: 100%; background: var(--color-primary); }
.billing-dashboard { display: grid; grid-template-columns: minmax(0, 2.3fr) minmax(280px, 1fr); gap: 20px; align-items: start; }
.billing-dashboard__main, .billing-dashboard__aside { min-width: 0; display: flex; flex-direction: column; gap: 20px; }
.billing-dashboard .card { margin: 0; min-width: 0; }
.billing-dashboard .table-wrapper { max-width: 100%; overflow-x: auto; }
.billing-dashboard .card-header { font-size: 15px; }
.billing-dashboard__aside .form-helper, .billing-dashboard__aside p { font-size: 12px; }
@media (max-width: 1200px) { .billing-summary { grid-template-columns: repeat(2, minmax(0, 1fr)); } .billing-dashboard { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 600px) { .billing-summary { gap: 10px; } .billing-summary__item { padding: 14px 10px; gap: 8px; } .billing-summary__icon { width: 28px; height: 28px; } .billing-summary__item strong { font-size: 19px; } }
/* =========================================================================
   Test Session Recorder — the header pill and the account-menu section.

   Dev-only surface (contract §8.1): in production the feature flag is false,
   nothing here is ever rendered, and these ~90 lines are the whole cost.

   Everything below is tokens from variables.css. Two deliberate choices, both
   from the ui-ux-pro-max review:
     - RED means "recording", and never on its own — the dot always sits beside
       the word REC, and the degraded state says "not delivered" in words.
     - The pulse is a hint, not the signal, so prefers-reduced-motion drops it
       to a static dot with nothing lost.
   ========================================================================= */

/* ---- The header pill ------------------------------------------------- */

.qa-pill {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-xs);
  height: 32px;
  padding: 0 10px;
  border: 1px solid var(--color-danger);
  border-radius: var(--radius-full);
  background: var(--color-danger-soft);
  color: var(--color-danger-text);
  font-size: var(--font-size-xs);
  font-weight: 600;
  white-space: nowrap;
}

.qa-pill-dot {
  width: 8px;
  height: 8px;
  border-radius: var(--radius-full);
  background: var(--color-danger);
  animation: qa-pill-pulse 1.6s var(--ease-standard) infinite;
}

.qa-pill-label {
  letter-spacing: 0.06em;
}

.qa-pill-id {
  font-family: var(--font-mono);
  /* Tabular figures so the id does not jitter as the counter changes. */
  font-variant-numeric: tabular-nums;
  font-weight: 500;
}

/* The step in force. `min-width: 0` so it is the part that shrinks rather
   than pushing the pill out of the header, one line only, and the full value
   is always readable in the QA menu (.qa-menu-step) — never hover-only. */
.qa-pill-step {
  display: inline-flex;
  align-items: center;
  gap: var(--spacing-xs);
  min-width: 0;
  max-width: 12ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--font-mono);
  font-weight: 600;
}

.qa-pill-sep {
  opacity: 0.6;
}

.qa-pill.is-degraded {
  border-color: var(--color-warning);
  background: var(--color-warning-soft);
  color: var(--color-warning-text);
}

.qa-pill.is-degraded .qa-pill-dot {
  background: var(--color-warning);
}

@keyframes qa-pill-pulse {
  0%,
  100% { opacity: 1; }
  50% { opacity: 0.35; }
}

@media (prefers-reduced-motion: reduce) {
  .qa-pill-dot { animation: none; }
}

/* ---- The account-menu section ---------------------------------------- */

.qa-menu {
  min-width: 260px;
  padding: 10px 12px var(--spacing-sm);
  border-bottom: 1px solid var(--color-border);
  margin-bottom: var(--spacing-xs);
}

.qa-menu-heading {
  margin: 0 0 var(--spacing-xs);
  font-size: var(--font-size-xs);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-text-subtle);
}

.qa-menu-hint {
  margin: 0 0 var(--spacing-sm);
  font-size: var(--font-size-xs);
  line-height: var(--line-height-base);
  color: var(--color-text-muted);
}

.qa-menu-start { width: 100%; justify-content: center; }

/* The step in force, in full. Wraps rather than truncating — there is room
   here and truncating the one value this line exists to show would be absurd
   (ui-ux-pro-max: prefer wrapping over truncation). */
.qa-menu-step {
  margin: 0 0 var(--spacing-sm);
  font-size: var(--font-size-xs);
  line-height: var(--line-height-base);
  color: var(--color-text-muted);
  overflow-wrap: anywhere;
}

.qa-menu-step strong {
  font-family: var(--font-mono);
  color: var(--color-text);
}

/* The session id is a long token: let it wrap rather than push the menu wide. */
.qa-menu-id .copy-field-value {
  min-inline-size: 0;
  overflow-wrap: anywhere;
  font-variant-numeric: tabular-nums;
}

.qa-menu-id .form-group { margin-bottom: var(--spacing-sm); }

.qa-menu-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--spacing-xs);
}

.qa-menu-stop {
  width: 100%;
  justify-content: center;
  margin-top: var(--spacing-sm);
}

.qa-menu-note {
  display: flex;
  align-items: flex-start;
  gap: var(--spacing-xs);
  margin: var(--spacing-sm) 0 0;
  padding: var(--spacing-sm);
  border-radius: var(--radius-sm);
  background: var(--color-surface-sunken);
  font-size: var(--font-size-xs);
  line-height: var(--line-height-base);
  color: var(--color-text-muted);
}

.qa-menu-note svg { flex: none; margin-top: 2px; }

.qa-menu-note.is-degraded {
  background: var(--color-warning-soft);
  color: var(--color-warning-text);
}

.qa-menu-note.is-error {
  background: var(--color-danger-soft);
  color: var(--color-danger-text);
}

/* The Telescope fallback link. A blocked new tab cannot be detected, so the
   url is always offered inline; it has to read as pressable inside a note that
   otherwise is not. */
.qa-menu-note a {
  color: var(--color-primary);
  font-weight: 600;
  text-decoration: underline;
}

.qa-menu-note a:hover {
  color: var(--color-primary-hover);
}

/* Below 640px the header has no room for the id; REC keeps the state readable
   without relying on the colour of the dot. The STEP stays: the id is one tap
   away in the menu, and "which step am I on" is the question this pill exists
   to answer (S-2026-09-02-1 @R14). */
@media (max-width: 640px) {
  .qa-pill-id { display: none; }
}
/* Agency accounts (2b-2): register chooser, clients, client tag, grouped selector. */
/* =========================================================================
   Agency accounts (Phase 2b-2): the /register chooser, Clients, a client's
   page, the connect-number client step and the tidy-up page. Builds on
   components/ui and locations.css; only what they do not have lives here.
   ========================================================================= */

/* ---- /register chooser ---------------------------------------------------- */
.reg-choices { display: grid; gap: 12px; margin: 0; padding: 0; list-style: none; }
.reg-choice {
  display: grid;
  gap: 4px;
  min-height: 44px;
  padding: 16px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md, 10px);
  background: var(--color-surface, #fff);
  color: var(--color-text);
  text-decoration: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.reg-choice:hover { border-color: var(--color-primary); }
.reg-choice:focus-visible { outline: 3px solid var(--color-primary-soft-border); outline-offset: 2px; border-color: var(--color-primary); }
.reg-choice-title { font-weight: 700; color: var(--color-primary); }
.reg-choice-text { font-size: var(--font-size-sm); color: var(--color-text-muted); }

/* ---- Clients list --------------------------------------------------------- */
.cl-page .wz-tab { text-decoration: none; }
.cl-toolbar { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; justify-content: space-between; }
.cl-limit { margin: 0; color: var(--wz-text-secondary, #52627a); font-size: 14px; }
.cl-list { display: grid; gap: 12px; margin: 0; padding: 0; list-style: none; grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr)); }
.cl-card {
  display: grid;
  gap: 10px;
  align-content: start;
  min-width: 0;
  padding: 16px;
  border: 1px solid var(--wz-border, #dee6f0);
  border-radius: var(--wz-radius-card, 12px);
  background: var(--wz-surface, #fff);
}
.cl-card.is-archived { background: var(--wz-surface-muted, #f8fafc); }
.cl-card-head { display: flex; gap: 8px; align-items: flex-start; justify-content: space-between; min-width: 0; }
.cl-card-name { margin: 0; font-size: 16px; font-weight: 700; overflow-wrap: anywhere; }
.cl-card-name a { color: inherit; text-decoration: none; }
.cl-card-name a:hover { color: var(--wz-primary, #2563eb); text-decoration: underline; }
.cl-card-name a:focus-visible { outline: 3px solid var(--color-primary-soft-border, #bfdbfe); outline-offset: 2px; border-radius: 4px; }
.cl-counts { display: flex; flex-wrap: wrap; gap: 6px 14px; margin: 0; padding: 0; list-style: none; color: var(--wz-text-secondary, #52627a); font-size: 14px; }
.cl-card-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.cl-card-actions .btn { min-height: 44px; }
.cl-badge {
  flex: none;
  display: inline-flex;
  align-items: center;
  padding: 2px 10px;
  border-radius: 999px;
  background: #eef2f7;
  color: #334155;
  font-size: 12px;
  font-weight: 600;
  line-height: 20px;
}
.cl-section-title { margin: 8px 0 0; font-size: 15px; font-weight: 700; color: var(--wz-text-secondary, #52627a); }
.cl-form { display: grid; gap: 16px; }
.cl-error { margin: 0; color: #991b1b; font-size: 14px; }

/* ---- Client page ---------------------------------------------------------- */
.cl-crumb { display: inline-flex; align-items: center; gap: 4px; min-height: 44px; font-size: 14px; color: var(--wz-primary, #2563eb); text-decoration: none; }
.cl-crumb:hover { text-decoration: underline; }

/* ---- Members tab ---------------------------------------------------------- */
.cl-members { display: grid; gap: 16px; max-width: 720px; }
.cl-check-list { display: grid; gap: 0; margin: 0; padding: 0; list-style: none; border: 1px solid var(--wz-border, #dee6f0); border-radius: var(--wz-radius-input, 8px); }
.cl-check-list li + li { border-top: 1px solid var(--wz-border, #dee6f0); }
.cl-check {
  display: flex;
  gap: 12px;
  align-items: center;
  min-height: 48px;
  padding: 8px 14px;
  cursor: pointer;
}
.cl-check input { width: 20px; height: 20px; flex: none; }
.cl-check-text { display: grid; gap: 2px; min-width: 0; overflow-wrap: anywhere; }
.cl-check-sub { color: var(--wz-text-secondary, #52627a); font-size: 13px; }
.cl-readonly { margin: 0; padding: 0; list-style: none; display: grid; gap: 6px; }
.cl-readonly li { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.cl-actions-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }

/* ---- Connect-number client step ------------------------------------------ */
.cl-choice-list { display: grid; gap: 8px; margin: 0; padding: 0; border: 0; min-width: 0; }
.cl-choice-list legend { padding: 0; margin-bottom: 6px; font-weight: 700; }
.cl-radio {
  display: flex;
  gap: 12px;
  align-items: center;
  min-height: 48px;
  padding: 8px 14px;
  border: 1px solid var(--wz-border, #dee6f0);
  border-radius: var(--wz-radius-input, 8px);
  cursor: pointer;
}
.cl-radio:has(input:checked) { border-color: var(--wz-primary, #2563eb); background: var(--wz-primary-soft, #eff6ff); }
.cl-radio input { width: 20px; height: 20px; flex: none; }
.cl-chosen {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 12px;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px;
  border: 1px solid var(--wz-primary-border, #bfdbfe);
  border-radius: var(--wz-radius-input, 8px);
  background: var(--wz-primary-soft, #eff6ff);
}
.cl-chosen p { margin: 0; }

/* ---- Pending-client banner ------------------------------------------------ */
.cl-pending {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;
  padding: 12px 14px;
  border: 1px solid #fcd34d;
  border-radius: var(--wz-radius-input, 8px);
  background: #fffbeb;
  color: #78350f;
  font-size: 14px;
}
.cl-pending p { margin: 0; flex: 1 1 240px; }

/* ---- Grouped workspace selector: client headings ------------------------- */
.wz-scope-group {
  padding: 10px 12px 4px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--wz-text-secondary, #52627a);
  overflow-wrap: anywhere;
}
.wz-scope-group-list { margin: 0; padding: 0; list-style: none; }

/* ---- Client name in headers ---------------------------------------------- */
.cl-client-tag {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  max-width: 100%;
  padding: 2px 10px;
  border-radius: 999px;
  background: var(--wz-primary-soft, #eff6ff);
  color: #1e3a8a;
  font-size: 13px;
  font-weight: 600;
  overflow-wrap: anywhere;
}

/* ---- Tidy-up -------------------------------------------------------------- */
.tu-groups { display: grid; gap: 20px; }
.tu-group-title { margin: 0 0 8px; font-size: 16px; font-weight: 700; }
.tu-list { display: grid; gap: 0; margin: 0; padding: 0; list-style: none; border: 1px solid var(--wz-border, #dee6f0); border-radius: var(--wz-radius-input, 8px); }
.tu-item { display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: center; justify-content: space-between; padding: 10px 14px; }
.tu-item + .tu-item { border-top: 1px solid var(--wz-border, #dee6f0); }
.tu-item-name { min-width: 0; flex: 1 1 200px; overflow-wrap: anywhere; }
.tu-item .btn { min-height: 44px; }
.tu-preview { margin: 0; padding: 12px 14px; border-radius: var(--wz-radius-input, 8px); background: var(--wz-surface-muted, #f8fafc); border: 1px solid var(--wz-border, #dee6f0); }
.tu-preview ul { margin: 6px 0 0; padding-left: 20px; }
.tu-numbers { display: grid; gap: 6px; margin: 0; padding: 0; border: 0; min-width: 0; }

@media (prefers-reduced-motion: reduce) {
  .reg-choice { transition: none; }
}
/* =========================================================================
   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: 1023.98px) {
  /* Same line as the shell's drawer (look-v2.css, DESKTOP_QUERY). */
  .header-menu-btn { display: inline-flex; }

  /* Also shrinks the inbox height calc, which reads this token. */
  .app-shell { --content-padding: var(--spacing-md); }
  .notif-nudge,
  .app-alert { 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; }

  /* Icon only on a phone; the title and the hidden label still name it. */
  .header-support-btn {
    width: 40px;
    padding: 0;
    justify-content: center;
    border-color: transparent;
  }

  .header-support-label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .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); }
}
/* App design — every rule inside is scoped under :root[data-look="v2"] (set by MainLayout). */
/* =========================================================================
   NEW LOOK (modernisation Phase 1, brief Part 00 + Part 20, 17 Oct 2026)

   ⚠️ EVERY RULE IN THIS FILE IS SCOPED UNDER :root[data-look="v2"].
   This is the standard design for every business (Akmal, 17 Oct: the New
   look switch is removed). MainLayout always sets the attribute for the
   signed-in app. The scope stays because it makes these rules outrank the
   base styles they replace, and keeps the separate Shopify page (which
   shares main.css) on its own plain look. Never add an unscoped rule.

   Owner decisions applied: D1 Inter only · D2 sidebar 264px / 72px ·
   D4 canvas #F2F6FB. Token values are DS02; they are mapped onto the
   existing variable names so every current stylesheet picks them up.
   ========================================================================= */

:root[data-look="v2"] {
  /* ---- DS02 canonical tokens ---------------------------------------- */
  --wz-nav: #101c35;
  --wz-nav-hover: #1d2e50;
  --wz-nav-text: #c5d2e5;
  --wz-nav-muted: #899cb8;
  --wz-primary: #2563eb;
  --wz-primary-hover: #1d4ed8;
  --wz-primary-soft: #eff6ff;
  --wz-primary-border: #bfdbfe;
  --wz-canvas: #f2f6fb;
  --wz-surface: #ffffff;
  --wz-surface-muted: #f8fafc;
  --wz-text: #111c32;
  --wz-text-secondary: #52627a;
  --wz-text-muted: #748299;
  --wz-border: #dee6f0;
  --wz-border-strong: #c8d5e5;
  --wz-success: #15803d;
  --wz-success-soft: #dcfce7;
  --wz-warning: #b45309;
  --wz-warning-soft: #fef3c7;
  --wz-danger: #dc2626;
  --wz-danger-soft: #fee2e2;
  --wz-info: #2563eb;
  --wz-focus: #3b82f6;
  /* AI accent: used sparingly for AI features only (F9, P7, A8.11). */
  --wz-ai: #6d28d9;
  --wz-ai-soft: #f3eeff;
  --wz-ai-border: #ddd0fb;

  --wz-radius-input: 8px;
  --wz-radius-card: 14px;
  --wz-radius-modal: 18px;
  --wz-shadow-card: 0 1px 3px rgba(16, 28, 53, 0.06);
  --wz-shadow-hover: 0 4px 16px rgba(16, 28, 53, 0.08);

  /* DS09 motion */
  --wz-ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  --wz-dur-hover: 140ms;
  --wz-dur-tab: 180ms;
  --wz-dur-modal: 200ms;
  --wz-dur-drawer: 250ms;

  /* ---- Mapped onto the existing names ------------------------------- */
  --color-primary: var(--wz-primary);
  --color-primary-hover: var(--wz-primary-hover);
  --color-primary-soft: var(--wz-primary-soft);
  --color-primary-soft-border: var(--wz-primary-border);
  --color-brand-navy: var(--wz-nav);
  --color-brand-navy-soft: var(--wz-nav-hover);
  --color-bg: var(--wz-canvas);
  --color-surface-sunken: var(--wz-surface-muted);
  --color-border: var(--wz-border);
  --color-border-strong: var(--wz-border-strong);
  --color-text: var(--wz-text);
  --color-text-muted: var(--wz-text-secondary);
  /* --color-text-subtle stays #64748b: DS02's #748299 is 4.0:1 on white,
     under the 4.5:1 floor this product holds for labels. */
  --color-sidebar-bg: var(--wz-nav);
  --color-sidebar-text: var(--wz-nav-text);
  --color-sidebar-heading: var(--wz-nav-muted);
  --color-sidebar-hover: var(--wz-nav-hover);

  /* D1: Inter only — headings use the same family as body text. */
  --font-display: var(--font-sans);

  --radius-md: var(--wz-radius-card);
  --radius-lg: var(--wz-radius-modal);
  --shadow-sm: var(--wz-shadow-card);
  --shadow-md: var(--wz-shadow-hover);

  /* D2 + DS04 */
  --sidebar-width: 264px;
  --sidebar-width-collapsed: 72px;
  --header-height: 72px;
  --content-max: 1440px;
}

:root[data-look="v2"] body { background: var(--wz-canvas); }

/* ---- DS03 typography on the existing page markup ------------------------ */
:root[data-look="v2"] .page-title,
:root[data-look="v2"] .wz-page-title {
  font-size: 28px;
  line-height: 34px;
  font-weight: 700;
  letter-spacing: -0.025em;
  color: var(--wz-text);
}
:root[data-look="v2"] .page-subtitle,
:root[data-look="v2"] .wz-page-subtitle {
  font-size: 14px;
  line-height: 22px;
  color: var(--wz-text-secondary);
}
:root[data-look="v2"] .section-title { font-size: 20px; line-height: 28px; font-weight: 700; }
:root[data-look="v2"] .card-title,
:root[data-look="v2"] .card-header h2,
:root[data-look="v2"] .card-header h3 { font-size: 16px; line-height: 24px; font-weight: 600; }
:root[data-look="v2"] .page-header { margin-bottom: 24px; align-items: flex-end; }

/* ---- DS06/DS07 shared controls ------------------------------------------ */
:root[data-look="v2"] .card { border-color: var(--wz-border); box-shadow: var(--wz-shadow-card); }
:root[data-look="v2"] .card-interactive { transition: box-shadow var(--wz-dur-hover) var(--wz-ease), border-color var(--wz-dur-hover) var(--wz-ease); }
:root[data-look="v2"] .card-interactive:hover { box-shadow: var(--wz-shadow-hover); transform: none; }
:root[data-look="v2"] .form-control { border-radius: var(--wz-radius-input); border-color: var(--wz-border-strong); }
:root[data-look="v2"] .form-control:focus,
:root[data-look="v2"] .form-control:focus-visible { border-color: var(--wz-primary); box-shadow: 0 0 0 2px var(--wz-focus); outline: none; }
:root[data-look="v2"] .form-label { font-weight: 600; font-size: 14px; }
:root[data-look="v2"] .table th {
  background: var(--wz-surface-muted);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--wz-text-secondary);
}
:root[data-look="v2"] .modal-container { border-radius: var(--wz-radius-modal); }
:root[data-look="v2"] .btn { transition: background var(--wz-dur-hover) var(--wz-ease), border-color var(--wz-dur-hover) var(--wz-ease), box-shadow var(--wz-dur-hover) var(--wz-ease); }

/* ---- DS04 top bar -------------------------------------------------------- */
:root[data-look="v2"] .app-header {
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
  padding: 0 32px;
  gap: 16px;
}
:root[data-look="v2"] .app-header-leading { flex: 1; min-width: 0; }
:root[data-look="v2"] .notif-nudge { margin: 0; padding: 6px var(--content-padding); border-radius: 0; border-width: 0 0 1px; box-shadow: none; gap: 8px; }
:root[data-look="v2"] .notif-nudge-text { font-size: 13px; }
:root[data-look="v2"] .notif-nudge-actions .btn { min-height: 32px; padding: 4px 10px; font-size: 12px; }
/* Padding goes through --content-padding: the inbox sizes its full-height
   panes from it (inbox.css), so fixed values here would misalign it. */
:root[data-look="v2"] .wz-shell { --content-padding: 28px; }
/* Settings pages: the new sidebar already lists every settings page, so the
   in-page strip would be the same links twice (DS04). */
:root[data-look="v2"] .settings-nav { display: none; }

/* ---- Breadcrumb ---------------------------------------------------------- */
:root[data-look="v2"] .wz-breadcrumb ol {
  display: flex;
  align-items: center;
  gap: 6px;
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: 13px;
  color: var(--wz-text-secondary);
  min-width: 0;
  overflow: hidden;
}
/* Every crumb can shrink and clips its OWN text with an ellipsis — a crumb
   that shrank without clipping drew its words over the next one (three-part
   trails at 768). Earlier crumbs give way first; the current page last. */
:root[data-look="v2"] .wz-breadcrumb li { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; min-width: 0; flex: 0 1 auto; overflow: hidden; }
:root[data-look="v2"] .wz-breadcrumb li:last-child { flex-shrink: 0.25; }
:root[data-look="v2"] .wz-breadcrumb li > a,
:root[data-look="v2"] .wz-breadcrumb li > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
:root[data-look="v2"] .wz-breadcrumb li:last-child span { color: var(--wz-text); font-weight: 600; }
:root[data-look="v2"] .wz-breadcrumb a { color: inherit; text-decoration: none; }
:root[data-look="v2"] .wz-breadcrumb a:hover { color: var(--wz-primary); text-decoration: underline; }
:root[data-look="v2"] .wz-breadcrumb-sep { color: var(--wz-nav-muted); flex: none; }

/* ---- Sidebar (Part 20) --------------------------------------------------- */
:root[data-look="v2"] .wz-sidebar {
  width: var(--sidebar-width);
  flex-shrink: 0;
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--wz-nav);
  color: var(--wz-nav-text);
  transition: width 200ms var(--wz-ease);
  z-index: var(--z-drawer);
}
:root[data-look="v2"] .wz-sidebar-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  height: var(--header-height);
  padding: 0 12px 0 20px;
  flex: none;
}
:root[data-look="v2"] .wz-sidebar-brand-name { color: #fff; font-weight: 700; font-size: 20px; letter-spacing: -0.02em; flex: 1; }
:root[data-look="v2"] .wz-sidebar .wz-icon-btn { color: var(--wz-nav-text); }
:root[data-look="v2"] .wz-sidebar .wz-icon-btn:hover { background: var(--wz-nav-hover); color: #fff; }
:root[data-look="v2"] .wz-sidebar .wz-sidebar-close { display: none; }
:root[data-look="v2"] .wz-sidebar-scope { padding: 0 12px 8px; flex: none; }
:root[data-look="v2"] .wz-sidebar-nav { flex: 1; overflow-y: auto; overscroll-behavior: contain; padding: 4px 12px 12px; }
:root[data-look="v2"] .wz-sidebar-footer { flex: none; padding: 8px 12px 16px; border-top: 1px solid rgba(255, 255, 255, 0.08); }
:root[data-look="v2"] .wz-nav-heading {
  margin: 8px 12px 6px;
  font-size: 11px;
  line-height: 16px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--wz-nav-muted);
}
:root[data-look="v2"] .wz-nav-link {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 44px;
  padding: 0 12px;
  border: 0;
  border-radius: 8px;
  background: none;
  color: var(--wz-nav-text);
  font: inherit;
  font-size: 14px;
  line-height: 20px;
  font-weight: 500;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--wz-dur-hover) var(--wz-ease), color var(--wz-dur-hover) var(--wz-ease);
}
:root[data-look="v2"] .wz-nav-link:hover { background: var(--wz-nav-hover); color: #fff; }
:root[data-look="v2"] .wz-nav-link:focus-visible { outline: 2px solid var(--wz-focus); outline-offset: 2px; }
:root[data-look="v2"] .wz-nav-link.is-active { background: var(--wz-primary); color: #fff; font-weight: 600; }
:root[data-look="v2"] .wz-nav-icon { flex: none; }
:root[data-look="v2"] .wz-nav-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
:root[data-look="v2"] .wz-nav-caret { flex: none; transition: transform 140ms var(--wz-ease); }
:root[data-look="v2"] .wz-nav-toggle[aria-expanded="true"] .wz-nav-caret { transform: rotate(180deg); }
:root[data-look="v2"] .wz-nav-group.has-active > .wz-nav-toggle { color: #fff; }
:root[data-look="v2"] .wz-nav-sub { display: grid; gap: 2px; margin: 2px 0 6px; padding-left: 20px; }
:root[data-look="v2"] .wz-nav-sub .wz-nav-link { min-height: 40px; padding-left: 20px; }
:root[data-look="v2"] .wz-nav-sub .wz-nav-icon { display: none; }

/* Collapsed rail (desktop only) */
@media (min-width: 1024px) {
  :root[data-look="v2"] .wz-sidebar.is-collapsed { width: var(--sidebar-width-collapsed); }
  :root[data-look="v2"] .wz-sidebar.is-collapsed .wz-sidebar-brand { padding: 0; flex-direction: column; justify-content: center; gap: 4px; }
  :root[data-look="v2"] .wz-sidebar.is-collapsed .wz-sidebar-brand .brand-mark-on-dark { display: none; }
  :root[data-look="v2"] .wz-sidebar.is-collapsed .wz-sidebar-scope,
  :root[data-look="v2"] .wz-sidebar.is-collapsed .wz-sidebar-nav,
  :root[data-look="v2"] .wz-sidebar.is-collapsed .wz-sidebar-footer { padding-left: 8px; padding-right: 8px; }
  :root[data-look="v2"] .wz-sidebar.is-collapsed .wz-nav-link { justify-content: center; padding: 0; }
  :root[data-look="v2"] .wz-sidebar.is-collapsed .wz-nav-label,
  :root[data-look="v2"] .wz-sidebar.is-collapsed .wz-nav-caret,
  :root[data-look="v2"] .wz-sidebar.is-collapsed .wz-nav-heading { display: none; }
}

/* Tablet and phone: off-canvas drawer opened from the top bar (DS10). 1023.98
   (not 1023) so a zoomed 1023.5px window is never in neither mode; the shell
   uses the same 1024px line (DESKTOP_QUERY). */
@media (max-width: 1023.98px) {
  :root[data-look="v2"] .wz-sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    width: min(86vw, var(--sidebar-width));
    transform: translateX(-100%);
    transition: transform 220ms var(--wz-ease);
    box-shadow: var(--shadow-lg);
  }
  :root[data-look="v2"] .wz-sidebar.is-open { transform: translateX(0); }
  :root[data-look="v2"] .wz-sidebar .wz-sidebar-collapse { display: none; }
  :root[data-look="v2"] .wz-sidebar .wz-sidebar-close { display: inline-flex; }
  :root[data-look="v2"] .app-header { padding: 0 20px; }
  :root[data-look="v2"] .wz-shell { --content-padding: 24px; }
}
@media (max-width: 767px) {
  :root[data-look="v2"] .app-header { padding: 0 12px; gap: 8px; }
  :root[data-look="v2"] .wz-shell { --content-padding: 16px; }
  :root[data-look="v2"] .page-title,
  :root[data-look="v2"] .wz-page-title { font-size: 24px; line-height: 30px; }
  /* The trail is too long for a phone header; the page title says where you are. */
  :root[data-look="v2"] .app-header-leading .wz-breadcrumb li:not(:last-child) { display: none; }
}

/* ---- Scope switcher ------------------------------------------------------ */
:root[data-look="v2"] .wz-scope-wrap { position: relative; }
:root[data-look="v2"] .wz-scope {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 56px;
  padding: 8px 10px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.04);
  color: #fff;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
:root[data-look="v2"] button.wz-scope:hover { background: var(--wz-nav-hover); }
:root[data-look="v2"] button.wz-scope:focus-visible { outline: 2px solid var(--wz-focus); outline-offset: 2px; }
:root[data-look="v2"] .wz-scope.is-static { cursor: default; }
:root[data-look="v2"] .wz-scope-avatar {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 8px;
  background: var(--scope-color, var(--wz-primary));
  color: #fff;
  font-weight: 700;
  font-size: 14px;
}
:root[data-look="v2"] .wz-scope-text { display: grid; min-width: 0; flex: 1; }
/* Wraps instead of clipping: a business account's label ends with the number
   ("Andheri · Sales · …0101", Part 20.12) and that ending must stay visible. */
:root[data-look="v2"] .wz-scope-title { font-weight: 600; font-size: 14px; overflow-wrap: anywhere; }
:root[data-look="v2"] .wz-scope-sub { display: flex; gap: 8px; align-items: center; font-size: 12px; color: var(--wz-nav-muted); white-space: nowrap; }
:root[data-look="v2"] .wz-scope-caret { flex: none; color: var(--wz-nav-text); }
:root[data-look="v2"] .wz-scope-conn { display: inline-flex; align-items: center; gap: 4px; }
:root[data-look="v2"] .wz-scope-dot { width: 7px; height: 7px; border-radius: 50%; background: #94a3b8; }
:root[data-look="v2"] .wz-scope-conn.is-on .wz-scope-dot { background: #22c55e; }
:root[data-look="v2"] .wz-scope-conn.is-off .wz-scope-dot { background: #f59e0b; }
:root[data-look="v2"] .wz-scope-list {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  width: max(100%, 260px);
  max-height: 60vh;
  overflow-y: auto;
  margin: 0;
  padding: 6px;
  list-style: none;
  background: var(--wz-surface);
  border: 1px solid var(--wz-border);
  border-radius: 12px;
  box-shadow: var(--shadow-lg);
  z-index: calc(var(--z-drawer) + 1);
  animation: wz-pop 160ms var(--wz-ease);
}
:root[data-look="v2"] .wz-sidebar.is-collapsed .wz-scope-list { left: calc(100% + 8px); top: 0; }
:root[data-look="v2"] .wz-scope-option {
  display: grid;
  gap: 2px;
  width: 100%;
  padding: 10px 12px;
  border: 0;
  border-radius: 8px;
  background: none;
  font: inherit;
  text-align: left;
  color: var(--wz-text);
  cursor: pointer;
}
:root[data-look="v2"] .wz-scope-option:hover,
:root[data-look="v2"] .wz-scope-option:focus-visible { background: var(--wz-primary-soft); outline: none; }
:root[data-look="v2"] .wz-scope-option.is-selected { box-shadow: inset 3px 0 0 var(--wz-primary); background: var(--wz-primary-soft); }
:root[data-look="v2"] .wz-scope-option-title { font-weight: 600; font-size: 14px; }
:root[data-look="v2"] .wz-scope-option-sub { display: flex; gap: 8px; font-size: 12px; color: var(--wz-text-secondary); }
:root[data-look="v2"] .wz-scope-option .wz-scope-conn.is-on { color: var(--wz-success); }
:root[data-look="v2"] .wz-scope-option .wz-scope-conn.is-off { color: var(--wz-warning); }

@keyframes wz-pop {
  from { opacity: 0; transform: translateY(-4px) scale(0.98); }
  to { opacity: 1; transform: none; }
}

/* ---- DS09: honour reduced motion everywhere in the app ------------------ */
@media (prefers-reduced-motion: reduce) {
  :root[data-look="v2"] *,
  :root[data-look="v2"] *::before,
  :root[data-look="v2"] *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }
}
/* =========================================================================
   NEW LOOK — shared building blocks (components/ui, brief DS11).
   ⚠️ Scoped under :root[data-look="v2"], like look-v2.css. Pages never
   restyle these individually; change them here or not at all.
   ========================================================================= */

/* ---- Page header ---------------------------------------------------------- */
:root[data-look="v2"] .wz-page { display: grid; gap: 20px; }
:root[data-look="v2"] .wz-page-header { display: grid; gap: 8px; margin-bottom: 4px; }
:root[data-look="v2"] .wz-page-header-row { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
:root[data-look="v2"] .wz-page-header-text { min-width: 0; flex: 1 1 320px; }
:root[data-look="v2"] .wz-page-title { margin: 0; }
:root[data-look="v2"] .wz-page-subtitle { margin: 4px 0 0; max-width: 72ch; }
:root[data-look="v2"] .wz-page-scope { margin-top: 8px; }
:root[data-look="v2"] .wz-page-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }

/* ---- Tabs (DS06) ---------------------------------------------------------- */
:root[data-look="v2"] .wz-tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--wz-border);
  overflow-x: auto;
  /* overflow-x alone makes the strip scroll vertically too (the active line
     sits 1px below it), which showed a stray scrollbar thumb on phones. */
  overflow-y: hidden;
  scrollbar-width: thin;
}
:root[data-look="v2"] .wz-tab {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  padding: 0 14px;
  border: 0;
  background: none;
  font: inherit;
  font-size: 14px;
  font-weight: 500;
  color: var(--wz-text-secondary);
  white-space: nowrap;
  cursor: pointer;
}
:root[data-look="v2"] .wz-tab::after {
  content: '';
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: -1px;
  height: 3px;
  border-radius: 3px 3px 0 0;
  background: transparent;
  transition: background var(--wz-dur-tab) var(--wz-ease);
}
:root[data-look="v2"] .wz-tab:hover { color: var(--wz-text); }
:root[data-look="v2"] .wz-tab.is-active { color: var(--wz-primary); font-weight: 600; }
:root[data-look="v2"] .wz-tab.is-active::after { background: var(--wz-primary); }
:root[data-look="v2"] .wz-tab:focus-visible { outline: 2px solid var(--wz-focus); outline-offset: -2px; border-radius: 6px; }
:root[data-look="v2"] .wz-tab-count {
  padding: 0 7px;
  border-radius: 999px;
  background: var(--wz-surface-muted);
  border: 1px solid var(--wz-border);
  font-size: 12px;
  line-height: 18px;
  color: var(--wz-text-secondary);
}

/* ---- Card + KPI (DS05/DS07) ---------------------------------------------- */
:root[data-look="v2"] .wz-card {
  background: var(--wz-surface);
  border: 1px solid var(--wz-border);
  border-radius: var(--wz-radius-card);
  box-shadow: var(--wz-shadow-card);
  min-width: 0;
}
:root[data-look="v2"] .wz-card-header { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: flex-start; gap: 12px; padding: 20px 24px 0; }
/* The text takes the room; when the actions no longer fit beside a readable
   line they wrap below it instead of squeezing it into a narrow column. */
:root[data-look="v2"] .wz-card-header > div:first-child { flex: 1 1 260px; min-width: 0; }
:root[data-look="v2"] .wz-card-title { margin: 0; font-size: 16px; line-height: 24px; font-weight: 600; }
:root[data-look="v2"] .wz-card-subtitle { margin: 2px 0 0; font-size: 13px; color: var(--wz-text-secondary); }
:root[data-look="v2"] .wz-card-actions { display: flex; flex-wrap: wrap; gap: 8px; }
@media (max-width: 767px) {
  :root[data-look="v2"] .wz-card-header { padding: 16px 16px 0; }
  :root[data-look="v2"] .wz-card-actions { width: 100%; }
  :root[data-look="v2"] .wz-card-actions > .btn { flex: 1 1 auto; justify-content: center; min-height: 44px; }
  :root[data-look="v2"] .wz-card-body { padding: 16px; }
}
:root[data-look="v2"] .wz-card-body { padding: 16px 24px 20px; }
:root[data-look="v2"] .wz-card-footer { padding: 12px 24px; border-top: 1px solid var(--wz-border); }
:root[data-look="v2"] .wz-kpi {
  display: grid;
  gap: 4px;
  padding: 16px 20px;
  background: var(--wz-surface);
  border: 1px solid var(--wz-border);
  border-radius: var(--wz-radius-card);
  box-shadow: var(--wz-shadow-card);
  color: inherit;
  text-decoration: none;
}
:root[data-look="v2"] .wz-kpi.is-link { transition: box-shadow var(--wz-dur-hover) var(--wz-ease), border-color var(--wz-dur-hover) var(--wz-ease); }
:root[data-look="v2"] .wz-kpi.is-link:hover { box-shadow: var(--wz-shadow-hover); border-color: var(--wz-primary-border); }
:root[data-look="v2"] .wz-kpi-label { font-size: 13px; font-weight: 600; color: var(--wz-text-secondary); }
:root[data-look="v2"] .wz-kpi-value { font-size: 28px; line-height: 36px; font-weight: 700; font-variant-numeric: tabular-nums; }
:root[data-look="v2"] .wz-kpi-unit { margin-left: 4px; font-size: 13px; font-weight: 500; color: var(--wz-text-secondary); }
:root[data-look="v2"] .wz-kpi-note { font-size: 12px; color: var(--wz-text-secondary); }

/* ---- Status badge (DS06) -------------------------------------------------- */
:root[data-look="v2"] .wz-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 2px 10px;
  border-radius: 999px;
  font-size: 12px;
  line-height: 20px;
  font-weight: 600;
  white-space: nowrap;
}
:root[data-look="v2"] .wz-badge-dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
:root[data-look="v2"] .wz-badge-success { background: var(--wz-success-soft); color: #14532d; }
:root[data-look="v2"] .wz-badge-warning { background: var(--wz-warning-soft); color: #78350f; }
:root[data-look="v2"] .wz-badge-danger { background: var(--wz-danger-soft); color: #991b1b; }
:root[data-look="v2"] .wz-badge-info { background: var(--wz-primary-soft); color: #1e40af; }
:root[data-look="v2"] .wz-badge-neutral { background: #eef2f7; color: #334155; }
:root[data-look="v2"] .wz-badge-ai { background: var(--wz-ai-soft); color: var(--wz-ai); }

/* ---- Form field (DS06) ---------------------------------------------------- */
:root[data-look="v2"] .wz-field { display: grid; gap: 8px; }
:root[data-look="v2"] .wz-field-label { font-size: 14px; font-weight: 600; color: var(--wz-text); }
:root[data-look="v2"] .wz-required { color: var(--wz-danger); }
:root[data-look="v2"] .wz-field-help { margin: 0; font-size: 13px; color: var(--wz-text-secondary); }
:root[data-look="v2"] .wz-field-error { display: flex; gap: 6px; align-items: center; margin: 0; font-size: 13px; color: #991b1b; }
:root[data-look="v2"] .wz-field.has-error .form-control { border-color: var(--wz-danger); }

/* ---- Icon button --------------------------------------------------------- */
:root[data-look="v2"] .wz-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border: 0;
  border-radius: 8px;
  background: none;
  color: var(--wz-text-secondary);
  cursor: pointer;
  transition: background var(--wz-dur-hover) var(--wz-ease), color var(--wz-dur-hover) var(--wz-ease);
}
:root[data-look="v2"] .wz-icon-btn:hover { background: var(--wz-surface-muted); color: var(--wz-text); }
:root[data-look="v2"] .wz-icon-btn:focus-visible { outline: 2px solid var(--wz-focus); outline-offset: 1px; }

/* ---- Drawer (DS08) -------------------------------------------------------- */
:root[data-look="v2"] .wz-drawer-layer { position: fixed; inset: 0; z-index: var(--z-modal); }
:root[data-look="v2"] .wz-drawer-scrim { position: absolute; inset: 0; background: rgba(16, 28, 53, 0.45); animation: wz-fade 160ms var(--wz-ease); }
:root[data-look="v2"] .wz-drawer {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: min(480px, 100vw);
  max-width: 100vw;
  display: flex;
  flex-direction: column;
  background: var(--wz-surface);
  box-shadow: -12px 0 32px rgba(16, 28, 53, 0.16);
  animation: wz-slide 250ms var(--wz-ease);
}
:root[data-look="v2"] .wz-drawer.is-wide { width: min(max(520px, 40vw), 100vw); }
:root[data-look="v2"] .wz-drawer-header { display: flex; justify-content: space-between; gap: 12px; padding: 20px 24px; border-bottom: 1px solid var(--wz-border); }
:root[data-look="v2"] .wz-drawer-title { margin: 0; font-size: 18px; line-height: 26px; font-weight: 700; }
:root[data-look="v2"] .wz-drawer-subtitle { margin: 2px 0 0; font-size: 13px; color: var(--wz-text-secondary); }
:root[data-look="v2"] .wz-drawer-body { flex: 1; overflow-y: auto; padding: 20px 24px; }
:root[data-look="v2"] .wz-drawer-footer { display: flex; justify-content: flex-end; gap: 8px; padding: 16px 24px; border-top: 1px solid var(--wz-border); }

@keyframes wz-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes wz-slide { from { transform: translateX(24px); opacity: 0; } to { transform: none; opacity: 1; } }

/* ---- Sticky actions ------------------------------------------------------- */
:root[data-look="v2"] .wz-sticky-actions {
  position: sticky;
  bottom: 0;
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 12px 0;
  padding-bottom: max(12px, env(safe-area-inset-bottom));
  background: linear-gradient(to bottom, transparent, var(--wz-canvas) 30%);
}

/* ---- Skeleton + error panel ---------------------------------------------- */
:root[data-look="v2"] .wz-skeleton-group { display: grid; gap: 8px; }
:root[data-look="v2"] .wz-skeleton {
  display: block;
  border-radius: 6px;
  background: linear-gradient(90deg, #e8eef6 0%, #f3f6fa 50%, #e8eef6 100%);
  background-size: 200% 100%;
  animation: wz-shimmer 1.4s linear infinite;
}
@keyframes wz-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }
:root[data-look="v2"] .wz-error-panel {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 16px 20px;
  border: 1px solid #fecaca;
  border-radius: var(--wz-radius-card);
  background: #fff7f7;
  color: #991b1b;
}
:root[data-look="v2"] .wz-error-panel > div { flex: 1; }
:root[data-look="v2"] .wz-error-title { margin: 0; font-weight: 600; }
:root[data-look="v2"] .wz-error-message { margin: 2px 0 0; font-size: 13px; color: #7f1d1d; }

/* ---- Menu (anchored, 160–240px) ------------------------------------------ */
:root[data-look="v2"] .wz-menu { position: relative; display: inline-flex; }
:root[data-look="v2"] .wz-menu-list {
  position: absolute;
  top: calc(100% + 4px);
  min-width: 200px;
  max-width: 260px;
  padding: 6px;
  background: var(--wz-surface);
  border: 1px solid var(--wz-border);
  border-radius: 10px;
  box-shadow: var(--shadow-lg);
  z-index: var(--z-modal);
  animation: wz-pop 140ms var(--wz-ease);
}
:root[data-look="v2"] .wz-menu-list.align-end { right: 0; }
:root[data-look="v2"] .wz-menu-list.align-start { left: 0; }
:root[data-look="v2"] .wz-menu-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 40px;
  padding: 0 10px;
  border: 0;
  border-radius: 6px;
  background: none;
  font: inherit;
  font-size: 14px;
  color: var(--wz-text);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}
:root[data-look="v2"] .wz-menu-item:hover,
:root[data-look="v2"] .wz-menu-item:focus-visible { background: var(--wz-surface-muted); outline: none; }
:root[data-look="v2"] .wz-menu-item.is-danger { color: var(--wz-danger); }
:root[data-look="v2"] .wz-menu-sep { height: 1px; margin: 6px 4px; background: var(--wz-border); }

/* ---- Data table (DS07) ---------------------------------------------------- */
:root[data-look="v2"] .wz-table-wrap { overflow-x: auto; border: 1px solid var(--wz-border); border-radius: var(--wz-radius-card); background: var(--wz-surface); }
:root[data-look="v2"] .wz-table { width: 100%; border-collapse: collapse; font-size: 14px; }
:root[data-look="v2"] .wz-table th {
  padding: 12px 16px;
  background: var(--wz-surface-muted);
  border-bottom: 1px solid var(--wz-border);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--wz-text-secondary);
  text-align: left;
  white-space: nowrap;
}
:root[data-look="v2"] .wz-table td { height: 52px; padding: 8px 16px; border-bottom: 1px solid var(--wz-border); vertical-align: middle; }
:root[data-look="v2"] .wz-table tr:last-child td { border-bottom: 0; }
:root[data-look="v2"] .wz-table tbody tr { transition: background 120ms var(--wz-ease); }
:root[data-look="v2"] .wz-table tbody tr:hover { background: #f9fbfe; }
:root[data-look="v2"] .wz-table .is-numeric { text-align: right; font-variant-numeric: tabular-nums; }
:root[data-look="v2"] .wz-table-empty { margin: 0; padding: 24px; text-align: center; color: var(--wz-text-secondary); }
@media (max-width: 767px) {
  :root[data-look="v2"] .wz-table thead { display: none; }
  :root[data-look="v2"] .wz-table tr { display: grid; gap: 6px; padding: 12px 16px; border-bottom: 1px solid var(--wz-border); }
  :root[data-look="v2"] .wz-table td { display: flex; justify-content: space-between; gap: 12px; height: auto; padding: 0; border: 0; }
  :root[data-look="v2"] .wz-table td::before { content: attr(data-label); font-size: 12px; font-weight: 600; color: var(--wz-text-secondary); }
  :root[data-look="v2"] .wz-table .is-numeric { text-align: left; }
}

/* ---- Filter bar ----------------------------------------------------------- */
:root[data-look="v2"] .wz-filter-bar { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
:root[data-look="v2"] .wz-filter-bar .form-control { width: auto; min-width: 160px; flex: 0 1 auto; }
:root[data-look="v2"] .wz-filter-bar .wz-filter-search { flex: 1 1 260px; }

/* ---- Design reference page (features/DesignReference) --------------------- */
:root[data-look="v2"] .wz-ref-grid { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); }
:root[data-look="v2"] .wz-ref-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }

/* ---- Business isolation states (Phase 2b-1) ------------------------------- */
:root[data-look="v2"] .wz-notice {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin: 0 0 16px;
  padding: 12px 16px;
  border: 1px solid var(--wz-border);
  border-radius: var(--wz-radius-card);
  font-size: 14px;
}
:root[data-look="v2"] .wz-notice > .icon { flex: none; margin-top: 2px; }
:root[data-look="v2"] .wz-notice > div { flex: 1; min-width: 0; overflow-wrap: anywhere; }
:root[data-look="v2"] .wz-notice.is-warning { border-color: #fcd34d; background: var(--wz-warning-soft); color: #78350f; }
:root[data-look="v2"] .wz-notice.is-info { border-color: var(--wz-primary-border, #bfdbfe); background: var(--wz-primary-soft); color: #1e3a8a; }
:root[data-look="v2"] .wz-notice-title { margin: 0; font-weight: 600; }
:root[data-look="v2"] .wz-notice-text { margin: 2px 0 0; }
:root[data-look="v2"] .wz-notice-help { margin: 4px 0 0; font-size: 13px; opacity: 0.9; }
:root[data-look="v2"] .wz-hold-line {
  display: flex;
  align-items: flex-start;
  gap: 6px;
  margin: 4px 0 0;
  font-size: 13px;
  color: #78350f;
  white-space: normal;
  overflow-wrap: anywhere;
}
:root[data-look="v2"] .wz-hold-line .icon { flex: none; margin-top: 2px; }
:root[data-look="v2"] .wz-not-available { padding: 24px 0; }
:root[data-look="v2"] .wz-hold-badge { margin: 4px 0 0; white-space: nowrap; }
:root[data-look="v2"] td > .bc-badge + .wz-hold-badge { margin-left: 4px; }
