/* Acqustic frontend — estilos propios (complementan Pico.css 2.1.1).
 *
 * Pico v2 cubre el grosor del styling (botones, tablas, forms). Aquí
 * añadimos, en el orden físico del archivo:
 *
 *   1. Brand foundation — paleta BACKSTAGE (turquesa #06B8AD, dark
 *      #2B2B34, blanco) + tipografía Inter única (Light/Regular/
 *      Medium/Semibold/Bold) + override de Pico vars para que el
 *      theme entero respire la identidad de marca. Light forzado vía
 *      `data-theme="light"` en `base.html.j2` — el PDF descargado
 *      existe sólo en light, coherencia visual HTML↔PDF.
 *   2. Utility classes (`.alert`/`.alert-*`, `.num`, `.table-wrapper`)
 *      reusables por templates — sustituyen inline `style="..."`
 *      duplicados en múltiples sitios.
 *   3. `figure img` responsive — las charts del informe (donuts,
 *      choropleth) llegan como data URIs base64 con dimensiones
 *      nativas de matplotlib y necesitan `max-width: 100%` para no
 *      desbordar viewports estrechos.
 *   4. Anchor scroll smooth + `scroll-margin-top` para que el sticky
 *      no tape el `<h3>` al saltar a una sección.
 *   5. Sticky header del informe (`position: sticky` con offset).
 *   6. TOC del informe con look de "tabs" (`.toc-tabs` + `.toc-tab`,
 *      underline + active state vía scroll-spy.js).
 *   7. Chart containers — alturas responsive para Chart.js canvas.
 *   8. `:target` highlight al hacer click en un anchor — pista
 *      visual de "estás aquí".
 *   9. Filas TOTAL en tablas del informe — fondo + bold via CSS.
 *  10. `@media print` que prepara la página para imprimir (Cmd+P en
 *      el browser). Oculta nav top, sticky header y botones; fuerza
 *      colores B&W; reintroduce page-breaks que el sticky scroll de
 *      navegador no necesitaba.
 *
 * Este stylesheet NO replica el de `acq_cli/render/styles.css` (ese
 * es para WeasyPrint paged media); aquí estamos en navegador HTML.
 * Pero sí comparte la paleta turquesa para que el HTML interactivo
 * y el PDF descargado se vean familiares.
 */


/* -------------------------------------------------------------------
 * Brand foundation — paleta + tipografía + override Pico.
 *
 * `data-theme="light"` se fija en `base.html.j2` (no usamos auto vía
 * `prefers-color-scheme`). Decisiones:
 *   - El PDF descargado existe sólo en light → consistencia HTML↔PDF.
 *   - La audiencia es operador (admin) que pasa el día con la app.
 *   - El turquesa Acqustic luce mejor sobre fondos claros.
 *
 * El bloque queda anclado al `data-theme="light"` por si en el futuro
 * (Phase 6+) entra un toggle dark — el bloque dark vivirá en
 * `:root[data-theme="dark"]` y el theme picker cambia el atributo.
 * ------------------------------------------------------------------- */

/* Global font-size base: 75% → 12px desde el default 16px del browser.
 * Decisión del operador (2026-05-26, tras varias iteraciones):
 *   1. Default Pico 16px → todo demasiado grande, zoom browser 50%
 *      necesario.
 *   2. 87.5% (14px) → seguía grande.
 *   3. 50% (8px) → texto bien pero "elementos al 100%" (paddings no
 *      encogían lo suficiente).
 *   4. 50% texto + 75% root split → texto demasiado chiquito.
 *   5. 75% único (texto + elementos a 12px) ← AQUÍ.
 *
 * Pico CSS y nuestros tamaños usan `rem` así que TODO (paddings,
 * sidebar, gaps, font-sizes) escala uniformemente al 75% del default.
 * 12px es legible para data tables densas y mantiene buena densidad
 * visual de la app.
 *
 * Si users futuros se quejan, subir a 81.25% (13px) o 87.5% (14px).
 * Bajar a 62.5% (10px) si quieres MÁS densidad. Pico v2 estructura
 * funciona OK desde 10-16px. */
html {
  font-size: 75%;
}

:root[data-theme="light"] {
  /* Brand — paleta BACKSTAGE (líneas de diseño 22 SEPT 2025).
   * Tres colores oficiales: turquesa #06B8AD, dark azulado #2B2B34, blanco puro. */
  --acq-primary: #06B8AD;
  --acq-primary-hover: #059992;
  --acq-primary-soft: color-mix(in srgb, #06B8AD 12%, transparent);
  --acq-primary-on: #FFFFFF;

  /* Neutros fríos del mockup (sin warmth "pergamino"). El surface-2
   * (#F4F4F6) es el grey muy claro de las placeholder cells en las
   * tablas con thumbnail. Text muted #6B6B73 sobre #2B2B34 saturation. */
  --acq-bg: #FFFFFF;
  --acq-surface: #FFFFFF;
  --acq-surface-2: #F4F4F6;
  --acq-text: #2B2B34;
  --acq-text-muted: #6B6B73;
  --acq-border: #E5E5E8;

  /* Semantic — coral BACKSTAGE (#E64B3D) para FILL/BG del toggle
   * "COMPLETA" destacado en mockup #3. Contraste sobre blanco ≈ 4.05:1
   * (FALLA WCAG AA para texto normal, pasa para texto large + para
   * background). `--acq-error-text` queda RESERVADA — se consumirá
   * cuando los commits PR2 (botones / alerts) introduzcan selectores
   * donde el coral aparezca como COLOR DE TEXTO (≈5.1:1 sobre
   * blanco). Decisión derivada del code-review del commit 1. */
  --acq-error: #E64B3D;
  --acq-error-text: #D43A2C; /* reservada — consumer en PR2 */
  --acq-success: #2E8B57;
  --acq-warning: #C68B2E;

  /* Override Pico vars — un punto único para reskinning. La cascada
   * de Pico usa estas vars en TODOS sus selectores; cambiarlas aquí
   * propaga al stack entero (botones, links, forms, cards, tablas). */
  --pico-primary: var(--acq-primary);
  --pico-primary-hover: var(--acq-primary-hover);
  --pico-primary-background: var(--acq-primary);
  --pico-primary-border: var(--acq-primary);
  --pico-primary-underline: var(--acq-primary);
  --pico-primary-focus: var(--acq-primary-soft);
  --pico-primary-inverse: var(--acq-primary-on);
  --pico-background-color: var(--acq-bg);
  --pico-color: var(--acq-text);
  --pico-h1-color: var(--acq-text);
  --pico-h2-color: var(--acq-text);
  --pico-h3-color: var(--acq-text);
  --pico-h4-color: var(--acq-text);
  --pico-muted-color: var(--acq-text-muted);
  --pico-muted-border-color: var(--acq-border);
  --pico-card-background-color: var(--acq-surface);
  --pico-card-border-color: var(--acq-border);
  --pico-card-sectioning-background-color: var(--acq-surface-2);
  --pico-secondary-background: var(--acq-surface-2);
  --pico-form-element-background-color: var(--acq-surface);
  --pico-form-element-border-color: var(--acq-border);
  --pico-form-element-focus-color: var(--acq-primary);

  /* Pico colores semánticos — alineados a paleta cálida. */
  --pico-color-red-500: var(--acq-error);
  --pico-color-green-500: var(--acq-success);
  --pico-color-amber-500: var(--acq-warning);
  --pico-mark-background-color: var(--acq-primary-soft);
  --pico-mark-color: var(--acq-text);

  /* h5/h6 no se usan hoy en los templates, pero Pico los pinta con
   * un grey por defecto (`#5c6370` / `#646b79`) que no encaja en la
   * paleta cálida. Override para que cualquier `<h5>/<h6>` futuro
   * herede el color del cuerpo sin volver a tocar este bloque. */
  --pico-h5-color: var(--acq-text);
  --pico-h6-color: var(--acq-text-muted);

  /* `::selection` — Pico v2 default es un azul (`rgba(2, 154, 232,
   * 0.25)`) que rompe la identidad turquesa al seleccionar texto. */
  --pico-text-selection-color: var(--acq-primary-soft);

  /* Numeric features — `tnum` (tabular-nums) + `lnum` (lining figures)
   * fuerzan dígitos de ancho fijo + altura uniforme para alinear
   * columnas numéricas en tablas y cards. Inter trae lining figures
   * por defecto, así que `lnum` es defense-in-depth contra los
   * fallbacks de `--acq-font-sans` (system-ui en Linux/macOS exóticos,
   * Roboto en Android, etc.) que pueden usar old-style por defecto.
   * Coste cero, evita drift si Google Fonts falla y el browser cae al
   * stack siguiente. */
  --num-features: "tnum" 1, "lnum" 1;

  /* Tipografía — Inter única (BACKSTAGE 22 SEPT 2025).
   * Geométrica, muy legible para datos numéricos densos y cómoda
   * en headings al peso 600. Fallbacks robustos a system-ui para
   * que la página siga viéndose decente si el CDN no carga.
   *
   * `--acq-font-serif` se mantiene como ALIAS de `--acq-font-sans`
   * para que reglas legacy (h1..h4, .hero-tagline, .kpi-value)
   * sigan resolviendo a Inter sin tener que tocar cada selector.
   * Limpieza definitiva del alias en commit final del rediseño. */
  --acq-font-sans: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --acq-font-serif: var(--acq-font-sans);
  --pico-font-family: var(--acq-font-sans);
  --pico-font-family-sans-serif: var(--acq-font-sans);
}

/* Headings BACKSTAGE — Inter Semibold con letter-spacing más estrecho
 * para ganar densidad visual en títulos grandes (`Inter Semibold 45pt`
 * en el mockup). El bloque se resuelve a Inter via el alias. */
h1,
h2,
h3,
h4 {
  font-family: var(--acq-font-sans);
  font-weight: 600;
  letter-spacing: -0.015em;
}

/* `.display-name` — nombres prominentes en turquesa (BACKSTAGE p.3
 * "Paula Mattheus" como Inter Light 45 en color primary). Usar en
 * cabecera de informe por right-holder, o en cualquier sitio donde un
 * nombre sea el sujeto visual principal de la página. */
.display-name {
  font-family: var(--acq-font-sans);
  font-weight: 300;
  /* Handoff 2026-05-15 P13: 2.75rem (era 2.5rem) — match spec brand
   * "44px Inter Light 300". El badge de periodo al lado necesita el
   * line-height ajustado (1.05) o flota mal alineado con la baseline. */
  font-size: 2.75rem;
  color: var(--acq-primary);
  letter-spacing: -0.02em;
  line-height: 1.05;
  margin: 0;
}

/* Brand logo en el header — color turquesa explícito para que el
 * `currentColor` del wordmark del SVG (`<text fill="currentColor">`)
 * sea determinista y NO dependa del color por defecto que Pico aplique
 * al `<a>`. Sin esta regla el render acaba siendo turquesa "por suerte"
 * (Pico pinta los links con `--pico-primary`); si en el futuro Pico
 * cambia ese default o el `<a>` recibe otra clase, el wordmark
 * cambiaría sigilosamente. Subrayado off — el logo no es un link
 * subrayable. */
.brand-logo {
  color: var(--acq-primary);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
}


/* -------------------------------------------------------------------
 * Layout — topbar horizontal oscura + main content centrado.
 *
 * Phase 7 reemplaza el sidebar vertical (Phase 5.6+) por un top-nav
 * horizontal full-width, theme dark, que matchea la herramienta de
 * referencia del usuario (`old.interfaz/top_nav.png`):
 *   - Logo izquierda, items nav CENTRADOS (BACKSTAGE mockup #2),
 *     usuario derecha.
 *   - Grupos con dropdown flotante hacia abajo en hover.
 *   - Theme dark BACKSTAGE: `#2B2B34` fondo, texto blanco, items
 *     activos con underline turquesa 2px (no soft background).
 *   - Altura 64px (mockup BACKSTAGE — ligeramente más alta que la
 *     56px previa para acomodar el wordmark "ac~qustic" 30px).
 *   - Desktop-only: sin mobile fallback (admin tool, no responsive).
 *
 * Body usa flex-column: topbar al top, content debajo. El login usa
 * `body.minimal-shell` (extends `base_minimal.html.j2`) sin topbar —
 * full-bleed para la hero.
 * ------------------------------------------------------------------- */

body.topbar-shell {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  margin: 0;
}

body.minimal-shell {
  margin: 0;
  min-height: 100vh;
}

/* -------------------------------------------------------------------
 * Topbar BACKSTAGE — rewrite 2026-05-15 (handoff Claude Design).
 *
 * Las dos iteraciones anteriores (Phase 7 + handoff 2026-05-11)
 * mapeaban las clases del prototipo (`.brand`, `.nav-item`,
 * `.nav-group`, `.user`) a clases BEM-`topbar-*` del live. El
 * resultado nunca convencía visualmente: Pico aplica defaults a los
 * elementos semánticos (`<button>`, `<nav>`, `<ul>`, `<li>`) que se
 * colaban entre nuestros overrides y rompían el balance del mockup.
 *
 * Este rewrite copia literalmente la CSS del prototipo
 * (`/tmp/acq_design/acq/project/assets/styles.css` líneas 59-201)
 * usando sus mismos selectores y nombres de clase, así no hay
 * traducción a deshacer. El HTML del topbar en `base.html.j2` y
 * `_nav.html.j2` se rehizo en paralelo para emitir el DOM esperado.
 * ------------------------------------------------------------------- */

.topbar {
  /* Grid `auto 1fr auto` exactamente como el prototipo: brand a la
   * izquierda (auto), nav en el centro (1fr toma todo el resto),
   * chip de usuario a la derecha (auto). Limpio, sin flex+margin-
   * auto hacks. */
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  height: 72px;
  padding: 0 2.5rem;
  gap: 2rem;
  /* Hex hardcoded (no tokens) — la topbar es la única superficie
   * dark de la app y los 3 colores oficiales BACKSTAGE están fuera
   * de los tokens light por diseño. */
  background: #2B2B34;
  color: #FFFFFF;
  position: relative;
  z-index: 50;
  flex-shrink: 0;
}

/* Logo oficial como <img> (`logo.png`, variante blanca del wordmark
 * `logo_real.webp` para la franja dark del topbar). 2026-05-28: antes
 * era texto inline "ac~qustic"; se unificó con el asset oficial que
 * ya usaban login/welcome. */
.topbar .brand {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  flex-shrink: 0;
}
.topbar .brand img {
  display: block;
  height: 32px;
  width: auto;
}

/* `<nav>` dentro del topbar (sin clase, igual que el prototipo). El
 * `height: 100%` permite que items y triggers rellenen los 72px del
 * topbar, condición necesaria para que el underline activo
 * (`::after { bottom: -1px }`) caiga pegado al borde inferior. */
.topbar nav {
  display: flex;
  align-items: center;
  justify-content: center;
  /* Handoff topbar 2026-05-16 P2: 44 → 40px — con 5 items + chevrons
   * a 44px el centrado se desequilibra en viewports 1280-1440px
   * (los items extremos rozan el chip de usuario); 40px mantiene
   * el aire pero deja margin al chip. */
  gap: 2.5rem;
  height: 100%;
  margin: 0;
  padding: 0;
  min-width: 0;
}

@media (max-width: 75em) {
  .topbar nav { gap: 1.5rem; }
}

/* Items planos (`.nav-item`) + trigger de grupo (`.nav-group >
 * .nav-trigger`) comparten estilo de base: blanco a 0.65 opacidad,
 * 15px Inter Medium, full-height, padding 8px 4px. Hover/active
 * suben opacidad a 1. La regla `background: transparent` + `border:
 * 0` + `font-family: inherit` neutraliza los defaults de Pico
 * para `<button>` (que pinta primary bg, border y padding propio).
 * `position: relative` ancla el `::after` (underline activo) al
 * propio item / trigger, no a su padre. */
.topbar nav .nav-item,
.topbar nav .nav-group > .nav-trigger {
  position: relative;
  display: inline-flex;
  align-items: center;
  /* Handoff topbar 2026-05-16 P3: gap 4 → 6px — los chevrons pegaban
   * al texto y "Releases▾" se leía como una sola palabra. */
  gap: 0.375rem;
  height: 100%;
  /* Handoff topbar 2026-05-16 P3 — FIX BUG vertical alignment.
   * Pico aplica `margin-bottom: var(--pico-spacing)` (≈18px) a TODOS
   * los `<button>`. Con `align-items: center` en el flex padre, esos
   * 18px fantasma desplazaban Releases / Royalties / Opciones (que
   * son `<button>`) ~9px arriba mientras Dashboard / Analíticas (que
   * son `<a>`) se quedaban en su sitio. Reset explícito a margin: 0
   * los devuelve a la misma center-line que los `<a>`. */
  margin: 0;
  padding: 0.5rem 0.25rem;
  background: transparent;
  border: 0;
  color: #FFFFFF;
  /* Handoff topbar 2026-05-16 P3: 0.65 → 0.72 — a 0.65 los items
   * inactivos se leían como deshabilitados; 0.72 los hace legibles
   * manteniendo la jerarquía vs el activo (1.0). */
  opacity: 0.72;
  font-family: inherit;
  /* 2026-06-02 (feedback del operador): el header de la app se veía
   * notablemente más pequeño que el del site público (Roster/Tienda).
   * Con el root al 75% (12px), `1rem` rendía 12px reales — demasiado
   * chico. 1.4rem ≈ 17px acerca el tamaño al header público sin desbordar
   * el nav centrado (5 items) en viewports desktop. */
  font-size: 1.4rem;
  font-weight: 500;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  user-select: none;
  transition: opacity 0.15s ease;
}

.topbar nav .nav-item:hover,
.topbar nav .nav-group:hover > .nav-trigger,
.topbar nav .nav-group:focus-within > .nav-trigger {
  opacity: 1;
}

.topbar nav .nav-item.active,
.topbar nav .nav-group.active > .nav-trigger {
  opacity: 1;
  font-weight: 600;
}

/* Underline turquesa 2px del item activo, anclado al filo inferior
 * del topbar como un tab indicator (mockup BACKSTAGE). `bottom: -1px`
 * (vs 0) compensa el subpixel rounding que algunos navegadores
 * hacen con el `position: absolute` dentro de items con altura
 * percent. */
.topbar nav .nav-item.active::after,
.topbar nav .nav-group.active > .nav-trigger::after {
  content: "";
  position: absolute;
  /* Handoff topbar 2026-05-16 P4: left/right -2 → -4px — un poco más
   * ancho para que el indicador no parezca apretado en torno al
   * texto; height 2 → 2.5px — 2px se diluía visualmente sobre la
   * franja dark, 2.5px lo convierte en un tab-indicator inequívoco. */
  left: -4px;
  right: -4px;
  bottom: -1px;
  height: 2.5px;
  background: var(--acq-primary);
  border-radius: 2px;
}

/* Chevron del trigger de grupo. Handoff topbar 2026-05-16 P5: era
 * `display: inline-block` para el glifo Unicode "▾"; ahora flex SVG.
 * El glifo Unicode tenía baseline impredecible cross-platform
 * (Safari macOS alto, Chrome Linux bajo) — SVG con currentColor se
 * alinea perfecto en todos los browsers. Rota 180° en hover/focus
 * del grupo o si está active. */
/* `.chev-sm` global (no scoped a `.topbar nav`) — el sub-popover del
 * 3er nivel del nav re-usa el mismo componente y necesita el sizing del
 * SVG fuera del topbar. La rotación on-hover sigue scopeada al
 * topbar porque sólo aplica al nav-group top-level (los sub-groups
 * usan `.chev-r` y otra transformación). */
.chev-sm {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 10px;
  height: 10px;
  flex-shrink: 0;
  opacity: 0.75;
  transition: transform 0.15s ease, opacity 0.15s ease;
}
.chev-sm svg {
  width: 100%;
  height: 100%;
  display: block;
}
.topbar nav .nav-group:hover .chev-sm,
.topbar nav .nav-group:focus-within .chev-sm,
.topbar nav .nav-group.active .chev-sm {
  transform: rotate(180deg);
}

/* `.nav-group` — wrapper relative para anclar el popover absoluto.
 * Full-height + flex centered alinea el trigger verticalmente
 * dentro del topbar. */
.topbar nav .nav-group {
  position: relative;
  display: flex;
  align-items: center;
  height: 100%;
}

/* Popover floating bajo el trigger. Handoff topbar 2026-05-16 P6:
 * - `display: block` — FIX BUG Pico. Pico aplica `nav ul { display:
 *   flex }` que el `.nav-popover` (siendo <ul> dentro de <nav>)
 *   heredaba; con 1 child (Releases/Royalties) no se notaba, pero
 *   con 3 children (Opciones) los items se pintaban en fila.
 * - min-width 220 → 240px — espacio para "Salud del catálogo" cómodo.
 * - padding 6px → 6px 0 — gutter solo vertical; los <a> van full-bleed
 *   horizontal para que el hover bg cubra toda la línea.
 * - overflow: hidden — recorta el hover bg de items extremos al
 *   radius del popover. Sin esto los <a> sin border-radius pintarían
 *   bg cuadrado y se vería "pico" en las esquinas.
 * - border-radius 12 → 14px — alinea con cards del informe (16-22).
 * - sombra reforzada: 0.18 se diluía sobre contenido coloreado del
 *   informe; 0.22 + capa corta 1px para borde óptico. */
.topbar nav .nav-popover {
  display: block;
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translate(-50%, -4px);
  min-width: 240px;
  padding: 0.375rem 0;
  list-style: none;
  margin: 0;
  background: #FFFFFF;
  border: 1px solid var(--acq-border);
  border-radius: 14px;
  /* Handoff "Mes de venta" 2026-05-19: overflow: hidden → visible.
   * El sub-popover del 3er nivel (Analíticas → Mes de venta → Matriz /
   * Analíticas) abre en cascada lateral a la derecha y `overflow:hidden`
   * lo recortaba (invisible aunque el DOM exista). El padding vertical
   * 0.375rem mantiene los items separados de las esquinas, así que el
   * hover bg de items extremos no asoma sobre el border-radius. */
  overflow: visible;
  box-shadow:
    0 1px 0 rgba(0, 0, 0, 0.04),
    0 16px 40px rgba(0, 0, 0, 0.22);
  visibility: hidden;
  opacity: 0;
  transition: opacity 0.12s ease, transform 0.12s ease, visibility 0s linear 0.12s;
  z-index: 80;
}

.topbar nav .nav-group:hover .nav-popover,
.topbar nav .nav-group:focus-within .nav-popover {
  visibility: visible;
  opacity: 1;
  transform: translate(-50%, 0);
  transition: opacity 0.12s ease, transform 0.12s ease;
}

/* Reset Pico defaults para `<li>` dentro del popover. Pico aplica
 * `padding-inline-start: 10px` y un list-style invisible que reserva
 * espacio; sin reset los items quedan desalineados a la derecha. */
.topbar nav .nav-popover li {
  display: block;
  padding: 0;
  margin: 0;
  list-style: none;
}

.topbar nav .nav-popover a,
.topbar nav .nav-popover .disabled {
  display: block;
  /* Handoff topbar 2026-05-16 P7 — FIX BUG full-bleed. Pico aplica
   * `nav a.active { margin: -9px; padding: 9px }` para generar un
   * "pill negativo" en links activos dentro de `<nav>`. Eso hacía que
   * el `<a class="active">` saliera 9px por cada lado fuera del `<li>`
   * padre (ancho efectivo 257px sobre popover de 240px). El reset
   * a `margin: 0` + `width: 100%` + `box-sizing: border-box` lo
   * encaja exactamente en la línea del popover. */
  margin: 0;
  width: 100%;
  box-sizing: border-box;
  /* Handoff topbar 2026-05-16 P7: padding 9/14 → 10/18 — full-bleed
   * horizontal; el clip de las esquinas redondeadas lo hace ahora
   * el `overflow: hidden` + `border-radius` del popover padre.
   * Border-radius en el `<a>` pasa a 0 — hover bg cubre full-row
   * sin inset. */
  padding: 0.625rem 1.125rem;
  border-radius: 0;
  color: var(--acq-text);
  font-size: 0.875rem;
  font-weight: 500;
  opacity: 1;
  text-decoration: none;
  transition: background 0.15s ease, color 0.15s ease;
}

.topbar nav .nav-popover a:hover,
.topbar nav .nav-popover a:focus-visible {
  background: var(--acq-primary-soft);
  color: var(--acq-primary);
}

.topbar nav .nav-popover a.active {
  background: var(--acq-primary-soft);
  color: var(--acq-primary);
  font-weight: 600;
}

.topbar nav .nav-popover .disabled {
  color: var(--acq-text-muted);
  font-style: italic;
  cursor: not-allowed;
  user-select: none;
}


/* -------------------------------------------------------------------
 * Chip de usuario — `.user-chip` wrapper + `<button class="user">`.
 *
 * El prototipo solo tiene el botón visual; aquí añadimos un popover
 * con el link de logout (sin él el live no podría cerrar sesión).
 * Estilo del popover idéntico al de los grupos pero anclado a la
 * derecha (`right: 0`) en vez de centrado, porque el chip vive en
 * el borde derecho del topbar y un menú centrado se saldría del
 * viewport.
 * ------------------------------------------------------------------- */

.topbar .user-chip {
  position: relative;
  display: flex;
  align-items: center;
  height: 100%;
}

.topbar .user {
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-rows: auto auto;
  /* Handoff topbar 2026-05-16 P8: 10 → 12px — el chevron rozaba el
   * texto a 10px. */
  column-gap: 0.75rem;
  align-items: center;
  background: transparent;
  border: 0;
  /* Handoff topbar 2026-05-16 P8 — FIX BUG vertical alignment.
   * Mismo Pico bug que `.nav-item`/`.nav-trigger`: el chip es
   * `<button>` y Pico le aplicaba `margin-bottom: 18px` que lo
   * desalineaba verticalmente con el resto de la nav. Reset
   * explícito a margin: 0. */
  margin: 0;
  /* Handoff topbar 2026-05-16 P8: 6px 8px → 6px 4px 6px 8px —
   * quitar padding derecho excesivo (el chevron ya está pegado al
   * filo del topbar y no necesita aire extra). */
  padding: 0.375rem 0.25rem 0.375rem 0.5rem;
  color: #FFFFFF;
  font-family: inherit;
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
  text-align: right;
  min-width: 0;
}
.topbar .user:focus { outline: 0; }

.topbar .user .name {
  display: inline-flex;
  align-items: center;
  /* Handoff topbar 2026-05-16 P9: 6 → 7px — el check turquesa
   * estaba pegado al apellido. */
  gap: 0.4375rem;
  grid-column: 1;
  grid-row: 1;
  font-weight: 600;
  /* Handoff topbar 2026-05-16 P9: 14 → 15px — el name es el sujeto
   * del chip, merece presencia. */
  font-size: 0.9375rem;
  white-space: nowrap;
  /* Handoff topbar 2026-05-16 P9: line-height 1.1 — ajusta el stack
   * vertical de name+id para que el chip mantenga vertical-center
   * pulido en 72px. */
  line-height: 1.1;
}
.topbar .user .name svg {
  color: var(--acq-primary);
  flex-shrink: 0;
}

.topbar .user .id {
  grid-column: 1;
  grid-row: 2;
  font-size: 0.6875rem;
  color: var(--acq-primary);
  white-space: nowrap;
  /* Handoff topbar 2026-05-16 P10: letter-spacing 0.02em — "ID:" se
   * lee mejor con un pelín más de aire, sobre todo en mixed-case;
   * weight 500 — a 11px turquesa sobre dark, weight 400 (default)
   * se ve débil. */
  letter-spacing: 0.02em;
  font-weight: 500;
}

/* Chevron del chip. Handoff topbar 2026-05-16 P11: mismo motivo que
 * `.chev-sm` — era texto Unicode con baseline cross-browser
 * impredecible; ahora SVG flex container alineado pixel-perfect. */
.topbar .user .chev {
  grid-column: 2;
  grid-row: 1 / span 2;
  align-self: center;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 12px;
  height: 12px;
  line-height: 1;
  opacity: 0.55;
  transition: transform 0.15s ease, opacity 0.15s ease;
}
.topbar .user .chev svg {
  width: 100%;
  height: 100%;
  display: block;
}

.topbar .user-chip:hover .chev,
.topbar .user-chip:focus-within .chev {
  transform: rotate(180deg);
}

/* Handoff topbar 2026-05-16 P12: alineado con `.nav-popover` —
 * display: block (reset Pico nav ul flex), 200px (era 12rem ≈ 192px,
 * cómodo para "Cerrar sesión"), padding 6px 0 (gutter vertical),
 * radius 14px, overflow hidden (clip hover bg), sombra reforzada. */
.topbar .user-popover {
  display: block;
  position: absolute;
  top: 100%;
  right: 0;
  transform: translateY(-4px);
  min-width: 200px;
  padding: 0.375rem 0;
  list-style: none;
  margin: 0;
  background: #FFFFFF;
  border: 1px solid var(--acq-border);
  border-radius: 14px;
  overflow: hidden;
  box-shadow:
    0 1px 0 rgba(0, 0, 0, 0.04),
    0 16px 40px rgba(0, 0, 0, 0.22);
  visibility: hidden;
  opacity: 0;
  transition: opacity 0.12s ease, transform 0.12s ease, visibility 0s linear 0.12s;
  z-index: 80;
}

.topbar .user-chip:hover .user-popover,
.topbar .user-chip:focus-within .user-popover {
  visibility: visible;
  opacity: 1;
  transform: translateY(0);
  transition: opacity 0.12s ease, transform 0.12s ease;
}

.topbar .user-popover li {
  display: block;
  padding: 0;
  margin: 0;
  list-style: none;
}

.topbar .user-popover a {
  display: block;
  /* Handoff topbar 2026-05-16 P13: mismo fix full-bleed que
   * `.nav-popover a` (Pico nav a.active margin -9px). */
  margin: 0;
  width: 100%;
  box-sizing: border-box;
  padding: 0.625rem 1.125rem;
  border-radius: 0;
  color: var(--acq-text);
  font-size: 0.875rem;
  font-weight: 500;
  text-decoration: none;
  transition: background 0.15s ease, color 0.15s ease;
}
.topbar .user-popover a:hover,
.topbar .user-popover a:focus-visible {
  background: var(--acq-primary-soft);
  color: var(--acq-primary);
}

/* `.content` envuelve el `<main>`. Phase 8.1: full-bleed (sin
 * max-width) — el contenido ocupa el viewport completo hasta los
 * bordes. Antes había un cap de 1200px que dejaba gutters laterales
 * en monitores grandes (look de recuadro centrado); el usuario lo
 * señaló como bug visual. Trade-off aceptado: en monitores ultra-
 * wide el texto de informes puede tener líneas largas, pero las
 * tablas de analytics (12+ columnas de meses) ganan mucho espacio.
 * Si la legibilidad de texto en monitores 21:9+ se vuelve un
 * problema, se puede aplicar `max-width` selectivo a las páginas
 * de informe (no a analytics). */
.content {
  width: 100%;
  padding: 2rem 2.5rem;
  box-sizing: border-box;
  /* `flex: 1` (con `body.topbar-shell` siendo flex column) hace que
   * el `<main>` se expanda para empujar el `.app-footer` al pie del
   * viewport cuando el contenido es corto (sticky footer pattern).
   * Sin esto el footer "flotaba" en mitad de la pantalla en páginas
   * con poco contenido (e.g. `/royalties/reports` con form vacío). */
  flex: 1 0 auto;
}

/* Hero — login full-bleed. Centro vertical + horizontal del viewport.
 * El `.hero-content` agrupa la marca arriba (logo) y la card del form
 * abajo, con un gap respirado entre ambos. La imagen de fondo viene
 * inline desde el template (foto del roster elegida al azar por el
 * servidor); aquí dejamos solo el color base + position/size/repeat
 * para que la imagen cubra el viewport.
 *
 * `align-items: safe center`: el `safe` previene el bug de centrado
 * con overflow. Si el form crece (login con error visible) más allá
 * de 100vh, `align-items: center` desplaza el contenido hacia arriba
 * fuera de la viewport sin scroll. `safe` cae a `flex-start` cuando
 * detecta overflow, permitiendo scroll natural. Soportado en navegadores
 * modernos; en navegadores que ignoren `safe`, el comportamiento cae al
 * `center` previo (no hay regresión). */
.hero {
  min-height: 100vh;
  display: flex;
  align-items: safe center;
  justify-content: center;
  padding: 2rem 1rem;
  /* Fondo: foto del roster elegida aleatoriamente por el servidor
   * (`bg_photo`, inline style en el template). `background-color`
   * fallback queda en turquesa para los casos sin imagen (carpeta
   * `static/fotos/` vacía o ausente). Properties separadas (no
   * shorthand) para que `background-image` inline no resetee el
   * color/position/size. */
  background-color: var(--acq-primary);
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
}

.hero-content {
  width: 100%;
  max-width: 480px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2rem;
}

/* Home / landing tras el login: carrusel full-bleed de las fotos del
 * roster. Rompe el padding de `.content` (2rem/2.5rem) con márgenes
 * negativos para llegar a los bordes, y ocupa el viewport menos la
 * topbar (72px). Los slides se apilan en absolute y crossfade por
 * opacidad; el JS (`home_carousel.js`) rota la clase `.is-active`. */
.home-hero {
  position: relative;
  margin: -2rem -2.5rem;
  min-height: calc(100vh - 72px);
  overflow: hidden;
  /* Fallback turquesa si no hay fotos (carpeta vacía/ausente). */
  background-color: var(--acq-primary);
}

.home-hero__slide {
  position: absolute;
  inset: 0;
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
  opacity: 0;
  /* Crossfade suave entre fotos. `is-active` la trae a opacidad plena. */
  transition: opacity 1.2s ease-in-out;
}

.home-hero__slide.is-active {
  opacity: 1;
}

/* Sin JS / `prefers-reduced-motion`: nada de animación, pero el primer
 * slide queda visible (la plantilla le pone `is-active`). */
@media (prefers-reduced-motion: reduce) {
  .home-hero__slide {
    transition: none;
  }
}

/* -------------------------------------------------------------------
 * Landing inmersiva "full page" — `body.is-landing` (home.html.j2).
 *
 * Feedback del operador 2026-06-02 ("capricho del jefe"): la home debe
 * ser a pantalla completa SIN el banner oscuro; el header se vuelve
 * transparente y flota sobre el carrusel con las letras blancas y una
 * barrita turquesa que aparece al pasar el ratón (como el site público).
 * Al entrar en cualquier sección vuelve el banner oscuro normal (las
 * reglas de abajo SOLO aplican bajo `body.is-landing`).
 * ------------------------------------------------------------------- */

/* Topbar fuera de flujo, superpuesta al carrusel. Un scrim degradado
 * MUY sutil (no es un banner) garantiza legibilidad de las letras
 * blancas sobre fotos claras sin romper la sensación de transparencia. */
body.is-landing .topbar {
  position: absolute;
  inset: 0 0 auto 0;
  background: linear-gradient(180deg, rgba(0, 0, 0, 0.32), rgba(0, 0, 0, 0));
}

/* El carrusel pasa a ocupar el viewport completo (incl. detrás del
 * header). Anulamos el padding del `.content` y los márgenes negativos
 * del `.home-hero` para que llene exactamente 100vh sin scroll. */
body.is-landing .content {
  padding: 0;
}
body.is-landing .home-hero {
  margin: 0;
  min-height: 100vh;
}

/* Footer fuera: en la landing inmersiva no debe asomar bajo el carrusel. */
body.is-landing .app-footer {
  display: none;
}

/* Letras un punto más opacas que en el banner oscuro (sobre foto se
 * agradece algo más de cuerpo). */
body.is-landing .topbar nav .nav-item,
body.is-landing .topbar nav .nav-group > .nav-trigger {
  opacity: 0.92;
}

/* Barrita turquesa en HOVER/FOCUS (la landing no tiene item activo:
 * ningún href casa con "/"). Mismo indicador que el `.active` del banner.
 * `:focus-visible` en el item plano da paridad de teclado con el hover. */
body.is-landing .topbar nav .nav-item:hover::after,
body.is-landing .topbar nav .nav-item:focus-visible::after,
body.is-landing .topbar nav .nav-group:hover > .nav-trigger::after,
body.is-landing .topbar nav .nav-group:focus-within > .nav-trigger::after {
  content: "";
  position: absolute;
  left: -4px;
  right: -4px;
  bottom: -1px;
  height: 2.5px;
  background: var(--acq-primary);
  border-radius: 2px;
}

/* `.hero-card-dark` BACKSTAGE (mockup #1): card central #2B2B34
 * con border-radius 16px y padding generoso. Contiene logo +
 * form + iconos sociales + términos. */
.hero-card.hero-card-dark {
  background: #2B2B34;
  color: #FFFFFF;
  border: 0;
  border-radius: 16px;
  padding: 2.5rem 2rem;
  width: 100%;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.5rem;
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35);
}

