/* =====================================================================
   Accendo Hub — app shell (internal CRM)
   Layer stack (load order in fragments/head.html):
     1. fonts-brand.css    (@font-face → /fonts/geist, geist-mono, newsreader)
     2. vendor/bootstrap 5.3.8
     3. brand/accendo.css  (marketing design tokens + Bootstrap overrides)
     4. hub.css            (this file — app chrome only)

   Prefer Bootstrap utilities/components. Prefer brand tokens (var(--navy),
   var(--blue), var(--ink), …). Do not re-declare the brand palette here.
   ===================================================================== */

/*
 * CRM density: slightly smaller type than marketing, tables stay readable.
 * Override only inside .hub-body so brand/marketing tokens stay intact.
 *
 * Surface guideline (card-on-paper):
 *   --paper / gray = app canvas only (headers, toolbars, tab chrome, spacing).
 *   Working content (forms, tables, empty states, audit, stats) sits on white
 *   cards: .panel, .hub-table-panel, .stat-card, .kanban-card, etc.
 *   Do not leave body copy floating on the gray canvas.
 */
.hub-body {
  --hub-fs: 0.875rem;           /* 14px body — CRM density */
  --hub-fs-sm: 0.8125rem;       /* 13px secondary */
  --hub-fs-xs: 0.6875rem;       /* 11px labels / thead */
  --hub-fs-title: 1.25rem;      /* 20px page titles */
  --hub-lh: 1.45;
  /* Cell air: modest vertical rhythm so dense type still breathes */
  --hub-cell-y: 0.55rem;
  --hub-cell-x: 0.75rem;
  --hub-sidebar-w: 15rem;
  --hub-content-topbar-h: 3.25rem;

  /*
   * Semáforo (opportunity temperature): a true thermal gradient. The warm end burns
   * red→orange→amber (Caliente/Cálida/Fría), then crosses over to cool light→deep blue
   * (Helada/Glaciar). Each pair is a text/icon tone plus a light background tint for the
   * status chip and the lit gauge step.
   */
  --sem-hot: #c8452b;
  --sem-hot-tint: #fbe7e1;
  --sem-warm: #e07b39;
  --sem-warm-tint: #fbeede;
  /* Fría is the pivot of the ramp, where a deal stops being warm and starts being cold, so it is
     the one rung that is neither. A desaturated periwinkle marks that crossover and drops the
     amber this used to be: amber read as a warning the band does not mean, and at #eaa92e on its
     own tint it was also the least legible pair in the palette. */
  --sem-cool: #6f6bb0;
  --sem-cool-tint: #edecf8;
  --sem-cold: #4f9fcb;
  --sem-cold-tint: #e4f0f8;
  --sem-frozen: #2c6a95;
  --sem-frozen-tint: #dbe7f0;

  margin: 0;
  min-height: 100vh;
  background: var(--paper);
  color: var(--body);
  font-family: var(--font-sans);
  font-size: var(--hub-fs);
  line-height: var(--hub-lh);
}

/* Bootstrap text controls inherit CRM density */
.hub-body .btn {
  font-size: var(--hub-fs);
  line-height: 1.35;
  padding: 0.35rem 0.7rem;
}

.hub-body .btn-sm {
  font-size: var(--hub-fs-sm);
  padding: 0.2rem 0.45rem;
}

.hub-body .form-control,
.hub-body .form-select {
  font-size: var(--hub-fs);
  line-height: 1.4;
  padding: 0.4rem 0.55rem;
}

/* Reserve right-side room for Bootstrap's chevron on every hub select. The density
   overrides above use a padding shorthand that zeroes the space Bootstrap keeps for
   the chevron background, so option text ran under the arrow. Selects only (never
   text inputs); specificity beats the shorthand and the -sm/quote select rules. */
.hub-body select.form-select {
  padding-right: 1.9rem;
}

.hub-body .form-label,
.hub-body .hub-form label {
  font-size: var(--hub-fs-sm);
}

.hub-body .alert {
  font-size: var(--hub-fs);
  padding: 0.55rem 0.75rem;
}

.hub-body .badge {
  font-size: var(--hub-fs-xs);
  font-weight: 500;
}

code,
kbd,
pre,
.font-mono,
.num-mono {
  font-family: var(--font-mono);
}

.serif,
.font-serif {
  font-family: var(--font-serif);
}

/* ── Shell: brand sidebar (full Accendo color) + content column ── */
.hub-shell {
  display: grid;
  grid-template-columns: 1fr;
  min-height: 100vh;
  min-height: 100dvh;
  padding: 0;
  max-width: 100%;
  align-items: stretch;
  background: var(--paper);
  transition: grid-template-columns 0.22s ease;
}

@media (min-width: 992px) {
  .hub-shell {
    grid-template-columns: var(--hub-sidebar-w) 1fr;
    overflow-x: clip; /* clip the slid-out rail; clip (not hidden) keeps sticky working */
    background-image: linear-gradient(
      to right,
      var(--navy) 0,
      var(--navy) var(--hub-sidebar-w),
      transparent var(--hub-sidebar-w)
    );
  }
  .hub-sidebar {
    min-width: var(--hub-sidebar-w);
    transition: transform 0.22s ease;
  }
  /* Collapse the rail to reclaim width for dense views (quote wizard on small laptops). */
  .hub-shell.is-nav-collapsed {
    grid-template-columns: 0 1fr;
    background-image: none;
  }
  .hub-shell.is-nav-collapsed .hub-sidebar {
    transform: translateX(-100%);
  }
}

@media (prefers-reduced-motion: reduce) {
  .hub-shell,
  .hub-sidebar {
    transition: none;
  }
}

/* Brand rail — full Accendo navy */
.hub-sidebar {
  background: var(--navy);
  color: var(--white);
  padding: 1.1rem 0.85rem 1rem;
  flex-direction: column;
  gap: 1rem;
  align-self: stretch;
  min-height: 100vh;
  min-height: 100dvh;
  position: sticky;
  top: 0;
  max-height: 100vh;
  max-height: 100dvh;
  overflow-y: auto;
  border-right: none;
}

.hub-sidebar-brand {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  text-decoration: none;
  color: var(--white);
  padding: 0.25rem 0.4rem 0.75rem;
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
  margin-bottom: 0.25rem;
}

.hub-sidebar-brand:hover {
  color: var(--blue-soft);
}

.hub-sidebar-logo {
  height: 1.35rem;
  width: auto;
  display: block;
}

.hub-sidebar-hub {
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  opacity: 0.92;
}

.hub-sidebar-brand-compact {
  border-bottom: none;
  margin: 0;
  padding: 0;
}

.hub-sidebar-footer {
  margin-top: auto;
  padding: 0.75rem 0.4rem 0.15rem;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
}

.hub-sidebar-footer-label {
  font-size: var(--hub-fs-xs);
  letter-spacing: 0.02em;
  text-transform: none;
  font-variant-numeric: tabular-nums;
  color: rgba(255, 255, 255, 0.45);
  font-weight: 500;
}

.hub-nav {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  width: 100%;
}

/* Links + group summaries share one row style on the brand rail */
.hub-nav-on-brand .hub-nav-link {
  color: rgba(255, 255, 255, 0.88);
  border-radius: 8px;
  padding: 0.45rem 0.7rem;
  font-weight: 500;
  font-size: var(--hub-fs-sm);
  display: flex;
  align-items: center;
  gap: 0.5rem;
  text-decoration: none;
  width: 100%;
  border: 0;
  background: transparent;
  cursor: pointer;
  line-height: 1.3;
}

.hub-nav-on-brand .hub-nav-link .ph {
  font-size: 1.05rem;
  opacity: 0.9;
  flex-shrink: 0;
}

.hub-nav-on-brand .hub-nav-link:hover {
  background: rgba(255, 255, 255, 0.1);
  color: var(--white);
}

/* Current page leaf */
.hub-nav-on-brand .hub-nav-link.is-active {
  background: rgba(255, 255, 255, 0.16);
  color: var(--white);
  font-weight: 600;
  box-shadow: inset 3px 0 0 0 var(--blue-soft, #7eb6e0);
}

.hub-nav-on-brand .hub-nav-link.is-active .ph {
  opacity: 1;
}

/* Branch that contains the current page */
.hub-nav-on-brand .hub-nav-summary.is-branch-active {
  color: var(--white);
  font-weight: 600;
}

/* Collapsible groups (level 1 and 2) */
.hub-nav-group {
  margin: 0;
  width: 100%;
}

.hub-nav-group > .hub-nav-summary {
  list-style: none;
  user-select: none;
}

.hub-nav-group > .hub-nav-summary::-webkit-details-marker {
  display: none;
}

.hub-nav-chevron {
  margin-left: auto;
  font-size: 0.95rem !important;
  opacity: 0.65 !important;
  transition: transform 0.15s ease;
}

.hub-nav-group[open] > .hub-nav-summary .hub-nav-chevron,
.hub-nav-group.is-open > .hub-nav-summary .hub-nav-chevron {
  transform: rotate(90deg);
}

.hub-nav-children {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  margin: 0.15rem 0 0.35rem;
  padding: 0.1rem 0 0.15rem 0.35rem;
  border-left: 1px solid rgba(255, 255, 255, 0.12);
  margin-left: 0.85rem;
}

.hub-nav-on-brand .hub-nav-sub {
  padding: 0.38rem 0.55rem;
  font-size: var(--hub-fs-sm);
  font-weight: 450;
}

.hub-nav-on-brand .hub-nav-sub .ph {
  font-size: 0.95rem;
}

/* Disabled nav leaf: a released-soon feature. Shown for wayfinding, not clickable. */
.hub-nav-on-brand .hub-nav-link.is-disabled {
  opacity: 0.5;
  cursor: default;
  pointer-events: none;
}

.hub-nav-on-brand .hub-nav-link.is-disabled .hub-nav-soon {
  margin-left: auto;
  padding: 0.05rem 0.4rem;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.28);
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  opacity: 0.85;
}

/* Level-2 nesting */
.hub-nav-group-nested {
  margin: 0.1rem 0;
}

.hub-nav-children-nested {
  margin-left: 0.65rem;
  padding-left: 0.3rem;
}

.hub-nav-on-brand .hub-nav-sub2 {
  padding: 0.32rem 0.5rem;
  font-size: 0.8125rem;
}

/* Content column: own top bar (not tied to the brand rail) */
.hub-main-column {
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 100vh;
  min-height: 100dvh;
}

.hub-content-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  min-height: var(--hub-content-topbar-h);
  padding: 0.45rem 1.25rem;
  background: var(--white);
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 1020;
}

.hub-content-topbar-start,
.hub-content-topbar-end {
  display: flex;
  align-items: center;
  min-width: 0;
}

.hub-content-topbar-end {
  gap: 0.75rem;
}

.hub-nav-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--paper);
  color: var(--ink);
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
  flex-shrink: 0;
}

.hub-nav-toggle:hover {
  background: var(--navy-tint);
  border-color: var(--blue-soft);
}

.hub-nav-toggle:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

/* User chip (content top bar) */
.hub-user-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  max-width: 16rem;
  padding: 0.25rem 0.55rem 0.25rem 0.3rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink);
  text-decoration: none;
  font: inherit;
  cursor: pointer;
}

.hub-user-chip:hover,
.hub-user-chip:focus-visible {
  border-color: var(--blue-soft);
  background: var(--white);
  color: var(--ink);
}

.hub-user-chip::after {
  margin-left: 0.15rem;
  opacity: 0.55;
}

.hub-user-avatar {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 999px;
  flex-shrink: 0;
  overflow: hidden;
  background: var(--navy);
  color: var(--white);
}

.hub-user-avatar-icon {
  font-size: 1rem;
  line-height: 1;
  opacity: 0.95;
}

/* Photo sits on top of the Phosphor user icon; on error JS removes the img. */
.hub-user-avatar-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  border-radius: 999px;
  background: var(--navy);
}

.hub-user-meta {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  min-width: 0;
  line-height: 1.2;
  text-align: left;
}

.hub-user-name {
  font-size: var(--hub-fs-sm);
  font-weight: 600;
  color: var(--ink);
  max-width: 11rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.hub-user-email {
  font-size: var(--hub-fs-xs);
  color: var(--muted);
  max-width: 11rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.hub-user-dropdown {
  min-width: 14rem;
  font-size: var(--hub-fs-sm);
}

.hub-user-dropdown-email {
  font-size: var(--hub-fs-xs);
  color: var(--muted);
}

.hub-logout-form {
  margin: 0;
}

.hub-logout-btn {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  width: 100%;
}

/* Offcanvas (phone) — same brand paint as desktop rail */
.hub-offcanvas {
  --bs-offcanvas-width: min(18rem, 88vw);
  background: var(--navy);
  color: var(--white);
  border-right: none;
}

.hub-offcanvas-header {
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}

.hub-offcanvas-body {
  padding-top: 1rem;
}

.hub-main {
  padding: 1rem 1.25rem 1.5rem;
  min-width: 0;
  max-width: 100%;
  width: 100%;
  overflow-x: clip;
  flex: 1 1 auto;
}

/* Login (standalone) */
.hub-login-body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  background:
    radial-gradient(1200px 600px at 10% -10%, rgba(73, 141, 190, 0.35), transparent 55%),
    radial-gradient(900px 500px at 100% 100%, rgba(57, 54, 100, 0.45), transparent 50%),
    var(--navy);
  color: var(--white);
  font-family: var(--font-sans);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
}

/* Static locally hosted contour layer over the navy gradient. */
.hub-login-contours {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
  object-fit: cover;
  opacity: 0.78;
  mix-blend-mode: screen;
}

.hub-login {
  position: relative;
  z-index: 1;
  width: min(24rem, 100%);
}

.hub-login-panel {
  background: rgba(11, 25, 49, 0.88);
  border: 1px solid rgba(255, 255, 255, 0.24);
  border-radius: 18px;
  padding: 2.25rem 1.85rem 1.85rem;
  backdrop-filter: blur(10px);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.28);
}

.hub-login-brand {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  margin-bottom: 1.75rem;
}

.hub-login-brand img {
  height: 1.5rem;
  width: auto;
}

.hub-login-title {
  font-family: var(--font-serif);
  font-size: 1.75rem;
  font-weight: 500;
  margin: 0 0 0.65rem;
  letter-spacing: -0.02em;
  color: var(--white);
}

.hub-login-lead {
  margin: 0 0 1.85rem;
  color: rgba(255, 255, 255, 0.72);
  font-size: 0.95rem;
  line-height: 1.55;
}

.hub-login-actions {
  margin-top: 0.25rem;
}

.hub-login-google {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.65rem;
  width: 100%;
  padding: 0.8rem 1rem;
  border-radius: 10px;
  background: var(--white);
  color: var(--ink);
  font-weight: 600;
  font-size: 0.95rem;
  text-decoration: none;
  border: none;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}

.hub-login-google:hover {
  color: var(--ink);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
  transform: translateY(-1px);
}

.hub-login-google-icon {
  display: inline-flex;
}

.hub-login-divider {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 1.75rem 0 1.25rem;
  color: rgba(255, 255, 255, 0.45);
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.hub-login-divider::before,
.hub-login-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: rgba(255, 255, 255, 0.14);
}

.hub-login-local {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.hub-login-field label {
  display: block;
  margin-bottom: 0.35rem;
  font-size: 0.8rem;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.7);
}

.hub-login-field .form-control {
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.18);
  color: var(--white);
  border-radius: 8px;
  padding: 0.55rem 0.7rem;
}

.hub-login-field .form-control::placeholder {
  color: rgba(255, 255, 255, 0.35);
}

.hub-login-field .form-control:focus {
  background: rgba(255, 255, 255, 0.1);
  border-color: var(--blue-soft);
  color: var(--white);
  box-shadow: 0 0 0 0.15rem rgba(146, 187, 216, 0.25);
}

.hub-login-local-submit {
  margin-top: 0.25rem;
  width: 100%;
  padding: 0.7rem 1rem;
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: 10px;
  background: transparent;
  color: var(--white);
  font-weight: 600;
  font-size: 0.9rem;
  cursor: pointer;
}

.hub-login-local-submit:hover {
  background: rgba(255, 255, 255, 0.08);
}

.hub-login-footnote {
  margin: 1.5rem 0 0;
  font-size: 0.75rem;
  color: rgba(255, 255, 255, 0.62);
  line-height: 1.5;
}

.hub-login-footnote .hub-login-local-link {
  margin-top: 0;
  margin-right: 0.15rem;
}

.hub-login-local-access {
  margin: 0.45rem 0 0;
}

/* Terms of use (public, linked from login) — readable on login canvas.
   The login container is a 24rem card, which is the wrong shape for a legal document: it turned
   fifteen clauses into a phone-width ribbon. The page widens to a real document and sets the text
   in two columns, so the measure stays readable (~55 characters) instead of growing with the panel. */
