/* ==========================================================================
   CertiProf OS · Componentes
   ========================================================================== */

/* --------------------------------------------------------------- Botones */
/* Cada variante declara su fondo, su fondo de hover y su sombra de hover como
   variables; la regla base las consume. Así ninguna variante pierde su color al
   pasar el cursor y ninguna necesita su propia regla de :hover.

   El gesto: al pasar el cursor el botón sube UN píxel y apoya una sombra suave
   del color de su propio relleno; al pulsar baja un píxel y la sombra se va.
   Antes subía tres y apoyaba un bloque sólido de 4 px (el botón de Hubstaff):
   en una pantalla de uso continuo, cada botón saltando es ruido. Los valores
   viven en tokens.css para que el login —congelado— pueda apagarlos. */
.btn {
  --btn-bg: var(--surface);
  --btn-bg-hover: var(--surface-2);
  --btn-ink: var(--ink);
  --btn-ink-hover: var(--btn-ink);
  --btn-bd: var(--border-strong);
  --btn-bd-hover: var(--ink-4);
  --btn-shadow-hover: var(--shadow-xs);
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  height: 38px; padding: 0 var(--s4);
  font-size: var(--fs-md); font-weight: 600; line-height: 1;
  color: var(--btn-ink); background: var(--btn-bg);
  border: 1px solid var(--btn-bd); border-radius: var(--r-sm);
  white-space: nowrap; user-select: none;
  transition: background-color var(--t-fast) var(--ease), background-position var(--t-slow) var(--ease),
              border-color var(--t-fast) var(--ease), transform var(--t-fast) var(--ease),
              box-shadow var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.btn:hover {
  background: var(--btn-bg-hover); color: var(--btn-ink-hover); border-color: var(--btn-bd-hover);
  transform: translateY(var(--btn-lift));
  box-shadow: var(--btn-shadow-hover);
}
.btn:active { transform: translateY(var(--btn-press)); box-shadow: none; }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .5; pointer-events: none; }
.btn svg { width: 17px; height: 17px; flex: none; }

/* El azul de marca, plano. Pesa porque es el único botón con color, no porque
   flote: la sombra de hover es su propio azul al 55 %, nunca un gris. `.btn-brand`
   sigue existiendo porque muchas vistas lo piden como llamada principal; es el
   mismo botón. El degradado original solo vive dentro del login. */
.btn-primary,
.btn-brand {
  --btn-bg: var(--primary); --btn-bg-hover: var(--primary-hover);
  --btn-ink: var(--primary-ink); --btn-ink-hover: var(--primary-ink);
  --btn-bd: transparent; --btn-bd-hover: transparent;
  --btn-shadow-hover: 0 6px 14px -6px color-mix(in srgb, var(--primary) 55%, transparent);
}

.btn-soft {
  --btn-bg: var(--primary-soft); --btn-bg-hover: var(--primary-soft-2);
  --btn-ink: var(--primary); --btn-ink-hover: var(--primary);
  --btn-bd: transparent; --btn-bd-hover: transparent;
  --btn-shadow-hover: none;
}

.btn-ghost {
  --btn-bg: transparent; --btn-bg-hover: var(--surface-3);
  --btn-ink: var(--ink-2); --btn-ink-hover: var(--ink);
  --btn-bd: transparent; --btn-bd-hover: transparent;
  --btn-shadow-hover: none;
}

.btn-danger {
  --btn-bg: var(--danger-soft); --btn-bg-hover: var(--danger);
  --btn-ink: var(--danger); --btn-ink-hover: #fff;
  --btn-bd: transparent; --btn-bd-hover: transparent;
  --btn-shadow-hover: 0 6px 14px -6px color-mix(in srgb, var(--danger) 50%, transparent);
}

.btn-success {
  --btn-bg: var(--success-soft); --btn-bg-hover: var(--success);
  --btn-ink: var(--success); --btn-ink-hover: #fff;
  --btn-bd: transparent; --btn-bd-hover: transparent;
  --btn-shadow-hover: 0 6px 14px -6px color-mix(in srgb, var(--success) 50%, transparent);
}

/* El naranja de Certipoo, para las acciones que AÑADEN algo dentro de una
   ficha. Mismo gesto que `.btn-danger` y `.btn-success` —relleno suave en
   reposo, sólido al pasar el cursor—, así que se lee como uno más de la casa y
   no como un botón pegado. */
.btn-orange {
  --btn-bg: var(--orange-soft); --btn-bg-hover: var(--orange-solid);
  --btn-ink: var(--orange); --btn-ink-hover: var(--orange-ink);
  --btn-bd: transparent; --btn-bd-hover: transparent;
  --btn-shadow-hover: 0 6px 14px -6px color-mix(in srgb, var(--orange-solid) 55%, transparent);
}

.btn-sm { height: 32px; padding: 0 var(--s3); font-size: var(--fs-sm); border-radius: var(--r-xs); }
.btn-sm svg { width: 15px; height: 15px; }
.btn-lg { height: 44px; padding: 0 var(--s6); font-size: var(--fs-base); border-radius: var(--r-sm); }
.btn-block { width: 100%; }

.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; flex: none;
  color: var(--ink-2); background: transparent;
  border: 1px solid transparent; border-radius: var(--r-sm);
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.icon-btn:hover { background: var(--surface-3); color: var(--ink); }
.icon-btn:active { transform: translateY(1px); }
.icon-btn svg { width: 19px; height: 19px; }
.icon-btn-sm { width: 30px; height: 30px; }
.icon-btn-sm svg { width: 16px; height: 16px; }
.icon-btn.is-active { background: var(--primary-soft); color: var(--primary); }

/* ---------------------------------------------------------------- Cards */
/* La tarjeta se lee por el escalón de superficie contra el lienzo, su línea de
   1 px y una sombra de UN píxel: lo justo para que se apoye y no flote. En una
   rejilla de veinte tarjetas, veinte sombras grandes son ruido; veinte líneas
   de un píxel son una rejilla. El hover solo oscurece la línea. */
.card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-card);
  transition: box-shadow var(--t) var(--ease), border-color var(--t) var(--ease), transform var(--t) var(--ease);
}
.card-pad { padding: var(--s5); }
.card-hover:hover { border-color: var(--border-strong); box-shadow: var(--shadow-sm); }
.card-lift:hover { transform: translateY(-2px); border-color: var(--border-strong); box-shadow: var(--shadow-md); }

.card-head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s3);
  padding: var(--s4) var(--s5);
  border-bottom: 1px solid var(--border-soft);
}
.card-head h3, .card-head h2 { font-size: var(--fs-base); font-weight: 600; letter-spacing: -.01em; }
.card-head .sub { font-size: var(--fs-xs); color: var(--ink-3); font-weight: 400; margin-top: 2px; }
.card-body { padding: var(--s5); }
.card-body-flush { padding: 0; }
.card-foot {
  padding: var(--s3) var(--s5);
  border-top: 1px solid var(--border-soft);
  background: var(--surface-2);
  border-radius: 0 0 var(--r-lg) var(--r-lg);
}

/* Tarjeta con acento de marca en el borde superior: una línea de 2 px en azul
   sólido. Es un señalador, no un adorno. */
.card-accent::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: var(--primary);
  border-radius: var(--r-lg) var(--r-lg) 0 0;
}

/* --------------------------------------------------------------- Badges */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px;
  font-size: var(--fs-2xs); font-weight: 600; line-height: 1.5;
  letter-spacing: .01em; white-space: nowrap;
  border-radius: var(--r-full);
  background: var(--neutral-soft); color: var(--ink-2);
}
.badge svg { width: 12px; height: 12px; flex: none; }
.badge-dot::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: currentColor; flex: none;
}
.badge-success { background: var(--success-soft); color: var(--success); }
.badge-warning { background: var(--warning-soft); color: var(--warning); }
.badge-danger  { background: var(--danger-soft);  color: var(--danger); }
.badge-info    { background: var(--info-soft);    color: var(--info); }
.badge-primary { background: var(--primary-soft); color: var(--primary); }
.badge-accent  { background: var(--accent-soft);  color: var(--accent); }
.badge-outline { background: transparent; border: 1px solid var(--border-strong); color: var(--ink-3); }
.badge-lg { padding: 5px 12px; font-size: var(--fs-xs); }

/* La etiqueta de una plataforma de venta: su logo pequeño y su nombre
   (UI.plataforma). Juan, 22-sep-2026: el logo en vez del punto de color, en
   toda la plataforma. La pastilla es neutra a propósito: el color ya lo pone
   el logo. */
.src-chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 9px 2px 7px;
  font-size: var(--fs-xs); font-weight: 600; line-height: 1.5; color: var(--ink-2);
  white-space: nowrap; vertical-align: middle;
  background: var(--surface-2); border: 1px solid var(--border-soft); border-radius: var(--r-full);
}
.src-logo { display: block; flex: none; }

/* -------------------------------------------------------------- Avatars */
/* Fondo plano teñido con el color del equipo e iniciales en ese mismo color
   (lo inyecta UI.avatar). Antes cada avatar era un degradado de dos tintas: en
   un directorio de 60 personas eso son 60 focos de color compitiendo. */
.avatar {
  position: relative; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px;
  font-family: var(--font-display);
  font-size: var(--fs-sm); font-weight: 600; letter-spacing: .01em;
  color: var(--ink-2); background: var(--surface-3);
  border-radius: var(--r-full);
  overflow: hidden; user-select: none;
}
/* La foto se monta ENCIMA de las iniciales, no en su lugar: si la URL firmada
   caduca, `onerror` quita el <img> y debajo siguen estando las iniciales. */
