/* ⚠ COPIA AUTOMÁTICA · NO EDITAR ESTE ARCHIVO ⚠
   El original vive en `website/design-system/dashboard.css` y se reparte con
   `_scripts/sync-design-system.py`. Cualquier cambio hecho aquí se pierde en la
   siguiente sincronización. Para cambiar un color, un radio o una tipografía en
   TODOS los productos a la vez, se edita el original y se ejecuta el programa. */

/* ============================================================
   LON Design System · dashboard.css
   Capa de TABLERO DE DATOS. Se apila sobre tokens.css + components.css
   y no los modifica. Consume solo la capa semántica de tokens
   (--bg, --surface, --panel, --text, --text-muted, --text-soft, --line,
   --brand, --brand-strong, --brand-fill, --brand-contrast, --ok, --warn,
   --err, --sh-1..3, --r-*, --s-*, --font-body, --font-display).

   Reglas duras heredadas del sistema y respetadas aquí:
   · Arranque SIEMPRE en claro. El oscuro solo con data-theme="dark"
     explícito. Cero prefers-color-scheme como respaldo.
   · Cero borde decorativo de 2px o más. Hairline de 1px separador,
     contorno de 2px solo para foco, 1px en campos de formulario.
   · Cero texto blanco sobre fondo claro o beige.
   · Cero radio de píldora en cajas con texto de dos o más líneas.
   · Etiquetas y distintivos con la primera letra en mayúscula,
     nunca en versales (sin text-transform: uppercase).
   · Elevación al pasar el ratón: 2px de ascenso y sombra, nada más.

   Hexadecimales propios: solo en dos sitios, los dos justificados en su
   comentario. (1) La paleta de series de las gráficas, sección 9.
   (2) Las seis tintas de estado de la sección 0, porque los tokens
   --ok/--warn/--err del sistema son colores de relleno y como TEXTO no
   llegan a 4,5:1. Fuera de esos dos bloques, cero hexes.
   ============================================================ */

/* ============================================================
   0 · Variables de la capa
   ============================================================ */
:root {
  --db-side-w: 280px;          /* ancho del menú lateral */
  --db-topbar-h: 68px;         /* alto de la barra superior */
  --db-anchors-h: 56px;        /* alto de la barra de anclas */
  --db-gutter: clamp(20px, 2.4vw, 34px);

  /* Tintas de estado legibles sobre superficies claras.
     Los tokens --ok/--warn/--err del sistema son colores de RELLENO
     (barras, puntos, medidores). Como TEXTO no llegan a 4,5:1 sobre
     crema, así que la capa define su versión entintada. */
  --db-ok-ink: #3D5530;
  --db-warn-ink: #7A4D08;
  --db-err-ink: #7E2B39;
  --db-neutral-ink: var(--text-muted);

  /* Fondos suaves de los distintivos: el color de estado diluido en la
     superficie, nunca una banda de color al lado de la caja. */
  --db-ok-bg: color-mix(in srgb, var(--ok) 18%, var(--surface));
  --db-warn-bg: color-mix(in srgb, var(--warn) 20%, var(--surface));
  --db-err-bg: color-mix(in srgb, var(--err) 15%, var(--surface));
  --db-neutral-bg: var(--panel);

  /* Tinta que va ENCIMA del relleno de marca. Sigue al token del sistema en
     los dos temas, por decisión del CEO (2026-08-08).

     Queda constancia del dato que se le puso delante para decidir: en oscuro
     el relleno de marca es el naranja del logo, un color claro, y la letra
     blanca encima da 2,70:1, por debajo del 4,5:1 que pide la norma de
     accesibilidad. Se midió y se le presentó; eligió mantener el blanco por
     coherencia con su decisión del 2026-07-13. Es una decisión suya, tomada
     con la cifra a la vista, no un descuido. No se reabre. */
  --db-on-brand: var(--brand-contrast);

  --db-row-hover: color-mix(in srgb, var(--panel) 62%, var(--surface));
  --db-row-sel: color-mix(in srgb, var(--brand) 10%, var(--surface));
  --db-track: color-mix(in srgb, var(--line) 70%, var(--surface));
  --db-scrim: rgba(28, 20, 16, .48);
}

:root[data-theme="dark"] {
  --db-ok-ink: #A9CE8E;
  --db-warn-ink: #F0C173;
  --db-err-ink: #F0949F;
  --db-neutral-ink: var(--text-muted);
  /* Mismo token que en claro: el CEO mantiene la letra blanca sobre el
     relleno de marca también en oscuro (ver la nota de arriba). */
  --db-on-brand: var(--brand-contrast);

  --db-ok-bg: color-mix(in srgb, var(--ok) 26%, var(--surface));
  --db-warn-bg: color-mix(in srgb, var(--warn) 22%, var(--surface));
  --db-err-bg: color-mix(in srgb, var(--err) 30%, var(--surface));
  --db-neutral-bg: var(--panel);

  --db-row-hover: color-mix(in srgb, var(--panel) 70%, var(--surface));
  --db-row-sel: color-mix(in srgb, var(--brand) 16%, var(--surface));
  --db-track: color-mix(in srgb, var(--line) 90%, var(--surface));
  --db-scrim: rgba(0, 0, 0, .62);
}

/* ============================================================
   1 · db-shell · armazón del tablero
   Menú lateral de borde superior a borde inferior, con la marca DENTRO,
   y contenido que ocupa el resto desde el primer píxel. No es una
   portada con un menú debajo.
   ============================================================ */
.db-shell {
  display: grid;
  grid-template-columns: var(--db-side-w) minmax(0, 1fr);
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  background: var(--bg);
}

/* ---- 1.1 · db-side · menú lateral fijo con grupos plegables ---- */
.db-side {
  grid-column: 1;
  display: flex; flex-direction: column;
  min-height: 0; overflow-y: auto;
  background: var(--panel);
  box-shadow: 1px 0 0 var(--line);
  scrollbar-width: thin;
}
.db-side__brand {
  display: flex; align-items: center; gap: 12px;
  padding: 20px var(--s-3) 18px;
  color: var(--brand);
  text-decoration: none;
  flex: 0 0 auto;
}
.db-side__brand svg { height: 24px; width: auto; flex: 0 0 auto; }
.db-side__brand span {
  font: 600 13px/1.2 var(--font-body);
  color: var(--text);
  letter-spacing: .01em;
}
.db-side__nav { padding: 4px 10px 10px; display: grid; gap: 2px; }
.db-side__group { display: grid; }
.db-side__group > summary {
  display: flex; align-items: center; gap: 10px;
  list-style: none; cursor: pointer;
  font: 600 11.5px/1 var(--font-body);
  letter-spacing: .06em;
  color: var(--text-muted);
  padding: 14px 12px 8px;
}
.db-side__group > summary::-webkit-details-marker { display: none; }
.db-side__group > summary svg {
  width: 13px; height: 13px; margin-left: auto;
  transition: transform .18s ease;
}
.db-side__group[open] > summary svg { transform: rotate(180deg); }
.db-side__link {
  display: flex; align-items: center; gap: 11px;
  font: 500 14px/1.3 var(--font-body);
  color: var(--text-muted);
  text-decoration: none;
  padding: 10px 12px;
  border-radius: var(--r-sm);
  background: transparent;
  border: 0; cursor: pointer; width: 100%; text-align: left;
}
.db-side__link svg { width: 17px; height: 17px; flex: 0 0 auto; }
.db-side__link:hover { background: var(--surface); color: var(--text); }
/* Solo la entrada ACTIVA se colorea. Un fondo permanente en varias
   entradas se lee como si hubiera tres secciones abiertas a la vez. */
.db-side__link[aria-current="page"],
.db-side__link.is-active {
  background: var(--brand-fill);
  color: var(--db-on-brand);
}
.db-side__link[aria-current="page"]:hover,
.db-side__link.is-active:hover {
  background: var(--brand-fill-strong);
  color: var(--db-on-brand);
}
.db-side__count {
  margin-left: auto;
  font: 600 11.5px/1 var(--font-body);
  font-variant-numeric: tabular-nums;
  color: inherit;
}
.db-side__foot {
  margin-top: auto;
  padding: 14px var(--s-3) 18px;
  border-top: 1px solid var(--line);
  display: grid; gap: 10px;
}

/* ---- 1.2 · db-main · contenido con scroll propio ---- */
.db-main {
  grid-column: 2;
  min-width: 0; min-height: 0;
  overflow-y: auto;
  display: flex; flex-direction: column;
  background: var(--bg);
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) { .db-main { scroll-behavior: auto; } }
.db-main__body {
  padding: var(--s-4) var(--db-gutter) var(--s-7);
  display: grid; gap: var(--s-5);
  align-content: start;
  min-width: 0;
}