.hub-login.hub-terms {
  width: min(64rem, 100%);
}
.hub-terms .hub-terms-panel {
  max-width: none;
  max-height: min(92vh, 60rem);
  overflow: auto;
  text-align: left;
  padding: 2.5rem 2.75rem 2rem;
}
.hub-terms-meta {
  font-size: 0.8rem;
  color: rgba(255, 255, 255, 0.55);
  line-height: 1.45;
  margin: 0 0 1.25rem;
}
.hub-terms-body {
  font-size: 0.85rem;
  color: rgba(255, 255, 255, 0.82);
  line-height: 1.55;
  columns: 2;
  column-gap: 3rem;
}
.hub-terms-body h2 {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--white);
  margin: 1.25rem 0 0.4rem;
  /* A clause heading stranded at the foot of a column reads as a different clause than the one it
     introduces, so headings stay with their text and no paragraph is split across the fold. */
  break-after: avoid;
  break-inside: avoid;
}
.hub-terms-body h2:first-child {
  margin-top: 0;
}
.hub-terms-body p,
.hub-terms-body li {
  break-inside: avoid;
}
@media (max-width: 900px) {
  .hub-terms-body {
    columns: 1;
  }
}
.hub-terms-body p,
.hub-terms-body ul {
  margin: 0 0 0.65rem;
}
.hub-terms-body ul {
  padding-left: 1.2rem;
}
.hub-terms-body li {
  margin-bottom: 0.35rem;
}

.hub-login-local-link {
  display: inline-block;
  margin-top: 0.55rem;
  color: rgba(255, 255, 255, 0.55);
  text-decoration: none;
  border-bottom: 1px solid rgba(255, 255, 255, 0.2);
  font-size: 0.72rem;
}

.hub-login-local-link:hover {
  color: var(--blue-soft);
  border-bottom-color: var(--blue-soft);
}

.hub-login-alert {
  border-radius: 8px;
  padding: 0.6rem 0.75rem;
  font-size: 0.85rem;
  margin-bottom: 1.25rem;
}

.hub-login-alert-ok {
  background: rgba(110, 164, 203, 0.2);
  border: 1px solid rgba(110, 164, 203, 0.45);
  color: var(--blue-soft);
}

.hub-login-alert-error {
  background: rgba(180, 60, 60, 0.2);
  border: 1px solid rgba(220, 120, 120, 0.4);
  color: #f0c4c4;
}

.hub-content {
  width: 100%;
  max-width: none;
  font-size: var(--hub-fs);
  line-height: var(--hub-lh);
}

.hub-crumbs {
  font-size: var(--hub-fs-xs);
  color: var(--muted);
  margin-bottom: 0.85rem;
  letter-spacing: 0.02em;
}

/*
 * Views use the full width of the main column (sidebar already reserved).
 * Do not re-introduce page max-widths — tables and headers should breathe.
 */
.hub-page,
.hub-page-sm,
.hub-page-wide {
  width: 100%;
  max-width: none;
}

/* Vertical rhythm between title block and body (no horizontal rules) */
.page-header,
.hub-form-header {
  margin: 0 0 1.15rem;
  padding: 0;
}

.page-header h1,
.hub-page-title,
.hub-form-title {
  margin: 0 0 0.25rem;
  font-size: var(--hub-fs-title);
  font-family: var(--font-sans);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.25;
  color: var(--ink);
}

.page-header-text {
  min-width: 0;
  flex: 1 1 auto;
}

.page-header-actions {
  flex-shrink: 0;
}

.page-header .subtitle,
.subtitle {
  margin: 0;
  color: var(--muted);
  max-width: none;
  font-size: var(--hub-fs-sm);
  line-height: 1.4;
}

.page-header-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 0.65rem 1rem;
  flex-wrap: wrap;
  margin-bottom: 1.15rem;
}

.page-header-row > .btn,
.page-header-row > .action-row {
  flex-shrink: 0;
}

/* Stack of sections under a page header */
.page-header + .panel,
.page-header + .hub-table-panel,
.page-header + .hub-form,
.page-header + .stat-row,
.page-header + .kanban-scroll,
.page-header + .hub-detail-toolbar {
  margin-top: 0.55rem;
}

.hub-form-header + .hub-form,
.hub-form-header + .hub-form-summary {
  margin-top: 0;
}

/* Identity + toolbar read as one block: less gap under the title when toolbar follows */
.page-header:has(+ .hub-detail-toolbar) {
  margin-bottom: 0;
}

/*
 * Detail ficha toolbar: navigation (Regresar) left, mutate (Editar / Eliminar) right.
 * Invisible row — spacing only, no bar. Keeps destructive actions away from back.
 */
.hub-detail-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.65rem 1rem;
  margin: 0 0 1.15rem;
  padding: 0;
}

.hub-detail-toolbar-end {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.45rem;
  margin-left: auto;
}

/* Icon + word actions (detail pages). List row actions stay icon-only. */
.hub-btn-icon-text {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: var(--hub-fs-sm);
  line-height: 1.3;
  padding: 0.35rem 0.7rem;
}

.hub-btn-icon-text .ph {
  font-size: 1.05em;
  line-height: 1;
  flex-shrink: 0;
}

/*
  Permission-denied primary action (see fragments/gated-action.html). Reads as a button but is
  inert: dimmed, no hover lift, not-allowed cursor. Keeps pointer-events so the "sin permiso"
  title tooltip still appears on hover (Bootstrap's .disabled would suppress it).
*/
.hub-action-denied,
.hub-action-denied:hover,
.hub-action-denied:focus {
  opacity: 0.55;
  cursor: not-allowed;
  box-shadow: none;
  transform: none;
  filter: grayscale(0.25);
}

/* Soft danger outline aligned with brand red (not Bootstrap purple-pink) */
.btn-outline-danger.hub-btn-icon-text {
  --bs-btn-color: #c23b3b;
  --bs-btn-border-color: #e0a0a0;
  --bs-btn-hover-bg: #fdecea;
  --bs-btn-hover-border-color: #c23b3b;
  --bs-btn-hover-color: #9a2e2e;
  --bs-btn-active-bg: #fdecea;
  --bs-btn-active-border-color: #9a2e2e;
  --bs-btn-active-color: #9a2e2e;
}

.hub-detail-toolbar + .panel,
.hub-detail-toolbar + .hub-meta-panel,
.hub-detail-toolbar + .hub-tab-bar {
  margin-top: 0;
}

/* Header state control (opportunity detail): quiet, same row as Editar/Eliminar. */
.hub-state-form {
  align-items: center;
  gap: 0.4rem;
}

.hub-state-form .form-select {
  width: auto;
}

/*
 * Company-spine tabs (and any future entity hub tabs).
 * Path-driven ?tab= — active underline, counts for list tabs.
 */
.hub-tab-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.15rem 0.1rem;
  margin: 0 0 1rem;
  padding: 0;
  border-bottom: 1px solid var(--line-soft);
}

.hub-tab-item {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.55rem 0.75rem;
  margin-bottom: -1px;
  font-size: var(--hub-fs-sm);
  font-weight: 500;
  color: var(--muted);
  text-decoration: none;
  /* Normalize <button> chrome so JS-toggled tabs (home) match the <a> tabs
     (company spine): no UA background, outset border, radius, or font. */
  appearance: none;
  -webkit-appearance: none;
  background: none;
  border: 0;
  border-radius: 0;
  border-bottom: 2px solid transparent;
  font-family: inherit;
  white-space: nowrap;
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease;
}

.hub-tab-item:hover {
  color: var(--ink);
}

.hub-tab-item.is-active {
  color: var(--navy);
  border-bottom-color: var(--navy);
  font-weight: 600;
}

.hub-tab-count {
  font-size: var(--hub-fs-xs);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  color: var(--muted);
  background: var(--paper);
  border: 1px solid var(--line-soft);
  border-radius: 999px;
  padding: 0.05rem 0.4rem;
  min-width: 1.35rem;
  text-align: center;
}

.hub-tab-item.is-active .hub-tab-count {
  color: var(--navy);
  border-color: var(--line);
  background: var(--navy-tint, var(--paper));
}

.hub-tab-panel {
  width: 100%;
  margin: 0 0 1rem;
}

/* Secondary actions only — never a second copy of the tab label */
.hub-tab-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 0.5rem 1rem;
  margin: 0 0 0.75rem;
}

/* Create / primary actions sit above the table in every list tab */
.hub-tab-create {
  margin: 0 0 1rem;
}

.hub-tab-create + .hub-table-panel,
.hub-tab-create + .empty-hint {
  margin-top: 0;
}

.hub-tab-bar + .hub-tab-panel {
  margin-top: 0;
}

.panel + .panel,
.hub-meta-panel + .panel,
.panel + .hub-form {
  margin-top: 0.85rem;
}

/* UI paradigm: no horizontal bars / HR separators — ever.
   Use spacing, type weight, and panels for hierarchy. */
.section-divider,
hr,
.hub-hr {
  display: none !important;
}

/* Brand eyebrow — always Geist sans (never serif / system default) */
.eyebrow {
  font-family: var(--font-sans);
  margin: 0 0 0.3rem;
  font-size: var(--hub-fs-xs);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 500;
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
}

/* ── Form pages (canonical: /companies/new) ── */
.hub-form-page .hub-form-header {
  margin-bottom: 1.15rem;
}

.hub-form-page .hub-form-title {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--hub-fs-title);
  letter-spacing: -0.02em;
  line-height: 1.2;
  color: var(--ink);
  margin: 0 0 0.25rem;
}

.hub-form-page .subtitle {
  max-width: none;
}

/* Fields may stay readable-width; the page itself is full width */
.hub-form-page .hub-form .field {
  max-width: 36rem;
}

.hub-form-page .hub-form .form-control,
.hub-form-page .hub-form .form-select {
  max-width: 100%;
  width: 100%;
  border-color: var(--line);
  border-radius: 8px;
  font-family: var(--font-sans);
  color: var(--ink);
}

.hub-form-page .hub-form .form-control:focus {
  border-color: var(--blue);
  box-shadow: 0 0 0 0.2rem rgba(73, 141, 190, 0.2);
}

.field-req {
  display: inline-block;
  margin-left: 0.35rem;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--blue-deep);
  background: var(--navy-tint);
  border-radius: 999px;
  padding: 0.1rem 0.45rem;
  vertical-align: middle;
}

.field-opt {
  display: inline-block;
  margin-left: 0.35rem;
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0.1rem 0.45rem;
  vertical-align: middle;
}

/* Percent suffix group (landed, margins) — always one horizontal row */
.hub-percent-input {
  max-width: 12rem;
  flex-wrap: nowrap !important;
  display: flex;
  align-items: stretch;
}
.hub-percent-input .form-control {
  letter-spacing: 0.02em;
  width: 1%;
  flex: 1 1 auto;
  min-width: 0;
}
.hub-percent-suffix {
  min-width: 2.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  background: var(--white);
  border-left: 1px solid var(--line-soft);
  font-weight: 600;
  flex: 0 0 auto;
  white-space: nowrap;
}

/*
 * Hub checkbox — calm square control (not Bootstrap form-switch pills).
 * Use .hub-check / .hub-check-input / .hub-check-label on forms.
 */
.hub-check {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  margin: 0;
  padding: 0.45rem 0;
  cursor: pointer;
  user-select: none;
}
.hub-check-input {
  appearance: none;
  -webkit-appearance: none;
  flex: 0 0 auto;
  width: 1.125rem;
  height: 1.125rem;
  margin: 0;
  border: 1.5px solid var(--line);
  border-radius: 4px;
  background: var(--white);
  cursor: pointer;
  transition: border-color 0.12s ease, background-color 0.12s ease, box-shadow 0.12s ease;
}
.hub-check-input:hover {
  border-color: var(--blue-soft);
}
.hub-check-input:focus {
  outline: none;
  border-color: var(--blue);
  box-shadow: 0 0 0 3px rgba(73, 141, 190, 0.22);
}
.hub-check-input:checked {
  border-color: var(--navy);
  background-color: var(--navy);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' d='M3.5 8.5l3 3 6-6'/%3E%3C/svg%3E");
  background-size: 0.75rem 0.75rem;
  background-position: center;
  background-repeat: no-repeat;
}
.hub-check-input:checked:hover {
  border-color: var(--navy);
  background-color: var(--navy-2, #102036);
}
.hub-check-label {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--hub-fs-sm);
  font-weight: 500;
  color: var(--ink);
  line-height: 1.4;
  cursor: pointer;
}
.hub-check-hint {
  display: block;
  margin-top: 0.15rem;
  font-size: var(--hub-fs-xs);
  font-weight: 400;
  color: var(--muted);
  line-height: 1.35;
}

/* Role group on party (tercero) form */
.party-roles {
  border: 0;
  margin: 0;
  padding: 0;
  min-inline-size: 0;
}
.party-roles-legend {
  font-size: var(--hub-fs-sm);
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 0.15rem;
  padding: 0;
}
.party-roles-box {
  margin-top: 0.35rem;
  padding: 0.15rem 0.85rem;
  border: 1px solid var(--line-soft);
  border-radius: 8px;
  background: var(--white);
}

/* Never use Bootstrap form-switch pills in hub forms */
.hub-form .form-switch {
  display: none !important;
}

.field-hint {
  margin: 0.25rem 0 0;
  font-size: var(--hub-fs-xs);
  color: var(--muted);
  line-height: 1.35;
}

.is-invalid-field label {
  color: #8b1e1e;
}

.hub-form-summary {
  background: #fdecea;
  color: #5c1a1a;
  border-radius: 12px;
  padding: 0.85rem 1rem;
  margin: 0 0 1rem;
}

.hub-form-summary-title {
  margin: 0 0 0.35rem;
  font-weight: 600;
  font-family: var(--font-sans);
}

.hub-form-summary ul {
  margin: 0;
  padding-left: 1.1rem;
}

.hub-meta-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: 0.85rem 1.25rem;
  margin: 0;
}

.hub-meta-grid dt {
  font-size: var(--hub-fs-xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  font-weight: 600;
  margin: 0 0 0.2rem;
}

.hub-meta-grid dd {
  margin: 0;
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--hub-fs);
  line-height: var(--hub-lh);
}

.hub-meta-by {
  display: block;
  font-size: var(--hub-fs-sm);
  color: var(--muted);
  margin-top: 0.15rem;
}

/*
 * One table system for every hub list (DataTables and plain).
 * Markup: .hub-table-panel > table.table.table-striped.table-hover.table-borderless
 *         .align-middle.hub-datatable (add .hub-datatable-nav when row click navigates)
 * Excel: HubDataTable default Buttons (data-hub-export="false" to opt out).
 */
.hub-table-panel {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  padding: 0.85rem 0.9rem 0.65rem;
  width: 100%;
  margin: 0 0 1rem;
  box-shadow: 0 1px 0 rgba(14, 42, 69, 0.03);
}

/* Wide DataTables (e.g. Registro with its Detalle column) scroll horizontally
   inside their card instead of spilling past it. Scrollbar sits under the table;
   the search/length/paging chrome and the card edges stay put. */
.hub-table-panel .dt-container .dt-layout-table {
  overflow-x: auto;
}