.hero-card-brand {
  display: flex;
  justify-content: center;
  margin-bottom: 0.5rem;
}

/* Tamaño del logo del login. IMPRESCINDIBLE en CSS (no basta el atributo
 * `height` del <img>): Pico aplica `img { height: auto }`, que GANA al
 * atributo HTML por especificidad → sin esta regla el wordmark se pinta a
 * su tamaño NATIVO (384×77 ≈ 77px de alto), de ahí el "pegote". Mismo
 * patrón que `.topbar .brand img { height: 32px }`. 30px (~150px de ancho):
 * discreto y nítido en retina (el asset es ráster 384×77, sin vector). */
.hero-card-brand img {
  height: 30px;
  width: auto;
}

.login-form {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.login-field {
  margin: 0;
}

/* Input blanco redondeado con texto dark, placeholder grey. Mockup
 * #1: input fill blanco sobre card dark, sin border visible. */
.login-form input[type="password"],
.login-form input[type="text"],
.login-form input[type="email"] {
  width: 100%;
  background: #FFFFFF;
  color: var(--acq-text);
  border: 0;
  border-radius: 8px;
  padding: 0.85rem 1rem;
  font-family: var(--acq-font-sans);
  font-size: 1rem;
  box-shadow: none;
}

.login-form input::placeholder {
  color: rgba(43, 43, 52, 0.45);
  font-weight: 400;
}

.login-form input:focus-visible {
  outline: 2px solid var(--acq-primary);
  outline-offset: 2px;
}

/* Botón ENTRAR (mockup #1): turquesa fill, mayúsculas, block. */
.btn-login,
button.btn-login {
  background: var(--acq-primary);
  color: #FFFFFF;
  border: 0;
  border-radius: 8px;
  font-family: var(--acq-font-sans);
  font-weight: 500;
  font-size: 0.9rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding: 0.85rem 1rem;
  cursor: pointer;
  width: 100%;
  margin-top: 0.5rem;
  transition: background 0.15s ease;
}

.btn-login:hover,
.btn-login:focus-visible {
  background: var(--acq-primary-hover);
  outline: none;
}

/* Variante OAuth (PR5-B): se aplica a un `<a>` que enlaza a
 * `/auth/oauth/login`. Reemplaza el background turquesa por un fondo
 * blanco con texto dark para diferenciarlo claramente del POST de
 * dev-mode (cuando ambos se muestran a la vez). Coherente con
 * estética de Google Sign-In. */
a.btn-login-oauth,
.btn-login.btn-login-oauth {
  display: block;
  background: #FFFFFF;
  color: #2B2B34;
  text-align: center;
  text-decoration: none;
  box-sizing: border-box;
}

a.btn-login-oauth:hover,
.btn-login.btn-login-oauth:hover,
a.btn-login-oauth:focus-visible,
.btn-login.btn-login-oauth:focus-visible {
  background: #F2F2F5;
  color: #2B2B34;
}

/* Welcome pending (PR5-C self-service onboarding): mensaje en la
 * card dark + botón refresh. Mismo layout que login, sin form. */
.pending-message {
  color: rgba(255, 255, 255, 0.88);
  text-align: center;
  margin: 1.25rem 0 0.5rem;
}

.pending-title {
  font-family: var(--acq-font-sans);
  font-weight: 500;
  font-size: 1.15rem;
  margin: 0 0 0.75rem;
  color: #FFFFFF;
}

.pending-body {
  font-size: 0.9rem;
  line-height: 1.5;
  margin: 0 0 0.75rem;
  color: rgba(255, 255, 255, 0.75);
}

.pending-body strong {
  color: #FFFFFF;
  font-weight: 500;
}

a.btn-login.pending-refresh,
.btn-login.pending-refresh {
  margin-top: 1rem;
}

/* PR5-C #3: bloque "Pendientes de aprobación" en /admin/users.
 * Card destacada arriba del listado normal con borde amarillo sutil
 * para llamar la atención del master sin ser estridente. */
.pending-approval-block {
  border-left: 4px solid #E8B447;
  background: #FDF8EC;
}

.pending-approval-title {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 1rem;
  font-weight: 500;
  margin: 0 0 0.5rem;
}

.pending-approval-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.5rem;
  padding: 0.1rem 0.45rem;
  border-radius: 999px;
  background: #E8B447;
  color: #2B2B34;
  font-size: 0.8rem;
  font-weight: 500;
}

.pending-approval-hint {
  font-size: 0.85rem;
  color: var(--acq-text-muted, #555);
  margin: 0 0 0.75rem;
}

.pending-approval-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.pending-approval-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.6rem 0;
  border-top: 1px solid rgba(232, 180, 71, 0.3);
}

.pending-approval-item:first-child {
  border-top: 0;
}

.pending-approval-info {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.pending-approval-name {
  font-size: 0.85rem;
  color: var(--acq-text-muted, #555);
}

.pending-approval-date {
  font-size: 0.75rem;
  color: var(--acq-text-muted, #888);
}

/* Separador "o" entre dropdown dev y botón OAuth — visible solo
 * cuando ambos modos están activos en DEV_MODE. Hairline horizontal
 * a cada lado del texto centrado. */
.login-oauth-divider {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 1rem 0 0.25rem;
  color: rgba(255, 255, 255, 0.55);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

.login-oauth-divider::before,
.login-oauth-divider::after {
  content: "";
  flex: 1 1 auto;
  border-top: 1px solid rgba(255, 255, 255, 0.18);
}

.hero-card-terms {
  font-family: var(--acq-font-sans);
  font-size: 0.85rem;
  color: rgba(255, 255, 255, 0.7);
  margin: 0;
  text-align: center;
}

.hero-card-terms-link {
  color: var(--acq-primary);
  text-decoration: none;
}

.hero-card-terms-link:hover,
.hero-card-terms-link:focus-visible {
  text-decoration: underline;
  outline: none;
}

/* Visually-hidden helper (a11y): oculta visualmente pero deja
 * accesible para screen readers. Reusable. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Hero editorial legacy (Phase 5.6): `.hero-brand` y `.hero-tagline`
 * pertenecen al diseño anterior con tagline editorial bajo el logo.
 * El login BACKSTAGE ya NO los usa (el logo va dentro de la card
 * dark). Mantenemos las reglas vivas por si entra otra página con
 * hero editorial (e.g. landing pública, página de error). Si en
 * limpieza final no encuentran consumer, se borran. */
.hero-brand {
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
}

.hero-tagline {
  font-family: var(--acq-font-sans);
  font-size: 1.1rem;
  font-style: italic;
  color: var(--acq-text-muted);
  margin: 0;
  letter-spacing: 0.005em;
}

.brand-logo-lg {
  display: flex;
  justify-content: center;
}


/* -------------------------------------------------------------------
 * Footer BACKSTAGE.
 *
 * Banda dark #2B2B34 al pie de páginas autenticadas (mockup #2/#3/#4).
 * Izquierda: "© 2025 copyright: www.acqustic.com" — prefix muted +
 * dominio blanco semibold. Derecha: 5 iconos sociales en círculos
 * #3B3B43 36px. Hover/focus → bg `--acq-primary-hover` (#059992) para
 * cumplir WCAG 1.4.11 (contraste UI ≥ 3:1 con texto blanco).
 * Mobile (<600px): apila el footer en columna.
 * ------------------------------------------------------------------- */

.app-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  padding: 1.75rem 2rem;
  background: #2B2B34;
  color: rgba(255, 255, 255, 0.7);
  flex-shrink: 0;
  font-size: 0.85rem;
}

.app-footer-copy {
  display: inline-flex;
  align-items: baseline;
  gap: 0.5rem;
}

.app-footer-copy-prefix {
  opacity: 0.55;
  font-weight: 400;
}

.app-footer-copy-domain {
  color: #FFFFFF;
  font-weight: 600;
  letter-spacing: 0.01em;
}

@media (max-width: 37.5em) {
  .app-footer {
    flex-direction: column;
    gap: 1rem;
    text-align: center;
  }
}


/* -------------------------------------------------------------------
 * Dashboard section headers BACKSTAGE.
 *
 * Mockup #2 separa el dashboard en bloques con headers que combinan
 * `<h2>` Inter Semibold + link secundario a la derecha (e.g.
 * "Ver meses anteriores"). Para "Estado del sistema" el link no es
 * necesario (modifier `dashboard-section-header-secondary` añade
 * margin-top para separar visualmente del bloque previo).
 * ------------------------------------------------------------------- */

.dashboard-section-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1rem;
}

.dashboard-section-header h2 {
  margin: 0;
}

.dashboard-section-header-secondary {
  margin-top: 2.5rem;
}

.dashboard-link-secondary {
  color: var(--acq-primary);
  text-decoration: none;
  font-size: 0.9rem;
  font-weight: 500;
}

.dashboard-link-secondary:hover,
.dashboard-link-secondary:focus-visible {
  text-decoration: underline;
  outline: none;
}

.dashboard-link-secondary[aria-disabled="true"] {
  cursor: not-allowed;
}


/* -------------------------------------------------------------------
 * KPI cards BACKSTAGE.
 *
 * Mockup #2 (Home "Ingresos Recientes") y mockup #3 (informe lateral):
 * cards turquesa sólido con valor blanco grande centrado.
 *
 * - background: `--acq-primary-hover` (#059992) en lugar de
 *   `--acq-primary` (#06B8AD) — WCAG 1.4.11 (UI 3:1): el blanco sobre
 *   #06B8AD da 2.48:1 (falla), sobre #059992 da ≈3.5:1 (pasa). Tono
 *   perceptualmente idéntico al mockup.
 * - `.kpi-header` con `font-weight: 700` (Bold) para que cuente como
 *   "bold ≥14pt" en WCAG (3:1).
 * - `.kpi-value` con `clamp(1.5rem, 4vw, 2.5rem)`: cifras largas
 *   (millones con coma decimal) se contraen en cards estrechas en
 *   lugar de hacer overflow. `min-width: 0` en `.kpi-card` habilita
 *   la contracción del flex item.
 * - `.alert-warning` dentro de `.kpi-card`: amber sobre turquesa
 *   contrasta 1.8:1 → ilegible. Override con bg dark translúcido +
 *   texto blanco para legibilidad sobre la card.
 * - `.kpi-delta` reservada para "↑ X% / ↓ Y%" del mockup #2 (sin
 *   consumer hasta commit 12; test guardián anti-borrado).
 * ------------------------------------------------------------------- */

.kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1.5rem;
  margin-bottom: 2rem;
}

.kpi-card {
  background: var(--acq-primary-hover);
  border: 0;
  border-radius: 12px;
  padding: 1.5rem 1.75rem;
  box-shadow: 0 2px 8px color-mix(in srgb, var(--acq-primary) 25%, transparent);
  color: #FFFFFF;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  min-width: 0;
  text-align: center;
  transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.kpi-card:hover {
  box-shadow: 0 6px 18px color-mix(in srgb, var(--acq-primary) 40%, transparent);
  transform: translateY(-1px);
}

.kpi-header {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  color: #FFFFFF;
  font-size: 1rem;
  font-weight: 700;
  border: none;
  margin: 0;
  padding: 0;
  background: transparent;
}

/* `<strong>` dentro del header (`dashboard.html.j2` lo envuelve con
 * el lexema del KPI) heredaría `font-weight: bolder` UA, que sobre
 * 700 resuelve a 900 — Inter solo carga hasta 700 → el browser
 * sintetiza faux-bold borroso, peor render en retina. Forzar a
 * `inherit` mantiene el 700 del header sin desviarse. */
.kpi-header strong {
  font-weight: inherit;
}

.kpi-icon {
  /* Hereda `currentColor` blanco sobre turquesa. */
  color: #FFFFFF;
  flex-shrink: 0;
}

.kpi-value {
  font-family: var(--acq-font-sans);
  font-weight: 600;
  /* clamp baseline 1.25rem, max 2rem (32px): conservador para que
   * cifras de 12 chars con "€" ("158.255,18 €") quepan sin recorte
   * en cards de ~300px (auto-fit minmax(240px,1fr) a 1440 viewport).
   * Inter Semibold 32px × 12 chars × 0.55em ≈ 211px, dentro de los
   * 244px útiles tras padding 1.75rem. */
  font-size: clamp(1.25rem, 3vw, 2rem);
  line-height: 1.1;
  color: #FFFFFF;
  margin: 0;
  max-width: 100%;
  letter-spacing: -0.02em;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  font-feature-settings: var(--num-features);
}

.kpi-unit {
  font-size: 1rem;
  font-weight: 400;
  color: rgba(255, 255, 255, 0.75);
  margin-left: 0.25rem;
}

.kpi-footer {
  border: none;
  padding: 0;
  margin: 0;
  background: transparent;
}

.kpi-footer small {
  color: rgba(255, 255, 255, 0.85);
}

/* Alert warning dentro de la card turquesa: amber sobre turquesa
 * contrasta ~1.8:1 (ilegible). Repintamos para legibilidad sobre
 * turquesa sin perder la semántica de "warning". */
.kpi-card .alert-warning {
  background: rgba(0, 0, 0, 0.18);
  border: 1px solid rgba(255, 255, 255, 0.45);
  border-left: 4px solid rgba(255, 255, 255, 0.7);
  color: #FFFFFF;
}

/* Delta opcional al pie (↑ 8,54% / ↓ -5,61%) — mockup #2 muestra
 * deltas vs mes anterior bajo el valor. Sin consumer hasta commit
 * 12 (Dashboard "Ingresos Recientes"). */
.kpi-delta {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  font-size: 0.85rem;
  color: rgba(255, 255, 255, 0.9);
  font-variant-numeric: tabular-nums;
}

.kpi-delta-icon {
  width: 0.9em;
  height: 0.9em;
  flex-shrink: 0;
}


/* -------------------------------------------------------------------
 * Form del informe — width tope + centrado horizontal en viewport.
 *
 * Audit BACKSTAGE: el form estaba pegado a la izquierda. `margin: 0
 * auto` lo centra en la viewport (sobre tablet/mobile <760px ocupa
 * el 100% gracias al max-width). El dropdown del holder usa
 * `<datalist>` nativo del navegador — el custom HTMX (Phase 5.7,
 * `.autocomplete-*`) se eliminó completo (138 LoC JS + 55 CSS +
 * endpoint).
 * ------------------------------------------------------------------- */

.reports-form {
  max-width: 760px;
  margin: 0 auto;
}

/* Buttons "secondary": el default de Pico era prácticamente
 * invisible (gris muy claro sobre fondo crema). Override global con
 * `outline` turquesa para que el operador SÍ vea que es un botón.
 * El selector NO está scopeado a `.reports-actions` porque queremos
 * el mismo tratamiento en cualquier botón secundario futuro. */
.secondary {
  border-color: var(--acq-primary);
  color: var(--acq-primary);
  background: transparent;
}

.secondary:hover {
  background: var(--acq-primary-soft);
  color: var(--acq-primary);
}


/* -------------------------------------------------------------------
 * Empty states del informe (Phase 5.7).
 *
 * Cuando un holder no tiene actividad en una sección concreta
 * (resumen, evolución, streaming, RRSS, países), la tabla NO se
 * renderiza con TOTAL=0,00 € (visualmente confuso). En su lugar,
 * un párrafo `.empty-state` con mensaje claro. Diseño deliberadamente
 * sutil: fondo `--acq-surface-2` (gris claro neutro) + borde
 * `--acq-border` + padding generoso. Sin colores semánticos
 * (warning/error) — la ausencia de datos no es un problema.
 * ------------------------------------------------------------------- */

.empty-state {
  background: var(--acq-surface-2);
  border: 1px dashed var(--acq-border);
  /* Handoff 2026-05-16 W11: radius var-Pico → 10px (consistente con
   * cards), padding 1.25/1.5 → 1.5/1.75 (más respiración), margin
   * bottom 1.5 → 0 (el `section[id]` ya da margin-bottom 3rem),
   * `text-align: center` — empático como mensaje, no como bullet
   * de cuerpo. */
  border-radius: 10px;
  padding: 1.5rem 1.75rem;
  color: var(--acq-text-muted);
  margin: 0;
  font-style: italic;
  text-align: center;
}

/* Handoff analytics 2026-05-17 A9: empty-state-pivot pasa de
 * párrafo a card con icono target turquesa. COPY 100% server-
 * rendered (las sugerencias en `_pivot_table.html.j2` siguen
 * siendo dinámicas según `form.filter_X` — sólo cambia el styling.
 * Tokens `<em>` dentro de los bullets pasan a tokens monoespaciados
 * con bg para diferenciar valores de usuario del cuerpo de la
 * sugerencia. */
.empty-state.empty-state-pivot {
  background: var(--acq-surface);
  border: 1px solid var(--acq-border);
  border-radius: 12px;
  padding: 2rem 2.5rem 2rem 4.5rem;
  margin: 1.5rem 0;
  font-style: normal;
  text-align: left;
  color: var(--acq-text);
  position: relative;
}
.empty-state.empty-state-pivot::before {
  content: "";
  position: absolute;
  left: 1.5rem;
  top: 2rem;
  width: 28px;
  height: 28px;
  border: 2px solid var(--acq-primary);
  border-radius: 50%;
  background:
    radial-gradient(circle at center, var(--acq-primary) 22%, transparent 24%);
}
.empty-state.empty-state-pivot p:first-child {
  font-weight: 600;
  font-size: 1.1rem;
  color: var(--acq-text);
  margin-top: 0;
  margin-bottom: 0.5rem;
}
.empty-state.empty-state-pivot p:nth-of-type(2) {
  color: var(--acq-text-muted);
  margin-bottom: 0.875rem;
}
.empty-state.empty-state-pivot ul {
  margin: 0;
  padding-left: 1.25rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.empty-state.empty-state-pivot li {
  line-height: 1.55;
  color: var(--acq-text);
}
.empty-state.empty-state-pivot li em {
  font-style: normal;
  background: var(--acq-surface-2);
  padding: 0.05rem 0.4rem;
  border-radius: 4px;
  font-size: 0.85em;
  border: 1px solid var(--acq-border);
}


/* -------------------------------------------------------------------
 * Forms con file input — drop zone visual.
 *
 * Phase 5.6 commit 5: el `<input type="file">` por defecto es feo en
 * todos los browsers (botón "Choose File" + nombre del archivo).
 * Para los flows de Royalties (Subir CSV, Catálogo) lo envolvemos en
 * un `<label class="drop-zone">` que pinta una caja con borde dashed
 * turquesa + hover. No es drag-and-drop real (no lo necesitamos —
 * Phase 6+); sólo visual.
 * ------------------------------------------------------------------- */

.drop-zone {
  display: block;
  border: 2px dashed var(--acq-border);
  border-radius: var(--pico-border-radius);
  padding: 1.5rem 1.25rem;
  background: var(--acq-surface-2);
  transition: border-color 0.15s ease, background 0.15s ease;
  cursor: pointer;
  margin-bottom: 1rem;
}

.drop-zone:hover,
.drop-zone:focus-within {
  border-color: var(--acq-primary);
  background: var(--acq-primary-soft);
}

.drop-zone-label {
  display: block;
  font-weight: 600;
  color: var(--acq-text);
  margin-bottom: 0.25rem;
}

.drop-zone-help {
  display: block;
  font-size: 0.875rem;
  color: var(--acq-text-muted);
  margin-bottom: 0.75rem;
}

.drop-zone input[type="file"] {
  width: 100%;
  margin: 0;
}

/* Phase 7: el mobile fallback se elimina. Acqustic es admin tool
 * desktop-only — sin responsive. Si en el futuro hace falta, la
 * topbar se colapsa a hamburger (Phase 8+). */


/* -------------------------------------------------------------------
 * Utility classes.
 *
 * Sustituyen inline `style="border-color: var(--pico-color-red-500);
 * border-width: 2px"` y similares que se repetían en 5+ templates
 * (`_ingest_result`, `_catalog_result`, `_backups_result`, `reports`,
 * `dashboard`). Una sola fuente de estilo: cambio futuro de paleta
 * toca un solo sitio.
 * ------------------------------------------------------------------- */

/* Banner para resultados de operaciones — error / success / warning.
 * Borde-izquierdo grueso de color + fondo sutil (8% del color en
 * `color-mix`) que conserva contraste en modo oscuro y claro.
 *
 * Cuando se aplica sobre un `<article>` en lugar de un `<div>`, el
 * selector `article.alert` neutraliza el padding/margin/border-radius
 * de la card de Pico para que NO se acumulen con los del `.alert`
 * (resultaba en padding interno doble y border-radius redundante). */
.alert {
  padding: 0.75rem 1rem;
  margin-bottom: 1rem;
  border-radius: var(--pico-border-radius);
  border-left: 4px solid;
}

/* El último bloque dentro del banner no debe arrastrar el
 * `margin-bottom` por defecto de `<p>` / `<table>` — ya cuenta el
 * padding del `.alert` al pie. */
.alert > *:last-child {
  margin-bottom: 0;
}

article.alert {
  /* Neutraliza el padding por defecto de `<article>` de Pico para
   * que no se sume al padding del `.alert`. */
  padding: 0.75rem 1rem;
  margin-bottom: 1rem;
  border-radius: var(--pico-border-radius);
}

.alert-error {
  border-left-color: var(--pico-color-red-500);
  background: color-mix(in srgb, var(--pico-color-red-500) 8%, transparent);
}

.alert-success {
  border-left-color: var(--pico-color-green-500);
  background: color-mix(in srgb, var(--pico-color-green-500) 8%, transparent);
}

.alert-warning {
  border-left-color: var(--pico-color-amber-500);
  background: color-mix(in srgb, var(--pico-color-amber-500) 8%, transparent);
}

.alert-info {
  border-left-color: var(--pico-color-azure-500);
  background: color-mix(in srgb, var(--pico-color-azure-500) 8%, transparent);
}

/* Bloque destacado dentro de un .alert para los avisos multi-source
 * del uploader. Borde + tinte ámbar más fuerte que el del banner para
 * que el usuario vea "esto es lo que hay que revisar".
 * Phase 9: parte de la UX agresiva tras el incidente 2026-05-12. */
.multi-source-notices {
  margin: 0.75rem 0;
  padding: 0.5rem 0.75rem;
  border-radius: var(--pico-border-radius);
  background: color-mix(in srgb, var(--pico-color-amber-500) 12%, transparent);
}

.multi-source-notices ul {
  margin: 0.25rem 0 0.5rem 1.25rem;
}

/* Botón "Deshacer esta subida": rojo de aviso, no botón primario, para
 * que se distinga del CTA principal. Mismo tamaño que el botón
 * estándar de Pico. */
.btn-undo {
  background: var(--pico-color-red-500);
  border-color: var(--pico-color-red-500);
  color: var(--pico-color-white);
  margin-top: 0.75rem;
}

.btn-undo:hover {
  background: var(--pico-color-red-600);
  border-color: var(--pico-color-red-600);
}

/* Variante compacta para el botón "Deshacer" dentro de la tabla del
 * batch: padding reducido + tipografía más pequeña para que no domine
 * la celda visualmente y no rompa el rhythm de la tabla. */
.btn-undo-row {
  margin: 0;
  padding: 0.25rem 0.5rem;
  font-size: 0.85em;
}

/* Barra de progreso del uploader JS chunked: contenedor + fill animado
 * que crece en `width` a medida que se suben ficheros (un POST por
 * fichero, ver `static/uploader.js`). */
.uploader-progress {
  width: 100%;
  height: 8px;
  background: color-mix(in srgb, var(--pico-color-azure-500) 12%, transparent);
  border-radius: 4px;
  overflow: hidden;
  margin: 0.5rem 0;
}

.uploader-progress-fill {
  height: 100%;
  width: 0%;
  background: var(--pico-color-azure-500);
  transition: width 0.25s ease-out;
}

.uploader-progress-label {
  font-size: 0.85em;
  margin: 0.25rem 0 0.5rem;
  color: var(--pico-color-azure-700, var(--pico-color-azure-500));
}

/* Fila "Subiendo…" placeholder antes de que llegue el resultado por
 * fichero. Heredada del `.batch-row-pending` (mismo nombre que los
 * otros estados para que el JS pueda reemplazar la clase entera). */
.batch-row-pending {
  background: color-mix(in srgb, var(--pico-color-azure-500) 4%, transparent);
}

/* Batch ingest: tabla con una fila por fichero + chips de estado.
 * Phase 9: tras el incidente 2026-05-12 + multi-upload del mismo día. */
.batch-summary {
  margin: 0.5rem 0 0.75rem 1.25rem;
}

.batch-summary li {
  margin-bottom: 0.25rem;
}

.batch-table {
  width: 100%;
  margin-top: 0.75rem;
}

.batch-table th,
.batch-table td {
  vertical-align: middle;
  padding: 0.4rem 0.6rem;
}

.batch-row-ingested { background: color-mix(in srgb, var(--pico-color-green-500) 4%, transparent); }
.batch-row-skipped { background: color-mix(in srgb, var(--pico-color-azure-500) 4%, transparent); }
.batch-row-soft_duplicate { background: color-mix(in srgb, var(--pico-color-amber-500) 8%, transparent); }
.batch-row-error { background: color-mix(in srgb, var(--pico-color-red-500) 8%, transparent); }

.batch-table .badge-ok,
.batch-table .badge-info,
.batch-table .badge-warn,
.batch-table .badge-error {
  display: inline-block;
  padding: 0.15rem 0.5rem;
  border-radius: 999px;
  font-size: 0.85em;
  font-weight: 600;
  white-space: nowrap;
}

.batch-table .badge-ok { background: var(--pico-color-green-500); color: white; }
.batch-table .badge-info { background: var(--pico-color-azure-500); color: white; }
.batch-table .badge-warn { background: var(--pico-color-amber-500); color: white; }
.batch-table .badge-error { background: var(--pico-color-red-500); color: white; }

/* Celdas numéricas en tablas financieras: alineación derecha +
 * tabular-nums para que las cifras se alineen columna por columna.
 * Sin tabular-nums, en la mayoría de fonts los dígitos `1` ocupan
 * menos ancho que `0`/`8` y la lectura comparativa se rompe.
 * Aplicar tanto a `<th>` como a `<td>` para que la cabecera quede
 * alineada con los datos.
 *
 * Crítico en informes financieros: sin esta clase, las tablas
 * muestran "1.000,00 €" e "123.456,78 €" alineados a la izquierda,
 * imposible comparar visualmente las cifras. */
.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-feature-settings: var(--num-features);
  /* `nowrap` evita que el browser parta `1.234,56 €` entre el número
   * y el símbolo de moneda en columnas estrechas. El separador entre
   * número y `€`/`%` ya es NBSP (`acq_core.format`); esto es defensa
   * en profundidad para browsers que aun así intentan partir. */
  white-space: nowrap;
}

/* Cabeceras de tabla con texto multi-palabra ("Apple Music", "%
 * Lic.", "% RH") rompían en 2 líneas en columnas justas. Aplicado
 * sólo a `<th>` con `.num` (columnas numéricas). Las `<th>` no-num
 * (Artista, Pista, Mes, País) sí pueden wrappear porque sus datos
 * son texto variable. */
th.num {
  white-space: nowrap;
}

/* Wrapper para tablas anchas: scroll horizontal en lugar de
 * desbordar el viewport. Aplicar a tablas con 7+ columnas o filas
 * largas. La `<table>` interna pierde su `margin-bottom` por
 * defecto de Pico para no acumular dos espaciados (el del wrapper
 * + el de la tabla). */
.table-wrapper {
  overflow-x: auto;
  margin-bottom: 1rem;
}

.table-wrapper > table {
  margin-bottom: 0;
}


/* -------------------------------------------------------------------
 * Tablas BACKSTAGE — `.table-bare` modifier.
 *
 * Mockups #2 (Home "Próximos/Lanzamientos recientes"), #3 (informe
 * "Artista/Pista/Streams..."), #4 (Releases): tablas planas sin
 * zebra striping de Pico, headers Inter Semibold 0.85rem, rows con
 * padding generoso, separadores hairline. La clase `.cell-product`
 * monta una celda con thumbnail placeholder + título turquesa primary
 * + subtítulo dark debajo. Sin consumer hasta commits 12 (Dashboard
 * releases) y 14 (Royalties tabla); test guardián anti-borrado.
 * ------------------------------------------------------------------- */

.table-bare {
  width: 100%;
  border-collapse: collapse;
  background: transparent;
}

/* Handoff 2026-05-16 W8: headers más sutiles — uppercase + tracking
 * (mismo lenguaje que el PDF que va a 7pt uppercase), color muted
 * (el body es lo que importa), size 0.85 → 0.78 (más compactos),
 * padding vertical 0.75 → 0.625 (vertical más apretado), bg
 * transparent + border-bottom más fuerte (1.5px) — el bg gris en
 * tablas largas se sentía pesado. */
.table-bare thead th {
  font-family: var(--acq-font-sans);
  font-weight: 600;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--acq-text-muted);
  text-align: left;
  padding: 0.625rem 1rem;
  background: transparent;
  border-bottom: 1.5px solid var(--acq-border);
}

.table-bare tbody td {
  font-family: var(--acq-font-sans);
  font-size: 0.95rem;
  color: var(--acq-text);
  padding: 1rem;
  vertical-align: middle;
  background: transparent;
  border-bottom: 1px solid var(--acq-border);
}

.table-bare tbody tr:last-child td {
  border-bottom: none;
}

/* Handoff 2026-05-16 W9: row hover sutil — el operador lee tablas
 * de 6-15 filas × hasta 9 cols; el hover ayuda a no perder la línea
 * horizontalmente. La regla específica preserva el bg de la fila
 * TOTAL (que tiene su propio bg turquesa-soft). */
.table-bare tbody tr:hover td {
  background: var(--acq-surface-2);
}
.table-bare tbody tr.report-total:hover td {
  background: var(--acq-primary-soft);
}

/* NOTA: las filas TOTAL del informe son `<tr class="report-total">`
 * dentro de `<tbody>` (no `<tfoot>`). El estilo TOTAL viene de la
 * regla `tr.report-total` global del Phase 5 (más abajo en este
 * file), no de un override `.table-bare tfoot`. La regla específica
 * `.table-bare tfoot td` añadida en commit 8 follow-up fue código
 * muerto — eliminada en review del commit 14. */

/* Numeric cells: alinear a la derecha + tabular-nums. Selector matchea
 * tanto `td.num` como `th.num` (header de columna numérica). */
.table-bare .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-feature-settings: var(--num-features);
}