.avatar img {
  position: absolute; inset: 0; z-index: 1;
  width: 100%; height: 100%; object-fit: cover;
}
.avatar-xs { width: 24px; height: 24px; font-size: var(--fs-3xs); }
.avatar-sm { width: 30px; height: 30px; font-size: var(--fs-2xs); }
.avatar-lg { width: 52px; height: 52px; font-size: var(--fs-lg); }
.avatar-xl { width: 84px; height: 84px; font-size: var(--fs-2xl); }
.avatar-2xl { width: 112px; height: 112px; font-size: var(--fs-3xl); }
.avatar-ring { box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--primary-soft-2); }

.avatar-status::after {
  content: ""; position: absolute; right: -1px; bottom: -1px;
  width: 11px; height: 11px; border-radius: 50%;
  border: 2px solid var(--surface); background: var(--ink-4);
}
.avatar-status[data-status="online"]::after  { background: var(--success); }
.avatar-status[data-status="away"]::after    { background: var(--warning); }
.avatar-status[data-status="offline"]::after { background: var(--ink-4); }

.avatar-stack { display: flex; align-items: center; }
.avatar-stack .avatar { margin-left: -9px; box-shadow: 0 0 0 2px var(--surface); }
.avatar-stack .avatar:first-child { margin-left: 0; }
.avatar-more {
  background: var(--surface-3); color: var(--ink-3);
  font-weight: 600; font-size: var(--fs-2xs);
}

/* --------------------------------------------------------------- Inputs */
.field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.field > label, .label {
  font-size: var(--fs-xs); font-weight: 600; color: var(--ink-2);
  letter-spacing: .01em;
}
.field .hint { font-size: var(--fs-xs); color: var(--ink-4); }
.field .err { font-size: var(--fs-xs); color: var(--danger); font-weight: 500; }
.req::after { content: " *"; color: var(--danger); }

