/*
 * Dashboard Styles — Ulfratech Client Portal
 * Extends /assets/css/ulfratech.css (light mode, no overrides to public site)
 *
 * Table of Contents:
 *   1.  Font
 *   2.  Dashboard Tokens
 *   3.  Base
 *   4.  Layout Shell
 *   5.  Sidebar
 *   6.  Main Wrapper & Topbar
 *   7.  Content Area
 *   8.  Cards
 *   9.  Stat Cards
 *  10.  Status Badges
 *  11.  Tables
 *  12.  Forms & Inputs
 *  13.  Buttons
 *  14.  Progress
 *  15.  Nav Pills (content-area scoped)
 *  16.  List Groups
 *  17.  Utility Classes
 *  18.  Dev Toolbar
 *  19.  Permission Visibility
 *  20.  Responsive
 */

/* ── 1. Font ────────────────────────────────────────────────── */
@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700;800&display=swap');

/* ── 2. Dashboard Tokens ────────────────────────────────────── */
:root {
  --sidebar-width:   256px;
  --topbar-height:   60px;

  /* Surfaces — light, clean */
  --dash-bg:         #f4f6f9;
  --dash-surface:    #ffffff;
  --dash-border:     rgba(0, 0, 0, 0.06);
  --dash-border-2:   rgba(0, 0, 0, 0.10);

  /* Elevation */
  --dash-shadow:     0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);
  --dash-shadow-md:  0 4px 16px rgba(0,0,0,0.09);

  /* Fill in --accent-200 (missing from ulfratech.css) */
  --accent-200:      #0072b5;

  /* Semantic status palette */
  --status-green:    #059669;
  --status-green-bg: #ecfdf5;
  --status-amber:    #d97706;
  --status-amber-bg: #fffbeb;
  --status-red:      #dc2626;
  --status-red-bg:   #fef2f2;
  --status-gray:     #6b7280;
  --status-gray-bg:  #f3f4f6;
}

/* ── 3. Base ────────────────────────────────────────────────── */
body {
  background-color: var(--dash-bg);
  font-family: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  font-size: 0.9375rem;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

/* ── 4. Layout Shell ────────────────────────────────────────── */
.dashboard-layout {
  display: flex;
  min-height: 100vh;
}

/* ── 5. Sidebar ─────────────────────────────────────────────── */
.sidebar {
  width: var(--sidebar-width);
  background: var(--dash-surface);
  border-right: 1px solid var(--dash-border);
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  z-index: 1030;
  display: flex;
  flex-direction: column;
  transition: transform var(--transition-normal);
  overflow: hidden;
}

.sidebar-brand {
  height: var(--topbar-height);
  display: flex;
  align-items: center;
  padding: 0 1.25rem;
  border-bottom: 1px solid var(--dash-border);
  flex-shrink: 0;
}

.sidebar-brand img {
  height: 34px;
  width: auto;
}

.sidebar-content {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  padding: 0.5rem 0 1rem;
  scrollbar-width: thin;
  scrollbar-color: var(--bg-300) transparent;
}

.sidebar-content::-webkit-scrollbar       { width: 3px; }
.sidebar-content::-webkit-scrollbar-track { background: transparent; }
.sidebar-content::-webkit-scrollbar-thumb { background: var(--bg-300); border-radius: 2px; }

/* Nav Categories */
.nav-category {
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  font-weight: 700;
  color: var(--text-300);
  padding: 0 1.25rem;
  margin: 1.25rem 0 0.25rem;
  display: block;
}

.nav-category:first-child { margin-top: 0.5rem; }

/* Sidebar Nav Links — scoped to .sidebar to prevent conflicts with Bootstrap
   .navbar-nav .nav-link and content-area .nav-pills .nav-link               */
.sidebar .nav-item { position: relative; }

.sidebar .nav-link {
  display: flex;
  align-items: center;
  padding: 0.5rem 1.25rem;
  color: var(--text-200) !important;
  font-weight: 500;
  font-size: 0.875rem;
  border-left: 3px solid transparent;
  border-radius: 0;
  transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
  text-decoration: none;
  gap: 0.625rem;
  margin: 1px 0;
}

.sidebar .nav-link i {
  font-size: 1rem;
  width: 18px;
  text-align: center;
  opacity: 0.6;
  flex-shrink: 0;
  transition: opacity var(--transition-fast);
}

.sidebar .nav-link:hover {
  background-color: var(--primary-300);
  color: var(--primary-100) !important;
}

.sidebar .nav-link:hover i { opacity: 1; }

.sidebar .nav-link.active {
  background-color: var(--primary-300);
  color: var(--primary-100) !important;
  border-left-color: var(--primary-100);
  font-weight: 600;
}

.sidebar .nav-link.active i { opacity: 1; }

/* Locked nav items (user lacks required group/permission) */
.sidebar .nav-link-locked {
  opacity: 0.4;
  cursor: not-allowed;
  pointer-events: none;
}

/* ── Collapsible Nav Sections ───────────────────────────────────────────
   Sectioned sidebar entries render as an accordion: a button header
   (small-caps label + chevron) and a list of indented nav items. State
   persistence lives in localStorage under `dashboard.sidebar.sections`.
   Honors prefers-reduced-motion by suppressing chevron rotation. */
.sidebar .nav-section {
  margin: 0.75rem 0 0.25rem;
}

.sidebar .nav-section--first { margin-top: 0.5rem; }

.sidebar .nav-section-header {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.375rem 1.25rem;
  background: none;
  border: 0;
  color: var(--text-300);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-align: left;
  cursor: pointer;
  border-radius: 0;
  transition: color var(--transition-fast), background var(--transition-fast);
}

.sidebar .nav-section-header:hover,
.sidebar .nav-section-header:focus-visible {
  color: var(--primary-100);
  background: var(--bg-200);
  outline: none;
}

.sidebar .nav-section-header:focus-visible {
  box-shadow: inset 0 0 0 2px var(--primary-100);
}

.sidebar .nav-section-label {
  flex: 1;
  min-width: 0;
}

.sidebar .nav-section-chevron {
  font-size: 0.75rem;
  opacity: 0.7;
  transition: transform var(--transition-fast);
}

.sidebar .nav-section.is-open .nav-section-chevron {
  transform: rotate(180deg);
}

/* Items are visually indented relative to the section header so the
   grouping is obvious at a glance without changing the link's gutter. */
.sidebar .nav-section-items .nav-link {
  padding-left: 1.75rem;
}

@media (prefers-reduced-motion: reduce) {
  .sidebar .nav-section-chevron,
  .sidebar .nav-section-header {
    transition: none;
  }
  .sidebar .nav-section.is-open .nav-section-chevron {
    transform: rotate(180deg);
  }
}

/* Sidebar Footer */
.sidebar-footer {
  padding: 0.875rem 1.25rem;
  border-top: 1px solid var(--dash-border);
  flex-shrink: 0;
}

.user-avatar {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--primary-100);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.75rem;
  font-weight: 700;
  flex-shrink: 0;
  letter-spacing: -0.02em;
}

/* Mobile overlay */
.sidebar-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.3);
  z-index: 1025;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition-normal);
  backdrop-filter: blur(2px);
}

/* ── 6. Main Wrapper & Topbar ───────────────────────────────── */
.main-wrapper {
  flex: 1;
  margin-left: var(--sidebar-width);
  display: flex;
  flex-direction: column;
  min-width: 0;
  transition: margin-left var(--transition-normal);
}

.topbar {
  height: var(--topbar-height);
  background: var(--dash-surface);
  border-bottom: 1px solid var(--dash-border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 1.5rem;
  position: sticky;
  top: 0;
  z-index: 1020;
  gap: 1rem;
}

.toggle-sidebar {
  display: none;
  background: none;
  border: none;
  font-size: 1.25rem;
  color: var(--text-200);
  cursor: pointer;
  padding: 0.25rem 0.375rem;
  margin-right: 0.5rem;
  border-radius: 0.375rem;
  transition: background var(--transition-fast), color var(--transition-fast);
  line-height: 1;
}

.toggle-sidebar:hover { background: var(--bg-200); color: var(--primary-100); }

/* ── 7. Content Area ────────────────────────────────────────── */
.content-area {
  padding: 1.5rem;
  flex: 1;
  min-width: 0;
}

.page-header {
  margin-bottom: 1.5rem;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 0.75rem;
}

.page-title {
  font-size: 1.375rem;
  font-weight: 700;
  color: var(--text-100);
  margin-bottom: 0.125rem;
  letter-spacing: -0.015em;
  line-height: 1.2;
}

.page-subtitle {
  font-size: 0.8125rem;
  color: var(--text-300);
  margin-bottom: 0;
}

/* ── 8. Cards ───────────────────────────────────────────────── */
.card {
  border: 1px solid var(--dash-border) !important;
  box-shadow: var(--dash-shadow) !important;
  border-radius: 0.75rem !important;
  background: var(--dash-surface);
  /* ulfratech.css sets transition:all on .card — narrow it so hover
     transform changes don't animate and bleed into adjacent elements */
  transition: box-shadow var(--transition-fast) !important;
}

.card:hover {
  transform: none !important;               /* beat ulfratech.css translateY(-5px) */
  box-shadow: var(--dash-shadow-md) !important;
}

.stat-card {
  /* Explicit reset so no stacking-context side-effects from any
     transform left on the element between paint cycles */
  transform: none !important;
  position: relative !important;
}

.card-header {
  padding: 0.875rem 1.25rem !important;
  background: var(--dash-surface) !important;
  border-bottom: 1px solid var(--dash-border) !important;
  border-radius: 0.75rem 0.75rem 0 0 !important;
  font-weight: 600;
  /* assets/css/ulfratech.css sets `.card-header { color: white }` for the
     marketing site's brand-filled headers. The dashboard flattens the header
     onto --dash-surface but never reset the colour, so every card-header
     heading rendered WHITE ON WHITE and was invisible — including
     "Recibos incluidos (N)" and "Relaciones (N)" in the Contabilidad console.
     Bound to the body colour so it stays correct in both themes. */
  color: var(--bs-body-color, var(--text-100)) !important;
}

.card-body { padding: 1.25rem !important; }

.card-footer {
  padding: 0.75rem 1.25rem !important;
  background: var(--bg-200) !important;
  border-top: 1px solid var(--dash-border) !important;
  border-radius: 0 0 0.75rem 0.75rem !important;
}

/* ── 9. Stat Cards ──────────────────────────────────────────── */
.stat-card {
  display: flex;
  flex-direction: column;
  padding: 1.25rem !important;
}

.stat-label {
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-300);
}

