/* ═══════════════════════════════════════════════════════
   PulsifyAI Master CRM — Design System v2 (premium light)
   ═══════════════════════════════════════════════════════
   shadcn/Vercel register: near-white canvas, white cards with
   zinc hairline borders, restrained Action Blue, Inter, soft
   1-2px shadows. SKIN ONLY — no layout, spacing or DOM changes.

   Scope: body.ds-v2 — toggled by the router for the tabs under
   test (Overview + Clients & VPS). Other tabs keep the legacy
   neumorphic theme until v2 is approved.

   Core trick: the legacy components lean on the neumorphic
   shadow tokens for elevation. Redefining those tokens as a
   1px zinc ring (box-shadow spread) + a soft shadcn drop
   converts every "raised" surface into a bordered flat card
   with zero structural edits.
   ═══════════════════════════════════════════════════════ */

body.ds-v2 {
  /* ── Surfaces (Vercel: #fafafa canvas, white cards) ── */
  --bg-base: #fafafa;
  --bg-card: #ffffff;
  --bg-card-2: #f4f4f5;
  --bg-sidebar: #fafafa;

  /* ── Text (zinc) ── */
  --text-primary: #09090b;
  --text-secondary: #52525b;
  --text-tertiary: #a1a1aa;
  --text-accent: #2563eb;

  /* ── Accent (Action Blue; darker on hover for light surfaces) ── */
  --accent: #2563eb;
  --accent-hover: #1d4ed8;
  --accent-light: rgba(37, 99, 235, 0.08);
  --accent-glow: rgba(37, 99, 235, 0.18);

  /* ── Hairlines (zinc-200 / zinc-300) ── */
  --line: #e4e4e7;
  --line-strong: #d4d4d8;

  /* ── Elevation: zinc ring + shadcn-soft drop (replaces neumorphism) ── */
  --shadow-light: rgba(255, 255, 255, 0.9);
  --shadow-dark: rgba(9, 9, 11, 0.10);
  --shadow-raised: 0 0 0 1px var(--line), 0 1px 2px rgba(9, 9, 11, 0.05), 0 4px 12px -4px rgba(9, 9, 11, 0.06);
  --shadow-raised-sm: 0 0 0 1px var(--line), 0 1px 2px rgba(9, 9, 11, 0.04);
  --shadow-pressed: inset 0 0 0 1px var(--line);
  --shadow-flat: 0 0 0 1px var(--line);

  /* ── Status (light-surface variants per DESIGN.md) ── */
  --success: #059669;
  --success-bg: rgba(5, 150, 105, 0.08);
  --danger: #dc2626;
  --danger-bg: rgba(220, 38, 38, 0.08);
  --warning: #d97706;
  --warning-bg: rgba(217, 119, 6, 0.10);

  /* ── Cliente 360 "dossier" ──────────────────────────────
     The 360 keeps its editorial register (warm paper, ledger
     rules) rather than the zinc chrome — it reads as a document,
     not a screen. Tokenised here so it follows the theme instead
     of staying a cream slab in dark mode. */
  --ed-bg: #f5f2ea;
  --ed-paper: #ffffff;
  --ed-paper-2: #fbf9f3;
  --ed-tint: #f0ece0;
  --ed-ink: #1b1b1b;
  --ed-ink-2: #3a352c;
  --ed-muted: #6d685e;
  --ed-faint: #9b9384;
  --ed-hair: #e5e1d5;
  --ed-hair-2: #d8d2c2;
  --ed-accent: #bb4a20;
  --ed-accent-soft: #f3e4d8;
  --ed-good: #3e6b4d;
  --ed-warn: #c98e3d;
  --ed-crit: #a63d33;
  --ed-blue: #3c5a78;
  /* inverted margin tile */
  --ed-inv-bg: #1b1b1b;
  --ed-inv-label: #c8bfa8;
  --ed-inv-value: #ffffff;
  --ed-inv-sub: #a89e86;
  /* provider swatches */
  --ed-p-el: #2a2520;
  --ed-p-or: #6b7a52;
  --ed-p-zad: #bb4a20;
  --ed-p-tw: #a6564e;

  /* ── Client-type dots (360 taxonomy: voz / legacy / storage / teste) ── */
  --type-voice: #2563eb;
  --type-voice-ring: rgba(37, 99, 235, 0.15);
  --type-legacy: #8b5cf6;
  --type-legacy-ring: rgba(139, 92, 246, 0.15);
  --type-storage: #0891b2;
  --type-storage-ring: rgba(8, 145, 178, 0.15);
  --type-test: #a1a1aa;
  --type-test-ring: rgba(161, 161, 170, 0.15);

  background: var(--bg-base);
  color: var(--text-primary);
  /* Native controls (date/number/select/checkbox/scrollbar) follow the theme */
  color-scheme: light;
}

/* Raised/flat surfaces become white cards above the canvas */
body.ds-v2 .nm-raised,
body.ds-v2 .nm-raised-sm,
body.ds-v2 .nm-flat {
  background: var(--bg-card);
}
body.ds-v2 .nm-pressed {
  background: var(--bg-card);
}

/* ═══════════ Shell ═══════════ */

body.ds-v2 .sidebar {
  background: var(--bg-sidebar);
  border-right: 1px solid var(--line);
  box-shadow: none;
}
/* Brand lockup — mark + two-tone wordmark. The dim half keeps the logo
   reading as a label at 15px instead of shouting like a banner. */
body.ds-v2 .sidebar-brand { text-decoration: none; }
body.ds-v2 .sidebar-wordmark { color: var(--text-primary); }
/* "PulsifyAI" é uma palavra só: o "AI" leva o mesmo branco e o mesmo peso do
   resto da marca. Só "CRM", que nomeia o produto e não a marca, recua. */
body.ds-v2 .sidebar-wordmark-dim { color: inherit; font-weight: inherit; }
body.ds-v2 .sidebar-wordmark-crm { color: var(--text-tertiary); font-weight: 500; }
body.ds-v2 .sidebar-collapse:hover { background: rgba(9, 9, 11, 0.045); }
body.ds-v2 .sidebar-footer { border-top: 1px solid var(--line); }

body.ds-v2 .nav-section-label { color: var(--text-tertiary); }

body.ds-v2 .nav-item {
  font-weight: 500;
  border-radius: 12px;
  color: var(--text-secondary);
}
body.ds-v2 .nav-item:hover {
  background: rgba(9, 9, 11, 0.045);
  box-shadow: none;
  color: var(--text-primary);
}
body.ds-v2 .nav-item.active {
  background: #ffffff;
  box-shadow: 0 0 0 1px var(--line), 0 1px 2px rgba(9, 9, 11, 0.04);
  color: var(--text-primary);
  font-weight: 600;
}
body.ds-v2 .nav-item.active::before { display: none; }
body.ds-v2 .nav-item.active .nav-icon { color: var(--accent); opacity: 1; }

body.ds-v2 .sidebar-avatar {
  background: linear-gradient(135deg, #3b82f6, #2563eb);
  box-shadow: 0 4px 12px -4px rgba(37, 99, 235, 0.5);
}
body.ds-v2 .sidebar-logout {
  box-shadow: inset 0 0 0 1px var(--line);
  background: transparent;
}
body.ds-v2 .sidebar-logout:hover {
  box-shadow: inset 0 0 0 1px rgba(220, 38, 38, 0.30);
  background: var(--danger-bg);
  color: var(--danger);
}

/* Mobile chrome */
body.ds-v2 .mobile-header,
body.ds-v2 .mobile-bottom-nav {
  background: rgba(250, 250, 250, 0.9);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  box-shadow: none;
  border-bottom: 1px solid var(--line);
}
body.ds-v2 .mobile-bottom-nav { border-bottom: none; border-top: 1px solid var(--line); }
body.ds-v2 .btn-hamburger { box-shadow: var(--shadow-raised-sm); background: var(--bg-card); }
body.ds-v2 .sidebar-overlay { background: rgba(9, 9, 11, 0.30); }
body.ds-v2 .sidebar.open { box-shadow: 16px 0 48px rgba(9, 9, 11, 0.12); }

/* ═══════════ Login ═══════════
   The one screen the DS v2 migration had missed: it was still a neumorphic
   card (--shadow-raised) on a DS v2 canvas. Now the same ring + soft shadow
   as every other surface, and it follows the persisted theme. */

body.ds-v2 .login-card {
  box-shadow: var(--elev-overlay);
  border: 1px solid transparent; /* the ring IS the border — see §2 */
}

body.ds-v2 .login-wordmark-dim { color: var(--text-tertiary); font-weight: 600; }

/* Provider button: neutral surface + hairline, never the app accent. Google's
   own mark supplies the only colour, which is exactly the point. */
body.ds-v2 .login-google {
  box-shadow: inset 0 0 0 1px var(--line), 0 1px 2px rgba(9, 9, 11, 0.04);
}
body.ds-v2 .login-google:hover:not([disabled]) {
  background: var(--bg-card-2);
  box-shadow: inset 0 0 0 1px var(--line-strong), 0 1px 2px rgba(9, 9, 11, 0.06);
}
body.ds-v2 .login-google:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 1px var(--accent), 0 0 0 3px var(--accent-light);
}

body.ds-v2 .login-foot { border-top: 1px solid var(--line); }

body.ds-v2 .login-error {
  box-shadow: inset 0 0 0 1px rgba(220, 38, 38, 0.22);
  background: var(--danger-bg);
  color: var(--danger);
  border-radius: 10px;
  padding: 10px 14px;
  margin-bottom: 16px;
  text-align: left;
  font-size: 0.8125rem;
  line-height: 1.45;
}