.input, .select, .textarea {
  width: 100%; min-width: 0;
  height: 40px; padding: 0 var(--s3);
  /* `normal` y no el line-height heredado del body (1.55): con altura fija,
     un select hereda esa línea alta y el navegador pinta el texto por encima
     del centro — se veía en todos los desplegables. Con `normal`, el control
     de una línea se centra solo. El textarea lo repone abajo. */
  line-height: normal;
  font-size: var(--fs-md); color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.textarea { height: auto; min-height: 92px; padding: var(--s3); line-height: 1.55; resize: vertical; }
.input::placeholder, .textarea::placeholder { color: var(--ink-4); }
.input:hover, .select:hover, .textarea:hover { border-color: var(--ink-4); }
.input:focus, .select:focus, .textarea:focus {
  outline: none; border-color: var(--primary); box-shadow: var(--ring);
}
.input:disabled, .select:disabled, .textarea:disabled {
  background: var(--surface-3); color: var(--ink-4); cursor: not-allowed;
}
.input.is-error, .textarea.is-error, .select.is-error { border-color: var(--danger); }

.select {
  appearance: none; padding-right: 34px; cursor: pointer;
  /* Con `appearance: none` Chrome deja de centrar el texto del select y lo
     pinta ARRIBA, a la altura de su línea — era el «texto un poco arriba» que
     se veía en todos los desplegables. La línea pasa a medir lo que mide el
     control (40 menos los dos bordes) y el texto queda centrado. Los <input>
     no lo necesitan: esos sí centran solos. */
  line-height: 38px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%239aa1b1' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='m6 9 6 6 6-6'/></svg>");
  background-repeat: no-repeat; background-position: right 10px center;
}
[data-theme="dark"] .select {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236e7480' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='m6 9 6 6 6-6'/></svg>");
}

/* La LISTA que abre un <select> la pinta el navegador, y en Windows puede
   seguir el tema del SISTEMA y no el de la página: con la app en oscuro y
   Windows en claro el panel sale blanco, mientras las opciones sí heredan el
   `color` de la página — la tinta casi blanca del tema oscuro. Blanco sobre
   blanco. Dentro de ese panel lo único que el navegador respeta siempre es el
   fondo y la tinta declarados POR OPCIÓN, así que se declaran aquí para todos
   los desplegables de la app, lleven la clase que lleven. En tema claro estos
   tokens valen lo mismo que el panel nativo, y no cambian nada. */
option {
  background-color: var(--surface);
  color: var(--ink);
}

/* ---- El panel del desplegable, con la piel de la casa ----
   `appearance: base-select` (Chromium 135+) le quita al <select> el panel del
   sistema operativo y deja pintar la lista con el CSS de la página: los
   tokens visten superficie, borde, radio y sombra en los dos temas. Donde no
   existe —Firefox, Safari— el bloque entero se ignora y queda el panel nativo
   con los colores por opción de arriba: menos bonito, igual de legible. */
@supports (appearance: base-select) {
  /* Con `!important`, y no es capricho: `.select` y `.fsel select` declaran
     `appearance: none` para matar la flecha nativa en los navegadores sin
     esto, y ambas ganan por especificidad (y la segunda además por orden:
     views.css carga después). Sin la prioridad, el panel propio no se activa
     en NINGÚN select real de la app — pasó el 27-ago: la prueba se hizo con
     un select sin clase y en producción todo siguió con la cara de Windows.
     El `!important` vive solo dentro de este @supports y también blinda
     contra el próximo estilo de select que declare `none` sin acordarse de
     este bloque. */
  select,
  ::picker(select) { appearance: base-select !important; }

  /* El galón que dibuja base-select dentro del botón se apaga: los selects de
     la casa ya traen el suyo (.select por fondo, .fsel por svg) y dos flechas
     en el mismo botón se leen como un control roto. */
  select::picker-icon { display: none; }

  ::picker(select) {
    background: var(--surface);
    color: var(--ink);
    border: 1px solid var(--border);
    border-radius: var(--r-md);
    box-shadow: var(--shadow-lg);
    padding: var(--s1);
    margin-top: 4px;
    transition: opacity var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
  }
  @starting-style {
    ::picker(select) { opacity: 0; transform: translateY(-4px); }
  }

  option {
    background-color: transparent;
    padding: 7px 10px;
    border-radius: var(--r-sm);
    font-size: var(--fs-sm);
    cursor: pointer;
  }
  option:hover, option:focus { background-color: var(--primary-soft); }
  option:checked { color: var(--primary); font-weight: 600; }

  /* El galón del .fsel acompaña al panel: mirando arriba mientras está
     abierto, sin animación aparte — la transición ya vive en el svg. */
  .fsel > svg { transition: transform var(--t-fast) var(--ease); }
  .fsel:has(select:open) > svg { transform: rotate(180deg); }
}

/* ---- Campos de fecha ----
   El indicador nativo se apaga: abría el panel del sistema, que ya no se usa.
   El icono propio es decorativo — el campo ENTERO abre el calendario de la
   casa (ui.js), así que no hay una zona de 20px que haya que atinar. */
input[type="date"] { cursor: pointer; }
input[type="date"]::-webkit-calendar-picker-indicator { display: none; }
.input[type="date"] {
  padding-right: 34px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 24 24' fill='none' stroke='%239aa1b1' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect x='3' y='4' width='18' height='17' rx='2'/><path d='M16 2v4M8 2v4M3 10h18'/></svg>");
  background-repeat: no-repeat; background-position: right 10px center;
}
[data-theme="dark"] .input[type="date"] {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 24 24' fill='none' stroke='%236e7480' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect x='3' y='4' width='18' height='17' rx='2'/><path d='M16 2v4M8 2v4M3 10h18'/></svg>");
}

/* ---- Calendario de la casa (UI.datePicker en ui.js) ----
   El panel del <input type="date"> no acepta CSS: o es el del sistema o es
   nuestro. Es nuestro: mismo popover en los dos temas, vía tokens. */
.cal-pop {
  position: fixed; z-index: var(--z-palette);
  width: 252px; padding: var(--s3);
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--border); border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
}
.cal-head { display: flex; align-items: center; gap: var(--s2); margin-bottom: var(--s2); }
.cal-title {
  flex: 1; text-align: center;
  font-size: var(--fs-sm); font-weight: 600; text-transform: capitalize;
}
.cal-nav {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: var(--r-sm);
  color: var(--ink-3); cursor: pointer;
}
.cal-nav:hover { background: var(--surface-3); color: var(--ink); }
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.cal-dow {
  text-align: center; font-size: var(--fs-2xs); color: var(--ink-4);
  padding: 3px 0 5px; font-weight: 600;
}
.cal-day {
  height: 30px; border-radius: var(--r-sm);
  font-size: var(--fs-sm); font-variant-numeric: tabular-nums;
  color: var(--ink-2); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.cal-day:hover { background: var(--primary-soft); color: var(--ink); }
.cal-day.is-out { color: var(--ink-4); opacity: .5; }
.cal-day.is-today { box-shadow: inset 0 0 0 1px var(--primary); }
.cal-day.is-selected { background: var(--primary); color: var(--primary-ink); font-weight: 600; }
.cal-day.is-selected:hover { background: var(--primary-hover); }
.cal-day:disabled { color: var(--ink-4); opacity: .35; cursor: default; }
.cal-day:disabled:hover { background: none; }

.input-icon { position: relative; display: flex; align-items: center; }
.input-icon > svg {
  position: absolute; left: 11px; width: 17px; height: 17px;
  color: var(--ink-4); pointer-events: none;
}
.input-icon .input { padding-left: 36px; }

.check {
  display: inline-flex; align-items: flex-start; gap: var(--s2);
  cursor: pointer; font-size: var(--fs-md); color: var(--ink-2);
}
.check input[type="checkbox"], .check input[type="radio"] {
  appearance: none; flex: none;
  width: 17px; height: 17px; margin-top: 2px;
  border: 1.5px solid var(--border-strong); border-radius: 5px;
  background: var(--surface); cursor: pointer;
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.check input[type="radio"] { border-radius: 50%; }
.check input:checked {
  background: var(--primary) url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'><path d='M20 6 9 17l-5-5'/></svg>") center / 12px no-repeat;
  border-color: var(--primary);
}
.check input[type="radio"]:checked {
  background-image: radial-gradient(circle, #fff 0 3px, transparent 3.5px);
  background-size: auto;
}
.check input:focus-visible { box-shadow: var(--ring); }

.switch {
  position: relative; flex: none;
  width: 40px; height: 23px;
  background: var(--border-strong); border-radius: var(--r-full);
  cursor: pointer; transition: background var(--t) var(--ease);
}
.switch::after {
  content: ""; position: absolute; top: 2.5px; left: 2.5px;
  width: 18px; height: 18px; background: #fff; border-radius: 50%;
  box-shadow: var(--shadow-xs); transition: transform var(--t) var(--ease-out);
}
.switch[aria-checked="true"] { background: var(--primary); }
.switch[aria-checked="true"]::after { transform: translateX(17px); }

/* Segmented control */
.segmented {
  display: inline-flex; padding: 3px; gap: 2px;
  background: var(--surface-3); border-radius: var(--r-sm);
  border: 1px solid var(--border-soft);
}
.segmented button, .segmented a {
  padding: 6px 13px; font-size: var(--fs-sm); font-weight: 600;
  color: var(--ink-3); border-radius: 6px; white-space: nowrap;
  display: inline-flex; align-items: center; gap: 6px;
  text-decoration: none; cursor: pointer;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.segmented button svg, .segmented a svg { width: 15px; height: 15px; }
.segmented button:hover, .segmented a:hover { color: var(--ink); text-decoration: none; }
.segmented button.is-active, .segmented a.is-active {
  background: var(--surface); color: var(--ink); box-shadow: var(--shadow-xs), 0 0 0 1px var(--border);
}

/* ----------------------------------------------------------------- Tabs */
.tabs {
  display: flex; align-items: center; gap: var(--s1);
  border-bottom: 1px solid var(--border);
  overflow-x: auto; scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tab {
  position: relative; display: inline-flex; align-items: center; gap: 7px;
  padding: var(--s3) var(--s4);
  font-size: var(--fs-md); font-weight: 600; color: var(--ink-3);
  white-space: nowrap;
  transition: color var(--t-fast) var(--ease);
}
.tab svg { width: 16px; height: 16px; }
.tab:hover { color: var(--ink); }
.tab.is-active { color: var(--primary); }
.tab.is-active::after {
  content: ""; position: absolute; left: var(--s3); right: var(--s3); bottom: -1px;
  height: 2px; background: var(--primary); border-radius: 2px 2px 0 0;
}
.tab .count {
  padding: 1px 7px; font-size: var(--fs-2xs); font-weight: 700;
  background: var(--surface-3); color: var(--ink-3); border-radius: var(--r-full);
}
.tab.is-active .count { background: var(--primary-soft); color: var(--primary); }

/* --------------------------------------------------------------- Tablas */
.table-wrap {
  width: 100%; overflow-x: auto;
  border-radius: var(--r-lg);
}
.table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: var(--fs-md); }
/* Cabecera en frase normal, no en versalita espaciada: una tabla se lee, y
   doce rótulos en mayúscula compiten con los datos que nombran. */
.table thead th {
  position: sticky; top: 0; z-index: 2;
  padding: 10px var(--s4);
  font-size: var(--fs-xs); font-weight: 600; letter-spacing: 0;
  color: var(--ink-3); text-align: left; white-space: nowrap;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
.table thead th.sortable { cursor: pointer; user-select: none; }
.table thead th.sortable:hover { color: var(--ink); }
.table thead th .sort-ind { display: inline-block; margin-left: 4px; opacity: .55; }
.table tbody td {
  padding: var(--s3) var(--s4);
  border-bottom: 1px solid var(--border-soft);
  vertical-align: middle;
}
.table tbody tr { transition: background var(--t-fast) var(--ease); }
.table tbody tr:hover { background: var(--surface-2); }
.table tbody tr.is-clickable { cursor: pointer; }
.table tbody tr:last-child td { border-bottom: 0; }
.table .num { text-align: right; font-variant-numeric: tabular-nums; }
.table .shrink { width: 1%; white-space: nowrap; }

/* ------------------------------------------------------------- Progreso */
.progress {
  /* `display: block` desde el 5-sep-2026. Es un `<span>`, y un span es inline:
     sobre un elemento inline el navegador IGNORA `width` y `height`, asi que la
     barra colapsaba a nada. No se veia hasta ahora porque en todos los sitios
     donde se usaba era hijo de un flex --y un hijo de flex se convierte en
     bloque solo--; en el Inicio, dentro de un `<div>` normal, desaparecio. */
  display: block;
  position: relative; width: 100%; height: 7px;
  background: var(--surface-3); border-radius: var(--r-full); overflow: hidden;
}
.progress > span {
  display: block; height: 100%; border-radius: var(--r-full);
  background: var(--primary);
  /* Sin `transition: width`: animar el ancho obliga al navegador a recalcular
     la maquetacion en cada fotograma, y aqui ademas nunca llegaba a verse
     --las vistas se repintan enteras, asi que el nodo siempre nace ya con su
     ancho final--. La unica barra que se mueve en sitio es `.jt-fill`, que no
     es esta. */
}
.progress.is-grad > span { background: var(--primary); }
.progress.is-success > span { background: var(--success); }
.progress.is-warning > span { background: var(--warning); }
.progress.is-danger > span  { background: var(--danger); }
.progress-lg { height: 10px; }
.progress-sm { height: 5px; }

.ring { display: block; transform: rotate(-90deg); }
.ring circle { fill: none; stroke-linecap: round; }
.ring .ring-track { stroke: var(--surface-3); }
.ring .ring-fill { transition: stroke-dashoffset var(--t-slow) var(--ease-out); }

/* ==========================================================================
   Cargador
   Indicador único de la plataforma: se usa en cualquier sitio donde antes se
   escribía «Cargando…». Los dos trazos son cian y azul de marca —el degradado
   del logotipo, resuelto en dos tintas planas en vez de una rampa—.
   El color se declara aquí y no en el marcado, para que el tema oscuro pueda
   aclararlo sin tocar el SVG.

   Diseño original: Uiverse.io · fanishah (MIT).
   ========================================================================== */
.loader { width: 96px; height: 96px; flex: none; overflow: visible; }
.loader-lg { width: 128px; height: 128px; }
.loader-sm { width: 44px; height: 44px; }
.loader-xs { width: 20px; height: 20px; vertical-align: -.32em; display: inline-block; }

/* Relleno y trazo van en elementos distintos a propósito: el rectángulo de los
   ojos se rellena, los arcos de la boca se trazan. Si el color se declarase en
   el grupo padre, el rectángulo heredaría también el trazo de 12 px. */
.loader__fill1   { fill: var(--loader-1); }
.loader__stroke1 { stroke: var(--loader-1); }
.loader__fill2   { fill: var(--loader-2); }
.loader__stroke2 { stroke: var(--loader-2); }

.loader__eye1,
.loader__eye2,
.loader__mouth1,
.loader__mouth2 { animation: loader-eye1 3s ease-in-out infinite; }

.loader__eye1,
.loader__eye2 { transform-origin: 64px 64px; }

.loader__eye2 { animation-name: loader-eye2; }
.loader__mouth1 { animation-name: loader-mouth1; }
.loader__mouth2 { animation-name: loader-mouth2; visibility: hidden; }

@keyframes loader-eye1 {
  from { transform: rotate(-260deg) translate(0, -56px); }
  50%, 60% {
    animation-timing-function: cubic-bezier(.17, 0, .58, 1);
    transform: rotate(-40deg) translate(0, -56px) scale(1);
  }
  to { transform: rotate(225deg) translate(0, -56px) scale(.35); }
}

@keyframes loader-eye2 {
  from { transform: rotate(-260deg) translate(0, -56px); }
  50%  { transform: rotate(40deg) translate(0, -56px) rotate(-40deg) scale(1); }
  52.5% { transform: rotate(40deg) translate(0, -56px) rotate(-40deg) scale(1, 0); }
  55%, 70% {
    animation-timing-function: cubic-bezier(0, 0, .28, 1);
    transform: rotate(40deg) translate(0, -56px) rotate(-40deg) scale(1);
  }
  to { transform: rotate(150deg) translate(0, -56px) scale(.4); }
}

@keyframes loader-mouth1 {
  from {
    animation-timing-function: ease-in;
    stroke-dasharray: 0 351.86; stroke-dashoffset: 0;
  }
  25% {
    animation-timing-function: ease-out;
    stroke-dasharray: 175.93 351.86; stroke-dashoffset: 0;
  }
  50% {
    animation-timing-function: steps(1, start);
    stroke-dasharray: 175.93 351.86; stroke-dashoffset: -175.93;
    visibility: visible;
  }
  75%, to { visibility: hidden; }
}

@keyframes loader-mouth2 {
  from { animation-timing-function: steps(1, end); visibility: hidden; }
  50%  { animation-timing-function: ease-in-out; visibility: visible; stroke-dashoffset: 0; }
  to   { stroke-dashoffset: -351.86; }
}

/* Un indicador inmóvil no indica nada, así que con «reducir movimiento» no se
   apaga: se cambia el recorrido por un latido de opacidad, que no desplaza
   nada en pantalla. */
@media (prefers-reduced-motion: reduce) {
  .loader__eye1, .loader__eye2, .loader__mouth1, .loader__mouth2 { animation: none; }
  .loader__mouth1 { stroke-dasharray: 175.93 351.86; visibility: visible; }
  .loader__mouth2 { visibility: hidden; }
  .loader { animation: loader-breathe 1.6s ease-in-out infinite; }
}
@keyframes loader-breathe { 0%, 100% { opacity: 1 } 50% { opacity: .45 } }

/* ==========================================================================
   Interruptor día / noche
   Diseño original: Uiverse.io · Galahhad (MIT).

   Tres cambios respecto al original, todos necesarios:

   1. `--toggle-size` baja de 30 px a 13. Toda la pieza está medida en `em`
      sobre esa variable, así que con 30 px mediría 168 × 75 px y no cabe en
      una barra de 66. Con 13 queda en 73 × 33.
   2. Se omite su bloque `@media (prefers-color-scheme: dark)`, que redefine
      `--bg` y `--fg` en `:root`. Aquí eso pisaría los tokens de la
      plataforma y repintaría media interfaz.
   3. La casilla no se oculta con `display: none` —así no puede recibir foco
      y el control queda fuera del teclado— sino con tamaño cero y opacidad,
      que sí es enfocable. El anillo de foco se pinta sobre el contenedor.
   ========================================================================== */
.theme-switch {
  --toggle-size: 13px;
  --container-width: 5.625em;
  --container-height: 2.5em;
  --container-radius: 6.25em;
  --container-light-bg: #3d7eae;
  --container-night-bg: #1d1f2c;
  --circle-container-diameter: 3.375em;
  --sun-moon-diameter: 2.125em;
  --sun-bg: #ecca2f;
  --moon-bg: #c4c9d1;
  --spot-color: #959db1;
  --circle-container-offset: calc((var(--circle-container-diameter) - var(--container-height)) / 2 * -1);
  --stars-color: #fff;
  --clouds-color: #f3fdff;
  --back-clouds-color: #aacadf;
  /* Las dos curvas venían del componente original y llevaban rebote (el 1.25
     y el 1.17 se pasan del destino y vuelven). Se cambiaron el 4-sep-2026 por
     una salida exponencial: la misma duración y el mismo recorrido, pero el
     sol y la luna frenan como frena algo real en vez de pasarse de largo. El
     resto del interruptor --tamaños, colores, nubes, estrellas-- no se toca. */
  --transition: .5s cubic-bezier(.22, 1, .36, 1);
  --circle-transition: .3s cubic-bezier(.22, 1, .36, 1);
  flex: none;
}
@media (max-width: 640px) { .theme-switch { --toggle-size: 11px; } }

.theme-switch, .theme-switch *, .theme-switch *::before, .theme-switch *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  font-size: var(--toggle-size);
}

.theme-switch__container {
  width: var(--container-width);
  height: var(--container-height);
  background-color: var(--container-light-bg);
  border-radius: var(--container-radius);
  overflow: hidden;
  cursor: pointer;
  box-shadow: 0 -.062em .062em rgba(0, 0, 0, .25), 0 .062em .125em rgba(255, 255, 255, .94);
  transition: var(--transition);
  position: relative;
}
.theme-switch__container::before {
  content: "";
  position: absolute;
  z-index: 1;
  inset: 0;
  box-shadow: 0 .05em .187em rgba(0, 0, 0, .25) inset, 0 .05em .187em rgba(0, 0, 0, .25) inset;
  border-radius: var(--container-radius);
}

.theme-switch__checkbox {
  position: absolute;
  width: 0; height: 0;
  opacity: 0;
  pointer-events: none;
}
.theme-switch__checkbox:focus-visible + .theme-switch__container {
  outline: 2px solid var(--primary);
  outline-offset: 3px;
}

.theme-switch__circle-container {
  width: var(--circle-container-diameter);
  height: var(--circle-container-diameter);
  background-color: rgba(255, 255, 255, .1);
  position: absolute;
  left: var(--circle-container-offset);
  top: var(--circle-container-offset);
  border-radius: var(--container-radius);
  box-shadow: inset 0 0 0 3.375em rgba(255, 255, 255, .1), inset 0 0 0 3.375em rgba(255, 255, 255, .1),
              0 0 0 .625em rgba(255, 255, 255, .1), 0 0 0 1.25em rgba(255, 255, 255, .1);
  display: flex;
  transition: var(--circle-transition);
  pointer-events: none;
}

.theme-switch__sun-moon-container {
  pointer-events: auto;
  position: relative;
  z-index: 2;
  width: var(--sun-moon-diameter);
  height: var(--sun-moon-diameter);
  margin: auto;
  border-radius: var(--container-radius);
  background-color: var(--sun-bg);
  box-shadow: .062em .062em .062em 0 rgba(254, 255, 239, .61) inset, 0 -.062em .062em 0 #a1872a inset;
  filter: drop-shadow(.062em .125em .125em rgba(0, 0, 0, .25)) drop-shadow(0 .062em .125em rgba(0, 0, 0, .25));
  overflow: hidden;
  transition: var(--transition);
}

.theme-switch__moon {
  transform: translateX(100%);
  width: 100%;
  height: 100%;
  background-color: var(--moon-bg);
  border-radius: inherit;
  box-shadow: .062em .062em .062em 0 rgba(254, 255, 239, .61) inset, 0 -.062em .062em 0 #969696 inset;
  transition: var(--transition);
  position: relative;
}

.theme-switch__spot {
  position: absolute;
  top: .75em;
  left: .312em;
  width: .75em;
  height: .75em;
  border-radius: var(--container-radius);
  background-color: var(--spot-color);
  box-shadow: 0 .0312em .062em rgba(0, 0, 0, .25) inset;
}
.theme-switch__spot:nth-of-type(2) { width: .375em; height: .375em; top: .937em; left: 1.375em; }
.theme-switch__spot:nth-last-of-type(3) { width: .25em; height: .25em; top: .312em; left: .812em; }

.theme-switch__clouds {
  width: 1.25em;
  height: 1.25em;
  background-color: var(--clouds-color);
  border-radius: var(--container-radius);
  position: absolute;
  bottom: -.625em;
  left: .312em;
  box-shadow: .937em .312em var(--clouds-color), -.312em -.312em var(--back-clouds-color),
              1.437em .375em var(--clouds-color), .5em -.125em var(--back-clouds-color),
              2.187em 0 var(--clouds-color), 1.25em -.062em var(--back-clouds-color),
              2.937em .312em var(--clouds-color), 2em -.312em var(--back-clouds-color),
              3.625em -.062em var(--clouds-color), 2.625em 0 var(--back-clouds-color),
              4.5em -.312em var(--clouds-color), 3.375em -.437em var(--back-clouds-color),
              4.625em -1.75em 0 .437em var(--clouds-color), 4em -.625em var(--back-clouds-color),
              4.125em -2.125em 0 .437em var(--back-clouds-color);
  transition: var(--transition);
}

.theme-switch__stars-container {
  position: absolute;
  color: var(--stars-color);
  top: -100%;
  left: .312em;
  width: 2.75em;
  height: auto;
  transition: var(--transition);
}

/* ---- Estado nocturno ---- */
.theme-switch__checkbox:checked + .theme-switch__container { background-color: var(--container-night-bg); }
.theme-switch__checkbox:checked + .theme-switch__container .theme-switch__circle-container {
  left: calc(100% - var(--circle-container-offset) - var(--circle-container-diameter));
}
.theme-switch__checkbox:checked + .theme-switch__container .theme-switch__circle-container:hover {
  left: calc(100% - var(--circle-container-offset) - var(--circle-container-diameter) - .187em);
}
.theme-switch__circle-container:hover { left: calc(var(--circle-container-offset) + .187em); }
.theme-switch__checkbox:checked + .theme-switch__container .theme-switch__moon { transform: translate(0); }
.theme-switch__checkbox:checked + .theme-switch__container .theme-switch__clouds { bottom: -4.062em; }
.theme-switch__checkbox:checked + .theme-switch__container .theme-switch__stars-container {
  top: 50%;
  transform: translateY(-50%);
}

/* El interruptor sigue cambiando de estado; lo que se apaga es el viaje. */
@media (prefers-reduced-motion: reduce) {
  .theme-switch__container,
  .theme-switch__circle-container,
  .theme-switch__sun-moon-container,
  .theme-switch__moon,
  .theme-switch__clouds,
  .theme-switch__stars-container { transition: none; }
}

/* Bloque de carga: el cargador centrado con su rótulo. Ocupa el sitio del
   contenido que va a llegar, así la página no salta cuando aparece. */
.loading {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--s4); padding: var(--s9) var(--s5); text-align: center;
  min-height: 240px;
}
.loading .lo-text { font-size: var(--fs-md); font-weight: 500; color: var(--ink-3); }
.loading .lo-hint { font-size: var(--fs-xs); color: var(--ink-4); max-width: 44ch; }
.loading-inline {
  display: inline-flex; flex-direction: row; align-items: center; gap: var(--s2);
  min-height: 0; padding: 0; text-align: left;
}
.loading-inline .lo-text { font-size: inherit; color: var(--ink-3); }

/* Pantalla de arranque: cubre el viewport mientras se resuelve la sesión.
   Vive en index.html para poder pintarse antes de que cargue el JavaScript,
   y se apaga cuando `app.js` marca el documento como listo. */
#boot {
  position: fixed; inset: 0; z-index: var(--z-toast);
  display: grid; place-items: center;
  background: var(--bg);
}
html.is-ready #boot { display: none; }

/* ------------------------------------------------------- Estados vacíos */
.empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--s3); padding: var(--s9) var(--s5); text-align: center;
}
.empty-icon {
  display: grid; place-items: center;
  width: 56px; height: 56px; border-radius: var(--r-xl);
  background: var(--primary-soft); color: var(--primary);
}
.empty-icon svg { width: 27px; height: 27px; }
.empty h4 { font-size: var(--fs-base); }
.empty p { max-width: 380px; font-size: var(--fs-md); color: var(--ink-3); }