/* Celda de producto: thumbnail placeholder grey + título turquesa +
 * subtítulo dark. Mockup #2/#4 muestra thumbnail 56×56 con border-
 * radius. Cuando entren cover-arts reales en el catálogo, swap
 * `.cell-product-thumb` por `<img>` y la regla sigue válida. */
.cell-product {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.cell-product-thumb {
  display: inline-block;
  width: 3.5rem;
  height: 3.5rem;
  background: var(--acq-surface-2);
  border-radius: 8px;
  flex-shrink: 0;
}

.cell-product-text {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  /* `min-width: 0` permite que el ellipsis funcione dentro del flex
   * container. Sin él los textos largos hacen wrap a 2+ líneas y
   * rompen la altura 56px del thumb (mockup #2/#4). */
  min-width: 0;
  overflow: hidden;
}

/* `.cell-product-title` se renderiza como `<a>` si la fila lleva a un
 * detalle (mockup #2 "Sentidos" → ficha del release) o como `<span>`
 * si no hay landing aún. El `text-decoration: none` cubre ambos; el
 * `:hover { underline }` sólo es efectivo sobre `<a>` (el span no
 * dispara hover-interaction visualmente útil, pero la regla es
 * inerte allí — no rompe nada). */
.cell-product-title {
  font-family: var(--acq-font-sans);
  font-weight: 600;
  color: var(--acq-primary);
  text-decoration: none;
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cell-product-title:hover {
  text-decoration: underline;
}

.cell-product-subtitle {
  font-family: var(--acq-font-sans);
  font-weight: 400;
  color: var(--acq-text);
  font-size: 0.875rem;
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}


/* -------------------------------------------------------------------
 * Subnav pill BACKSTAGE.
 *
 * Mockup #3 (Royalties / Right Holders / Artistas / Estado Adelantos)
 * y mockup #5 (Royalties / Artistas activa): píldora horizontal
 * turquesa con título + tabs. Estructura:
 *
 *   <nav class="subnav-pill" aria-label="...">
 *     <span class="subnav-pill-title">Royalties</span>
 *     <a class="subnav-pill-tab active" aria-current="page">Right Holders</a>
 *     <a class="subnav-pill-tab">Artistas</a>
 *     <span class="subnav-pill-tab disabled">Estado Adelantos</span>
 *   </nav>
 *
 * El primer tab es el TÍTULO de la sección (semibold 1.25rem), los
 * siguientes son tabs navegables (regular 1rem con underline si
 * `.active`). Items disabled (placeholders de páginas no
 * implementadas) se renderizan en `<span>` con cursor not-allowed.
 * ------------------------------------------------------------------- */

/* Contraste blanco/#06B8AD ≈ 2.48:1 → falla WCAG AA tanto para
 * texto normal (4.5:1) como para large bold (3:1). El título (1.25rem
 * semibold = 20px bold) y la tab activa (1rem semibold = 16px bold)
 * NO cumplen AA. Es decisión BACKSTAGE consciente — el mockup #3
 * dicta el turquesa puro y el equipo de diseño aceptó la deuda. Si
 * llegara una auditoría A11y obligatoria, alternativa: cambiar el bg
 * a `--acq-primary-hover` (#059992) que da ≈3.5:1 (pasa large bold). */
.subnav-pill {
  display: flex;
  align-items: center;
  gap: 2rem;
  background: var(--acq-primary);
  border-radius: 999px;
  padding: 0.875rem 1.75rem;
  color: #FFFFFF;
  margin-bottom: 1.5rem;
  flex-wrap: wrap;
}

.subnav-pill-title {
  font-family: var(--acq-font-sans);
  font-weight: 600;
  font-size: 1.25rem;
  color: #FFFFFF;
  letter-spacing: -0.01em;
}

.subnav-pill-tab {
  font-family: var(--acq-font-sans);
  font-weight: 400;
  font-size: 1rem;
  color: rgba(255, 255, 255, 0.85);
  text-decoration: none;
  padding: 0.25rem 0;
  position: relative;
  transition: color 0.15s ease;
}

.subnav-pill-tab:hover,
.subnav-pill-tab:focus-visible {
  color: #FFFFFF;
  outline: none;
}

/* Tab activa: blanco puro + underline blanco 2px sobreelevado para
 * que pegue al borde inferior del pill (mockup #3). */
.subnav-pill-tab.active {
  color: #FFFFFF;
  font-weight: 600;
}

/* Underline pegado al borde inferior del pill (mockup #3). Antes
 * estaba en `-0.375rem` que lo dejaba flotando dentro del pill;
 * `-0.875rem` cancela exactamente el padding-bottom del pill
 * (`.subnav-pill { padding: 0.875rem 1.75rem }`) y empuja el
 * underline hasta el borde inferior visible. */
.subnav-pill-tab.active::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -0.875rem;
  height: 2px;
  background: #FFFFFF;
  border-radius: 1px;
}

.subnav-pill-tab.disabled {
  color: rgba(255, 255, 255, 0.45);
  cursor: not-allowed;
}


/* -------------------------------------------------------------------
 * Botones BACKSTAGE — variantes secondary, danger y toggle group.
 *
 * Pico ya cubre el botón primary (turquesa default `var(--pico-
 * primary-background)`). Añadimos 2 variantes nuevas + el toggle
 * group COMPLETA/MEDIA/REDUCIDA del informe (mockup #3):
 *
 * - `.btn-dark`: secondary dark #2B2B34 con texto blanco mayúsculas
 *   Inter Medium. Para CTAs neutras como "FILTRAR" del filter pill.
 * - `.btn-danger`: coral #E64B3D mayúsculas blanco. Para acciones
 *   destacadas; en mockup #3 lo lleva el botón "COMPLETA" del toggle.
 * - `.toggle-group`: contenedor flex de 3 botones encadenados.
 *   El active recibe la variante (danger por defecto en COMPLETA);
 *   los inactivos son dark.
 *
 * Sin consumer todavía — entran en commit 13 (Royalties Report shell)
 * con la sección filtrar turquesa. Test guardián anti-borrado.
 * ------------------------------------------------------------------- */

.btn-dark,
button.btn-dark,
[role="button"].btn-dark {
  background: #2B2B34;
  color: #FFFFFF;
  border: 1px solid #2B2B34;
  font-family: var(--acq-font-sans);
  font-weight: 500;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 0.5rem 1.25rem;
  border-radius: 6px;
  cursor: pointer;
  transition: background 0.15s ease, opacity 0.15s ease;
}

.btn-dark:hover,
.btn-dark:focus-visible {
  background: #1F1F26;
  border-color: #1F1F26;
  color: #FFFFFF;
  outline: none;
}

.btn-danger,
button.btn-danger,
[role="button"].btn-danger {
  background: var(--acq-error);
  color: #FFFFFF;
  border: 1px solid var(--acq-error);
  font-family: var(--acq-font-sans);
  font-weight: 500;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: 0.5rem 1.25rem;
  border-radius: 6px;
  cursor: pointer;
  transition: background 0.15s ease, opacity 0.15s ease;
}

.btn-danger:hover,
.btn-danger:focus-visible {
  background: #C93828;
  border-color: #C93828;
  color: #FFFFFF;
  outline: none;
}

/* Toggle group: 3 botones encadenados sin gap, sólo el active se
 * destaca. Estructura:
 *
 *   <div role="group" class="toggle-group">
 *     <button class="toggle-group-btn active">COMPLETA</button>
 *     <button class="toggle-group-btn">MEDIA</button>
 *     <button class="toggle-group-btn">REDUCIDA</button>
 *   </div>
 *
 * El active = coral danger; los inactivos = dark. La diferenciación
 * matchea mockup #3 (COMPLETA destacada en rojo coral, MEDIA y
 * REDUCIDA en negro). */
/* Handoff 2026-05-15 P7: rewrite del toggle a pill segmentado
 * white-translucent (vivía como botones dark separados antes). El
 * contenedor ahora es un pill que aloja los 3 buttons como pills
 * más pequeños — inactive transparent + texto blanco translúcido,
 * COMPLETA active coral fill con sombra ligera. Match mockup #3. */
/* `.toggle-group*` (maqueta COMPLETA/MEDIA/REDUCIDA del informe) eliminado:
   el toggle de presets se sustituyó por config de columnas por titular. */


/* HTMX activa la clase `.htmx-request` en el elemento (o en un
 * ancestro) durante la petición; nuestro `.htmx-indicator` se
 * vuelve visible. Sin spinner SVG — un texto "Procesando…" o
 * "Buscando…" basta y es accesible (screen readers lo leen). El
 * operador necesita feedback de "esto está corriendo", no animación. */
.htmx-indicator {
  display: none;
  color: var(--pico-muted-color);
  margin-left: 0.5rem;
  font-size: 0.875em;
}

.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator {
  display: inline-block;
}


/* -------------------------------------------------------------------
 * Imágenes responsive dentro de `<figure>`.
 *
 * Aplica globalmente a cualquier `<figure><img>`. Las charts del
 * informe (donuts y choropleth) llegan como data URIs base64 con
 * dimensiones nativas de matplotlib; sin `max-width: 100%`, en
 * viewports <= ~700 px se cortan o desbordan. El `height: auto`
 * preserva el aspect ratio cuando `max-width` recorta el ancho.
 *
 * Hoy las únicas figuras del frontend están en `report_view.html.j2`
 * (donuts de streaming + mapa choropleth), pero la regla es global a
 * propósito: cualquier `<figure>` futura recibe el mismo tratamiento
 * sin tener que añadir reglas adicionales.
 * ------------------------------------------------------------------- */

figure img {
  max-width: 100%;
  height: auto;
  display: block;
}


/* -------------------------------------------------------------------
 * Smooth anchor scrolling + offset por el sticky header.
 * ------------------------------------------------------------------- */

html {
  scroll-behavior: smooth;
}

/* `scroll-margin-top` sobre las secciones con anchor (no `html`/
 * `scroll-padding-top` global). Aplicado sólo a `<section>` con
 * `id`, así no afecta a otras páginas (login, dashboard, ingest…)
 * que no tienen sticky header — un anchor en cualquier otra página
 * NO debería saltar demasiado bajo.
 *
 * Phase 5.7: el `.report-sticky` ahora contiene el TOC también
 * (hgroup + KPIs + actions + tabs) → ~18rem. Click en un tab del
 * TOC necesita esta margen para que la sección destino quede
 * justo debajo del header sticky completo, no parcialmente
 * tapada. */
section[id] {
  scroll-margin-top: 18rem;
}


/* -------------------------------------------------------------------
 * Header BACKSTAGE del informe (no sticky, scroll-anclado).
 *
 * Mockup #3: bloque título "Royalties Report – Right Holders" +
 * subtítulo + link "Ver meses anteriores" derecha. La sección
 * filtrar turquesa + KPIs lateral derecha vienen abajo. El sticky
 * header con nombre del artista + TOC viene al final.
 * ------------------------------------------------------------------- */

.report-header-row {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1.5rem;
}

.report-header-title {
  margin: 0;
}

.report-header-title h2 {
  margin: 0 0 0.25rem 0;
  font-size: 1.75rem;
}

.report-header-title p {
  margin: 0;
  color: var(--acq-text-muted);
  font-size: 0.95rem;
}


/* -------------------------------------------------------------------
 * Sección filtrar BACKSTAGE — pill turquesa + card KPIs lateral.
 *
 * Mockup #3: form completo (mes/año desde/hasta + holder + pista +
 * FILTRAR) en un bloque fondo turquesa redondeado. A la derecha,
 * en la misma fila, card lateral white con KPIs (Bruto/Neto/RH)
 * y borde turquesa. Debajo del form: links export Excel/PDF + toggle
 * COMPLETA/MEDIA/REDUCIDA.
 * ------------------------------------------------------------------- */

.report-filter-row {
  display: grid;
  grid-template-columns: 1fr auto;
  /* Handoff 2026-05-15 P1: gap 2rem (era 1.5rem) — despega el KPI
   * box del filter card sin meter divider visible. */
  gap: 2rem;
  margin-bottom: 2rem;
  align-items: stretch;
}

.report-filter-form {
  /* `--acq-primary-hover` (#059992) en lugar de `--acq-primary`
   * (#06B8AD): mismo tono WCAG-friendly que `.kpi-card`,
   * `.chart-container` y `.analytics-filter-bar` — los 4 filter/
   * card turquesa convergen al mismo tono para que la app respire
   * coherente. Visual indistinguible del primary; texto blanco
   * sobre el hover-tone pasa AA large bold. */
  background: var(--acq-primary-hover);
  /* Handoff 2026-05-15 P2: radius 20px (era 16px) — empareja con
   * KPI aside (22px) y respira más. */
  border-radius: 20px;
  /* Handoff 2026-05-15 P2: padding 1.5rem 1.75rem (era 1.25rem 1.5rem). */
  padding: 1.5rem 1.75rem;
  display: flex;
  flex-direction: column;
  /* Handoff 2026-05-15 P2: gap 1.25rem (era 0.75rem) — separa
   * row-top de row-bottom para que el border-top hairline destaque. */
  gap: 1.25rem;
}

/* Handoff 2026-05-15 P3 (mockup #3): 7 columnas con `fr` proporcionales
 * que crean clusters visuales sin hack de `:nth-child margin-right` —
 * años (0.7fr) más estrechos que meses (1fr), identidad (2fr) más
 * ancha que fechas. Column-gap uniforme 0.75rem da el aire entre los
 * clusters de forma natural. Mobile colapsa a 2 cols. */
.report-filter-row-top {
  display: grid;
  grid-template-columns:
    minmax(120px, 1fr)   /* mes inicio */
    minmax(96px, 0.7fr)  /* año inicio */
    minmax(120px, 1fr)   /* mes fin */
    minmax(96px, 0.7fr)  /* año fin */
    minmax(180px, 2fr)   /* holder */
    minmax(180px, 2fr)   /* pista */
    auto                 /* toggle Royalties productor */
    auto;                /* FILTRAR */
  column-gap: 0.75rem;
  row-gap: 0.5rem;
  align-items: center;
}

/* Toggle "Royalties productor": checkbox + label en línea, alineado con
 * el resto de controles del filtro (altura del row). `white-space: nowrap`
 * evita que el label parta en dos líneas y descuadre el grid. */
.report-filter-check {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-family: var(--acq-font-sans);
  font-size: 0.85rem;
  color: var(--acq-text);
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
}

.report-filter-check input {
  cursor: pointer;
}

@media (max-width: 56.25em) {
  .report-filter-row-top {
    grid-template-columns: 1fr 1fr;
  }
}

.report-filter-input {
  background: #FFFFFF;
  border: 0;
  /* Handoff 2026-05-15 P4: radius 10px (era 8px) — match input radii
   * del spec brand. */
  border-radius: 10px;
  /* Handoff 2026-05-15 P4: padding 0.625rem 0.875rem (era 0.5rem 0.75rem). */
  padding: 0.625rem 0.875rem;
  font-family: var(--acq-font-sans);
  font-size: 0.9rem;
  color: var(--acq-text);
  width: 100%;
  min-width: 0;
}

.report-filter-input[disabled] {
  opacity: 0.65;
  cursor: not-allowed;
}

.report-filter-input::placeholder {
  color: rgba(43, 43, 52, 0.45);
}

.report-filter-row-bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  /* `flex-wrap: wrap` + `row-gap` para que en viewport estrecho
   * (<700px) los export-links + toggle salten a 2 filas en lugar
   * de hacer overflow horizontal. */
  flex-wrap: wrap;
  row-gap: 0.5rem;
  /* Handoff 2026-05-15 P5: border-top más sutil (0.18 vs 0.2) y
   * padding-top mayor (1rem vs 0.75rem). */
  border-top: 1px solid rgba(255, 255, 255, 0.18);
  padding-top: 1rem;
}

.report-filter-export {
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  color: rgba(255, 255, 255, 0.85);
  font-size: 0.85rem;
}

/* Handoff 2026-05-15 P6: selector ultra-específico
 * (`.report-filter-row` + `button.report-export-link`) para ganar a
 * Pico, que pintaba `<button>` con su background primary + border
 * + padding. Sin `!important`. */
.report-filter-row .report-export-link,
.report-filter-row button.report-export-link {
  color: rgba(255, 255, 255, 0.85);
  text-decoration: none;
  background: transparent;
  border: 0;
  font-family: var(--acq-font-sans);
  font-size: 0.875rem;
  font-weight: 400;
  padding: 0;
  margin: 0;
  cursor: pointer;
  width: auto;
  line-height: 1.4;
}

.report-filter-row .report-export-link:hover,
.report-filter-row button.report-export-link:hover,
.report-filter-row .report-export-link:focus-visible,
.report-filter-row button.report-export-link:focus-visible {
  color: #FFFFFF;
  text-decoration: underline;
  outline: none;
}

.report-filter-row .report-export-link[disabled],
.report-filter-row .report-export-link[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  text-decoration: none;
}

.report-export-sep {
  color: rgba(255, 255, 255, 0.4);
  font-weight: 300;
}

/* Handoff 2026-05-15 P8: card destacada — borde 1.5px turquesa (era
 * 1px), radius 22px (era 16px), padding 1.75rem 2rem (era 1rem 1.5rem),
 * min-width 360px (era 240px; labels uppercase + cifras 9-10 chars
 * necesitan ~340px mínimos para no wrap), sombra del spec brand. */
.report-kpi-aside {
  background: #FFFFFF;
  border: 1.5px solid var(--acq-primary);
  border-radius: 22px;
  padding: 1.75rem 2rem;
  min-width: 22.5rem;
  display: flex;
  align-items: center;
  box-shadow:
    0 1px 0 rgba(43, 43, 52, 0.04),
    0 8px 24px rgba(43, 43, 52, 0.05);
}

/* Handoff 2026-05-15 P9: gap 0 — el spacing entre filas lo da ahora
 * el padding-vertical de cada `.report-kpi-row` + el hairline divider. */
.report-kpi-list {
  margin: 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 0;
}

/* Handoff 2026-05-15 P10: hairline divider entre filas + padding
 * vertical generoso. La primera row sin padding-top y la última sin
 * border-bottom para que la card cierre limpio en ambos extremos. */
.report-kpi-row {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  align-items: baseline;
  padding: 0.875rem 0;
  border-bottom: 1px solid var(--acq-border);
}
.report-kpi-row:first-child { padding-top: 0; }
.report-kpi-row:last-child {
  padding-bottom: 0;
  border-bottom: 0;
}

/* Handoff 2026-05-15 P11: label uppercase muted 0.75rem letter-spacing
 * 0.06em (era 400/text/0.9rem normal-case). Mejor jerarquía
 * label/cifra. `white-space: nowrap` SOLO en dt — "INGRESO RIGHT
 * HOLDER" ~20 chars debe caber en una línea; las cifras EUR (dd)
 * sí pueden wrap si crecen mucho, no las queremos nowrap forzado. */
.report-kpi-row dt {
  font-family: var(--acq-font-sans);
  font-weight: 500;
  color: var(--acq-text-muted);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin: 0;
  white-space: nowrap;
}

/* Handoff 2026-05-15 P12: cifra más prominente — Semibold 1.25rem
 * (era 700/1rem). La 3ª fila (Ingreso Right Holder) es la principal
 * del informe → turquesa bold para destacar como cifra de referencia. */
.report-kpi-row dd {
  font-family: var(--acq-font-sans);
  font-weight: 600;
  color: var(--acq-text);
  font-size: 1.25rem;
  margin: 0;
  font-variant-numeric: tabular-nums;
  font-feature-settings: var(--num-features);
  letter-spacing: -0.01em;
}
.report-kpi-row:last-child dd {
  color: var(--acq-primary);
  font-weight: 700;
}

/* Estado vacío del KPI (template emite `<dd class="kpi-empty">—</dd>`
 * cuando `data is None`). El placeholder no debe competir
 * visualmente con cifras reales — peso normal y color muted. */
.report-kpi-row dd.kpi-empty {
  color: var(--acq-text-muted);
  font-weight: 400;
}


/* Handoff 2026-05-16 W2: identidad pasa de row a column — display-name
 * arriba como protagonista visual, período abajo como caption con
 * bullet turquesa. Antes ambos iban inline y el badge pill competía
 * con el KPI box; ahora el período es subordinado. */
.report-sticky-identity {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.375rem;
}

/* Handoff 2026-05-16 W3: el periodo deja de ser pill (era padding +
 * border-radius 999px + bg surface-2 + border). Ahora caption muted
 * con bullet turquesa antes — más sutil, no compite con el KPI box. */
.report-period-badge {
  padding: 0;
  background: transparent;
  border: 0;
  color: var(--acq-text-muted);
  font-size: 0.95rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}
.report-period-badge::before {
  content: "";
  width: 6px;
  height: 6px;
  background: var(--acq-primary);
  border-radius: 999px;
  flex-shrink: 0;
}


/* -------------------------------------------------------------------
 * Sticky header del informe — handoff 2026-05-16 (parte web).
 *
 * Rediseño: identidad (display-name + período caption) + TOC tabs.
 * El botón Imprimir solitario se eliminó (Cmd+P universal + duplicaba
 * función con "Exportar contenido a PDF" del filter card). El
 * `counter-reset` inicia el contador que las `<section[id]>`
 * hermanas incrementan; el `::before` del h3 lo emite como
 * "01", "02", …, "05" (Inter Light turquesa grande + divider).
 * ------------------------------------------------------------------- */

.report-sticky {
  position: sticky;
  top: 0;
  background: var(--acq-bg);
  /* Handoff 2026-05-16 W1: 0.5rem 0 → 1.25rem 0 0 — respira
   * verticalmente para que la identidad del holder respire dentro
   * del sticky. */
  padding: 1.25rem 0 0;
  margin-bottom: 1.5rem;
  /* Handoff 2026-05-16 W1: sin border-bottom — el `.toc-tabs` ya
   * lleva su propio bottom border; duplicado se veía como doble
   * línea fina. */
  z-index: 10;
  /* Handoff 2026-05-16 W6: counter-reset inicializa el contador de
   * capítulo que las `<section[id]>` hermanas incrementan; permite
   * emitir "01", "02", … via `::before { content: counter(...) }`
   * sin JS ni cambios de template. */
  counter-reset: section-num;
}


/* -------------------------------------------------------------------
 * TOC del informe — handoff 2026-05-16.
 *
 * El TOC sigue siendo anchor scroll (`href="#resumen"` etc) — no son
 * tabs reales. Look de "tabs" con underline + active state via
 * scroll-spy.js. Conserva Cmd+F nativo + print-friendly del scroll.
 * ------------------------------------------------------------------- */

.toc-tabs {
  display: flex;
  flex-wrap: wrap;
  /* Handoff 2026-05-16 W4: gap 0.25/2rem → 0/1.75rem — items pegados
   * vertical (el espacio entre tabs es el visual rhythm); margin-top
   * 0.5 → 1.25rem para separar identity de TOC como bloques
   * independientes. */
  gap: 0 1.75rem;
  margin-top: 1.25rem;
  margin-bottom: 0;
  border-bottom: 1px solid var(--acq-border);
}