/* ═══════════ Page chrome ═══════════ */

/* One page-title treatment for every tab. Pages that render a bare <h1>
   (Mapping, Portal, Billing, Cost Calc, Drive) inherited the ~2rem browser
   default with stray margins; this pins them to the same scale/weight as the
   icon-prefixed .page-title used by Overview/Clients/VPS. */
body.ds-v2 .page-header h1 {
  font-size: 1.6rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.2;
  color: var(--text-primary);
  margin: 0;
}
body.ds-v2 .page-title { letter-spacing: -0.02em; font-weight: 700; }
body.ds-v2 .page-subtitle { color: var(--text-secondary); }
body.ds-v2 .page-title-icon {
  background: var(--bg-card);
  box-shadow: var(--shadow-raised-sm);
}
body.ds-v2 .search-bar {
  background: var(--bg-card);
  box-shadow: inset 0 0 0 1px var(--line);
  border-radius: 10px;
  transition: box-shadow var(--transition-fast);
}
body.ds-v2 .search-bar:focus-within {
  box-shadow: inset 0 0 0 1px var(--accent), 0 0 0 3px var(--accent-light);
}

/* ═══════════ Buttons ═══════════ */

body.ds-v2 .btn { border-radius: 10px; font-weight: 600; }
body.ds-v2 .btn-raised {
  background: var(--bg-card);
  box-shadow: 0 0 0 1px var(--line), 0 1px 2px rgba(9, 9, 11, 0.04);
  color: var(--text-primary);
}
body.ds-v2 .btn-raised:hover {
  box-shadow: 0 0 0 1px var(--line-strong), 0 1px 2px rgba(9, 9, 11, 0.06);
  background: var(--bg-card-2);
  transform: none;
}
body.ds-v2 .btn-raised:active { box-shadow: inset 0 0 0 1px var(--line-strong); transform: none; }
body.ds-v2 .btn-accent {
  background: var(--accent);
  color: #fff;
  box-shadow: 0 1px 2px rgba(9, 9, 11, 0.05), 0 6px 16px -6px rgba(37, 99, 235, 0.45);
}
body.ds-v2 .btn-accent:hover {
  background: var(--accent-hover);
  box-shadow: 0 1px 2px rgba(9, 9, 11, 0.05), 0 10px 20px -8px rgba(37, 99, 235, 0.55);
  transform: none;
}
body.ds-v2 .btn-danger {
  background: var(--bg-card);
  color: var(--danger);
  box-shadow: 0 0 0 1px rgba(220, 38, 38, 0.30);
}
body.ds-v2 .btn-danger:hover { background: var(--danger-bg); transform: none; }
body.ds-v2 .btn-copy { background: var(--bg-card); box-shadow: 0 0 0 1px var(--line); color: var(--text-secondary); }
body.ds-v2 .btn-copy:hover { color: var(--text-primary); box-shadow: 0 0 0 1px var(--line-strong); }
body.ds-v2 .btn-copy.copied { color: var(--success); box-shadow: 0 0 0 1px rgba(5, 150, 105, 0.35); }

/* ═══════════ KPI tiles ═══════════ */

body.ds-v2 .kpi-card {
  background: var(--bg-card);
  transition: box-shadow var(--transition-fast), transform var(--transition-fast);
}
body.ds-v2 .kpi-card:hover {
  box-shadow: 0 0 0 1px var(--line-strong), 0 8px 24px -8px rgba(9, 9, 11, 0.10);
  transform: translateY(-1px);
}
body.ds-v2 .kpi-card-label {
  color: var(--text-tertiary);
  letter-spacing: 0.08em;
}
body.ds-v2 .kpi-card-value {
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}
body.ds-v2 .kpi-card-icon {
  background: var(--accent-light);
  box-shadow: none;
  color: var(--accent);
  transition: background var(--transition-fast), transform var(--transition-fast);
}
body.ds-v2 .kpi-card:hover .kpi-card-icon {
  background: rgba(37, 99, 235, 0.14);
  transform: scale(1.05);
}

/* Sparkline — quiet single-hue area, the Vercel-analytics register */
body.ds-v2 .kpi-card-viz { min-height: 36px; }
body.ds-v2 .kpi-spark {
  display: block;
  width: 100%;
  height: 36px;
}
body.ds-v2 .kpi-spark-line {
  stroke: var(--accent);
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
body.ds-v2 .kpi-spark-area { fill: rgba(37, 99, 235, 0.07); }

/* Segmented meter — one discrete cell per client, filled = has VPS */
body.ds-v2 .kpi-meter {
  display: flex;
  gap: 4px;
  align-items: center;
  height: 36px;
}
body.ds-v2 .kpi-meter i {
  display: block;
  height: 6px;
  flex: 1;
  border-radius: 999px;
  background: var(--line);
  transition: background var(--transition-med);
}
body.ds-v2 .kpi-meter i.on { background: var(--accent); }

/* KPI footer: the gradient progress bar is legacy noise — the number is the
   story. The delta reads as quiet muted text, dot-prefixed, never wrapping. */
body.ds-v2 .kpi-bar { display: none; }
body.ds-v2 .kpi-change {
  background: transparent;
  padding: 0;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--text-secondary);
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 7px;
}
body.ds-v2 .kpi-change::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: var(--text-tertiary);
  flex-shrink: 0;
}
body.ds-v2 .kpi-change.positive { color: var(--text-secondary); }
body.ds-v2 .kpi-change.positive::before { background: var(--success); }
body.ds-v2 .kpi-change.negative { color: var(--text-secondary); }
body.ds-v2 .kpi-change.negative::before { background: var(--danger); }

/* ═══════════ Cards (clients) — premium minimal ═══════════ */

body.ds-v2 .client-card {
  background: var(--bg-card);
  box-shadow: 0 0 0 1px var(--line), 0 1px 2px rgba(9, 9, 11, 0.04), 0 4px 12px -6px rgba(9, 9, 11, 0.08);
  transition: box-shadow 0.2s var(--transition-fast), transform 0.2s var(--transition-fast);
}
body.ds-v2 .client-card:hover {
  box-shadow: 0 0 0 1px var(--line-strong), 0 2px 4px rgba(9, 9, 11, 0.04), 0 16px 32px -16px rgba(9, 9, 11, 0.16);
  transform: translateY(-2px);
}
body.ds-v2 .client-avatar {
  background: linear-gradient(135deg, #3b82f6, #2563eb);
  color: #fff;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 4px 10px -4px rgba(37, 99, 235, 0.5);
}
body.ds-v2 .cc2 .cc2-id { min-width: 0; }
body.ds-v2 .cc2 .client-card-name { letter-spacing: -0.01em; }
body.ds-v2 .cc2 .client-card-company {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Type chip — modern etiquette: hairline pill, tinted dot, quiet text */
body.ds-v2 .cc2-type {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: auto;
  align-self: flex-start;
  flex-shrink: 0;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--text-secondary);
  background: var(--bg-card);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 3px 10px;
}
body.ds-v2 .cc2-type i {
  width: 6px;
  height: 6px;
  border-radius: 999px;
  flex-shrink: 0;
}
body.ds-v2 .cc2-type-voice i   { background: var(--type-voice);   box-shadow: 0 0 0 3px var(--type-voice-ring); }
body.ds-v2 .cc2-type-vps i,
body.ds-v2 .cc2-type-legacy i  { background: var(--type-legacy);  box-shadow: 0 0 0 3px var(--type-legacy-ring); }
body.ds-v2 .cc2-type-storage i { background: var(--type-storage); box-shadow: 0 0 0 3px var(--type-storage-ring); }
body.ds-v2 .cc2-type-test i    { background: var(--type-test);    box-shadow: 0 0 0 3px var(--type-test-ring); }
body.ds-v2 .cc2-type-new i     { background: var(--text-tertiary); box-shadow: 0 0 0 3px var(--type-test-ring); }
body.ds-v2 .cc2-type-none i    { background: var(--text-tertiary); box-shadow: none; }

/* Quiet contact lines — no boxed panel, just rhythm */
body.ds-v2 .cc2-meta {
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding: 2px 2px 0;
}
body.ds-v2 .cc2-line {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 0.83rem;
  color: var(--text-secondary);
  min-width: 0;
}
body.ds-v2 .cc2-line svg { color: var(--text-tertiary); flex-shrink: 0; }
body.ds-v2 .cc2-line span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
body.ds-v2 .cc2-slugline code {
  font-family: 'JetBrains Mono', ui-monospace, Menlo, monospace;
  font-size: 0.75rem;
  color: var(--text-secondary);
  background: var(--bg-card-2);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 1px 7px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
body.ds-v2 .cc2-copy {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--text-tertiary);
  padding: 2px;
  display: inline-flex;
  flex-shrink: 0;
  border-radius: 5px;
  transition: color var(--transition-fast);
}
body.ds-v2 .cc2-copy:hover { color: var(--accent); }

/* Footer — hairline divider, status left, quiet action right.
   Pinned to the card bottom so rows of unequal content stay aligned. */
body.ds-v2 .cc2 { display: flex; flex-direction: column; }
body.ds-v2 .cc2-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-top: 1px solid var(--line);
  margin-top: auto;
  padding-top: 12px;
}
body.ds-v2 .cc2 .cc2-meta { padding-bottom: 14px; }
body.ds-v2 .cc2-vps {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 0.78rem;
  font-weight: 500;
  color: var(--text-tertiary);
}
body.ds-v2 .cc2-vps i {
  width: 7px;
  height: 7px;
  border-radius: 999px;
  background: var(--text-tertiary);
  opacity: 0.5;
}
body.ds-v2 .cc2-vps.on { color: var(--success); }
body.ds-v2 .cc2-vps.on i { background: var(--success); opacity: 1; box-shadow: 0 0 0 3px var(--success-bg); }
body.ds-v2 .cc2-open {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: none;
  border: none;
  cursor: pointer;
  font-family: inherit;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text-secondary);
  padding: 4px 2px;
  border-radius: 6px;
  transition: color var(--transition-fast);
}
body.ds-v2 .cc2-open svg { transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1); }
body.ds-v2 .cc2-open:hover { color: var(--accent); }
body.ds-v2 .cc2-open:hover svg { transform: translateX(2px); }
body.ds-v2 .client-card:hover .cc2-open { color: var(--accent); }