/* ---- 1.3 · db-topbar · título, migas y acciones ---- */
.db-topbar {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center; gap: var(--s-3);
  min-height: var(--db-topbar-h);
  padding: 12px var(--db-gutter);
  background: var(--bg);
  box-shadow: 0 1px 0 var(--line);
  flex-wrap: nowrap;
}
.db-topbar__txt { display: grid; gap: 3px; min-width: 0; }
.db-topbar__crumbs {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  font: 500 12px/1.2 var(--font-body);
  color: var(--text-muted);
  margin: 0; padding: 0; list-style: none;
}
.db-topbar__crumbs a { color: var(--text-muted); text-decoration: none; }
.db-topbar__crumbs a:hover { color: var(--text); text-decoration: underline; text-underline-offset: 3px; }
.db-topbar__crumbs li + li::before { content: "/"; margin-right: 7px; color: var(--text-muted); }
.db-topbar h1 {
  font: 600 clamp(18px, 2.1vw, 24px)/1.2 var(--font-display);
  margin: 0; letter-spacing: -0.005em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.db-topbar__acts { margin-left: auto; display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
.db-burger { display: none; }

/* ---- 1.4 · db-anchors · barra de anclas de UNA sola fila ---- */
.db-anchors {
  position: sticky; top: var(--db-topbar-h); z-index: 35;
  display: flex; align-items: center; gap: 8px;
  min-height: var(--db-anchors-h);
  padding: 9px var(--db-gutter);
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  box-shadow: 0 1px 0 var(--line);
  flex-wrap: nowrap;                 /* nunca salta a segunda fila */
  overflow-x: auto; overflow-y: hidden;
  scrollbar-width: none;             /* barra de desplazamiento oculta */
  -ms-overflow-style: none;
  overscroll-behavior-x: contain;
}
@supports not (backdrop-filter: blur(1px)) { .db-anchors { background: var(--bg); } }
.db-anchors::-webkit-scrollbar { display: none; }
.db-anchors a {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: 8px;
  font: 500 13px/1 var(--font-body);
  color: var(--text-muted); text-decoration: none;
  padding: 10px 14px; border-radius: var(--r-pill);
  background: var(--panel);
  white-space: nowrap;
}
.db-anchors a:hover { background: var(--surface); color: var(--text); box-shadow: var(--sh-1); }
.db-anchors a[aria-current="true"] { background: var(--brand-fill); color: var(--db-on-brand); }
.db-anchors a .db-anchors__n {
  font: 600 11.5px/1 var(--font-body);
  font-variant-numeric: tabular-nums;
  padding: 3px 7px; border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--text) 10%, transparent);
  color: inherit;
}
.db-anchors a[aria-current="true"] .db-anchors__n {
  background: color-mix(in srgb, var(--db-on-brand) 26%, transparent);
}
/* El destino no queda debajo de las barras fijas. */
.db-anchor-target { scroll-margin-top: calc(var(--db-topbar-h) + var(--db-anchors-h) + 12px); }
@media (prefers-reduced-motion: no-preference) {
  .db-anchors a, .db-side__link { transition: transform .16s ease, background-color .16s ease, box-shadow .16s ease; }
  .db-anchors a:hover { transform: translateY(-2px); }
}

/* ---- 1.5 · db-section · bloque de contenido ---- */
.db-section { display: grid; gap: var(--s-3); min-width: 0; }
.db-section__head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--s-3); flex-wrap: wrap;
}
.db-section__head h2 {
  font: 600 clamp(17px, 1.9vw, 21px)/1.25 var(--font-display);
  margin: 0; letter-spacing: -0.005em;
}
.db-section__head p { font: 400 13.5px/1.55 var(--font-body); color: var(--text-muted); margin: 0; max-width: 72ch; }

/* ---- 1.6 · Móvil: el lateral pasa a menú de hamburguesa ---- */
@media (max-width: 1000px) {
  .db-shell { grid-template-columns: minmax(0, 1fr); }
  .db-side {
    position: fixed; inset: 0 auto 0 0; z-index: 90;
    width: min(var(--db-side-w), 84vw);
    transform: translateX(-102%);
    box-shadow: var(--sh-3);
  }
  .db-side.is-open { transform: translateX(0); }
  @media (prefers-reduced-motion: no-preference) {
    .db-side { transition: transform .22s ease; }
  }
  .db-main { grid-column: 1; }
  .db-burger {
    display: inline-flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; flex: 0 0 auto;
    border: 0; border-radius: 50%; cursor: pointer;
    background: var(--panel); color: var(--text);
  }
  .db-burger svg { width: 19px; height: 19px; }
  .db-burger:hover { background: var(--line); }
  /* La barra superior se queda en UNA sola fila. */
  .db-topbar { flex-wrap: nowrap; gap: 10px; }
  .db-topbar__crumbs { display: none; }
  .db-topbar h1 { font-size: 17px; }
  .db-scrim-side {
    position: fixed; inset: 0; z-index: 85;
    background: var(--db-scrim);
    border: 0; padding: 0; cursor: pointer;
  }
  .db-scrim-side[hidden] { display: none; }
}
@media (min-width: 1001px) { .db-scrim-side { display: none; } }

/* ============================================================
   2 · db-table · tabla de datos
   Cabecera fija, cifras de ancho fijo alineadas a la derecha, fila con
   realce, fila seleccionada, fila desplegable, fila de totales y
   desplazamiento horizontal DENTRO de la caja: la página nunca se
   desplaza a lo ancho.
   ============================================================ */
.db-tablebox {
  background: var(--surface);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-1);
  overflow: hidden;              /* recorta el radio */
  min-width: 0;
}
.db-tablebox__head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-3); flex-wrap: wrap;
  padding: 14px 18px;
  border-bottom: 1px solid var(--line);
}
.db-tablebox__head h3 { font: 600 15px/1.3 var(--font-body); margin: 0; }
.db-tablebox__head .db-actualizado { margin-left: auto; }
.db-tablebox__scroll {
  overflow: auto;                /* el desplazamiento vive AQUÍ */
  max-height: min(70vh, 620px);
  overscroll-behavior: contain;
  /* La barra de desplazamiento se deja SIEMPRE a la vista, no solo al pasar el
     ratón. Una tabla con más columnas de las que caben parece completa si la barra
     está escondida: el lector no sabe que hay más y nunca las busca. */
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--text) 30%, transparent) transparent;
  scrollbar-gutter: stable;
}
.db-tablebox__scroll::-webkit-scrollbar { width: 11px; height: 11px; }
.db-tablebox__scroll::-webkit-scrollbar-track { background: color-mix(in srgb, var(--text) 5%, transparent); }
.db-tablebox__scroll::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--text) 28%, transparent);
  border-radius: 999px;
  border: 3px solid transparent;
  background-clip: content-box;
}
.db-tablebox__scroll::-webkit-scrollbar-thumb:hover { background: color-mix(in srgb, var(--text) 45%, transparent); background-clip: content-box; }
.db-table {
  width: 100%;
  border-collapse: separate; border-spacing: 0;
  font: 400 14px/1.45 var(--font-body);
  color: var(--text);
}
.db-table thead th {
  position: sticky; top: 0; z-index: 2;   /* cabecera fija al hacer scroll */
  background: var(--panel);
  font: 600 12px/1.3 var(--font-body);
  color: var(--text-muted);
  text-align: left;
  letter-spacing: .02em;
  padding: 12px 16px;
  white-space: nowrap;
  box-shadow: 0 1px 0 var(--line);
}
.db-table tbody td { padding: 13px 16px; border-bottom: 1px solid var(--line); vertical-align: middle; }
.db-table tbody tr:last-child td { border-bottom: 0; }
/* Cifras: alineadas a la derecha y de ancho fijo, para que las columnas
   de números se lean como una columna y no como un texto irregular. */
.db-table .db-num, .db-table th.db-num { text-align: right; font-variant-numeric: tabular-nums; }
.db-table .db-num { font-weight: 500; }
.db-table tbody tr:hover td { background: var(--db-row-hover); }
.db-table tbody tr[aria-selected="true"] td,
.db-table tbody tr.is-sel td { background: var(--db-row-sel); }
.db-table tbody tr.is-total td {
  background: var(--panel);
  font-weight: 600;
  border-top: 1px solid var(--line);
  border-bottom: 0;
}
/* Primera columna anclada al desplazar a lo ancho.

   OJO al relleno: la regla general de arriba da `padding: 13px 16px` a las celdas
   `td`, pero esta primera columna se escribe como celda de cabecera de fila (`th`),
   que NO entra en esa regla. Sin repetirlo aquí, el nombre queda pegado al borde
   izquierdo, y como esta celda lleva su propio fondo, el pegote se ve muchísimo.
   Es el mismo fallo en los cuatro tableros que usan tablas ancladas. */
.db-table--anclada tbody th[scope="row"],
.db-table--anclada thead th:first-child {
  position: sticky; left: 0; z-index: 1;
  background: var(--surface);
  text-align: left; font-weight: 500;
  padding: 13px 16px;
  box-shadow: 1px 0 0 var(--line);
}
/* Y un ancho mínimo por columna: si no, con muchas columnas el navegador las
   aplasta hasta que caben, la tabla nunca desborda y la barra de desplazamiento
   no llega a aparecer. El lector cree que están todas. */
.db-table thead th, .db-table tbody td { min-width: 112px; }
.db-table--anclada tbody th[scope="row"],
.db-table--anclada thead th:first-child { min-width: 190px; max-width: 260px; }
.db-table--anclada thead th:first-child { z-index: 3; background: var(--panel); }
/* La celda anclada acompaña al estado de SU fila: si no, la fila
   seleccionada y la de totales aparecen con la primera celda en blanco. */
.db-table--anclada tbody tr:hover th[scope="row"] { background: var(--db-row-hover); }
.db-table--anclada tbody tr[aria-selected="true"] th[scope="row"],
.db-table--anclada tbody tr.is-sel th[scope="row"] { background: var(--db-row-sel); }
.db-table--anclada tbody tr.is-total th[scope="row"] { background: var(--panel); }
.db-table--anclada tbody tr.db-table__detalle > td:first-child { background: var(--panel); }

/* Densidades */
.db-table--comoda tbody td, .db-table--comoda tbody th { padding-block: 17px; }
.db-table--compacta tbody td, .db-table--compacta tbody th { padding-block: 8px; font-size: 13.5px; }
.db-table--compacta thead th { padding-block: 9px; }