/* ------------------------------------------------------------- Dropdown */
.dropdown { position: relative; }
.dropdown-menu {
  position: absolute; z-index: var(--z-sticky);
  min-width: 210px; padding: var(--s2);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
  animation: slide-down var(--t-fast) var(--ease-out) both;
}
.dropdown-menu[data-align="end"] { right: 0; }
.dropdown-menu[data-align="start"] { left: 0; }
.dropdown-menu.is-top { bottom: calc(100% + 6px); }
.dropdown-menu:not(.is-top) { top: calc(100% + 6px); }

.menu-item {
  display: flex; align-items: center; gap: var(--s3);
  width: 100%; padding: 8px 10px;
  font-size: var(--fs-md); color: var(--ink-2); text-align: left;
  border-radius: var(--r-xs);
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.menu-item:hover { background: var(--surface-3); color: var(--ink); text-decoration: none; }
.menu-item svg { width: 17px; height: 17px; flex: none; color: var(--ink-4); }
.menu-item:hover svg { color: var(--primary); }
.menu-item.is-danger { color: var(--danger); }
.menu-item.is-danger svg { color: var(--danger); }
.menu-item.is-danger:hover { background: var(--danger-soft); }
.menu-item .kbd { margin-left: auto; }
.menu-sep { height: 1px; margin: var(--s2) 0; background: var(--border-soft); }
.menu-label {
  padding: 6px 10px 4px;
  font-size: var(--fs-2xs); font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-4);
}