/* Segmented filter (All / Voice / VPS) — styled inline in Clients.js with
   legacy literals; these scoped rules out-rank that <style> block. */
body.ds-v2 .client-type-filter {
  background: var(--bg-card-2);
  box-shadow: inset 0 0 0 1px var(--line);
}
body.ds-v2 .client-type-filter .ctf-pill { color: var(--text-secondary); }
body.ds-v2 .client-type-filter .ctf-pill:hover { color: var(--text-primary); }
body.ds-v2 .client-type-filter .ctf-pill.active {
  background: #ffffff;
  color: var(--text-primary);
  box-shadow: 0 0 0 1px var(--line), 0 1px 2px rgba(9, 9, 11, 0.06);
}

/* ═══════════ Status pills ═══════════
   Movido para "Badges v3" mais abaixo. Ficam só os que não são estado. */

body.ds-v2 .vps-status { border-radius: 6px; box-shadow: none; }

/* ═══════════ Tables ═══════════ */

body.ds-v2 .nm-table-container { background: var(--bg-card); }
body.ds-v2 .nm-table-header { border-bottom: 1px solid var(--line); }
body.ds-v2 .nm-table thead th {
  color: var(--text-tertiary);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  border-bottom: 1px solid var(--line);
}
body.ds-v2 .nm-table tbody tr { border-bottom: 1px solid var(--line); }
body.ds-v2 .nm-table tbody tr:hover { background: var(--bg-base); box-shadow: none; }
body.ds-v2 .nm-table tbody td { color: var(--text-secondary); font-variant-numeric: tabular-nums; }
body.ds-v2 .nm-table-tiles .nm-tile-row { background: var(--bg-card); }
body.ds-v2 .nm-table-tiles .nm-tile-row:hover {
  box-shadow: 0 0 0 1px var(--line-strong), 0 4px 12px -4px rgba(9, 9, 11, 0.08);
  background: var(--bg-card);
}

/* ═══════════ Charts / activity ═══════════ */

body.ds-v2 .chart-container { background: var(--bg-card); }
body.ds-v2 .chart-title { letter-spacing: -0.01em; }
body.ds-v2 .chart-subtitle { color: var(--text-tertiary); }
body.ds-v2 .activity-item { background: var(--bg-card); }
body.ds-v2 .activity-item:hover {
  background: var(--bg-card);
  box-shadow: 0 0 0 1px var(--line-strong), 0 4px 12px -4px rgba(9, 9, 11, 0.08);
}
body.ds-v2 .activity-icon {
  background: var(--accent-light);
  color: var(--accent);
  box-shadow: none;
}
body.ds-v2 .activity-icon.success { background: var(--success-bg); color: var(--success); }
body.ds-v2 .activity-icon { border-radius: 999px; }
body.ds-v2 .activity-time {
  color: var(--text-tertiary);
  text-transform: none;
  letter-spacing: 0;
  font-size: 0.75rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}
body.ds-v2 .activity-title { letter-spacing: -0.005em; }

/* ═══════════ Forms ═══════════ */

body.ds-v2 .input-field,
body.ds-v2 .vps-module-input,
body.ds-v2 .vps-textarea {
  background: var(--bg-card);
  box-shadow: inset 0 0 0 1px var(--line);
  color: var(--text-primary);
  border-radius: 10px;
  transition: box-shadow var(--transition-fast);
}
body.ds-v2 .input-field:focus,
body.ds-v2 .vps-module-input:focus,
body.ds-v2 .vps-textarea:focus {
  box-shadow: inset 0 0 0 1px var(--accent), 0 0 0 3px var(--accent-light);
}
body.ds-v2 .input-field::placeholder { color: var(--text-tertiary); }
body.ds-v2 .input-label { color: var(--text-secondary); }

/* ═══════════ Modals ═══════════ */