.stat-value {
  font-size: 2rem;
  font-weight: 700;
  color: var(--text-100);
  line-height: 1.1;
  letter-spacing: -0.02em;
  margin: 0.375rem 0;
}

.stat-icon {
  width: 36px;
  height: 36px;
  border-radius: 0.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1rem;
  background: var(--primary-300);
  color: var(--primary-100);
  margin-bottom: 0.75rem;
}

.stat-trend {
  font-size: 0.75rem;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 0.2rem;
}

.stat-trend.positive { color: var(--status-green); }
.stat-trend.negative { color: var(--status-red); }
.stat-trend.neutral  { color: var(--status-gray); }

/* ── 10. Status Badges — tone-tinted dot chips ──────────────────
   Elevated to the edge-fleet console language: a small tone dot + soft
   halo, a ~10% tone-tinted surface, a hairline tone border, and a squared
   (not pill) corner. Theme-aware by construction — every tint is mixed
   against --dash-surface, so it flips automatically in dark mode. The
   four semantic variants (active/pending/inactive/neutral) are preserved,
   so no markup changes anywhere they're used. */
.status-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  padding: 0.2em 0.6em 0.2em 0.5em;
  font-size: 0.6875rem;
  font-weight: 650;
  border-radius: 7px;
  letter-spacing: 0.02em;
  line-height: 1.45;
  vertical-align: middle;
  white-space: nowrap;
  color: var(--chip-fg, var(--status-gray));
  background: var(--chip-bg, var(--status-gray-bg));
  border: 1px solid var(--chip-bd, var(--dash-border-2));
}
/* Leading tone dot with a faint halo (currentColor = the chip's tone). */
.status-badge::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
  box-shadow: 0 0 0 2px color-mix(in srgb, currentColor 20%, transparent);
}

.status-active {
  --chip-fg: var(--status-green);
  --chip-bg: color-mix(in srgb, var(--status-green) 10%, var(--dash-surface));
  --chip-bd: color-mix(in srgb, var(--status-green) 28%, var(--dash-border-2));
}
.status-pending {
  --chip-fg: var(--status-amber);
  --chip-bg: color-mix(in srgb, var(--status-amber) 12%, var(--dash-surface));
  --chip-bd: color-mix(in srgb, var(--status-amber) 30%, var(--dash-border-2));
}
.status-inactive {
  --chip-fg: var(--status-red);
  --chip-bg: color-mix(in srgb, var(--status-red) 10%, var(--dash-surface));
  --chip-bd: color-mix(in srgb, var(--status-red) 30%, var(--dash-border-2));
}
.status-neutral {
  --chip-fg: var(--status-gray);
  --chip-bg: color-mix(in srgb, var(--status-gray) 10%, var(--dash-surface));
  --chip-bd: var(--dash-border-2);
}

/* Recibo vs. Factura — same tone-tinted chip mechanic as the status badges,
   but a document-KIND signal, not a lifecycle-status one. Deliberately
   distinct: a Recibo (neutral gray, receipt icon) must never read as the
   same kind of thing as a Factura (brand purple, fiscal-check icon) — see
   ulfratech-main-site/dashboard/js/pages/tax-documents.js. */
.doctype-recibo {
  --chip-fg: var(--status-gray);
  --chip-bg: color-mix(in srgb, var(--status-gray) 10%, var(--dash-surface));
  --chip-bd: var(--dash-border-2);
}
.doctype-factura {
  --chip-fg: var(--primary-100);
  --chip-bg: color-mix(in srgb, var(--primary-100) 10%, var(--dash-surface));
  --chip-bd: color-mix(in srgb, var(--primary-100) 28%, var(--dash-border-2));
}
/* These are a document-KIND signal (icon carries it); suppress the
   lifecycle-status tone dot so it doesn't read as a second, redundant cue. */
.doctype-recibo::before,
.doctype-factura::before {
  display: none;
}

/* Destino fiscal — the THIRD fiscal axis (where the settled OPERATION ended
   up), never to be confused with the document's own lifecycle status sitting
   next to it in the same row. Same tone mechanics, but a dashed hairline and a
   suppressed tone dot so the two chips are told apart by SHAPE, not only by
   colour — a wrong fiscal reading is expensive and some operators are
   colour-blind. Icon + full Spanish text always accompany the tone.
   See dashboard/js/admin/fiscal-status.js. */
.dest-badge {
  border-style: dashed;
  font-weight: 600;
}
.dest-badge::before { display: none; }

/* A fiscal status chip carries a MEANING icon (hourglass, patch-check, warning
   triangle, …) as its non-colour signal. The generic tone dot would then be a
   second, redundant cue right next to it, so it is suppressed — same treatment
   the doctype chips already get. Applied by fiscal-status.js `statusBadge()`. */
.status-badge.sb-icon::before { display: none; }

/* Quiet manual-refresh spin (fleet list-refresh convention) — applied to the
   icon only, never blocks the surrounding list with a full skeleton. */
@keyframes u-spin { to { transform: rotate(360deg); } }
.u-spin { animation: u-spin .7s linear infinite; display: inline-block; }

/* ── Deadline chip (factura global) ──────────────────────────────────────
   Live countdown to a deadline the BACKEND reported. Four tones, escalating:
   ok (>6 h) → warn (≤6 h) → critical (≤2 h) → breached (past due). A breached
   stamping deadline is a compliance failure, not a backlog item, so it gets a
   solid red chip plus a slow pulse — it must be impossible to scroll past.
   See dashboard/js/admin/fiscal-globals-tab.js. */