.kbd {
  display: inline-flex; align-items: center; gap: 2px;
  padding: 2px 6px; min-width: 20px; justify-content: center;
  font-family: var(--font-sans); font-size: var(--fs-2xs); font-weight: 600;
  color: var(--ink-3); background: var(--surface-3);
  border: 1px solid var(--border); border-radius: 5px;
}

/* --------------------------------------------------------------- Modales */
.overlay {
  position: fixed; inset: 0; z-index: var(--z-modal);
  display: grid; place-items: center;
  padding: var(--s5);
  background: rgba(13, 16, 32, .38);
  animation: fade-in var(--t-fast) var(--ease) both;
}
[data-theme="dark"] .overlay { background: rgba(0, 0, 0, .6); }

.modal {
  display: flex; flex-direction: column;
  width: 100%; max-width: 560px; max-height: min(88vh, 900px);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-xl);
  overflow: hidden;
  animation: pop var(--t) var(--ease-out) both;
}
.modal-sm { max-width: 420px; }
.modal-lg { max-width: 760px; }
.modal-xl { max-width: 1040px; }
.modal-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s4);
  padding: var(--s5) var(--s5) var(--s4);
  border-bottom: 1px solid var(--border-soft);
}
.modal-head h3 { font-size: var(--fs-lg); }
.modal-head .sub { margin-top: 3px; font-size: var(--fs-sm); color: var(--ink-3); }
.modal-body { padding: var(--s5); overflow-y: auto; flex: 1 1 auto; }
.modal-foot {
  display: flex; align-items: center; justify-content: flex-end; gap: var(--s3);
  padding: var(--s4) var(--s5);
  border-top: 1px solid var(--border-soft);
  background: var(--surface-2);
}
.modal-foot .grow { display: flex; }

/* Drawer lateral (ficha rápida) */
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: var(--z-modal);
  display: flex; flex-direction: column;
  width: min(520px, 100vw);
  background: var(--surface);
  border-left: 1px solid var(--border);
  box-shadow: var(--shadow-xl);
  animation: drawer-in var(--t) var(--ease-out) both;
}
@keyframes drawer-in { from { transform: translateX(100%) } to { transform: none } }

/* --------------------------------------------------------------- Toasts */
.toast-root {
  position: fixed; right: var(--s5); bottom: var(--s5); z-index: var(--z-toast);
  display: flex; flex-direction: column; gap: var(--s3);
  width: min(370px, calc(100vw - var(--s8)));
  pointer-events: none;
}
/* El aviso llevaba una banda de 3 px a la izquierda con el color del tipo.
   Se quitó el 4-sep-2026: el icono ya va teñido de ese mismo color --y es lo
   primero que se mira--, así que la banda repetía la señal y además dejaba el
   texto descolocado respecto al resto de las tarjetas de la casa. Ahora el
   color va en el borde entero, de un píxel. */
.toast {
  display: flex; align-items: flex-start; gap: var(--s3);
  padding: var(--s3) var(--s4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-lg);
  pointer-events: auto;
  animation: toast-in var(--t) var(--ease-out) both;
}
@keyframes toast-in { from { opacity: 0; transform: translateX(20px) scale(.97) } to { opacity: 1; transform: none } }
.toast.is-out { animation: toast-out var(--t-fast) var(--ease) forwards; }
@keyframes toast-out { to { opacity: 0; transform: translateX(20px) scale(.97) } }
.toast-ico { flex: none; margin-top: 1px; }
.toast-ico svg { width: 19px; height: 19px; }
.toast-title { font-size: var(--fs-md); font-weight: 600; }
.toast-msg { font-size: var(--fs-sm); color: var(--ink-3); margin-top: 1px; }
.toast[data-kind="success"] { border-color: var(--success); }
.toast[data-kind="success"] .toast-ico { color: var(--success); }
.toast[data-kind="error"] { border-color: var(--danger); }
.toast[data-kind="error"] .toast-ico { color: var(--danger); }
.toast[data-kind="warning"] { border-color: var(--warning); }
.toast[data-kind="warning"] .toast-ico { color: var(--warning); }
.toast[data-kind="info"] .toast-ico { color: var(--primary); }

/* ------------------------------------------------------------- Tooltips */
[data-tip] { position: relative; }
[data-tip]::after {
  content: attr(data-tip);
  position: absolute; z-index: var(--z-sticky);
  left: 50%; bottom: calc(100% + 7px);
  transform: translateX(-50%) translateY(3px);
  padding: 5px 9px;
  font-size: var(--fs-2xs); font-weight: 500; line-height: 1.4;
  color: var(--ink-invert); background: var(--ink);
  border-radius: var(--r-xs); white-space: nowrap;
  opacity: 0; pointer-events: none;
  transition: opacity var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
[data-tip]:hover::after, [data-tip]:focus-visible::after {
  opacity: 1; transform: translateX(-50%) translateY(0);
}
[data-tip][data-tip-pos="right"]::after {
  left: calc(100% + 7px); bottom: auto; top: 50%;
  transform: translateY(-50%) translateX(-3px);
}
[data-tip][data-tip-pos="right"]:hover::after,
[data-tip][data-tip-pos="right"]:focus-visible::after { transform: translateY(-50%) translateX(0); }

/* Hacia abajo: obligatorio en la barra superior, que está pegada al borde
   del viewport y recortaría cualquier globo colocado por encima. */
[data-tip][data-tip-pos="bottom"]::after,
.topbar [data-tip]::after,
.emp-hero [data-tip]::after {
  top: calc(100% + 8px); bottom: auto;
  transform: translateX(-50%) translateY(-3px);
}
[data-tip][data-tip-pos="bottom"]:hover::after,
[data-tip][data-tip-pos="bottom"]:focus-visible::after,
.topbar [data-tip]:hover::after,
.topbar [data-tip]:focus-visible::after,
.emp-hero [data-tip]:hover::after,
.emp-hero [data-tip]:focus-visible::after { transform: translateX(-50%) translateY(0); }

/* Los controles del extremo derecho anclan el globo a su borde derecho para
   que no se salga de la pantalla. */
[data-tip][data-tip-align="end"]::after {
  left: auto; right: 0; transform: translateY(-3px);
}
[data-tip][data-tip-align="end"]:hover::after,
[data-tip][data-tip-align="end"]:focus-visible::after { transform: translateY(0); }
[data-tip][data-tip-align="start"]::after {
  left: 0; right: auto; transform: translateY(-3px);
}
[data-tip][data-tip-align="start"]:hover::after,
[data-tip][data-tip-align="start"]:focus-visible::after { transform: translateY(0); }

/* El globo nunca debe ser más ancho que la pantalla en móvil */
@media (max-width: 640px) {
  [data-tip]::after { max-width: 60vw; white-space: normal; }
}

/* --------------------------------------------------------------- Charts */
.chart { width: 100%; overflow: visible; }
.chart .grid-line { stroke: var(--grid); stroke-width: 1; }
.chart .axis-text {
  font-family: var(--font-sans); font-size: 11px;
  fill: var(--axis-ink); font-variant-numeric: tabular-nums;
}
.chart .mark-label {
  font-family: var(--font-sans); font-size: 11px; font-weight: 600;
  fill: var(--ink-2);
}
.chart .bar { transition: opacity var(--t-fast) var(--ease); }
.chart .hit { fill: transparent; cursor: pointer; }
.chart .hit:hover + .bar, .chart .bar:hover { opacity: .82; }

.chart-tip {
  position: fixed; z-index: var(--z-toast);
  padding: 8px 11px;
  font-size: var(--fs-xs); line-height: 1.45;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--border); border-radius: var(--r-sm);
  box-shadow: var(--shadow-lg);
  pointer-events: none; white-space: nowrap;
  transform: translate(-50%, -115%);
}
.chart-tip .k { color: var(--ink-3); }
.chart-tip .v { font-weight: 700; font-variant-numeric: tabular-nums; }