.toc-tab {
  display: inline-block;
  /* Handoff 2026-05-16 W5: padding 0.625/0.25 → 0.75/0.25 — touch
   * target mayor; font-weight 500 (era inherit default 400) —
   * tabs más legibles. */
  padding: 0.75rem 0.25rem;
  margin-bottom: -1px; /* solapa el border-bottom del nav */
  color: var(--acq-text-muted);
  text-decoration: none;
  border-bottom: 2px solid transparent;
  transition: color 0.15s ease, border-color 0.15s ease;
  font-size: 0.95rem;
  font-weight: 500;
}

.toc-tab:hover {
  color: var(--acq-primary);
}

.toc-tab.active {
  color: var(--acq-primary);
  border-bottom-color: var(--acq-primary);
  font-weight: 600;
}


/* -------------------------------------------------------------------
 * Chapter numbering — handoff 2026-05-16 W6.
 *
 * Las 5 secciones del informe (#resumen, #evolucion, #streaming,
 * #rrss, #paises) se numeran automáticamente "01" → "05" via CSS
 * counter sin cambios de template. Scope a las `<section[id]>` que
 * viven después de `<header class="report-sticky">`.
 * ------------------------------------------------------------------- */

.report-sticky ~ section[id] {
  counter-increment: section-num;
  /* margin-bottom 2.5 → 3rem — secciones largas con tablas necesitan
   * más aire entre ellas; scroll-margin-top 18 → 11rem — sticky
   * header redesignado es más bajo (sin botones, sin badge pill). */
  margin-bottom: 3rem;
  scroll-margin-top: 11rem;
}

.report-sticky ~ section[id] > h3 {
  /* h3 1.25 → 1.5rem — más presencia. Layout flex baseline para
   * alinear el chapter number a la izquierda del título. */
  font-size: 1.5rem;
  margin: 0 0 1.25rem 0;
  display: flex;
  align-items: baseline;
  gap: 1rem;
}

.report-sticky ~ section[id] > h3::before {
  content: counter(section-num, decimal-leading-zero);
  color: var(--acq-primary);
  font-weight: 300;
  font-size: 2rem;
  letter-spacing: -0.02em;
  line-height: 1;
  padding-right: 1rem;
  border-right: 1.5px solid var(--acq-border);
  font-variant-numeric: tabular-nums;
  font-feature-settings: var(--num-features);
}

/* h4 dentro de section (sub-tablas en streaming/rrss). Antes 1rem
 * muted; ahora 0.95rem semibold dark — sub-título distinguible sin
 * competir con h3. */
.report-sticky ~ section[id] h4 {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--acq-text);
  margin: 1.75rem 0 0.875rem 0;
  letter-spacing: -0.005em;
}
.report-sticky ~ section[id] h4:first-of-type {
  margin-top: 0;
}


/* -------------------------------------------------------------------
 * Chart containers — alturas responsive para Chart.js canvas.
 *
 * Chart.js con `maintainAspectRatio: false` se adapta al contenedor;
 * sin altura explícita el canvas colapsa a 0. `aspect-ratio: 1`
 * mantiene los donuts cuadrados; las barras toman 320px de alto.
 * ------------------------------------------------------------------- */

.chart-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 1.5rem;
  margin-bottom: 2rem;
}

/* `.chart-container` BACKSTAGE (mockup #3): card turquesa con bordes
 * redondeados generosos que contiene el canvas Chart.js. Los datasets
 * usan colores blancos translúcidos (configurados en el init JS de
 * cada chart) para que destaquen sobre el fondo turquesa.
 *
 * Handoff 2026-05-16 W12: padding 1.25 → 1.5/1.5/1.25 (más aire
 * arriba) + `position: relative` para anclar el overlay
 * `.donut-center` absolute-positioned con el TOTAL inscrito. */
.chart-container {
  position: relative;
  margin: 0;
  padding: 1.5rem 1.5rem 1.25rem;
  background: var(--acq-primary-hover);
  border: 0;
  border-radius: 16px;
  color: #FFFFFF;
  box-shadow: 0 2px 8px color-mix(in srgb, var(--acq-primary) 25%, transparent);
}

/* Handoff 2026-05-16 W12: figcaption pasa de cuerpo a leyenda
 * uppercase tracked — el caption es etiqueta del chart, no pie de
 * figura. */
.chart-container figcaption {
  color: rgba(255, 255, 255, 0.95);
  text-align: center;
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin-top: 0.75rem;
}

/* Donuts: cuadrados, máx 320×320 incluso si la celda del grid es
 * más ancha (auto-fit con `1fr` puede dar 600px+ en monitores grandes
 * con sólo 2 donuts). `max-width: 320px` + `margin-inline: auto`
 * mantiene el aspect ratio 1:1 y centra el canvas dentro del card.
 * Sin el `max-width`, `width: 100%` + `max-height: 320px` produce
 * elipses (canvas más ancho que alto). */
.chart-container canvas {
  width: 100% !important;
  max-width: 20rem;
  aspect-ratio: 1 / 1;
  max-height: 20rem;
  margin-inline: auto;
  display: block;
}

.chart-container-bars canvas {
  aspect-ratio: auto;
  height: 20rem !important;
  max-height: 20rem;
}


/* -------------------------------------------------------------------
 * `.donut-canvas` + `.donut-center` — handoff 2026-05-16 W13
 * (PRIMITIVO NUEVO).
 *
 * Overlay con el TOTAL inscrito en el hole del donut Chart.js.
 * El donut alone da proporciones; el TOTAL completa la lectura
 * ("qué fracción de QUÉ total"). `pointer-events: none` evita que
 * robe clicks de los wedges. Aplicado a los 2 donuts de #streaming
 * hoy; reusable en cualquier donut futuro del informe.
 *
 * `.donut-canvas` ciñe el canvas cuadrado: anclamos el overlay aquí
 * (no en `.chart-container`, que además lleva padding + figcaption)
 * para que el centro del overlay coincida con el centro real del
 * agujero del donut, sin offsets a ojo.
 * ------------------------------------------------------------------- */
.donut-canvas {
  position: relative;
}
.donut-center {
  position: absolute;
  top: 50%;
  left: 50%;
  /* −20px sobre el centro geométrico del canvas: Chart.js dibuja la
   * leyenda en la franja inferior del canvas, así que el círculo del
   * donut queda centrado en el área de ARRIBA. Subir el overlay lo
   * lleva al centro real del agujero. El offset es fijo porque la
   * leyenda tiene altura constante: ambos donuts llevan SIEMPRE los 5
   * STREAMING_BUCKETS y la ordenan igual (ver `legend.labels.sort` en
   * el init) → mismo nº de filas de leyenda en los dos. Si algún día un
   * donut tuviera un set de buckets variable, este −20px dejaría de
   * cuadrar y habría que anclar al círculo dinámicamente. */
  transform: translate(-50%, calc(-50% - 20px));
  text-align: center;
  pointer-events: none;
}
.donut-center-value {
  display: block;
  font-size: 1.5rem;
  font-weight: 700;
  color: #FFFFFF;
  letter-spacing: -0.02em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  font-feature-settings: var(--num-features);
}
.donut-center-label {
  display: block;
  margin-top: 0.25rem;
  font-size: 0.7rem;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.75);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}


/* -------------------------------------------------------------------
 * `.paises-mapa` — handoff 2026-05-16 W14 (PRIMITIVO NUEVO).
 *
 * Frame visual para el choropleth del mundo (matplotlib PNG inline).
 * Antes era `<figure>` bare; ahora card con borde + radius alineado
 * con `.chart-container` para consistencia visual entre el chart
 * grid y el mapa.
 * ------------------------------------------------------------------- */
.paises-mapa {
  margin: 0 0 1.5rem 0;
  padding: 1.5rem;
  background: var(--acq-surface-2);
  border: 1px solid var(--acq-border);
  border-radius: 16px;
}
.paises-mapa img {
  width: 100%;
  height: auto;
  display: block;
  border-radius: 8px;
}
.paises-mapa figcaption {
  color: var(--acq-text-muted);
  text-align: center;
  font-size: 0.85rem;
  margin-top: 0.75rem;
  font-style: italic;
}


/* -------------------------------------------------------------------
 * `:target` highlight — handoff 2026-05-16 W7.
 *
 * Cuando el operador hace click en una tab del TOC, la `<section>`
 * destino lanza una pulse animation corta para orientarle visualmente
 * tras el scroll. Antes era `box-shadow` estático; el pulse es más
 * empático sin dejar artifact permanente.
 * ------------------------------------------------------------------- */
section:target {
  animation: section-target-pulse 1.2s ease-out;
}
@keyframes section-target-pulse {
  0% { box-shadow: 0 0 0 0 var(--acq-primary-soft); }
  50% { box-shadow: 0 0 0 8px var(--acq-primary-soft); }
  100% { box-shadow: 0 0 0 0 transparent; }
}


/* -------------------------------------------------------------------
 * Filas TOTAL en tablas del informe — fondo distintivo + bold.
 *
 * El bold se aplica a TODAS las celdas de la fila vía CSS, no en
 * cada `<td>` con `<strong>` inline (sería 7+ wraps redundantes por
 * tabla, multiplicado por 5 tablas TOTAL). Templates más limpios y
 * un único punto de cambio si más adelante se quita el bold o se
 * cambia por otro indicador visual.
 * ------------------------------------------------------------------- */

/* Handoff 2026-05-16 W10: TOTAL row contractual reforzada.
 * - bg surface-2 → primary-soft (turquesa muy suave) — el TOTAL es
 *   la cifra que el right holder verifica primero.
 * - Top border 1.5px turquesa — separador visual fuerte vs filas
 *   de detalle del cuerpo.
 * - Bottom border 0 — el bg ya delimita; doble línea (top + bottom)
 *   se veía cargada.
 * - Padding vertical mayor — el TOTAL respira aparte del cuerpo. */
tr.report-total td,
.table-bare tbody tr.report-total td {
  background: var(--acq-primary-soft);
  border-top: 1.5px solid var(--acq-primary);
  border-bottom: 0;
  font-weight: 700;
  padding-top: 0.875rem;
  padding-bottom: 0.875rem;
}


/* -------------------------------------------------------------------
 * @media print — el operador hace Cmd+P en el navegador.
 *
 * Oculta nav top, sticky header (vuelve a static), botones y TOC.
 * Reintroduce page-breaks entre secciones porque WeasyPrint usaba
 * `page-break-after` y aquí queremos que la impresión del navegador
 * respete saltos similares. Forzar colores B&W para tinta y para
 * que los charts en PNG (que tienen colores) no se desangren.
 * ------------------------------------------------------------------- */

@media print {
  /* Oculta cualquier elemento marcado `.no-print` — clase utility
   * que se aplica a la topbar (Phase 7), al TOC del informe y a
   * los botones de acción. Una sola estrategia (clase) en lugar de
   * mezclar selector estructural + clase: más resiliente a
   * refactors del HTML. */
  .no-print {
    display: none !important;
  }

  /* Neutralizar el flex column del topbar-shell en print: el
   * `min-height: 100vh` fuerza la primera página a ≥ 1 viewport,
   * dejando huecos en blanco si el contenido es corto. `display:
   * block` evita cualquier sorpresa de flex en el flow del print. */
  body.topbar-shell {
    display: block !important;
    min-height: 0 !important;
  }

  .content {
    max-width: none !important;
    padding: 0 !important;
  }

  /* El sticky header pierde el sticky para que se imprima sólo una
   * vez al inicio. */
  .report-sticky {
    position: static !important;
    border-bottom: 1px solid #ccc !important;
    padding: 0 !important;
    z-index: auto !important;
  }

  /* Forzar colores imprimibles. Las tablas con fondos claros se
   * mantienen pero quitamos cualquier tono dark del tema. BACKSTAGE
   * añade fondos turquesa en `.kpi-card`, `.chart-container`,
   * `.report-filter-form`, `.analytics-filter-bar` y `.subnav-pill`
   * — todos se neutralizan a blanco + texto negro para imprimir
   * legible sobre papel sin gastar tinta turquesa. */
  body,
  main,
  article,
  .kpi-card,
  .chart-container,
  .report-filter-form,
  .analytics-filter-bar,
  .subnav-pill,
  .report-kpi-aside {
    background: white !important;
    color: black !important;
    box-shadow: none !important;
  }

  /* Bordes hairline grey claro para preservar la estructura visual
   * de cards/aside cuando se neutraliza el fondo turquesa. */
  .kpi-card,
  .chart-container,
  .report-filter-form,
  .analytics-filter-bar,
  .report-kpi-aside {
    border: 1px solid #ccc !important;
  }

  /* Tipografía interna a negro: en pantalla los `.kpi-header`,
   * `.kpi-value`, `.kpi-unit`, etc. son blancos sobre turquesa;
   * en print pasamos a negro sobre blanco. */
  .kpi-header,
  .kpi-value,
  .kpi-unit,
  .kpi-footer small,
  .subnav-pill-title,
  .subnav-pill-tab,
  .report-filter-export,
  .report-export-link {
    color: black !important;
  }

  /* Inputs de filtros: el negativo blanco-on-turquesa pasa a
   * neutral. */
  .report-filter-input {
    background: white !important;
    color: black !important;
    border: 1px solid #ccc !important;
  }

  /* Cada sección del informe (resumen, evolución, streaming, rrss,
   * países) en una página nueva — coherente con el PDF actual.
   * Lógica inversa (`:not(:first-of-type)`) en lugar de poner
   * page-break en todas y luego excepción en la primera: si Phase
   * 6+ reordena las secciones, la regla "todas las non-first
   * empiezan en página nueva" sigue siendo correcta sin override. */
  section:not(:first-of-type) {
    page-break-before: always;
  }

  /* `:target` highlight no debe imprimirse — neutralizamos el
   * `box-shadow` que aplica `section:target` en pantalla. */
  section:target {
    box-shadow: none !important;
  }

  /* Tablas: evitar partir filas entre páginas. Las cabeceras se
   * repiten en cada página de la tabla. */
  table {
    page-break-inside: avoid;
  }

  table thead {
    display: table-header-group;
  }

  table tbody tr {
    page-break-inside: avoid;
  }

  /* Charts a tamaño completo, evitar partirlos. */
  figure img {
    max-width: 100% !important;
    page-break-inside: avoid;
  }

  /* Quitar subrayados y colores de los links — al imprimir no son
   * clickables. */
  a {
    color: inherit !important;
    text-decoration: none !important;
  }
}


/* -------------------------------------------------------------------
 * Analíticas dashboard (Phase 6).
 *
 * Filter bar turquesa estilo screenshot del usuario + tabla pivot
 * con dual header (MES DE FACTURACIÓN / MES DEL INFORME) y
 * sticky-first-column para que el nombre del artista quede visible
 * al scrollear meses.
 * ------------------------------------------------------------------- */

/* -------------------------------------------------------------------
 * Handoff analytics 2026-05-18 — rediseño del filter bar
 *
 * Reemplaza el bloque anterior (Phase 8 + Handoff 2026-05-17 + iter
 * 5 + defensive resets). La nueva estructura es PLANA:
 *
 *   .analytics-filter-bar
 *   ├─ .filter-grid-primary   (grid 10 cols, aloja TODOS los selects
 *   │                          y los 3 inputs de búsqueda como
 *   │                          siblings directos; cada control va
 *   │                          dentro de un .field-wrap > .field)
 *   ├─ .filter-meta           (línea hairline-separated con
 *   │                          threshold + checkbox + export)
 *   └─ details.filter-advanced (DSP + Geografía colapsable)
 *
 * Eliminados (selectores muertos en el DOM tras este handoff):
 *   .filter-row-primary, .filter-row-search, .search-inputs,
 *   .action-cluster-right, .filter-search-button,
 *   .analytics-context-chip + .ctx-*, .filter-checkbox-inline,
 *   .filter-threshold-input-wrap, .filter-threshold-unit,
 *   .filter-advanced-summary-label.
 *
 * Tokens anclados a `assets/styles.css` del bundle de design original
 * (las variables --teal, --teal-h, --teal-soft, --ink, --ink-soft,
 * --line, --surface-2 están mapeadas a sus equivalentes --acq-* del
 * live).
 * ------------------------------------------------------------------- */

/* ---- Subnav pill — alineado con assets/styles.css 252-284 ---- */
/* (El selector `.subnav-pill` global vive más arriba en este archivo
 * para Royalties / Opciones. Aquí no se duplica.) */

/* ---- Analytics header ---- */
.analytics-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.5rem;
  margin-bottom: 1.25rem;
}
.analytics-h2 {
  font-size: 1.75rem;
  font-weight: 600;
  letter-spacing: -0.015em;
  margin: 0;
}
.analytics-meta {
  font-size: 0.8125rem;
  color: var(--acq-text-muted);
  margin: 0;
}
.analytics-meta strong {
  color: var(--acq-text);
  font-weight: 500;
}

/* ---- Filter bar — bg teal por WCAG 3:1 con texto blanco. El
 * handoff sugiere `var(--acq-primary)` #06B8AD (canónico
 * `assets/styles.css` línea 14), pero `#06B8AD` sobre blanco da
 * solo 2.48:1 → falla 1.4.11. El hover-tone `#059992` da 3.05:1
 * (pasa con margen). La diferencia visual es imperceptible (~3%
 * lightness) y se mantiene para preservar el guardián WCAG
 * `test_styles_filter_forms_use_primary_hover_for_wcag` y la
 * coherencia con `.kpi-card` y `.chart-container` que también
 * usan el hover-tone. ---- */
.analytics-filter-bar {
  background: var(--acq-primary-hover);
  border-radius: 20px;
  padding: 1.5rem 1.75rem;
  margin-bottom: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 1.125rem;
  color: #FFFFFF;
}
.analytics-filter-bar label { color: #FFFFFF; margin: 0; }

/* ---- Grid principal 10 cols: spans inline en el template ---- */
.filter-grid-primary {
  display: grid;
  grid-template-columns: repeat(10, minmax(0, 1fr));
  gap: 0.875rem 0.75rem;
  /* Trello #1 item 2: todas las CAJAS de control miden 44px y se anclan
   * arriba, bajo su label de una sola línea (ver `white-space: nowrap`
   * en los labels), así quedan a la misma altura. Los tag-inputs de
   * artista/pista pintan sus chips DEBAJO de la caja (no dentro), de
   * modo que añadir chips crece hacia abajo sin empujar a los vecinos. */
  align-items: start;
}

/* ---- field-wrap: label + .field stacked ---- */
.filter-grid-primary .field-wrap {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  min-width: 0;
}
.filter-grid-primary .field-label {
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.7);
  /* Trello #1 item 2: una sola línea para que todas las cajas de control
   * arranquen a la misma altura (un label de 2 líneas como "Segundo
   * nivel" bajaba su caja respecto a los vecinos). */
  white-space: nowrap;
}

/* ---- .field — replica del patrón canónico de assets/styles.css 357 ---- */
.filter-grid-primary .field {
  display: inline-flex;
  align-items: center;
  height: 44px;
  padding: 0 0.875rem;
  border-radius: 12px;
  background: #FFFFFF;
  font-size: 0.875rem;
  color: var(--acq-text);
  gap: 0.625rem;
  min-width: 0;
  box-sizing: border-box;
}
.filter-grid-primary .field > select,
.filter-grid-primary .field > input {
  flex: 1 1 auto;
  height: 100%;
  background: transparent;
  border: 0;
  font: inherit;
  color: var(--acq-text);
  padding: 0;
  margin: 0;
  appearance: none;
  -webkit-appearance: none;
  min-width: 0;
  outline: none;
}
.filter-grid-primary .field > input::placeholder {
  color: var(--acq-text-mute, #9A9AA1);
}
.filter-grid-primary .field .chev {
  color: var(--acq-text-mute, #9A9AA1);
  font-size: 0.6875rem;
  pointer-events: none;
  flex: 0 0 auto;
}

/* ============================================================
 * MULTI-CHIP — filter chip multi-select con popover anclado.
 * Bundle del handoff Claude Design 2026-05-19 (multi_chip_bundle).
 *
 * El chip se renderiza dentro de un `.filter-field` (mismo wrapper
 * que el resto de campos del filter bar). El `<summary>` matchea
 * box-model de los `<select>` y `<input>` adyacentes: misma altura,
 * mismo radius (10px), mismo padding, misma fuente.
 *
 * Contextos:
 *   1. `.analytics-filter-bar .filter-field .multi-chip-details`
 *      → inside el filter bar teal. Summary white sin border.
 *   2. `.multi-chip-field .multi-chip-details` standalone
 *      → fuera del filter bar (Dashboard, Salud, Backups). Summary
 *        white con 1px border var(--acq-border).
 *
 * Wire format intacto: cada opción es
 *   <input type="checkbox" name="<name>" value="<value>">
 * El browser envía N pares al submit. FastAPI deserializa como list.
 * ============================================================ */


/* ---------- Wrapper field ---------- */
.multi-chip-field {
    /* span se aplica por inline style="grid-column: span N;" */
}


/* ---------- Details / wrapper del popover ----------
 * Reset defensivo de los defaults de Pico v2 sobre <details>:
 * `padding-bottom`, `border-bottom`, `margin-bottom` del summary
 * cuando [open]. Sin esto el `.filter-field` cell crece 1rem al
 * abrir y el chip salta por culpa de `align-items: end`. */
.multi-chip-details {
    position: relative;
    display: block;
    margin: 0;
    padding: 0;
    border: 0;
    min-width: 0;
}
.multi-chip-details[open] > .multi-chip-summary {
    margin-bottom: 0;
}


/* ---------- Summary (el chip cerrado) ---------- */
.multi-chip-summary {
    list-style: none;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
    min-width: 0;
    padding: 0.5rem 0.75rem;
    background: #FFFFFF;
    border: 0;
    border-radius: 10px;
    font-family: inherit;
    font-size: 0.875rem;
    line-height: 1.4;
    color: var(--acq-text);
    cursor: pointer;
    user-select: none;
    box-sizing: border-box;
    transition: box-shadow 0.15s ease, background 0.15s ease;
}

.multi-chip-summary:hover {
    box-shadow: 0 0 0 2px rgba(255, 255, 255, 0.25);
}
.multi-chip-summary:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--acq-primary-soft);
}

/* Pico v2 quirks — anula marker nativo + chevron de fondo */
.multi-chip-details > summary::-webkit-details-marker { display: none; }
.multi-chip-details > summary::after {
    display: none;
    content: none;
    background: none;
    background-image: none;
    width: 0;
    height: 0;
}

/* Estado abierto: ring teal-soft + sube box-shadow */
.multi-chip-details[open] > .multi-chip-summary {
    box-shadow: 0 0 0 2px var(--acq-primary), 0 1px 2px rgba(0,0,0,0.04);
}

/* Estado multi-activo (>=1 selección).
   Indicador principal: punto teal — DOM real (.multi-chip-dot),
   no ::before, porque los engines colapsan ::before a 0×0 sobre
   <summary> (display: list-item por default). La macro emite el
   span siempre; CSS lo muestra cuando data-active.
   Indicador secundario: value en bold + tint teal-soft del bg en
   contexto standalone (sobre filter-bar teal el tint era invisible). */
.multi-chip-dot {
    flex: 0 0 auto;
    visibility: hidden;
    width: 0.4375rem;
    height: 0.4375rem;
    border-radius: 999px;
    background: var(--acq-primary);
}
.multi-chip-summary[data-active="true"] > .multi-chip-dot {
    visibility: visible;
}
.multi-chip-summary[data-active="true"] .multi-chip-value {
    color: var(--acq-text);
    font-weight: 600;
}
/* Tint del bg sólo en contexto standalone (white page bg). En el
   filter bar teal el chip queda blanco — el dot teal hace de signal único. */
.multi-chip-field:not(.analytics-filter-bar *)
    .multi-chip-summary[data-active="true"] {
    background: var(--acq-primary-soft);
    border-color: var(--acq-primary);
}


/* ---------- Contexto STANDALONE (fuera del .analytics-filter-bar) ---------- */
.multi-chip-field:not(.analytics-filter-bar *) .multi-chip-summary {
    border: 1px solid var(--acq-border);
}
.multi-chip-field:not(.analytics-filter-bar *) .multi-chip-summary:hover {
    border-color: var(--acq-primary);
    box-shadow: none;
}
.multi-chip-field:not(.analytics-filter-bar *)
    .multi-chip-details[open] > .multi-chip-summary {
    border-color: var(--acq-primary);
    box-shadow: 0 0 0 3px var(--acq-primary-soft);
}


/* ---------- Contexto FILTER BAR de /analytics ----------
 * Trello #1 item 2: el chip de Sello/Distribuidor vive en el mismo grid
 * (`.filter-grid-primary`) que los `<select>`/`<input>`, que usan
 * `.field` con `height: 44px` y `border-radius: 12px`. El summary base
 * es padding-based (~36px, radius 10px), así que quedaba más BAJO que
 * los dropdowns vecinos → su borde inferior no alineaba con la fila.
 * Igualamos el box-model para que Sello/Distribuidor queden a la misma
 * altura que el resto de campos del filtro. */
.analytics-filter-bar .multi-chip-summary {
    height: 44px;
    padding: 0 0.875rem;
    border-radius: 12px;
}

/* Trello #1 items 5 + 2: los tag-inputs de Artista/Pista del filter bar.
 * El contenedor NO es la caja blanca: es un flex en columna transparente.
 * La caja blanca es el `<input>` (44px, radius 12px) — idéntica a los
 * `.field` vecinos para que cuadre la fila. Los chips seleccionados se
 * pintan DEBAJO del input (`order` los manda abajo), no dentro, así no
 * roban espacio a la zona de escritura ni cambian la altura de la caja.
 * Con `align-items: start` del grid, añadir chips crece hacia abajo sin
 * empujar a los controles vecinos. */
.analytics-filter-bar .tag-input-container {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    background: transparent;
    border: 0;
    border-radius: 0;
    padding: 0;
    min-height: 0;
    /* La regla base `.tag-input-container` trae `align-items: center`
     * (layout en fila del admin); en columna eso centraba los chips bajo
     * el input. `stretch` los deja alineados a la izquierda como los de
     * país. */
    align-items: stretch;
}
.analytics-filter-bar .tag-input-container .tag-chips {
    justify-content: flex-start;
}
.analytics-filter-bar .tag-input-container:focus-within {
    box-shadow: none;
}
.analytics-filter-bar .tag-input-container .tag-input {
    order: -1; /* el input arriba; los chips quedan debajo */
    height: 44px;
    width: 100%;
    flex: none;
    background: #FFFFFF;
    border-radius: 12px;
    padding: 0 0.875rem;
    box-sizing: border-box;
    /* El filter bar fija `color:#fff`; sobre la caja blanca el texto
     * tecleado quedaba invisible. Forzamos texto oscuro + placeholder
     * legible. */
    color: var(--acq-text);
}
.analytics-filter-bar .tag-input-container .tag-input::placeholder {
    color: var(--acq-text-mute, #9a9aa1);
}
.analytics-filter-bar .tag-input-container .tag-input:focus {
    outline: none;
    box-shadow: 0 0 0 2px var(--acq-primary);
}
/* `.tag-chips` deja de ser `display: contents` aquí para ser una fila
 * real DEBAJO del input que envuelve los chips. Oculta si no hay chips
 * (evita un hueco vacío por el `gap`). */
.analytics-filter-bar .tag-input-container .tag-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
}
/* `:not(:has(.tag-chip))` en vez de `:empty` porque el markup del macro
 * deja whitespace (text nodes) y `:empty` no matchearía → quedaba un
 * hueco bajo el input cuando no hay chips. */
.analytics-filter-bar .tag-input-container .tag-chips:not(:has(.tag-chip)) {
    display: none;
}
/* Chips legibles sobre el filter bar teal: fondo blanco, texto oscuro
 * (el primary-soft base se confundía con el teal del bar). */
.analytics-filter-bar .tag-input-container .tag-chip {
    background: #FFFFFF;
    color: var(--acq-text);
}


/* ---------- Value + chevron dentro del summary ---------- */
.multi-chip-value {
    flex: 1 1 auto;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    font-weight: 500;
}
.multi-chip-chevron {
    width: 0.625rem;
    height: 0.375rem;
    flex: 0 0 auto;
    color: var(--acq-text-muted);
    transition: transform 0.15s ease, color 0.15s ease;
}
.multi-chip-details[open] > .multi-chip-summary .multi-chip-chevron {
    transform: rotate(180deg);
    color: var(--acq-primary);
}


/* ---------- Estado vacío (Distribuidor sin datos) ---------- */
.multi-chip-details[data-empty="true"] > .multi-chip-summary {
    background: var(--acq-surface-2);
}
.multi-chip-details[data-empty="true"] .multi-chip-value,
.multi-chip-details[data-empty="true"] .multi-chip-chevron {
    color: var(--acq-text-muted);
    font-style: italic;
    font-weight: 400;
}


/* ---------- Popover ----------
 * Forzamos display:block (override UA hiding de `<details>`) y
 * controlamos visibilidad por opacity + transform + visibility
 * para conseguir la transición CSS al abrir. */
.multi-chip-popover {
    display: block;
    position: absolute;
    top: calc(100% + 0.375rem);
    left: 0;
    min-width: 12.5rem;
    max-width: 22rem;
    max-height: 18rem;
    overflow-y: auto;
    padding: 0.375rem;
    margin: 0;
    background: #FFFFFF;
    border: 1px solid var(--acq-border);
    border-radius: 0.625rem;
    box-shadow:
        0 1px 0 rgba(0, 0, 0, 0.04),
        0 12px 32px rgba(43, 43, 52, 0.18);
    z-index: 50;

    opacity: 0;
    visibility: hidden;
    transform: translateY(-4px);
    pointer-events: none;
    transition:
        opacity 120ms ease-out,
        transform 120ms ease-out,
        visibility 0ms linear 120ms;
}
.multi-chip-details[open] > .multi-chip-popover {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    pointer-events: auto;
    transition:
        opacity 120ms ease-out,
        transform 120ms ease-out,
        visibility 0ms linear 0ms;
}

.multi-chip-details[data-anchor="right"] > .multi-chip-popover {
    left: auto;
    right: 0;
}