body.ds-v2 .modal-overlay {
  background: rgba(9, 9, 11, 0.35);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
body.ds-v2 .modal-card {
  background: var(--bg-card);
  box-shadow: 0 0 0 1px var(--line), 0 24px 60px -20px rgba(9, 9, 11, 0.25);
}
body.ds-v2 .modal-header { border-bottom: 1px solid var(--line); }
body.ds-v2 .modal-footer { border-top: 1px solid var(--line); }
body.ds-v2 .modal-close { box-shadow: 0 0 0 1px var(--line); background: var(--bg-card); color: var(--text-secondary); }
body.ds-v2 .modal-close:hover { color: var(--text-primary); box-shadow: 0 0 0 1px var(--line-strong); }

/* Detail modal sections */
body.ds-v2 .detail-section { background: var(--bg-base); box-shadow: inset 0 0 0 1px var(--line); }
body.ds-v2 .cred-card { background: var(--bg-card); box-shadow: 0 0 0 1px var(--line); }

/* ═══════════ Feedback ═══════════ */

body.ds-v2 .toast {
  background: var(--bg-card);
  box-shadow: 0 0 0 1px var(--line), 0 12px 32px -12px rgba(9, 9, 11, 0.18);
  color: var(--text-primary);
}
/* Empty state: base ships #f9fafb bg + #e5e7eb dashed border (a light panel
   that reads as a hole in dark). Token both so it tracks the theme. */
body.ds-v2 .empty-state { background: var(--bg-card-2); border-color: var(--line); color: var(--text-tertiary); }
body.ds-v2 .empty-state h3 { color: var(--text-secondary); }

body.ds-v2 .skeleton {
  background: linear-gradient(90deg, var(--bg-card-2) 25%, var(--line) 50%, var(--bg-card-2) 75%);
  background-size: 200% 100%;
  border-radius: 8px;
}
body.ds-v2 .skeleton-text { height: 12px; margin-bottom: 8px; border-radius: 6px; }
body.ds-v2 .skeleton-heading { height: 22px; border-radius: 7px; }
body.ds-v2 .skeleton-card { border-radius: 10px; }
@media (prefers-reduced-motion: reduce) {
  body.ds-v2 .skeleton { animation: none; }
}

body.ds-v2 .pagination-btn { background: var(--bg-card); box-shadow: 0 0 0 1px var(--line); color: var(--text-secondary); }
body.ds-v2 .pagination-btn:hover { color: var(--text-primary); box-shadow: 0 0 0 1px var(--line-strong); }
body.ds-v2 .pagination-btn.active { background: var(--accent-light); color: var(--accent); box-shadow: 0 0 0 1px rgba(37, 99, 235, 0.30); }

/* ═══════════ Consumo — editorial module remapped to DS v2 ═══════════
   The page defines its whole "editorial ledger" identity as custom
   properties on .consumo (paper/ink/hair/serif). Remapping them here
   converts the module to the DS v2 register — Inter instead of
   Playfair, zinc instead of beige, the data-viz palette on provider
   dots — while keeping its distinctive layout intact. */

body.ds-v2 .consumo {
  --bg: #fafafa;
  --paper: #ffffff;
  --paper-2: #fafafa;
  --tint: #f4f4f5;
  --ink: #09090b;
  --ink-2: #3f3f46;
  --muted: #52525b;
  --faint: #a1a1aa;
  --hair: #e4e4e7;
  --hair-2: #d4d4d8;
  --heavy: #18181b;
  --accent: #2563eb;
  --accent-soft: rgba(37, 99, 235, 0.08);
  --good: #059669;
  --warn: #d97706;
  --crit: #dc2626;
  --p-el: #2563eb;   /* ElevenLabs → chart series 1 */
  --p-or: #0891b2;   /* OpenRouter → series 2 */
  --p-zad: #d97706;  /* Zadarma → series 3 */
  --p-tw: #8b5cf6;   /* Twilio → series 4 */
  --f-disp: 'Inter', -apple-system, system-ui, sans-serif;
}
/* O resto do skin do Consumo mudou-se para client/styles/consumo.css, com
   âmbito body[data-page="consumption"] e carregado depois desta folha. Aqui
   fica só o remapeamento de tokens (o trabalho do skin) e o tooltip flutuante,
   que vive no <body> e não dentro de .consumo. */

/* Floating tooltip — light, bordered (was near-black) */
body.ds-v2 .co-tip-float {
  background: #ffffff;
  color: #09090b;
  border: 1px solid #e4e4e7;
  border-radius: 8px;
  box-shadow: 0 8px 24px -8px rgba(9, 9, 11, 0.2);
}
body.ds-v2 .co-tip-float .tsep { color: #a1a1aa; }

/* Mapping Health: os patches que aqui viviam remendavam o bloco <style> que a
   página trazia dentro do render(). Esse bloco morreu e a folha própria da rota
   (mapping-health.css, âmbito body[data-page="mapping"]) passou a mandar. */

/* ═══════════ Client Portal — inline-styled bits → DS v2 ═══════════ */

body.ds-v2 .cp-btn {
  background: var(--accent);
  color: #fff;
  border-radius: 10px;
  box-shadow: 0 1px 2px rgba(9, 9, 11, 0.05), 0 6px 16px -6px rgba(37, 99, 235, 0.45);
}
body.ds-v2 .cp-btn:hover { background: var(--accent-hover); }
body.ds-v2 .cp-card {
  background: var(--bg-card);
  box-shadow: 0 0 0 1px var(--line);
}
/* .cp-ok / .cp-off vivem agora em client-portal.css, no registo de estado
   (ponto + texto). Este patch enchia o chip por trás e o texto transbordava. */
body.ds-v2 .cp-table code { background: var(--bg-card-2); }

/* ═══════════ Scrollbar ═══════════ */

body.ds-v2 ::-webkit-scrollbar-thumb {
  background: var(--line-strong);
  border-radius: 999px;
}
body.ds-v2 ::-webkit-scrollbar-thumb:hover { background: var(--text-tertiary); }

/* ═══════════ Client 360 (detail view) — neumorphic inline styles → DS v2 ═══ */

/* The 360 renders full-page inside the detail overlay, which pins its own
   blue-grey background with !important — match its specificity. */
body.ds-v2 #detail-modal-overlay.open { background: var(--bg-base) !important; }
body.ds-v2 #detail-modal-overlay .modal-card.modal-wide { background: var(--bg-base) !important; }

body.ds-v2 .cc-card {
  background: var(--bg-card);
  box-shadow: 0 0 0 1px var(--line), 0 1px 2px rgba(9, 9, 11, 0.04), 0 4px 12px -6px rgba(9, 9, 11, 0.08);
  border-radius: 16px;
  animation: dsv2-rise 0.5s cubic-bezier(0.16, 1, 0.3, 1) backwards;
}
body.ds-v2 .cc-inset {
  background: var(--bg-base);
  box-shadow: inset 0 0 0 1px var(--line);
  border-radius: 12px;
}
body.ds-v2 .cc-chip { background: var(--bg-card-2); border: 1px solid var(--line); border-radius: 6px; }
body.ds-v2 .cc-dim { color: var(--text-secondary); }
body.ds-v2 .cc-label { color: var(--text-tertiary); }
body.ds-v2 .cc-val { color: var(--text-primary); }
body.ds-v2 .cc-copy { color: var(--text-tertiary); }
body.ds-v2 .cc-copy:hover { color: var(--accent); }
body.ds-v2 .cc-pill.cc-ok   { background: var(--success-bg); color: var(--success); border-color: rgba(5, 150, 105, 0.25); }
body.ds-v2 .cc-pill.cc-warn { background: var(--warning-bg); color: var(--warning); border-color: rgba(217, 119, 6, 0.25); }
body.ds-v2 .cc-pill.cc-off  { background: var(--bg-card-2); color: var(--text-tertiary); border: 1px solid var(--line); }
body.ds-v2 .cc-dot-ok { background: var(--success); }
body.ds-v2 .cc-dot-off { background: var(--text-tertiary); }
body.ds-v2 .cc-back { color: var(--accent); }

/* Typography — Inter, zinc ink (was Geist + navy) */
body.ds-v2 .cc-title,
body.ds-v2 .cc-name,
body.ds-v2 .cc-sec-title,
body.ds-v2 .cc-tokens-num,
body.ds-v2 .cc-tokens-big,
body.ds-v2 .cc-api-name {
  font-family: 'Inter', -apple-system, system-ui, sans-serif;
  color: var(--text-primary);
  letter-spacing: -0.02em;
}
body.ds-v2 .cc-tokens-num,
body.ds-v2 .cc-tokens-big { font-variant-numeric: tabular-nums; }
body.ds-v2 .cc-tokens-zero { color: var(--danger); }
body.ds-v2 .cc-sub,
body.ds-v2 .cc-sec-sub,
body.ds-v2 .cc-api-sub { color: var(--text-secondary); }
body.ds-v2 .cc-sec-title svg { color: var(--accent); }

/* Buttons */
body.ds-v2 .cc-edit {
  background: var(--bg-card);
  box-shadow: 0 0 0 1px var(--line), 0 1px 2px rgba(9, 9, 11, 0.04);
  border-radius: 10px;
  color: var(--text-primary);
  transition: all 0.25s cubic-bezier(0.16, 1, 0.3, 1);
}
body.ds-v2 .cc-edit:hover {
  box-shadow: 0 0 0 1px var(--line-strong), 0 4px 12px -4px rgba(9, 9, 11, 0.1);
  transform: translateY(-1px);
}
body.ds-v2 .cc-edit:active { box-shadow: 0 0 0 1px var(--line); transform: scale(0.98); }
body.ds-v2 .cc-btn-primary { background: var(--accent); border-radius: 10px; }
body.ds-v2 .cc-btn-primary:hover { background: var(--accent-hover); }

/* Tabs — the shared segmented-control pattern (white thumb, not blue) */
body.ds-v2 .cc-tabs {
  background: var(--bg-card-2);
  box-shadow: inset 0 0 0 1px var(--line);
  border-radius: 10px;
  padding: 3px;
  gap: 3px;
}
body.ds-v2 .cc-tab { border-radius: 8px; padding: 7px 16px; font-size: 13px; color: var(--text-secondary); transition: all 0.25s cubic-bezier(0.16, 1, 0.3, 1); }
body.ds-v2 .cc-tab:hover { color: var(--text-primary); }
body.ds-v2 .cc-tab.active {
  background: #ffffff;
  color: var(--text-primary);
  font-weight: 600;
  box-shadow: 0 0 0 1px var(--line), 0 1px 2px rgba(9, 9, 11, 0.06);
}

/* Profile / misc */
body.ds-v2 .cc-avatar {
  background: linear-gradient(135deg, #3b82f6, #2563eb);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 8px 20px -8px rgba(37, 99, 235, 0.5);
}
body.ds-v2 .cc-api-icon { background: var(--accent-light); color: var(--accent); }
body.ds-v2 .cc-agent-col-2 { border-left-color: var(--line); }
body.ds-v2 .cc-input,
body.ds-v2 .cc-textarea {
  background: var(--bg-card);
  box-shadow: inset 0 0 0 1px var(--line);
  border-radius: 10px;
  color: var(--text-primary);
  transition: box-shadow var(--transition-fast);
}
body.ds-v2 .cc-input:focus,
body.ds-v2 .cc-textarea:focus {
  box-shadow: inset 0 0 0 1px var(--accent), 0 0 0 3px var(--accent-light);
}

/* ═══════════ Drive — line-icon treatment ═══════════ */

body.ds-v2 .drive-item-icon { color: var(--text-tertiary); display: flex; justify-content: center; }
body.ds-v2 .drive-folder .drive-item-icon { color: var(--accent); }
body.ds-v2 .drive-act { color: var(--text-tertiary); transition: color var(--transition-fast); }
body.ds-v2 .drive-act:hover { color: var(--accent); }
body.ds-v2 .drive-crumb { display: inline-flex; align-items: center; gap: 5px; }
body.ds-v2 .drive-crumb svg { flex-shrink: 0; }

/* ═══════════ Seamless details (Apple register) ═══════════
   Fluid exponential easing, staggered entrance, tactile press
   states, frosted sticky header, soft modal reveal. All motion
   respects prefers-reduced-motion. */

/* Text selection in brand tint */
body.ds-v2 ::selection { background: rgba(37, 99, 235, 0.15); }

/* Cards enter with a quiet cascade */
@keyframes dsv2-rise {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
body.ds-v2 .cc2,
body.ds-v2 .kpi-card {
  animation: dsv2-rise 0.5s cubic-bezier(0.16, 1, 0.3, 1) backwards;
}
body.ds-v2 .cc2:nth-child(1), body.ds-v2 .kpi-card:nth-child(1) { animation-delay: 0.03s; }
body.ds-v2 .cc2:nth-child(2), body.ds-v2 .kpi-card:nth-child(2) { animation-delay: 0.07s; }
body.ds-v2 .cc2:nth-child(3), body.ds-v2 .kpi-card:nth-child(3) { animation-delay: 0.11s; }
body.ds-v2 .cc2:nth-child(4) { animation-delay: 0.15s; }
body.ds-v2 .cc2:nth-child(5) { animation-delay: 0.19s; }
body.ds-v2 .cc2:nth-child(6) { animation-delay: 0.23s; }
body.ds-v2 .cc2:nth-child(7) { animation-delay: 0.27s; }
body.ds-v2 .cc2:nth-child(8) { animation-delay: 0.31s; }
body.ds-v2 .cc2:nth-child(n+9) { animation-delay: 0.35s; }

/* Card hover glides with exponential ease; avatar breathes with it */
body.ds-v2 .client-card {
  transition: box-shadow 0.35s cubic-bezier(0.16, 1, 0.3, 1), transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}
body.ds-v2 .client-avatar { transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1); }
body.ds-v2 .client-card:hover .client-avatar { transform: scale(1.04); }
body.ds-v2 .cc2-type { transition: border-color 0.25s ease; }
body.ds-v2 .client-card:hover .cc2-type { border-color: var(--line-strong); }

/* Tactile press states */
body.ds-v2 .btn:active,
body.ds-v2 .cc2-open:active,
body.ds-v2 .pagination-btn:active { transform: scale(0.97); }
body.ds-v2 .client-type-filter .ctf-pill { transition: all 0.25s cubic-bezier(0.16, 1, 0.3, 1); }
body.ds-v2 .client-type-filter .ctf-pill:active { transform: scale(0.95); }

/* Frosted sticky page header — content glides underneath */
body.ds-v2 .page-header {
  position: sticky;
  top: 0;
  z-index: 60;
  margin: -32px -40px 24px;
  padding: 24px 40px 16px;
  background: rgba(250, 250, 250, 0.82);
  backdrop-filter: blur(14px) saturate(1.4);
  -webkit-backdrop-filter: blur(14px) saturate(1.4);
}
@media (max-width: 1024px) {
  body.ds-v2 .page-header { margin: -24px -20px 20px; padding: 20px 20px 14px; }
}
@media (max-width: 640px) {
  body.ds-v2 .page-header { position: static; margin: 0 0 20px; padding: 0; background: transparent; backdrop-filter: none; -webkit-backdrop-filter: none; }
}

/* Modal reveals like a sheet — overlay fades, card settles into place */
@keyframes dsv2-overlay-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes dsv2-modal-in {
  from { opacity: 0; transform: translateY(10px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}
body.ds-v2 .modal-overlay { animation: dsv2-overlay-in 0.25s ease-out; }
body.ds-v2 .modal-card { animation: dsv2-modal-in 0.4s cubic-bezier(0.16, 1, 0.3, 1); }

/* Copy button confirms in place — no toast interruption */
body.ds-v2 .cc2-copy { transition: color 0.2s ease, transform 0.3s cubic-bezier(0.34, 1.2, 0.64, 1); }
body.ds-v2 .cc2-copy.ok { color: var(--success); transform: scale(1.15); }

@media (prefers-reduced-motion: reduce) {
  body.ds-v2 .cc2,
  body.ds-v2 .kpi-card,
  body.ds-v2 .modal-overlay,
  body.ds-v2 .modal-card { animation: none; }
  body.ds-v2 .client-card,
  body.ds-v2 .client-avatar,
  body.ds-v2 .cc2-copy { transition: none; }
}

/* ═══════════ EXPERIMENT: liquid glass HÍBRIDO (chrome-only) — Clients & VPS ═══
   O vidro vive no CHROME (sidebar, header, toolbar), não no conteúdo:
   um campo ambiente da marca cobre a shell inteira, o chrome refrata-o
   em vidro fosco, e os cards ficam sólidos para legibilidade máxima.
   Scoped a body[data-page="clients"] — apagar este bloco para reverter. */

body.ds-v2[data-page="clients"] {
  background:
    radial-gradient(680px 460px at 8% -4%, rgba(37, 99, 235, 0.14), transparent 64%),
    radial-gradient(600px 440px at 90% 12%, rgba(139, 92, 246, 0.10), transparent 64%),
    radial-gradient(520px 380px at 28% 60%, rgba(8, 145, 178, 0.08), transparent 62%),
    radial-gradient(800px 560px at 72% 108%, rgba(0, 132, 255, 0.11), transparent 64%),
    var(--bg-base);
  background-attachment: fixed;
}
body.ds-v2[data-page="clients"] .main-content { background: transparent; }

/* Chrome em vidro — sidebar e header refratam o campo ambiente */
body.ds-v2[data-page="clients"] .sidebar {
  background: rgba(250, 250, 250, 0.62);
  backdrop-filter: blur(24px) saturate(1.5);
  -webkit-backdrop-filter: blur(24px) saturate(1.5);
  border-right: 1px solid rgba(15, 23, 42, 0.07);
}
body.ds-v2[data-page="clients"] .page-header {
  background: rgba(250, 250, 250, 0.5);
  backdrop-filter: blur(22px) saturate(1.5);
  -webkit-backdrop-filter: blur(22px) saturate(1.5);
}
body.ds-v2[data-page="clients"] .search-bar,
body.ds-v2[data-page="clients"] .client-type-filter {
  background: rgba(255, 255, 255, 0.55);
  backdrop-filter: blur(18px) saturate(1.5);
  -webkit-backdrop-filter: blur(18px) saturate(1.5);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.85), inset 0 0 0 1px rgba(15, 23, 42, 0.07);
}
body.ds-v2[data-page="clients"] .client-type-filter .ctf-pill.active {
  background: rgba(255, 255, 255, 0.95);
}

/* Conteúdo sólido — cards opacos com specular edge subtil, pousados
   sobre o campo ambiente (o vidro é moldura, não conteúdo) */
body.ds-v2[data-page="clients"] .client-card {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.9),
    0 0 0 1px rgba(15, 23, 42, 0.07),
    0 4px 16px -8px rgba(9, 9, 11, 0.1);
}
body.ds-v2[data-page="clients"] .client-card:hover {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.95),
    0 0 0 1px rgba(15, 23, 42, 0.1),
    0 16px 36px -16px rgba(9, 9, 11, 0.18);
}

/* ═══════════ QW — Sistema de consistência (research 2026-07-10) ═══════════
   Fonte: docs/research/2026-07-10-crm-ui-design-systems-inspiration/
   QW1 escala numérica · QW2 .kv unificado · QW3 elevação 3 níveis ·
   Altura de chip: ver "Badges v3" (--badge-h). Regra: páginas não declaram literais — só tokens. */

body.ds-v2 {
  /* QW3 — elevação formal: tom (bg-card) + borda (ring) + sombra, 3 níveis */
  --elev-rest: 0 0 0 1px var(--line), 0 1px 2px rgba(9, 9, 11, 0.04);
  --elev-hover: 0 0 0 1px var(--line-strong), 0 8px 24px -10px rgba(9, 9, 11, 0.14);
  --elev-overlay: 0 0 0 1px var(--line), 0 24px 60px -20px rgba(9, 9, 11, 0.25);

  /* QW1 — escala numérica dedicada (weight 600, tracking apertado, lh 1, tabular) */
  --num-xl: 44px;
  --num-lg: 32px;
  --num-md: 24px;
  --num-sm: 17px;
}

/* QW1 — um só tratamento para números em todo o CRM */
body.ds-v2 .kpi-card-value,
body.ds-v2 .consumo .co-tot,
body.ds-v2 .cc-tokens-num,
body.ds-v2 .cc-tokens-big,
body.ds-v2 .bucket-value,
body.ds-v2 .billing-summary-card .value {
  font-family: 'Inter', -apple-system, system-ui, sans-serif;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.03em;
  line-height: 1;
}
body.ds-v2 .cc-tokens-big { font-size: var(--num-xl); }
body.ds-v2 .kpi-card-value,
body.ds-v2 .cc-tokens-num,
body.ds-v2 .billing-summary-card .value { font-size: var(--num-lg); }
body.ds-v2 .bucket-value { font-size: var(--num-md); }
body.ds-v2 .consumo .co-tot { font-size: var(--num-sm); }

/* QW2 — par label/valor unificado: TODAS as implementações convergem
   para a mesma spec (label 11px/600/uppercase/tertiary · valor 14px/
   500/primary/tabular) */
body.ds-v2 .cc-label,
body.ds-v2 .detail-field-label,
body.ds-v2 .client-card-row-label,
body.ds-v2 .bucket-label,
body.ds-v2 .vps-info-label,
body.ds-v2 .kpi-card-label {
  font-size: 0.6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-tertiary);
}
body.ds-v2 .cc-val,
body.ds-v2 .detail-field-value,
body.ds-v2 .client-card-row-value,
body.ds-v2 .vps-info-value {
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}

/* A altura única de chip vive agora em "Badges v3" (--badge-h). Uma só
   fonte de verdade: dois sítios a definir altura saíam sempre de sincronia. */

/* Anti-borda-dupla: componentes com border próprio + ring de elevação
   somavam 2px visuais (VPS Infra vs resto). O ring é a borda única;
   a border real fica transparente para manter o box model. */
body.ds-v2 .vps-server-card,
body.ds-v2 .billing-summary-card,
body.ds-v2 .billing-card,
body.ds-v2 .drive-item { border-color: transparent; }
body.ds-v2 .vps-server-card { box-shadow: var(--elev-rest); background: var(--bg-card); }

/* QW3 — superfícies principais consomem a escala de elevação */
body.ds-v2 .kpi-card,
body.ds-v2 .chart-container,
body.ds-v2 .nm-table-container,
body.ds-v2 .activity-item,
body.ds-v2 .cc-card,
body.ds-v2 .billing-card,
body.ds-v2 .billing-summary-card { box-shadow: var(--elev-rest); }
body.ds-v2 .kpi-card:hover,
body.ds-v2 .activity-item:hover { box-shadow: var(--elev-hover); }
body.ds-v2 .modal-card,
body.ds-v2 .consumo .co-fixpop,
body.ds-v2 .consumo .co-rangepop,
body.ds-v2 .consumo .co-dd-pop { box-shadow: var(--elev-overlay); }

/* ═══════════ Pormenores (auditoria Bruno 2026-07-11) ═══════════ */

/* Wizard Add Client: linha do stepper com respiro e cor hairline;
   rodapé sem faixa cinzenta (a "sombra" era background bg-base) */
body.ds-v2 .wizard-step-line { margin: 0 18px; background: var(--line); height: 1.5px; }
body.ds-v2 .wizard-footer { background: transparent; border-top: 1px solid var(--line); padding-top: 16px; }

/* Consumo: mini-barras dos providers — finas e arredondadas, não retângulos */

/* Consumo: popover de calendário premium — cantos redondos em tudo */
body.ds-v2 .consumo .co-rangepop { border-radius: 12px; padding: 16px; }
body.ds-v2 .consumo .co-rp-quick button { border-radius: 8px; transition: all 0.15s ease; }
body.ds-v2 .consumo .co-rp-quick button:hover { background: var(--accent-light); border-color: rgba(37, 99, 235, 0.3); }
body.ds-v2 .consumo .co-rp-dates input {
  border-radius: 8px;
  padding: 9px 10px;
  border-color: var(--line);
  background: var(--bg-card);
  color: var(--text-primary);
}
body.ds-v2 .consumo .co-rp-dates input:focus { border-color: var(--accent); outline: none; box-shadow: 0 0 0 3px var(--accent-light); }
body.ds-v2 .consumo .co-range { border-radius: 10px; }

/* Billing: números nunca saem do cartão */
body.ds-v2 .bucket { min-width: 0; }
body.ds-v2 .bucket-value { font-size: 19px; }
body.ds-v2 .bucket-value small { font-size: 12px; }

/* Billing: cartões compactos com expand — bater o olho e saber o estado */
body.ds-v2 .bc-compact { display: flex; align-items: flex-end; gap: 24px; padding: 12px 0 2px; }
body.ds-v2 .bc-kv { display: flex; flex-direction: column; gap: 3px; }
body.ds-v2 .bc-kv-label {
  font-size: 0.6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-tertiary);
}
body.ds-v2 .bc-kv b {
  font-size: var(--num-sm);
  font-weight: 600;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
}
body.ds-v2 .bc-toggle {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: none;
  border: none;
  cursor: pointer;
  font-family: inherit;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text-secondary);
  padding: 4px 2px;
}
body.ds-v2 .bc-toggle:hover { color: var(--accent); }
body.ds-v2 .bc-toggle svg { transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1); }
body.ds-v2 .billing-card.open .bc-toggle svg { transform: rotate(180deg); }
body.ds-v2 .billing-card .bc-details { display: none; }
body.ds-v2 .billing-card.open .bc-details { display: block; animation: dsv2-rise 0.35s cubic-bezier(0.16, 1, 0.3, 1); }