.legend { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2) var(--s4); }
.legend-item { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-xs); color: var(--ink-2); }
.legend-swatch { width: 9px; height: 9px; border-radius: 3px; flex: none; }
.legend-swatch.is-line { width: 14px; height: 3px; border-radius: 2px; }

/* --------------------------------------------------------- Stat tiles */
.stat {
  display: flex; flex-direction: column; gap: var(--s2);
  padding: var(--s4) var(--s5);
}
.stat-top { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s3); }
/* Rótulo en frase normal: es el nombre de un dato, no un cartel. La cifra
   —en Outfit y con dígitos tabulares— es lo que manda en la tarjeta. */
.stat-label {
  font-size: var(--fs-sm); font-weight: 500; color: var(--ink-3);
  letter-spacing: 0; text-transform: none;
}
.stat-value {
  margin-top: 2px;
  font-family: var(--font-display);
  font-size: var(--fs-3xl); font-weight: 600; line-height: 1.05;
  letter-spacing: -.025em; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.stat-value .unit { font-size: var(--fs-lg); font-weight: 500; color: var(--ink-3); margin-left: 3px; }
.stat-ico {
  display: grid; place-items: center; flex: none;
  width: 36px; height: 36px; border-radius: var(--r-md);
  background: var(--primary-soft); color: var(--primary);
}
.stat-ico svg { width: 18px; height: 18px; }
.stat-ico[data-tone="teal"]   { background: var(--success-soft); color: var(--success); }
.stat-ico[data-tone="purple"] { background: var(--accent-soft); color: var(--accent); }
.stat-ico[data-tone="amber"]  { background: var(--warning-soft); color: var(--warning); }
.stat-ico[data-tone="danger"] { background: var(--danger-soft); color: var(--danger); }
.stat-ico[data-tone="success"]{ background: var(--success-soft); color: var(--success); }
.stat-ico[data-tone="warning"]{ background: var(--warning-soft); color: var(--warning); }
.stat-ico[data-tone="accent"] { background: var(--accent-soft); color: var(--accent); }
.stat-ico[data-tone="magenta"]{ background: color-mix(in srgb, var(--c4) 12%, transparent); color: var(--c4); }
.stat-ico[data-tone="muted"]  { background: var(--neutral-soft); color: var(--ink-3); }
.stat-delta { display: inline-flex; align-items: center; gap: 3px; font-size: var(--fs-xs); font-weight: 600; font-variant-numeric: tabular-nums; }
.stat-delta svg { width: 13px; height: 13px; }
.stat-delta[data-dir="up"]   { color: var(--success); }
.stat-delta[data-dir="down"] { color: var(--danger); }
.stat-delta[data-dir="flat"] { color: var(--ink-4); }
.stat-foot { font-size: var(--fs-xs); color: var(--ink-4); }

/* ------------------------------------------------------------ Timeline */
.timeline { position: relative; padding-left: 26px; }
.timeline::before {
  content: ""; position: absolute; left: 8px; top: 6px; bottom: 6px;
  width: 2px; background: var(--border);
}
.tl-item { position: relative; padding-bottom: var(--s5); }
.tl-item:last-child { padding-bottom: 0; }
.tl-item::before {
  content: ""; position: absolute; left: -22px; top: 5px;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--surface); border: 2px solid var(--border-strong);
}
.tl-item[data-tone="primary"]::before { border-color: var(--primary); background: var(--primary); }
.tl-item[data-tone="success"]::before { border-color: var(--success); background: var(--success); }
.tl-item[data-tone="warning"]::before { border-color: var(--warning); background: var(--warning); }
.tl-item[data-tone="danger"]::before  { border-color: var(--danger);  background: var(--danger); }

/* -------------------------------------------------------------- Chips */
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  height: 30px; padding: 0 11px;
  font-size: var(--fs-sm); font-weight: 500; color: var(--ink-2);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-full); white-space: nowrap;
  transition: all var(--t-fast) var(--ease);
}
.chip:hover { border-color: var(--border-strong); background: var(--surface-2); }
.chip.is-active { background: var(--primary-soft); border-color: transparent; color: var(--primary); font-weight: 600; }
.chip svg { width: 14px; height: 14px; }
.chip .x { display: grid; place-items: center; width: 15px; height: 15px; border-radius: 50%; margin-right: -4px; }
.chip .x:hover { background: var(--primary-soft-2); }

/* --------------------------------------------------------- Filter bar */
.filters {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s3);
  padding: var(--s3) var(--s4);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-md);
}
.filters .input, .filters .select { height: 34px; font-size: var(--fs-sm); }
.filters .search { width: min(280px, 100%); }

/* --------------------------------------------------------- Definition list */
.dl { display: grid; grid-template-columns: minmax(120px, auto) 1fr; gap: var(--s3) var(--s5); align-items: baseline; }
.dl dt { font-size: var(--fs-xs); font-weight: 600; color: var(--ink-3); }
.dl dd { font-size: var(--fs-md); color: var(--ink); margin: 0; }
@media (max-width: 560px) { .dl { grid-template-columns: 1fr; gap: var(--s1) 0; } .dl dd { margin-bottom: var(--s2); } }

/* --------------------------------------------------------------- Alerts */
.alert {
  display: flex; align-items: flex-start; gap: var(--s3);
  padding: var(--s3) var(--s4);
  font-size: var(--fs-md);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface-2);
}
.alert svg { width: 18px; height: 18px; flex: none; margin-top: 1px; }
.alert-info    { background: var(--info-soft);    border-color: transparent; color: var(--info); }
.alert-success { background: var(--success-soft); border-color: transparent; color: var(--success); }
.alert-warning { background: var(--warning-soft); border-color: transparent; color: var(--warning); }
.alert-danger  { background: var(--danger-soft);  border-color: transparent; color: var(--danger); }
.alert strong { display: block; color: inherit; }
.alert p { color: inherit; opacity: .88; }

/* ==========================================================================
   Consistencia de iconos y espaciado
   Cierra los huecos donde antes no había regla de tamaño y el SVG crecía.
   ========================================================================== */

/* Iconos sueltos dentro de contenedores sin regla propia */
.card-head > svg.ico,
.card-head > .row > svg.ico { width: 18px; height: 18px; color: var(--ink-4); flex: none; }
.punch-box svg.ico { width: 16px; height: 16px; }
.settings-nav a svg.ico,
.settings-nav button svg.ico { width: 17px; height: 17px; }
.doc-viewer svg.ico { width: 15px; height: 15px; vertical-align: -.2em; }
.kpi-mini svg.ico { width: 14px; height: 14px; }
.stat-foot svg.ico { width: 13px; height: 13px; }
.login-feat svg.ico { width: 17px; height: 17px; }
.login-box .badge svg.ico { width: 12px; height: 12px; }

/* Iconos embebidos en texto pequeño: siguen la escala del texto */
.t-2xs svg.ico, .t-3xs svg.ico { width: 13px; height: 13px; vertical-align: -.2em; }
.t-xs svg.ico { width: 14px; height: 14px; vertical-align: -.2em; }
.t-sm svg.ico { width: 15px; height: 15px; vertical-align: -.2em; }
.t-mut-2 svg.ico, .t-mut svg.ico { flex: none; }

/* Insignias y chips: el icono nunca domina la etiqueta */
.badge svg.ico { width: 12px; height: 12px; }
.badge-lg svg.ico { width: 14px; height: 14px; }
.chip svg.ico { width: 14px; height: 14px; }
.tab svg.ico { width: 16px; height: 16px; }
.legend-item svg.ico { width: 13px; height: 13px; }
.menu-item svg.ico { width: 17px; height: 17px; }
.ev-row svg.ico, .feed-item svg.ico, .bday svg.ico { flex: none; }
.doc-meta svg.ico { width: 13px; height: 13px; vertical-align: -.2em; }
.timeline svg.ico { width: 14px; height: 14px; }
.action-item svg.ico { width: 13px; height: 13px; vertical-align: -.15em; }
.dl dd svg.ico { width: 15px; height: 15px; vertical-align: -.2em; }

/* Botones: tamaño ligado al alto del botón */
.btn svg.ico { width: 17px; height: 17px; }
.btn-sm svg.ico { width: 15px; height: 15px; }
.btn-lg svg.ico { width: 18px; height: 18px; }
.icon-btn svg.ico { width: 19px; height: 19px; }
.icon-btn-sm svg.ico { width: 16px; height: 16px; }

/* Ritmo uniforme dentro de una vista: todo bloque de primer nivel separa igual */
.view > .grid + .grid,
.view > .grid + .card,
.view > .card + .grid,
.view > .card + .card { margin-top: var(--s5); }
.view > .filters + .card,
.view > .filters + .grid,
.view > .filters + .kanban,
.view > .filters + .table-wrap { margin-top: var(--s5); }

/* Las columnas apiladas usan el mismo hueco que la rejilla */
.col.gap-5 { gap: var(--s5); }

/* ==========================================================================
   Paginación
   ========================================================================== */