/* DataTables top chrome: length + Excel sit calmly together */
div.dt-container .dt-buttons {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin: 0;
  float: none;
}
div.dt-container .dt-buttons .btn.hub-dt-export,
div.dt-container .dt-buttons .dt-button.hub-dt-export {
  font-size: var(--hub-fs-sm);
  font-weight: 500;
  border-radius: 8px;
  padding: 0.28rem 0.7rem;
  border: 1px solid var(--line);
  background: var(--white);
  color: var(--ink);
  line-height: 1.35;
}
div.dt-container .dt-buttons .btn.hub-dt-export:hover,
div.dt-container .dt-buttons .dt-button.hub-dt-export:hover {
  background: var(--paper);
  border-color: var(--blue-soft, #7eb6e0);
  color: var(--navy);
}
/* Buttons 3 processing state — clear affordance while audit + zip run */
div.dt-container .dt-buttons .dt-button.processing,
div.dt-container .dt-buttons .btn.processing {
  opacity: 0.65;
  pointer-events: none;
  position: relative;
}
div.dt-container .dt-buttons .dt-button.processing::after,
div.dt-container .dt-buttons .btn.processing::after {
  content: "";
  display: inline-block;
  width: 0.7rem;
  height: 0.7rem;
  margin-left: 0.4rem;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  vertical-align: -0.1rem;
  animation: hub-dt-spin 0.6s linear infinite;
}
@keyframes hub-dt-spin {
  to { transform: rotate(360deg); }
}

.hub-datatable,
.hub-table {
  --dt-row-hover: 210, 232, 245;
  font-family: var(--font-sans);
  font-size: var(--hub-fs);
  line-height: var(--hub-lh);
  width: 100%;
  margin: 0;
  border-color: var(--line-soft);
  background: var(--white);
}

/* Row click affordance only when navigation is wired */
.hub-datatable-nav tbody tr {
  cursor: pointer;
}

/* Brand sky hover (overrides Bootstrap grey/white hover) */
table.hub-datatable.table-hover > tbody > tr:hover > *,
table.hub-table.table-hover > tbody > tr:hover > * {
  --bs-table-bg-state: transparent;
  background-color: rgba(110, 164, 203, 0.14) !important;
  box-shadow: none !important;
}

table.hub-datatable.table-striped > tbody > tr:nth-of-type(odd):hover > *,
table.hub-table.table-striped > tbody > tr:nth-of-type(odd):hover > * {
  background-color: rgba(110, 164, 203, 0.16) !important;
}

.hub-datatable thead th,
.hub-table th {
  font-size: var(--hub-fs-xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  font-weight: 600;
  white-space: nowrap;
  background: var(--paper);
  border-bottom-color: var(--line-soft);
  padding: var(--hub-cell-y) var(--hub-cell-x);
  vertical-align: middle;
}

.hub-datatable tbody td,
.hub-table td {
  font-size: var(--hub-fs);
  line-height: var(--hub-lh);
  color: var(--ink);
  border-bottom-color: var(--line-soft);
  padding: var(--hub-cell-y) var(--hub-cell-x);
  vertical-align: middle;
}

.hub-datatable tbody tr:last-child td,
.hub-table tr:last-child td {
  border-bottom: none;
}

.hub-datatable a,
.hub-table a {
  color: var(--blue-deep);
  text-decoration: none;
  font-weight: 500;
}

/* Outcome chips on the system log */
.badge.hub-table-badge-ok {
  background: #e6f7f1;
  color: #0d7a55;
}
.badge.hub-table-badge-warn {
  background: #fff6e5;
  color: #9a6b00;
}
.badge.hub-table-badge-danger {
  background: #fdecec;
  color: #a32020;
}

.hub-datatable a:hover,
.hub-table a:hover {
  color: var(--navy);
}

/* Status / enum chips inside tables (same on list and tab tables) */
.badge.hub-table-badge,
.hub-datatable .badge.hub-table-badge {
  font-weight: 500;
  font-size: var(--hub-fs-xs);
  background: var(--navy-tint);
  color: var(--navy);
  border: 1px solid var(--line-soft);
}

.hub-col-actions {
  width: 1%;
  white-space: nowrap;
}

/*
 * Semáforo (opportunity temperature) chips — fragments/semaforo.html :: badge / badgeCompact.
 * The sem-* modifier carries a color/tint pair via CSS variables; the chip itself just reads them,
 * so badge, compact badge, kanban accent, and gauge all share one palette definition.
 */
.sem-hot {
  --sem-color: var(--sem-hot);
  --sem-tint: var(--sem-hot-tint);
}
.sem-warm {
  --sem-color: var(--sem-warm);
  --sem-tint: var(--sem-warm-tint);
}
.sem-cool {
  --sem-color: var(--sem-cool);
  --sem-tint: var(--sem-cool-tint);
}
.sem-cold {
  --sem-color: var(--sem-cold);
  --sem-tint: var(--sem-cold-tint);
}
.sem-frozen {
  --sem-color: var(--sem-frozen);
  --sem-tint: var(--sem-frozen-tint);
}

/*
 * Contact circuit and recommendation chips. Both reuse the .sem-badge chrome and only supply the
 * --sem-color/--sem-tint pair, so the workspace stays on one palette definition instead of growing
 * a second chip system.
 *
 * The circuit colors stay calm on purpose: an open circuit is a decision the system made on the
 * consultant's behalf, not a failure to flag at them.
 */
.circuit-closed {
  --sem-color: var(--muted);
  --sem-tint: var(--line-soft);
}
.circuit-open {
  --sem-color: var(--sem-frozen);
  --sem-tint: var(--sem-frozen-tint);
}
/* Borrows the "work that is due" tone rather than a temperature band: an authorised single retry
   is a task, not a temperature, and it used to inherit the amber that Fría no longer wears. */
.circuit-half-open {
  --sem-color: var(--sem-warm);
  --sem-tint: var(--sem-warm-tint);
}

/*
 * Repair affordance: a record that cannot do its job because a link is missing says so and offers
 * the fix in place. Amber rather than red, because nothing is broken or lost; something is
 * incomplete and the person reading the row is the one who can complete it.
 */
.hub-repair-link {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  color: #9a6b00;
  font-weight: 600;
  text-decoration: none;
}
.hub-repair-link:hover {
  text-decoration: underline;
}

/*
 * Ink-only chip: same chrome, no signal color. Used where a chip is context rather than the
 * decision, so a row carries exactly one colored element. The icon and the word still carry the
 * meaning; only the hue is spent elsewhere.
 */
.chip-quiet {
  --sem-color: var(--muted);
  --sem-tint: var(--line-soft);
}

/* Three urgency tiers, not nine prompts: attention now, work that is due, deliberate silence. */
.rec-now {
  --sem-color: var(--sem-hot);
  --sem-tint: var(--sem-hot-tint);
}
.rec-soon {
  --sem-color: var(--sem-warm);
  --sem-tint: var(--sem-warm-tint);
}
.rec-quiet {
  --sem-color: var(--muted);
  --sem-tint: var(--line-soft);
}

/* Temperatura workspace: derived customer response beside the team's effort clock. */
.temperature-help-grid,
.temperature-patterns {
  display: grid;
  gap: 1rem;
}
.temperature-patterns p {
  margin-bottom: 0;
}

/*
 * Legend above the table. Three blocks reading left to right in the order the columns do, so the
 * page teaches its own vocabulary without a trip to the help guide.
 */
.temperature-legend {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.5rem 2rem;
  margin-bottom: 1rem;
}
.temperature-legend-block-wide {
  grid-column: 1 / -1;
}
.temperature-legend-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0.55rem 0 0.6rem;
}
.temperature-legend-note {
  margin-bottom: 0;
  color: var(--muted);
  font-size: var(--hub-fs-sm);
  line-height: 1.5;
  max-width: 62ch;
}
.temperature-followup {
  color: var(--muted);
  font-weight: 600;
}
/* Overdue used to be red, which restated the Acción chip in a second color one column earlier.
   Weight and ink carry it now; the row's one color stays on the decision. */
.temperature-followup.is-overdue {
  color: var(--ink);
  font-weight: 700;
}
.temperature-contact {
  min-width: 11rem;
}
.temperature-guidance {
  min-width: 17rem;
  line-height: 1.4;
}
.temperature-action-text {
  display: block;
  margin-top: 0.35rem;
  font-weight: 600;
}
.temperature-reason {
  min-width: 19rem;
  color: var(--muted);
  line-height: 1.4;
}
.temperature-age {
  display: block;
  color: var(--muted);
  font-size: var(--hub-fs-xs);
  margin-top: 0.2rem;
}
.temperature-help-grid {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.temperature-help-list {
  margin-bottom: 0;
  padding-left: 1.25rem;
}
.temperature-help-list li {
  margin-bottom: 0.45rem;
}
.temperature-patterns {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.temperature-patterns h3 {
  font-size: var(--hub-fs-md);
  margin-bottom: 0.4rem;
}
@media (max-width: 900px) {
  .temperature-legend,
  .temperature-help-grid,
  .temperature-patterns {
    grid-template-columns: 1fr;
  }
}

/* Colors plain text by the sem-* modifier already on the element (e.g. the opportunity-detail
   subtitle's state word) without the badge/chip chrome. */
.sem-text {
  color: var(--sem-color);
}

.sem-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.15rem 0.55rem;
  border-radius: 999px;
  font-size: var(--hub-fs-xs);
  font-weight: 600;
  line-height: 1.3;
  color: var(--sem-color);
  background: var(--sem-tint);
  white-space: nowrap;
}

.sem-badge i {
  font-size: 1.15em;
  line-height: 1;
  /* Only the Phosphor Regular weight is vendored (no Bold font file), so a thicker stroke stands
     in for a true bold glyph. Drop this if it ever looks rough at a given size. */
  -webkit-text-stroke: 0.4px currentColor;
  text-stroke: 0.4px currentColor;
}

/* Icon-only form for dense contexts (kanban card). The chip grew from 1.3rem to fit the larger,
   faux-bold icon without clipping. */
.sem-badge-compact {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  flex-shrink: 0;
  border-radius: 999px;
  color: var(--sem-color);
  background: var(--sem-tint);
}

.sem-badge-compact i {
  font-size: 1.25rem;
  line-height: 1;
  -webkit-text-stroke: 0.4px currentColor;
  text-stroke: 0.4px currentColor;
}

/* =====================================================================
   Excel-like per-column filter (hub-column-filter.js) — opt-in via
   table[data-hub-col-filter]. Reference implementation: catalog/items.
   Funnel affordance appears on hover/focus of a filterable header cell;
   the popover is a single "contains" text input plus a clear (×).
   ===================================================================== */
.hub-col-filter-header {
  position: relative;
  padding-right: calc(var(--hub-cell-x) + 1.1rem);
}

.hub-col-filter-trigger {
  position: absolute;
  top: 50%;
  right: 0.25rem;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.25rem;
  height: 1.25rem;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--muted);
  border-radius: var(--radius-btn);
  opacity: 0;
  transition: opacity 0.12s ease, color 0.12s ease, background-color 0.12s ease;
}

.hub-col-filter-header:hover .hub-col-filter-trigger,
.hub-col-filter-header:focus-within .hub-col-filter-trigger,
.hub-col-filter-trigger:focus-visible,
.hub-col-filter-active .hub-col-filter-trigger {
  opacity: 1;
}

.hub-col-filter-trigger:hover {
  background: var(--navy-tint);
  color: var(--blue-deep);
}

/* An active filter keeps the funnel visible and tinted, even off-hover. */
.hub-col-filter-active .hub-col-filter-trigger {
  color: var(--blue-deep);
}

.hub-col-filter-popover {
  position: absolute;
  z-index: 1080;
  display: flex;
  align-items: center;
  gap: 0.25rem;
  min-width: 11rem;
  padding: 0.35rem;
  background: #fff;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-btn);
  box-shadow: var(--elev-1, 0 4px 18px rgba(15, 23, 42, 0.08));
}

.hub-col-filter-input {
  flex: 1 1 auto;
  min-width: 0;
  border: 1px solid var(--line-soft);
  border-radius: var(--radius-btn);
  padding: 0.3rem 0.5rem;
  font-size: var(--hub-fs-sm);
  color: var(--ink);
}

.hub-col-filter-input:focus {
  outline: none;
  border-color: var(--blue-deep);
  box-shadow: 0 0 0 0.15rem rgba(73, 141, 190, 0.22);
}

.hub-col-filter-clear {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border: none;
  background: transparent;
  color: var(--muted);
  font-size: var(--hub-fs);
  line-height: 1;
  border-radius: var(--radius-btn);
}

.hub-col-filter-clear:hover {
  background: var(--navy-tint);
  color: var(--blue-deep);
}

/* Icon-only row actions (Phosphor) */
.hub-row-actions {
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
  justify-content: flex-end;
}

.hub-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: none;
  border-radius: 8px;
  background: transparent;
  color: var(--ink);
  text-decoration: none;
  line-height: 1;
  cursor: pointer;
  font-size: 1.15rem;
  transition: background 0.15s ease, color 0.15s ease;
}

.hub-icon-btn:hover {
  background: var(--paper);
  color: var(--blue-deep);
}

.hub-icon-btn:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 1px;
}

/* Brand-adjacent danger red (not Bootstrap default purple-pink) */
.hub-icon-btn-danger {
  color: #c23b3b;
}

.hub-icon-btn-danger:hover {
  color: #9a2e2e;
  background: #fdecea;
}

.hub-icon-btn .ph {
  font-size: 1.15rem;
  line-height: 1;
}

/* DT Bootstrap 5 layout chrome */
div.dt-container.dt-bootstrap5 {
  font-family: var(--font-sans);
  color: var(--body);
}

/*
 * DT2 feature chrome: exactly one label + one control.
 * Never hide labels with font-size:0 (that regressed descriptors).
 * Duplicate controls are stripped in HubDataTable.sanitizeFeatureChrome.
 */
div.dt-container.dt-bootstrap5 .dt-search,
div.dt-container.dt-bootstrap5 .dt-length {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.5rem;
}

div.dt-container.dt-bootstrap5 .dt-search label,
div.dt-container.dt-bootstrap5 .dt-length label {
  font-size: var(--hub-fs-sm);
  font-weight: 500;
  color: var(--muted);
  margin: 0;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

/* Hard guard: if a second control ever appears, keep only the last */
div.dt-container.dt-bootstrap5 .dt-search input.form-control ~ input.form-control,
div.dt-container.dt-bootstrap5 .dt-length select.form-select ~ select.form-select {
  display: none !important;
}

div.dt-container.dt-bootstrap5 .dt-search input.form-control,
div.dt-container.dt-bootstrap5 .dt-length select.form-select {
  font-size: var(--hub-fs-sm);
  border-radius: 8px;
  border-color: var(--line);
  font-family: var(--font-sans);
  min-width: 8rem;
  padding: 0.35rem 0.5rem;
}

div.dt-container.dt-bootstrap5 .dt-search input.form-control:focus,
div.dt-container.dt-bootstrap5 .dt-length select.form-select:focus {
  border-color: var(--blue);
  box-shadow: 0 0 0 0.2rem rgba(73, 141, 190, 0.2);
}

div.dt-container.dt-bootstrap5 .pagination {
  --bs-pagination-color: var(--ink);
  --bs-pagination-hover-color: var(--blue-deep);
  --bs-pagination-active-bg: var(--blue);
  --bs-pagination-active-border-color: var(--blue);
  --bs-pagination-focus-box-shadow: 0 0 0 0.2rem rgba(73, 141, 190, 0.25);
  margin-bottom: 0;
}

div.dt-container.dt-bootstrap5 .page-link {
  font-family: var(--font-sans);
  font-size: var(--hub-fs-sm);
  padding: 0.3rem 0.55rem;
}

div.dt-container.dt-bootstrap5 .dt-info {
  font-size: var(--hub-fs-sm);
  color: var(--muted);
  padding-top: 0.35rem;
}

div.dt-container.dt-bootstrap5 table.dataTable.table {
  margin-top: 0.65rem !important;
  border-color: var(--line-soft);
  font-size: var(--hub-fs);
}

div.dt-container.dt-bootstrap5 table.dataTable.table > :not(caption) > * > * {
  border-bottom-color: var(--line-soft);
  padding: var(--hub-cell-y) var(--hub-cell-x);
}

/* Hub primary actions map to brand blue via Bootstrap primary (overridden in accendo.css) */
.btn-primary {
  --bs-btn-bg: var(--blue);
  --bs-btn-border-color: var(--blue);
  --bs-btn-hover-bg: var(--blue-deep);
  --bs-btn-hover-border-color: var(--blue-deep);
  --bs-btn-active-bg: var(--blue-deep);
  --bs-btn-active-border-color: var(--blue-deep);
}

/* Dashboard stat tiles (home). A grid, not a flex wrap: with flex the tiles that wrap onto a short
   last line stretch to fill it, so the lone TRM tile rendered as a full-width slab. auto-fill keeps
   the empty tracks, so an orphan tile stays exactly one column wide and the tiles stay on a shared
   rhythm at every width. */
.stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr));
  gap: 0.75rem;
  margin-bottom: 1.5rem;
}

/* A card that opens what it counts. The lift is the app's standing signal for "clickable", so the
   TRM card — which counts nothing you can open — deliberately does not get it. */
a.stat-card.is-linked {
  color: inherit;
  text-decoration: none;
  transition: transform 120ms ease, box-shadow 120ms ease;
}

a.stat-card.is-linked:hover,
a.stat-card.is-linked:focus-visible {
  transform: translateY(-1px);
  box-shadow: var(--elev-1, 0 6px 20px rgba(21, 36, 60, 0.12));
}

.stat-card {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  padding: 0.85rem 1rem;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 0.65rem;
}

.stat-card-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  flex-shrink: 0;
  border-radius: var(--radius-card);
  background: var(--paper);
  color: var(--muted);
  font-size: 1.15rem;
}

.stat-card-text {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  min-width: 0;
}

.stat-label {
  font-size: var(--hub-fs-xs);
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 600;
}