.deadline-chip {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  padding: .18rem .5rem;
  border-radius: 999px;
  font-size: .76rem;
  font-weight: 600;
  line-height: 1.2;
  white-space: nowrap;
  border: 1px solid var(--chip-bd, var(--dash-border-2));
  color: var(--chip-fg, inherit);
  background: var(--chip-bg, var(--dash-surface));
}
.deadline-ok {
  --chip-fg: var(--status-gray);
  --chip-bg: color-mix(in srgb, var(--status-gray) 8%, var(--dash-surface));
  --chip-bd: var(--dash-border-2);
}
.deadline-warn {
  --chip-fg: var(--status-amber);
  --chip-bg: color-mix(in srgb, var(--status-amber) 14%, var(--dash-surface));
  --chip-bd: color-mix(in srgb, var(--status-amber) 34%, var(--dash-border-2));
}
.deadline-critical {
  --chip-fg: var(--status-red);
  --chip-bg: color-mix(in srgb, var(--status-red) 14%, var(--dash-surface));
  --chip-bd: color-mix(in srgb, var(--status-red) 40%, var(--dash-border-2));
}
.deadline-breached {
  --chip-fg: #fff;
  --chip-bg: var(--status-red);
  --chip-bd: var(--status-red);
  animation: deadline-pulse 1.8s ease-in-out infinite;
}
@keyframes deadline-pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--status-red) 55%, transparent); }
  50%      { box-shadow: 0 0 0 5px color-mix(in srgb, var(--status-red) 0%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .deadline-breached { animation: none; }
}
/* Row accents so an at-risk period is visible while scanning the table. */
.globals-row-alert > td:first-child { box-shadow: inset 3px 0 0 0 var(--status-red); }
.globals-row-warn  > td:first-child { box-shadow: inset 3px 0 0 0 var(--status-amber); }

/* ── Cierre contable mensual (§19-H) ─────────────────────────────────────
   The outcome of a close check is THREE facts, not two: cumplida, no
   cumplida, and INDETERMINADA — a check that could not be evaluated. A
   close that reads green because something was unevaluable is the exact
   failure this screen exists to prevent, so the indeterminate variant is
   told apart from both others by SHAPE as well as tone: a dashed 2 px
   hairline against the solid 1 px of pass/fail, plus its own icon and its
   own Spanish word. Colour is never the only signal.
   See dashboard/js/admin/fiscal-close-tab.js. */
.check-badge { border-width: 1px; }
.check-pass {
  --chip-fg: var(--status-green);
  --chip-bg: color-mix(in srgb, var(--status-green) 10%, var(--dash-surface));
  --chip-bd: color-mix(in srgb, var(--status-green) 30%, var(--dash-border-2));
}
.check-fail {
  --chip-fg: var(--status-red);
  --chip-bg: color-mix(in srgb, var(--status-red) 12%, var(--dash-surface));
  --chip-bd: color-mix(in srgb, var(--status-red) 40%, var(--dash-border-2));
}
.check-indet {
  --chip-fg: var(--status-amber);
  --chip-bg: color-mix(in srgb, var(--status-amber) 10%, var(--dash-surface));
  --chip-bd: color-mix(in srgb, var(--status-amber) 45%, var(--dash-border-2));
  border-style: dashed;
  border-width: 2px;
}
/* There is deliberately no "no aplicable" tone: billing-service emits three
   verdicts and only three. A control that does not apply to a month is a
   control nobody evaluated, which is INDETERMINATE — giving it a fourth,
   calmer tone would be inventing a way for an unevaluated control to look
   settled. */

/* Compact counter used in the list row and the checks header. Same tone
   variables as the chips above, so a count can never disagree with the
   badge it summarises. */
.check-count {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  font-size: .74rem;
  font-weight: 700;
  line-height: 1;
  padding: .16rem .42rem;
  border-radius: 6px;
  white-space: nowrap;
  color: var(--chip-fg, var(--status-gray));
  background: var(--chip-bg, var(--status-gray-bg));
  border: 1px solid var(--chip-bd, var(--dash-border-2));
}
.check-count.check-indet { border-style: dashed; border-width: 2px; }

/* The ten §19-H requirements. Rendered as a fixed list — a requirement the
   service did not report is a visible "no informada" row, never a missing
   one — with a left accent per outcome so the checklist can be scanned. */
.check-list { list-style: none; margin: 0; padding: 0; }
.check-item {
  padding: .55rem .7rem;
  border: 1px solid var(--dash-border-2);
  border-left-width: 4px;
  border-radius: 8px;
  margin-bottom: .4rem;
  background: var(--dash-surface);
}
.check-item-passed        { border-left-color: var(--status-green); }
.check-item-failed        { border-left-color: var(--status-red); }
.check-item-indeterminate { border-left-color: var(--status-amber); border-left-style: dashed; }
.check-num {
  flex: none;
  width: 1.4rem; height: 1.4rem;
  border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: .68rem; font-weight: 700;
  color: var(--status-gray);
  border: 1px solid var(--dash-border-2);
}

/* The §15 equation, laid out so it visibly balances or does not. Terms wrap
   on narrow screens rather than scrolling the page sideways. */
.eq-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: .4rem;
}
.eq-term {
  flex: 1 1 8.5rem;
  min-width: 8rem;
  padding: .5rem .6rem;
  border: 1px solid var(--dash-border-2);
  border-radius: 8px;
  background: var(--dash-surface);
}
.eq-term-missing { border-style: dashed; border-width: 2px; }
.eq-term-label {
  font-size: .66rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  font-weight: 700;
  color: var(--status-gray);
}
.eq-term-value { font-size: .95rem; font-weight: 700; line-height: 1.4; }
.eq-term-note  { font-size: .64rem; color: var(--status-gray); margin-top: .15rem; }
.eq-term-flag  {
  font-size: .64rem;
  font-weight: 700;
  color: var(--status-amber);
  margin-top: .2rem;
  display: flex;
  align-items: center;
  gap: .2rem;
}
.eq-op {
  flex: none;
  align-self: center;
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--status-gray);
  padding: 0 .1rem;
}
.eq-op-equals { color: inherit; }

/* Row accents for the period list — same mechanic the factura-global list
   uses, so the two Contabilidad tables are read the same way. */
.close-row-alert > td:first-child { box-shadow: inset 3px 0 0 0 var(--status-red); }
.close-row-warn  > td:first-child { box-shadow: inset 3px 0 0 0 var(--status-amber); }

/* ── 11. Tables ─────────────────────────────────────────────── */
.table {
  font-size: 0.875rem;
  margin-bottom: 0;
}

.table thead th {
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--text-300);
  background: var(--bg-200) !important;
  border-bottom: 1px solid var(--dash-border) !important;
  padding: 0.625rem 1rem !important;
  white-space: nowrap;
}

.table tbody td {
  padding: 0.75rem 1rem !important;
  vertical-align: middle;
  border-color: var(--dash-border) !important;
  color: var(--text-100);
}

.table tbody tr:last-child td {
  border-bottom-color: transparent !important;
}

/* Accent-tinted row hover, mixed against the surface so it stays subtle in
   both themes (the flat --primary-300 stayed light on dark surfaces). */
.table-hover tbody tr:hover td {
  background: color-mix(in srgb, var(--primary-100) 6%, var(--dash-surface)) !important;
}

/* ── 12. Forms & Inputs ─────────────────────────────────────── */
.form-control,
.form-select {
  font-size: 0.875rem;
  padding: 0.45rem 0.875rem;
  border-radius: 0.5rem;
  border-color: var(--dash-border-2);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
  background-color: var(--dash-surface);
}

.form-control:focus,
.form-select:focus {
  border-color: var(--primary-100);
  box-shadow: 0 0 0 3px rgba(94, 74, 174, 0.1);
}

.form-control.bg-light,
.form-select.bg-light {
  background-color: var(--bg-200) !important;
  border-color: transparent;
}

.form-control.bg-light:focus {
  background-color: var(--dash-surface) !important;
  border-color: var(--primary-100);
}

.form-label {
  font-weight: 600;
  font-size: 0.8125rem;
  color: var(--text-200);
  margin-bottom: 0.375rem;
}

.input-group-text {
  font-size: 0.875rem;
  border-color: var(--dash-border-2);
  background: var(--bg-200);
  padding: 0.45rem 0.75rem;
}

.form-control-color {
  width: 56px;
  height: 42px;
  padding: 0.25rem;
  border-radius: 0.5rem;
  border-color: var(--dash-border-2);
}

/* ── 13. Buttons ────────────────────────────────────────────── */
.btn {
  font-weight: 600;
  font-family: 'Outfit', sans-serif;
  border-radius: 0.5rem;
  font-size: 0.875rem;
  padding: 0.45rem 1rem;
  transition: all var(--transition-fast);
}

.btn-sm  { padding: 0.3rem 0.75rem;  font-size: 0.8125rem; }
.btn-lg  { padding: 0.65rem 1.5rem;  font-size: 0.9375rem; }

/* ── 14. Progress ───────────────────────────────────────────── */
.progress {
  height: 8px;
  border-radius: 1rem;
  background: var(--bg-300);
  overflow: hidden;
}

.progress-bar {
  background: var(--primary-100);
  border-radius: 1rem;
}

.progress-bar-striped.progress-bar-animated {
  /* Flat color — no gradient overlay per design rule. */
  background-image: none;
}

/* ── 15. Sub-nav — underline tab bar (content-area scoped) ──────
   Elevated to the edge-fleet console language: a hairline underline tab
   bar (no pill fill), muted inactive labels, and an accent underline +
   weight bump on the active tab. Any count badge inside a tab renders as
   a squared mono chip that lights in the brand accent only when active
   (see §25). Scoped so it NEVER leaks into .sidebar .nav-link. Behaviour
   is unchanged — Bootstrap still toggles .active on click. */
.content-area .nav-pills {
  gap: 2px;
  border-bottom: 1px solid var(--dash-border);
  flex-wrap: wrap;
}

/* A sub-nav that opted into a segmented pill container (bg-light / p-1 /
   rounded-pill) is folded into the same underline system for one look. */
.content-area .nav-pills.rounded-pill {
  border-radius: 0 !important;
  background: transparent !important;
  padding: 0 !important;
}

.content-area .nav-pills .nav-link {
  padding: 0.5rem 0.9rem;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--text-300);
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  margin-bottom: -1px;
  transition: color var(--transition-fast), border-color var(--transition-fast);
}

.content-area .nav-pills .nav-link.active {
  background: transparent;
  color: var(--primary-100);
  border-bottom-color: var(--primary-100);
  box-shadow: none;
  font-weight: 700;
}

.content-area .nav-pills .nav-link:not(.active):hover {
  background: transparent;
  color: var(--text-100);
  border-bottom-color: var(--dash-border-2);
}

.content-area .nav-pills .nav-link:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--primary-100) 55%, transparent);
  outline-offset: 2px;
  border-radius: 4px;
}

/* ── 16. List Groups ────────────────────────────────────────── */
.list-group-item {
  padding: 0.875rem 1.25rem !important;
  border-color: var(--dash-border) !important;
  font-size: 0.875rem;
}

.list-group-item-action:hover {
  background: var(--primary-300) !important;
  color: var(--primary-100) !important;
}

/* ── 17. Utility Classes ────────────────────────────────────── */

/* Gradient backgrounds used in accent cards */
.bg-brand  { background: var(--primary-100) !important; }
.bg-accent { background: var(--accent-200)  !important; }

/* ── 18. Subscription chips (my-site overview) ─────────────── */

/* Tenant card body: stacks below 992px, side-by-side at lg+.
   Subs column is fixed to its natural cap so its space is predictable;
   sites column claims everything else and uses a wrap-grid (below) so
   the remaining width fills with cards instead of going blank. */