/* ---------- Option (label + checkbox) ---------- */
.multi-chip-option {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0.5rem 0.625rem;
    margin: 0;
    border-radius: 0.375rem;
    cursor: pointer;
    user-select: none;
    font-size: 0.875rem;
    color: var(--acq-text);
    line-height: 1.4;
    transition: background 0.1s ease;
}
.multi-chip-option:hover,
.multi-chip-option:focus-within {
    background: var(--acq-surface-2);
}
.multi-chip-option input[type="checkbox"] {
    width: 1rem;
    height: 1rem;
    margin: 0;
    accent-color: var(--acq-primary);
    flex: 0 0 auto;
    cursor: pointer;
}
.multi-chip-option input[type="checkbox"]:focus-visible {
    outline: 2px solid var(--acq-primary);
    outline-offset: 2px;
}
.multi-chip-option:has(input:checked) {
    color: var(--acq-primary);
    font-weight: 500;
}
.multi-chip-option-label {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.multi-chip-option-label.capitalize {
    text-transform: capitalize;
}

/* Defensa contra cascada del filter-bar teal:
   `.analytics-filter-bar label { color: #FFFFFF }` afecta a TODOS
   los <label> descendientes, incluyendo los `.multi-chip-option`
   del popover → texto blanco sobre bg blanco = invisible.
   Bumpeamos specificity y reseteamos color. */
.multi-chip-popover .multi-chip-option,
.multi-chip-popover .multi-chip-option .multi-chip-option-label {
    color: var(--acq-text);
}
.multi-chip-popover .multi-chip-option:has(input:checked),
.multi-chip-popover .multi-chip-option:has(input:checked) .multi-chip-option-label {
    color: var(--acq-primary);
}


/* ---------- Empty state (popover) ---------- */
.multi-chip-empty {
    padding: 0.875rem 0.75rem;
    margin: 0;
    font-size: 0.8125rem;
    font-style: italic;
    color: var(--acq-text-muted);
    text-align: center;
    line-height: 1.5;
}


/* ---------- Variants por vista ---------- */
.multi-chip-field.multi-chip--compact {
    max-width: 15rem;
}
/* Popover de un chip compacto (Sello: pocas opciones y cortas). El
 * `min-width: 12.5rem` base lo deja sobredimensionado para "Acqustic"/
 * "Voltereta": la tarjeta se ve grande y la fila resaltada parece no
 * llenarla (hueco a la derecha). Lo ajustamos al contenido — al menos
 * tan ancho como el trigger — para que cada fila ocupe el ancho real y la
 * tarjeta quede ceñida a las opciones. */
.multi-chip--compact .multi-chip-popover {
    min-width: 100%;
    width: max-content;
}
.multi-chip-field.multi-chip--inline {
    width: auto;
    min-width: 11rem;
}

/* ---- Meta row hairline ---- */
.filter-meta {
  display: grid;
  grid-template-columns: auto auto 1fr auto auto;
  align-items: center;
  gap: 1.125rem;
  padding-top: 1.125rem;
  border-top: 1px solid rgba(255, 255, 255, 0.15);
  font-size: 0.8125rem;
  color: rgba(255, 255, 255, 0.92);
}
.filter-meta-spacer { display: block; }
/* Variante de la fila de export en modo matriz: sus hijos visibles son
 * spacer + 2 botones (Excel/PDF) — no los 5 de la fila normal. Con el
 * grid de 5 pistas heredado, el spacer quedaba a la izquierda (ancho 0)
 * y el botón PDF se estiraba en el `1fr`. Con 3 pistas `1fr auto auto`
 * el spacer empuja ambos botones a la derecha, como en la fila normal. */
.filter-meta-matriz { grid-template-columns: 1fr auto auto; }
.filter-meta-item {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  white-space: nowrap;
}
.filter-threshold input[type="number"] {
  width: 56px;
  height: 32px;
  padding: 0 0.5rem;
  border-radius: 8px;
  border: 0;
  background: rgba(255, 255, 255, 0.92);
  color: var(--acq-text);
  text-align: right;
  font: inherit;
  margin: 0;
}
.filter-check input[type="checkbox"] {
  width: 16px;
  height: 16px;
  accent-color: #FFFFFF;
  margin: 0;
}

/* ---- Export button — replica de .btn dark variant ---- */
.btn-export {
  height: 36px;
  padding: 0 1.125rem;
  border: 0;
  border-radius: 999px;
  background: var(--acq-text);
  color: #FFFFFF;
  font-family: inherit;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: none;
  cursor: pointer;
  white-space: nowrap;
  width: auto;
  margin: 0;
  transition: background 0.15s ease;
}
.btn-export:hover { background: #1c1c22; }

/* ---- Details — discreto, link-style ---- */
.filter-advanced { margin: 0; }
.filter-advanced-summary {
  list-style: none;
  cursor: pointer;
  user-select: none;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  /* Trello #1: el texto «Más filtros» en blanco sobre el teal del bar
   * (#059992) daba ~3.5:1 (ilegible a este tamaño). Lo metemos en una
   * pill con fondo oscuro translúcido: oscurece el fondo bajo el texto
   * y sube el contraste del blanco muy por encima de 4.5:1. Sin
   * subrayado punteado (ensuciaba la lectura). */
  padding: 0.4rem 0.75rem;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.28);
  font-size: 0.8125rem;
  font-weight: 600;
  text-decoration: none;
  width: fit-content;
}
/* Color del texto bulletproof contra los estados de <summary> de Pico
 * (default oscuro, hover primary, [open] gris): forzamos blanco en
 * TODOS los estados con specificity alta (3 clases + element) y también
 * sobre el <span> interno. Trello #1. */
.analytics-filter-bar .filter-advanced > summary.filter-advanced-summary,
.analytics-filter-bar .filter-advanced[open] > summary.filter-advanced-summary,
.analytics-filter-bar .filter-advanced > summary.filter-advanced-summary:hover,
.analytics-filter-bar .filter-advanced > summary.filter-advanced-summary:focus,
.analytics-filter-bar .filter-advanced > summary.filter-advanced-summary span {
  color: #ffffff;
}
.filter-advanced-summary:hover {
  background: rgba(0, 0, 0, 0.38);
}
.analytics-filter-bar .filter-advanced > summary::-webkit-details-marker {
  display: none;
}
.analytics-filter-bar .filter-advanced > summary::after {
  display: none;
  content: none;
  background: none;
  background-image: none;
  width: 0;
  height: 0;
}
.analytics-filter-bar .filter-advanced > summary::before {
  content: "+";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border: 1px solid rgba(255, 255, 255, 0.5);
  border-radius: 999px;
  font-size: 0.75rem;
  line-height: 1;
}
.analytics-filter-bar .filter-advanced[open] > summary::before { content: "−"; }
.filter-advanced-badge {
  display: inline-flex;
  align-items: center;
  padding: 1px 0.4375rem;
  background: var(--acq-error);
  color: #FFFFFF;
  border-radius: 4px;
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.04em;
}
/* El `display: inline-flex` de autor gana sobre la regla UA `[hidden]`,
 * así que sin esto el atributo `hidden` (count 0) no ocultaría el badge. */
.filter-advanced-badge[hidden] { display: none; }

/* ---- Filter advanced body — DSP + Geografía ---- */
.filter-advanced[open] .filter-advanced-body {
  margin-top: 0.875rem;
  padding: 0.875rem 0 0;
  border-top: 1px solid rgba(255, 255, 255, 0.15);
  display: grid;
  /* Trello #1 (panel filtros): Lanzamiento y Geografía comparten la fila
   * superior (2 cols); DSP ocupa una fila propia a ancho completo debajo
   * (`grid-column: 1 / -1`), porque tiene muchos checkboxes y necesita
   * espacio para envolver sin descuadrar a los otros dos. */
  grid-template-columns: 1fr 1fr;
  /* Trello #1: gap de fila pequeño (0.3rem) para que DSP (fila 2) quede
   * bien pegado a Lanzamiento/Geografía (fila 1). Col gap se mantiene. */
  gap: 0.3rem 1.25rem;
  /* Trello #1: `start` (no `end`) → las 3 columnas alinean su label
   * arriba y su caja de control justo debajo, a la misma altura. Con
   * `end` los labels bailaban porque la columna de Geografía es más
   * alta (chips). */
  align-items: start;
}
/* Lanzamiento dentro del «Más filtros»: misma caja blanca 44px que los
 * `.field` de las filas superiores (el selector `.field` base está
 * scopeado a `.filter-grid-primary`, así que lo replicamos aquí). */
.filter-advanced-body .field {
  display: inline-flex;
  align-items: center;
  height: 44px;
  padding: 0 0.875rem;
  border-radius: 12px;
  background: #ffffff;
  font-size: 0.875rem;
  color: var(--acq-text);
  min-width: 0;
  box-sizing: border-box;
}
.filter-advanced-body .field > input {
  flex: 1 1 auto;
  height: 100%;
  background: transparent;
  border: 0;
  font: inherit;
  color: var(--acq-text);
  padding: 0;
  margin: 0;
  min-width: 0;
  outline: none;
}

/* Trello #1: uniformar tamaños dentro de «Más filtros». Las 3 cajas
 * (Lanzamiento, DSP, Geografía) a 44px de alto y radius 12; los chips
 * de DSP y Geografía con la MISMA altura/tipografía/radio para que no
 * desentonen entre sí. */
/* DSP a ancho completo en su propia fila (Trello #1): así sus pills
 * envuelven con holgura sin forzar la altura de Lanzamiento/Geografía. */
.filter-advanced-body .filter-field-dsp {
  grid-column: 1 / -1;
}
.filter-advanced-body .filter-checkbox-group {
  min-height: 44px;
  border-radius: 12px;
  /* DSP a ancho completo: reparte los checkboxes uniformemente por todo
   * el ancho del box (Trello #1) en vez de amontonarlos a la izquierda. */
  justify-content: space-between;
}
.filter-advanced-body .filter-territorio-input {
  height: 44px;
  border: 0;
  border-radius: 12px;
  padding: 0 0.875rem;
  box-sizing: border-box;
  background: #ffffff;
  color: var(--acq-text);
  /* El input va ANTES que los chips (que se pintan debajo), igual que
   * los tag-inputs de artista/pista — así su caja alinea con Lanzamiento
   * y DSP. El label es order 0; input order 1; chips order 2. */
  order: 1;
}
.filter-advanced-body .filter-territorio-chips {
  order: 2;
  /* Sin reserva de alto cuando no hay chips (antes 1.6rem dejaba hueco
   * bajo el input). Crece con los chips. */
  min-height: 0;
  margin-top: 0.35rem;
}
/* Colapsa la fila de chips de país cuando no hay ninguno (whitespace del
 * loop Jinja impide usar `:empty`); así Geografía no es más alta que
 * Lanzamiento y DSP sube pegado a la fila 1. */
.filter-advanced-body .filter-territorio-chips:not(:has(.acq-chip)) {
  display: none;
}
.filter-advanced-body .filter-checkbox-item,
.filter-advanced-body .acq-chip {
  min-height: 26px;
  font-size: 0.8125rem;
  border-radius: 8px;
  box-sizing: border-box;
}
/* El chip de país debe verse IDÉNTICO a los chips de artista/pista/
 * lanzamiento (`.tag-chip`): mismas dimensiones exactas (alto 24px,
 * padding, fuente, line-height, gap, pill blanco). El `min-height:26px`
 * de la regla compartida de arriba lo hacía más alto → lo anulamos. */
.filter-advanced-body .acq-chip {
  border: 0;
  background: #ffffff;
  color: var(--acq-text);
  border-radius: 999px;
  height: 24px;
  min-height: 0;
  padding: 0 0.4rem 0 0.625rem;
  font-size: 0.825rem;
  line-height: 1;
  gap: 0.35rem;
}

/* Trello #1: TODOS los chips del filter bar (artista/pista/lanzamiento =
 * `.tag-chip`, y país = `.acq-chip`) deben ser idénticos. Las reglas base
 * en conflicto daban alturas distintas; esta regla unificada (al final,
 * gana por orden de cascada sobre las (0,2,0) previas) fija un único
 * box-model con `box-sizing: border-box`. */
.analytics-filter-bar .tag-chip,
.analytics-filter-bar .acq-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  height: 26px;
  min-height: 0;
  padding: 0 0.45rem 0 0.7rem;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: var(--acq-text);
  font-size: 0.8125rem;
  font-weight: 500;
  line-height: 1;
  box-sizing: border-box;
  white-space: nowrap;
}
@media (max-width: 64em) {
  .filter-advanced[open] .filter-advanced-body {
    grid-template-columns: 1fr;
  }
}

/* `.filter-checkbox-group` y `.filter-checkbox-item` se mantienen con
 * los estilos previos (pills de DSP con `:has(input:checked)` →
 * primary-soft). Compatibilidad cubierta: ambos siguen viviendo
 * dentro de `.filter-advanced-body > .filter-field` que conserva su
 * `.filter-field-label`. */
.analytics-filter-bar .filter-field {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
  min-width: 0;
}
.analytics-filter-bar .filter-field-label {
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.7);
  white-space: nowrap;
}

.filter-checkbox-group {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem 0.625rem;
  padding: 0.5rem 0.625rem;
  background: var(--acq-surface);
  border: 0;
  border-radius: 10px;
  min-height: 2.875rem;
  align-content: center;
}
.analytics-filter-bar .filter-checkbox-item {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0;
  font-size: 0.85rem;
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
  color: var(--acq-text);
  padding: 0.25rem 0.625rem;
  border-radius: 6px;
  transition: background 0.15s ease;
}
.analytics-filter-bar .filter-checkbox-item:hover {
  background: var(--acq-surface-2);
}
.analytics-filter-bar .filter-checkbox-item:has(input:checked) {
  background: var(--acq-primary-soft);
  color: var(--acq-primary);
  font-weight: 600;
}
.filter-checkbox-item input[type="checkbox"] {
  margin: 0;
  width: 1rem;
  height: 1rem;
  flex: 0 0 auto;
  accent-color: var(--acq-primary);
}

/* ---- Geografía widget (chips + datalist) — sin cambios estructurales ---- */
.filter-territorio-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem;
  margin: 0;
  padding: 0;
  min-height: 1.6rem;
}
.acq-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.1rem 0.25rem 0.1rem 0.5rem;
  font-size: 0.8125rem;
  background: var(--acq-surface);
  color: var(--acq-text);
  border: 1px solid var(--acq-border);
  border-radius: 12px;
  line-height: 1.4;
}
.acq-chip-label {
  max-width: 14rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.acq-chip-remove {
  appearance: none;
  background: transparent;
  border: 0;
  padding: 0 0.2rem;
  margin: 0;
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  color: var(--acq-text-muted);
  border-radius: 50%;
  flex: 0 0 auto;
  width: auto;
  min-width: 0;
}
.acq-chip-remove:hover {
  color: var(--acq-primary);
  background: color-mix(in srgb, var(--acq-primary) 15%, transparent);
}
.filter-territorio-input {
  background: var(--acq-surface);
  color: var(--acq-text);
  border: 1px solid var(--acq-border);
  border-radius: 10px;
  padding: 0.5rem 0.75rem;
  width: 100%;
  font: inherit;
  margin: 0;
}

/* ---- Loading indicator HTMX ---- */
.pivot-loading {
  display: none;
  align-items: center;
  gap: 0.5rem;
  color: #FFFFFF;
  font-size: 0.875rem;
  font-weight: 600;
}
.pivot-loading.htmx-request { display: inline-flex; }
.pivot-loading::before {
  content: "";
  display: inline-block;
  width: 1rem;
  height: 1rem;
  border: 2px solid rgba(255, 255, 255, 0.4);
  border-top-color: #FFFFFF;
  border-radius: 50%;
  animation: pivot-spin 0.8s linear infinite;
}
@keyframes pivot-spin {
  to { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  .pivot-loading::before { animation: none; }
}

/* ---- Pivot summary chips — reusa el patrón .pill / .pill.teal ---- */
.pivot-summary {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
  margin: 1.25rem 0 1rem;
}
.pivot-summary-label {
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--acq-text-muted);
  margin-right: 0.25rem;
}
.pivot-summary-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.25rem 0.625rem;
  background: var(--acq-surface-2);
  border: 1px solid var(--acq-border);
  border-radius: 999px;
  font-size: 0.8rem;
  color: var(--acq-text);
}
.pivot-summary-chip-key {
  color: var(--acq-text-muted);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.pivot-summary-chip strong { font-weight: 600; }
.pivot-summary-chip.pivot-summary-chip-active {
  background: var(--acq-primary-soft);
  border-color: transparent;
  color: var(--acq-primary);
  font-weight: 500;
}
.pivot-summary-chip.pivot-summary-chip-active .pivot-summary-chip-key {
  color: var(--acq-primary);
  opacity: 0.7;
}

/* ---- sr-only (mantenido del Phase 8 — usado en a11y labels) ---- */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}


/* -------- Pivot table -------- */

/* Handoff analytics 2026-05-17 A11: wrapper con borde + radius —
 * la tabla flotaba bare en la página; ahora tiene presencia de
 * card sutil. */
.pivot-table-wrapper {
  /* Trello #1 item 4 (freeze panes): región de scroll ACOTADA. Antes
   * sólo `overflow-x: auto` — pero eso fuerza `overflow-y` a `auto`
   * (regla CSS: visible+auto → auto), creando un scroll container
   * vertical SIN altura máxima que nunca scrollea internamente, así que
   * `position: sticky; top` en el thead se anclaba al wrapper (que
   * scrollea con la página) y la cabecera NO quedaba fija. Con
   * `max-height` el wrapper sí scrollea por dentro y las dos filas de
   * fecha + la 1ª columna quedan congeladas (ver reglas sticky abajo).
   * El offset reserva topbar + subnav + filter bar + summary; en tablas
   * cortas el wrapper se encoge al contenido (no hay scroll interno). */
  overflow: auto;
  max-height: calc(100vh - 17rem);
  position: relative;
  border: 1px solid var(--acq-border);
  border-radius: 12px;
}

.pivot-table {
  border-collapse: separate;
  border-spacing: 0;
  width: 100%;
  font-size: 0.875rem;
  /* Altura aprox. de la fila 1 de cabecera (MES DE FACTURACIÓN), usada
   * como `top` de la fila 2 para que queden apiladas al congelarse
   * (Trello #1 item 4). Coincide con su padding 0.625rem + font 0.85rem
   * + borde. */
  --pivot-head-row1-h: 2.45rem;
}

/* Handoff analytics 2026-05-17 A11 (CHECK 4): dual header con
 * jerarquía visual sin enterrar MES DEL INFORME.
 * - Row 1 (MES DE FACTURACIÓN) = turquesa primary + texto blanco:
 *   es lo que el right-holder ve en el extracto bancario.
 * - Row 2 (MES DEL INFORME) sutil PERO no enterrado — color blanco
 *   92% + size 0.78rem + tracking SIN uppercase. El dato físico de
 *   cada col ES este mes_informe del CSV; FACTURACIÓN es derivado
 *   +2. Si la row 2 fuera caption 7pt muted, el operador pensaría
 *   que es metadata decorativa y no podría conciliar con el XLS. */
.pivot-table thead tr:first-child th {
  background: var(--acq-primary);
  color: #FFFFFF;
  font-weight: 600;
  font-size: 0.85rem;
  text-align: right;
  padding: 0.625rem 0.875rem;
  white-space: nowrap;
  border-bottom: 1px solid var(--acq-primary-hover);
}
.pivot-table thead tr:first-child th.pivot-corner {
  text-align: left;
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
}
.pivot-table thead tr:first-child th:first-child { border-top-left-radius: 12px; }
.pivot-table thead tr:first-child th:last-child { border-top-right-radius: 12px; }

.pivot-table thead tr:last-child th {
  background: var(--acq-primary-hover);
  color: rgba(255, 255, 255, 0.92);
  font-weight: 500;
  font-size: 0.78rem;
  letter-spacing: 0.02em;
  padding: 0.4rem 0.875rem;
  text-align: right;
  white-space: nowrap;
  border-bottom: 1.5px solid var(--acq-border);
}
.pivot-table thead tr:last-child th.pivot-corner {
  text-align: left;
}

.pivot-table thead .pivot-corner {
  position: sticky;
  left: 0;
  z-index: 3;
}

/* Trello #1 item 4 (freeze panes): cabecera de fecha siempre visible al
 * scrollear vertical dentro del wrapper acotado. Fila 1 pegada arriba
 * (top:0); fila 2 justo debajo (top = alto de la fila 1). `nth-child(2)`
 * (no `last-child`) para que en el eje venta —cabecera de UNA sola
 * fila— ese segundo `top` no aplique y la única fila quede en top:0. */
.pivot-table thead tr:first-child th {
  position: sticky;
  top: 0;
  z-index: 2;
}
.pivot-table thead tr:nth-child(2) th {
  position: sticky;
  top: var(--pivot-head-row1-h);
  z-index: 2;
}
/* Las celdas corner (cruce fila-fecha × columna-label) son sticky en
 * AMBOS ejes y deben quedar por encima de las celdas de mes (que
 * scrollean por debajo en horizontal) y del cuerpo. z-index alto +
 * specificity suficiente para ganar a las reglas de fila de arriba. */
.pivot-table thead tr:first-child th.pivot-corner {
  z-index: 5;
}
.pivot-table thead tr:nth-child(2) th.pivot-corner {
  top: var(--pivot-head-row1-h);
  z-index: 5;
}

/* Handoff analytics 2026-05-17 A12: body con hover-row + sticky col
 * con shadow lateral sutil al scrollear horizontal. */
.pivot-table tbody td,
.pivot-table tbody th {
  padding: 0.625rem 0.875rem;
  border-bottom: 1px solid var(--acq-border);
  white-space: nowrap;
  font-size: 0.875rem;
}
.pivot-table tbody td.num,
.pivot-table tbody th.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-feature-settings: var(--num-features);
}

.pivot-table .pivot-artist {
  position: sticky;
  left: 0;
  background: var(--acq-surface);
  font-weight: 500;
  text-align: left;
  z-index: 1;
  /* Box-shadow right como indicador sutil de col sticky en scroll
   * horizontal. */
  box-shadow: 4px 0 6px -4px rgba(43, 43, 52, 0.08);
}

/* Row-hover sobre todo el row incluyendo sticky col + total col. */
.pivot-table tbody tr:hover td {
  background: var(--acq-surface-2);
}
.pivot-table tbody tr:hover th.pivot-artist {
  background: var(--acq-surface-2);
}

.pivot-table .pivot-rank {
  color: var(--acq-text-muted);
  margin-right: 0.5rem;
  font-variant-numeric: tabular-nums;
  font-feature-settings: var(--num-features);
  font-size: 0.8rem;
  font-weight: 400;
}

.pivot-table .pivot-empty {
  color: color-mix(in srgb, var(--acq-text-muted) 50%, transparent);
  font-weight: 400;
}

.pivot-table .pivot-total-col {
  background: color-mix(in srgb, var(--acq-primary) 6%, transparent);
  font-weight: 600;
}
.pivot-table tbody tr:hover td.pivot-total-col {
  background: color-mix(in srgb, var(--acq-primary) 12%, transparent);
}

/* Handoff analytics 2026-05-17 A13: filas especiales — Otros
 * (debajo del threshold, italic muted), Sin asignar (ISRCs sin
 * artist), Subfila drill-down. */
.pivot-table .pivot-row-otros th.pivot-artist,
.pivot-table .pivot-row-otros td {
  color: var(--acq-text-muted);
  font-style: italic;
  background: color-mix(in srgb, var(--acq-surface-2) 60%, transparent);
}
.pivot-table .pivot-row-otros th.pivot-artist {
  background: color-mix(in srgb, var(--acq-surface-2) 60%, var(--acq-surface));
}

.pivot-table .pivot-row-sin-asignar th.pivot-artist,
.pivot-table .pivot-row-sin-asignar td {
  color: var(--acq-text-muted);
}

/* Drill-down subfila. Phase 8.3 conserva content-visibility:auto +
 * contain-intrinsic-size para perf con drill-downs masivos (~25k
 * subfilas). */
.pivot-table .pivot-row-subfila {
  font-size: 0.875rem;
  content-visibility: auto;
  contain-intrinsic-size: auto 2rem;
}
.pivot-table .pivot-row-subfila td,
.pivot-table .pivot-row-subfila th {
  background: color-mix(in srgb, var(--acq-surface-2) 50%, var(--acq-surface));
  font-weight: 400;
  padding-block: 0.5rem;
  font-size: 0.85rem;
}
.pivot-table .pivot-row-subfila:hover td,
.pivot-table .pivot-row-subfila:hover th.pivot-artist {
  background: var(--acq-surface-2);
}

.pivot-table .pivot-artist-sub {
  padding-left: 2.25rem;
  color: var(--acq-text-muted);
}
.pivot-table .pivot-subfila-indent {
  opacity: 0.6;
  margin-right: 0.4rem;
  color: var(--acq-primary);
}

/* Handoff analytics 2026-05-17 A14: TOTAL GENERAL del tfoot con
 * bg turquesa-soft + top border turquesa. Coherente con la TOTAL
 * row del informe de Royalties (Patch W10 del handoff anterior). */
.pivot-table tfoot .pivot-row-total-general th,
.pivot-table tfoot .pivot-row-total-general td {
  background: var(--acq-primary-soft);
  font-weight: 700;
  border-top: 1.5px solid var(--acq-primary);
  border-bottom: 0;
  padding-top: 0.75rem;
  padding-bottom: 0.75rem;
}
.pivot-table tfoot .pivot-row-total-general th.pivot-artist {
  background: var(--acq-primary-soft);
  color: var(--acq-text);
}

.pivot-footnote {
  margin-top: 1rem;
  color: var(--acq-text-muted);
}

/* Phase 8.4 commit 1: fila de paginación bajo cada parent del
 * drill-down. Aparece cuando `subfilas_total > page_size`. Buttons
 * «Ver más» / «Ver menos» crecen y encogen acumulativamente la
 * ventana de subfilas en bloques de 25 (el modelo discreto
 * Anterior/Siguiente fue revertido en favor del cumulativo). */
.pivot-table .pivot-row-pagination td {
  padding: 0.5rem 0.75rem;
  background: var(--acq-surface-1);
  border-top: 1px dashed var(--acq-border);
}

.pivot-pagination-controls {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.875rem;
}

/* Handoff analytics 2026-05-17 A15: status text con <strong> dentro
 * para que el rango numérico destaque. */
.pivot-pagination-status {
  color: var(--acq-text-muted);
  font-size: 0.825rem;
}
.pivot-pagination-status strong { color: var(--acq-text); }

.pivot-pagination-btn {
  appearance: none;
  background: var(--acq-surface);
  border: 1px solid var(--acq-border);
  /* Handoff A15: radius 4 → 8px, coherente con inputs/buttons del
   * filter bar. Hover bg primary-soft + border + color turquesa
   * (en lugar de cambio sólo de bg). */
  border-radius: 8px;
  padding: 0.4rem 0.875rem;
  font: inherit;
  font-size: 0.825rem;
  font-weight: 500;
  color: var(--acq-text);
  cursor: pointer;
  transition: all 0.15s ease;
}

.pivot-pagination-btn:hover {
  background: var(--acq-primary-soft);
  border-color: var(--acq-primary);
  color: var(--acq-primary);
}

.pivot-pagination-btn:focus-visible {
  outline: 2px solid var(--acq-primary);
  outline-offset: 1px;
}
.pivot-pagination-btn[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
}

/* Handoff analytics 2026-05-17 A15: paginación parents al pie como
 * card con justify-between (status izq, controles der). Antes era
 * compacto justify-end; ahora respira y el operador ve "Mostrando
 * 1-25 de 87" sin tener que buscarlo. */
.pivot-parent-pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 1rem;
  padding: 0.875rem 1rem;
  font-size: 0.875rem;
  background: var(--acq-surface-2);
  border: 1px solid var(--acq-border);
  border-radius: 10px;
}


/* -------------------------------------------------------------------
 * BACKSTAGE handoff — bloques visuales del prototipo Acqustic
 * (acqustic.html / pages.css del design bundle 2026-05-11) que el
 * frontend live aún no tenía. Cada clase tiene UN consumidor en los
 * templates Jinja; añadir aquí evita parchear inline-styles.
 * ------------------------------------------------------------------- */

/* `.code-pill` — badge monoespaciado para tokens cortos (ISRC, mes
 * en formato YYYY-MM, IDs). Sustituye al `<code>` inline cuando la
 * etiqueta es self-contained (no parte de prosa). */
.code-pill {
  display: inline-block;
  font-family: var(--acq-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 0.8rem;
  padding: 0.15rem 0.5rem;
  background: var(--acq-surface-2);
  border-radius: 4px;
  color: var(--acq-text);
  line-height: 1.4;
}

/* `.month-pills` — wrapper flex para clusters de `.code-pill` (gaps
 * de meses en salud del catálogo). Override teal-soft sobre los
 * pills hijos para diferenciarlos de un código neutro. */
.month-pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.75rem;
}
.month-pills .code-pill {
  background: var(--acq-primary-soft);
  color: var(--acq-primary-hover);
}

/* `.check-row` — checkbox card con título strong + descripción
 * pequeña. Reemplaza el patrón `<label>` plano del fieldset en
 * ingest/catalog-merge para alinear con el mockup #5 (cards con
 * borde + radius, no labels desnudos). Se hereda dentro de
 * `<fieldset>` sin tener que tocar el wrapper semántico. */
.check-row {
  display: flex;
  gap: 0.875rem;
  align-items: flex-start;
  padding: 0.875rem 1rem;
  border-radius: 10px;
  border: 1px solid var(--acq-border);
  margin-top: 0.625rem;
  background: var(--acq-surface);
}
.check-row > input[type="checkbox"] {
  width: 18px;
  height: 18px;
  accent-color: var(--acq-primary);
  margin-top: 2px;
  flex-shrink: 0;
}
.check-row > .ck-body {
  display: block;
  min-width: 0;
}
.check-row .ck-body > strong {
  display: block;
  color: var(--acq-text);
  margin-bottom: 0.25rem;
  font-weight: 600;
  font-size: 0.9375rem;
}
.check-row .ck-body > small,
.check-row .ck-body > .ck-help {
  display: block;
  color: var(--acq-text-muted);
  font-size: 0.85rem;
  line-height: 1.5;
}
/* Aclaración inline en el título (e.g. "Auto-aceptar correcciones
 * (mismo INICIO, contenido distinto)"): mismo tamaño que el strong
 * pero peso regular y muted, para que el ojo lea primero la acción
 * y luego la condición. */