.stat-value {
  /* Responsive so a long money value (the TRM tile) shrinks with the tile instead of spilling past
     its card at narrow widths; still reads as one line at any size. A figure is never ellipsised —
     that would silently cut digits from a money value — so the card must be free to shrink
     (min-width: 0 above) rather than clip its content. */
  display: block;
  font-size: clamp(1rem, 2.2vw, 1.25rem);
  font-weight: 600;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  line-height: 1.2;
  min-width: 0;
  /* A stat is one figure. Without this the TRM tile breaks at the space after "$" and reads as two
     lines of nonsense at narrow tile widths. */
  white-space: nowrap;
}

.hub-trm-provenance {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.3rem;
}

.hub-trm-provenance .quote-trm-status {
  margin-left: 0;
}

.hub-trm-validity {
  color: var(--muted);
  font-size: var(--hub-fs-xs);
  line-height: 1.3;
}

.action-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 1.5rem;
}

/* Home dashboard: "Atención" and "Actividad del sistema" share one tabbed panel (home-panels.js
   toggles `hidden`), so its height stays stable regardless of which tab is active. */
.hub-home-tab-panel {
  min-height: 22rem;
}

/* Scroll wrapper for non-DT tables (same card surface as .hub-table-panel) */
.table-responsive.hub-table-wrap {
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  background: var(--white);
  -webkit-overflow-scrolling: touch;
}

.table-responsive.hub-table-wrap .hub-table {
  border: none;
  border-radius: 0;
}

.badge.hub-badge,
.badge {
  font-weight: 500;
  font-size: var(--hub-fs-xs);
  background: var(--navy-tint);
  color: var(--navy);
}

/* Muted helper text — always place inside a card (.panel), not bare on paper */
.empty-hint {
  margin: 0;
  color: var(--muted);
  font-size: var(--hub-fs-sm);
  line-height: var(--hub-lh);
}

/*
 * White content cards on gray paper canvas.
 * Prefer .panel for forms/empty/audit blocks; .hub-table-panel for DataTables.
 */
.panel {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  padding: 0.95rem 1.05rem;
  margin: 0 0 1rem;
  width: 100%;
  box-shadow: 0 1px 0 rgba(14, 42, 69, 0.03);
}

.panel-title {
  margin: 0 0 0.6rem;
  font-size: var(--hub-fs);
  font-weight: 600;
  color: var(--ink);
}

.panel-spaced {
  margin-bottom: 1.25rem;
}

.hub-kv {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8rem, 1fr));
  gap: 0.75rem 1.25rem;
  margin: 0;
}

.hub-kv dt {
  font-size: var(--hub-fs-sm);
  color: var(--muted);
  font-weight: 500;
}

.hub-kv dd {
  margin: 0.15rem 0 0;
  font-weight: 600;
}

.hub-plain-list {
  list-style: none;
  padding: 0;
  margin: 0 0 1rem;
}

.hub-plain-list li {
  padding: 0.35rem 0;
  border-bottom: 1px solid var(--line);
}

.hub-stack {
  margin-bottom: 1rem;
  padding-bottom: 1rem;
  border-bottom: 1px solid var(--line);
}

.hub-form .field {
  margin-bottom: 0.8rem;
}

.hub-form label {
  display: block;
  font-size: var(--hub-fs-sm);
  margin-bottom: 0.25rem;
  color: var(--ink);
  font-weight: 500;
}

.hub-form .optional {
  color: var(--muted);
  font-weight: 400;
}

/* Reassert the shared checkbox layout after the generic form-label rule above. */
.hub-form label.hub-check {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  margin: 0;
  padding: 0.45rem 0;
}

/* Text-like inputs only: checkboxes/radios keep their own sizing (.hub-check-input,
   .hub-seg) — otherwise this width:100%/pill rule stretches every checkbox into a
   full-width oval site-wide. */
.hub-form input:not([type="checkbox"]):not([type="radio"]),
.hub-form select,
.hub-form .form-control,
.hub-form .form-select {
  width: 100%;
  max-width: 100%;
  padding: 0.4rem 0.55rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  font: inherit;
  font-size: var(--hub-fs);
  line-height: 1.4;
  background: var(--white);
  color: var(--ink);
}

/* Bootstrap input-group needs flex children, not width:100% (else % suffix wraps). */
.hub-form .input-group > .form-control,
.hub-form .input-group > .form-select,
.hub-form .input-group > input,
.hub-form .input-group > select {
  width: 1%;
  max-width: none;
  flex: 1 1 auto;
  min-width: 0;
}
.hub-form .input-group > .input-group-text,
.hub-form .input-group > .btn {
  width: auto;
  max-width: none;
  flex: 0 0 auto;
}

.hub-form input:not([type="checkbox"]):not([type="radio"]):focus,
.hub-form select:focus {
  outline: 2px solid var(--blue);
  outline-offset: 1px;
  border-color: var(--blue);
}

.hub-form-inline {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
  gap: 0.75rem 1rem;
  align-items: end;
}

.hub-form-inline .form-actions {
  grid-column: 1 / -1;
}

.field-error {
  color: #8b1e1e;
  font-size: var(--hub-fs-xs);
  margin: 0.25rem 0 0;
}

.form-actions {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.5rem;
}
/* Wizard step footer: back on the left, reset in the middle, the way forward on the right. The
   empty slot keeps those positions steady on the first step, which has nowhere to go back to. */
.form-actions-wizard {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  width: 100%;
}
.form-actions-slot {
  flex: 0 0 auto;
}
/* Reset is a quiet escape hatch, not a third thing competing to be pressed. */
.form-actions-reset {
  color: var(--muted);
  text-decoration: none;
}
.form-actions-reset:hover {
  color: var(--ink);
  text-decoration: underline;
}

/*
 * The year of service: five weekday rows, a column per week.
 *
 * Colour is the whole content here, so it is the one place in the app that spends the saturated
 * end of the ramp — and it still stays inside the existing tokens rather than inventing a traffic
 * light. Met is the calm structural green-blue the brand already uses for "fine"; late borrows the
 * warm rung; unmet borrows the hot one, which is the only place red means what red means.
 *
 * A day with nothing owed is drawn, faintly: it happened, and the firm was open, and it had nothing
 * to keep. A day that has NOT happened is not drawn at all — see ServiceYearView for why that
 * distinction is the whole point of the panel.
 */
/* First in the card, so the rule sits under it rather than over it. */
.hub-service-year {
  margin-bottom: 1.25rem;
  padding-bottom: 1.15rem;
  border-bottom: 1px solid var(--line-soft);
}

.hub-service-legend {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
  font-size: var(--hub-fs-xs);
  color: var(--muted);
}

.hub-service-legend > span:not(.hub-service-cell) {
  margin-right: 0.6rem;
}

/* The grid and the recent numbers, side by side: the year shows shape, the aside gives size. */
.hub-service-body {
  display: flex;
  align-items: stretch;
  gap: 1.5rem;
}

.hub-service-periods {
  flex: none;
  display: grid;
  align-content: center;
  gap: 0.75rem;
  min-width: 11rem;
  padding-left: 1.5rem;
  border-left: 1px solid var(--line-soft);
}

.hub-service-period {
  display: grid;
  gap: 0.1rem;
}

.hub-service-period-label {
  font-size: var(--hub-fs-xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
}

.hub-service-period-value {
  font-size: 1.05rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.hub-service-period-value.is-late {
  color: var(--sem-warm);
}

.hub-service-period-value.is-breached {
  color: var(--sem-hot);
}

.hub-service-period-note {
  font-size: var(--hub-fs-xs);
  color: var(--muted);
}

/* Summary on the left, colour key on the right: both explain the picture above them. */
.hub-service-foot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  margin-top: 0.35rem;
}

@media (max-width: 991.98px) {
  .hub-service-body {
    flex-wrap: wrap;
  }

  .hub-service-periods {
    padding-left: 0;
    border-left: 0;
    grid-auto-flow: column;
    min-width: 0;
  }
}

.hub-service-grid-scroll {
  overflow-x: auto;
  scrollbar-width: thin;
  padding: 0.5rem 0 0.35rem;
}

.hub-service-grid {
  display: grid;
  gap: 3px;
  width: max-content;
}

.hub-service-months {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 15px;
  gap: 3px;
  height: 1.1rem;
  font-size: var(--hub-fs-xs);
  color: var(--muted);
}

.hub-service-row {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 15px;
  gap: 3px;
}

.hub-service-cell {
  display: block;
  width: 15px;
  height: 15px;
  border-radius: 3px;
  background: var(--line-soft);
  text-decoration: none;
}

/* Not drawn at all: a day outside the window, or a hole a holiday left in its week. */
.hub-service-cell.is-empty {
  background: none;
}

.hub-service-cell.is-nothing_owed {
  background: var(--line-soft);
}

.hub-service-cell.is-met {
  background: var(--sem-frozen);
}

.hub-service-cell.is-late {
  background: var(--sem-warm);
}

.hub-service-cell.is-breached {
  background: var(--sem-hot);
}

/* Today, still running. An outline rather than a colour on purpose: every filled cell is a verdict
   about a day that finished, and today has not earned one yet. */
.hub-service-cell.is-en_curso {
  background: none;
  box-shadow: inset 0 0 0 2px var(--blue);
}

a.hub-service-cell:hover,
a.hub-service-cell:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 1px;
}

.hub-service-summary {
  margin: 0.35rem 0 0;
  font-size: var(--hub-fs-sm);
  color: var(--muted);
}

/*
 * A commitment row: the date, what it is about, and what is owed. Used by Atención › Compromisos
 * and by Inicio's «Lo que viene», which is the whole reason it is one class and not two.
 *
 * Hairline separators and no boxes, per the house rules for lists: a horizon of five rows drawn as
 * five cards reads as five alarms.
 */
.hub-commitment-row {
  display: grid;
  grid-template-columns: 3.5rem minmax(0, 1fr) minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 0.25rem 1rem;
  padding: 0.6rem 0;
  border-top: 1px solid var(--line-soft);
}

.hub-commitment-row:first-of-type {
  border-top: none;
}

.hub-commitment-when {
  font-size: var(--hub-fs-sm);
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

.hub-commitment-what {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}

.hub-commitment-what > span {
  font-size: var(--hub-fs-sm);
}

/* What we actually owe. The one thing on the row a consultant acts on, so it carries the ink. */
.hub-commitment-detail {
  color: var(--ink);
  font-size: var(--hub-fs-sm);
}

/* Only ever drawn when we committed past our own standard, so it can afford to be quiet. */
.hub-commitment-beyond {
  font-size: var(--hub-fs-xs);
  color: var(--muted);
  white-space: nowrap;
}

.hub-upcoming {
  margin-top: 1.75rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
}

.hub-upcoming-group + .hub-upcoming-group {
  margin-top: 1.25rem;
}

.hub-upcoming-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 0.25rem;
  font-size: var(--hub-fs-xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Overdue is the only rung that gets alarm colour. "Due today" is work, not a failure. */
.hub-upcoming-head.is-overdue {
  color: var(--sem-hot);
}

.hub-upcoming-head.is-today {
  color: var(--ink);
}

@media (max-width: 40rem) {
  .hub-commitment-row {
    grid-template-columns: 3.5rem minmax(0, 1fr);
  }

  .hub-commitment-detail,
  .hub-commitment-beyond {
    grid-column: 2;
  }
}

/*
 * "¿Cómo se calcula?", folded away next to the number it explains. A measurement nobody can
 * reproduce is a measurement nobody argues with, and one nobody argues with is not being read —
 * but the rules are six paragraphs, and six paragraphs above the answer is a wall.
 */
.hub-explainer {
  margin-top: 0.35rem;
  font-size: var(--hub-fs-sm);
}

.hub-explainer > summary {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  cursor: pointer;
  color: var(--muted);
  list-style: none;
}

.hub-explainer > summary::-webkit-details-marker {
  display: none;
}

.hub-explainer > summary:hover {
  color: var(--ink);
}

.hub-explainer-body {
  max-width: 68ch;
  margin-top: 0.5rem;
  padding: 0.85rem 1rem;
  border-left: 2px solid var(--line-soft);
  color: var(--body);
}

.hub-explainer-body p,
.hub-explainer-body ul {
  margin-bottom: 0.6rem;
}

.hub-explainer-body ul {
  padding-left: 1.1rem;
}

/* The day page: the score, then what happened to each promise. */
.hub-service-score.is-breached {
  color: var(--sem-hot);
}

.hub-service-score.is-late {
  color: var(--sem-warm);
}

.hub-service-outcome {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-size: var(--hub-fs-sm);
}

.hub-service-outcome.is-met {
  color: var(--muted);
}

.hub-service-outcome.is-late {
  color: var(--sem-warm);
}

.hub-service-outcome.is-breached {
  color: var(--sem-hot);
  font-weight: 500;
}

/* Section icon beside a page title: muted and slightly smaller than the text, so it identifies
   the record without competing with its name. */
.hub-page-title-icon {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.hub-page-title-icon > .ph {
  font-size: 0.8em;
  color: var(--muted);
  flex: none;
}

/* ── Opportunity detail: identity, actions, the two columns ── */

/*
 * The state chip. The state is the record's position, so its control sits in the subtitle where a
 * reader already looks for it, not as a form in the action bar.
 */
.hub-state-picker {
  position: relative;
  display: inline-block;
}

.hub-state-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--white);
  padding: 0.05rem 0.5rem;
  font: inherit;
  color: inherit;
  cursor: pointer;
}

.hub-state-chip:hover,
.hub-state-chip:focus-visible {
  border-color: var(--sem-color, var(--ink));
}

.hub-state-chip .ph {
  font-size: 0.85em;
  color: var(--muted);
}

.hub-state-menu {
  position: absolute;
  z-index: 20;
  top: calc(100% + 0.35rem);
  left: 0;
  display: grid;
  min-width: 11rem;
  padding: 0.25rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  background: var(--white);
  box-shadow: var(--elev-1, 0 6px 20px rgba(21, 36, 60, 0.12));
}

.hub-state-menu button {
  border: 0;
  background: none;
  padding: 0.4rem 0.6rem;
  border-radius: 8px;
  text-align: left;
  font: inherit;
  color: var(--ink);
  cursor: pointer;
}

.hub-state-menu button:hover:not(:disabled) {
  background: var(--canvas);
}

.hub-state-menu button:disabled {
  color: var(--muted);
  cursor: default;
}

/* The title row: the record's name on the left, the one control that moves it on the right. It is
   the most consequential thing on the page, so it is sized like it rather than tucked into a
   subtitle. Wraps below the title on a narrow screen. */
.hub-title-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.75rem 1.5rem;
}

.hub-state-picker-label {
  font-size: var(--hub-fs-sm);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  margin-right: 0.5rem;
}

.hub-state-picker-lg .hub-state-chip {
  padding: 0.3rem 0.9rem;
  font-size: 1.05rem;
  font-weight: 600;
}

/* Right-aligned control, so the menu opens back under it rather than off the edge. */
.hub-state-picker-lg .hub-state-menu {
  left: auto;
  right: 0;
}

/* The macro heading. Not a button, because the macro is derived from whichever stage is picked. */
.hub-state-menu-group {
  margin: 0.5rem 0 0.15rem;
  padding: 0 0.6rem;
  font-size: var(--hub-fs-sm);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}

.hub-state-menu-group:first-child {
  margin-top: 0.15rem;
}