/* ── Colapsar cliente ────────────────────────────────────
   Reduz o cartão ao cabeçalho (nome + estado). Diferente de "Detalhes", que
   revela mais: um esconde, o outro mostra, cada um com o seu controlo. */
body.ds-v2 .bc-collapse {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  padding: 0;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--text-tertiary);
  cursor: pointer;
  flex-shrink: 0;
  transition: color 0.15s ease, background 0.15s ease, transform 0.2s ease;
}
body.ds-v2 .bc-collapse:hover { color: var(--text-primary); background: var(--bg-card-2); }
body.ds-v2 .billing-card.is-collapsed .bc-collapse svg { transform: rotate(180deg); }
body.ds-v2 .billing-card.is-collapsed .billing-card-plan,
body.ds-v2 .billing-card.is-collapsed .bc-compact,
body.ds-v2 .billing-card.is-collapsed .bc-details,
body.ds-v2 .billing-card.is-collapsed .billing-card-actions { display: none; }
body.ds-v2 .billing-card.is-collapsed { padding-bottom: 14px; }
body.ds-v2 .billing-card.is-collapsed .billing-card-header { margin-bottom: 0; }
/* Sem isto, um cartão colapsado numa linha com outro por colapsar esticava à
   altura do vizinho: a grelha estica os itens por omissão. */