/* Fila desplegable */
.db-table__toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: 50%;
  border: 0; cursor: pointer;
  background: var(--panel); color: var(--text);
}
.db-table__toggle:hover { background: var(--line); }
.db-table__toggle svg { width: 14px; height: 14px; transition: transform .18s ease; }
.db-table__toggle[aria-expanded="true"] svg { transform: rotate(180deg); }
.db-table__detalle > td {
  background: var(--panel);
  padding: 16px 18px 18px;
}
.db-table__detalle[hidden] { display: none; }
.db-table__detalle dl {
  margin: 0; display: grid; gap: 10px 26px;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}
.db-table__detalle dt { font: 600 11.5px/1.3 var(--font-body); color: var(--text-muted); margin: 0; }
.db-table__detalle dd { margin: 2px 0 0; font: 400 14px/1.45 var(--font-body); }

/* ---- 2.1 · db-sort · ordenación por columna ---- */
/* SE PUEDE PULSAR, ASI QUE TIENE QUE PARECERLO. Iba sin fondo, sin filete y sin aire:
   en reposo era la cabecera de la tabla y nada mas. Se le da aire y esquina, y al
   pasar el raton una caja suave que confirma que responde. Sin filete a proposito:
   dentro de una tabla, un contorno por columna es ruido. */
.db-sort {
  display: inline-flex; align-items: center; gap: 7px;
  background: none; border: 0; padding: 4px 8px; margin: -4px -8px; cursor: pointer;
  font: inherit; color: inherit;
  border-radius: var(--r-sm, 8px);
}
.db-sort:hover { color: var(--text); background: var(--panel); }
.db-sort svg { width: 13px; height: 13px; opacity: .4; flex: 0 0 auto; }
th[aria-sort="ascending"] .db-sort, th[aria-sort="descending"] .db-sort { color: var(--brand-strong); }
th[aria-sort="ascending"] .db-sort svg, th[aria-sort="descending"] .db-sort svg { opacity: 1; }
th[aria-sort="descending"] .db-sort svg { transform: rotate(180deg); }
[data-theme="dark"] th[aria-sort="ascending"] .db-sort,
[data-theme="dark"] th[aria-sort="descending"] .db-sort { color: var(--brand); }

/* ---- 2.2 · db-empty · estado vacío ---- */
.db-empty {
  display: grid; gap: 12px; justify-items: center; text-align: center;
  padding: clamp(34px, 6vw, 64px) var(--s-4);
  background: var(--surface); border-radius: var(--r-lg);
  color: var(--text-muted);
}
.db-empty__ico {
  width: 54px; height: 54px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--panel); color: var(--text-muted);
}
.db-empty__ico svg { width: 23px; height: 23px; }
.db-empty h3 { font: 600 16px/1.3 var(--font-body); color: var(--text); margin: 0; }
.db-empty p { margin: 0; font: 400 14px/1.55 var(--font-body); max-width: 46ch; }

/* ---- 2.3 · db-loading · esqueleto de carga ---- */
.db-loading { display: grid; gap: 10px; padding: 18px; background: var(--surface); border-radius: var(--r-lg); }
.db-skel {
  height: 14px; border-radius: 7px;
  background: linear-gradient(90deg,
    var(--db-track) 0%,
    color-mix(in srgb, var(--db-track) 55%, var(--surface)) 50%,
    var(--db-track) 100%);
  background-size: 220% 100%;
}
.db-skel--titulo { height: 20px; width: 42%; }
.db-skel--corto { width: 62%; }
.db-skel--medio { width: 84%; }
@media (prefers-reduced-motion: no-preference) {
  .db-skel { animation: db-shimmer 1.4s ease-in-out infinite; }
}
@keyframes db-shimmer { from { background-position: 140% 0; } to { background-position: -40% 0; } }

/* ---- 2.4 · db-error · error con reintento ---- */
.db-error {
  display: flex; align-items: flex-start; gap: 14px; flex-wrap: wrap;
  padding: 18px 20px;
  background: var(--db-err-bg);
  border-radius: var(--r-lg);
  color: var(--db-err-ink);
}
.db-error__ico { flex: 0 0 auto; color: var(--db-err-ink); }
.db-error__ico svg { width: 21px; height: 21px; }
.db-error__txt { display: grid; gap: 4px; min-width: 220px; flex: 1 1 260px; }
.db-error strong { font: 600 14.5px/1.35 var(--font-body); }
.db-error p { margin: 0; font: 400 13.5px/1.55 var(--font-body); color: var(--db-err-ink); opacity: .92; }
.db-error .btn { flex: 0 0 auto; align-self: center; }

/* ---- 2.5 · db-pager · paginación ---- */
.db-pager {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 12px 18px;
  border-top: 1px solid var(--line);
  font: 400 13px/1.4 var(--font-body); color: var(--text-muted);
}
.db-pager__info { font-variant-numeric: tabular-nums; }
.db-pager__nav { margin-left: auto; display: flex; align-items: center; gap: 4px; }
.db-pager__nav button {
  min-width: 34px; height: 34px; padding: 0 10px;
  border: 0; border-radius: var(--r-sm); cursor: pointer;
  background: transparent; color: var(--text);
  font: 500 13.5px/1 var(--font-body); font-variant-numeric: tabular-nums;
  display: inline-flex; align-items: center; justify-content: center;
}
.db-pager__nav button:hover:not(:disabled) { background: var(--panel); }
/* Igual que el filtro: la pagina en la que estas lleva letra clara sobre el relleno
   de marca, y el fondo claro del hover la dejaba en 1,0. */
.db-pager__nav button.is-active:hover:not(:disabled),
.db-pager__nav button[aria-current]:hover:not(:disabled) {
  background: var(--brand-strong); color: var(--brand-contrast); }
.db-pager__nav button[aria-current="page"] { background: var(--brand-fill); color: var(--db-on-brand); }
.db-pager__nav button:disabled { opacity: .38; cursor: default; }
.db-pager__nav svg { width: 15px; height: 15px; }

/* ============================================================
   3 · db-kpi · indicador
   Parte de stat-tile del catálogo: misma superficie, mismo radio,
   misma sombra. Añade variación respecto al periodo anterior y
   minigráfica opcional.
   ============================================================ */