/* A panel head's right-hand side: the "ver todas" link and the action that adds one. */
.hub-column-head-actions {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

/* Rare and destructive actions, one click away: they do not earn permanent width beside the two
   buttons pressed all day. */
.hub-overflow {
  position: relative;
}

.hub-overflow > summary {
  list-style: none;
  cursor: pointer;
}

.hub-overflow > summary::-webkit-details-marker {
  display: none;
}

.hub-overflow-menu {
  position: absolute;
  z-index: 20;
  top: calc(100% + 0.35rem);
  right: 0;
  display: grid;
  min-width: 12rem;
  padding: 0.25rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  background: var(--white);
  box-shadow: var(--elev-1, 0 6px 20px rgba(21, 36, 60, 0.12));
}

.hub-overflow-menu a,
.hub-overflow-menu button {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  border: 0;
  background: none;
  padding: 0.45rem 0.6rem;
  border-radius: 8px;
  text-align: left;
  font: inherit;
  color: var(--ink);
  cursor: pointer;
  white-space: nowrap;
}

.hub-overflow-menu a,
.hub-overflow-menu a:hover {
  color: var(--ink);
  text-decoration: none;
}

.hub-overflow-menu a:hover,
.hub-overflow-menu button:hover {
  background: var(--canvas);
}

.hub-overflow-menu button.is-danger {
  color: var(--danger, #c8452b);
}

/* Resumen: what the opportunity *is*, in one row read left to right. Labels above values, hairline
   dividers between cells, no boxes — the row is a sentence, not five cards. */
.hub-summary-row {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 2.5rem;
  align-items: flex-start;
}

.hub-summary-cell {
  display: grid;
  gap: 0.3rem;
}

.hub-summary-gauge {
  /* The gauge brings its own label and readout, so the cell only has to give it room. */
  min-width: 15rem;
}

.hub-summary-label {
  font-size: var(--hub-fs-sm);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
}

.hub-summary-value {
  font-weight: 500;
}

/*
 * La espera: a statement on the left, the one thing that can be resolved on the right.
 *
 * The one panel in the app that is not white. A deal in espera is stopped — nothing will move until
 * somebody delivers something — and rendering that as another white card among white cards said it
 * was ordinary. Pale amber and a warning glyph, which is the app's only anomaly treatment; red is
 * kept for destructive actions and would say "this is wrong" when waiting is often correct.
 */
.hub-espera {
  background: var(--sem-warm-tint);
  border-color: color-mix(in srgb, var(--sem-warm) 30%, transparent);
}

.hub-espera-title {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.hub-espera-title .ph {
  color: var(--sem-warm);
  font-size: 1.1em;
}

.hub-espera {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}

.hub-espera-when {
  margin-top: 0.35rem;
  font-size: var(--hub-fs-sm);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.hub-espera-when.is-overdue {
  color: var(--danger, #c8452b);
}

.hub-espera-actions {
  flex: none;
}

/* The provenance line, above the actions: read once to trust the page, then ignored. */
.hub-last-move {
  margin: 0 0 0.75rem;
  font-size: var(--hub-fs-sm);
  color: var(--muted);
}

/* A description is prose, so it gets prose measure rather than the full page width. */
.hub-prose {
  max-width: 68ch;
}

/* One gestión in the summary: date, outcome, note, on one line. */
.hub-gestion-brief {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.5rem;
  padding: 0.6rem 0;
  border-top: 1px solid var(--line-soft);
  font-size: var(--hub-fs-sm);
}

/* Resumen: what happened beside what is owed. One column each, because they are two different
   nouns and interleaving them would invent a third thing. */
.hub-two-columns {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem;
  align-items: start;
}

@media (max-width: 991.98px) {
  .hub-two-columns {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Side by side, not stacked: the `.panel + .panel` top margin is for a vertical stack and inside
   this grid it pushed the right-hand column down by 0.85rem, so the two heads never lined up. The
   gap does the spacing here. */
.hub-two-columns > .panel,
.hub-two-columns > .panel + .panel {
  margin: 0;
}

.hub-column-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
}

.hub-column-head a {
  font-size: var(--hub-fs-sm);
}

/* One entry, in either column. */
.hub-entry {
  padding: 0.6rem 0;
  border-top: 1px solid var(--line-soft);
}

.hub-entry:first-of-type {
  border-top: 0;
}

.hub-entry-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.45rem;
  margin-bottom: 0.2rem;
}

.hub-entry-when,
.hub-entry-by,
.hub-entry-meta {
  font-size: var(--hub-fs-xs);
  color: var(--muted);
}

.hub-entry-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin: 0.2rem 0 0;
}

.hub-entry-note {
  margin: 0;
  font-size: var(--hub-fs-sm);
}

.hub-entry-by {
  margin: 0.2rem 0 0;
}

/* A closed compromiso recedes: it is history, and the open ones above it are the work. */
.hub-entry.is-closed {
  color: var(--muted);
}

.hub-entry-state {
  font-size: var(--hub-fs-xs);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0.05rem 0.45rem;
  color: var(--muted);
}

.hub-entry-state.is-late,
.hub-entry-state.is-due {
  border-color: var(--sem-hot);
  color: var(--sem-hot);
}

/* ── Pipeline kanban (app-specific) ── */
/* Three columns: Nuevo and Activo are where the work is, so they get double width; Ganado is a
   shorter confirmation of what landed. Glaciar and Perdido are not board states (see
   ProjectService.BOARD_COLUMNS); five equal columns spread the working ones thin to make room for
   two nobody scanned. */
/* One column per stage, all of them on screen. The count is data (hub.opportunity_stage decides
   which stages draw a column), so the grid cannot name it: auto-flow column with equal fractions
   fits whatever the table holds. The minmax floor is the point at which a card stops being
   readable — past that the board scrolls rather than shrinking into confetti. */
.kanban {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(8.5rem, 1fr);
  gap: 0.6rem;
  align-items: start;
}

.kanban-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  padding-bottom: 0.35rem;
  margin-inline: -0.15rem;
  padding-inline: 0.15rem;
  scrollbar-width: thin;
}

.kanban-scroll .kanban {
  /* No floor: the grid already refuses to shrink a column below 8.5rem, and a fixed minimum here
     forced a scrollbar on a board that fitted. */
  min-width: 100%;
}

.kanban-col {
  background: var(--canvas);
  border-radius: var(--radius-card);
  padding: 0.5rem;
  min-height: 12rem;
  border: 1px solid var(--line-soft);
}

.kanban-col-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.35rem 0.4rem 0.6rem;
}

.kanban-col-head h2 {
  margin: 0;
  font-size: var(--hub-fs-xs);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  font-weight: 600;
}

/* The count is a link into the registry for this state, so a column can be capped without hiding
   anything. It reads as a badge until hovered, when it admits it is a way across. */
.kanban-count {
  font-size: var(--hub-fs-xs);
  background: var(--white);
  border-radius: 999px;
  padding: 0.1rem 0.45rem;
  color: var(--ink);
  border: 1px solid var(--line);
  font-variant-numeric: tabular-nums;
  text-decoration: none;
}

.kanban-count:hover,
.kanban-count:focus-visible {
  color: var(--accent-strong, var(--ink));
  border-color: var(--accent, var(--line));
}

.kanban-truncated {
  font-size: var(--hub-fs-xs);
  color: var(--muted);
  margin: 0 0 0.5rem;
}

.kanban-truncated a {
  color: var(--blue);
}

.kanban-col-body {
  min-height: 4rem;
  padding: 0.15rem;
  border-radius: 10px;
  transition: background 0.15s ease, box-shadow 0.15s ease;
}

.kanban-col.is-drop-target .kanban-col-body {
  background: color-mix(in srgb, var(--blue-deep) 8%, var(--white));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--blue-deep) 35%, var(--line));
}

.kanban-card {
  position: relative;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 0.55rem 0.65rem;
  margin-bottom: 0.45rem;
  cursor: grab;
  user-select: none;
}

.kanban-card:active {
  cursor: grabbing;
}

.kanban-card.is-dragging {
  opacity: 0.55;
}

.kanban-card-company {
  display: block;
  font-size: var(--hub-fs-xs);
  color: var(--blue-deep);
  text-decoration: none;
  margin-bottom: 0.35rem;
  font-weight: 500;
  position: relative;
  z-index: 2;
  width: fit-content;
}

.kanban-card-company:hover {
  color: var(--navy);
  text-decoration: underline;
}

.kanban-card-name {
  display: block;
  margin: 0 0 0.15rem;
  font-weight: 650;
  font-size: var(--hub-fs);
  line-height: 1.3;
  color: var(--ink);
  text-decoration: none;
}

.kanban-card-name::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
}

.kanban-card-name:hover {
  color: var(--navy);
}

.kanban-card-name:focus-visible::after {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

/* Wraps rather than overflows: with one column per stage a card is narrow, and "TRACKVY ·
   ADQUISICION" beside a temperature chip does not fit on one line at that width. */
.kanban-card-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.15rem 0.4rem;
  margin: 0;
  font-size: var(--hub-fs-xs);
  color: var(--muted);
}

/* A type key like CUSTOM_SOFTWARE is one unbreakable word wider than the column. It breaks rather
   than pushing the card past its own edge. */
.kanban-card-meta > span {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* What is owed on the left, the console trigger on the right: the card states its clock and
   offers the one thing a consultant records. */
.kanban-card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.15rem 0.4rem;
  margin: 0.3rem 0 0;
  min-height: 1.6rem;
}

.kanban-card-countdown {
  margin: 0;
  font-size: var(--hub-fs-xs);
  color: var(--muted);
}

/* The sub-state, in the countdown's place. Muted and small: it is the absence of a reminder, not
   an alarm, and the card is still in its column because its state has not changed. */
/* A promise owed today or earlier, in the countdown's place. Inked rather than muted: unlike the
   forecast it replaces, this one is a fact about something somebody agreed to. */
/*
 * A commitment, coloured by how close it is. It used to be red the moment a date existed, which
 * made a promise for next month look like an emergency and taught everyone that red on this card
 * means nothing. Red is now reserved for a date that has passed.
 */
.kanban-card-due {
  font-size: var(--hub-fs-xs);
  color: var(--muted);
  font-weight: 500;
}

.kanban-card-due.is-soon {
  color: var(--sem-warm);
  font-weight: 600;
}

.kanban-card-due.is-overdue {
  color: var(--sem-hot);
  font-weight: 600;
}

.kanban-card-substate {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  font-size: var(--hub-fs-xs);
  color: var(--muted);
}

.kanban-card-substate .ph {
  font-size: 0.95em;
}

/* The console triggers stay quiet until the card is engaged with: a board of cards each shouting
   two icons is noisier than the information on the cards themselves. */
/* Above .kanban-card-name::after, which is a stretched link covering the whole card. Without this
   the overlay sits on top of the buttons and every click on them opens the opportunity instead —
   and a scripted .click() still works, so it passes a JS check and fails a real one. */
.hub-registro-triggers {
  position: relative;
  z-index: 2;
  display: inline-flex;
  gap: 0.15rem;
  margin-left: auto;
}

/* Same reason: the company link is a real link and must beat the card-wide overlay. */
.kanban-card-company {
  position: relative;
  z-index: 2;
}

.kanban-card .hub-registro-triggers {
  opacity: 0;
  transition: opacity 120ms ease;
}

.kanban-card:hover .hub-registro-triggers,
.kanban-card:focus-within .hub-registro-triggers {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .kanban-card .hub-registro-triggers {
    transition: none;
  }
}

/* Coarse pointers have no hover, so the triggers are always visible there. */
@media (hover: none) {
  .kanban-card .hub-registro-triggers {
    opacity: 1;
  }
}

/* Perdido has no column. This target appears only while a card is in flight (is-armed), so the
   board never carries a standing invitation to lose a deal.

   Fixed to the viewport rather than placed after the columns: as a block at the bottom of the board
   it sat below the fold, so a consultant mid-drag could neither see it nor reach it. */
.kanban-discard {
  position: fixed;
  left: 50%;
  bottom: 1.25rem;
  transform: translate(-50%, 0.75rem);
  z-index: 1040;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.85rem 1.5rem;
  border: 1px dashed var(--line);
  border-radius: 999px;
  background: var(--white);
  box-shadow: var(--elev-1, 0 6px 20px rgba(21, 36, 60, 0.12));
  color: var(--muted);
  font-size: var(--hub-fs-sm);
  white-space: nowrap;
  opacity: 0;
  visibility: hidden;
  transition: opacity 120ms ease, transform 120ms ease;
}

.kanban-discard.is-armed {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0);
}

.kanban-discard.is-drop-target {
  border-style: solid;
  border-color: var(--danger, #c8452b);
  color: var(--danger, #c8452b);
}

@media (prefers-reduced-motion: reduce) {
  .kanban-discard {
    transition: none;
  }
}

.kanban-empty {
  margin: 0.5rem;
  font-size: var(--hub-fs-sm);
  color: var(--muted);
}

@media (prefers-reduced-motion: reduce) {
  .kanban-col-body {
    transition: none;
  }
}

/* Desktop: let kanban columns fill the viewport height instead of shrink-wrapping their
   cards. Offset accounts for the page's top padding, header/crumb, and the column head. */
@media (min-width: 992px) {
  .kanban-col-body {
    min-height: calc(100vh - 16rem);
  }
}

/*
 * Kanban card semáforo: a subtle left-edge accent on a white card plus the pastel compact badge.
 * GANADO/PERDIDO cards get neither class, since a closed deal has no semáforo.
 */
.kanban-card.sem-hot,
.kanban-card.sem-warm,
.kanban-card.sem-cool,
.kanban-card.sem-cold,
.kanban-card.sem-frozen {
  background: var(--white);
  box-shadow: inset 3px 0 0 0 color-mix(in srgb, var(--sem-color) 72%, var(--white));
}

/*
 * Opportunity temperature gauge — fragments/semaforo.html :: gauge. A calm five-step ladder
 * (Caliente → Glaciar); the active step lights up, the rest stay muted paper-gray.
 */
.sem-gauge {
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
}

.sem-gauge-ladder {
  position: relative;
  display: flex;
  gap: 0.3rem;
  padding-top: 0.6rem;
}

.sem-gauge-step {
  flex: 1 1 0;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 2.5rem;
  border-radius: 8px;
  background: var(--paper);
  color: var(--line);
  opacity: 0.6;
  transition: opacity 0.15s ease, background-color 0.15s ease, color 0.15s ease;
}

.sem-gauge-step i {
  font-size: 1.5rem;
  line-height: 1;
  /* Only the Phosphor Regular weight is vendored (no Bold font file), so a thicker stroke stands
     in for a true bold glyph. Drop this if it ever looks rough at a given size. */
  -webkit-text-stroke: 0.4px currentColor;
  text-stroke: 0.4px currentColor;
}

.sem-gauge-step.is-active {
  opacity: 1;
  background: var(--sem-tint);
  color: var(--sem-color);
}

.sem-gauge-readout {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.sem-gauge-label {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  width: fit-content;
  font-weight: 600;
  font-size: var(--hub-fs);
  color: var(--sem-color);
}

.sem-gauge-label i {
  font-size: 1.125rem;
  line-height: 1;
  -webkit-text-stroke: 0.4px currentColor;
  text-stroke: 0.4px currentColor;
}

.sem-gauge-days {
  margin: 0;
  color: var(--muted);
  font-size: var(--hub-fs-sm);
}

@media (prefers-reduced-motion: reduce) {
  .sem-gauge-step {
    transition: none;
  }
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  border: 0;
}

/* ── Breakpoints (desktop-first; best-effort menus & chrome) ── */
@media (max-width: 1199.98px) {
  .hub-main {
    padding: 1.1rem 1.15rem 1.75rem;
  }
}

@media (max-width: 991.98px) {
  /* Sidebar is display:none via Bootstrap d-lg-*; shell is single column */
  .hub-main {
    padding: 1rem 1rem 1.5rem;
  }

  .page-header h1 {
    font-size: 1.15rem;
  }

  /* .stat-row is a grid, so the tracks already size themselves; the card itself stays min-width: 0
     so its content (the stat value) can shrink to the track instead of overflowing it. */
  /* A card that opens what it counts. The lift is the app's standing signal for "clickable", so the
   TRM card — which counts nothing you can open — deliberately does not get it. */
a.stat-card.is-linked {
  color: inherit;
  text-decoration: none;
  transition: transform 120ms ease, box-shadow 120ms ease;
}

a.stat-card.is-linked:hover,
a.stat-card.is-linked:focus-visible {
  transform: translateY(-1px);
  box-shadow: var(--elev-1, 0 6px 20px rgba(21, 36, 60, 0.12));
}

.stat-card {
    min-width: 0;
  }
}

@media (max-width: 767.98px) {
  .hub-brand-text {
    display: none;
  }

  .hub-topbar-tag {
    display: none;
  }

  .hub-main {
    padding: 0.85rem 0.85rem 1.5rem;
  }

  .page-header-row {
    flex-direction: column;
    align-items: stretch;
  }

  .page-header-row > .btn {
    width: 100%;
    justify-content: center;
  }

  .hub-detail-toolbar {
    flex-direction: column;
    align-items: stretch;
  }

  .hub-detail-toolbar-end {
    margin-left: 0;
    width: 100%;
  }

  .hub-detail-toolbar .btn {
    justify-content: center;
  }

  .hub-detail-toolbar-end .btn {
    flex: 1 1 auto;
  }

  .action-row {
    width: 100%;
  }

  .action-row .btn {
    flex: 1 1 auto;
    justify-content: center;
  }

  .form-actions {
    flex-wrap: wrap;
  }

  .form-actions .btn {
    flex: 1 1 auto;
  }

  .hub-form-inline {
    grid-template-columns: 1fr;
  }

  .kanban-scroll .kanban {
    min-width: 52rem;
  }
}

@media (max-width: 575.98px) {
  .stat-row {
    gap: 0.5rem;
  }

  .hub-table th,
  .hub-table td {
    padding: 0.45rem 0.55rem;
    font-size: var(--hub-fs-sm);
  }

  div.dt-container.dt-bootstrap5 table.dataTable.table > :not(caption) > * > * {
    padding: 0.45rem 0.55rem;
  }
}

/* ── Status & elevation tokens ─────────────────────────────────────────────
   Semantic feedback colors composed from brand/accendo.css primitives, plus
   one restrained elevation. Reuse across the app instead of inline hexes. */
:root {
  --elev-1: 0 1px 2px rgba(11, 23, 38, 0.05), 0 10px 26px -14px rgba(11, 23, 38, 0.16);
  --ok-bg: #E6F7F1;
  --ok-fg: #0D7A55;
  --ok-line: #B7E4D4;
  --warn-bg: #FFF6E5;
  --warn-fg: #9A6B00;
  --warn-line: #F0D9A0;
  --bad-bg: #FDECEC;
  --bad-fg: #A32020;
  --bad-line: #F0B8B8;
}

/* ── Quote draft wizard (Web Flow + HTMX) ─────────────────────────────────── */
/*
 * Connected stepper rail: each step is its own POST <form> (real navigation
 * target) and also owns half of the connector line on each side, so two
 * adjoining halves always resolve to the same color — no two-tone seams.
 * States (done / current / ahead) are computed in the template from
 * s.order() vs step.order() and applied as a class on the form.
 */
.quote-wizard-nav {
  display: flex;
  align-items: flex-start;
  margin: 0 0 1.25rem;
  padding: 0.4rem 0.4rem 0;
}
.quote-wizard-pill-form {
  flex: 1 1 0;
  position: relative;
  margin: 0;
  padding-top: 0.35rem;
}
.quote-wizard-pill-form::before,
.quote-wizard-pill-form::after {
  content: "";
  position: absolute;
  top: calc(0.35rem + 14px);
  height: 2px;
  background: var(--line);
}
.quote-wizard-pill-form::before { left: 0; right: 50%; }
.quote-wizard-pill-form::after { left: 50%; right: 0; }
.quote-wizard-pill-form:first-child::before,
.quote-wizard-pill-form:last-child::after {
  display: none;
}
.quote-wizard-pill-form.is-done::before,
.quote-wizard-pill-form.is-done::after {
  background: var(--blue);
}
.quote-wizard-pill-form.is-current::before {
  background: var(--blue);
}
.quote-wizard-pill {
  position: relative;
  z-index: 1;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.42rem;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.quote-wizard-pill:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
  border-radius: 8px;
}
.quote-wizard-body.panel {
  margin-bottom: 0;
  padding: 1.15rem 1.25rem 1.25rem;
  box-shadow: var(--elev-1);
}
.quote-step-title {
  margin: 0 0 0.35rem;
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--ink);
}
.quote-form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: 0.85rem 1rem;
  margin-bottom: 0.75rem;
}
/*
 * Step dot: number by default, swaps to a check icon once done. The "ahead"
 * state is the unstyled baseline (white dot, muted number/label); done and
 * current below are the only states that need explicit overrides.
 */
.quote-wizard-step-dot {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--white);
  border: 2px solid var(--line);
  color: var(--muted);
  font-size: var(--hub-fs-sm);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  transition: border-color 0.14s ease, background 0.14s ease, color 0.14s ease;
}
.quote-wizard-step-dot .ph {
  font-size: 0.8rem;
}
.quote-wizard-pill:hover .quote-wizard-step-dot {
  border-color: var(--blue);
}
.quote-wizard-pill-form.is-done .quote-wizard-step-dot {
  background: var(--navy-tint);
  border-color: var(--blue);
  color: var(--blue);
}
.quote-wizard-pill-form.is-current .quote-wizard-step-dot {
  background: var(--navy);
  border-color: var(--navy);
  color: var(--white);
  /* Ring at --blue (73,141,190) 18% alpha; no rgb-triplet token exists for it. */
  box-shadow: 0 0 0 4px rgba(73, 141, 190, 0.18);
}
.quote-wizard-pill-label {
  font-size: var(--hub-fs-sm);
  color: var(--muted);
  font-weight: 500;
  text-align: center;
}
.quote-wizard-pill-form.is-current .quote-wizard-pill-label {
  color: var(--ink);
  font-weight: 700;
}
.quote-wizard-pill-chip {
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 0.15rem 0.4rem;
  border-radius: 4px;
  background: var(--line-soft, #EFF1F4);
  color: var(--muted);
}
.quote-wizard-pill-chip.is-ready { background: var(--ok-bg); color: var(--ok-fg); }
.quote-wizard-pill-chip.is-incomplete { background: var(--warn-bg); color: var(--warn-fg); }
.quote-wizard-pill-chip.is-na { background: var(--line-soft); color: var(--muted); }
.quote-wizard-pill-chip.is-blocked { background: var(--bad-bg); color: var(--bad-fg); }

.quote-money-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem 1.75rem;
  align-items: baseline;
  margin-bottom: 1rem;
}
.quote-money-strip.panel {
  box-shadow: var(--elev-1);
}
.quote-money-label {
  display: block;
  font-size: var(--hub-fs-xs);
  color: var(--muted);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.quote-money-value { font-weight: 600; color: var(--ink); }
/* Subtotal / IVA / Total read at one equal size; Total is distinguished by
   navy color + weight only, never by size. */
.quote-money-total .quote-money-value { color: var(--navy); font-weight: 700; }
/* TRM reference stat: smaller and muted, deliberately not part of the three
   equal-size money values above. */
.quote-money-trm .quote-money-value {
  font-size: var(--hub-fs-sm);
  font-weight: 500;
  color: var(--muted);
}
/* Single readiness verdict pill, appended at the end of the strip. */
.quote-verdict {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  align-self: center;
  margin-left: auto;
  padding: 0.42rem 0.8rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--white);
  color: var(--ink);
  font-size: var(--hub-fs-sm);
  font-weight: 600;
  white-space: nowrap;
}
.quote-verdict .ph {
  font-size: 1rem;
}
.quote-verdict.is-ok { background: var(--ok-bg); color: var(--ok-fg); border-color: var(--ok-line); }
.quote-verdict.is-warn { background: var(--warn-bg); color: var(--warn-fg); border-color: var(--warn-line); }
.quote-verdict.is-bad { background: var(--bad-bg); color: var(--bad-fg); border-color: var(--bad-line); }