.check-row .ck-body strong .ck-help-inline {
  font-weight: 400;
  color: var(--acq-text-muted);
  margin-left: 0.25rem;
}

/* `.option-section` — wrapper de sub-sección en páginas de Opciones.
 * Da margin-top consistente + header con título y hint a la derecha
 * (alineado con baseline). Replaces ad-hoc `<section>` + `<header>`
 * que cada página componía a mano. */
.option-section {
  margin-top: 2.25rem;
}
.option-section > .option-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.375rem;
}
.option-section > .option-section-head > h3 {
  margin: 0;
  font-size: 1.25rem;
  font-weight: 600;
  letter-spacing: -0.005em;
}
.option-section > .option-section-head > .option-section-hint {
  font-size: 0.8rem;
  color: var(--acq-text-muted);
}

/* `.backup-list` — grid de 4 columnas (timestamp · tamaño · nota ·
 * acción) para la tabla de backups del catálogo. Sustituye al
 * `<table class="table-bare">` del partial _backups_table_section
 * cuando se renderiza dentro de catalog-merge (mockup #6). La fila
 * con `.row.head` es el cabecero. */
.backup-list {
  margin-top: 0.875rem;
  border: 1px solid var(--acq-border);
  border-radius: 14px;
  overflow: hidden;
}
.backup-list > .backup-row {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr auto;
  align-items: center;
  padding: 0.875rem 1.125rem;
  border-bottom: 1px solid var(--acq-border);
  font-size: 0.9rem;
  gap: 1rem;
}
/* 3 cols sin "nota" (sólo tenemos timestamp + size del backup-service
 * actual). Se mantiene la cuarta col `auto` para la acción. */
.backup-list.backup-list-3col > .backup-row {
  grid-template-columns: 1.4fr 1fr auto;
}
.backup-list > .backup-row:last-child {
  border-bottom: 0;
}
.backup-list > .backup-row.head {
  background: var(--acq-surface-2);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--acq-text-muted);
  font-weight: 500;
}
.backup-list .backup-when {
  font-variant-numeric: tabular-nums;
  font-feature-settings: var(--num-features);
  font-weight: 500;
}
.backup-list .backup-size {
  color: var(--acq-text-muted);
  font-variant-numeric: tabular-nums;
  font-feature-settings: var(--num-features);
}
.backup-list .backup-note {
  color: var(--acq-text-muted);
}
.backup-list .backup-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
}
.backup-list .backup-actions form {
  margin: 0;
}

/* `.alert-muted` — variante neutra del bloque alert (mockup #7,
 * "Gaps de meses": el contenido es informativo, no warning ni info-
 * teal, así que el surface-2 con texto medium muted es la nota
 * correcta). Convive con `.alert-warning`/`.alert-info` ya
 * existentes. */
.alert-muted {
  background: var(--acq-surface-2);
  color: var(--acq-text-muted);
  border: 1px solid var(--acq-border);
  border-left: 4px solid var(--acq-border);
}
.alert-muted strong {
  color: var(--acq-text);
}


/* ===========================================================================
 * Handoff Opciones 2026-05-18 — primitivos canónicos del sistema
 *
 * Trasplante 1:1 desde `acq/project/assets/styles.css` y `pages.css`
 * del bundle BACKSTAGE original. Las 3 páginas de Opciones
 * (Liquidaciones / Right Holders / Salud del catálogo) usan estos
 * primitivos en su rewrite. Algunos ya existían parcialmente en el
 * live (`.subnav-pill`, `.check-row`, `.drop-zone`, `.option-section`,
 * `.code-pill`, `.month-pills`, `.backup-list`) pero con drift en
 * nombres o valores — este bloque consolida el patrón canónico.
 * =========================================================================== */

/* --- Page head — h1 + .sub --- */
.page-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.5rem;
  margin-bottom: 0.5rem;
}
.page-head h1 {
  font-size: 1.625rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 0;
  color: var(--acq-text);
}
.page-head .sub {
  color: var(--acq-text-muted);
  font-size: 0.9375rem;
  margin: 0.375rem 0 0;
}

/* --- Options prose — párrafos intro, max-width acotado para legibilidad --- */
.options-prose {
  max-width: 780px;
  color: var(--acq-text-muted);
  font-size: 0.9rem;
  line-height: 1.6;
}
.options-prose p { margin: 0 0 0.75rem; }
.options-prose code,
.t code {
  font-family: var(--acq-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 0.8rem;
  background: var(--acq-surface-2);
  padding: 1px 0.375rem;
  border-radius: 4px;
  color: var(--acq-text);
}
.options-prose strong { color: var(--acq-text); font-weight: 600; }

/* --- Buttons canónicos --- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  height: 40px;
  padding: 0 1.375rem;
  border-radius: 999px;
  background: var(--acq-primary);
  color: #FFFFFF;
  font-weight: 500;
  font-size: 0.8125rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border: 0;
  cursor: pointer;
  white-space: nowrap;
  width: auto;             /* override Pico's button { width: 100% } */
  flex: 0 0 auto;
  transition: background 0.15s ease, transform 0.05s;
}
.btn:hover { background: var(--acq-primary-hover); }
.btn:active { transform: translateY(1px); }
.btn.lg { height: 52px; padding: 0 2rem; font-size: 0.875rem; }
.btn.block { width: 100%; }

.btn-ghost {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  height: 36px;
  padding: 0 1rem;
  border: 1px solid var(--acq-border);
  border-radius: 999px;
  background: #FFFFFF;
  color: var(--acq-text);
  font-size: 0.8125rem;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
  width: auto;
  flex: 0 0 auto;
  transition: border-color 0.15s, color 0.15s;
}
.btn-ghost:hover { border-color: var(--acq-text); }
.btn-ghost svg { color: var(--acq-text-muted); }

/* --- Card + table canónicos --- */
.card {
  background: #FFFFFF;
  border: 1px solid var(--acq-border);
  border-radius: 16px;
  padding: 1.5rem;
}

.t {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
}
.t-scroll { overflow-x: auto; }
.t.nowrap td, .t.nowrap th { white-space: nowrap; }
.t thead th {
  text-align: left;
  font-weight: 500;
  font-size: 0.75rem;
  color: var(--acq-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 0.875rem 1rem;
  border-bottom: 1px solid var(--acq-border);
  background: var(--acq-surface-2);
}
.t tbody td {
  padding: 1rem;
  border-bottom: 1px solid var(--line-soft, #F2F2F4);
  vertical-align: middle;
}
.t tbody tr:last-child td { border-bottom: 0; }
.t tbody tr:hover td { background: var(--acq-surface-2); }
.t .num { font-variant-numeric: tabular-nums; }
.t .right { text-align: right; }

/* --- Drop zone iconográfica (handoff Opciones — los .drop-zone-label/-help
 *     legacy se renombran a los canónicos .dz-icon/-label/-help) --- */
.drop-zone .dz-icon {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--acq-primary);
  color: #FFFFFF;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 0.875rem;
}
.drop-zone .dz-label {
  display: block;
  font-size: 1.0625rem;
  font-weight: 600;
  color: var(--acq-text);
  margin-bottom: 0.375rem;
}
.drop-zone .dz-help {
  display: block;
  font-size: 0.8125rem;
  color: var(--acq-text-muted);
  line-height: 1.5;
}
.drop-zone .dz-help kbd {
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 0.6875rem;
  padding: 1px 0.375rem;
  background: #FFFFFF;
  border: 1px solid var(--acq-border);
  border-radius: 4px;
}

/* --- Alert variants modifier classes (sin prefix `alert-`) — pattern
 *     canónico del sistema. El live tenía .alert-warning/-info/-muted
 *     con guión, ahora consolidados a .alert.warning etc. (los dos
 *     coexisten en el CSS por compat). --- */
.alert .icon {
  flex-shrink: 0;
  margin-top: 2px;
}
.alert.warning {
  background: color-mix(in srgb, var(--acq-error) 8%, transparent);
  color: var(--acq-error);
  border: 1px solid color-mix(in srgb, var(--acq-error) 18%, transparent);
  border-left: 4px solid var(--acq-error);
}
.alert.warning strong { color: var(--acq-error); }
.alert.info {
  background: color-mix(in srgb, var(--acq-primary) 8%, transparent);
  color: var(--acq-primary-hover);
  border: 1px solid color-mix(in srgb, var(--acq-primary) 20%, transparent);
  border-left: 4px solid var(--acq-primary);
}
.alert.info strong { color: var(--acq-primary-hover); }
.alert.success {
  background: color-mix(in srgb, var(--acq-success) 8%, transparent);
  color: var(--acq-success);
  border: 1px solid color-mix(in srgb, var(--acq-success) 18%, transparent);
  border-left: 4px solid var(--acq-success);
}
.alert.muted {
  background: var(--acq-surface-2);
  color: var(--acq-text-muted);
  border: 1px solid var(--acq-border);
  border-left: 4px solid var(--acq-border);
}
.alert.muted strong { color: var(--acq-text); }

/* --- Option-section uses .head (no .option-section-head). Backcompat:
 *     mantenemos las reglas viejas porque catalog-merge aún usa
 *     `.option-section-head`. Cuando se actualice ese template, el
 *     selector legacy se borra. --- */
.option-section > .head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.375rem;
}
.option-section > .head > h2 {
  margin: 0;
  font-size: 1.25rem;
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--acq-text);
}
.option-section > .head > h2 code {
  font-family: var(--acq-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 0.9em;
  background: var(--acq-surface-2);
  padding: 1px 0.375rem;
  border-radius: 4px;
  color: var(--acq-text);
  font-weight: 600;
}
.option-section > .head > .hint {
  font-size: 0.8rem;
  color: var(--acq-text-muted);
  white-space: nowrap;
}

/* --- Utility classes — margin-top steps --- */
.mt-sm { margin-top: 0.625rem; }
.mt-md { margin-top: 1.25rem; }
.mt-lg { margin-top: 2rem; }

/* --- Download link styling para Salud del catálogo --- */
.link-download {
  color: var(--acq-primary);
  font-size: 0.8125rem;
  font-weight: 500;
  text-decoration: none;
  transition: color 0.15s, text-decoration-color 0.15s;
}
.link-download:hover {
  color: var(--acq-primary-hover);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* --- Check-row helper inline — variante del primitivo .check-row para
 *     un span muted dentro del strong del título. Reemplaza al
 *     .ck-help-inline (drift del live). El nuevo copy en Right Holders
 *     no debería necesitarlo, pero queda como utility por si futuros
 *     check-rows lo piden. --- */
.check-row .ck-body strong > span.ck-soft {
  font-weight: 400;
  color: var(--acq-text-muted);
}

/* --- SVG inline-en-texto: 1em para que escalen con el font-size del
 *     contexto cuando el usuario sube el zoom de texto (WCAG 1.4.4).
 *     Solo aplica a iconos *acompañando texto* — chrome geométrico
 *     (topbar chev, avatar, dz-icon circular, login background) mantiene
 *     sus dimensiones fijas. --- */
.alert .icon svg,
.option-section .head .icon svg,
.filter-banner-teal .fb-icon {
  width: 1em;
  height: 1em;
}

/* ============================================================
 * RELEASES PAGE — primitivos nuevos (handoff Claude Design 2026-05-18)
 *
 * 1. .filter-banner-teal — banner teal con 3 fields + botón FILTRAR
 * 2. .pagination-teal    — paginación pills cuadradas teal
 *
 * (El subnav usa `.subnav-pill` base — ya es teal con
 * `var(--acq-primary)`. La variante `.subnav-pill-teal` que existía
 * inicialmente se eliminó porque era redundante; Releases ahora reusa
 * la misma estructura que Opciones para coherencia visual.)
 *
 * Mockup: acqustic/diseño/paginas/4-Releases.pdf
 * Compatibles con pass 1+2 de unidades (rem/em). Chrome geométrico
 * (height de controles, hairlines) en px deliberado.
 * ============================================================ */

/* ------------------------------------------------------------
 * 1. .filter-banner-teal — banner teal con filtros white-on-teal
 * ------------------------------------------------------------ */
.filter-banner-teal {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr) minmax(0, 1fr) auto;
  align-items: end;
  gap: 1rem 1.25rem;
  background: var(--acq-primary);
  border-radius: 999px;
  padding: 1.25rem 1.5rem;
  margin-bottom: 1.5rem;
  color: #FFFFFF;
}
/* Variant 3 columnas — tab Pistas (sprint 1.1, sin dropdown Tipo).
 * El template añade `.filter-banner-teal--3col` cuando `show_tipo
 * =False`. Mantiene la misma proporción 1.5fr:1fr entre search y
 * dropdown (el search sigue siendo el field dominante) + auto para
 * el botón a la derecha. */
.filter-banner-teal.filter-banner-teal--3col {
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr) auto;
}
.filter-banner-teal .fb-field { display: flex; flex-direction: column; gap: 0.375rem; min-width: 0; }
.filter-banner-teal .fb-label {
  font-size: 0.75rem;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.92);
  letter-spacing: 0.02em;
}
.filter-banner-teal .fb-field-with-icon { position: relative; display: flex; align-items: center; }
.filter-banner-teal .fb-icon {
  position: absolute; left: 0.75rem; top: 50%;
  transform: translateY(-50%);
  color: var(--acq-text-muted);
  pointer-events: none;
  flex: 0 0 auto;
}
.filter-banner-teal .fb-field-with-icon .fb-input { padding-left: 2.25rem; }
.filter-banner-teal .fb-input,
.filter-banner-teal .fb-select {
  display: block;
  width: 100%;
  height: 44px;
  padding: 0 0.875rem;
  background: #FFFFFF;
  color: var(--acq-text);
  border: 0;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.08);
  border-radius: 0.375rem;
  font-family: inherit;
  font-size: 0.9375rem;
  line-height: 1.4;
  margin: 0;
  min-width: 0;
}
.filter-banner-teal .fb-input::placeholder { color: var(--acq-text-muted); opacity: 1; }
.filter-banner-teal .fb-input:focus,
.filter-banner-teal .fb-select:focus {
  outline: none;
  box-shadow:
    inset 0 0 0 1px rgba(0, 0, 0, 0.08),
    0 0 0 3px rgba(255, 255, 255, 0.35);
}
.filter-banner-teal .fb-select {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none' stroke='%232B2B34' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.875rem center;
  background-size: 0.75rem 0.5rem;
  padding-right: 2.25rem;
}
.filter-banner-teal .fb-submit {
  height: 44px;
  padding: 0 1.5rem;
  background: var(--acq-text);
  color: #FFFFFF;
  border: 0;
  border-radius: 0.375rem;
  font-family: inherit;
  font-size: 0.8125rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  cursor: pointer;
  margin: 0;
  width: auto;
  min-width: 0;
  transition: background 0.15s ease, transform 0.05s ease;
}
.filter-banner-teal .fb-submit:hover { background: #1c1c22; }
.filter-banner-teal .fb-submit:active { transform: translateY(1px); }
.filter-banner-teal .fb-submit:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.5);
}
@media (max-width: 64em) {
  .filter-banner-teal { grid-template-columns: 1fr; }
  .filter-banner-teal .fb-submit { width: 100%; }
}

/* ------------------------------------------------------------
 * 2. .pagination-teal — paginación pills teal
 * ------------------------------------------------------------ */
.pagination-teal {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin: 2rem auto;
  list-style: none;
  padding: 0;
}
.pagination-teal .pg-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  background: var(--acq-primary);
  color: #FFFFFF;
  border: 0;
  border-radius: 0.375rem;
  font-family: inherit;
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.05s ease;
  user-select: none;
}
.pagination-teal .pg-pill:hover { background: var(--acq-primary-hover); }
.pagination-teal .pg-pill:active { transform: translateY(1px); }
.pagination-teal .pg-pill:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(6, 184, 173, 0.35);
}
.pagination-teal .pg-pill.pg-current,
.pagination-teal .pg-pill[aria-current="page"] {
  background: var(--acq-primary-hover);
  font-weight: 700;
  cursor: default;
}
.pagination-teal .pg-pill.pg-current:hover,
.pagination-teal .pg-pill[aria-current="page"]:hover {
  background: var(--acq-primary-hover);
}
.pagination-teal .pg-pill[aria-disabled="true"] {
  opacity: 0.4;
  cursor: not-allowed;
  pointer-events: none;
}
.pagination-teal .pg-sep {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 2.25rem;
  padding: 0 0.25rem;
  color: var(--acq-primary);
  font-size: 1rem;
  font-weight: 600;
  user-select: none;
}

/* ------------------------------------------------------------
 * Tabla de releases — celdas con thumb + título + sub.
 * Apoyo a .releases-table dentro de .t (las clases base ya pintan
 * borders y typography); aquí añadimos sólo lo específico de la
 * celda doble (thumb cuadrado + columna texto titulo/artista) y
 * el meta-row con el contador. --- */
.releases-meta-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 0.5rem 0 1rem;
  color: var(--acq-text);
  font-size: 0.875rem;
}
.releases-meta-row strong { font-weight: 600; }

.cell-release {
  display: flex;
  align-items: center;
  gap: 0.875rem;
  min-width: 0;
}
.cell-release-text {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
  min-width: 0;
}
.cell-release-title {
  color: var(--acq-primary);
  font-weight: 500;
  font-size: 0.9375rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 18rem;
}
.cell-release-sub {
  color: var(--acq-text-muted);
  font-size: 0.8125rem;
}

.releases-empty {
  padding: 2rem 0;
  text-align: center;
  color: var(--acq-text-muted);
}

/* ------------------------------------------------------------
 * Multi-tenant divider (2026-05-24) — chip de sello entre
 * grupos en las tablas Releases / Pistas / Artistas cuando el
 * user tiene >1 sello y no ha filtrado a uno.
 *
 * El divider es un <tr> con un único <td colspan> alojando un
 * chip pill compacto. Se diferencia visualmente del row de
 * datos con (i) background gris pálido, (ii) sin hover row,
 * (iii) padding generoso vertical para abrir aire entre grupos.
 *
 * Chips por sello: `--acqustic` (teal corporate) y `--voltereta`
 * (violeta/indigo para diferenciarlo). Fallback genérico para
 * sellos nuevos (gris). --- */