body.ds-v2 .billing-grid { align-items: start; }
body.ds-v2 .billing-card-header { align-items: flex-start; }
body.ds-v2 .billing-card-badges { flex-wrap: wrap; justify-content: flex-end; }

body.ds-v2 .bc-collapse-all {
  margin-left: auto;
  border: 0;
  border-radius: 8px;
  background: var(--bg-card);
  box-shadow: inset 0 0 0 1px var(--line);
  color: var(--text-secondary);
  font: inherit;
  font-size: 0.75rem;
  font-weight: 600;
  height: 28px;
  padding: 0 11px;
  cursor: pointer;
  transition: box-shadow 0.15s ease, color 0.15s ease;
}
body.ds-v2 .bc-collapse-all:hover { color: var(--text-primary); box-shadow: inset 0 0 0 1px var(--line-strong); }
body.ds-v2 .billing-section-title { display: flex; align-items: center; gap: 10px; }

/* ═══════════ Theme toggle (acima da hairline do rodapé) ═══════════
   Linha própria: é preferência, não identidade nem navegação, por isso não
   divide a linha com o utilizador nem compete com a marca no topo do rail. */

body.ds-v2 .sidebar-prefs { padding: 2px 0 8px; }
body.ds-v2 .theme-toggle {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 30px;
  padding: 0 8px;
  border: 0;
  border-radius: 12px;
  color: var(--text-secondary);
  background: transparent;
  box-shadow: none;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  text-align: left;
  cursor: pointer;
  transition: color 0.2s ease, background 0.2s ease;
}
body.ds-v2 .theme-toggle svg { flex-shrink: 0; width: 16px; height: 16px; opacity: 0.75; }
body.ds-v2 .theme-toggle:hover { color: var(--text-primary); background: rgba(9, 9, 11, 0.045); box-shadow: none; }
body.ds-v2 .theme-toggle:hover svg { opacity: 1; }
/* Rail colapsado: só o ícone, centrado como qualquer nav-item. */
body.ds-v2 .sidebar.is-collapsed .theme-toggle { justify-content: center; padding: 0; }
body.ds-v2 .sidebar.is-collapsed .tt-label { display: none; }
body.ds-v2 .theme-toggle:active { transform: scale(0.94); }
body.ds-v2 .theme-toggle .tt-sun { display: none; }
body.ds-v2.dark .theme-toggle .tt-sun { display: block; }
body.ds-v2.dark .theme-toggle .tt-moon { display: none; }

/* ═══════════ DARK — sibling theme completo ═══════════
   Tudo o que consome tokens muda aqui; abaixo só os overrides
   dos pontos com literais claros (thumbs, frost, specular). */


/* ═══════════════════════════════════════════════════════
   Badges v3 — dois registos, não um
   ═══════════════════════════════════════════════════════
   O que fazia tudo isto ler como genérico: ESTADO e CATEGORIA
   eram a mesma coisa. "Ativo" e "Voz · Enterprise" saíam os
   dois como pastilha cheia, borda de 1px, 999px de raio,
   maiúsculas e peso 700, com a mesma saturação. Numa tabela,
   uma coluna inteira de pastilhas cheias grita toda ao mesmo
   volume e deixa de se ler nada.

   Passam a existir dois registos, e o tipo do dado decide:

     ESTADO  → ponto de cor + texto simples, sem caixa. O ponto
               carrega a semântica, o texto fica em tom neutro.
               Numa lista de 50 linhas quase todas "Ativo", o
               olho salta direto às que não são.
     ETIQUETA → retângulo suave: raio 6px, fundo em alfa baixo
               da própria cor, anel de 1px da mesma cor. Nunca
               fundo cheio; nunca borda a competir com o fundo.

   Regras: 22px de altura (era 26), peso 500, sem maiúsculas,
   sem letter-spacing. O anel é a única borda.
   ═══════════════════════════════════════════════════════ */

body.ds-v2 {
  --badge-h: 22px;
  --badge-r: 6px;
}

/* ── Registo 1: ESTADO (ponto + texto) ─────────────────── */
body.ds-v2 .status-badge,
body.ds-v2 .clx-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: var(--badge-h);
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  color: var(--text-secondary);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  white-space: nowrap;
  --dot: var(--text-tertiary);
}
body.ds-v2 .status-badge::before,
body.ds-v2 .clx-pill::before {
  content: '';
  width: 6px;
  height: 6px;
  flex-shrink: 0;
  border-radius: 999px;
  background: var(--dot);
  /* Halo do ponto: dá-lhe presença sem o engordar. Fallback primeiro,
     para quem não tem color-mix ficar com o ponto limpo e mais nada. */
  box-shadow: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--dot) 20%, transparent);
}
body.ds-v2 .status-badge.active   { --dot: var(--success); }
body.ds-v2 .status-badge.pending  { --dot: var(--warning); }
body.ds-v2 .status-badge.inactive { --dot: var(--text-tertiary); color: var(--text-tertiary); }
body.ds-v2 .clx-pill.good { --dot: var(--success); }
body.ds-v2 .clx-pill.warn { --dot: var(--warning); }
body.ds-v2 .clx-pill.crit { --dot: var(--danger); }
body.ds-v2 .clx-pill.idle { --dot: var(--text-tertiary); color: var(--text-tertiary); }

/* ── Registo 2: ETIQUETA (retângulo suave) ─────────────── */
body.ds-v2 .badge,
body.ds-v2 .clx-type,
body.ds-v2 .cc-pill,
body.ds-v2 .cc-chip,
body.ds-v2 .kbadge,
body.ds-v2 .co-pbadge,
body.ds-v2 .cost-badge,
body.ds-v2 .detail-section-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: var(--badge-h);
  padding: 0 8px;
  border: 0;
  border-radius: var(--badge-r);
  background: var(--bg-card-2);
  box-shadow: inset 0 0 0 1px var(--line);
  color: var(--text-secondary);
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0;
  text-transform: none;
  white-space: nowrap;
  box-sizing: border-box;
}
body.ds-v2 .badge svg,
body.ds-v2 .clx-type svg,
body.ds-v2 .cc-pill svg { width: 12px; height: 12px; flex-shrink: 0; pointer-events: none; }

/* Variantes tonais. O anel é a mesma cor do texto em alfa baixo: com
   fundo cheio + borda de outra cor voltávamos ao registo bootstrap. */