.quote-group-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.65rem;
}
.quote-kit-controls {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-left: auto;
}
.quote-kit-quantity-form {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  margin: 0;
}
.quote-kit-quantity-form label {
  margin: 0;
  color: var(--muted);
  font-size: var(--hub-fs-xs);
  font-weight: 600;
}
.quote-kit-quantity-form .form-control { width: 4.25rem; }
.quote-kit-note {
  margin: -0.25rem 0 0.7rem;
  color: var(--muted);
  font-size: var(--hub-fs-sm);
}
.quote-derived-values {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 0.6rem;
  margin-top: 0.25rem;
  color: var(--muted);
  font-family: var(--font-mono, monospace);
  font-size: var(--hub-fs-xs);
}
.quote-line-edit-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  align-items: center;
}
.quote-line-edit-grid .form-control,
.quote-line-edit-grid .form-select {
  width: auto;
  min-width: 4.5rem;
  max-width: 8rem;
}
.quote-doc-check {
  display: flex;
  gap: 0.5rem;
  align-items: flex-start;
  padding: 0.45rem 0;
  font-size: var(--hub-fs-sm);
}
.quote-doc-check.is-ok { color: var(--ok-fg); }
.quote-doc-check.is-off { color: var(--bad-fg); }
.quote-badge-frozen {
  display: inline-block;
  margin-left: 0.35rem;
  padding: 0.1rem 0.4rem;
  font-size: var(--hub-fs-xs);
  font-weight: 600;
  border-radius: 4px;
  background: var(--navy-tint);
  color: var(--navy);
}
/* TRM provenance chip (LIVE / STALE / FALLBACK) on draft wizard masthead */
.quote-trm-status {
  display: inline-block;
  margin-left: 0.25rem;
  padding: 0.05rem 0.35rem;
  font-size: var(--hub-fs-xs);
  font-weight: 600;
  letter-spacing: 0.02em;
  border-radius: 4px;
  vertical-align: middle;
}
.quote-trm-status.is-live { background: var(--ok-bg); color: var(--ok-fg); }
.quote-trm-status.is-stale { background: var(--warn-bg); color: var(--warn-fg); }
.quote-trm-status.is-fallback { background: var(--bad-bg); color: var(--bad-fg); }
.cot-dot { margin: 0 0.25rem; color: var(--muted); }
a.is-current-version { font-weight: 700; color: var(--ink); text-decoration: none; }