.releases-table tr.sello-divider {
  background: #f6f8fa;
}
.releases-table tr.sello-divider:hover {
  background: #f6f8fa;
}
.releases-table tr.sello-divider > td {
  padding: 0.875rem 1rem;
  border-top: 1px solid var(--acq-border, #e5e7eb);
  border-bottom: 1px solid var(--acq-border, #e5e7eb);
}

.chip-sello {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.25rem 0.75rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  /* Default (sellos no mapeados explícitamente): gris neutro. */
  background: #e5e7eb;
  color: #374151;
}
.chip-sello--acqustic {
  background: var(--acq-primary-soft, rgba(6, 184, 173, 0.15));
  color: var(--acq-primary, #06B8AD);
}
.chip-sello--voltereta {
  background: rgba(124, 58, 237, 0.12);
  color: #6d28d9;
}

/* ------------------------------------------------------------
 * Detalle de pista (2026-05-24) — /releases/pistas/{isrc}.
 * Una sección por sello (caso Zzoilo cross-sello), dentro cards
 * de fase con su ventana + tabla de holders. Foco: legibilidad
 * del contrato (acqustic %, productores, RH<n>) — estética
 * consistente con el resto del frontend (Pico + tokens BACKSTAGE).
 * --- */
.pista-detail {
  display: flex;
  flex-direction: column;
  gap: 1.75rem;
}
.pista-detail-sello {
  border: 1px solid var(--acq-border, #e5e7eb);
  border-radius: 0.75rem;
  padding: 1.25rem 1.25rem 1rem;
  background: #fff;
}
.pista-detail-sello-head {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 1rem;
}
.pista-detail-sello-meta {
  color: var(--acq-text-muted);
  font-size: 0.8125rem;
}
.pista-phase {
  /* Margen/padding default 0 — sólo el adjacent sibling selector
   * abajo añade el border. NH-7 del /review 0b821db: pre-fix
   * usábamos `:first-of-type` para suprimir el border en el primer
   * <article>; eso es frágil ante un futuro <article> hermano
   * (e.g. botón "Añadir fase" en commit 3). El sibling selector
   * "separar fases entre sí" es semánticamente correcto y robusto. */
}
.pista-phase + .pista-phase {
  border-top: 1px dashed var(--acq-border, #e5e7eb);
  padding-top: 0.875rem;
  margin-top: 0.875rem;
}
.pista-phase-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.5rem;
}
.pista-phase-head h3 {
  margin: 0;
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--acq-text);
}
.pista-phase-window {
  font-size: 0.8125rem;
  color: var(--acq-text-muted);
  font-variant-numeric: tabular-nums;
}
.pista-phase-table { margin: 0; }
.pista-phase-table td small { color: var(--acq-text-muted); }

/* Badges de tipo en la tabla de holders.
 * Misma paleta turquesa que el chip-sello acqustic para
 * "Sello" (consistencia visual), tono violeta tenue para
 * "Productor" (diferenciable de RH sin chocar con Voltereta
 * teal), gris suave para "RH<n>" (el típico holder neutro). */
.kind-badge {
  display: inline-block;
  padding: 0.125rem 0.5rem;
  border-radius: 999px;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  white-space: nowrap;
}
.kind-acqustic {
  background: var(--acq-primary-soft, rgba(6, 184, 173, 0.15));
  color: var(--acq-primary, #06B8AD);
}
.kind-producer {
  background: rgba(99, 102, 241, 0.12);
  color: #4338ca;
}
.kind-rightholder {
  background: #f3f4f6;
  color: #4b5563;
}

/* PR-B: badges del panel "Artistas" (artistas.csv).
 * `Display` = TRACKARTIST<n>, credit Spotify (rosa suave).
 * `Income` = ARTIST<n> + ARTIST<n> %, reparto canónico (ámbar). */
.kind-trackartist {
  background: rgba(236, 72, 153, 0.12);
  color: #9d174d;
}
.kind-artistincome {
  background: rgba(245, 158, 11, 0.15);
  color: #92400e;
}

/* ------------------------------------------------------------
 * Phase edit forms (2026-05-24) — embebidos en cada
 * <article class="pista-phase"> y como card aparte para "Añadir
 * fase". CSS-only (no JS) — el collapse usa <details>/<summary>
 * nativos, consistente con el patrón de Phase 8 del frontend.
 * --- */
.phase-form-collapse {
  margin-top: 1rem;
  border-top: 1px solid var(--acq-border, #e5e7eb);
  padding-top: 1rem;
}
.phase-form-collapse > summary.btn-edit-phase {
  display: inline-block;
  cursor: pointer;
  padding: 0.4rem 0.875rem;
  background: var(--acq-primary, #06B8AD);
  color: #fff;
  border-radius: 0.375rem;
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  list-style: none;
  margin: 0;
}
.phase-form-collapse > summary.btn-edit-phase::-webkit-details-marker {
  display: none;
}
.phase-form-collapse[open] > summary.btn-edit-phase {
  background: #6b7280;
}
.phase-form-collapse[open] > summary.btn-edit-phase::after {
  content: " ▾";
}

.phase-form {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  margin-top: 1rem;
  padding: 1rem;
  background: #fafafa;
  border-radius: 0.5rem;
}
.phase-form-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 0.75rem;
}
.phase-form-row-rh {
  grid-template-columns: 2fr 1fr 1.2fr 1.2fr;
}
.phase-form label {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  font-size: 0.8125rem;
}
.phase-form-label {
  color: var(--acq-text-muted);
  font-weight: 500;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.phase-form input[type="text"],
.phase-form input[type="date"],
.phase-form select {
  padding: 0.4rem 0.625rem;
  border: 1px solid var(--acq-border, #d1d5db);
  border-radius: 0.375rem;
  font-size: 0.875rem;
  background: #fff;
  font-family: inherit;
}
.phase-form input:focus,
.phase-form select:focus {
  outline: 2px solid var(--acq-primary, #06B8AD);
  outline-offset: -1px;
  border-color: transparent;
}
.phase-form-holders {
  border: 1px solid var(--acq-border, #e5e7eb);
  border-radius: 0.5rem;
  padding: 0.875rem 1rem 1rem;
  margin: 0;
}
.phase-form-holders > legend {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--acq-text, #2B2B34);
  padding: 0 0.5rem;
}
.phase-form-holders > .phase-form-row {
  margin-bottom: 0.625rem;
}
.phase-form-actions {
  display: flex;
  gap: 0.75rem;
  justify-content: flex-end;
}
.phase-form-actions .btn-primary {
  padding: 0.5rem 1.25rem;
  background: var(--acq-primary, #06B8AD);
  color: #fff;
  border: 0;
  border-radius: 0.375rem;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
}
.phase-form-actions .btn-primary:hover {
  background: #048b85;
}
.phase-form-actions .btn-danger {
  padding: 0.5rem 1.25rem;
  background: #fff;
  color: #b91c1c;
  border: 1px solid #b91c1c;
  border-radius: 0.375rem;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
}
.phase-form-actions .btn-danger:hover {
  background: #fef2f2;
}

.pista-detail-add-fase {
  margin-top: 2rem;
  padding: 1.25rem 1.25rem 1rem;
  border: 1px dashed var(--acq-border, #d1d5db);
  border-radius: 0.75rem;
  background: #fff;
}
.pista-detail-add-fase-head h2 {
  margin: 0 0 0.25rem;
  font-size: 1.05rem;
  font-weight: 600;
}
.pista-detail-add-fase-head .sub {
  margin: 0 0 1rem;
  color: var(--acq-text-muted);
  font-size: 0.8125rem;
}

/* PR-B: panel "Artistas" del detalle de pista. Estilo paralelo al
 * `.pista-detail-sello` de las fases. Cada sello tiene su sub-card
 * con la tabla TRACKARTIST/ARTIST y el form embebido. */
.pista-detail-artists {
  margin-top: 2rem;
  border: 1px solid var(--acq-border, #e5e7eb);
  border-radius: 0.75rem;
  padding: 1.25rem;
  background: #fff;
}
.pista-detail-artists-head h2 {
  margin: 0 0 0.25rem;
  font-size: 1.05rem;
  font-weight: 600;
}
.pista-detail-artists-head .sub {
  margin: 0 0 1.25rem;
  color: var(--acq-text-muted);
  font-size: 0.8125rem;
}
.pista-detail-artists-sello {
  padding: 0.875rem 0;
  border-top: 1px dashed var(--acq-border, #e5e7eb);
}
.pista-detail-artists-sello:first-of-type {
  border-top: 0;
  padding-top: 0;
}
.pista-detail-artists-sello-head {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 0.875rem;
}
.pista-detail-artists-meta {
  color: var(--acq-text-muted);
  font-size: 0.8125rem;
}
.pista-detail-artists-meta--missing {
  color: #b45309;  /* amber-700 — destaca la huérfana sin gritar */
}
/* NH-4 del /review e5dc49f: renombrado a `.form-hint` (sin
 * namespace `phase-`) porque ahora lo usan también los forms de
 * artists. El namespace previo era engañoso. */
.form-hint,
.phase-form-hint {  /* alias retro-compatible mientras dura el rename */
  margin: 0 0 0.875rem;
  padding: 0.625rem 0.875rem;
  background: rgba(6, 184, 173, 0.06);
  border-left: 3px solid var(--acq-primary, #06B8AD);
  font-size: 0.8125rem;
  color: var(--acq-text, #2B2B34);
}

.pista-detail-artists-sum {
  margin: 0.625rem 0 0;
  font-size: 0.8125rem;
  color: var(--acq-text-muted);
}
.pista-detail-artists-sum strong {
  color: var(--acq-text, #2B2B34);
  font-variant-numeric: tabular-nums;
}
.pista-detail-artists-sum-warn {
  color: #b45309;  /* amber-700 — paridad con `--missing` */
  margin-left: 0.5rem;
}

/* Task #19 del smoke 2026-05-26: panel del soft-404 RH huérfana.
 * Visualmente entre el page-head y el `.pista-detail` que en este
 * caso queda vacío. Tono ámbar suave (no error, es "acción pendiente
 * para el operador"). */
.pista-detail-orphan-rh {
  margin: 1.5rem 0 1rem;
  padding: 1.25rem;
  border: 1px solid rgba(245, 158, 11, 0.4);
  border-radius: 0.75rem;
  background: rgba(245, 158, 11, 0.04);
}
.pista-detail-orphan-rh > header > h2 {
  margin: 0 0 0.25rem;
  font-size: 1.05rem;
  color: #92400e;  /* amber-800 */
}
.pista-detail-orphan-rh > header > .sub {
  margin: 0 0 1rem;
  font-size: 0.8125rem;
  color: var(--acq-text-muted);
}

/* SF-9 del /review d5ece22: delete confirmation sin JS. <details>
 * anidado dentro del edit form; el <summary> es el botón danger
 * inicial, expand → warning + segundo botón de confirmación. */
.phase-form-delete {
  margin-top: 0.875rem;
  padding: 0;
}
.phase-form-delete > summary.btn-danger {
  display: inline-block;
  cursor: pointer;
  padding: 0.4rem 0.875rem;
  background: #fff;
  color: #b91c1c;
  border: 1px solid #b91c1c;
  border-radius: 0.375rem;
  font-size: 0.8125rem;
  font-weight: 600;
  list-style: none;
}
.phase-form-delete > summary.btn-danger::-webkit-details-marker {
  display: none;
}
.phase-form-delete > summary.btn-danger:hover {
  background: #fef2f2;
}
.phase-form-delete[open] > summary.btn-danger {
  background: #fef2f2;
}
.phase-form-delete-warning {
  margin: 0.75rem 0;
  padding: 0.75rem 1rem;
  border-left: 3px solid #b91c1c;
  background: #fef2f2;
  font-size: 0.8125rem;
  color: #7f1d1d;
}
.phase-form-delete-warning strong { display: block; margin-bottom: 0.25rem; }
.phase-form-delete > form {
  display: inline-block;
  margin: 0;
}
.phase-form-delete > form > button {
  padding: 0.5rem 1.125rem;
  background: #b91c1c;
  color: #fff;
  border: 0;
  border-radius: 0.375rem;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
}
.phase-form-delete > form > button:hover { background: #991b1b; }


/* ============================================================
   Handoff "Mes de venta" (2026-05-19) — pulido visual de las 2
   sub-páginas del eje venta + sub-popover del nav 3-niveles.
   Snapshot: Analytics Mes de Venta v2.html (Claude Design).
   ============================================================ */


/* ===== NUEVO — Sub-popover (3er nivel del nav) ============= */
/* Decisión de posicionamiento: CASCADA LATERAL a la derecha del
 * popover padre. Patrón estándar OS (Windows/macOS file menus,
 * Figma right-click). Mantiene visible el popover padre — el
 * operador puede volver al hermano sin re-abrir.
 *
 * El sub-popover NO usa hover-only: tiene `data-open=true`
 * togglable desde nav-sub.js para que tap táctil y Enter de
 * teclado lo abran sin necesidad de mantener el cursor sobre
 * el padre. */
.topbar nav .nav-subgroup {
  position: relative;
  /* el <li> padre limita el ancho; relative aquí ancla el sub-popover */
}

/* El sub-trigger es un <button>; le aplicamos el MISMO look-and-feel
 * que tiene un <a> del popover (Mes de informe) — para que el operador
 * no perciba diferencia visual entre "abrir sub-menu" y "navegar". La
 * única diferencia: `display: flex` con `justify-content: space-between`
 * para que el chevron `chev-r` quede pegado a la derecha. */
.topbar nav .nav-popover .nav-subtrigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin: 0;
  width: 100%;
  box-sizing: border-box;
  padding: 0.625rem 1.125rem;
  border-radius: 0;
  border: 0;
  background: transparent;
  font-family: inherit;
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--acq-text);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.topbar nav .nav-popover .nav-subtrigger:hover,
.topbar nav .nav-popover .nav-subtrigger:focus-visible {
  background: var(--acq-primary-soft);
  color: var(--acq-primary);
  outline: 0;
}
.topbar nav .nav-popover .nav-subgroup.active > .nav-subtrigger {
  background: var(--acq-primary-soft);
  color: var(--acq-primary);
  font-weight: 600;
}
.chev-r {
  display: inline-flex; align-items: center; justify-content: center;
  width: 12px; height: 12px; flex-shrink: 0;
  color: var(--acq-text-muted);
  transition: color 0.15s ease, transform 0.15s ease;
}
.chev-r svg { width: 100%; height: 100%; display: block; }
.topbar nav .nav-subtrigger:hover .chev-r,
.topbar nav .nav-subgroup.active > .nav-subtrigger .chev-r,
.topbar nav .nav-subgroup[data-open="true"] > .nav-subtrigger .chev-r {
  color: var(--acq-primary);
  transform: translateX(2px);
}
.topbar nav .nav-subpopover {
  display: block;            /* reset Pico nav ul { display: flex } */
  position: absolute;
  top: -0.375rem;            /* alinea con padding-top del popover padre */
  left: 100%;
  margin-left: 6px;          /* aire visible entre niveles */
  min-width: 280px;
  padding: 0.375rem 0;
  list-style: none;
  background: #FFFFFF;
  border: 1px solid var(--acq-border);
  border-radius: 14px;
  overflow: hidden;
  box-shadow: 0 1px 0 rgba(0,0,0,0.04), 0 16px 40px rgba(0,0,0,0.22);
  visibility: hidden;
  opacity: 0;
  transform: translateX(-4px);
  transition: opacity 0.12s ease, transform 0.12s ease,
              visibility 0s linear 0.12s;
  z-index: 90;
}
.topbar nav .nav-subgroup:hover > .nav-subpopover,
.topbar nav .nav-subgroup:focus-within > .nav-subpopover,
.topbar nav .nav-subgroup[data-open="true"] > .nav-subpopover {
  visibility: visible; opacity: 1; transform: translateX(0);
  transition: opacity 0.12s ease, transform 0.12s ease;
}
.topbar nav .nav-subpopover li {
  display: block; padding: 0; margin: 0; list-style: none;
}
.topbar nav .nav-subpopover a {
  display: block; margin: 0; width: 100%; box-sizing: border-box;
  padding: 0.625rem 1.125rem; border-radius: 0;
  color: var(--acq-text); font-size: 0.875rem; font-weight: 500;
  text-decoration: none;
  transition: background 0.15s ease, color 0.15s ease;
}
.topbar nav .nav-subpopover a:hover,
.topbar nav .nav-subpopover a:focus-visible {
  background: var(--acq-primary-soft); color: var(--acq-primary);
  outline: 0;
}
.topbar nav .nav-subpopover a.active {
  background: var(--acq-primary-soft); color: var(--acq-primary);
  font-weight: 600;
}
/* focus outline turquesa en sub-trigger (el browser default
 * no contrasta bien sobre el bg blanco del popover). */
.topbar nav .nav-subtrigger:focus-visible {
  outline: 2px solid var(--acq-primary);
  outline-offset: -2px;
}


/* ===== NUEVO — Header: h2-axis-suffix + meta-hint =========== */
/* Sufijo `/ eje venta` en el h2 cuando estamos en una sub-página
 * del eje venta. Read del header confirma modo sin escanear el
 * filter bar. */
.analytics-h2 .h2-axis-suffix {
  font-weight: 400; color: var(--acq-text-muted);
  font-size: 0.62em; letter-spacing: 0;
  margin-left: 0.5rem; vertical-align: 0.05em;
  white-space: nowrap;
}
/* Micro-caption bajo la meta line — indica que el sello fijado
 * a Acqustic es restricción de DISEÑO (no selección del operador). */
.analytics-meta-hint {
  display: block; margin-top: 0.25rem;
  font-size: 0.75rem; color: var(--acq-text-muted);
  font-style: italic;
}
.analytics-meta-hint::before {
  content: ""; display: inline-block;
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--acq-primary);
  vertical-align: 0.18em; margin-right: 0.4rem;
  opacity: 0.7;
}


/* =================================================================
   ============== NUEVO — Matriz mes_venta × mes_informe ===========
   ================================================================= */
/* Layout overview:
 *   El componente vive en `.matriz-venta-informe-section` (header →
 *   caption colapsable → tabla → footnote). La tabla
 *   `.matriz-venta-informe` está dentro del wrapper con
 *   `overflow:auto` y `max-height:640px` para que el scroll 4-way
 *   sea DENTRO de la pantalla, sin empujar el resto del layout.
 *
 * Sticky 4-way + z-index map (CRITICAL):
 *   7: top-left, top-right, bottom-left, bottom-right (4 esquinas)
 *   5: thead row1 / thead row2 (no-corner) + tfoot mid (no-corner)
 *   4: tbody primera col + tbody última col (no-corner)
 *   1: tbody body cells (no-sticky)
 *
 *   El orden importa porque dos stickys perpendiculares se solapan en
 *   las esquinas. Si el bottom-left (z=7) no estuviera por encima del
 *   thead-mid (z=5), al scrollear horizontal el contenido del cuerpo
 *   se vería "atravesar" el label TOTAL Facturado. Verificado
 *   Chrome / Safari / Firefox.
 */
.matriz-venta-informe-section { margin: 0 0 2rem 0; }

.matriz-venta-informe-section .section-header {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 1.5rem; margin: 0 0 0.5rem 0;
}
.matriz-venta-informe-section .section-header h3 {
  font-size: 1.15rem; font-weight: 600;
  display: inline-flex; align-items: baseline; gap: 0.6rem;
}
.matriz-venta-informe-section .section-header h3 .section-sub {
  font-weight: 400; font-size: 0.825rem;
  color: var(--acq-text-muted); letter-spacing: 0;
}

/* Heatmap legend (out of band) */
.heatmap-legend {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-size: 0.75rem; color: var(--acq-text-muted);
  padding: 0.375rem 0.75rem;
  background: var(--acq-surface-2);
  border-radius: 999px;
  white-space: nowrap;
}
.heatmap-legend .legend-bar {
  display: inline-block; width: 96px; height: 8px;
  border-radius: 4px;
  background: linear-gradient(
    to right,
    var(--acq-surface),
    color-mix(in srgb, var(--acq-primary) 15%, var(--acq-surface)),
    color-mix(in srgb, var(--acq-primary) 35%, var(--acq-surface)),
    color-mix(in srgb, var(--acq-primary) 55%, var(--acq-surface)),
    var(--acq-primary)
  );
  border: 1px solid var(--acq-border);
}
.heatmap-legend .legend-bar-label {
  font-variant-numeric: tabular-nums;
  color: var(--acq-text);
}

/* Caption colapsable — patrón <details>.
 *
 * <details open> por defecto (didáctico). El operador puede
 * colapsar tras la primera lectura; el estado se persiste en
 * sessionStorage (ver nav-sub.js parte final).
 *
 * Marker custom (chevron SVG) en vez del triángulo nativo del
 * browser, que renderiza distinto entre Chrome y Safari. */
.matriz-caption {
  margin: 0 0 1rem 0;
  background: var(--acq-surface-2);
  border: 1px solid var(--acq-border);
  border-radius: 10px;
  font-size: 0.85rem;
  color: var(--acq-text-muted);
  line-height: 1.5;
}
.matriz-caption summary {
  list-style: none;
  cursor: pointer; user-select: none;
  padding: 0.625rem 0.875rem;
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-weight: 600; color: var(--acq-text);
  font-size: 0.825rem;
}
.matriz-caption summary::-webkit-details-marker { display: none; }
.matriz-caption summary .chev {
  display: inline-flex; transition: transform 0.18s ease;
  color: var(--acq-text-muted);
}
.matriz-caption[open] summary .chev { transform: rotate(90deg); }
.matriz-caption summary:focus-visible {
  outline: 2px solid var(--acq-primary);
  outline-offset: -2px;
  border-radius: 10px;
}
.matriz-caption .caption-body {
  padding: 0 0.875rem 0.875rem 0.875rem;
  max-width: 76ch;
}
.matriz-caption .caption-body p { margin: 0 0 0.5rem 0; }
.matriz-caption .caption-body p:last-child { margin-bottom: 0; }
.matriz-caption strong { color: var(--acq-text); font-weight: 600; }

/* Tabla wrapper — scroll 2D + ring de borde + cue de scrollabilidad
 * lateral (patrón Lea Verou con background-attachment local).
 *
 * Ajuste 2026-05-19 (b): `max-height` con `clamp()` para que escale
 * con el viewport tras simplificar el filter bar en la página matriz.
 *
 * Fórmula: `clamp(420px, calc(100vh - 440px), 1100px)`
 *   - 100vh − 440px = alto disponible tras descontar el chrome:
 *     topbar (72) + content padding (32+32) + subnav (56+24) + header
 *     (~100 con meta-hint) + filter bar simplificado (~108+24) + section
 *     header (40+8) + caption colapsada (40+16) + footnote (~30) ≈ 440px.
 *   - Floor 420px: en laptops a 768px la matriz no se queda inutilizable.
 *   - Cap 1100px: en monitores 4K no se traga la página completa.
 *
 * Si el operador abre el <details> del caption, éste añade ~120px y
 * la matriz se reduce automáticamente (no es necesario un cálculo
 * dinámico — el flujo CSS comprime el wrapper porque el body no es
 * el scroll container; el wrapper sí). */
.matriz-venta-informe-wrapper {
  position: relative;
  border: 1px solid var(--acq-border);
  border-radius: 12px;
  overflow: auto;
  max-height: clamp(420px, calc(100vh - 440px), 1100px);
  background: var(--acq-surface);
  background:
    linear-gradient(to right, var(--acq-surface) 30%, rgba(255,255,255,0))
      left top / 16px 100% no-repeat local,
    linear-gradient(to left,  var(--acq-surface) 30%, rgba(255,255,255,0))
      right top / 16px 100% no-repeat local,
    radial-gradient(ellipse at left,  rgba(43,43,52,0.10), rgba(255,255,255,0) 70%)
      left top / 16px 100% no-repeat scroll,
    radial-gradient(ellipse at right, rgba(43,43,52,0.10), rgba(255,255,255,0) 70%)
      right top / 16px 100% no-repeat scroll,
    var(--acq-surface);
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--acq-text-muted) 50%, transparent) transparent;
}
.matriz-venta-informe-wrapper::-webkit-scrollbar { width: 10px; height: 10px; }
.matriz-venta-informe-wrapper::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--acq-text-muted) 40%, transparent);
  border-radius: 6px;
  border: 2px solid transparent; background-clip: padding-box;
}
.matriz-venta-informe-wrapper::-webkit-scrollbar-thumb:hover {
  background: color-mix(in srgb, var(--acq-text-muted) 65%, transparent);
  background-clip: padding-box; border: 2px solid transparent;
}

.matriz-venta-informe {
  border-collapse: separate; border-spacing: 0;
  width: max-content; min-width: 100%;
  font-size: 0.825rem;
  font-variant-numeric: tabular-nums;
  font-feature-settings: var(--num-features);
  background: var(--acq-surface);
}

/* --- Headers (2 filas, ambas sticky-top) -------------------- */
.matriz-venta-informe thead th {
  position: sticky;
  white-space: nowrap;
  text-align: right;
  background-clip: padding-box;
}
/* DUAL HEADER unificado: ambas rows comparten bg primary saturado,
 * size 0.78rem y letter-spacing 0.02em. La jerarquía se construye
 * SÓLO con peso tipográfico (600 vs 500) y opacidad del texto
 * (100% vs 85%) — así Mes de facturación + Mes de informe se leen
 * como UN bloque de dos líneas relacionadas, no como dos cajas
 * inconexas. Heights idénticos → simetría visual; el separador
 * entre rows es un border-bottom blanco al 18% (apenas visible).
 *
 * /review follow-up 2026-05-19: el alto de row 1 y el offset
 * sticky de row 2 viajan acoplados via `--matriz-thead-row-h`
 * (CSS variable). Si cambias el valor, ambos saltan a la vez —
 * elimina la fragilidad de "row 2 shiftea si tocas padding/font
 * de row 1 sin actualizar también el top". */
.matriz-venta-informe thead {
  --matriz-thead-row-h: 36px;
}
.matriz-venta-informe thead tr:nth-child(1) th {
  top: 0; z-index: 5;
  height: var(--matriz-thead-row-h);
  line-height: 1.2;
  box-sizing: border-box;
  background: var(--acq-primary);
  color: #FFFFFF;
  font-weight: 600; font-size: 0.78rem;
  letter-spacing: 0.02em;
  padding: 0 0.875rem;
  border-bottom: 1px solid rgba(255,255,255,0.18);
}
.matriz-venta-informe thead tr:nth-child(2) th {
  top: var(--matriz-thead-row-h); z-index: 5;
  height: var(--matriz-thead-row-h);
  line-height: 1.2;
  box-sizing: border-box;
  background: var(--acq-primary);
  color: rgba(255,255,255,0.85);
  font-weight: 500; font-size: 0.78rem;
  letter-spacing: 0.02em;
  padding: 0 0.875rem;
  border-bottom: 1.5px solid var(--acq-primary-hover);
}

/* Corner top-left (rowspan=2). Sticky top+left → z=7. Texto
 * multi-línea con grid 2×2 (flecha + label por eje) — SR-friendly
 * vs un <br> opaco. */
.matriz-venta-informe thead th.matriz-corner-tl {
  left: 0; top: 0;
  z-index: 7;
  background: var(--acq-primary);
  color: #FFFFFF;
  text-align: left;
  padding: 0.625rem 1rem;
  border-top-left-radius: 12px;
  /* La fila inferior ahora contiene "↓ Mes de venta  → Mes de informe"
   * en línea, así que el corner necesita más anchura que cuando sólo
   * tenía dos líneas con un único par cada una. */
  min-width: 304px;
  box-shadow: 4px 0 6px -4px rgba(0,0,0,0.18);
}
.matriz-corner-tl .corner-grid {
  display: flex;
  flex-direction: column;
  row-gap: 0.25rem;
}
.matriz-corner-tl .axis-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.matriz-corner-tl .axis-key {
  font-size: 0.66rem; font-weight: 600;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: #FFFFFF;
  white-space: nowrap;
}
.matriz-corner-tl .axis-arrow {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px;
  flex: 0 0 18px;
  border-radius: 5px;
  background: rgba(255,255,255,0.18);
  font-size: 0.78rem; font-weight: 700;
  line-height: 1;
  color: #FFFFFF;
}
/* Separador visual entre la primera pareja (↓ Mes de venta) y la
 * segunda (→ Mes de informe) cuando viven en la misma axis-row. */
.matriz-corner-tl .axis-arrow-extra { margin-left: 0.75rem; }

/* Corner top-right: TOTAL Devengado (sticky top + right). */
.matriz-venta-informe thead th.matriz-corner-tr {
  right: 0; top: 0; z-index: 7;
  background: var(--acq-primary);
  color: #FFFFFF;
  text-align: right;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  border-top-right-radius: 12px;
  border-left: 1.5px solid var(--acq-primary-hover);
  padding: 0.625rem 1rem;
  box-shadow: -4px 0 6px -4px rgba(0,0,0,0.18);
  min-width: 116px;
}

/* --- Body cells -------------------------------------------- */
.matriz-venta-informe tbody td,
.matriz-venta-informe tbody th {
  padding: 0.45rem 0.875rem;
  border-bottom: 1px solid var(--acq-border);
  white-space: nowrap;
  height: 32px;
  vertical-align: middle;
}
.matriz-venta-informe tbody td {
  text-align: right;
  color: var(--acq-text);
  background: var(--acq-surface);
}

/* Primera columna sticky-left = label mes_venta */
.matriz-venta-informe tbody th.matriz-row-label {
  position: sticky; left: 0; z-index: 4;
  background: var(--acq-surface);
  text-align: left;
  font-weight: 600; font-size: 0.82rem;
  color: var(--acq-text);
  padding: 0.45rem 1rem;
  box-shadow: 4px 0 6px -4px rgba(43,43,52,0.08);
  min-width: 168px;
}

/* Año frontera: separador visible NO-cromático (no es heatmap) */
.matriz-venta-informe tbody tr.year-border th.matriz-row-label,
.matriz-venta-informe tbody tr.year-border td {
  border-top: 1.5px dashed color-mix(in srgb, var(--acq-primary) 30%, transparent);
}

/* HEATMAP — log-scale turquesa sobre celdas DATA (no totales).
 *
 * Mapeo: cada td recibe --cell-intensity ∈ [0,1] computado en
 *        el template (Jinja) via
 *           log10(value + 1) / log10(maxCell + 1)
 * Fill:  mix(--acq-primary @ intensity*68%, surface) — pegado al
 *        68% para que la celda más "caliente" conserve contraste
 *        ≥ 4.5:1 con el texto oscuro (WCAG AA).
 * Bins:  además de la intensidad continua, etiquetamos data-bin
 *        (lo/mid/hi/peak) para ajustar peso tipográfico — la
 *        diagonal sigue siendo legible en monocromía (a11y).
 *
 * Por qué NO aplicamos heatmap a la fila/col TOTAL: son sumas y
 * destacarían por intensidad simplemente por ser agregados, no
 * por ser relevantes — el operador perdería la señal real. */
.matriz-venta-informe .heat-cell {
  --cell-intensity: 0;
  background-color: color-mix(
    in srgb,
    var(--acq-primary) calc(var(--cell-intensity) * 68%),
    var(--acq-surface)
  );
}
.matriz-venta-informe .heat-cell[data-bin="lo"]  {
  color: var(--acq-text-muted); font-weight: 400;
}
.matriz-venta-informe .heat-cell[data-bin="mid"] {
  color: var(--acq-text); font-weight: 500;
}
.matriz-venta-informe .heat-cell[data-bin="hi"]  {
  color: #FFFFFF; font-weight: 600;
}
.matriz-venta-informe .heat-cell[data-bin="peak"] {
  color: #FFFFFF; font-weight: 700;
  /* Signal NO-cromático para a11y monocromía: borde inferior fino
   * blanco que sólo aparece en el bin peak. Marca tipográfica
   * de la diagonal incluso impreso en B/N. */
  box-shadow: inset 0 -2px 0 rgba(255,255,255,0.55);
}

/* Celda vacía: NADA (sin glifo). Demasiados "—" repetidos
 * generaban ruido visual; la ausencia ya transmite "no aplica".
 * Para SR ponemos aria-label="sin valor" en el markup. */
.matriz-venta-informe .heat-empty {
  background: var(--acq-surface);
}

/* Columna sticky-right TOTAL Devengado (por fila / por mes_venta) */
.matriz-venta-informe td.matriz-row-total {
  position: sticky; right: 0; z-index: 4;
  background: color-mix(in srgb, var(--acq-primary) 6%, var(--acq-surface));
  font-weight: 700;
  border-left: 1.5px solid color-mix(in srgb, var(--acq-primary) 18%, var(--acq-border));
  box-shadow: -4px 0 6px -4px rgba(43,43,52,0.08);
  min-width: 116px;
}

/* --- tfoot: TOTAL Facturado por mes_informe + GRAN TOTAL ---
 *
 * Fix 2026-05-19: el fondo pasa de `--acq-primary-soft` (12% sobre
 * TRANSPARENT) a un mix opaco contra `--acq-surface`. Sin esto, al
 * scrollear verticalmente las filas del body se veían "atravesar"
 * el tfoot sticky por la semi-transparencia. Ahora el footer tapa
 * sólido lo que pasa por debajo. */
.matriz-venta-informe tfoot th,
.matriz-venta-informe tfoot td {
  position: sticky;
  bottom: 0;
  z-index: 5;
  background: color-mix(in srgb, var(--acq-primary) 12%, var(--acq-surface));
  font-weight: 700; font-size: 0.825rem;
  padding: 0.6rem 0.875rem;
  border-top: 1.5px solid var(--acq-primary);
  text-align: right;
  white-space: nowrap;
  background-clip: padding-box;
}
.matriz-venta-informe tfoot th.matriz-foot-label {
  /* Esquina bottom-left */
  left: 0; bottom: 0; z-index: 7;
  background: color-mix(in srgb, var(--acq-primary) 12%, var(--acq-surface));
  text-align: left;
  text-transform: uppercase;
  font-size: 0.7rem; letter-spacing: 0.06em;
  color: var(--acq-primary-hover);
  padding: 0.6rem 1rem;
  box-shadow: 4px 0 6px -4px rgba(43,43,52,0.08);
  border-top: 1.5px solid var(--acq-primary);
}
.matriz-venta-informe tfoot td.matriz-grand-total {
  /* Esquina bottom-right */
  right: 0; bottom: 0; z-index: 7;
  background: var(--acq-primary);
  color: #FFFFFF;
  border-left: 1.5px solid var(--acq-primary-hover);
  box-shadow: -4px 0 6px -4px rgba(43,43,52,0.08);
  font-size: 0.9rem;
  border-top: 1.5px solid var(--acq-primary-hover);
}

/* --- Hover crosshair (highlight fila + columna activa) ----- */
.matriz-venta-informe tbody tr:hover th.matriz-row-label {
  background: var(--acq-primary-soft);
  color: var(--acq-primary-hover);
}
.matriz-venta-informe tbody tr:hover td:not(.matriz-row-total):not(.heat-empty) {
  background-color: color-mix(
    in srgb,
    var(--acq-primary) calc(var(--cell-intensity, 0) * 68% + 8%),
    var(--acq-surface)
  );
}
.matriz-venta-informe tbody tr:hover td.heat-empty {
  background: color-mix(in srgb, var(--acq-primary) 4%, var(--acq-surface));
}
.matriz-venta-informe tbody tr:hover td.matriz-row-total {
  background: color-mix(in srgb, var(--acq-primary) 16%, var(--acq-surface));
}

/* Footnote del pie de la matriz (sin caja) */
.matriz-footnote {
  margin: 0.875rem 0 0 0;
  color: var(--acq-text-muted);
  font-size: 0.8rem;
}

/* ---------------------------------------------------------------------
 * Admin panel — T15+ (SHOULD-FIX-1 del /review dc6d2d1)
 * Chips + utility classes usadas por templates/admin/users_list.html.j2.
 * BACKSTAGE: chips redondeados pequeños, fondo tintado por categoría.
 * --------------------------------------------------------------------- */

/* Base chip — heredan los variantes. Usa color-mix con la paleta de
 * acq-primary para que se adapte a light/dark sin redefinir colores. */
.chip {
  display: inline-block;
  padding: 0.15rem 0.5rem;
  margin-left: 0.4rem;
  font-size: 0.75rem;
  font-weight: 500;
  border-radius: 999px;
  vertical-align: baseline;
  background: color-mix(in srgb, var(--acq-primary) 8%, var(--acq-surface));
  color: var(--acq-text);
}

/* Chip "tú" — el master logged in se identifica en su fila. */
.chip-self {
  background: color-mix(in srgb, var(--acq-primary) 24%, var(--acq-surface));
  color: var(--acq-primary);
  font-weight: 600;
}

/* Chips de role: master destacado, empleado neutral, titular (3er rol de
   primera clase, no una variante de empleado) con tinte propio (índigo)
   para distinguir los 3 roles de un vistazo en la tabla de usuarios. */
.chip-role-master {
  background: color-mix(in srgb, var(--acq-primary) 20%, var(--acq-surface));
  color: var(--acq-primary);
  font-weight: 600;
}
.chip-role-empleado {
  background: color-mix(in srgb, var(--acq-text-muted) 16%, var(--acq-surface));
  color: var(--acq-text);
}
.chip-role-titular {
  background: color-mix(in srgb, #6366f1 18%, var(--acq-surface));
  color: #4338ca;
}

/* Celda de acciones de la tabla de usuarios: separa botones adyacentes
   ("Editar" + "Ver como") para evitar que queden pegados / mis-tap. */
.t-right .btn + .inline-form,
.t-right .inline-form + .btn,
.t-right .btn + .btn { margin-left: 0.4rem; }

/* Chips de estado: ok / disabled / warning. */
.chip-ok {
  background: color-mix(in srgb, #1f9d6e 18%, var(--acq-surface));
  color: #0f7a52;
}
.chip-disabled {
  background: color-mix(in srgb, var(--acq-text-muted) 22%, var(--acq-surface));
  color: var(--acq-text-muted);
  text-decoration: line-through;
}
.chip-warning {
  background: color-mix(in srgb, #e8a93b 22%, var(--acq-surface));
  color: #9a6a07;
  font-weight: 500;
}

/* Row muted — empleados disabled atenuados en la tabla. */
.row-muted {
  opacity: 0.55;
}

/* ============================================================
 * Tag-input componente (`_tag_input.html.j2` + `tag_input.js`).
 *
 * Container = caja flex que pinta los chips ya seleccionados y
 * el input de búsqueda en la misma "línea visual" (wrap si
 * crece). Mismo lenguaje de chips del admin panel.
 * ============================================================ */
.tag-input-container {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  padding: 0.35rem 0.5rem;
  border: 1px solid var(--acq-border, #d4d4d4);
  border-radius: 4px;
  background: var(--acq-surface, #fff);
  align-items: center;
}
.tag-input-container:focus-within {
  border-color: var(--acq-primary);
  box-shadow: 0 0 0 1px var(--acq-primary);
}
.tag-input-container .tag-chips {
  display: contents;
}
.tag-input-container .tag-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.15rem 0.55rem;
  font-size: 0.825rem;
  font-weight: 500;
  border-radius: 999px;
  background: color-mix(in srgb, var(--acq-primary) 16%, var(--acq-surface));
  color: var(--acq-primary);
  line-height: 1.4;
  /* Evita que el chip parta su nombre en dos líneas si el container
     se queda pequeño — el flex-wrap del container lo baja entero. */
  white-space: nowrap;
}
.tag-input-container .tag-chip-remove {
  background: transparent;
  border: 0;
  padding: 0 0.15rem;
  margin: 0;
  cursor: pointer;
  color: inherit;
  font-size: 1rem;
  line-height: 1;
  font-weight: 700;
}
.tag-input-container .tag-chip-remove:hover,
.tag-input-container .tag-chip-remove:focus-visible {
  color: color-mix(in srgb, var(--acq-primary) 70%, black);
}
.tag-input-container .tag-input {
  flex: 1 1 12ch;
  min-width: 12ch;
  padding: 0.25rem 0.4rem;
  border: 0;
  outline: none;
  background: transparent;
  font: inherit;
  color: inherit;
}

/* Botón "Seleccionar todo" del tag-input (opt-in vía `select_all`). Discreto,
 * estilo enlace, alineado al final de la caja de chips. */
.tag-input-container .tag-select-all {
  flex: 0 0 auto;
  margin: 0;
  padding: 0.1rem 0.4rem;
  border: 0;
  background: transparent;
  color: var(--acq-primary);
  font: inherit;
  font-size: 0.78rem;
  line-height: 1.2;
  white-space: nowrap;
  cursor: pointer;
  width: auto;
}

.tag-input-container .tag-select-all:hover,
.tag-input-container .tag-select-all:focus-visible {
  color: var(--acq-primary-hover);
  text-decoration: underline;
}

/* Footnote opcional debajo del KPI box de `/royalties/artistas` —
 * explica que `Comisión Sello` puede incluir tracks sin rightholder
 * (en el catálogo) además de la cuota del sello. Solo se renderiza
 * cuando hay datos. */
.report-kpi-footnote {
  margin-top: 0.5rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--acq-border);
  color: var(--acq-text-muted);
  font-size: 0.78rem;
  line-height: 1.4;
}

/* ============================================================
 * Royalties › Artistas — filter row.
 *
 * Layout opción (a) del último feedback: input full-width dentro
 * de la cell (40px exactos como `.report-filter-input`); los chips
 * seleccionados viven en `.artistas-chips-row` debajo del filter-row.
 * Así el input siempre ocupa todo el ancho de su cell y no comparte
 * espacio con los chips.
 * ============================================================ */

/* `.report-filter-input` height 40px duros — establecido por el
 * handoff para que los selects/inputs sean medibles 1:1 con la cell
 * del tag-input. */
.report-filter-input {
  height: 40px;
  line-height: 1.4;
}

/* Cell wrapper: solo para el state `.is-required-empty` (marca roja
 * cuando Artistas obligatorio está vacío al hacer submit). El input
 * interno hereda TODOS los estilos visuales de `.report-filter-input`
 * (mismo bg, padding, font, height) para que se vea pixel-idéntico a
 * un select vecino. */
.artistas-tag-cell {
  display: block;
  min-width: 0;
}
.artistas-tag-input {
  /* Clon literal de `.report-filter-input` para alineación 1:1 con
   * los selects de mes/año vecinos del grid. */
  background: #FFFFFF;
  border: 0;
  border-radius: 10px;
  padding: 0.625rem 0.875rem;
  font-family: var(--acq-font-sans);
  font-size: 0.9rem;
  line-height: 1.4;
  color: var(--acq-text);
  width: 100%;
  height: 40px;
  min-width: 0;
  box-sizing: border-box;
}
.artistas-tag-input::placeholder {
  color: rgba(43, 43, 52, 0.45);
}
.artistas-tag-cell.is-required-empty .artistas-tag-input {
  box-shadow: inset 0 0 0 1.5px rgba(230, 75, 61, 0.45);
}
.artistas-tag-cell.is-required-empty .artistas-tag-input::placeholder {
  color: rgba(230, 75, 61, 0.75);
}

/* Row de chips seleccionados — debajo del filter-row, full-width.
 * Wrap libre (cuando hay muchos chips bajan a otra línea). Margen
 * superior pequeño para separar visualmente del filter-row. */
.artistas-chips-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-top: 0.25rem;
}
.artistas-chips-row .tag-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  height: 24px;
  padding: 0 0.4rem 0 0.625rem;
  border-radius: 999px;
  font-size: 0.8rem;
  font-weight: 500;
  white-space: nowrap;
  line-height: 1;
}
/* Color diferenciado por tipo de chip — todos blancos; el matiz viene
 * del color del border, que contrasta con el primary-hover del filter
 * card. Mismo formato (alto/padding/radio) en los tres niveles.
 *  - artistas      → border rojo (`--acq-error`, filtro obligatorio).
 *  - pistas        → border negro/oscuro (`--acq-text`, secundario).
 *  - rightholders  → border amarillo (`--acq-warning`, 3er nivel).
 */
.artistas-chips-row .tag-chip[data-chip-name="artistas"] {
  background: #FFFFFF;
  color: var(--acq-text);
  border: 1.5px solid var(--acq-error);
}
.artistas-chips-row .tag-chip[data-chip-name="pistas"] {
  background: #FFFFFF;
  color: var(--acq-text);
  border: 1.5px solid var(--acq-text);
}
.artistas-chips-row .tag-chip[data-chip-name="rightholders"] {
  background: #FFFFFF;
  color: var(--acq-text);
  border: 1.5px solid var(--acq-warning);
}
.artistas-chips-row .tag-chip-label {
  /* `line-height: 24px` (= alto del chip) forza al text a ocupar el
   * line-box COMPLETO del chip — el centro óptico del texto queda
   * en (24 / 2) = 12px del top, MISMO eje vertical que el botón
   * remove (también centrado flex en 24px).
   *
   * Sin esto, Inter (font-size 0.8rem ≈ 12.8px) renderiza el text en
   * un line-box de 12.8px → el centro óptico queda a ~6-7px del top
   * del line-box → ~5-6px del top del chip → 6px ARRIBA del centro
   * del botón remove (12px). Eso es el "X elevada" del feedback.
   */
  line-height: 24px;
  user-select: none;
}
/* Botón remove: wrapper flex que centra el SVG matemáticamente. El
 * `display: block` en el SVG elimina su baseline behavior (default
 * inline para `<svg>`), asegurando que el flex center funcione.
 */
.artistas-chips-row .tag-chip-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  border: 0;
  background: transparent;
  color: var(--acq-text-muted);
  cursor: pointer;
  padding: 0;
  border-radius: 50%;
  /* Offset manual del usuario: el centrado flex calculado dejaba la
   * X visualmente elevada respecto al label en Inter; +6px lo asienta
   * al baseline visual del texto. */
  position: relative;
  top: 6px;
}
.artistas-chips-row .tag-chip-remove svg {
  display: block;
  width: 10px;
  height: 10px;
}
.artistas-chips-row .tag-chip-remove:hover {
  color: var(--acq-text);
  background: rgba(43, 43, 52, 0.08);
}

/* ============================================================
 * Royalties › Artistas — `.table-bare` + modificador `.artistas-
 * pivot-table` con group rows.
 *
 * `.table-bare` ya aporta la estética base (headers transparentes
 * uppercase muted, body plano, hairlines, hover surface-2, TOTAL
 * con border-top fuerte). Aquí solo se añaden:
 *   - Drill-down click (cursor + caret rotador) sobre `.table-bare`.
 *   - Subfilas (`[data-sub-row]`) con label muted indentado +
 *     glyph `↳` via `::before` — sin bg, sin font-size distinto.
 *   - `.col-total` (peso 600 en la última col).
 *   - Group rows `.track-group` / `.artist-group` (parents bold,
 *     border-top entre grupos).
 *   - `.col-artista` (col secundaria muted en sección A).
 *   - `.cell-empty` (placeholders "—" muted).
 * ============================================================ */
.table-bare tr[data-toggle-subs] {
  cursor: pointer;
}
.table-bare tr[data-toggle-subs] .row-caret {
  display: inline-block;
  width: 0.85em;
  margin-right: 0.4rem;
  color: var(--acq-text-muted);
  transition: transform 0.15s ease;
  transform-origin: center;
}
.table-bare tr[data-toggle-subs][aria-expanded="true"] .row-caret {
  transform: rotate(90deg);
  color: var(--acq-primary);
}
.table-bare tr[data-toggle-subs]:hover th[scope="row"],
.table-bare tr[data-toggle-subs]:hover td {
  background: var(--acq-surface-2);
}

.table-bare tr[data-sub-row] th[scope="row"] {
  font-weight: 400;
  color: var(--acq-text-muted);
  /* Indentación por profundidad: `--rh-depth` (1, 2, …) lo fija la
   * fila inline. Nivel 1 = 2.5rem (idéntico al diseño previo de la
   * vista de 2 niveles); cada nivel extra añade 1.5rem. Soporta el
   * drill de 3 niveles (artista → pista → rightholder). */
  padding-left: calc(1rem + var(--rh-depth, 1) * 1.5rem);
  /* No fijamos `position: relative` aquí: en `.artistas-pivot-table`
   * el `.col-label` lleva `position: sticky` (sección 1ª col fija
   * en horizontal). Un `position: relative` aquí ganaba en
   * especificidad y rompía el sticky de las subfilas: scrolleaban
   * con los meses y, al hacer click en el parent, el contenido se
   * desplazaba. `position: sticky` ya actúa como contexto posicional
   * para el `::before` absolute. */
}
.table-bare tr[data-sub-row] th[scope="row"]::before {
  content: "↳";
  position: absolute;
  left: calc(var(--rh-depth, 1) * 1.5rem);
  color: var(--acq-text-muted);
  opacity: 0.55;
}
.table-bare tr[data-sub-row] td {
  color: var(--acq-text-muted);
  font-weight: 400;
}

.table-bare .col-total {
  font-weight: 600;
  color: var(--acq-text);
}
.table-bare thead th.col-total {
  font-weight: 600;
}

.cell-empty {
  color: var(--acq-text-muted);
  font-weight: 400;
  opacity: 0.7;
}

.row-sub-label {
  color: var(--acq-text-muted);
  font-weight: 400;
  margin-left: 0.25rem;
}

/* Group rows — parents bold + separador entre grupos consecutivos.
 * La jerarquía es tipográfica, no cromática. */
.artistas-pivot-table tr.track-group th[scope="row"],
.artistas-pivot-table tr.artist-group th[scope="row"] {
  font-weight: 600;
  color: var(--acq-text);
}
.artistas-pivot-table tr.track-group td,
.artistas-pivot-table tr.artist-group td {
  font-weight: 600;
}
.artistas-pivot-table tbody > tr.track-group:not(:first-child) > *,
.artistas-pivot-table tbody > tr.artist-group:not(:first-child) > * {
  border-top: 1.5px solid var(--acq-border);
}

/* Anchos consistentes para alinear las 3 tablas columna por columna.
 *
 * Mismo patrón que `/analytics/venta/analiticas`:
 *  - Wrapper con `overflow-x: auto` → scroll horizontal cuando el
 *    contenido excede el viewport.
 *  - Sin `table-layout: fixed` → la tabla crece a `max-content` por
 *    suma de `min-width` de cada celda; el browser nunca comprime
 *    columnas para caber en el wrapper. Con muchos meses la tabla
 *    se vuelve más ancha y aparece el scroll.
 *  - `white-space: nowrap` en TODA celda → ninguna cifra parte línea.
 *
 *   - col-label: 18rem max + ellipsis si el nombre de pista es largo.
 *   - col-mes:   7rem min (cabe "1.234,56 €" + padding).
 *   - col-total: 9rem min (totales 5-cifra).
 */
.artistas-pivot-wrapper {
  overflow-x: auto;
  position: relative;
}
.artistas-pivot-table {
  width: max-content;
  min-width: 100%;
}
.artistas-pivot-table th,
.artistas-pivot-table td {
  white-space: nowrap;
}
.artistas-pivot-table .col-label {
  /* `min-width` igual al `max-width` para que la col NO crezca cuando
   * se expanden subfilas con `padding-left: 2.5rem` + nombres de RH
   * largos (caso de "Francisco Javier Ojanguren Garcia" etc.). Antes
   * la col reflowaba al hacer click y empujaba los meses lateralmente. */
  min-width: 20rem;
  max-width: 20rem;
  overflow: hidden;
  text-overflow: ellipsis;
}
.artistas-pivot-table .col-mes {
  min-width: 7rem;
}
.artistas-pivot-table .col-total {
  min-width: 9rem;
}

/* Col-label sticky a la izquierda con bg opaco — los meses scrollean
 * por debajo de ella, no se solapa el texto. Sombra lateral para
 * señalar la separación. */
.artistas-pivot-table thead .col-label,
.artistas-pivot-table tbody .col-label {
  position: sticky;
  left: 0;
  z-index: 1;
  background: var(--acq-surface);
  box-shadow: 4px 0 6px -4px rgba(43, 43, 52, 0.08);
}
/* Hover de fila: el bg surface-2 se aplica también a la sticky col. */
.artistas-pivot-table tbody tr:hover .col-label {
  background: var(--acq-surface-2);
}
/* Fila TOTAL: bg transparent (no surface-2) en la sticky col para que
 * el border-top fuerte se vea limpio. */
.artistas-pivot-table tbody tr.report-total .col-label {
  background: var(--acq-surface);
}

/* T51 — Bloques de asignación por tenant en el admin edit/create. */
.tenant-assignment {
  border: 1px solid var(--acq-border, #d4d4d4);
  border-radius: 6px;
  padding: 0.75rem 1rem 0.5rem;
  background: color-mix(in srgb, var(--acq-primary) 3%, var(--acq-surface));
}
.tenant-assignment legend {
  padding: 0 0.4rem;
  font-weight: 600;
  color: var(--acq-primary);
}

/* T51-D UX rediseño — tenant-card con toggle + conditional body. */
.tenant-card {
  border: 1px solid var(--acq-border, #d4d4d4);
  border-radius: 8px;
  padding: 0.5rem 1rem 0.75rem;
  background: var(--acq-surface, #fff);
  transition: background 0.15s ease, border-color 0.15s ease;
}
.tenant-card.tenant-card-on {
  background: color-mix(in srgb, var(--acq-primary) 4%, var(--acq-surface));
  border-color: color-mix(in srgb, var(--acq-primary) 35%, var(--acq-border, #d4d4d4));
}
.tenant-card > legend {
  padding: 0 0.4rem;
}
.tenant-card-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  cursor: pointer;
  font-weight: 600;
  font-size: 1rem;
  color: var(--acq-text);
}
.tenant-card-toggle input[type="checkbox"] {
  /* Toggle visual más prominente que un checkbox plano. */
  width: 1.05rem;
  height: 1.05rem;
  accent-color: var(--acq-primary);
}
.tenant-card.tenant-card-on .tenant-card-toggle {
  color: var(--acq-primary);
}
.tenant-card-name {
  /* Nombre del sello (Acqustic, Voltereta, …). */
  letter-spacing: 0.01em;
}
.tenant-card-body {
  margin-top: 0.5rem;
}
.tenant-card-body[hidden] {
  display: none;
}

/* Segmented control para el rol — mejor UX que radios sueltos. */
.segmented-control {
  display: inline-flex;
  border: 1px solid var(--acq-border, #d4d4d4);
  border-radius: 6px;
  overflow: hidden;
  background: var(--acq-surface, #fff);
}
.segmented-option {
  margin: 0;
  cursor: pointer;
}
.segmented-option input[type="radio"] {
  /* Hide the native radio; lo controlamos con el sibling label. */
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.segmented-option span {
  display: inline-block;
  padding: 0.35rem 0.9rem;
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--acq-text-muted);
  background: transparent;
  border-right: 1px solid var(--acq-border, #d4d4d4);
  transition: background 0.12s ease, color 0.12s ease;
}
.segmented-option:last-child span {
  border-right: 0;
}
.segmented-option input[type="radio"]:checked + span {
  background: var(--acq-primary);
  color: var(--acq-on-primary, white);
}
.segmented-option:hover span {
  background: color-mix(in srgb, var(--acq-primary) 10%, var(--acq-surface));
  color: var(--acq-text);
}
.segmented-option input[type="radio"]:checked + span:hover {
  background: color-mix(in srgb, var(--acq-primary) 88%, black);
}
.segmented-option input[type="radio"]:focus-visible + span {
  outline: 2px solid var(--acq-primary);
  outline-offset: -2px;
}

/* Hidden state for conditional sections (data-empleado-only). */
.tenant-card-body [data-empleado-only][hidden] {
  display: none;
}

/* Advanced section colapsable. */
.form-advanced {
  margin-top: 0.75rem;
  padding-top: 0.5rem;
  border-top: 1px dashed var(--acq-border, #d4d4d4);
}
.form-advanced > summary {
  cursor: pointer;
  font-size: 0.85rem;
  color: var(--acq-text-muted);
  font-weight: 500;
}
.form-advanced > summary:hover {
  color: var(--acq-text);
}
.t-section-title {
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--acq-text);
  margin-bottom: 0.25rem;
}
/* Chip info-only para tenants fuera de la autoridad del ejecutor —
   stripped (F1): solo tenant_name, sin role/disabled/scope. */
.chip-info {
  background: color-mix(in srgb, var(--acq-text-muted) 14%, var(--acq-surface));
  color: var(--acq-text-muted);
}

/* Botón primario + small (variantes del .btn base). */
.btn-primary {
  background: var(--acq-primary);
  color: var(--acq-on-primary, white);
  border-color: var(--acq-primary);
}
.btn-primary:hover,
.btn-primary:focus-visible {
  background: color-mix(in srgb, var(--acq-primary) 88%, black);
  border-color: color-mix(in srgb, var(--acq-primary) 88%, black);
}
.btn-small {
  padding: 0.25rem 0.6rem;
  font-size: 0.825rem;
}

/* Utilities para tabla y page-head. */
.t-muted {
  color: var(--acq-text-muted);
}
.t-right {
  text-align: right;
}
.page-head-actions {
  /* page-head ya es flex; este wrapper agrupa acciones de la derecha. */
  display: flex;
  gap: 0.5rem;
  align-items: center;
}

/* `.inline-edit` — form de edición inline dentro de una celda de tabla
 * (input + botones en una fila compacta). Usado por la tabla de override
 * de /options/lanzamientos. */
.inline-edit {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  flex-wrap: wrap;
}

/* --- /options/lanzamientos: vista agrupada por EP/Álbum ------------------- */
/* `.muted` utilitario — texto atenuado (antes solo existía `.alert.muted`). */
.muted {
  color: var(--acq-text-muted);
}
/* Buscador (lanzamiento / pista / artista). */
.lanz-search {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  flex-wrap: wrap;
}
.lanz-search input[type="search"] {
  min-width: 320px;
  max-width: 100%;
}

/* Tarjeta plegable por lanzamiento de destino (CSS-only via <details>). */
.lanz-group {
  margin-top: 0.75rem;
  border: 1px solid var(--acq-border);
  border-radius: 8px;
  overflow: hidden;
}
.lanz-group-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem 0.75rem;
  padding: 0.6rem 0.85rem;
  cursor: pointer;
  background: var(--acq-surface-2);
  list-style: none; /* oculta el marker por defecto (Firefox) */
}
.lanz-group-head::-webkit-details-marker {
  display: none; /* y en WebKit/Blink */
}
/* Chevron propio que rota al abrir (consistente con el nav). */
.lanz-group-head::before {
  content: "▸";
  display: inline-block;
  color: var(--acq-text-muted);
  transition: transform 0.12s ease;
}
.lanz-group[open] > .lanz-group-head::before {
  transform: rotate(90deg);
}
.lanz-group-title {
  font-weight: 600;
}
.lanz-group-meta {
  color: var(--acq-text-muted);
  font-size: 0.85rem;
}
.lanz-group .card {
  border: 0;
  border-top: 1px solid var(--acq-border);
  border-radius: 0;
}

/* Tab disabled del subnav pill — para placeholders como /admin/audit
 * que llegarán en T18. NH del /review dc6d2d1: el link "Auditoría"
 * antes era clickable y devolvía 404 (mala UX). Ahora va con
 * `subnav-pill-tab disabled` que estiliza el cursor + opacidad sin
 * romper el layout. */
.subnav-pill-tab.disabled {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}

/* ============================================================
 * Analíticas RH (`/analytics/rh`) — secciones apiladas.
 *
 * Cada `.rh-section` (Visión por pista / agregada por RH / por RH +
 * artista) necesita aire vertical entre sí y respecto al KPI aside
 * de arriba — sin esto el `<h3>` de "Visión por pista" quedaba
 * pegado a la card de KPIs y a la sección siguiente.
 * ============================================================ */
.rh-section {
  margin-top: 2.5rem;
}
.rh-section > h3 {
  margin-bottom: 0.75rem;
}
/* Header de sección con control "Abrir/Cerrar todo" a la derecha
 * (vistas colapsables como "Visión por pista"). El h3 conserva su
 * margen inferior; el flex los alinea por la línea base. */
.rh-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}
.rh-expand-all {
  flex: none;
  background: transparent;
  border: 1px solid var(--acq-border);
  color: var(--acq-text-muted);
  font-family: var(--acq-font-sans);
  font-size: 0.8rem;
  font-weight: 500;
  padding: 0.3rem 0.75rem;
  border-radius: 6px;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.rh-expand-all:hover,
.rh-expand-all:focus-visible {
  background: var(--acq-surface-2);
  color: var(--acq-text);
  border-color: var(--acq-text-muted);
  outline: none;
}

/* Paginación "Ver más" al pie de las tablas RH (cota de render anti-OOM,
 * espejo de `.pivot-parent-pagination` de /analytics): status izq + botón
 * der dentro de una card que respira. */
.rh-pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 1.25rem;
  padding: 0.875rem 1rem;
  background: var(--acq-surface-2);
  border: 1px solid var(--acq-border);
  border-radius: 10px;
}
.rh-pagination-status {
  margin: 0;
  color: var(--acq-text-muted);
  font-size: 0.825rem;
}
.rh-pagination-status strong { color: var(--acq-text); }
.rh-pagination-btn { flex: none; }
/* El KPI aside en /analytics/rh es standalone (no dentro del filter
 * row como en royalties/artistas) — le damos margen inferior para
 * separarlo de la primera sección. */
.report-kpi-aside + .rh-section,
.report-filter-row + .rh-section {
  margin-top: 2rem;
}

/* ===================================================================
 * Dashboard Global (mock.pdf) — selector de catálogo/artista, strip de
 * meses, hero YTD, tarjeta "Top del mes" y rankings top-3.
 *
 * Estilo "Lali" del sistema (tema claro + turquesa), NO el look oscuro
 * del mockup de Gemini: reutiliza tokens (--acq-primary, --acq-border,
 * --acq-text…) y las clases existentes (.kpi-card, .table-bare).
 * =================================================================== */

/* --- Filtros de cabecera (chip Sello + selector de artista) ---
 * Ambos filtros (el multi_chip de Sello y el <select> de Artista) deben
 * verse como hermanos: misma label (uppercase/muted) y controles
 * alineados. El multi_chip no trae estilo de `.filter-field-label` fuera
 * del analytics-filter-bar, así que lo unificamos aquí — scoped a
 * `.dashboard-filters` para no tocar el chip en otras páginas. */
.dashboard-filters {
  display: flex;
  /* Alineación del filtro Sello (chip) con Artista (<select>). El bug era
   * que el margen inferior por defecto que Pico pone al <select> (y al
   * <label>) inflaba el campo Artista ~15px; con `align-items: flex-end`
   * eso empujaba "Sello" hacia abajo. Causa raíz: los `margin: 0` en
   * `.dashboard-artist-select` y `.filter-field-label` (más abajo), que
   * igualan la altura de ambos campos. `flex-start` es la red de
   * seguridad: ancla las labels (primer hijo) a la misma altura aunque
   * los controles (chip vs <select> nativo) no midan exactamente igual. */
  align-items: flex-start;
  gap: 1.25rem;
  flex-wrap: wrap;
}
.dashboard-filter-form {
  margin: 0;
  display: flex;
}
/* Estructura común label→control para ambos campos (el wrapper del chip
 * es `.filter-field.multi-chip-field`; el del select es `.filter-field
 * .dashboard-artist-field`). Mismo gap → controles alineados. */
.dashboard-filters .filter-field {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin: 0;
}
.dashboard-filters .filter-field-label {
  /* `margin: 0` neutraliza el margen por defecto del elemento <label>
   * (Pico) que NO tiene el <span> del chip — así el gap label→control es
   * el del flex (0.4rem) en ambos campos y los controles se alinean. */
  margin: 0;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  line-height: 1;
  color: var(--acq-text-muted);
}
.dashboard-artist-select {
  min-width: 220px;
  max-width: 320px;
  box-sizing: border-box;
  /* `margin: 0` quita el margen inferior por defecto que Pico aplica a
   * los <select> (era lo que descuadraba la altura del campo). Padding
   * vertical para una altura natural similar a la del chip de Sello.
   * Nada de `height` explícita: Chrome ignora `height` en <select>
   * nativos y el control quedaba más bajo de lo esperado. */
  margin: 0;
  padding: 0.4rem 0.75rem;
  font-size: 0.875rem;
  font-family: var(--acq-font-sans);
  color: var(--acq-text);
  background: var(--acq-surface);
  border: 1px solid var(--acq-border);
  border-radius: 10px;
  cursor: pointer;
}
.dashboard-artist-select:focus-visible {
  outline: 2px solid var(--acq-primary);
  outline-offset: 1px;
  border-color: var(--acq-primary);
}

/* --- Strip de meses recientes --- */
.kpi-grid--months {
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.kpi-month-head {
  justify-content: center;
}
.kpi-tag {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.85;
}
.kpi-month-name {
  margin: 0;
  font-size: 0.95rem;
  font-weight: 500;
  text-transform: capitalize;
  color: rgba(255, 255, 255, 0.92);
}

/* Cards no-ACTUAL: variante "soft" (superficie clara + texto oscuro)
 * para que el mes ACTUAL (turquesa sólido) resalte como en el mockup. */
.kpi-card--soft {
  background: var(--acq-surface);
  border: 1px solid var(--acq-border);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.04);
  color: var(--acq-text);
}
.kpi-card--soft:hover {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.kpi-card--soft .kpi-value,
.kpi-card--soft .kpi-tag {
  color: var(--acq-text);
}
.kpi-card--soft .kpi-month-name {
  color: var(--acq-text-muted);
}
.kpi-card--soft .kpi-tag {
  opacity: 0.6;
}

/* Delta vs mes anterior — verde (subida) / rojo (bajada). En la card
 * ACTUAL (turquesa) hereda el blanco translúcido de .kpi-delta. */
.kpi-card--soft .kpi-delta.is-up {
  color: var(--acq-primary-hover);
}
.kpi-card--soft .kpi-delta.is-down {
  color: var(--pico-color-red-500, #d33);
}

/* --- Hero YTD + tarjeta "Top del mes" --- */
.dashboard-hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: 1.5rem;
  margin-bottom: 2rem;
}
@media (max-width: 720px) {
  .dashboard-hero-grid {
    grid-template-columns: 1fr;
  }
}

.ytd-hero {
  /* Brand black BACKSTAGE (#2B2B34, uno de los 3 colores oficiales) en vez
   * del turquesa — petición del jefe. Texto ya blanco (lee perfecto sobre
   * negro); sombra neutra en vez del tinte turquesa. */
  background: #2B2B34;
  border-radius: 16px;
  padding: 1.75rem 2rem;
  color: #FFFFFF;
  box-shadow: 0 2px 8px rgba(43, 43, 52, 0.18);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.5rem;
}
.ytd-eyebrow {
  margin: 0;
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: rgba(255, 255, 255, 0.85);
}
.ytd-value {
  margin: 0;
  /* Blanco EXPLÍCITO: es un <p>, y Pico aplica `color: var(--pico-color)`
   * (= --acq-text, casi negro) directamente sobre `p`, lo que gana al
   * blanco HEREDADO de `.ytd-hero`. Sin esto el número saldría oscuro
   * (invisible sobre el fondo negro nuevo). Petición del jefe. */
  color: #FFFFFF;
  font-size: clamp(2.25rem, 6vw, 3.5rem);
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  font-feature-settings: var(--num-features);
}
.ytd-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem 1rem;
  margin-top: 0.25rem;
}
.ytd-delta {
  font-size: 1rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.ytd-delta.is-up {
  color: #FFFFFF;
}
.ytd-delta.is-down {
  color: #FFE3E3;
}
.ytd-projection {
  font-size: 0.9rem;
  color: rgba(255, 255, 255, 0.8);
}

.top-release-card {
  background: var(--acq-surface);
  border: 1px solid var(--acq-border);
  border-radius: 16px;
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}
.top-release-eyebrow {
  margin: 0;
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--acq-text-muted);
}
.top-release-body {
  display: flex;
  align-items: center;
  gap: 1rem;
  min-width: 0;
}
.top-release-art {
  width: 56px;
  height: 56px;
  border-radius: 10px;
  flex-shrink: 0;
  object-fit: cover;
  background: var(--acq-surface-2);
}
.top-release-art--ph {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--acq-primary);
  background: var(--acq-primary-soft);
}
.top-release-art--ph svg {
  width: 32px;
  height: 32px;
}
.top-release-meta {
  min-width: 0;
}
.top-release-title {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--acq-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.top-release-sub {
  margin: 0.15rem 0 0;
  font-size: 0.95rem;
  color: var(--acq-text-muted);
  font-variant-numeric: tabular-nums;
}

/* --- Rankings top-3 (canciones / países / DSPs) --- */
.top-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1.5rem;
  margin-bottom: 2rem;
}
.top-card {
  background: var(--acq-surface);
  border: 1px solid var(--acq-border);
  border-radius: 12px;
  padding: 1.25rem 1.5rem;
}
.top-card-head {
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--acq-text-muted);
  margin-bottom: 0.5rem;
}
.top-table {
  width: 100%;
  margin: 0;
}
.top-table .rank {
  width: 1.5rem;
  text-align: left;
  color: var(--acq-text-muted);
  font-variant-numeric: tabular-nums;
}
.top-table .top-name {
  max-width: 0;
  width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.top-table tbody td {
  padding: 0.6rem 0.5rem;
}
/* Columna "%": share de la fila sobre el total de la dimensión. Muted +
 * tabular para que las cifras alineen y no compitan con el € (la columna
 * "Ingreso" es la principal). `width: 1px` + nowrap la encoge a su
 * contenido para que el nombre (`.top-name`) siga llevándose el ancho. */
.top-table .top-pct {
  width: 1px;
  white-space: nowrap;
  color: var(--acq-text-muted);
  font-variant-numeric: tabular-nums;
}
.top-empty {
  margin: 0.5rem 0 0;
  font-size: 0.9rem;
  color: var(--acq-text-muted);
}

/* Badge del año en cabeceras del dashboard (feedback del operador
 * 2026-06-02: "año actual, texto en blanco, caja en negro"). Reusa el
 * dark BACKSTAGE de la topbar (#2B2B34). `em` para escalar con el <h2>. */
.year-badge {
  display: inline-block;
  background: #2B2B34;
  color: #FFFFFF;
  font-size: 0.78em;
  font-weight: 600;
  line-height: 1;
  padding: 0.28em 0.6em;
  border-radius: 6px;
  vertical-align: middle;
  margin-left: 0.15em;
}

/* ============================================================
 * Banner de impersonación ("ver como usuario") — base.html.j2.
 * Barra de alto contraste (ámbar, NO el turquesa de marca) fija
 * bajo la topbar, imposible de ignorar, para que el master NUNCA
 * olvide que está viendo la app como otro user. `no-print` la
 * excluye de PDFs.
 * ============================================================ */
.impersonation-banner {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  flex-wrap: wrap;
  background: #B45309;          /* ámbar oscuro */
  color: #FFFFFF;
  padding: 0.5rem 1rem;
  font-size: 0.9rem;
  border-bottom: 2px solid #7C2D12;
  /* Pegajoso de verdad: en páginas largas (informes, tablas de royalties)
     el banner debe seguir visible al hacer scroll — "imposible de ignorar".
     z-index 49 = justo bajo la topbar (z-index 50). */
  position: sticky;
  top: 0;
  z-index: 49;
}
.impersonation-banner strong { color: #FFFFFF; }
.impersonation-banner-text { text-align: center; }
.impersonation-banner-exit { margin: 0; }
.impersonation-banner-exit .btn {
  background: #FFFFFF;
  color: #7C2D12;
  border: none;
}
.impersonation-banner-exit .btn:hover { background: #FDE68A; }

/* Form inline para botones de acción en tablas (p.ej. "Ver como"). */
.inline-form { display: inline-block; margin: 0; }