body.ds-v2 .badge-success,
body.ds-v2 .cc-pill.cc-ok {
  background: var(--success-bg);
  box-shadow: inset 0 0 0 1px var(--line);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--success) 26%, transparent);
  color: var(--success);
}
body.ds-v2 .badge-warning,
body.ds-v2 .cc-pill.cc-warn {
  background: var(--warning-bg);
  box-shadow: inset 0 0 0 1px var(--line);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--warning) 26%, transparent);
  color: var(--warning);
}
body.ds-v2 .badge-danger {
  background: var(--danger-bg);
  box-shadow: inset 0 0 0 1px var(--line);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--danger) 26%, transparent);
  color: var(--danger);
}
body.ds-v2 .badge-info {
  background: var(--accent-light);
  box-shadow: inset 0 0 0 1px var(--line);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 26%, transparent);
  color: var(--text-accent);
}
body.ds-v2 .badge-muted,
body.ds-v2 .cc-pill.cc-off,
body.ds-v2 .clx-type.legacy,
body.ds-v2 .clx-type.test {
  background: var(--bg-card-2);
  box-shadow: inset 0 0 0 1px var(--line);
  color: var(--text-tertiary);
}
/* Categoria usa a escala --type-*, nunca as cores de estado: verde ali ao lado
   já quer dizer "ativo", e a mesma cor a dizer duas coisas não diz nenhuma. */
body.ds-v2 .clx-type.voice {
  background: var(--accent-light);
  box-shadow: inset 0 0 0 1px var(--line);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--type-voice) 26%, transparent);
  color: var(--type-voice);
}
body.ds-v2 .clx-type.storage {
  background: var(--bg-card-2);
  box-shadow: inset 0 0 0 1px var(--line);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--type-storage) 26%, transparent);
  color: var(--type-storage);
}

/* O chip de tipo dos cartões de cliente já era deste registo (ponto
   tingido + texto quieto): só alinha o raio e a altura ao resto. */
body.ds-v2 .cc2-type {
  height: var(--badge-h);
  padding: 0 9px;
  border: 0;
  border-radius: var(--badge-r);
  background: var(--bg-card-2);
  box-shadow: inset 0 0 0 1px var(--line);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0;
}
body.ds-v2 .client-card:hover .cc2-type { box-shadow: inset 0 0 0 1px var(--line-strong); }


body.ds-v2.dark {
  color-scheme: dark;
  --bg-base: #0a0a0f;
  --bg-card: #111118;
  --bg-card-2: #191922;
  --bg-sidebar: #0d0d13;
  --text-primary: #f4f5f7;
  --text-secondary: #9aa1ad;
  --text-tertiary: #646b78;
  --text-accent: #60a5fa;
  --accent: #3b82f6;
  --accent-hover: #60a5fa;
  --accent-light: rgba(59, 130, 246, 0.15);
  --accent-glow: rgba(0, 132, 255, 0.3);
  --line: rgba(255, 255, 255, 0.08);
  --line-strong: rgba(255, 255, 255, 0.16);
  --success: #34d399;
  --success-bg: rgba(52, 211, 153, 0.12);
  --danger: #f87171;
  --danger-bg: rgba(248, 113, 113, 0.12);
  --warning: #fbbf24;
  --warning-bg: rgba(251, 191, 36, 0.12);
  --shadow-light: rgba(255, 255, 255, 0.05);
  --shadow-dark: rgba(0, 0, 0, 0.6);
  --shadow-raised: 0 0 0 1px var(--line), 0 12px 32px -16px rgba(0, 0, 0, 0.55);
  --shadow-raised-sm: 0 0 0 1px var(--line);
  --shadow-pressed: inset 0 0 0 1px var(--line);
  --shadow-flat: 0 0 0 1px var(--line);
  --elev-rest: 0 0 0 1px var(--line), 0 1px 2px rgba(0, 0, 0, 0.4);
  --elev-hover: 0 0 0 1px var(--line-strong), 0 12px 32px -14px rgba(0, 0, 0, 0.6);
  --elev-overlay: 0 0 0 1px var(--line), 0 32px 80px -24px rgba(0, 0, 0, 0.8);
  /* Cliente 360 dossier — same editorial register on a warm near-black
     paper, so the page still reads as a document at night. */
  --ed-bg: #14120f;
  --ed-paper: #1c1916;
  --ed-paper-2: #201d19;
  --ed-tint: #262117;
  --ed-ink: #f2ede3;
  --ed-ink-2: #ddd5c7;
  --ed-muted: #b3aa99;
  --ed-faint: #8a8175;
  --ed-hair: rgba(255, 255, 255, 0.09);
  --ed-hair-2: rgba(255, 255, 255, 0.17);
  --ed-accent: #e8703f;
  --ed-accent-soft: rgba(232, 112, 63, 0.16);
  --ed-good: #6fae82;
  --ed-warn: #e0b160;
  --ed-crit: #e07a6c;
  --ed-blue: #7fa8cc;
  --ed-inv-bg: #2e2820;
  --ed-inv-label: #a89e86;
  --ed-inv-value: #f7f2e8;
  --ed-inv-sub: #8a8175;
  --ed-p-el: #d8cfc0;
  --ed-p-or: #9ab377;
  --ed-p-zad: #e8703f;
  --ed-p-tw: #d1857a;

  /* Type dots lift on the dark canvas; rings widen to stay visible */
  --type-voice: #60a5fa;
  --type-voice-ring: rgba(96, 165, 250, 0.22);
  --type-legacy: #a78bfa;
  --type-legacy-ring: rgba(167, 139, 250, 0.22);
  --type-storage: #22d3ee;
  --type-storage-ring: rgba(34, 211, 238, 0.22);
  --type-test: #71717a;
  --type-test-ring: rgba(113, 113, 122, 0.28);
}

/* Thumbs de segmented controls (eram #fff) */
body.ds-v2.dark .nav-item.active,
body.ds-v2.dark .client-type-filter .ctf-pill.active,
body.ds-v2.dark .cc-tab.active,
body.ds-v2.dark .consumo .co-tab.on {
  background: var(--bg-card-2);
  color: var(--text-primary);
  box-shadow: 0 0 0 1px var(--line-strong);
}
body.ds-v2.dark .nav-item:hover,
body.ds-v2.dark .theme-toggle:hover { background: rgba(255, 255, 255, 0.05); }
body.ds-v2.dark .sidebar-collapse:hover { background: rgba(255, 255, 255, 0.05); }

/* Login — the light shadows carry no signal on a near-black canvas, so the
   ring does all the work. Google's mark stays multi-colour on dark by design. */
body.ds-v2.dark .login-google { box-shadow: inset 0 0 0 1px var(--line); }
body.ds-v2.dark .login-google:hover:not([disabled]) { box-shadow: inset 0 0 0 1px var(--line-strong); }
body.ds-v2.dark .login-error { box-shadow: inset 0 0 0 1px rgba(248, 113, 113, 0.28); }

/* Frost do header + specular edges */
body.ds-v2.dark .page-header { background: rgba(10, 10, 15, 0.78); }
body.ds-v2.dark .client-card,
body.ds-v2.dark .kpi-card { box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05), var(--elev-rest); }
body.ds-v2.dark .mobile-header,
body.ds-v2.dark .mobile-bottom-nav { background: rgba(10, 10, 15, 0.88); }

/* Consumo — remap das variáveis do módulo */
body.ds-v2.dark .consumo {
  --bg: var(--bg-base);
  --paper: #111118;
  --paper-2: #15151d;
  --tint: #191922;
  --ink: #f4f5f7;
  --ink-2: #c2c7d0;
  --muted: #9aa1ad;
  --faint: #646b78;
  --hair: rgba(255, 255, 255, 0.08);
  --hair-2: rgba(255, 255, 255, 0.14);
  --heavy: #e4e4e7;
  --accent-soft: rgba(59, 130, 246, 0.14);
}
body.ds-v2.dark .co-tip-float { background: #16161d; color: #f4f5f7; border-color: rgba(255, 255, 255, 0.12); }

/* Liquid glass (clients) — variante dark do campo + chrome */
body.ds-v2.dark[data-page="clients"] {
  background:
    radial-gradient(680px 460px at 8% -4%, rgba(59, 130, 246, 0.16), transparent 64%),
    radial-gradient(600px 440px at 90% 12%, rgba(139, 92, 246, 0.12), transparent 64%),
    radial-gradient(800px 560px at 72% 108%, rgba(0, 132, 255, 0.1), transparent 64%),
    var(--bg-base);
  background-attachment: fixed;
}
body.ds-v2.dark[data-page="clients"] .sidebar { background: rgba(13, 13, 19, 0.6); }
body.ds-v2.dark[data-page="clients"] .page-header { background: rgba(10, 10, 15, 0.5); }
body.ds-v2.dark[data-page="clients"] .search-bar,
body.ds-v2.dark[data-page="clients"] .client-type-filter {
  background: rgba(17, 17, 24, 0.55);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06), inset 0 0 0 1px var(--line);
}
body.ds-v2.dark[data-page="clients"] .client-type-filter .ctf-pill.active { background: var(--bg-card-2); }
body.ds-v2.dark[data-page="clients"] .client-card {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05), 0 0 0 1px var(--line), 0 4px 16px -8px rgba(0, 0, 0, 0.5);
}

/* Insets em dark: superfícies interiores vão para MAIS claro que o
   cartão (card-2), nunca para a cor da página (leem-se como buracos) */
body.ds-v2.dark .cc-inset,
body.ds-v2.dark .detail-section,
body.ds-v2.dark .client-card-info,
body.ds-v2.dark .consumo .co-drill .inner,
body.ds-v2.dark .consumo .co-ldrill .linner { background: var(--bg-card-2); }