.tenant-card-grid {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.tenant-card-subs { min-width: 0; }
.tenant-card-sites {
  padding-top: 1rem;
  border-top: 1px solid var(--dash-border, #dee2e6);
  min-width: 0;
}
@media (min-width: 992px) {
  .tenant-card-grid {
    display: grid;
    grid-template-columns: minmax(280px, 560px) minmax(0, 1fr);
    gap: 1.5rem;
    align-items: start;
  }
  .tenant-card-sites {
    padding-top: 0;
    border-top: none;
    border-left: 1px solid var(--dash-border, #dee2e6);
    padding-left: 1.5rem;
  }
}

/* Soft plan pill (used on sub-chip + site mini-card). Keeps brand color
   recognizable via a tinted background and strong-colored text, but with
   far less visual weight than the saturated solid fill from PLAN_BADGE. */
.plan-pill-soft {
  display: inline-flex;
  align-items: center;
  padding: .1rem .45rem;
  border-radius: .85rem;
  font-size: .6rem;
  font-weight: 700;
  letter-spacing: .01em;
  background: var(--plan-pill-bg, rgba(108,117,125,.14));
  color:      var(--plan-pill-fg, #495057);
  white-space: nowrap;
  flex-shrink: 0;
  line-height: 1.3;
}
.plan-pill-soft[data-plan="plan.crece"]      { --plan-pill-bg: rgba(94,74,174,.14);  --plan-pill-fg: var(--primary-100); }
.plan-pill-soft[data-plan="plan.evoluciona"] { --plan-pill-bg: rgba(0,97,154,.15);   --plan-pill-fg: var(--accent-200); }
.plan-pill-soft[data-plan="plan.inicia"]     { --plan-pill-bg: rgba(108,117,125,.14); --plan-pill-fg: #495057; }

/* Dark theme: the pill's foregrounds above are chosen for a WHITE card, and a
   14%-opacity tint over a dark surface is nearly the surface itself. Lift both
   — brighter text, stronger tint — so the plan name stays readable. Measured
   before: 1.00–1.74:1. */
html[data-theme="dark"] .plan-pill-soft {
  background: var(--plan-pill-bg, rgba(255,255,255,.10));
  color:      var(--plan-pill-fg, #c9ced8);
}
html[data-theme="dark"] .plan-pill-soft[data-plan="plan.crece"]      { --plan-pill-bg: rgba(144,118,224,.24); --plan-pill-fg: #c3b5f5; }
html[data-theme="dark"] .plan-pill-soft[data-plan="plan.evoluciona"] { --plan-pill-bg: rgba(0,191,255,.22);   --plan-pill-fg: #7fd4ff; }
html[data-theme="dark"] .plan-pill-soft[data-plan="plan.inicia"]     { --plan-pill-bg: rgba(255,255,255,.12); --plan-pill-fg: #c9ced8; }

/* Site mini-cards: responsive wrap-grid (replaces former horizontal scroll).
   - Mobile: minmax forces 1 column on phones < ~400px (one full-width card).
   - Tablet & wide: auto-fills as many ~170px columns as fit, then stretches
     each to 1fr so cards keep edges aligned with no leftover blank space. */
.tenant-sites-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
  gap: .5rem;
}
.tenant-site-cell {
  min-height: 64px;
  transition: box-shadow .15s, border-color .15s;
}
.tenant-site-icon {
  width: 26px;
  height: 26px;
  font-size: .7rem;
}
@media (max-width: 399.98px) {
  .tenant-sites-grid {
    grid-template-columns: 1fr;
  }
}

.sub-list {
  max-width: 560px;
  /* Caps the visible list at ~4 typical rows. Mixed row heights
     (with/without the linked-sites sub-line) average ~50px + .5rem gap,
     so 4 rows ≈ 224px; 240px leaves a hint of the next row to signal scroll. */
  max-height: 240px;
  overflow-y: auto;
  padding-right: .35rem;
  scrollbar-gutter: stable;
}
.sub-list::-webkit-scrollbar { width: 6px; }
.sub-list::-webkit-scrollbar-thumb {
  background: var(--dash-border, #dee2e6);
  border-radius: 3px;
}
.sub-list::-webkit-scrollbar-thumb:hover { background: var(--primary-200, #9076e0); }
.sub-list { scrollbar-width: thin; scrollbar-color: var(--dash-border,#dee2e6) transparent; }

.sub-row {
  display: flex;
  flex-direction: column;
  gap: .15rem;
}

.sub-chip {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  width: 100%;
  padding: .35rem .55rem;
  background: transparent;
  border: 1px solid var(--dash-border);
  border-radius: .5rem;
  cursor: pointer;
  text-align: left;
  transition: background .15s, border-color .15s;
  line-height: 1.2;
}
.sub-chip:hover {
  background: var(--primary-300, rgba(94,74,174,.07));
  border-color: var(--primary-200, #9076e0);
}
.sub-chip:hover .sub-chip-arrow { opacity: 1; }
.sub-chip-price {
  font-size: .72rem;
  white-space: nowrap;
  flex-shrink: 0;
}
.sub-chip-renew {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  font-size: .7rem;
  white-space: nowrap;
  flex-shrink: 0;
}
.sub-chip-renew .bi { font-size: .72rem; opacity: .7; }
.sub-chip-renew-warn { color: var(--status-amber, #ad8b00); }
.sub-chip-renew-warn .bi { opacity: .85; }

/* Allocation pill colored by ENTITLEMENT UTILIZATION: using what you pay for is
   good. Base is NEUTRAL purple, matching the countable-quota vocabulary #usage
   uses; the dots show how full. Red means OVERAGE only. The previous scheme
   (red when empty, green when full) said the opposite of #usage for the same
   number, so the two screens disagreed about whether 0/3 was alarming. */
.sub-alloc {
  margin-left: auto;
  padding: .12rem .5rem;
  border-radius: .85rem;
  background: rgba(255,193,7,.18);
  color: var(--status-amber, #ad8b00);
  font-size: .68rem;
  font-weight: 600;
  white-space: nowrap;
  flex-shrink: 0;
}
/* Neutral by default: filling a plan's slots is a completion state, not an
   alarm and not a prize. The dots carry the "how full" signal, exactly as
   #usage does for the same countable quotas. */
.sub-alloc-neutral {
  background: rgba(94,74,174,.10);
  color: var(--primary-100, #5E4AAE);
}
/* Danger is reserved for genuine OVERAGE (used > cap) — the one case that is
   actually wrong rather than merely full. */
.sub-alloc-over {
  background: rgba(220,53,69,.14);
  color: var(--status-red, #dc3545);
}
.sub-alloc-dots {
  display: inline-flex;
  align-items: center;
  gap: .1rem;
  margin-right: .35rem;
  font-size: .5rem;
  vertical-align: middle;
}
.sub-alloc-dots .bi-circle-fill { color: var(--primary-100, #5E4AAE); }
.sub-alloc-dots .bi-circle      { opacity: .35; }

/* Shown only when every slot the plan grants is in use. States the fact and the
   two ways out; the offer itself comes from the service when the button is
   pressed, never from a guess made here. */
.sub-alloc-hint {
  margin-top: .35rem;
  font-size: .7rem;
  line-height: 1.35;
  color: var(--bs-secondary-color, #6c757d);
  max-width: 46ch;
}

/* ── Expansion nudge (engagement Phase 3) — contextual upsell, theme-aware.
   Inherits the .card background (dark-mode override handles it); adds a primary
   left accent. No gradient. ── */
.expansion-nudge {
  border: 1px solid var(--dash-border-2);
  border-left: 3px solid var(--primary-100);
}

/* ── Activation checklist (engagement Phase 1) — mobile-first, theme-aware ── */
.activation-card { border: 1px solid var(--dash-border-2); }
.act-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem 1.25rem; flex-wrap: wrap; }
.act-head-text { min-width: 0; }
.act-cta { flex-shrink: 0; white-space: nowrap; align-self: center; }
.act-progress { height: 6px; border-radius: 100px; background: var(--dash-border-2); margin: 1.1rem 0 .35rem; overflow: hidden; }
.act-progress > span { display: block; height: 100%; background: var(--primary-100); border-radius: 100px; }
.act-steps { list-style: none; margin: .5rem 0 0; padding: 0; display: flex; flex-direction: column; }
.act-step { display: flex; align-items: flex-start; gap: .8rem; padding: .5rem 0; }
.act-mark { flex: 0 0 auto; width: 22px; height: 22px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-size: .72rem; border: 2px solid var(--dash-border-2); color: var(--text-300); margin-top: .05rem; }
.act-done .act-mark { background: var(--status-green); border-color: var(--status-green); color: #fff; }
.act-current .act-mark { border-color: var(--primary-100); color: var(--primary-100); }
.act-body { display: flex; flex-direction: column; min-width: 0; }
.act-label { font-weight: 600; font-size: .92rem; color: var(--text-100); }
.act-done .act-label { color: var(--text-300); text-decoration: line-through; }
.act-hint { font-size: .78rem; color: var(--text-300); }
@media (prefers-reduced-motion: no-preference) { .act-progress > span { transition: width .5s ease; } }
@media (max-width: 575.98px) { .act-cta { width: 100%; align-self: stretch; margin-top: .25rem; } }

.sub-chip-arrow {
  margin-left: auto;
  flex-shrink: 0;
  opacity: 0;
  color: var(--primary-100);
  font-size: .65rem;
  transition: opacity .15s;
}
/* When the alloc pill is present, it takes the right-anchor slot
   and the chevron sits immediately after it with a small gap. */
.sub-alloc ~ .sub-chip-arrow { margin-left: .25rem; }

.sub-row-sites {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .35rem;
  padding: 0 .55rem 0 .75rem;
  font-size: .7rem;
  line-height: 1.3;
  color: var(--text-300, #6c757d);
}
.sub-row-sites::before {
  content: "└";
  color: var(--dash-border, #dee2e6);
  margin-right: .15rem;
}
.sub-row-sep { color: var(--dash-border, #dee2e6); }
.sub-site-link {
  color: var(--primary-100);
  text-decoration: none;
  font-weight: 500;
  display: inline-flex;
  align-items: center;
  gap: .2rem;
}
.sub-site-link:hover { text-decoration: underline; }
.sub-site-link .bi-globe { font-size: .65rem; opacity: .7; }
.sub-site-missing {
  color: var(--text-300, #6c757d);
  font-style: italic;
}
.sub-site-free {
  color: var(--primary-100);
  font-weight: 500;
}

.sub-chip-expired { opacity: .65; }
.sub-chip-expired:hover { opacity: 1; }

/* Cancelled subscription detail-cards inside the multi-sub <details> toggle.
   Slightly muted to signal "historical" without hiding their content. */
.sub-detail-card-muted { opacity: .75; }
.sub-detail-card-muted:hover { opacity: 1; }

/* ── Billing page (/dashboard/#billing) compact rows ───────────────────── */

.billing-sub-row {
  padding: .55rem .65rem;
  border: 1px solid var(--dash-border, #dee2e6);
  border-radius: .5rem;
  background: var(--dash-surface, #fff);
  color: var(--bs-body-color, inherit);
  transition: border-color .15s, box-shadow .15s;
}
.billing-sub-row:hover {
  border-color: var(--primary-200, #9076e0);
  box-shadow: 0 1px 4px rgba(0,0,0,.04);
}
.billing-sub-row.is-muted { opacity: .65; }
.billing-sub-row.is-muted:hover { opacity: 1; }

.billing-invoice-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  padding: .55rem .25rem;
  border-bottom: 1px solid var(--dash-border, #dee2e6);
}
.billing-invoice-row:last-child { border-bottom: none; }
/* Row is clickable → invoice-detail modal (delegated handler). */
.billing-invoice-row[data-invoice-id] { cursor: pointer; }
.billing-invoice-row[data-invoice-id]:hover { background: var(--dash-hover, rgba(0,0,0,.03)); }
/* The "Historial de pagos" per-page rows share the row style; the last row in a
   page shouldn't lose its border when a "Cargar más" wrap follows it. */
.history-rows-container .history-more-wrap { border-top: none; }

/* ── Subscription detail block (inside _renderSubscriptionBlock) ──
   Tight horizontal info bar replaces the old 3-card strip; section blocks
   with small uppercase titles replace the nested card wrappers around
   limits / features / addons / mgmt. */

.sub-info-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: .25rem 1.25rem;
  padding: .65rem .25rem;
  border-top: 1px solid var(--dash-border, #dee2e6);
  border-bottom: 1px solid var(--dash-border, #dee2e6);
  margin-bottom: 1rem;
}
.sub-info-cell {
  display: flex;
  flex-direction: column;
  gap: .2rem;
  min-width: 0;
  flex: 1 1 auto;
}
.sub-info-divider {
  width: 1px;
  background: var(--dash-border, #dee2e6);
  align-self: stretch;
}
@media (max-width: 575.98px) {
  .sub-info-bar { flex-direction: column; gap: .6rem; }
  .sub-info-divider { display: none; }
}

.sub-section { margin-bottom: 1rem; }
.sub-section:last-child { margin-bottom: 0; }
.sub-section-title {
  display: flex;
  align-items: center;
  gap: .35rem;
  font-size: .68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-300, #6c757d);
  margin-bottom: .4rem;
}

.limit-chip {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  padding: .15rem .55rem;
  font-size: .7rem;
  background: var(--dash-bg, #f8f9fa);
  color: var(--text-200, #495057);
  border-radius: .85rem;
  white-space: nowrap;
}
.limit-chip .bi { color: var(--primary-100); font-size: .72rem; }
.limit-chip .limit-value { font-weight: 700; color: var(--text-100, #212529); }

.feature-chip {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  padding: .12rem .5rem;
  font-size: .67rem;
  font-weight: 500;
  border-radius: .85rem;
  background: rgba(25,135,84,.10);
  color: #146c43;
}
.feature-chip .bi { font-size: .7rem; }
.feature-chip.is-disabled {
  background: rgba(108,117,125,.10);
  color: var(--text-300, #6c757d);
  font-weight: 400;
  text-decoration: line-through;
  text-decoration-thickness: 1px;
  opacity: .75;
}

.addon-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  padding: .35rem .25rem;
  font-size: .8rem;
  border-bottom: 1px solid var(--dash-border, #dee2e6);
}
.addon-row:last-child { border-bottom: none; }

.sub-expired-details summary {
  cursor: pointer;
  color: var(--primary-100);
  font-size: .72rem;
  font-weight: 500;
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  user-select: none;
}
.sub-expired-details summary::-webkit-details-marker { display: none; }
.sub-expired-details summary::after { content: "▾"; font-size: .6rem; }
.sub-expired-details[open] summary::after { content: "▴"; }

/* Cleanly land the expanded subscription card below any sticky chrome. */
[id^="subCollapse-"] { scroll-margin-top: 90px; }

/* Dropdown items */
.dropdown-item {
  padding: 0.6rem 1rem;
  font-size: 0.875rem;
  font-weight: 500;
}

/* Alerts */
.alert {
  font-size: 0.875rem;
  border-radius: 0.75rem;
}

/* Section divider label */
.section-label {
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text-300);
}

/* ── 19. Permission Visibility ──────────────────────────────── */
/*   Elements with data-requires-group / data-requires-permission
 *   are visible by default. dashboard.js hides them via .perm-hidden
 *   when the current user lacks the required claim.             */

.perm-hidden {
  display: none !important;
}

/* ── 20. Responsive ─────────────────────────────────────────── */
@media (max-width: 991.98px) {
  :root { --sidebar-width: 0px; }

  .sidebar {
    transform: translateX(-100%);
    width: 260px;
  }

  .sidebar.show {
    transform: translateX(0);
    box-shadow: var(--dash-shadow-md);
  }

  .sidebar-overlay {
    display: block;
  }

  .sidebar.show + .sidebar-overlay {
    opacity: 1;
    pointer-events: auto;
  }

  .toggle-sidebar { display: block; }
  .content-area   { padding: 1rem; }
}

@media (max-width: 575.98px) {
  .page-header    { flex-direction: column; align-items: stretch; }
  .stat-value     { font-size: 1.625rem; }
}

/* ── 21. W5 List-view primitives ────────────────────────────────────
 *   Extends the .u-empty-state / .u-skeleton primitives from
 *   /assets/css/ulfratech.css with classes the new shared/list-view.js
 *   helpers emit. See dashboard/UX_CONVENTIONS.md for adoption guide.
 */

.u-skeleton-block {
  display: flex;
  flex-direction: column;
  gap: .35rem;
  padding: 1rem;
}
.u-skeleton-row {
  display: flex;
  flex-direction: column;
  gap: .35rem;
}

.u-list-error.alert {
  margin: 0;
}
.u-list-error-msg {
  color: var(--text-200, #495057);
  word-break: break-word;
}

.u-load-more {
  border-top: 1px solid var(--dash-border);
}
.u-load-more-btn .spinner-border {
  vertical-align: -2px;
}

.u-list-count {
  display: inline-block;
}

/* Sortable column headers (shared/sort-header.js).
   Hover and focus get a subtle background hint so the affordance is
   discoverable; the arrow indicator gets pulled into the inline run by
   adjacent margin via .ms-1 in the JS, but live colors here. */
th.u-sortable {
  user-select: none;
  position: relative;
  white-space: nowrap;
  transition: background-color .12s;
}
th.u-sortable:hover {
  background: rgba(94, 74, 174, 0.06);
}
th.u-sortable:focus-visible {
  outline: 2px solid var(--primary-200, #9076e0);
  outline-offset: -2px;
}
th.u-sortable[aria-sort="ascending"] .u-sort-arrow,
th.u-sortable[aria-sort="descending"] .u-sort-arrow {
  color: var(--primary-100);
  opacity: 1;
}
th.u-sortable .u-sort-arrow {
  opacity: .55;
  font-size: .75rem;
  display: inline-block;
}

/* Date-bucket separators (shared/date-buckets.js).
   Sticky-ish header row inside long lists. Rounded top corners help
   visually punctuate the bucket inside .table-responsive. */
tr.u-date-bucket-row td.u-date-bucket {
  border-top: 1px solid var(--dash-border);
  border-bottom: 1px solid var(--dash-border);
  font-size: .68rem;
  letter-spacing: .04em;
}

/* ── 22. W5 Confirm-modal helper hooks ──────────────────────────────
 *   The shared/confirm-modal.js helper renders a typed-confirmation
 *   gate for irreversible operations. Match the surrounding form styles.
 */
#dashSharedConfirmModal .docs-confirm-list {
  margin: 0;
  padding-left: 1.1rem;
}
#dashSharedConfirmModal .docs-confirm-list li { line-height: 1.4; }
#dashSharedConfirmModal #dash-confirm-typed {
  font-family: 'JetBrains Mono', ui-monospace, monospace;
}

/* ── 23. W5 Required-field markers ──────────────────────────────────
 *   Forms that mark required fields with class .form-label-required
 *   get a small red asterisk auto-inserted via ::after. Pairs with
 *   aria-required="true" on the input.
 */
.form-label-required::after {
  content: " *";
  color: var(--status-red, #dc2626);
  font-weight: 700;
  margin-left: .15rem;
}

/* ── 24. Subscription summary card (shared component) ──────────────
 *   Used on #overview, #my-site, and #billing to give the customer a
 *   one-glance answer to "what am I paying for?". Composed of a header
 *   row (plan name + code + status), an optional description, a
 *   3-metric strip (cost / renewal / sites), and stacked sections for
 *   limits, add-ons, and capabilities. Inherits .sub-section,
 *   .limit-chip, .feature-chip, .plan-pill-soft, .status-badge from
 *   sections 10 and 18. */
.sub-summary-card {
  background: var(--dash-surface, #fff);
  color: var(--bs-body-color, inherit);
  border: 1px solid var(--dash-border, #dee2e6);
  border-radius: .65rem;
  padding: 1rem 1.1rem;
  box-shadow: 0 1px 2px rgba(0,0,0,.02);
}
.sub-summary-card-empty {
  background: var(--dash-bg, #f8f9fa);
  border-style: dashed;
}

.sub-summary-strip {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: .5rem 1.25rem;
  padding: .65rem .15rem;
  border-top: 1px solid var(--dash-border, #dee2e6);
  border-bottom: 1px solid var(--dash-border, #dee2e6);
  margin: .5rem 0 .85rem;
}
@media (max-width: 575.98px) {
  .sub-summary-strip {
    grid-template-columns: 1fr;
    gap: .55rem;
  }
}
.sub-summary-metric {
  display: flex;
  flex-direction: column;
  gap: .15rem;
  min-width: 0;
}
.sub-summary-metric-label {
  font-size: .62rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-300, #6c757d);
}
.sub-summary-metric-value {
  font-size: .85rem;
  line-height: 1.25;
  color: var(--text-100, #212529);
  display: flex;
  flex-direction: column;
  gap: .15rem;
  align-items: flex-start;
}
.sub-summary-actions { margin-top: .25rem; }

/* ── 21. Dark theme ────────────────────────────────────────────
 *
 * Minimal dark palette wired through the existing --dash-* tokens so every
 * surface that already read those tokens (sidebar, topbar, cards, tables,
 * modals) flips automatically — no per-component rewrite. The Bootstrap
 * bg-light / border-* utilities are the only stragglers; we override those
 * inline below where they appear in the dashboard chrome.
 *
 * Flat colors only — per [[no-gradients]] fleet convention. The palette
 * mirrors GitHub / Linear: near-black canvas, one step lighter for cards.
 * ─────────────────────────────────────────────────────────────── */
html[data-theme="dark"] {
  --dash-bg:        #0f1115;
  --dash-surface:   #171a21;
  --dash-border:    rgba(255, 255, 255, 0.08);
  --dash-border-2:  rgba(255, 255, 255, 0.14);
  --dash-shadow:    0 1px 3px rgba(0, 0, 0, 0.45), 0 1px 2px rgba(0, 0, 0, 0.35);
  --dash-shadow-md: 0 4px 16px rgba(0, 0, 0, 0.55);

  --bs-body-bg:     #0f1115;
  --bs-body-color:  #e6e8ec;

  /* The rest of the Bootstrap variables this stylesheet actually CONSUMES.
     They were missing, and a missing --bs-* does not fall back to a dark
     value — it keeps Bootstrap's LIGHT default, because we set our own
     `data-theme` attribute and never `data-bs-theme`, so Bootstrap's own dark
     block never activates.

     That is not cosmetic. `.plan-price-tax` on the checkout page reads
     `var(--bs-secondary-color)` and so rendered near-black #212529 at 75%
     opacity on a #171a21 card: a measured 1.13:1, i.e. the words "Incluye
     impuestos" were invisible on the page where the customer confirms what
     they are about to pay.

     Bridged here rather than by adding `data-bs-theme="dark"` to the shells:
     that would flip every Bootstrap component at once across four shells in
     one step, which is a much larger visual change than the bug warrants.
     Grep for `var(--bs-` before adding a consumer — if it is not in this
     list, it is still light. */
  --bs-secondary-color: rgba(230, 232, 236, 0.72);
  --bs-secondary:       #8a8f9a;
  --bs-border-color:    rgba(255, 255, 255, 0.14);
  --bs-tertiary-bg:     #1c1f27;
  --bs-light:           #1c1f27;

  /* Text tokens borrowed from ulfratech.css so utilities inherit correctly. */
  --text-100: #e6e8ec;
  --text-200: #b8bcc6;
  --text-300: #8a8f9a;
  --bg-100:   #171a21;
  --bg-200:   #1c1f27;
  --bg-300:   rgba(255, 255, 255, 0.16);
}

html[data-theme="dark"] body {
  background-color: var(--dash-bg);
  color: var(--bs-body-color);
}

/* Bootstrap chrome that hardcodes bg-light / white — hoist to dark surface. */
html[data-theme="dark"] .bg-light,
html[data-theme="dark"] .bg-white,
html[data-theme="dark"] .form-control.bg-light,
html[data-theme="dark"] .input-group-text.bg-light {
  background-color: var(--dash-surface) !important;
  color: var(--bs-body-color) !important;
  border-color: var(--dash-border) !important;
}

/* Cards read --dash-surface for background/border but the shadow needs a heavier
 * value in dark mode; --dash-shadow above already handles that. */
html[data-theme="dark"] .card {
  color: var(--bs-body-color);
}

/* Tables: Bootstrap defaults to light striping and dark text. */
html[data-theme="dark"] .table {
  --bs-table-bg:            transparent;
  --bs-table-color:         var(--bs-body-color);
  --bs-table-border-color:  var(--dash-border);
  --bs-table-striped-bg:    rgba(255, 255, 255, 0.03);
  --bs-table-striped-color: var(--bs-body-color);
  --bs-table-hover-bg:      rgba(255, 255, 255, 0.05);
  --bs-table-hover-color:   var(--bs-body-color);
  color: var(--bs-body-color);
}
html[data-theme="dark"] .table > :not(caption) > * > * {
  background-color: transparent;
  border-color: var(--dash-border);
}

/* Modals — background + border, plus header/footer separators. */
html[data-theme="dark"] .modal-content {
  background-color: var(--dash-surface);
  color: var(--bs-body-color);
  border-color: var(--dash-border);
}
html[data-theme="dark"] .modal-header,
html[data-theme="dark"] .modal-footer {
  border-color: var(--dash-border);
}
html[data-theme="dark"] .btn-close {
  /* Bootstrap ships a dark-on-light X SVG — invert it for dark surfaces. */
  filter: invert(1) grayscale(1) brightness(1.8);
}

/* Plain Bootstrap .nav-tabs (used by the unified #site-domains shell + the
 * domain detail modal). Bootstrap's default active tab is dark text on a light
 * fill with a light border — unreadable on a dark surface. Give the active tab
 * light text on the dark surface with a visible border; inactive/hover legible. */
html[data-theme="dark"] .nav-tabs {
  border-bottom-color: var(--dash-border);
}
html[data-theme="dark"] .nav-tabs .nav-link {
  color: var(--text-200);
}
html[data-theme="dark"] .nav-tabs .nav-link:hover,
html[data-theme="dark"] .nav-tabs .nav-link:focus {
  color: var(--text-100);
  border-color: var(--dash-border-2) var(--dash-border-2) var(--dash-border);
}
html[data-theme="dark"] .nav-tabs .nav-link.active {
  color: var(--text-100);
  background-color: var(--dash-surface);
  border-color: var(--dash-border-2) var(--dash-border-2) var(--dash-surface);
}

/* Form controls that don't opt into bg-light explicitly. */
html[data-theme="dark"] .form-control,
html[data-theme="dark"] .form-select,
html[data-theme="dark"] .input-group-text {
  background-color: var(--dash-surface);
  color: var(--bs-body-color);
  border-color: var(--dash-border-2);
}
html[data-theme="dark"] .form-control::placeholder {
  color: var(--text-300);
  opacity: 0.7;
}
html[data-theme="dark"] .form-control:focus,
html[data-theme="dark"] .form-select:focus {
  background-color: var(--dash-surface);
  color: var(--bs-body-color);
  border-color: var(--primary-200, #9076e0);
  box-shadow: 0 0 0 0.2rem rgba(144, 118, 224, 0.22);
}

/* Dropdown menus (notifications, admin, etc.). */
html[data-theme="dark"] .dropdown-menu {
  background-color: var(--dash-surface);
  color: var(--bs-body-color);
  border-color: var(--dash-border);
}
html[data-theme="dark"] .dropdown-item {
  color: var(--bs-body-color);
}
html[data-theme="dark"] .dropdown-item:hover,
html[data-theme="dark"] .dropdown-item:focus {
  background-color: rgba(255, 255, 255, 0.06);
  color: var(--bs-body-color);
}

/* text-muted maps to a softer gray on dark. */
html[data-theme="dark"] .text-muted {
  color: var(--text-300) !important;
}

/* List groups (search suggestions, tenant tabs, etc.). */
html[data-theme="dark"] .list-group-item {
  background-color: var(--dash-surface);
  color: var(--bs-body-color);
  border-color: var(--dash-border);
}

/* Billing-pending panels: warm peach tone in light mode; keep a subtle warm
 * tint in dark mode so the "attention" affordance survives the theme flip. */
.billing-pending-row {
  background: #fffaf0;
}
html[data-theme="dark"] .billing-pending-row {
  background: var(--dash-surface);
  color: var(--bs-body-color);
  border-color: var(--dash-border-2) !important;
}

/* Add-on price chip inside the subscription-summary add-on cards. The row
 * itself already sources --dash-surface / --dash-border and flips
 * automatically; the price pill sat on a hardcoded #f5f5f7 wash that stayed
 * light on dark. Tokenized here so both themes get the right neutral. */
.addon-price-chip {
  background: #f5f5f7;
}
html[data-theme="dark"] .addon-price-chip {
  background: rgba(255, 255, 255, 0.06);
  color: var(--text-200) !important;
}


/* ── Informative "i": hidden explanation, shown on hover or click-pin ──── */
/* Shared by the admin console (admin-dashboard.js) and the customer dashboard
   (dashboard.js) via shared/help-icon.js. Hidden by default; revealed on hover
   or when pinned open (.is-open) by a click. */
.admin-help {
  position: relative;
  display: inline-flex;
  vertical-align: middle;
  margin-left: .35rem;
}
.admin-help-i {
  border: 0;
  background: transparent;
  color: var(--bs-secondary, #6c757d);
  padding: 0;
  line-height: 1;
  font-size: .85rem;
  cursor: help;
  display: inline-flex;
  transition: color .15s ease;
}
.admin-help-i:hover,
.admin-help.is-open .admin-help-i { color: var(--primary-100, #5E4AAE); }
.admin-help-pop {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 1080;
  width: max-content;
  max-width: 340px;
  margin-top: .3rem;
  padding: .55rem .7rem;
  background: var(--dash-surface, #fff);
  color: var(--text-100, #212529);
  border: 1px solid var(--dash-border-2, #dee2e6);
  border-radius: .5rem;
  box-shadow: var(--dash-shadow-md, 0 .5rem 1.1rem rgba(0,0,0,.13));
  font-size: .78rem;
  font-weight: 400;
  line-height: 1.45;
  white-space: normal;
  text-align: left;
  text-transform: none;
  letter-spacing: normal;
}
.admin-help:hover .admin-help-pop,
.admin-help.is-open .admin-help-pop { display: block; }
/* Near the right edge of a container, anchor the popover to the right. */
.admin-help.help-end .admin-help-pop { left: auto; right: 0; }

/* Legend variant — a definition LIST rather than a one-line definition.
   The fiscal legend explains three orthogonal axes and cannot fit the 340px
   single-definition box: it would run 2000px tall and off the right edge.
   Widened, right-anchored and scrolled inside itself, so it stays the same
   component (hover / click-to-pin, same chrome) without ever pushing the page
   sideways. Used by fiscal-status.js `fiscalLegendHtml()`. */
.admin-help-pop.help-pop-legend {
  /* Left/right anchoring is decided at runtime by help-icon.js `_fitHelpPop`
     (which measures), so it is deliberately NOT pinned here. */
  width: min(30rem, calc(100vw - 3rem));
  max-width: none;
  max-height: min(70vh, 34rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: .75rem .9rem;
}

/* ══ 25. Elevated design layer — edge-fleet parity ══════════════════════
 *
 * A shared, dashboard-wide presentation layer that brings the refined
 * "precision-minimal" language shipped on the Flota Edge tab
 * (edge-fleet-ops-tab.js § _injectCss) to every OTHER tab, by enhancing the
 * SHARED components those tabs already render — with ZERO markup changes.
 *
 *   • Bootstrap badges (.badge.bg-*-subtle / .bg-* / .rounded-pill) become
 *     squared, hairline-bordered, tone-tinted chips — the loud rounded
 *     "pill" is gone platform-wide, and the tint is theme-aware (mixed
 *     against --dash-surface) so it reads correctly in dark mode too
 *     (Bootstrap's -subtle/-emphasis colours don't follow [data-theme]).
 *   • The underline sub-nav + accent mono counts live in §15 above.
 *   • Optional tone side-stripe stat cards (opt-in classes, additive).
 *
 * Rules are scoped to :is(.content-area, .modal) so they cover tab bodies
 * AND dialogs (incl. body-appended shared modals) without touching the
 * sidebar, topbar, or provisioning overlay. The edge-fleet tab is untouched
 * — it uses its own .fl-* classes + #fleetConsoleCss and never .badge /
 * .nav-pills. Flat colours only — NO gradients. */

/* Brighter status tones on dark surfaces so tinted chips + trend text keep
   their contrast (GitHub-dark-style palette). Also lifts .stat-trend and
   .status-* text automatically. */
html[data-theme="dark"] {
  --status-green: #3fb950;
  --status-amber: #d29922;
  --status-red:   #f85149;
  --status-gray:  #9198a1;
  --tone-info:    #4cc2ff;
}
:root { --tone-info: var(--accent-200); }

/* Base chip — typography + shape shared by every dashboard badge. Also
   normalises the oversized .badge padding inherited from the public-site
   ulfratech.css so counts and status tags read as compact chips. */
:is(.content-area, .modal) .badge {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  padding: 0.32em 0.6em;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  line-height: 1.4;
  vertical-align: middle;
  border-radius: 7px;
  border: 1px solid transparent;
}
/* Kill the pill — squared corners platform-wide. */
:is(.content-area, .modal) .badge.rounded-pill { border-radius: 7px; }

/* ── Alignment refinements — v/h align across shared components ───────────
   Additive, CSS-only. Inline icons, chips, and buttons sit on the OPTICAL
   MIDDLE of adjacent text instead of the baseline (the classic "icon/chip
   rides low" look); table headers align to their cells; icon-only buttons
   center their glyph. In flex containers vertical-align is ignored, so these
   only touch the inline contexts where the misalignment actually shows. */
:is(.content-area, .modal) .bi { vertical-align: -0.125em; line-height: 1; }
:is(.content-area, .modal) .btn { vertical-align: middle; }
:is(.content-area, .modal) .btn .bi { vertical-align: -0.075em; }
:is(.content-area, .modal) .table th,
:is(.content-area, .modal) .table td { vertical-align: middle; }
/* Icon-only buttons (just a .bi, no text) center the glyph both axes. */
:is(.content-area, .modal) .btn:has(> .bi:only-child) {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Tone mapping — each variant sets a tinted surface + tone text + hairline
   tone border, mixed against --dash-surface for theme awareness. !important
   + the two-class specificity beats Bootstrap's `.bg-* { …!important }` and
   any paired `.text-* {…!important}` utility. */
:is(.content-area, .modal) .badge.bg-success,
:is(.content-area, .modal) .badge.bg-success-subtle,
:is(.content-area, .modal) .badge.text-bg-success {
  color: var(--status-green) !important;
  background: color-mix(in srgb, var(--status-green) 11%, var(--dash-surface)) !important;
  border-color: color-mix(in srgb, var(--status-green) 30%, var(--dash-border-2)) !important;
}
:is(.content-area, .modal) .badge.bg-warning,
:is(.content-area, .modal) .badge.bg-warning-subtle,
:is(.content-area, .modal) .badge.text-bg-warning {
  color: var(--status-amber) !important;
  background: color-mix(in srgb, var(--status-amber) 13%, var(--dash-surface)) !important;
  border-color: color-mix(in srgb, var(--status-amber) 32%, var(--dash-border-2)) !important;
}
:is(.content-area, .modal) .badge.bg-danger,
:is(.content-area, .modal) .badge.bg-danger-subtle,
:is(.content-area, .modal) .badge.text-bg-danger {
  color: var(--status-red) !important;
  background: color-mix(in srgb, var(--status-red) 11%, var(--dash-surface)) !important;
  border-color: color-mix(in srgb, var(--status-red) 32%, var(--dash-border-2)) !important;
}
:is(.content-area, .modal) .badge.bg-primary,
:is(.content-area, .modal) .badge.bg-primary-subtle,
:is(.content-area, .modal) .badge.text-bg-primary {
  color: var(--primary-100) !important;
  background: color-mix(in srgb, var(--primary-100) 11%, var(--dash-surface)) !important;
  border-color: color-mix(in srgb, var(--primary-100) 32%, var(--dash-border-2)) !important;
}
:is(.content-area, .modal) .badge.bg-info,
:is(.content-area, .modal) .badge.bg-info-subtle,
:is(.content-area, .modal) .badge.text-bg-info {
  color: var(--tone-info) !important;
  background: color-mix(in srgb, var(--tone-info) 12%, var(--dash-surface)) !important;
  border-color: color-mix(in srgb, var(--tone-info) 32%, var(--dash-border-2)) !important;
}
:is(.content-area, .modal) .badge.bg-secondary,
:is(.content-area, .modal) .badge.bg-secondary-subtle,
:is(.content-area, .modal) .badge.bg-light,
:is(.content-area, .modal) .badge.bg-white,
:is(.content-area, .modal) .badge.text-bg-secondary,
:is(.content-area, .modal) .badge.text-bg-light,
:is(.content-area, .modal) .badge:not([class*="bg-"]) {
  color: var(--status-gray) !important;
  background: color-mix(in srgb, var(--status-gray) 10%, var(--dash-surface)) !important;
  border-color: var(--dash-border-2) !important;
}

/* Squared mono count chip inside an underline sub-nav tab (§15). Neutral by
   default; lights in the brand accent only when its tab is active. */
.content-area .nav-pills .nav-link .badge {
  margin-left: 0.1rem;
  padding: 0 0.32em;
  min-width: 1.15em;
  justify-content: center;
  font-family: 'JetBrains Mono', ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  font-size: 0.625rem;
  border-radius: 5px !important;
  color: var(--text-300) !important;
  background: var(--dash-bg) !important;
  border: 1px solid var(--dash-border) !important;
}
.content-area .nav-pills .nav-link.active .badge {
  color: var(--primary-100) !important;
  background: color-mix(in srgb, var(--primary-100) 10%, var(--dash-surface)) !important;
  border-color: color-mix(in srgb, var(--primary-100) 42%, var(--dash-border)) !important;
}

/* Optional tone side-stripe stat cards (opt-in, additive — no existing card
   regresses). Add .tone-ok / .tone-warn / .tone-bad / .tone-accent to a
   .stat-card to get a hairline elevation + a 3px inset tone stripe. */
.stat-card.tone-ok,
.stat-card.tone-warn,
.stat-card.tone-bad,
.stat-card.tone-accent {
  box-shadow: var(--dash-shadow), inset 3px 0 0 var(--stat-tone) !important;
}
.stat-card.tone-ok     { --stat-tone: var(--status-green); }
.stat-card.tone-warn   { --stat-tone: var(--status-amber); }
.stat-card.tone-bad    { --stat-tone: var(--status-red); }
.stat-card.tone-accent { --stat-tone: var(--primary-100); }
.stat-card.tone-warn .stat-value { color: var(--status-amber); }
.stat-card.tone-bad  .stat-value { color: var(--status-red); }

/* ── Rendered markdown (policy documents, read-only viewers) ────────────────
   Typography only. The HTML reaching here has already been through DOMPurify;
   these rules must never rely on that, they just make a long structured
   document readable instead of a wall of <pre>. */
.md-body { font-size: .875rem; line-height: 1.6; }
.md-body h1 { font-size: 1.35rem; }
.md-body h2 { font-size: 1.15rem; margin-top: 1.4rem; }
.md-body h3 { font-size: 1rem;    margin-top: 1.1rem; }
.md-body h1, .md-body h2, .md-body h3, .md-body h4 { font-weight: 700; }
.md-body h2, .md-body h3 { border-top: 1px solid var(--bs-border-color, #dee2e6); padding-top: .6rem; }
.md-body p, .md-body ul, .md-body ol, .md-body table { margin-bottom: .8rem; }
.md-body ul, .md-body ol { padding-left: 1.25rem; }
.md-body li { margin-bottom: .2rem; }
.md-body code {
  font-size: .82em;
  background: rgba(94,74,174,.09);
  padding: .1rem .3rem;
  border-radius: .25rem;
}
.md-body pre {
  background: var(--bs-tertiary-bg, #f8f9fa);
  padding: .7rem .85rem;
  border-radius: .5rem;
  overflow-x: auto;
}
.md-body pre code { background: none; padding: 0; }
.md-body blockquote {
  border-left: 3px solid var(--primary-100, #5E4AAE);
  padding: .2rem 0 .2rem .8rem;
  margin-left: 0;
  color: var(--bs-secondary-color, #6c757d);
}
/* Wide tables scroll inside the document, never widen the modal. */
.md-body table { width: 100%; border-collapse: collapse; display: block; overflow-x: auto; }
.md-body th, .md-body td { border: 1px solid var(--bs-border-color, #dee2e6); padding: .35rem .5rem; text-align: left; }
.md-body th { background: var(--bs-tertiary-bg, #f8f9fa); font-weight: 600; }
.md-body img { max-width: 100%; height: auto; }
.md-plain { white-space: pre-wrap; font-size: .8rem; margin: 0; }

/* ── Otorgar saldo — high-consequence value creation ───────────────────────
   Deliberately NOT an alert/danger treatment. Red is reserved for destruction,
   and an operator trained to click past red pays for it on a teardown screen.
   The weight here is FRICTION: a locked amount field, a consequence panel that
   updates as you choose, and a typed confirmation. No gradients. */
.gc-step { padding: .85rem 0; border-top: 1px solid var(--dash-border, rgba(0,0,0,.08)); }
.gc-step:first-of-type { border-top: 0; padding-top: .35rem; }
.gc-step-label {
  font-size: .68rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--text-300, #717171);
  margin-bottom: .35rem;
}
.gc-choices { display: grid; gap: .4rem; }
.gc-choice {
  display: flex; align-items: flex-start; gap: .1rem;
  padding: .55rem .7rem; border-radius: .5rem; cursor: pointer;
  border: 1px solid var(--dash-border-2, rgba(0,0,0,.12));
  font-size: .82rem;
}
.gc-choice:hover { border-color: var(--primary-200, #9076e0); }
.gc-choice:has(input:checked) {
  border-color: var(--primary-100, #5E4AAE);
  background: rgba(94, 74, 174, .06);
}
/* The consequence panel states, in the operator's own view, THE WORDS THE
   CUSTOMER WILL SEE — the most effective anti-confusion device on this screen,
   because a courtesy and a real balance are identical as a number. */
.gc-consequences {
  margin-top: 1rem; padding: .75rem .9rem;
  border-left: 3px solid var(--primary-100, #5E4AAE);
  background: var(--dash-surface-2, rgba(0,0,0,.03));
  border-radius: 0 .5rem .5rem 0;
}
.gc-consequences-title {
  font-size: .68rem; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: var(--text-300, #717171);
  margin-bottom: .35rem;
}
.gc-consequences-list { margin: 0; padding-left: 1.1rem; font-size: .8rem; line-height: 1.5; }
.gc-consequences-list > li + li { margin-top: .2rem; }

html[data-theme="dark"] .gc-choice:has(input:checked) { background: rgba(94, 74, 174, .18); }

/* ── Guided tour ─────────────────────────────────────────────────────────── */
/* The scrim is four solid panels around the target rather than one element
   with a hole: a box-shadow "hole" cannot be clicked through, and a gated step
   REQUIRES the real control to stay clickable. */
.tour-scrim {
    position: fixed;
    background: rgba(16, 16, 24, .55);
    z-index: 2000;
    pointer-events: auto;
}
.tour-ring {
    position: fixed;
    z-index: 2001;
    border-radius: .5rem;
    box-shadow: 0 0 0 3px #5E4AAE, 0 0 0 9px rgba(94, 74, 174, .28);
    pointer-events: none;
    transition: top .15s ease, left .15s ease, width .15s ease, height .15s ease;
}
.tour-pop {
    position: fixed;
    z-index: 2002;
    max-width: 22rem;
    background: var(--bs-body-bg, #fff);
    border: 1px solid var(--bs-border-color, #dee2e6);
    border-radius: .6rem;
    box-shadow: 0 .5rem 1.5rem rgba(0, 0, 0, .18);
    padding: .9rem 1rem;
}
.tour-pop h6 { margin: 0 0 .35rem; font-weight: 600; }
.tour-pop p  { margin: 0 0 .75rem; font-size: .86rem; color: var(--bs-secondary-color, #6c757d); }
.tour-pop-actions { display: flex; gap: .5rem; justify-content: flex-end; }
.tour-hint { font-size: .78rem; color: var(--bs-secondary-color, #6c757d); }

/* ─────────────────────────────────────────────────────────────────────────────
   Scrolling list boxes
   ---------------------------------------------------------------------------
   `.claude/rules/list-views.md`: a list of records is paginated and scrolls
   inside its own box. It must not grow the page without limit — once a list
   pushes everything below it off-screen, the controls around it (filters, the
   "new" button, the next section) stop being reachable without a long scroll
   back up, and on a phone that is most of the screen.

   `max-height` is in `vh` so the box adapts to the viewport instead of
   assuming a desktop window, with a `min-height` floor so a two-row list does
   not collapse into a sliver. `overscroll-behavior: contain` stops a flick at
   the end of the list from scrolling the page behind it, which on touch reads
   as the list "jumping".
   ────────────────────────────────────────────────────────────────────────── */
.support-scroll-list {
    max-height: 58vh;
    min-height: 8rem;
    overflow-y: auto;
    overscroll-behavior: contain;
    /* Room for the scrollbar so rows do not shift when it appears. */
    padding-right: .25rem;
}

/* The ticket thread inside the detail modal. Same rule, smaller budget: the
   modal also has to fit a reply box and its footer buttons, and a long thread
   that pushes "Responder" below the fold makes the modal look read-only. */
.support-thread-scroll {
    max-height: 42vh;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding-right: .25rem;
}