.pager {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: var(--s3);
  padding: var(--s3) var(--s4);
  border-top: 1px solid var(--border-soft);
  background: var(--surface-2);
}
.pager-info { font-size: var(--fs-xs); color: var(--ink-3); font-variant-numeric: tabular-nums; }
.pager-info b { color: var(--ink-2); }
.pager-nav { display: flex; align-items: center; gap: 3px; }
.pager-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  min-width: 32px; height: 32px; padding: 0 9px;
  font-size: var(--fs-sm); font-weight: 600; color: var(--ink-2);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-xs);
  font-variant-numeric: tabular-nums;
  transition: all var(--t-fast) var(--ease);
}
.pager-btn:hover:not(:disabled) { border-color: var(--primary); color: var(--primary); background: var(--primary-soft); }
.pager-btn:disabled { opacity: .4; cursor: not-allowed; }
.pager-btn.is-current {
  background: var(--primary); border-color: transparent; color: var(--primary-ink);
}
.pager-gap { padding: 0 4px; color: var(--ink-4); font-size: var(--fs-sm); }
.pager .select { height: 32px; font-size: var(--fs-sm); width: auto; }
@media (max-width: 560px) {
  .pager { justify-content: center; }
  .pager-size { display: none; }
}

/* Cuando la paginación va bajo una rejilla de tarjetas y no dentro de una card */
.pager-standalone {
  margin-top: var(--s5);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface);
}

/* Las banderas conservan su proporción 3:2 aunque vivan dentro de un icon-btn
   o de un menú, cuyas reglas genéricas de `svg` las cuadrarían. */
.icon-btn svg.flag,
.icon-btn-sm svg.flag,
.menu-item svg.flag,
.theme-opt svg.flag,
.topbar svg.flag { width: 24px; height: 17px; flex: none; }
.menu-item svg.flag { margin-right: 2px; }
.theme-opt svg.flag { width: 30px; height: 21px; }

/* ==========================================================================
   Gráfico de columnas (HTML, no SVG)
   Un viewBox estirado deforma el texto y uno uniforme lo descoloca, así que
   la rejilla, las columnas y las etiquetas son cajas normales.
   ========================================================================== */
.col-chart { --cc-h: 172px; --cc-gutter: 38px; --cc-bw: 34px; width: 100%; }

/* El aire de arriba —para la etiqueta del máximo y para el rótulo del eje, que
   va centrado en la línea superior y asoma media altura por encima— se hace
   con `margin-top`, no con `padding-top`.

   Con relleno no funcionaba: las capas del gráfico (rejilla, barras, puntos)
   están posicionadas en absoluto, y para ellas el bloque contenedor es la caja
   de relleno, así que `inset: 0` volvía a cubrir esos 18px y el aire no existía.
   La etiqueta del máximo terminaba pintada por encima del borde del gráfico.
   Con margen el hueco queda FUERA de la zona de trazado: las capas encajan
   exactamente con ella y la tarjeta crece lo que mide el aire. */
.cc-plot {
  position: relative;
  height: var(--cc-h);
  margin-left: var(--cc-gutter);
  margin-top: 20px;
}

/* Rejilla: 1px sólido, un paso por encima del fondo, siempre recesiva */
.cc-line {
  position: absolute; left: 0; right: 0;
  border-top: 1px solid var(--grid);
  pointer-events: none;
}
/* El cero no es una guía más: es el suelo donde se apoyan las barras. Un paso
   más de presencia que las otras dos y el gráfico deja de flotar. */
.cc-line.is-base { border-top-color: var(--border); }
/* La etiqueta vive en el canalón que `CHART` reserva para ella, medido sobre
   el texto que se va a pintar. El `max-width` es el cinturón: si alguna vez la
   reserva se queda corta, el número se corta con puntos suspensivos dentro del
   gráfico en vez de escaparse por la izquierda y aterrizar fuera de la
   tarjeta, encima del fondo de la página. */
.cc-ylab {
  position: absolute; right: 100%; top: 0;
  transform: translateY(-50%);
  max-width: var(--cc-gutter);
  padding-right: 8px;
  font-size: 11px; line-height: 1; white-space: nowrap;
  color: var(--axis-ink); font-variant-numeric: tabular-nums;
  overflow: hidden; text-overflow: ellipsis;
}

.cc-bars {
  position: absolute; inset: 0;
  display: flex; align-items: flex-end;
}
.cc-col {
  position: relative; flex: 1 1 0; min-width: 0; height: 100%;
  display: flex; flex-direction: column; justify-content: flex-end; align-items: center;
  cursor: default;
}
/* Realce de banda: al pasar el cursor se ilumina la columna ENTERA, no la
   barra. El objetivo de puntería pasa a ser toda la banda —bastante más que
   los 24px de mínimo que pide una diana cómoda— y la lectura del tooltip deja
   de exigir precisión. Va detrás de la barra, no encima. */
.cc-col::before {
  content: ''; position: absolute; inset: 0;
  background: var(--surface-2);
  border-radius: var(--r-sm);
  opacity: 0;
  transition: opacity var(--t-fast) var(--ease);
}
.cc-col:hover::before { opacity: 1; }

/* Extremo de dato redondeado —proporcional al grosor, porque 4px en una barra
   de 72px no se ven y en una de 8px la parten—, base recta.

   El grosor lo fija `--cc-bw` desde JS según cuántas barras hay. El `min(…,
   74%)` es el techo: por ancha que salga la cuenta, al menos una cuarta parte
   de la banda queda como aire y dos barras vecinas nunca se tocan. La
   separación entre columnas es superficie, no un borde. */