/* Light: bucket com tint distinto do fundo da página */
body.ds-v2 .bucket { background: var(--bg-card-2); border-color: var(--line); }

/* Botões — hovers com literais claros */
body.ds-v2.dark .btn-raised:hover,
body.ds-v2.dark .client-card-actions .btn-accent:hover { background: #1f1f2a; }

/* ── Billing / Cost Calc (billing.css tem literais claros) ── */
body.ds-v2.dark .billing-card-plan {
  background: var(--bg-card-2);
  border: 1px solid var(--line);
}
body.ds-v2.dark .billing-card-plan strong { color: var(--text-primary); }
body.ds-v2.dark .billing-card-plan span { color: var(--text-secondary); }
body.ds-v2.dark .bucket {
  background: var(--bg-card-2);
  border-color: var(--line);
}
body.ds-v2.dark .bucket-total { background: rgba(52, 211, 153, 0.08); border-color: rgba(52, 211, 153, 0.25); }
body.ds-v2.dark .bucket-label,
body.ds-v2.dark .bucket-foot { color: var(--text-tertiary); }
body.ds-v2.dark .bucket-value { color: var(--text-primary); }
body.ds-v2.dark .bucket-bar { background: rgba(255, 255, 255, 0.08); }
body.ds-v2.dark .billing-meta { color: var(--text-secondary); }
body.ds-v2.dark .billing-meta b { color: var(--text-primary); }
body.ds-v2.dark .billing-card-header small { color: var(--text-secondary); }

body.ds-v2.dark .data-table th { background: var(--bg-card-2); color: var(--text-secondary); border-color: var(--line); }
body.ds-v2.dark .data-table td { color: var(--text-secondary); border-bottom-color: var(--line) !important; }
body.ds-v2.dark .data-table tr:hover td { background: rgba(255, 255, 255, 0.03); }
body.ds-v2.dark .data-table code { background: var(--bg-card-2); color: var(--text-secondary); }
body.ds-v2.dark .alert-success { background: var(--success-bg); border-color: rgba(52, 211, 153, 0.3); color: var(--success); }
body.ds-v2.dark .alert-danger  { background: var(--danger-bg); border-color: rgba(248, 113, 113, 0.3); color: var(--danger); }
body.ds-v2.dark .form-control,
body.ds-v2.dark .cc-input {
  background: var(--bg-base);
  border-color: var(--line);
  color: var(--text-primary);
}
body.ds-v2.dark .cc-rates-grid > div { background: var(--bg-card); border-color: var(--line); }
body.ds-v2.dark .cc-rates-grid h3 { color: var(--text-primary); }
body.ds-v2.dark .cc-chip { background: var(--bg-card-2); color: var(--text-secondary); }
body.ds-v2.dark .cc-chip-red { background: var(--danger-bg); color: var(--danger); }
body.ds-v2.dark .cc-table th,
body.ds-v2.dark .cc-table td { color: var(--text-secondary); }

/* ── Client Portal (tabela com navy hardcoded) ── */
body.ds-v2.dark .cp-table th { color: var(--text-tertiary); border-bottom-color: var(--line); }
body.ds-v2.dark .cp-table td { color: var(--text-secondary); border-bottom-color: var(--line); }
body.ds-v2.dark .cp-table code { background: var(--bg-card-2); color: var(--text-secondary); }
body.ds-v2.dark .cp-dim { color: var(--text-tertiary); }
body.ds-v2.dark .cp-card h2 { color: var(--text-primary); }

/* ── Client 360 / detail / drive — restos de texto escuro ── */
body.ds-v2.dark .cc-title,
body.ds-v2.dark .cc-name { color: var(--text-primary); }
body.ds-v2.dark .drive-item-name { color: var(--text-primary); }
body.ds-v2.dark .drive-item-meta { color: var(--text-tertiary); }
body.ds-v2.dark .drive-item { background: var(--bg-card); border-color: var(--line); }
body.ds-v2.dark .drive-breadcrumb { background: var(--bg-card); border-color: var(--line); color: var(--text-secondary); }
body.ds-v2.dark .modal-title { color: var(--text-primary); }
body.ds-v2.dark .modal-body h3 { color: var(--text-primary); }
body.ds-v2.dark .page-title,
body.ds-v2.dark .chart-title,
body.ds-v2.dark .nm-table-title { color: var(--text-primary); }

/* ═══════════ Paridade shadcn — specs canónicas portadas ═══════════
   Fonte: registry @shadcn (button.tsx / input.tsx, base style).
   focus ring 3px @~50% · disabled opacity .5 · invalid ring danger ·
   escala de alturas h-9/h-8 · svg shrink-0 + pointer-events none. */

/* Focus ring — hugging, 3px translúcido (spec: focus-visible:ring-[3px] ring-ring/50) */
body.ds-v2 :focus-visible {
  outline: 3px solid rgba(37, 99, 235, 0.4);
  outline-offset: 0;
}
body.ds-v2.dark :focus-visible { outline-color: rgba(59, 130, 246, 0.45); }
body.ds-v2 .input-field:focus-visible,
body.ds-v2 .search-bar input:focus-visible { outline: none; } /* ring próprio via box-shadow */

/* Disabled — universal (spec: disabled:pointer-events-none disabled:opacity-50) */
body.ds-v2 .btn:disabled,
body.ds-v2 button:disabled {
  opacity: 0.5;
  pointer-events: none;
}
body.ds-v2 .input-field:disabled,
body.ds-v2 input:disabled,
body.ds-v2 select:disabled,
body.ds-v2 textarea:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Validação — invalid ring danger (spec: aria-invalid:border-destructive ring-destructive/20) */
body.ds-v2 .input-field[aria-invalid="true"],
body.ds-v2 .input-field.input-invalid,
body.ds-v2 .input-error {
  box-shadow: inset 0 0 0 1px var(--danger), 0 0 0 3px rgba(220, 38, 38, 0.15);
}
body.ds-v2.dark .input-field[aria-invalid="true"],
body.ds-v2.dark .input-field.input-invalid,
body.ds-v2.dark .input-error {
  box-shadow: inset 0 0 0 1px var(--danger), 0 0 0 3px rgba(248, 113, 113, 0.2);
}

/* Escala de alturas — h-9 default / h-8 sm; transition-all como no spec */
body.ds-v2 .btn {
  min-height: 36px;
  transition: all 0.15s ease;
}
body.ds-v2 .btn-sm,
body.ds-v2 .btn.btn-sm { min-height: 32px; padding-top: 0; padding-bottom: 0; }
body.ds-v2 .btn svg { flex-shrink: 0; pointer-events: none; }

/* ═══════════ VPS Infra · toolbar refit (segmented control + selects contidos) ═══════════
   A barra antiga tinha 3 botões flex:1 a ocupar a largura toda (bulky).
   Agora: segmented control compacto estilo shadcn Tabs, com a área de
   contexto (última atualização + Atualizar) alinhada à direita. */

body.ds-v2 .vps-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 20px;
}

body.ds-v2 .vps-tab-bar {
  display: inline-flex;
  width: max-content;
  flex: 0 0 auto;
  gap: 2px;
  margin: 0;
  padding: 3px;
  background: var(--bg-card-2);
  border-radius: 10px;
  box-shadow: none;
}

body.ds-v2 .vps-tab {
  flex: 0 0 auto;
  min-height: 30px;
  padding: 5px 14px;
  gap: 7px;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: -0.01em;
  border-radius: 8px;
  color: var(--text-secondary);
}
body.ds-v2 .vps-tab svg { width: 14px; height: 14px; }
body.ds-v2 .vps-tab:hover { color: var(--text-primary); }
body.ds-v2 .vps-tab.active {
  background: var(--bg-card);
  color: var(--text-primary);
  font-weight: 600;
  box-shadow: 0 0 0 1px var(--line), 0 1px 2px rgba(9, 9, 11, 0.05);
}
body.ds-v2.dark .vps-tab.active {
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.10), 0 1px 2px rgba(0, 0, 0, 0.4);
}

body.ds-v2 .vps-toolbar-side {
  display: flex;
  align-items: center;
  gap: 10px;
}
body.ds-v2 .vps-live-updated {
  font-size: 12px;
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
}

/* Selects · o dropdown de cliente ocupava a largura toda do painel
   (parecia um botão gigante). Contido a 440px + altura h-9. */
body.ds-v2 #buy-client-select,
body.ds-v2 #restore-client-select { max-width: 440px; }

body.ds-v2 .vps-page select.input-field {
  height: 38px;
  padding: 0 36px 0 12px;
  font-size: 13.5px;
  font-weight: 500;
  /* o .input-field base usa background: shorthand, que faz reset ao repeat — repor aqui */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23a1a1aa' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
}
body.ds-v2 .vps-page select.input-field:hover:not(:focus) {
  box-shadow: inset 0 0 0 1px var(--line-strong);
}
body.ds-v2.dark .vps-page select.input-field {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23646b78' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
}

/* Labels dos campos seguem o spec .kv (11px / tertiary / uppercase) */
body.ds-v2 .vps-field label {
  font-size: 11px;
  letter-spacing: 0.05em;
  color: var(--text-tertiary);
}

/* Número de passo · chip subtil accent em vez de quadrado azul cheio */
body.ds-v2 .vps-num {
  width: 22px;
  height: 22px;
  border-radius: 6px;
  background: var(--accent-light);
  color: var(--accent);
  font-size: 11px;
}