/* ── Company create mini-wizard (DRY with quote header panels / stepper) ─ */
.hub-mini-wizard {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 1.25rem;
  flex-wrap: wrap;
}
.hub-mini-wizard-step {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font-size: var(--hub-fs-sm);
  color: var(--muted);
  font-weight: 500;
}
.hub-mini-wizard-dot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 999px;
  border: 1px solid var(--line-soft, #e5e7eb);
  background: #fff;
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: 0.75rem;
  font-weight: 600;
}
.hub-mini-wizard-step.is-current {
  color: var(--ink);
  font-weight: 600;
}
.hub-mini-wizard-step.is-current .hub-mini-wizard-dot {
  border-color: var(--blue, #2563eb);
  background: var(--blue, #2563eb);
  color: #fff;
}
.hub-mini-wizard-step.is-done .hub-mini-wizard-dot {
  border-color: var(--ok-fg, #15803d);
  background: var(--ok-bg, #dcfce7);
  color: var(--ok-fg, #15803d);
}
.hub-mini-wizard-rail {
  flex: 0 0 1.75rem;
  height: 2px;
  background: var(--line-soft, #e5e7eb);
  border-radius: 1px;
}
.hub-mini-wizard-rail.is-done {
  background: var(--ok-fg, #15803d);
  opacity: 0.45;
}
.company-create-panel {
  max-width: 40rem;
}
.company-create-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  gap: 1.25rem;
  align-items: start;
}
@media (max-width: 900px) {
  .company-create-grid { grid-template-columns: 1fr; }
}
.company-create-actions {
  flex-wrap: wrap;
  gap: 0.5rem;
}
.company-create-actions .btn .ph {
  margin-right: 0.25rem;
}
/* Spreadsheet plantilla / export / import (master data) */
.spreadsheet-io-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.65rem 1rem;
  margin-bottom: 1rem;
  padding: 0.65rem 0.9rem;
}
.spreadsheet-io-bar-label {
  margin: 0;
  font-size: var(--hub-fs-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}
.spreadsheet-io {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 0.4rem;
}
.spreadsheet-io-switcher {
  align-items: center;
}
.spreadsheet-io-resource-field {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}
.spreadsheet-io-resource-label {
  font-size: var(--hub-fs-sm);
  font-weight: 600;
  color: var(--ink);
}
.spreadsheet-io-resource-select {
  width: auto;
  min-width: 9.5rem;
}
.spreadsheet-io-import {
  position: relative;
}
.spreadsheet-io-import > summary {
  list-style: none;
  cursor: pointer;
}
.spreadsheet-io-import > summary::-webkit-details-marker {
  display: none;
}
.spreadsheet-io-form {
  position: absolute;
  right: 0;
  top: calc(100% + 0.35rem);
  z-index: 20;
  min-width: 18rem;
  padding: 0.85rem 1rem;
  box-shadow: var(--elev-1, 0 4px 18px rgba(15, 23, 42, 0.08));
}
.spreadsheet-io-help {
  position: relative;
}
.spreadsheet-io-help > summary {
  list-style: none;
  cursor: pointer;
}
.spreadsheet-io-help > summary::-webkit-details-marker {
  display: none;
}
.spreadsheet-io-help-body {
  flex-basis: 100%;
  margin-top: 0.5rem;
  padding: 0.85rem 1rem;
}
.spreadsheet-io-help-rules {
  margin: 0.5rem 0 0;
  padding-left: 1.15rem;
  font-size: var(--hub-fs-sm);
}
.spreadsheet-io-errors {
  margin-bottom: 1rem;
}
.spreadsheet-io-error-list {
  margin: 0.5rem 0 0;
  padding-left: 1.15rem;
  font-size: var(--hub-fs-sm);
}
.spreadsheet-io-error-list li {
  margin-bottom: 0.25rem;
}
@media (max-width: 575.98px) {
  .spreadsheet-io-switcher {
    align-items: stretch;
  }
  .spreadsheet-io-resource-field {
    width: 100%;
  }
  .spreadsheet-io-resource-select {
    flex: 1 1 auto;
  }
}
.hub-perm-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
}
.hub-admin-access-form {
  max-width: 66rem;
}
.hub-admin-access-panel {
  max-width: none;
}
.hub-admin-identities-table {
  max-width: 100%;
}
.hub-admin-meta {
  padding: 0.65rem 0.75rem;
  background: var(--paper, #f4f4f5);
  border-radius: 0.35rem;
}
.panel-form-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0 0 1.5rem;
  padding: 0;
  background: transparent;
  border: 0;
  box-shadow: none;
}

/* ── RUES (company form + registry card) ───────────────────────────────── */
.rues-nit-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}
.rues-nit-row .form-control { flex: 1 1 12rem; min-width: 10rem; }
.rues-dv-label {
  font-size: var(--hub-fs-xs);
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.rues-dv-value {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-weight: 600;
  min-width: 1.25rem;
  text-align: center;
}
.rues-indicator {
  display: none;
  align-items: center;
  gap: 0.4rem;
  font-size: var(--hub-fs-sm);
  color: var(--muted);
  white-space: nowrap;
}
.rues-indicator.htmx-request { display: inline-flex; }
#rues-btn.htmx-request { opacity: 0.6; pointer-events: none; }
.rues-preview-host { margin-top: 0.65rem; }
.rues-box {
  display: flex;
  gap: 0.65rem;
  align-items: flex-start;
  padding: 0.75rem 0.9rem;
  border-radius: 8px;
  margin-bottom: 0.65rem;
  font-size: var(--hub-fs-sm);
}
.info-box.rues-box {
  background: var(--navy-tint, #eef2f7);
  color: var(--ink);
}
.warning-box.rues-box {
  background: #fff6e5;
  color: #5c4200;
  border: 1px solid #f0d9a0;
}
.rues-box .box-icon { font-size: 1.15rem; flex-shrink: 0; margin-top: 0.1rem; }
.rues-box .box-title { font-weight: 600; margin-bottom: 0.25rem; }
.rues-card {
  display: grid;
  gap: 0.35rem;
  padding: 0.75rem 0.9rem;
  border: 1px solid var(--line-soft, #e5e7eb);
  border-radius: 8px;
  background: #fff;
  margin-bottom: 0.65rem;
}
.rues-card .meta-row {
  display: grid;
  grid-template-columns: 8.5rem 1fr;
  gap: 0.5rem;
  font-size: var(--hub-fs-sm);
}
.rues-card .field-label {
  color: var(--muted);
  font-weight: 500;
}
/* ── Shared typeahead (company / catalog party) ───────────────────────────── */
.hub-typeahead {
  position: relative;
}
.hub-typeahead-menu {
  position: absolute;
  z-index: 40;
  left: 0;
  right: 0;
  top: calc(100% + 2px);
  max-height: 16rem;
  overflow-y: auto;
  margin: 0;
  padding: 0.25rem 0;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--white);
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.1);
}
.hub-typeahead-opt {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.1rem;
  width: 100%;
  margin: 0;
  padding: 0.45rem 0.75rem;
  border: 0;
  background: transparent;
  text-align: left;
  font: inherit;
  color: var(--ink);
  cursor: pointer;
}
.hub-typeahead-opt:hover,
.hub-typeahead-opt.is-active {
  background: var(--navy-tint, #E7EDF4);
}
.hub-typeahead-opt-label {
  font-weight: 500;
}
.hub-typeahead-opt-meta {
  font-size: var(--hub-fs-xs);
  color: var(--muted);
}
.hub-typeahead-empty {
  margin: 0;
  padding: 0.55rem 0.75rem;
  font-size: var(--hub-fs-sm);
  color: var(--muted);
}

/* ── Consultant quote wizard bodies ───────────────────────────────────────── */
.quote-step-title {
  margin: 0 0 0.35rem;
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--ink);
  font-family: var(--font-sans);
}
.quote-step-lead {
  margin: 0 0 1.25rem;
  color: var(--muted);
  font-size: var(--hub-fs-sm);
  max-width: 42rem;
  line-height: 1.5;
}
.quote-section-label {
  margin: 1.25rem 0 0.65rem;
  font-size: var(--hub-fs-xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}
.quote-section-label:first-child { margin-top: 0; }
.quote-empty {
  padding: 1.5rem 0;
  color: var(--muted);
  font-size: var(--hub-fs-sm);
}

/* Segmented control (zero-JS): styled radios for two/three exclusive choices. */
.hub-seg {
  display: inline-flex;
  padding: 3px;
  gap: 2px;
  background: var(--line-soft);
  border-radius: 11px;
}
.hub-seg label { margin: 0; cursor: pointer; }
.hub-seg input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.hub-seg span {
  display: block;
  padding: 0.34rem 0.85rem;
  border-radius: 8px;
  font-size: var(--hub-fs-sm);
  color: var(--body);
  font-weight: 500;
  transition: background 0.12s ease, color 0.12s ease;
}
.hub-seg input:checked + span {
  background: var(--white);
  color: var(--navy);
  font-weight: 600;
  box-shadow: 0 1px 0 rgba(14, 42, 69, 0.06);
}
.hub-seg input:focus-visible + span { outline: 2px solid var(--blue); outline-offset: 2px; }

/* Segmented control, multi-select variant: same pill track/tokens as .hub-seg, but each
   option is an independent checkbox so more than one can be active at once. */
.hub-seg-multi {
  display: flex;
  flex-wrap: wrap;
  width: fit-content;
  max-width: 100%;
  padding: 3px;
  gap: 2px;
  background: var(--line-soft);
  border-radius: 11px;
}
.hub-seg-multi label { margin: 0; cursor: pointer; }
.hub-seg-multi input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.hub-seg-multi span {
  display: block;
  padding: 0.34rem 0.85rem;
  border-radius: 8px;
  font-size: var(--hub-fs-sm);
  color: var(--body);
  font-weight: 500;
  transition: background 0.12s ease, color 0.12s ease;
}
.hub-seg-multi input:checked + span {
  background: var(--white);
  color: var(--navy);
  font-weight: 600;
  box-shadow: 0 1px 0 rgba(14, 42, 69, 0.06);
}
.hub-seg-multi input:focus-visible + span { outline: 2px solid var(--blue); outline-offset: 2px; }

/* Bound-company card at the top of Encabezado. */
.quote-company-card {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.85rem 1rem;
  margin-bottom: 1.25rem;
  border: 1px solid var(--line-soft);
  border-radius: 12px;
  background: var(--surface-soft, #fafbfc);
}
.quote-company-card .qc-ico {
  width: 38px;
  height: 38px;
  border-radius: 10px;
  background: var(--navy-tint);
  color: var(--navy);
  display: grid;
  place-items: center;
  flex: 0 0 auto;
}
.quote-company-card .qc-ico .ph { font-size: 1.2rem; }
.quote-company-card .qc-info { display: flex; flex-direction: column; gap: 0.1rem; min-width: 0; }
.quote-company-card .qc-label {
  font-size: var(--hub-fs-xs);
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
}
.quote-company-card .qc-name { font-size: 1rem; font-weight: 600; color: var(--ink); }
.quote-company-card .qc-meta {
  font-size: var(--hub-fs-xs);
  color: var(--muted);
  display: flex;
  gap: 0.45rem;
  flex-wrap: wrap;
  align-items: center;
}
.quote-company-card .qc-meta .sep { color: var(--line); }
.quote-company-card .qc-actions { margin-left: auto; }

/* Header step: two columns (encuadre | condiciones) */
.quote-header-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.25rem 1.5rem;
  margin-bottom: 0.25rem;
}
@media (max-width: 900px) {
  .quote-header-grid { grid-template-columns: 1fr; }
}
.quote-header-panel {
  margin: 0;
  padding: 1.1rem 1.15rem 1.2rem;
  border: 1px solid var(--line-soft);
  border-radius: 10px;
  background: var(--surface-soft, #fafbfc);
}
.quote-header-panel-title {
  margin: 0 0 1rem;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--ink);
}
.quote-header-panel .field { margin-bottom: 0.9rem; }
.quote-header-panel .field:last-child { margin-bottom: 0; }
.quote-header-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.75rem 1rem;
}
.quote-delivery-range {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.5rem;
}
.quote-delivery-range .form-control {
  width: 5.5rem;
  max-width: 5.5rem;
  flex: 0 0 auto;
}
.quote-delivery-sep {
  color: var(--muted);
  font-size: var(--hub-fs-sm);
}
.quote-delivery-unit {
  color: var(--muted);
  font-size: var(--hub-fs-sm);
}
.quote-milestones-block {
  margin-top: 1.25rem;
  padding-top: 0.15rem;
}
.quote-milestone-rows {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
  margin-bottom: 0.75rem;
}
.quote-milestone-row {
  display: grid;
  grid-template-columns: 7rem 1fr auto;
  gap: 0.5rem;
  align-items: center;
}
.quote-milestone-row .hub-percent-input {
  max-width: none;
  width: 100%;
}
.quote-ms-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
}
.quote-ms-head-actions {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.4rem;
}
.quote-ms-sum {
  font-size: var(--hub-fs-sm);
  font-weight: 600;
  color: var(--muted);
}
.quote-ms-sum.is-ok { color: var(--ok-fg); }
.quote-ms-del {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
.quote-ms-del:hover { color: var(--bad-fg); background: var(--bad-bg); }
.quote-ms-add {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.32rem 0.7rem;
  border: 1px dashed var(--line);
  border-radius: 8px;
  background: var(--paper);
  color: var(--blue-deep);
  font: inherit;
  font-size: var(--hub-fs-xs);
  font-weight: 600;
  cursor: pointer;
}
.quote-ms-add:hover { border-color: var(--blue-soft); }

/* Artículos editable line: labeled fields wrap in one row so each input is obvious. */
.quote-line-fields {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.35rem 0.7rem;
}
.quote-line-fields .quote-field {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  margin: 0;
}
.quote-line-fields .quote-field > span {
  font-size: var(--hub-fs-xs);
  font-weight: 600;
  color: var(--muted);
  letter-spacing: 0.02em;
}
.quote-field-desc { flex: 1 1 13rem; }
.quote-field-num .form-control { width: 5.5rem; }
.quote-recur-controls {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  height: calc(1.5em + 0.5rem + 2px); /* match form-control-sm height so the row aligns */
}
.quote-recur-controls .form-control { width: 4.5rem; }
.quote-line-save { align-self: flex-end; }
.quote-basis-cell { min-width: 7rem; }
.quote-price-hints {
  margin-top: 0.3rem;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}
.quote-price-hint {
  margin: 0;
  font-size: var(--hub-fs-xs);
  color: var(--muted);
  white-space: nowrap;
}
.quote-price-hint > span:first-child { margin-right: 0.25rem; }

/* Revisión: read-only content preview (grouped lines + totals + forma de pago + condiciones). */
.quote-review-group-title {
  font-size: var(--hub-fs-sm);
  font-weight: 600;
  color: var(--ink);
  margin: 1rem 0 0.4rem;
}
.quote-review-group:first-of-type .quote-review-group-title { margin-top: 0; }
.quote-review-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem 2.5rem;
  margin-top: 1.25rem;
}
.quote-review-block { flex: 1 1 12rem; min-width: 0; }
.quote-review-total { font-weight: 600; color: var(--navy); }
.quote-review-notes {
  margin-top: 0.5rem;
  color: var(--muted);
  font-size: var(--hub-fs-sm);
  white-space: pre-line;
}

.quote-chip {
  display: inline-block;
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 0.12rem 0.4rem;
  border-radius: 4px;
  background: var(--navy-tint, #E7EDF4);
  color: var(--navy);
}
.quote-chip-muted {
  background: var(--line-soft);
  color: var(--muted);
}
.quote-chip-warn {
  background: var(--warn-bg);
  color: var(--warn-fg);
}
.quote-chip-ok {
  background: var(--ok-bg);
  color: var(--ok-fg);
}

/* Status pills sitting next to buttons in a page-header action row (e.g. diagnostic detail):
   .action-row stretches its flex children to a common height by default, which distorts a
   .quote-chip's small fixed padding. This wrapper centers the pills on the button row and keeps
   a clear gap before the buttons that follow. */
.hub-status-pills {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-right: 0.5rem;
}

/* Unified add bar: one kind switch + one row of fields */
.quote-addbar {
  margin: 0 0 1.5rem;
  padding: 1rem 1.1rem;
  border: 1px solid var(--line-soft);
  border-radius: 10px;
  background: var(--surface-soft, #fafbfc);
}
.quote-addbar .eyebrow { margin-bottom: 0.65rem; }
.quote-addbar-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.55rem 0.65rem;
}
.quote-addbar-kind-field {
  flex: 0 0 auto;
  min-width: 8.5rem;
  margin: 0;
}
.quote-addbar-kind-field label {
  display: block;
  font-size: var(--hub-fs-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 0.3rem;
}
.quote-addbar-kind-field .form-select {
  width: auto;
  min-width: 8.5rem;
}
.quote-addbar-toolbar .field {
  margin: 0;
  flex: 1 1 10rem;
  min-width: 7rem;
  max-width: 18rem;
}
.quote-addbar-toolbar .field-qty {
  flex: 0 0 5.5rem;
  max-width: 5.5rem;
}
.quote-addbar-toolbar .field-price {
  flex: 0 0 7.5rem;
  max-width: 8rem;
}
.quote-addbar-toolbar .field-currency,
.quote-addbar-toolbar .field-class {
  flex: 0 0 6.5rem;
  max-width: 7.5rem;
}
.quote-addbar-toolbar .field-grow {
  flex: 2 1 14rem;
  max-width: 22rem;
}
.quote-addbar-toolbar .field label {
  display: block;
  font-size: var(--hub-fs-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 0.3rem;
}
.quote-addbar-toolbar .form-select,
.quote-addbar-toolbar .form-control {
  width: 100%;
  max-width: 100%;
}
.quote-addbar-toolbar .quote-addbar-submit {
  flex: 0 0 auto;
  align-self: flex-end;
}
.quote-addbar-hint {
  margin: 0.55rem 0 0;
  font-size: var(--hub-fs-xs);
  color: var(--muted);
  line-height: 1.4;
}

.catalog-variant-picker {
  display: grid;
  grid-template-columns: minmax(9rem, 13rem) minmax(14rem, 1fr);
  gap: 0.45rem;
}
.catalog-variant-picker .hub-typeahead { min-width: 0; }
@media (max-width: 640px) {
  .catalog-variant-picker { grid-template-columns: 1fr; }
}

/* Wizard help disclosure ("¿Cómo funciona el cotizador?") */
.quote-help {
  margin: 0 0 1rem;
}
.quote-help > summary {
  list-style: none;
  cursor: pointer;
}
.quote-help > summary::-webkit-details-marker {
  display: none;
}
.quote-help-body {
  margin-top: 0.5rem;
  padding: 0.85rem 1rem;
}
.quote-help-heading {
  margin: 0.9rem 0 0.35rem;
  font-size: var(--hub-fs-sm);
}
.quote-help-heading:first-of-type { margin-top: 0.35rem; }
.quote-help-list {
  margin: 0 0 0.5rem;
  padding-left: 1.15rem;
  font-size: var(--hub-fs-sm);
  color: var(--ink-mid, #4a5568);
}
.quote-help-list li { margin-bottom: 0.25rem; }
.quote-help-footnote {
  margin: 0.75rem 0 0;
  font-size: var(--hub-fs-xs);
  color: var(--muted);
}

/* Costing step table */
.quote-costing-note {
  margin: 0 0 1rem;
  padding: 0.75rem 0.9rem;
  border-radius: 8px;
  background: var(--surface-soft, #fafbfc);
  border: 1px solid var(--line-soft);
  font-size: var(--hub-fs-sm);
  color: var(--ink-mid, #4a5568);
  line-height: 1.45;
}
.quote-costing-note strong { color: var(--ink); font-weight: 600; }
.quote-cost-missing {
  color: #9a6b00;
  font-weight: 500;
}
.quote-group-block { margin-bottom: 1.5rem; }
.quote-group-title {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--ink);
}
.quote-lines-table thead th {
  font-size: var(--hub-fs-xs);
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--muted);
  border-bottom-color: var(--line-soft);
  background: transparent;
}
/* Wizard step tables carry a lot of columns — keep the body text compact. */
.quote-wizard-body table.table { font-size: var(--hub-fs-sm); }
.quote-wizard-body table.table thead th { font-size: var(--hub-fs-xs); }
.quote-line-edit { margin: 0; }
.quote-line-knobs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  align-items: center;
}
.quote-line-knobs .form-control,
.quote-line-knobs .form-select {
  width: auto;
  min-width: 3.5rem;
  max-width: 6.5rem;
}
.quote-money-strip-inline {
  margin-bottom: 1.15rem;
  padding-bottom: 0.85rem;
  border-bottom: 1px solid var(--line-soft);
}
.quote-dials {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
  gap: 1rem 1.25rem;
  margin-bottom: 0.5rem;
}
.quote-dial label {
  display: block;
  font-size: var(--hub-fs-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 0.35rem;
}
.quote-dial .field-hint {
  margin-top: 0.35rem;
}
.quote-dial .hub-percent-input {
  max-width: 10rem;
}
.quote-shipment {
  margin-bottom: 1.75rem;
  padding-bottom: 1.25rem;
  border-bottom: 1px solid var(--line-soft);
}
.quote-shipment:last-child { border-bottom: 0; }
.quote-shipment-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
  margin-bottom: 0.85rem;
}
.quote-shipment-title {
  margin: 0.15rem 0 0;
  font-size: 1rem;
  font-weight: 600;
  color: var(--ink);
}
.quote-shipment-fee { margin-bottom: 0.75rem; }
.field-action .btn { width: 100%; }
.quote-inline-form { margin: 0; display: inline-flex; }
.quote-health {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem 1.75rem;
  align-items: flex-start;
}
.quote-health-compact { margin-bottom: 1rem; }
.quote-health-score {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-width: 5.5rem;
  min-height: 5.5rem;
  padding: 0.75rem;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--white);
}
.quote-health-score-num {
  font-size: 1.65rem;
  font-weight: 700;
  line-height: 1;
  color: var(--ink);
}
.quote-health-score-label {
  margin-top: 0.35rem;
  font-size: var(--hub-fs-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}
.quote-health-score.is-ok { border-color: var(--ok-line); background: var(--ok-bg); }
.quote-health-score.is-ok .quote-health-score-num { color: var(--ok-fg); }
.quote-health-score.is-risk { border-color: var(--warn-line); background: var(--warn-bg); }
.quote-health-score.is-risk .quote-health-score-num { color: var(--warn-fg); }
.quote-health-score.is-blocker { border-color: var(--bad-line); background: var(--bad-bg); }
.quote-health-score.is-blocker .quote-health-score-num { color: var(--bad-fg); }
.quote-health-score.is-watch { border-color: var(--line); }
.quote-health-issues {
  list-style: none;
  margin: 0;
  padding: 0;
  flex: 1 1 16rem;
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
}
.quote-health-issue {
  display: flex;
  gap: 0.65rem;
  padding: 0.75rem 0.85rem;
  border-radius: 8px;
  border: 1px solid var(--line-soft);
  background: var(--white);
  font-size: var(--hub-fs-sm);
}
.quote-health-issue i { font-size: 1.15rem; margin-top: 0.1rem; color: var(--muted); }
.quote-health-issue.is-blocker i { color: #a32020; }
.quote-health-issue.is-risk i { color: #9a6b00; }
.quote-health-action {
  margin-top: 0.25rem;
  font-size: var(--hub-fs-xs);
  color: var(--muted);
}
.quote-cierre-actions { margin: 1rem 0 1.5rem; }
.quote-cierre-meta {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
  gap: 1.5rem;
}
.quote-doc-checks { display: flex; flex-direction: column; gap: 0.45rem; }
.quote-doc-check {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  font-size: var(--hub-fs-sm);
  padding: 0.55rem 0.7rem;
  border-radius: 8px;
  border: 1px solid var(--line-soft);
}
.quote-doc-check.is-ok { background: var(--ok-bg); border-color: var(--ok-line); }
.quote-doc-check.is-off { background: var(--bad-bg); border-color: var(--bad-line); }

/* Opportunity media: Dropzone owns selection/progress while this layer keeps it inside Hub's calm card system. */
.hub-media-pane { display:grid; gap:1.25rem; }
.hub-media-section-heading { display:flex; align-items:flex-start; justify-content:space-between; gap:1rem; margin-bottom:1.25rem; }
.hub-media-section-title { margin:0; color:var(--ink); font-size:var(--hub-fs-xl); }
.hub-media-section-copy { margin:.35rem 0 0; color:var(--muted); font-size:var(--hub-fs-sm); }
.hub-media-count { flex:0 0 auto; padding:.3rem .55rem; border:1px solid var(--line-soft); border-radius:999px; background:var(--surface-soft, var(--paper)); color:var(--muted); font-size:var(--hub-fs-xs); }
.hub-media-upload-layout { display:grid; grid-template-columns:minmax(15rem, .9fr) minmax(18rem, 1.1fr); gap:1rem; align-items:stretch; }
.hub-media-drop { display:flex; flex-direction:column; align-items:center; justify-content:center; gap:.35rem; min-height:13rem; padding:1.5rem; border:2px dashed var(--line); border-radius:10px; text-align:center; background:var(--white); cursor:pointer; }
.hub-media-drop:hover, .hub-media-drop.dz-drag-hover { border-color:var(--blue); background:var(--navy-tint); }
.hub-media-drop > i { font-size:2rem; color:var(--blue-deep); }
.hub-media-drop > strong { color:var(--ink); }
.hub-media-drop > span, .hub-media-drop > small { color:var(--muted); font-size:var(--hub-fs-sm); }
.hub-media-drop .btn { margin-top:.35rem; pointer-events:none; }
.hub-media-fallback-input { max-width:18rem; }
.hub-media-queue { display:flex; align-items:stretch; min-height:13rem; padding:.8rem; border:1px solid var(--line-soft); border-radius:10px; background:var(--surface-soft, var(--paper)); }
.hub-media-queue-empty { align-self:center; margin:auto; max-width:18rem; color:var(--muted); font-size:var(--hub-fs-sm); text-align:center; }
.hub-media-queued-file { display:flex; align-items:flex-start; gap:.7rem; width:100%; margin:0; padding:.75rem; border:1px solid var(--line-soft); border-radius:8px; background:var(--white); }
.hub-media-queued-icon { display:grid; place-items:center; flex:0 0 2.25rem; width:2.25rem; height:2.25rem; border-radius:7px; color:var(--blue-deep); background:var(--navy-tint); }
.hub-media-queued-details { flex:1 1 auto; min-width:0; }
.hub-media-queued-details strong, .hub-media-queued-details > span { display:block; overflow-wrap:anywhere; }
.hub-media-queued-details > span { margin-top:.15rem; color:var(--muted); font-size:var(--hub-fs-xs); }
.hub-media-queued-progress { height:.35rem; margin-top:.7rem; overflow:hidden; border-radius:999px; background:var(--line-soft); }
.hub-media-queued-progress .dz-upload { display:block; width:0; height:100%; background:var(--blue); transition:width .15s ease; }
.hub-media-queued-file .dz-error-message { display:none; margin:.45rem 0 0; color:var(--bad-fg); font-size:var(--hub-fs-xs); }
.hub-media-queued-file.dz-error .dz-error-message { display:block; }
.hub-media-remove { flex:0 0 auto; padding:.15rem; border:0; background:transparent; color:var(--muted); cursor:pointer; }
.hub-media-remove:hover, .hub-media-remove:focus-visible { color:var(--bad-fg); }
.hub-media-status { display:flex; align-items:flex-start; gap:.5rem; padding:.7rem .8rem; border:1px solid var(--line-soft); border-radius:8px; background:var(--surface-soft, var(--paper)); color:var(--muted); font-size:var(--hub-fs-sm); }
.hub-media-status i { flex:0 0 auto; font-size:1.1rem; }
.hub-media-status.is-ready { border-color:var(--ok-line); background:var(--ok-bg); color:var(--ok-fg); }
.hub-media-status.is-uploading { border-color:var(--blue-soft); background:var(--navy-tint); color:var(--navy); }
.hub-media-status.is-success { border-color:var(--ok-line); background:var(--ok-bg); color:var(--ok-fg); }
.hub-media-status.is-error { border-color:var(--bad-line); background:var(--bad-bg); color:var(--bad-fg); }
.hub-media-progress { display:block; width:100%; height:.65rem; accent-color:var(--blue); }
.hub-media-submit-tooltip { position:relative; display:inline-flex; }
.hub-media-submit-tooltip:focus-visible { outline:2px solid var(--blue); outline-offset:3px; border-radius:6px; }
.hub-media-submit-tooltip:has(button:disabled)::after { position:absolute; z-index:4; bottom:calc(100% + .45rem); left:0; width:max-content; max-width:19rem; padding:.45rem .6rem; border-radius:6px; background:var(--navy); color:var(--white); content:attr(data-tooltip); font-size:var(--hub-fs-xs); line-height:1.35; opacity:0; pointer-events:none; transform:translateY(.2rem); transition:opacity .15s ease, transform .15s ease; }
.hub-media-submit-tooltip:has(button:disabled):hover::after, .hub-media-submit-tooltip:has(button:disabled):focus-within::after, .hub-media-submit-tooltip:has(button:disabled):focus-visible::after { opacity:1; transform:translateY(0); }
.hub-media-submit-tooltip .btn:disabled { border-color:var(--line); background:var(--line-soft); color:var(--muted); opacity:1; cursor:not-allowed; }
@media (max-width: 767.98px) { .hub-media-upload-layout { grid-template-columns:1fr; } .hub-media-drop, .hub-media-queue { min-height:10rem; } .hub-media-section-heading { flex-direction:column; } }
.hub-media-grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(250px,1fr)); gap:1rem; }
.hub-media-card { display:flex; flex-direction:column; min-width:0; border:1px solid var(--line-soft); border-radius:10px; background:var(--white); overflow:hidden; }
.hub-media-preview { position:relative; display:grid; place-items:center; min-height:150px; background:var(--surface-soft, var(--paper)); text-decoration:none; overflow:hidden; }
.hub-media-preview img { width:100%; height:150px; object-fit:cover; transition:transform .18s ease; }
.hub-media-preview > span { position:absolute; right:.6rem; bottom:.6rem; padding:.25rem .45rem; border-radius:5px; background:color-mix(in srgb, var(--navy) 88%, transparent); color:var(--white); font-size:var(--hub-fs-xs); opacity:0; transform:translateY(.2rem); transition:opacity .15s ease, transform .15s ease; }
.hub-media-preview:hover img { transform:scale(1.02); }
.hub-media-preview:hover > span, .hub-media-preview:focus-visible > span { opacity:1; transform:translateY(0); }
.hub-media-card-body { display:flex; flex:1 1 auto; flex-direction:column; padding:.85rem; }
.hub-media-card p { margin:.35rem 0; color:var(--muted); font-size:var(--hub-fs-xs); overflow-wrap:anywhere; }
.hub-media-card-heading { display:flex; align-items:flex-start; justify-content:space-between; gap:.5rem; margin-bottom:.15rem; }
.hub-media-card-heading strong { min-width:0; overflow-wrap:anywhere; }
.hub-media-pdf { display:block; padding:1.5rem 0; color:var(--bad-fg); font-size:5rem; text-align:center; }
.hub-media-rename { margin-top:.6rem; color:var(--muted); font-size:var(--hub-fs-sm); }
.hub-media-rename summary { width:max-content; color:var(--blue-deep); cursor:pointer; }
.hub-media-rename form { margin-top:.55rem; }
.hub-media-rename-controls { display:flex; gap:.45rem; }
.hub-media-rename-controls .form-control { min-width:0; }
.hub-media-card-actions { display:flex; justify-content:space-between; gap:.5rem; margin-top:auto; padding-top:.85rem; }

/* Installed iOS web-apps need their content clear of the sensor/home-indicator areas. Desktop keeps its normal spacing. */
@supports (padding: max(0px)) {
  @media (max-width: 991.98px) {
    .hub-content-topbar { padding-top:max(.45rem, env(safe-area-inset-top)); padding-left:max(1.25rem, env(safe-area-inset-left)); padding-right:max(1.25rem, env(safe-area-inset-right)); }
    .hub-main { padding-bottom:max(1.5rem, env(safe-area-inset-bottom)); padding-left:max(1.25rem, env(safe-area-inset-left)); padding-right:max(1.25rem, env(safe-area-inset-right)); }
  }
}

/*
 * Gestión log (opportunity detail, Gestiones tab): a calm timeline — hairline
 * separators between entries, no per-row card boxes (see frontend-design.md).
 */
.hub-gestion-entry {
  padding: 1rem 0;
  border-bottom: 1px solid var(--line-soft);
}
.hub-gestion-entry:last-child {
  border-bottom: none;
  padding-bottom: 0;
}
.hub-gestion-entry-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 0.6rem;
  margin-bottom: 0.35rem;
}
.hub-gestion-entry-when {
  font-size: var(--hub-fs-sm);
  color: var(--muted);
}
.hub-gestion-entry-actions {
  margin-left: auto;
}
.hub-gestion-entry-note {
  margin: 0;
  color: var(--ink);
}

/* The next step, in one sentence: responsable · qué sigue · cuándo. The responsable is the row's
   single colored chip; the other two are ink and muted, so the eye lands on the chip and reads the
   rest only if it stays. */
.next-step-what {
  display: block;
  margin-top: 0.3rem;
  font-weight: 600;
  color: var(--ink);
}
/* "+2": the sentence names one compromiso, this says how many more are open. */
.next-step-more {
  margin-left: 0.35rem;
  font-size: var(--hub-fs-xs);
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0 0.35rem;
}

.next-step-when {
  display: block;
  font-size: var(--hub-fs-xs);
  color: var(--muted);
}
/* Late is weight and ink, never red: red is reserved for destructive actions. */
.next-step-when.is-overdue {
  color: var(--ink);
  font-weight: 700;
}

/* The next step on the opportunity header: the same sentence the workspace row carries, on the
   page a consultant lands on, so "what follows" never requires opening a tab. */
.hub-next-step {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem;
  margin: 0.35rem 0 0;
  font-size: var(--hub-fs-sm);
  color: var(--muted);
}
.hub-next-step-who {
  font-weight: 700;
  color: var(--ink);
}
.hub-next-step-what {
  color: var(--ink);
}
.hub-next-step-when.is-overdue {
  color: var(--ink);
  font-weight: 700;
}

/* Who owes the next move, under a pending commitment. Quiet by default: it is context, and the
   row's one colored element is the recommendation. "Vencido" is weight and ink rather than red,
   the same choice made for an overdue Seguimiento, so red keeps meaning one thing. */
.hub-ball {
  margin: 0.35rem 0 0;
  font-size: var(--hub-fs-sm);
  color: var(--muted);
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}
.hub-ball strong {
  color: var(--ink);
}
.hub-ball-late {
  color: var(--ink);
  font-weight: 700;
}

/* Registrar console (opportunity detail): Gestión and Compromiso as two columns of one card,
   the same two-column pattern .temperature-legend / .temperature-help-grid already use, at the
   same breakpoint. Each fieldset keeps its own submit button; only the layout changes. */
.hub-registro-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.5rem 2rem;
}
@media (max-width: 900px) {
  .hub-registro-grid {
    grid-template-columns: 1fr;
  }
}

/* ── Proposal detail: generate requirements checklist ──────────────────────
   Reuses the shared ok/warn status tokens (see :root above) rather than a
   new palette: a satisfied requirement reads as --ok, a pending one as
   --warn (never alarm red — nothing is broken, it just is not ready yet). */
.hub-gate-done {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0;
  color: var(--ok-fg);
  font-weight: 600;
}
.hub-gate-done .ph { font-size: 1.1rem; }

.hub-gatelist {
  list-style: none;
  margin: 0 0 0.6rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
}

.hub-gate {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: var(--hub-fs-sm);
}

.hub-gate .ph { font-size: 1rem; }

.hub-gate-ok { color: var(--ok-fg); }
.hub-gate-ok .ph { color: var(--ok-fg); }

.hub-gate-pending { color: var(--ink); }
.hub-gate-pending .ph { color: var(--warn-fg); }

/* A pending requirement is a jump link to the control that fixes it, with a one-line instruction
   underneath. Satisfied requirements stay plain text -- there is nothing to go and do. */
.hub-gate-link {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  color: inherit;
  text-decoration: none;
  border-bottom: 1px dashed var(--line);
}
.hub-gate-link:hover,
.hub-gate-link:focus-visible {
  color: var(--blue);
  border-bottom-color: currentColor;
}
.hub-gate-hint {
  font-size: var(--hub-fs-xs);
  color: var(--muted);
  line-height: 1.35;
}

/* Jumped-to sections must clear the sticky header instead of hiding under it. */
[id^="sec-"],
#route,
#coverTitle {
  scroll-margin-top: 5rem;
}

.hub-gate-summary {
  margin: 0;
  padding: 0.5rem 0.7rem;
  border-radius: 8px;
  background: var(--warn-bg);
  color: var(--warn-fg);
  font-size: var(--hub-fs-sm);
  font-weight: 500;
}

/* Compact read-only panels: tighter padding + kv rhythm than a working-form panel */
.panel-compact {
  padding: 0.7rem 1.05rem;
}

.hub-kv-tight {
  gap: 0.5rem 1.25rem;
}

.hub-form-inline {
  display: flex;
  align-items: flex-end;
  gap: 1rem;
  flex-wrap: wrap;
}

.hub-form-inline .field { margin-bottom: 0; flex: 1 1 16rem; }

/* Diagnostic detail "Enlace" card: the copy field + toggle/vigencia controls on the left, the QR
   code on the right, sharing the full card width instead of stacking in a narrow column. */
.diagnostic-link-row {
  display: flex;
  gap: 1.75rem;
  flex-wrap: wrap;
}

.diagnostic-link-main {
  flex: 1 1 22rem;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

.diagnostic-link-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 1.5rem;
  align-items: flex-end;
}

.diagnostic-link-qr {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
}

.diagnostic-link-qr img {
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  padding: 0.5rem;
  background: var(--white);
}

.diagnostic-link-qr-caption {
  margin: 0;
  font-size: var(--hub-fs-xs);
  color: var(--muted);
}

/* "Primeros pasos" guide page: an ordered, numbered list of calm cards. */
.guide-steps {
  list-style: none;
  margin: 0;
  padding: 0;
}
.guide-step-header {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 0.4rem;
}
.guide-step-number {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--navy-tint);
  color: var(--navy);
  font-weight: 600;
  font-size: var(--hub-fs-sm);
}
.guide-step-title {
  margin: 0;
  font-size: var(--hub-fs);
  font-weight: 600;
  color: var(--ink);
}
.guide-step-sentence {
  margin: 0 0 0.75rem;
  color: var(--muted);
  line-height: var(--hub-lh);
}
.guide-rules-list {
  margin: 0;
  padding-left: 1.15rem;
  font-size: var(--hub-fs-sm);
}
.guide-rules-list li {
  margin-bottom: 0.25rem;
}

.hub-page-title-sm {
  font-size: var(--hub-fs-title);
  margin: 0 0 0.9rem;
}
/* Proposal authoring keeps the common path compact and isolates customer-specific prose by section. */
.proposal-authoring-tabs {
  margin-bottom: 1.25rem;
}

.proposal-authoring-layout {
  display: grid;
  grid-template-columns: minmax(14rem, 18rem) minmax(0, 1fr);
  gap: 1.25rem;
  align-items: start;
}

.proposal-narrative-toc {
  position: sticky;
  top: 1rem;
}

.proposal-section-nav {
  display: grid;
  gap: 0.25rem;
  margin-top: 1rem;
}

.proposal-section-link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding: 0.65rem 0.75rem;
  border-radius: var(--radius-btn);
  color: var(--muted);
  text-decoration: none;
  line-height: 1.3;
}

.proposal-section-link:hover {
  background: var(--paper);
  color: var(--ink);
}

.proposal-section-link.is-active {
  background: var(--navy-tint);
  color: var(--navy);
  font-weight: 650;
}

.proposal-section-count {
  min-width: 1.55rem;
  padding: 0.1rem 0.4rem;
  border-radius: 999px;
  background: var(--white);
  color: var(--navy);
  font-size: var(--hub-fs-xs);
  text-align: center;
}

.proposal-narrative-editor-header,
.proposal-narrative-field-heading,
.proposal-token-toolbar {
  display: flex;
  align-items: center;
  gap: 0.65rem;
}

.proposal-narrative-editor-header {
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 1rem;
}

.proposal-token-toolbar {
  flex-wrap: wrap;
  padding: 0.75rem;
  border-radius: var(--radius-btn);
  background: var(--paper);
  margin-bottom: 1.25rem;
}

.proposal-token-toolbar-label {
  margin-right: 0.25rem;
  color: var(--muted);
  font-size: var(--hub-fs-sm);
  font-weight: 600;
}

.proposal-narrative-field {
  margin-block: 1.35rem;
}

.proposal-narrative-field-heading {
  min-height: 2rem;
  margin-bottom: 0.45rem;
}

.proposal-narrative-field-heading label {
  margin: 0 auto 0 0;
}

.proposal-narrative-actions {
  position: sticky;
  bottom: 0;
  z-index: 2;
  padding-block: 0.8rem;
  background: var(--white);
}

@media (max-width: 991.98px) {
  .proposal-authoring-layout {
    grid-template-columns: 1fr;
  }

  .proposal-narrative-toc {
    position: static;
  }

  .proposal-section-nav {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 575.98px) {
  .proposal-section-nav {
    grid-template-columns: 1fr;
  }

  .proposal-narrative-editor-header,
  .proposal-narrative-field-heading {
    align-items: flex-start;
    flex-direction: column;
  }

  .proposal-narrative-field-heading label {
    margin-right: 0;
  }
}