.db-kpi-grid { display: grid; gap: var(--s-3); grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.db-kpi {
  background: var(--surface);
  border-radius: var(--r-xl);
  box-shadow: var(--sh-1);
  padding: 20px var(--s-4) 18px;
  display: grid; gap: 6px; align-content: start;
  position: relative; min-width: 0;
}
.db-kpi__lbl { font: 500 12.5px/1.4 var(--font-body); color: var(--text-muted); margin: 0; }
.db-kpi__num {
  font: 600 clamp(28px, 3vw, 38px)/1.05 var(--font-display);
  letter-spacing: -0.015em;
  font-variant-numeric: tabular-nums;
}
.db-kpi__num small { font-size: .52em; font-weight: 500; color: var(--text-muted); margin-left: 3px; letter-spacing: 0; }
.db-kpi__pie { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 2px; }
.db-kpi__delta {
  display: inline-flex; align-items: center; gap: 5px;
  font: 600 12.5px/1 var(--font-body); font-variant-numeric: tabular-nums;
  padding: 6px 10px; border-radius: var(--r-pill);
  background: var(--db-neutral-bg); color: var(--db-neutral-ink);
}
.db-kpi__delta svg { width: 13px; height: 13px; }
.db-kpi__delta--bien { background: var(--db-ok-bg); color: var(--db-ok-ink); }
.db-kpi__delta--mal { background: var(--db-err-bg); color: var(--db-err-ink); }
.db-kpi__ref { font: 400 12px/1.4 var(--font-body); color: var(--text-muted); }
.db-kpi__spark { margin-top: 8px; display: block; width: 100%; height: 40px; color: var(--brand); overflow: visible; }
.db-kpi__spark path { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.db-kpi__spark .db-kpi__area { fill: color-mix(in srgb, currentColor 16%, transparent); stroke: none; }
.db-kpi__ico {
  position: absolute; top: 16px; right: 16px;
  width: 36px; height: 36px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--panel); color: var(--text-muted);
}
.db-kpi__ico svg { width: 17px; height: 17px; }
/* Destacado: fondo de marca sólido, nunca una banda lateral.

   VA CON LA CLASE BASE DELANTE (`.db-kpi.db-kpi--marca`) Y NO ES UN CAPRICHO. Escrito como
   `.db-kpi--marca` a secas pesa lo mismo que `.db-kpi`, así que basta con que una página
   vuelva a definir la tarjeta base MÁS ABAJO para que el fondo de marca desaparezca. Pasó
   en el tablero de leads: la página define sus propios recuadros pequeños reutilizando el
   mismo nombre de clase, su hoja se carga después, y la tarjeta destacada se quedó BLANCA
   con la letra blanca encima. En pantalla: una tarjeta en blanco entre otras tres, con su
   texto dentro y sin verse. Con la clase base delante, el modificador pesa más que ella y
   ya no puede borrarlo nadie por escribir después. */
.db-kpi.db-kpi--marca { background: var(--brand-fill); }
.db-kpi--marca .db-kpi__num { color: var(--db-on-brand); }
.db-kpi--marca .db-kpi__lbl,
.db-kpi--marca .db-kpi__ref { color: color-mix(in srgb, var(--db-on-brand) 90%, transparent); }
/* EL VELO DE ESTA ETIQUETA ESTABA DEMASIADO CARGADO. Va dentro de la tarjeta destacada,
   que es un bloque del rojo de marca, y se dibuja con un velo BLANCO encima para separarse
   del fondo. Con el velo al 22 % el rojo se aclara tanto que la letra blanca de dentro se
   queda en 3,77, por debajo del minimo de 4,5. Al 10 % la etiqueta se sigue distinguiendo
   del fondo y la letra sube a 4,71. Es el efecto contrario al que uno espera: cuanto mas
   velo, MENOS se lee lo que va encima. */
.db-kpi--marca .db-kpi__delta {
  background: color-mix(in srgb, var(--db-on-brand) 10%, transparent);
  color: var(--db-on-brand);
}
.db-kpi--marca .db-kpi__ico { background: color-mix(in srgb, var(--db-on-brand) 20%, transparent); color: var(--db-on-brand); }
.db-kpi--marca .db-kpi__spark { color: var(--db-on-brand); }

/* ============================================================
   4 · db-meter · barra de progreso y medidor con umbral
   ============================================================ */
.db-meter { display: grid; gap: 7px; min-width: 0; }
.db-meter__top {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  font: 500 13px/1.35 var(--font-body); color: var(--text-muted);
}
.db-meter__val { font: 600 13.5px/1.35 var(--font-body); font-variant-numeric: tabular-nums; color: var(--text); }
.db-meter__track {
  position: relative;
  height: 10px; border-radius: var(--r-pill);
  background: var(--db-track);
  overflow: hidden;
}
.db-meter__fill {
  position: absolute; inset: 0 auto 0 0;
  border-radius: var(--r-pill);
  background: var(--brand-fill);
}
.db-meter--bien .db-meter__fill { background: var(--ok); }
.db-meter--aviso .db-meter__fill { background: var(--warn); }
.db-meter--mal .db-meter__fill { background: var(--err); }
.db-meter--fina .db-meter__track { height: 6px; }
.db-meter--gruesa .db-meter__track { height: 16px; }
/* Marca de umbral: hairline de 1px, no una banda. */
.db-meter__umbral {
  position: absolute; top: -3px; bottom: -3px; width: 1px;
  background: var(--text);
  opacity: .55;
}
.db-meter__leyenda {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  font: 400 12px/1.4 var(--font-body); color: var(--text-muted);
}
.db-meter__leyenda span { display: inline-flex; align-items: center; gap: 6px; }
.db-meter__leyenda i { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }

/* Medidor de segmentos apilados (una barra, varias series) */
.db-meter__track--apilada { display: flex; }
.db-meter__track--apilada > span { height: 100%; display: block; }

/* ============================================================
   5 · db-badge · distintivo de estado (4 naturalezas)
   Primera letra en mayúscula, nunca en versales.
   ============================================================ */
.db-badge {
  display: inline-flex; align-items: center; gap: 7px;
  font: 600 12px/1.2 var(--font-body);
  letter-spacing: .01em;
  padding: 6px 11px;
  border-radius: var(--r-pill);
  background: var(--db-neutral-bg);
  color: var(--db-neutral-ink);
  white-space: nowrap;
}
.db-badge::before {
  content: ""; width: 7px; height: 7px; border-radius: 50%;
  background: currentColor; flex: 0 0 auto; opacity: .85;
}
.db-badge--bien { background: var(--db-ok-bg); color: var(--db-ok-ink); }
.db-badge--aviso { background: var(--db-warn-bg); color: var(--db-warn-ink); }
.db-badge--mal { background: var(--db-err-bg); color: var(--db-err-ink); }
.db-badge--sinpunto::before { display: none; }
.db-badge svg { width: 13px; height: 13px; }
/* Variante con icono en lugar de punto */
.db-badge--ico::before { display: none; }

/* ============================================================
   6 · db-chip-filtro · filtro aplicado con su aspa
   ============================================================ */
.db-chips { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.db-chip-filtro {
  display: inline-flex; align-items: center; gap: 8px;
  font: 500 12.5px/1 var(--font-body);
  color: var(--text);
  background: var(--panel);
  padding: 7px 8px 7px 13px;
  border-radius: var(--r-pill);
  box-shadow: var(--sh-1);
}
.db-chip-filtro__k { color: var(--text-muted); font-weight: 600; }
.db-chip-filtro__x {
  display: inline-grid; place-items: center;
  width: 20px; height: 20px; border-radius: 50%;
  border: 0; cursor: pointer;
  background: color-mix(in srgb, var(--text) 9%, transparent);
  color: var(--text);
}
.db-chip-filtro__x:hover { background: var(--brand-fill); color: var(--db-on-brand); }
.db-chip-filtro__x svg { width: 11px; height: 11px; }
.db-chips__conteo {
  font: 500 12.5px/1 var(--font-body); color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
/* «LIMPIAR TODO» ES UN BOTON, ASI QUE TIENE FORMA DE BOTON.
   Iba sin caja, sin filete y SUBRAYADO. Dos cosas mal en una regla: un boton sin forma no
   se lee como boton, y el subrayado es la señal de un enlace, no de un boton. Ahora lleva
   el filete fino y el aire de los demas, y el subrayado se va. */
.db-chips__limpiar {
  border: 1px solid var(--line); background: none; cursor: pointer;
  font: 600 12.5px/1 var(--font-body); color: var(--brand-strong);
  border-radius: var(--r-pill); padding: 8px 14px;
  transition: background .15s ease, border-color .15s ease;
}
.db-chips__limpiar:hover { background: var(--panel); border-color: var(--text-soft); }
[data-theme="dark"] .db-chips__limpiar { color: var(--brand); }

/* ============================================================
   7 · db-filtros · barra de filtros combinables
   Reutiliza el aspecto de filter-tabs y de tag-pill del catálogo,
   sin las versales.
   ============================================================ */
.db-filtros {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  background: var(--surface);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-1);
  padding: 12px 14px;
}
.db-filtros__grupo { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.db-filtros__lbl { font: 600 11.5px/1 var(--font-body); color: var(--text-muted); margin-right: 2px; }
.db-filtros button.db-filtro {
  border: 0; cursor: pointer;
  font: 600 12.5px/1 var(--font-body); letter-spacing: .01em;
  padding: 10px 14px; border-radius: var(--r-pill);
  background: var(--panel); color: var(--text);
}
/* El raton encima NO borra el estado de elegido. El filtro elegido lleva letra clara
   sobre el relleno de marca, y con el fondo claro del hover se quedaba en 1,27. */
.db-filtros button.db-filtro:hover { background: var(--line); }
.db-filtros button.db-filtro.is-active:hover,
.db-filtros button.db-filtro[aria-pressed="true"]:hover {
  background: var(--brand-strong); color: var(--brand-contrast); }
.db-filtros button.db-filtro[aria-pressed="true"],
.db-filtros button.db-filtro.is-active { background: var(--brand-fill); color: var(--db-on-brand); }
.db-filtros .db-select {
  font: 500 13px/1.2 var(--font-body); color: var(--text);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-sm); padding: 9px 12px; cursor: pointer;
}
.db-filtros__sep { width: 1px; align-self: stretch; background: var(--line); }
.db-filtros .db-search { margin-left: auto; }

/* ---- 7.1 · db-search · buscador ---- */
.db-search { position: relative; display: inline-flex; align-items: center; min-width: 220px; flex: 0 1 320px; }
.db-search svg {
  position: absolute; left: 12px; width: 16px; height: 16px;
  color: var(--text-muted); pointer-events: none;
}
.db-search input {
  width: 100%;
  font: 400 14px/1.3 var(--font-body); color: var(--text);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  padding: 10px 34px 10px 36px;
}
.db-search input::placeholder { color: var(--text-muted); }
.db-search__x {
  position: absolute; right: 8px;
  display: grid; place-items: center;
  width: 22px; height: 22px; border-radius: 50%;
  border: 0; cursor: pointer;
  background: var(--panel); color: var(--text-muted);
}
.db-search__x:hover { background: var(--line); color: var(--text); }
.db-search__x svg { position: static; width: 11px; height: 11px; color: inherit; }

/* ============================================================
   8 · db-chart · envoltorio de gráfica
   ============================================================ */
.db-chart {
  background: var(--surface);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-1);
  padding: 18px 20px 16px;
  display: grid; gap: 14px;
  min-width: 0; position: relative;
}
.db-chart__head { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; flex-wrap: wrap; }
.db-chart__head h3 { font: 600 15px/1.3 var(--font-body); margin: 0; }
.db-chart__head p { margin: 2px 0 0; font: 400 12.5px/1.5 var(--font-body); color: var(--text-muted); }
.db-chart__leyenda {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  font: 500 12.5px/1.3 var(--font-body); color: var(--text-muted);
  margin: 0; padding: 0; list-style: none;
}
.db-chart__leyenda li { display: inline-flex; align-items: center; gap: 7px; }
.db-chart__leyenda i { width: 10px; height: 10px; border-radius: 3px; flex: 0 0 auto; }
.db-chart__leyenda i.db-linea { width: 14px; height: 3px; border-radius: 2px; }
.db-chart__lienzo { width: 100%; height: auto; display: block; overflow: visible; }
/* Ejes y rejilla: hairline, sin peso visual */
.db-eje { stroke: var(--line); stroke-width: 1; }
.db-rejilla { stroke: var(--line); stroke-width: 1; stroke-dasharray: 3 5; }
.db-eje-txt { fill: var(--text-muted); font: 400 11px/1 var(--font-body); font-variant-numeric: tabular-nums; }
.db-eje-titulo { fill: var(--text-muted); font: 600 11.5px/1 var(--font-body); }
.db-serie-linea { fill: none; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.db-serie-area { stroke: none; opacity: .16; }
.db-serie-punto { stroke: var(--surface); stroke-width: 2; }
.db-barra { rx: 4; }
/* Globo de información */
.db-tip {
  position: absolute; z-index: 5;
  min-width: 150px; max-width: 260px;
  background: var(--surface);
  border-radius: var(--r-md);
  box-shadow: var(--sh-3);
  padding: 11px 13px;
  font: 400 12.5px/1.5 var(--font-body); color: var(--text);
  pointer-events: none;
}
.db-tip[hidden] { display: none; }
.db-tip strong { display: block; font: 600 12.5px/1.4 var(--font-body); margin-bottom: 6px; }
.db-tip dl { margin: 0; display: grid; gap: 4px; }
.db-tip .db-tip__fila { display: flex; align-items: center; gap: 8px; justify-content: space-between; }
.db-tip .db-tip__k { display: inline-flex; align-items: center; gap: 7px; color: var(--text-muted); }
.db-tip .db-tip__k i { width: 9px; height: 9px; border-radius: 2px; flex: 0 0 auto; }
.db-tip .db-tip__v { font-weight: 600; font-variant-numeric: tabular-nums; }

/* ============================================================
   9 · Paleta de series
   ÚNICO bloque con hexadecimales nuevos de esta capa.

   Criterios: (a) ocho tonos que se distinguen entre sí por MATIZ, no
   solo por claridad; (b) todos por encima de 3:1 contra el fondo de su
   tema, que es el mínimo del criterio 1.4.11 de la WCAG para objetos
   gráficos; (c) conviven con el rojo de la marca porque la primera
   serie ES el rojo de la marca; (d) el verde queda FUERA del reparto,
   porque en esta capa el verde significa "bien" en distintivos y
   medidores y una serie verde traería esa lectura de regalo; (e) el
   verde de San Fernando (#6F8F5B) y el azul de El Nido (#3D7A8C) no
   aparecen: están reservados a los proyectos.
   ============================================================ */
:root {
  /* 1 · Rojo LON. La serie principal es la marca, sin cambio de tono. */
  --db-s1: #B83E25;
  /* 2 · Ámbar tostado. La familia del arena (--sand #E8A13A) bajada en
         claridad hasta pasar 3:1 sobre la crema; el arena original se
         queda reservado para "aviso". */
  --db-s2: #B06A10;
  /* 3 · Azul acero. El matiz más lejano del territorio cálido de la
         marca, a 220 grados: es el que garantiza que dos series
         contiguas no se confundan en una gráfica de barras. */
  --db-s3: #2E5AA8;
  /* 4 · Vino magenta. Cierra el círculo por el lado frío del rojo, a
         335 grados, sin invadir el rojo de la marca. */
  --db-s4: #9C3462;
  /* 5 · Violeta. Puente entre el azul y el vino; separa las dos series
         frías cuando hay cuatro o más en el mismo lienzo. */
  --db-s5: #63499B;
  /* 6 · Marrón arena. Neutro cálido con cuerpo, hermano del token de
         tinta suave del sistema; sirve para la serie "resto". */
  --db-s6: #7C5637;
  /* 7 · Azul claro. Pareja clara del azul acero, para la novena y la
         décima categoría sin repetir matiz. */
  --db-s7: #3C86BE;
  /* 8 · Grafito. Serie de referencia (periodo anterior, objetivo,
         media): se ve pero no compite con las de color. */
  --db-s8: #5B5560;

  /* Escala secuencial (mapas de calor): una sola familia, la de la
     marca, de la crema al rojo tierra. Seis peldaños de claridad
     regular para que el ojo lea magnitud, no categoría. */
  --db-seq-1: #F7E9E2;
  --db-seq-2: #EFCDBE;
  --db-seq-3: #E3A88F;
  --db-seq-4: #D28062;
  --db-seq-5: #B04E30;
  --db-seq-6: #93321E;
  /* Tinta que toca sobre cada peldaño. La escala invierte al cambiar de
     tema, así que la tinta viaja con el peldaño y no se escribe a mano
     en el marcado: si no, en oscuro se pintaría tinta oscura sobre los
     peldaños oscuros y el número desaparece. */
  --db-seq-1-ink: #141414; --db-seq-2-ink: #141414; --db-seq-3-ink: #141414;
  --db-seq-4-ink: #141414; --db-seq-5-ink: #FFFFFF; --db-seq-6-ink: #FFFFFF;

  /* Escala divergente (desviaciones): azul acero para lo que queda por
     debajo, beige neutro en el cero, rojo de marca para lo que queda
     por encima. El cero se ve porque es el único peldaño sin color. */
  --db-div-n3: #2E5AA8;
  --db-div-n2: #6C8CC4;
  --db-div-n1: #B4C4DE;
  --db-div-0: #EFE7DF;
  --db-div-p1: #E8B6A2;
  --db-div-p2: #D07B5C;
  --db-div-p3: #B83E25;
  --db-div-n3-ink: #FFFFFF; --db-div-n2-ink: #141414; --db-div-n1-ink: #141414;
  --db-div-0-ink: #141414;
  --db-div-p1-ink: #141414; --db-div-p2-ink: #141414; --db-div-p3-ink: #FFFFFF;
}
:root[data-theme="dark"] {
  /* Mismos ocho matices, subidos de claridad para pasar 3:1 sobre el
     fondo #131110. El orden y el significado no cambian: una serie
     conserva su identidad al cambiar de tema. */
  --db-s1: #ED7F55;
  --db-s2: #E4A93F;
  --db-s3: #7BA6EE;
  --db-s4: #E97BA6;
  --db-s5: #AE94E4;
  --db-s6: #C7A183;
  --db-s7: #6FC2E8;
  --db-s8: #ADA6B4;

  --db-seq-1: #3A2119;
  --db-seq-2: #5A2E20;
  --db-seq-3: #7E4128;
  --db-seq-4: #9E5030;
  --db-seq-5: #CE7A4E;
  --db-seq-6: #F0A97E;
  --db-seq-1-ink: #FFFFFF; --db-seq-2-ink: #FFFFFF; --db-seq-3-ink: #FFFFFF;
  --db-seq-4-ink: #FFFFFF; --db-seq-5-ink: #141414; --db-seq-6-ink: #141414;

  --db-div-n3: #7BA6EE;
  --db-div-n2: #5C7FBE;
  --db-div-n1: #3E5A85;
  --db-div-0: #3A3430;
  --db-div-p1: #8A462F;
  --db-div-p2: #C46540;
  --db-div-p3: #ED7F55;
  --db-div-n3-ink: #141414; --db-div-n2-ink: #141414; --db-div-n1-ink: #FFFFFF;
  --db-div-0-ink: #FFFFFF;
  --db-div-p1-ink: #FFFFFF; --db-div-p2-ink: #141414; --db-div-p3-ink: #141414;
}

/* Utilidades de serie: valen para relleno (barras, puntos de leyenda)
   y para trazo (líneas), así el mismo número identifica a la serie en
   cualquier forma. */
.db-f1 { fill: var(--db-s1); } .db-t1 { stroke: var(--db-s1); } .db-b1 { background: var(--db-s1); } .db-c1 { color: var(--db-s1); }
.db-f2 { fill: var(--db-s2); } .db-t2 { stroke: var(--db-s2); } .db-b2 { background: var(--db-s2); } .db-c2 { color: var(--db-s2); }
.db-f3 { fill: var(--db-s3); } .db-t3 { stroke: var(--db-s3); } .db-b3 { background: var(--db-s3); } .db-c3 { color: var(--db-s3); }
.db-f4 { fill: var(--db-s4); } .db-t4 { stroke: var(--db-s4); } .db-b4 { background: var(--db-s4); } .db-c4 { color: var(--db-s4); }
.db-f5 { fill: var(--db-s5); } .db-t5 { stroke: var(--db-s5); } .db-b5 { background: var(--db-s5); } .db-c5 { color: var(--db-s5); }
.db-f6 { fill: var(--db-s6); } .db-t6 { stroke: var(--db-s6); } .db-b6 { background: var(--db-s6); } .db-c6 { color: var(--db-s6); }
.db-f7 { fill: var(--db-s7); } .db-t7 { stroke: var(--db-s7); } .db-b7 { background: var(--db-s7); } .db-c7 { color: var(--db-s7); }
.db-f8 { fill: var(--db-s8); } .db-t8 { stroke: var(--db-s8); } .db-b8 { background: var(--db-s8); } .db-c8 { color: var(--db-s8); }

/* Rampas para muestrarios y mapas de calor */
.db-rampa { display: flex; border-radius: var(--r-sm); overflow: hidden; box-shadow: var(--sh-1); }
.db-rampa > span { flex: 1 1 0; height: 34px; display: block; }
.db-heat { display: grid; gap: 3px; }
.db-heat__fila { display: grid; grid-auto-flow: column; gap: 3px; align-items: center; }
.db-heat__celda {
  height: 30px; border-radius: 4px;
  display: grid; place-items: center;
  font: 600 11.5px/1 var(--font-body); font-variant-numeric: tabular-nums;
}
.db-heat__rot { font: 500 11.5px/1 var(--font-body); color: var(--text-muted); white-space: nowrap; }
/* Cada peldaño trae su tinta: el número se lee en los dos temas sin
   escribir un color en el marcado. */
.db-heat__celda--1 { background: var(--db-seq-1); color: var(--db-seq-1-ink); }
.db-heat__celda--2 { background: var(--db-seq-2); color: var(--db-seq-2-ink); }
.db-heat__celda--3 { background: var(--db-seq-3); color: var(--db-seq-3-ink); }
.db-heat__celda--4 { background: var(--db-seq-4); color: var(--db-seq-4-ink); }
.db-heat__celda--5 { background: var(--db-seq-5); color: var(--db-seq-5-ink); }
.db-heat__celda--6 { background: var(--db-seq-6); color: var(--db-seq-6-ink); }

/* Distintivo sobre la escala divergente, con la misma regla de tinta. */
.db-badge--div-n3 { background: var(--db-div-n3); color: var(--db-div-n3-ink); }
.db-badge--div-n2 { background: var(--db-div-n2); color: var(--db-div-n2-ink); }
.db-badge--div-n1 { background: var(--db-div-n1); color: var(--db-div-n1-ink); }
.db-badge--div-0 { background: var(--db-div-0); color: var(--db-div-0-ink); }
.db-badge--div-p1 { background: var(--db-div-p1); color: var(--db-div-p1-ink); }
.db-badge--div-p2 { background: var(--db-div-p2); color: var(--db-div-p2-ink); }
.db-badge--div-p3 { background: var(--db-div-p3); color: var(--db-div-p3-ink); }

/* ============================================================
   10 · db-drawer · panel lateral deslizante de detalle
   ============================================================ */
.db-drawer {
  position: fixed; inset: 0 0 0 auto; z-index: 95;
  width: min(460px, 92vw);
  background: var(--surface);
  box-shadow: var(--sh-3);
  display: flex; flex-direction: column;
  transform: translateX(102%);
}
.db-drawer.is-open { transform: translateX(0); }
@media (prefers-reduced-motion: no-preference) {
  .db-drawer { transition: transform .24s ease; }
}
.db-drawer__head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 14px;
  padding: 18px 20px 14px;
  border-bottom: 1px solid var(--line);
  flex: 0 0 auto;
}
.db-drawer__head h3 { font: 600 17px/1.25 var(--font-display); margin: 0; }
.db-drawer__head p { margin: 4px 0 0; font: 400 13px/1.5 var(--font-body); color: var(--text-muted); }
.db-drawer__body { padding: 18px 20px 22px; overflow-y: auto; display: grid; gap: var(--s-3); align-content: start; }
.db-drawer__foot {
  margin-top: auto; flex: 0 0 auto;
  padding: 14px 20px 18px;
  border-top: 1px solid var(--line);
  display: flex; gap: 10px; flex-wrap: wrap;
}
.db-cerrar {
  display: inline-grid; place-items: center;
  width: 34px; height: 34px; border-radius: 50%;
  border: 0; cursor: pointer; flex: 0 0 auto;
  background: var(--panel); color: var(--text);
}
.db-cerrar:hover { background: var(--line); }
.db-cerrar svg { width: 15px; height: 15px; }
.db-scrim {
  position: fixed; inset: 0; z-index: 90;
  background: var(--db-scrim);
  border: 0; padding: 0; cursor: pointer;
}
.db-scrim[hidden], .db-drawer[hidden] { display: none; }

/* Lista de pares dato/valor dentro del cajón */
.db-datos { margin: 0; display: grid; gap: 0; }
.db-datos > div {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  padding: 11px 0; border-bottom: 1px solid var(--line);
}
.db-datos > div:last-child { border-bottom: 0; }
.db-datos dt { font: 400 13px/1.4 var(--font-body); color: var(--text-muted); margin: 0; }
.db-datos dd { margin: 0; font: 600 13.5px/1.4 var(--font-body); font-variant-numeric: tabular-nums; text-align: right; }

/* ============================================================
   11 · db-modal · ventana modal
   ============================================================ */
dialog.db-modal {
  border: 0; padding: 0;
  border-radius: var(--r-lg);
  background: var(--surface); color: var(--text);
  box-shadow: var(--sh-3);
  width: min(680px, calc(100vw - 40px));
  max-height: min(84vh, 860px);
}
dialog.db-modal::backdrop { background: var(--db-scrim); }
.db-modal__head {
  position: sticky; top: 0; z-index: 2;
  display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
  padding: 20px 22px 14px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}
.db-modal__head h3 { margin: 0; font: 600 18px/1.25 var(--font-display); }
.db-modal__head p { margin: 4px 0 0; font: 400 13px/1.5 var(--font-body); color: var(--text-muted); }
.db-modal__body { padding: 18px 22px 22px; overflow-y: auto; display: grid; gap: var(--s-3); }
.db-modal__foot {
  display: flex; gap: 10px; flex-wrap: wrap; justify-content: flex-end;
  padding: 14px 22px 20px;
  border-top: 1px solid var(--line);
}

/* ============================================================
   12 · db-aviso · nota destacada
   ============================================================ */
.db-aviso {
  display: flex; align-items: flex-start; gap: 13px;
  padding: 15px 18px;
  border-radius: var(--r-md);          /* nunca píldora: son dos líneas */
  background: var(--db-neutral-bg);
  color: var(--text);
}
.db-aviso__ico { flex: 0 0 auto; margin-top: 1px; color: var(--text-muted); }
.db-aviso__ico svg { width: 19px; height: 19px; }
.db-aviso__txt { display: grid; gap: 3px; min-width: 0; }
.db-aviso strong { font: 600 14px/1.4 var(--font-body); }
.db-aviso p { margin: 0; font: 400 13.5px/1.6 var(--font-body); color: var(--text-muted); max-width: 78ch; }
.db-aviso--bien { background: var(--db-ok-bg); color: var(--db-ok-ink); }
.db-aviso--aviso { background: var(--db-warn-bg); color: var(--db-warn-ink); }
.db-aviso--mal { background: var(--db-err-bg); color: var(--db-err-ink); }
.db-aviso--bien .db-aviso__ico, .db-aviso--aviso .db-aviso__ico, .db-aviso--mal .db-aviso__ico { color: inherit; }
.db-aviso--bien p, .db-aviso--aviso p, .db-aviso--mal p { color: inherit; opacity: .92; }

/* ============================================================
   13 · db-toast · notificación efímera
   ============================================================ */
.db-toasts {
  position: fixed; right: 20px; bottom: 20px; z-index: 100;
  display: grid; gap: 10px; justify-items: end;
  pointer-events: none;
}
.db-toast {
  display: flex; align-items: flex-start; gap: 12px;
  min-width: 260px; max-width: 380px;
  padding: 13px 15px;
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: var(--sh-3);
  color: var(--text);
  pointer-events: auto;
}
.db-toast__ico { flex: 0 0 auto; margin-top: 1px; }
.db-toast__ico svg { width: 18px; height: 18px; }
.db-toast__txt { display: grid; gap: 2px; min-width: 0; }
.db-toast strong { font: 600 13.5px/1.35 var(--font-body); }
.db-toast p { margin: 0; font: 400 13px/1.5 var(--font-body); color: var(--text-muted); }
.db-toast--bien .db-toast__ico { color: var(--db-ok-ink); }
.db-toast--aviso .db-toast__ico { color: var(--db-warn-ink); }
.db-toast--mal .db-toast__ico { color: var(--db-err-ink); }
.db-toast .db-cerrar { width: 26px; height: 26px; margin-left: auto; }
.db-toast .db-cerrar svg { width: 12px; height: 12px; }
@media (prefers-reduced-motion: no-preference) {
  .db-toast { animation: db-entra .22s ease both; }
}
@keyframes db-entra { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* ============================================================
   14 · db-actualizado · marca de última actualización
   ============================================================ */
.db-actualizado {
  display: inline-flex; align-items: center; gap: 7px;
  font: 500 12px/1.2 var(--font-body);
  color: var(--text-muted);
  background: var(--panel);
  padding: 7px 12px;
  border-radius: var(--r-pill);
  white-space: nowrap;
}
.db-actualizado svg { width: 13px; height: 13px; flex: 0 0 auto; }
.db-actualizado time { font-variant-numeric: tabular-nums; }
.db-actualizado--vivo::before {
  content: ""; width: 7px; height: 7px; border-radius: 50%;
  background: var(--ok); flex: 0 0 auto;
}

/* ============================================================
   15 · Rejillas de composición del tablero
   ============================================================ */
.db-grid { display: grid; gap: var(--s-3); min-width: 0; }
.db-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.db-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.db-grid--2-1 { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
@media (max-width: 1180px) { .db-grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 860px) {
  .db-grid--2, .db-grid--3, .db-grid--2-1 { grid-template-columns: minmax(0, 1fr); }
}

/* Panel genérico de la capa (mismo material que db-chart, sin gráfica) */
.db-panel {
  background: var(--surface);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-1);
  padding: 18px 20px;
  display: grid; gap: 14px; align-content: start;
  min-width: 0;
}
.db-panel > h3 { font: 600 15px/1.3 var(--font-body); margin: 0; }

/* ============================================================
   16 · Botones sobre relleno de marca en oscuro
   Aquí vivía una corrección que subía la letra a tinta oscura en el tema
   oscuro, porque el par del sistema (relleno naranja del logo + letra
   blanca) da 2,70:1 y la norma pide 4,5:1.

   RETIRADA el 2026-08-08 por decisión del CEO, tomada con la medición
   delante: mantiene la letra blanca en los dos temas, por coherencia con
   su decisión del 2026-07-13. Los botones heredan del sistema base sin
   que esta capa los toque.

   Se deja escrito para que quien lo mida en el futuro sepa que ya se
   detectó y ya se decidió, y no lo vuelva a "arreglar" por su cuenta.
   ============================================================ */

/* ============================================================
   17 · db-ranking · comparación de magnitudes en fila
   ------------------------------------------------------------
   Sustituye a la gráfica de barras horizontales dibujada en SVG.
   MOTIVO, medido el 2026-08-31: un lienzo SVG con `width:100%` y
   viewBox fijo ESCALA todo lo que hay dentro, letra incluida. Un
   rótulo declarado a 12 px salía a 19 px en pantalla, así que las
   gráficas nunca cuadraban con el tamaño de texto del resto del
   tablero por muy bien declarado que estuviera.

   Escrito en HTML, el texto lo pone el sistema y la comparación
   sigue siendo exacta: el ancho de cada barra es su porcentaje.
   Además se lee con lector de pantalla y se puede copiar.

   Marcado:
     <ol class="db-ranking">
       <li class="db-ranking__fila">
         <span class="db-ranking__lbl">Villas Premium
           <small>San Fernando</small></span>
         <span class="db-ranking__pista">
           <span class="db-ranking__barra" style="width:62%"></span>
         </span>
         <span class="db-ranking__val">148 €</span>
       </li>
     </ol>
   ============================================================ */
.db-ranking {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 14px;
}
.db-ranking__fila {
  display: grid; align-items: center; gap: 14px;
  grid-template-columns: minmax(150px, 26%) 1fr auto;
}
.db-ranking__lbl {
  display: grid; gap: 1px; min-width: 0;
  font: 500 13px/1.35 var(--font-body); color: var(--text);
}
.db-ranking__lbl small { font: 400 11.5px/1.3 var(--font-body); color: var(--text-muted); }
.db-ranking__pista {
  position: relative; display: block; height: 12px;
  border-radius: var(--r-pill); background: var(--db-track);
  overflow: hidden;
}
.db-ranking__barra {
  display: block; height: 100%; border-radius: var(--r-pill);
  background: var(--brand-fill);
  transform-origin: left center;
}
@media (prefers-reduced-motion: no-preference) {
  .db-ranking__barra { animation: db-ranking-entra .7s cubic-bezier(.22, .9, .3, 1) both; }
  @keyframes db-ranking-entra { from { transform: scaleX(0); } to { transform: scaleX(1); } }
}
.db-ranking + .db-chart__leyenda,
.db-columnas + .db-chart__leyenda { margin-top: 14px; }
.db-ranking__val {
  font: 600 13.5px/1.35 var(--font-body); font-variant-numeric: tabular-nums;
  color: var(--text); text-align: right; min-width: 62px;
}
/* Fila apagada: la que sirve de contexto y no es el dato principal. */
.db-ranking__fila--tenue .db-ranking__lbl,
.db-ranking__fila--tenue .db-ranking + .db-chart__leyenda,
.db-columnas + .db-chart__leyenda { margin-top: 14px; }
.db-ranking__val { color: var(--text-muted); }
/* En móvil el rótulo se pone encima y la barra ocupa el ancho. */
@media (max-width: 700px) {
  .db-ranking__fila { grid-template-columns: 1fr auto; row-gap: 7px; }
  .db-ranking__lbl { grid-column: 1 / -1; }
}

/* ============================================================
   18 · db-columnas · comparación de magnitudes en vertical
   ------------------------------------------------------------
   La hermana vertical de db-ranking, y por el mismo motivo: en
   HTML el texto no escala. Cada columna crece hasta su altura
   porcentual dentro de una caja de altura fija.

   Marcado:
     <div class="db-columnas" style="--db-columnas-alto:180px">
       <div class="db-columna">
         <span class="db-columna__val">347</span>
         <span class="db-columna__barra" style="height:96%"></span>
         <span class="db-columna__lbl">Standard<small>San Fernando</small></span>
       </div>
     </div>
   ============================================================ */
.db-columnas {
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  gap: clamp(10px, 2vw, 26px); align-items: end;
}
.db-columna {
  display: grid; gap: 8px; align-content: end; justify-items: center;
  grid-template-rows: auto var(--db-columnas-alto, 170px) auto;
  min-width: 0;
}
.db-columna__val {
  font: 600 13.5px/1 var(--font-body); font-variant-numeric: tabular-nums;
  color: var(--text);
  /* Reserva su línea aunque no lleve texto: si no, la columna sin valor
     sube y la fila de columnas queda a distinta altura. Medido el
     2026-08-31 con las doce semanas de personal en obra. */
  min-height: 1em;
}
.db-columna__barra {
  display: block; width: min(100%, 74px); align-self: end;
  border-radius: var(--r-sm) var(--r-sm) 3px 3px;
  background: var(--brand-fill);
  transform-origin: bottom center;
  min-height: 3px;
}
@media (prefers-reduced-motion: no-preference) {
  .db-columna__barra { animation: db-columna-entra .65s cubic-bezier(.22, .9, .3, 1) both; }
  @keyframes db-columna-entra { from { transform: scaleY(0); } to { transform: scaleY(1); } }
}
.db-columna__lbl {
  display: grid; gap: 1px; text-align: center;
  font: 500 12.5px/1.3 var(--font-body); color: var(--text);
  min-height: 1.3em;   /* misma razón que el valor: reserva su línea */
}
.db-columna__lbl small { font: 400 11.5px/1.3 var(--font-body); color: var(--text-muted); }
/* Columna destacada: la de referencia dentro de una comparación. */
.db-columna--foco .db-columna__val { color: var(--brand-strong); }
/* Línea de base bajo las columnas, del grosor de un filete. */
.db-columnas--base { border-bottom: 1px solid var(--line); padding-bottom: 10px; }

/* ============================================================
   19 · db-lienzo · la ÚNICA gráfica que sigue siendo SVG
   ------------------------------------------------------------
   Una curva de evolución no se dibuja con cajas. Pero el lienzo se
   genera a TAMAÑO REAL (una unidad de dibujo = un píxel de
   pantalla), nunca estirado: así el texto de los ejes mide lo que
   dice medir y cuadra con la tabla de al lado.

   El motor que lo dibuja mide el contenedor y vuelve a dibujar al
   cambiar el ancho. Aquí solo viven las tintas.
   ============================================================ */
.db-lienzo { display: block; width: 100%; height: auto; overflow: visible; }
.db-lienzo .db-rejilla { stroke: var(--line); stroke-width: 1; stroke-dasharray: 2 6; }
.db-lienzo .db-base { stroke: var(--line); stroke-width: 1; }
.db-lienzo .db-eje-txt { fill: var(--text-muted); font-size: 11.5px; font-variant-numeric: tabular-nums; }
.db-lienzo .db-serie { fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.db-lienzo .db-serie-area { stroke: none; opacity: .10; }
.db-lienzo .db-punto { stroke: var(--surface); stroke-width: 2; }
/* Etiqueta pegada al final de la línea: quita la necesidad de leyenda. */
.db-lienzo .db-fin { font-size: 12px; font-weight: 600; }

/* ============================================================
   20 · db-fila · ficha de lista con miniatura
   ------------------------------------------------------------
   La fila que se repite en cualquier panel: una unidad, un
   documento, un movimiento, una consulta. Sustituye al cuadradito
   gris con dos letras dentro, que era invento de una pieza y no
   se parecía a nada de la web.

   El lenguaje viene de `info-chip`, la ficha flotante de la web:
   miniatura REDONDA de 44 px, título de 14 px, apoyo de 12,5 px
   apagado, y a la derecha la acción o el distintivo. Lo único que
   cambia es que aquí no es una píldora suelta sino una fila de
   lista, así que se separa con un filete de un píxel.

   La miniatura admite tres formas, y se elige por lo que haya:
     · foto real de la unidad         -> <img class="db-fila__foto">
     · punto de color del proyecto    -> <span class="db-fila__dot">
     · icono del sistema              -> <span class="db-fila__ico">

   Marcado:
     <div class="db-fila">
       <img class="db-fila__foto" src="..." alt="">
       <span class="db-fila__txt">
         <strong>Villa Premium C-14</strong>
         <span>San Fernando · 129.900 €</span>
       </span>
       <span class="db-fila__acts">
         <span class="db-badge db-badge--aviso">En obra</span>
       </span>
     </div>
   ============================================================ */
.db-lista { display: grid; }
.db-fila {
  display: flex; align-items: center; gap: 14px;
  padding: 12px 0; border-bottom: 1px solid var(--line);
  min-width: 0;
}
.db-fila:last-child { border-bottom: 0; }
.db-fila:first-child { padding-top: 4px; }

.db-fila__foto {
  width: 44px; height: 44px; border-radius: 50%; object-fit: cover;
  flex: 0 0 auto; display: block;
}
.db-fila__ico {
  width: 44px; height: 44px; border-radius: 50%; flex: 0 0 auto;
  display: grid; place-items: center;
  background: var(--panel); color: var(--text-muted);
}
.db-fila__ico svg { width: 19px; height: 19px; }
.db-fila__ico--marca { background: color-mix(in srgb, var(--brand) 14%, var(--surface)); color: var(--brand-strong); }
.db-fila__dot {
  width: 44px; height: 44px; border-radius: 50%; flex: 0 0 auto;
  display: grid; place-items: center; background: var(--panel);
}
.db-fila__dot::before {
  content: ""; width: 11px; height: 11px; border-radius: 50%;
  background: var(--db-fila-dot, var(--brand));
}

.db-fila__txt { display: grid; gap: 2px; min-width: 0; }
.db-fila__txt strong { font: 600 14px/1.3 var(--font-body); }
.db-fila__txt span { font: 400 12.5px/1.4 var(--font-body); color: var(--text-muted); }

.db-fila__acts {
  margin-left: auto; flex: 0 0 auto;
  display: flex; align-items: center; gap: 10px;
}
.db-fila__cuando { font: 400 12.5px/1.4 var(--font-body); color: var(--text-muted); white-space: nowrap; }
/* El círculo de acción de la fila es más pequeño que el de la web: allí
   preside una tarjeta, aquí acompaña a una línea de texto. */
.db-fila .btn-circle { width: 34px; height: 34px; }
.db-fila .btn-circle svg { width: 15px; height: 15px; }
@media (max-width: 560px) {
  .db-fila__acts { gap: 6px; }
  .db-fila__foto, .db-fila__ico, .db-fila__dot { width: 38px; height: 38px; }
}

/* ============================================================
   21 · El botón del sistema NO se estira dentro del tablero
   ------------------------------------------------------------
   POR QUÉ EXISTE (2026-08-31, lo vio el CEO). Un botón del sistema
   metido dentro de un panel salía ocupando TODO el ancho, con la
   pastilla naranja convertida en una barra de lado a lado. No era un
   descuido de una pieza: es cómo funciona una rejilla. Casi todos los
   contenedores de esta capa son `display: grid`, y una rejilla estira
   a sus hijos a lo ancho de la columna, aunque el hijo sea
   `inline-flex` y aunque su contenido mida cuatro palabras.

   Así que el defecto se reproducía SOLO por escribir el marcado bien:
   coger el botón del sistema, ponerlo dentro de un panel del sistema,
   y salía deformado. Un sistema en el que hacer lo correcto da un
   resultado incorrecto no es un sistema, así que la corrección va aquí
   y no en la pieza.

   QUÉ HACE. El botón se queda con su ancho natural y pegado al margen
   izquierdo, que es como se ve en la web. Si alguna vez se quiere de
   lado a lado a propósito (una acción principal en el cajón lateral
   del móvil, por ejemplo), se pide con `db-btn-ancho`.
   ============================================================ */
/* LA LISTA VA POR EL LADO DEL HIJO, NO DEL PADRE, y la primera version de
   esta regla se equivoco de lado. Enumeraba solo el boton, asi que en cuanto
   se puso un distintivo dentro de un panel volvio a pasar lo mismo: la
   pastilla de «Lo proximo» salio de lado a lado. El defecto no es del boton,
   es de TODO lo que tiene ancho propio, asi que se enumera eso. */
:is(.db-panel, .db-section, .db-grid, .db-main__body, .db-drawer__body,
    .db-modal__body, .db-chart, .db-kpi, .db-loading, .db-tablebox)
  > :is(.btn, .btn-circle, .db-badge, .db-chip-filtro, .tag-pill, .db-select, .db-search) {
  justify-self: start;
}
/* El pie del menú lateral es columna flexible, no rejilla: ahí la
   propiedad que manda es otra. */
.db-side__foot > .btn, .db-side__foot > .btn-circle { align-self: start; }

/* La fila de acciones: varios botones seguidos sin que ninguno se estire. */
.db-acciones {
  display: flex; flex-wrap: wrap; gap: 10px; align-items: center;
  justify-self: start;
}

/* La excepción declarada, para cuando SÍ se quiere de lado a lado. */
.db-btn-ancho { justify-self: stretch; align-self: stretch; justify-content: center; }

/* ============================================================
   22 · db-cal · calendario de disponibilidad
   ------------------------------------------------------------
   POR QUÉ EXISTE (2026-08-31). La capa de tablero tenía mapa de calor,
   que pinta INTENSIDAD (más oscuro es más), y no servía para lo que hacía
   falta: un mes donde cada día está en uno de tres ESTADOS que no se
   ordenan de menor a mayor. Alquilada, reservada por el propietario y
   libre no son tres grados de lo mismo, así que la escala secuencial los
   habría mentido.

   Lo pide cualquier pieza de esta marca que hable de ocupación: el uso
   propio del leaseholder, el calendario del alojamiento, la agenda de
   visitas a obra. Por eso va aquí y no dentro de una pieza.

   CÓMO SE USA
     <div class="db-cal">
       <div class="db-cal__sem"><span>L</span>…<span>D</span></div>   cabecera
       <div class="db-cal__dias">
         <span class="db-cal__d db-cal__d--vacio"></span>             relleno
         <span class="db-cal__d db-cal__d--libre">1</span>
         <span class="db-cal__d db-cal__d--alquilado">2</span>
         <span class="db-cal__d db-cal__d--propio">3</span>
         <span class="db-cal__d db-cal__d--pedido">4</span>
       </div>
     </div>
   ============================================================ */
.db-cal { display: grid; gap: 8px; min-width: 0; }
.db-cal__mes { font: 600 13px/1 var(--font-body); color: var(--text-muted); }
/* EL `minmax(0, 1fr)` NO ES UN ADORNO, y costo una ronda de correccion.
   Con `1fr` a secas, cada columna se niega a bajar del tamaño de su
   contenido, y siete columnas cuadradas dentro de una rejilla de tres meses
   suman mas ancho del que hay: el calendario se sale de su columna y se pinta
   ENCIMA del mes de al lado. No da ningun error, no rompe ninguna medida y
   solo se ve mirando la pantalla. El `min-width: 0` de las dos filas es la
   otra mitad del mismo cierre. */
.db-cal__sem, .db-cal__dias {
  display: grid; grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 4px; min-width: 0;
}
.db-cal__sem span {
  font: 600 11px/1 var(--font-body); color: var(--text-soft);
  text-align: center; padding-bottom: 2px;
}
.db-cal__d {
  aspect-ratio: 1; display: grid; place-items: center;
  border-radius: 6px; font: 500 12px/1 var(--font-body);
  font-variant-numeric: tabular-nums;
}
/* Libre es el fondo del panel con un filete: un día sin nada NO grita. */
.db-cal__d--libre { background: transparent; color: var(--text-muted); box-shadow: inset 0 0 0 1px var(--line); }
/* Alquilado es el color de la marca: es el día que da dinero. */
.db-cal__d--alquilado { background: var(--brand-fill); color: var(--brand-contrast); }
/* El propietario en su casa va en neutro sólido, para leerse a la vez
   que el de marca sin competir con él. */
.db-cal__d--propio { background: var(--text); color: var(--surface); }
/* Pedido y sin confirmar: el mismo neutro, solo dibujado. */
.db-cal__d--pedido { background: transparent; color: var(--text); box-shadow: inset 0 0 0 2px var(--text); }
.db-cal__d--vacio { background: transparent; box-shadow: none; }

/* La leyenda, para que los cuatro estados se puedan nombrar. */
.db-cal-leyenda { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; }
.db-cal-leyenda span {
  display: inline-flex; align-items: center; gap: 7px;
  font: 500 12.5px/1.3 var(--font-body); color: var(--text-muted);
}
.db-cal-leyenda i { width: 13px; height: 13px; border-radius: 4px; flex: 0 0 auto; }
.db-cal-leyenda .es-alquilado { background: var(--brand-fill); }
.db-cal-leyenda .es-propio { background: var(--text); }
.db-cal-leyenda .es-pedido { box-shadow: inset 0 0 0 2px var(--text); }
.db-cal-leyenda .es-libre { box-shadow: inset 0 0 0 1px var(--line); }

@media (max-width: 560px) {
  .db-cal__d { font-size: 11px; border-radius: 5px; }
}

/* ============================================================
   23 · db-panel--marca · el panel que destaca sobre los demás
   ------------------------------------------------------------
   POR QUÉ EXISTE (2026-08-31). Un tablón de anuncios necesita que lo
   próximo se vea antes que lo demás, y hasta ahora el sistema solo sabía
   destacar una TARJETA DE CIFRA (`db-kpi--marca`), no un panel entero con
   su título, su texto, sus datos y sus botones.

   VA CON LA CLASE BASE DELANTE (`.db-panel.db-panel--marca`), por la misma
   razón que la tarjeta: escrito a secas pesaría lo mismo que `.db-panel`,
   y bastaría con que una pieza volviera a definir el panel más abajo para
   que el fondo de marca desapareciera y quedara letra clara sobre blanco.
   Ya pasó una vez con la tarjeta, en el tablero de leads.

   Y LOS BOTONES DE DENTRO CAMBIAN DE PIEL, que es la parte que se olvida:
   el botón principal del sistema es relleno de marca, y sobre un fondo de
   marca sería invisible. Aquí se invierte, papel con letra de marca.
   ============================================================ */
.db-panel.db-panel--marca {
  background: var(--brand-fill);
  color: var(--brand-contrast);
  box-shadow: var(--sh-2);
}
.db-panel--marca > h3,
.db-panel--marca .pi-nota,
.db-panel--marca p { color: var(--brand-contrast); }

/* EL ROTULO DEL DATO LLEVA SU COLOR ESCRITO, Y ESA ES LA PARTE QUE FALLABA.
   Bajarle la opacidad no servia de nada: la hoja de la pieza le pone un gris
   apagado (`--text-muted`), que gana sobre el color heredado del panel. Sobre
   el relleno de marca ese gris da 1,56:1 MEDIDO, cuando lo legible empieza en
   4,5:1. O sea: el rotulo estaba practicamente invisible y la comprobacion de
   la opacidad decia que todo iba bien.
   La leccion: medir la PROPIEDAD no es medir el RESULTADO. Lo que hay que
   medir es el contraste que sale en pantalla. */
.db-panel--marca .pi-nota { opacity: .88; }
.db-panel--marca .db-datos .pi-dato__k,
.db-panel--marca .db-datos dt,
.db-panel--marca .db-meter__top {
  color: var(--brand-contrast);
  opacity: .9;
  font-weight: 600;
}

/* Las líneas que separan datos dentro del panel de marca no pueden usar la
   línea gris del sistema: sobre el relleno de marca no se ve. */
.db-panel--marca .db-datos > * { border-color: color-mix(in srgb, var(--brand-contrast) 26%, transparent); }

/* Los botones se invierten: el principal pasa a papel, el secundario a
   contorno sobre el propio relleno. */
.db-panel--marca .btn-primary {
  background: var(--brand-contrast);
  color: var(--brand-fill);
}
.db-panel--marca .btn-primary:hover {
  background: color-mix(in srgb, var(--brand-contrast) 88%, var(--brand-fill));
}
.db-panel--marca .btn-secondary {
  background: transparent;
  color: var(--brand-contrast);
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--brand-contrast) 46%, transparent);
}
.db-panel--marca .btn-secondary:hover {
  background: color-mix(in srgb, var(--brand-contrast) 14%, transparent);
}

/* El distintivo dentro del panel de marca: papel con letra de marca, para
   que no compita con el relleno ni se pierda dentro de él. */
.db-panel--marca .db-badge {
  background: color-mix(in srgb, var(--brand-contrast) 20%, transparent);
  color: var(--brand-contrast);
}