.cc-bar {
  position: relative;
  width: min(var(--cc-bw), 74%);
  min-height: 2px;
  border-radius: clamp(3px, calc(var(--cc-bw) * .18), 10px) clamp(3px, calc(var(--cc-bw) * .18), 10px) 0 0;
  background: var(--cc-c, var(--c1));
  /* Degradado mínimo —el mismo tono, un punto más claro arriba— para que la
     barra tenga volumen sin dejar de ser un color plano de la paleta. Si el
     navegador no entiende `color-mix`, esta línea se descarta entera y queda
     el color sólido de arriba: nunca se pierde la barra. */
  background-image: linear-gradient(180deg,
    color-mix(in oklab, var(--cc-c, var(--c1)) 86%, white) 0%,
    var(--cc-c, var(--c1)) 62%);
  /* Solo `filter`. `height` estaba en la lista y era doblemente malo: animar
     la altura recalcula la maquetacion, y no se veia nunca --al redibujar el
     grafico las barras son nodos nuevos, y su entrada ya la hace `cc-rise`
     con `clip-path`, que no toca la maquetacion--. */
  transition: filter var(--t-fast) var(--ease);
  /* Entrada: la barra se revela de abajo arriba. Se hace con `clip-path` y no
     con `scaleY`, que aplastaría el redondeo del extremo en un óvalo durante
     toda la animación. `--i` escalona la entrada por el eje X. */
  animation: cc-rise .55s var(--ease-out) backwards;
  animation-delay: calc(var(--i, 0) * 28ms);
}
@keyframes cc-rise { from { clip-path: inset(100% 0 0 0); } to { clip-path: inset(0 0 0 0); } }
.cc-col:hover .cc-bar { filter: brightness(1.07) saturate(1.06); }
.cc-val {
  position: absolute; bottom: 100%; left: 50%; transform: translateX(-50%);
  margin-bottom: 5px;
  font-size: 11px; font-weight: 600; line-height: 1; white-space: nowrap;
  color: var(--ink-2); font-variant-numeric: tabular-nums;
}
.cc-labels {
  display: flex; margin-left: var(--cc-gutter); margin-top: 7px;
}
.cc-labels > span {
  flex: 1 1 0; min-width: 0;
  text-align: center;
  font-size: 11px; line-height: 1.3; color: var(--axis-ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* En la variante de línea cada rótulo se ancla a su punto —el primero por su
   izquierda y el último por su derecha, para no salirse del gráfico—, en vez
   de repartirse en bandas iguales, que dejaba medio hueco de desfase respecto
   al dato que nombra. */
.cc-labels.is-line { display: block; position: relative; height: 1.4em; }
.cc-labels.is-line > span {
  position: absolute; top: 0;
  flex: none; width: auto; overflow: visible;
  transform: translateX(-50%);
}
.cc-labels.is-line > span:first-child { transform: none; }
.cc-labels.is-line > span:last-child { transform: translateX(-100%); }
/* Un solo punto es a la vez el primero y el último: se ancla por la izquierda,
   o la regla del último lo empujaría fuera del gráfico. */
.cc-labels.is-line > span:first-child:last-child { transform: none; }

/* --------------------------------------------------------- Variante de línea */
.cc-svg { position: absolute; inset: 0; width: 100%; height: 100%; }

.cc-dots, .cc-hits { position: absolute; inset: 0; }
.cc-dots { pointer-events: none; }
/* Las zonas de captura van centradas sobre su punto, así que las de los
   extremos asoman media banda fuera del trazado. Se recortan aquí: sin esto la
   primera se salía por la izquierda de la tarjeta. */
.cc-hits { overflow: hidden; }

/* Marcador de punto: 9px con anillo de 2px del color de superficie, para que
   siga leyéndose donde dos series se cruzan. Con pocos puntos están siempre a
   la vista; con muchos aparecen al entrar en el gráfico, porque una nube de
   puntos sobre una línea densa tapa la propia línea. */
.cc-dot {
  position: absolute;
  width: 9px; height: 9px; border-radius: 50%;
  transform: translate(-50%, 50%);
  box-shadow: 0 0 0 2px var(--chart-surface);
  opacity: 0;
  transition: opacity var(--t) var(--ease);
}
.cc-plot.is-dots .cc-dot { opacity: 1; }
.col-chart:hover .cc-dot { opacity: 1; }

/* Zona de captura centrada en el punto, no repartida en bandas iguales: así la
   línea vertical del cursor cae sobre el dato. */
.cc-hit {
  position: absolute; top: 0; bottom: 0;
  transform: translateX(-50%);
}
.cc-hit::before {
  content: ''; position: absolute; left: 50%; top: 0; bottom: 0;
  width: 1px; background: var(--border-strong);
  opacity: 0;
  transition: opacity var(--t-fast) var(--ease);
}
.cc-hit:hover::before { opacity: 1; }

@media (max-width: 640px) {
  .col-chart { --cc-gutter: 30px; }
  .cc-labels > span, .cc-ylab, .cc-val { font-size: 10px; }
}

/* ==========================================================================
   Barras horizontales
   Una fila del ancho de la tarjeta con el relleno detrás del texto: el nombre
   a la izquierda, la cifra a la derecha y el color midiendo el largo.
   ========================================================================== */
.hbars { display: flex; flex-direction: column; gap: 6px; width: 100%; }

.hbar {
  position: relative;
  display: flex; align-items: center; gap: var(--s3);
  min-height: 34px; padding: 7px 12px;
  border-radius: var(--r-sm);
  background: var(--surface-2);
  overflow: hidden;
  cursor: default;
  transition: background var(--t-fast) var(--ease);
}
/* El relleno es el tono de la serie al 22%, no plano: una fila de 34px con
   color saturado es un bloque que grita y deja el nombre ilegible encima. Al
   22% el largo sigue midiendo y la tinta conserva su contraste.

   El 22% se consigue con `opacity` y no con `color-mix`: al cambiar de tema,
   `--c1` cambia y el `color-mix` de esta regla se quedaba con el color viejo
   —la mezcla no se recalcula cuando la variable que la alimenta se redefine
   más arriba—, así que en oscuro las barras seguían pintadas con el azul del
   tema claro. Con opacidad el color se resuelve cada vez y el tema manda.

   Extremo de dato redondeado y base cuadrada contra el borde izquierdo de la
   pista: un cero es un cero, no media píldora. */
.hbar-fill {
  position: absolute; left: 0; top: 0; bottom: 0;
  width: var(--hb-p, 0%);
  background-color: var(--hb-c, var(--c1));
  opacity: .22;
  border-radius: var(--r-sm) 4px 4px var(--r-sm);
  transform-origin: left center;
  animation: hb-grow .5s var(--ease-out) backwards;
  animation-delay: calc(var(--i, 0) * 40ms);
  transition: opacity var(--t-fast) var(--ease);
}
@keyframes hb-grow { from { transform: scaleX(0); } to { transform: scaleX(1); } }

.hbar-name {
  position: relative; z-index: 1;
  flex: 1 1 auto; min-width: 0;
  font-size: var(--fs-sm); color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hbar-val {
  position: relative; z-index: 1; flex: none;
  font-size: var(--fs-sm); font-weight: 700; color: var(--ink);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.hbar-dot {
  display: inline-block; width: 8px; height: 8px;
  border-radius: 3px; margin-right: 7px; flex: none;
}
.hbar:hover { background: var(--surface-3); }
.hbar:hover .hbar-fill { opacity: .34; }

/* ------------------------------------------------------- Barra apilada */
.stack-bar {
  display: flex; gap: 2px;
  border-radius: var(--r-full); overflow: hidden;
  background: var(--surface-3);
}
.stack-bar > span {
  transition: filter var(--t-fast) var(--ease);
  animation: hb-grow .5s var(--ease-out) backwards;
  animation-delay: calc(var(--i, 0) * 60ms);
  transform-origin: left center;
}
.stack-bar > span:hover { filter: brightness(1.1) saturate(1.06); }

/* ------------------------------------------------------------------ Dona */
.donut-svg path { transition: opacity var(--t-fast) var(--ease); cursor: default; }
.donut-svg:hover path { opacity: .38; }
.donut-svg path:hover { opacity: 1; }
.donut-row { padding: 3px 6px; border-radius: var(--r-xs); }
.donut-row:hover { background: var(--surface-2); }

/* --------------------------------------------------------- Tendencia */
.trend-wrap { position: relative; display: block; width: 100%; }
/* El punto se apoya EN el borde derecho, no a caballo sobre él: alguna de estas
   miniaturas vive con margen negativo hasta el filo de la tarjeta, y medio
   punto asomando por fuera se recortaría. Los 3,5px que se desplaza respecto
   al último dato no se ven; el recorte sí. */
.trend-dot {
  position: absolute; right: 0;
  width: 7px; height: 7px; border-radius: 50%;
  transform: translateY(50%);
  box-shadow: 0 0 0 2px var(--chart-surface);
}

/* Sin movimiento: las entradas se quedan en su estado final. Los tokens de
   duración ya se anulan arriba, pero las animaciones de aquí llevan tiempos
   literales y hay que apagarlas a mano. */
@media (prefers-reduced-motion: reduce) {
  .cc-bar, .hbar-fill, .stack-bar > span { animation: none; }
}

/* ------------------------------------------------------------- Memorandos --
   La lista de memorandos abre el detalle al pulsar una fila. Se marca con el
   cursor y con un fondo al pasar por encima, porque una fila que reacciona
   pero no lo aparenta es una función que nadie encuentra. */
.memo-row { cursor: pointer; }
.memo-row:hover { background: var(--surface-2); }

/* El cuerpo del memorando es texto que alguien escribió a mano: se respeta su
   ancho de lectura y se deja respirar, en vez de estirarlo de borde a borde. */
.memo-body {
  max-width: 68ch;
  padding: var(--s4);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: var(--surface-2);
  font-size: var(--fs-md);
  line-height: 1.65;
  white-space: normal;
}

/* Faltaba el gemelo en rojo de `.t-warn` y `.t-success`. */
.t-danger { color: var(--danger); }

/* ------------------------------------------------ Directorio documental --
   Cada documento es una tarjeta con su descripcion y su enlace. Se usa
   `flex` en columna para que el pie --enlace y fecha-- quede abajo del todo
   aunque las descripciones tengan alturas distintas: si no, en una rejilla
   de dos columnas los enlaces bailan de altura y cuesta barrerlos con la
   vista. */
.doc-card {
  display: flex; flex-direction: column; gap: var(--s3);
  padding: var(--s4);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background: var(--surface);
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.doc-card:hover { border-color: var(--border-strong); box-shadow: var(--shadow-sm); }
/* Pendiente: el borde entero se tine de ambar. Antes era una banda de 3 px a
   la izquierda; el borde completo dice lo mismo sin partir la tarjeta. */
.doc-card.is-pending { border-color: var(--warning); }

.doc-top { display: flex; align-items: flex-start; gap: var(--s3); }
.doc-ico {
  flex: 0 0 auto; display: grid; place-items: center;
  width: 34px; height: 34px; border-radius: var(--r-md);
  background: color-mix(in srgb, var(--primary) 12%, transparent);
  color: var(--primary);
}
.doc-title { margin: 0; font-size: var(--fs-md); font-weight: 650; line-height: 1.35; }
.doc-desc {
  margin: 4px 0 0; font-size: var(--fs-sm); color: var(--ink-3); line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}

.doc-foot {
  display: flex; align-items: center; gap: var(--s2);
  margin-top: auto; padding-top: var(--s3);
  border-top: 1px solid var(--border);
}
/* Sin `wrap` a propósito: el nombre del archivo puede ser larguísimo
   —«CERTIPROF - Checklist inicio y cierre de jornada Ventas (Canal
   Corporativo/Enterprise)»— y si el pie se parte, el lápiz de editar cae solo
   a una segunda línea y cada tarjeta queda de una altura distinta. Se encoge
   el nombre, que ya lleva su elipsis, y lo demás se queda donde está. */
.doc-foot > .doc-file { min-width: 0; flex: 0 1 auto; }
.doc-foot > .btn, .doc-foot > .icon-btn, .doc-foot > .t-xs { flex: 0 0 auto; }

/* Los 24 documentos sin URL enseñan el nombre del archivo en Drive. Va en
   `code` y con boton de copiar porque lo unico util que se puede hacer con
   ellos es pegarlo en el buscador de Drive. */
.doc-file {
  display: inline-flex; align-items: center; gap: 6px; min-width: 0;
  max-width: 100%; padding: 3px 4px 3px 8px;
  border: 1px dashed var(--border-strong); border-radius: var(--r-sm);
  color: var(--ink-3);
}
.doc-file code {
  font-size: var(--fs-xs); color: var(--ink-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  min-width: 0;
}
.doc-foot .t-xs { white-space: nowrap; }
.doc-file .icon-btn { width: 24px; height: 24px; }

@media (max-width: 720px) {
  .doc-file code { max-width: 46vw; }
}

/* --------------------------------------------- Gestión de Personal ------
   Las tarjetas de las personas a cargo son enlaces: se marcan como tales y
   se separan del texto de dentro, que si no se pega al borde. */
.mt-person { display: block; padding: var(--s4); text-decoration: none; color: inherit; }
.mt-person:hover { text-decoration: none; }

/* La fila de una solicitud que espera el visto bueno de quien mira. Es lo
   único de esa tabla sobre lo que hay que hacer algo hoy, así que se marca
   con una banda a la izquierda en vez de con color de fondo: el fondo
   compite con las insignias de estado que ya lleva la fila. */
.mt-mine > td:first-child { box-shadow: inset 3px 0 0 var(--primary); }
.mt-view .is-today { background: color-mix(in srgb, var(--primary) 6%, transparent); }
