/* ── TOKENS ──────────────────────────────────────────────── */
:root{
  --ink:#0B1220;--bar:#0F172A;--sub:#1D3A5F;--row:#14202E;--row2:#182534;
  --card:#1E293B;--line:#243447;--coral:#F97316;--mint:#34D399;--red:#F87171;
  --amber:#FBBF24;--muted:#94A3B8;--white:#F8FAFC;--soft:#CBD5E1;
  --sans:'DM Sans',sans-serif;--display:'Space Grotesk',sans-serif;
  --radius:16px;--radius-sm:10px;--radius-pill:999px;
  --shadow-card:0 1px 1px rgba(0,0,0,.2),0 14px 30px -18px rgba(0,0,0,.6);
  --shadow-pop:0 22px 46px -20px rgba(0,0,0,.65)
}

/* ── LIGHT MODE ──────────────────────────────────────────── */
html[data-theme="light"]{
  --ink:#E4E9F1;
  --bar:#FFFFFF;
  --sub:#1D3A5F;
  --row:#FFFFFF;
  --row2:#F0F4FA;
  --card:#FFFFFF;
  --line:#C8D4E3;
  --muted:#4A5B70;
  --white:#0F1F33;
  --soft:#1E3552;
  --shadow-card:0 1px 2px rgba(15,31,51,.04),0 14px 28px -18px rgba(15,31,51,.22);
  --shadow-pop:0 22px 40px -18px rgba(15,31,51,.24);
}
html[data-theme="light"] body{background:#E4E9F1}
html[data-theme="light"] .sidebar{
  background:#FFFFFF;
  border-right:1px solid #C8D4E3;
  box-shadow:2px 0 12px rgba(15,31,51,.06)
}
html[data-theme="light"] .live-state{background:#F5F8FC;border-color:#C8D4E3}
html[data-theme="light"] .nav-item{color:#4A5B70}
html[data-theme="light"] .nav-item:hover{color:#0F1F33;background:#EEF2F7}
html[data-theme="light"] .nav-item.active{color:#1b120b;background:var(--coral);box-shadow:0 10px 22px -10px rgba(249,115,22,.45)}
html[data-theme="light"] .nav-item.active .nav-index{color:#1b120b}
html[data-theme="light"] .sidebar-footer{color:#7A8FA3;border-top-color:#C8D4E3}
html[data-theme="light"] .topbar{border-bottom-color:#C8D4E3}
html[data-theme="light"] .eyebrow,.section-kicker{color:#4A5B70}
html[data-theme="light"] .connection-strip{background:#F5F8FC;border-color:#C8D4E3}
html[data-theme="light"] .filters{background:#FFFFFF;border-color:#C8D4E3;box-shadow:var(--shadow-card)}
html[data-theme="light"] .filters label{color:#4A5B70}
html[data-theme="light"] .connection-strip input,
html[data-theme="light"] .filters input,
html[data-theme="light"] .filters select,
html[data-theme="light"] .refresh-control select{
  background:#FFFFFF;border-color:#B8C8DB;color:#1E3552
}
html[data-theme="light"] .metric-card{
  background:#FFFFFF;border-color:#C8D4E3;
  box-shadow:var(--shadow-card)
}
html[data-theme="light"] .metric-label{color:#4A5B70}
html[data-theme="light"] .metric-value{color:#0F1F33}
html[data-theme="light"] .metric-detail{color:#4A5B70}
html[data-theme="light"] .panel{
  background:#FFFFFF;border-color:#C8D4E3;
  box-shadow:var(--shadow-card)
}
html[data-theme="light"] .panel-head h2{color:#0F1F33}
html[data-theme="light"] .panel-note{color:#4A5B70}
html[data-theme="light"] .line-target{stroke:#9CB3C9}
html[data-theme="light"] .target-label{fill:#7C93AC}
html[data-theme="light"] .line-axis{color:#4A5B70}
html[data-theme="light"] .chart-legend{color:#4A5B70}
html[data-theme="light"] .deviation-number{color:#0F1F33}
html[data-theme="light"] .deviation-number.good{color:#059669}
html[data-theme="light"] .deviation-number.bad{color:#DC2626}
html[data-theme="light"] .deviation-copy{color:#4A5B70}
html[data-theme="light"] .rank-name{color:#0F1F33}
html[data-theme="light"] .rank-sub{color:#4A5B70}
html[data-theme="light"] .rank-value{color:#0F1F33}
html[data-theme="light"] .rank-bar{background:#D5E0EC}
html[data-theme="light"] .section-kicker{color:#4A5B70}
html[data-theme="light"] .view-heading h1{color:#0F1F33}
html[data-theme="light"] .view-heading p{color:#4A5B70}
html[data-theme="light"] .period-badge,.roas-badge{background:#FFFFFF;color:#1E3552;border-color:var(--coral)}
html[data-theme="light"] .table-wrap th{background:#1D3A5F;color:#FFFFFF}
html[data-theme="light"] .table-wrap td{color:#1E3552;border-color:#D5E0EC}
html[data-theme="light"] .table-wrap tbody tr:nth-child(even){background:#F0F4FA}
html[data-theme="light"] .table-wrap tbody tr:nth-child(odd){background:#FFFFFF}
html[data-theme="light"] .table-wrap tbody tr:nth-child(even) td:first-child{background:#F0F4FA}
html[data-theme="light"] .table-wrap tbody tr:nth-child(odd) td:first-child{background:#FFFFFF}
html[data-theme="light"] .table-wrap tbody tr:hover td{background:#E0EBF5!important;color:#0F1F33!important}
html[data-theme="light"] .num{color:#0F1F33!important}
html[data-theme="light"] .positive{color:#059669!important}
html[data-theme="light"] .negative{color:#DC2626!important}
html[data-theme="light"] .warning{color:#B45309!important}
html[data-theme="light"] .seller-name{color:#0F1F33!important}
html[data-theme="light"] .seller-location{color:#4A5B70!important}
html[data-theme="light"] .funnel-track,html[data-theme="light"] .progress-track{background:#E0EBF5}
html[data-theme="light"] .health-chip{background:#F5F8FC;border-color:#C8D4E3}
html[data-theme="light"] .health-name{color:#0F1F33}
html[data-theme="light"] .health-local{color:#4A5B70}
html[data-theme="light"] .health-empty{color:#4A5B70}
html[data-theme="light"] .ads-line{color:#4A5B70;border-color:#D5E0EC}
html[data-theme="light"] .ads-line strong{color:#0F1F33}
html[data-theme="light"] .ads-line strong.good{color:#059669}
html[data-theme="light"] .ads-line strong.bad{color:#DC2626}
html[data-theme="light"] .seller-period-filters select{background:#FFFFFF;border-color:#C8D4E3;color:#1E3552}
html[data-theme="light"] .app-footer{color:#7A8FA3;border-color:#C8D4E3}
html[data-theme="light"] .icon-button{background:#FFFFFF;border-color:#C8D4E3;color:#4A5B70}
html[data-theme="light"] .text-button{color:var(--coral)}
html[data-theme="light"] .accessory-cell strong{color:#0F1F33}
html[data-theme="light"] .accessory-cell span,
html[data-theme="light"] .accessory-cell small{color:#4A5B70}
html[data-theme="light"] .missing-value{color:#7A8FA3}
html[data-theme="light"] .bar-label{color:#7A8FA3}

/* ── AVISO DE ACTUALIZACIÓN DISPONIBLE ───────────────────────
   Se muestra cuando el Service Worker detecta una versión nueva ya publicada — ver applyTheme
   y el bloque de registro de sw.js al final de app.js. "Actualizar" solo hace un reload: el SW
   nuevo ya está activo en segundo plano (skipWaiting+clients.claim), el reload es lo que hace
   que la página cargue el HTML/JS/CSS nuevos en vez de los que ya estaban en memoria. */
.update-banner{
  position:fixed;top:0;left:0;right:0;z-index:100;
  display:flex;align-items:center;justify-content:center;gap:12px;flex-wrap:wrap;
  background:var(--coral);color:#1b120b;
  padding:calc(env(safe-area-inset-top) + 10px) 16px 10px;
  font:700 12.5px var(--sans);text-align:center;
}
.update-banner button{
  flex-shrink:0;height:28px;padding:0 14px;border-radius:var(--radius-pill);border:1px solid rgba(27,18,11,.35);
  background:#1b120b;color:#fff;font:700 11.5px var(--sans);cursor:pointer;
}
.update-banner button:active{transform:scale(.96)}

/* ── THEME TOGGLE ─────────────────────────────────────────── */
.theme-toggle{display:flex;gap:3px;background:var(--ink);border:1px solid var(--line);border-radius:var(--radius-pill);padding:3px;width:fit-content}
.theme-btn{width:28px;height:28px;border:0;border-radius:var(--radius-pill);background:transparent;color:var(--muted);font-size:13px;line-height:1;cursor:pointer;display:grid;place-items:center;transition:.2s}
.theme-btn:hover{color:var(--white)}
.theme-btn:active{transform:scale(.9)}
.theme-btn[aria-pressed="true"]{background:var(--coral);color:#1b120b;box-shadow:0 6px 14px -6px rgba(249,115,22,.55)}

/* ── ÍCONOS SVG (reemplazan emoji en toda la interfaz de supervisión) ── */
.icon-svg{width:15px;height:15px;flex-shrink:0}
.kicker-icon{width:11px;height:11px;flex-shrink:0;vertical-align:-1.5px;margin-right:3px}
.medal-icon{width:16px;height:16px;flex-shrink:0}
.medal-gold{color:#F5B942}
.medal-silver{color:#C0C8D4}
.medal-bronze{color:#C97C3D}
.trophy-icon{width:14px;height:14px;color:var(--coral);vertical-align:-2px}

/* ── BOTTOM NAV + DRAWER (mobile < 721px, estilo Tiendanube) ──
   Mismo componente que ya se armó en equipo/ — acá adaptado a los tokens y las 7 secciones del
   panel de gestión (bottom-nav cubre las 3 más usadas + Inicio; el resto vive en el drawer). */
.bottom-nav{
  display:none;position:fixed;left:0;right:0;bottom:0;z-index:60;
  grid-template-columns:repeat(4,1fr);background:var(--card);
  border-top:1px solid var(--line);padding:6px 4px calc(env(safe-area-inset-bottom) + 4px);
}
.bottom-nav-item{
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  background:none;border:none;color:var(--muted);font:600 9.5px var(--sans);padding:7px 2px;
  border-radius:var(--radius-sm);cursor:pointer;touch-action:manipulation;
}
.bottom-nav-item .icon-svg{width:20px;height:20px}
.bottom-nav-item.active{color:var(--coral)}
.bottom-nav-item:active{transform:scale(.94)}

.drawer-backdrop{position:fixed;inset:0;z-index:65;background:rgba(4,8,16,.68)}
.drawer-panel{
  position:fixed;top:0;right:0;bottom:0;z-index:66;width:min(84vw,340px);
  background:var(--card);border-left:1px solid var(--line);
  display:flex;flex-direction:column;box-shadow:-14px 0 40px rgba(0,0,0,.4);
}
.drawer-head{
  display:flex;align-items:center;justify-content:space-between;padding:calc(env(safe-area-inset-top) + 16px) 16px 14px;
  border-bottom:1px solid var(--line);font:700 14px var(--display);color:var(--white);flex-shrink:0;
}
.drawer-close{
  width:40px;height:40px;border-radius:50%;border:1px solid var(--line);background:transparent;
  color:var(--muted);cursor:pointer;touch-action:manipulation;flex-shrink:0;
  display:flex;align-items:center;justify-content:center;
}
.drawer-close svg{width:18px;height:18px}
.drawer-close:active{background:var(--ink);color:var(--white)}
.drawer-body{overflow-y:auto;padding:10px 10px calc(env(safe-area-inset-bottom) + 20px);flex:1}
.drawer-group{margin-bottom:18px}
.drawer-group-title{display:block;padding:6px 10px 6px;font-size:10px;letter-spacing:1px;text-transform:uppercase;color:var(--coral);font-weight:700}
.drawer-item{
  width:100%;min-height:50px;display:flex;align-items:center;gap:14px;text-align:left;
  padding:13px 12px;border:none;border-radius:var(--radius-sm);background:transparent;color:var(--white);
  font:600 14px var(--sans);cursor:pointer;touch-action:manipulation;
}
.drawer-item:active{background:var(--ink)}
.drawer-icon{width:21px;height:21px;flex-shrink:0;color:var(--muted)}
.drawer-item:active .drawer-icon{color:var(--coral)}
.drawer-theme-row{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;gap:10px}
.drawer-item-label{display:flex;align-items:center;gap:14px;color:var(--white);font:600 14px var(--sans)}

/* ── RESET / BASE ─────────────────────────────────────────── */
*{box-sizing:border-box}
body{margin:0;background:var(--ink);color:var(--white);font:14px var(--sans);line-height:1.45}
.app-shell{display:flex;min-height:100vh}

/* ── SIDEBAR ──────────────────────────────────────────────── */
.sidebar{width:238px;flex:none;background:var(--bar);border-right:1px solid var(--line);padding:28px 18px 20px;display:flex;flex-direction:column;min-height:100vh}
.brand{display:flex;align-items:center;gap:10px;padding:4px 10px 34px}
.brand-logo{display:flex;align-items:center;justify-content:center;flex-shrink:0}
.brand-logo img{display:block;height:30px;width:auto}
.brand-logo .logo-dark{display:none}
html[data-theme="light"] .brand-logo .logo-light{display:none}
html[data-theme="light"] .brand-logo .logo-dark{display:block}
.brand-label{border-left:1px solid var(--line);padding-left:10px;color:var(--muted);font-size:11px;line-height:1.05;text-transform:uppercase;letter-spacing:1.2px}
.brand-label small{color:var(--coral);font-size:8px;letter-spacing:1.5px}
.live-state{border:1px solid var(--line);background:#111d2e;border-radius:var(--radius-pill);padding:10px 14px;color:var(--muted);font-size:11px;margin:0 4px 30px;display:flex;align-items:center;gap:8px}
.pulse{width:7px;height:7px;border-radius:50%;background:var(--red);box-shadow:0 0 0 4px #f8717118}
.pulse.online{background:var(--mint);box-shadow:0 0 0 4px #34d39918}
.nav{display:grid;gap:5px}
.nav-item{border:0;background:transparent;color:var(--muted);text-align:left;padding:12px 13px;display:flex;gap:12px;align-items:flex-start;font:500 13px var(--sans);cursor:pointer;border-radius:var(--radius-sm);transition:.2s}
.nav-item:hover{color:var(--white);background:#172438}
.nav-item:active{background:var(--ink)}
.nav-item.active{color:#1b120b;background:var(--coral);box-shadow:0 10px 22px -10px rgba(249,115,22,.55)}
.nav-item.active:active{background:#e2670f}
.nav-index{font:600 11px var(--display);color:#64748B;margin-top:2px}
.nav-item.active .nav-index{color:#1b120b}
.sidebar-footer{margin-top:auto;border-top:1px solid var(--line);padding:18px 10px 0;display:flex;flex-direction:column;gap:14px}
.footer-meta{color:#64748B;font-size:10px;display:flex;justify-content:space-between}

[hidden]{display:none!important}

/* ── LAYOUT ───────────────────────────────────────────────── */
.version{color:var(--coral)}
.main-content{width:min(100%,1500px);padding:0 38px 34px;overflow:hidden;position:relative}
.topbar{height:70px;border-bottom:1px solid var(--line);display:flex;align-items:center;justify-content:space-between}
.eyebrow,.section-kicker{color:var(--muted);font-size:10px;letter-spacing:1.5px;font-weight:700}
.section-kicker::before{content:"// "}
.view-heading .section-kicker::before{content:""}
.slash{color:var(--coral);padding:0 5px}
.top-actions{display:flex;align-items:center;gap:14px}
.data-status{color:var(--muted);font-size:12px}
/* Confirmación puntual de "se actualizó", al lado del botón que el usuario acaba de tocar — antes
   la única señal de éxito era el punto verde de la sidebar, lejos de donde está mirando quien tocó
   ↻ en el topbar. flashRefreshConfirm() la prende un par de segundos y se apaga sola. */
.refresh-confirm{color:var(--mint);font:600 11px var(--sans);opacity:0;transition:opacity .25s ease;white-space:nowrap}
.refresh-confirm.show{opacity:1}
.icon-button{width:36px;height:36px;border:1px solid var(--line);background:var(--card);color:var(--soft);font-size:18px;cursor:pointer;border-radius:var(--radius-pill);box-shadow:var(--shadow-card);transition:.2s}
.icon-button:hover{color:var(--coral);border-color:var(--coral)}
.icon-button:active{transform:scale(.92)}
.icon-button:disabled{opacity:.5;cursor:not-allowed}
/* Gira mientras loadData() está en vuelo (prendido/apagado por startRefreshSpin/stopRefreshSpin) —
   reusa el mismo keyframe "spin" de .app-loading-spinner más abajo. */
.icon-button.is-spinning{animation:spin .7s linear infinite}

/* ── CARGA INICIAL ────────────────────────────────────────────
   Tapa el contenido de .main-content (que hasta que llegan los datos son puros "Sin datos" y "—"
   repetidos 8 vistas) con un estado de carga de verdad, en vez de dejar que la app se vea rota
   durante el fetch inicial (hasta 20s si el endpoint tarda, ver loadData). Vive DENTRO de
   .main-content (position:relative de esa clase, arriba) para no tapar la sidebar — el usuario ve
   la marca/navegación al instante, solo el contenido espera. Se apaga una sola vez, en el finally
   de loadData() (éxito o error), vía hideAppLoading() — nunca vuelve a mostrarse en refrescos
   posteriores (esos usan el spin del botón + refresh-confirm de arriba, no esta pantalla completa). */
.app-loading{position:absolute;inset:0;z-index:30;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;background:var(--ink);transition:opacity .35s ease,visibility .35s ease}
.app-loading.is-loaded{opacity:0;visibility:hidden;pointer-events:none}
.app-loading-spinner{width:34px;height:34px;border:3px solid var(--line);border-top-color:var(--coral);border-radius:50%;animation:spin .8s linear infinite}
.app-loading p{margin:0;color:var(--muted);font:600 12px var(--sans);letter-spacing:.3px}
@keyframes spin{to{transform:rotate(360deg)}}
/* Respeta "reducir movimiento" del sistema operativo — se agrega acá porque esta tanda de cambios
   sumó las primeras animaciones de spin/fade reales de la app (antes solo existía "rise", la
   entrada de vistas). No apaga las animaciones a secas (igual necesitan completar su rol de dar
   estado), solo las acorta a instantáneas. */
@media(prefers-reduced-motion:reduce){
  *{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}
}

/* ── CONNECTION / FILTERS ─────────────────────────────────── */
.connection-strip{margin:26px 0 17px;padding:12px 14px;background:#111d2e;border:1px solid var(--line);display:flex;align-items:center;gap:14px;border-radius:var(--radius)}
.connection-copy{display:flex;flex-direction:column;min-width:175px}
.connection-copy strong{font:600 13px var(--display)}
.connection-copy span{color:var(--muted);font-size:11px}
.connection-strip input{flex:1;min-width:0}
.connection-strip input,.filters input,.filters select,.refresh-control select{height:36px;background:var(--ink);border:1px solid var(--line);border-radius:var(--radius-sm);color:var(--soft);padding:0 12px;font:12px var(--sans);outline:none;transition:.2s}
.connection-strip input:focus,.filters input:focus,.filters select:focus{border-color:var(--coral)}
.filters input[type="date"]{color-scheme:dark}
html[data-theme="light"] .filters input[type="date"]{color-scheme:light}
.filters input[type="date"]::-webkit-calendar-picker-indicator{cursor:pointer;border-radius:4px;padding:3px;transition:.2s}
.filters input[type="date"]::-webkit-calendar-picker-indicator:hover{background:var(--coral)}
.primary-button{height:36px;border:0;border-radius:var(--radius-pill);background:var(--coral);color:#1b120b;padding:0 18px;font:700 12px var(--sans);cursor:pointer}
.primary-button:active{transform:scale(.96)}
.primary-button span{font-size:16px;padding-left:7px}
.refresh-control{color:var(--muted);font-size:11px;display:flex;align-items:center;gap:6px;white-space:nowrap}
.refresh-control select{width:86px;height:31px}
/* auto-fit en vez de columnas fijas: en Resumen General solo hay 2 campos visibles (Desde/Hasta,
   ver switchView) y con columnas fijas quedaban 4 tracks vacíos a la derecha — así los campos
   visibles siempre reparten el ancho completo, sean 2 o 4. */
/* margin-top: sin esto, .filters quedaba pegado (0px) contra el border-bottom recto de .topbar —
   como .filters tiene esquinas redondeadas, esa línea recta del header quedaba "sobresaliendo"
   justo en la esquina en vez de separarse limpio. */
/* minmax mínimo en 190px (antes 140px) — con auto-fit, un contenedor ancho + pocos campos
   visibles (ej. Período/Período seleccionado solos en Resumen) hace que el grid calcule MUCHAS
   columnas angostas al mínimo (140-160px) antes de colapsar las vacías, y esas 2 columnas reales
   quedaban más angostas que el min-width:190px del .period-trigger — el botón se desbordaba de su
   propia columna y comía el gap, por más margin/gap que se le pusiera encima. 190px iguala el
   mínimo de columna al min-width real del contenido más angosto que vive en esta grilla. */
.filters{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));column-gap:20px;row-gap:14px;padding:16px 18px;background:#101c2d;border:1px solid var(--line);border-radius:var(--radius);margin-top:22px;margin-bottom:27px;box-shadow:var(--shadow-card)}
.filter-heading{grid-column:1/-1;display:flex;justify-content:space-between;align-items:center;margin-bottom:0}
.filters label{display:grid;gap:5px;color:var(--muted);font-size:11px}
.filters select,.filters input{width:100%}
.text-button{background:none;border:0;color:var(--coral);font:600 11px var(--sans);cursor:pointer;padding:0}
.text-button:active{opacity:.6}
.error-banner{background:#451d27;border:1px solid #9f3446;color:#fecdd3;padding:12px 15px;border-radius:var(--radius-sm);margin-bottom:20px;font-size:13px}
/* Aviso de sección en preparación (datos de ejemplo, no reales todavía) — mismo patrón que
   .error-banner pero en tono ámbar en vez de rojo, para no confundirse con un error real. */
.demo-banner{display:flex;align-items:center;gap:9px;background:#402c06;border:1px solid #92650b;color:#fde68a;padding:12px 15px;border-radius:var(--radius-sm);margin-bottom:20px;font-size:13px}
.demo-banner .icon-svg{flex:none;width:18px;height:18px;color:#fbbf24}

/* ── SELECTOR DE PERÍODO (presets + calendario de rango) ─────
   Reemplaza los <input type="date"> sueltos de Desde/Hasta — ver initPeriodPicker() en app.js.
   Vive solo en Resumen/Locales/E-commerce: switchView() lo oculta en Ranking y Temporada.
   "Período" y "Período seleccionado" (campo 2) van SIEMPRE los dos visibles, uno al lado del
   otro, y nunca uno depende de que el otro esté en modo Personalizado para aparecer — cada uno
   abre solo su propio desplegable. Son 2 grid-items sueltos de .filters (NO un wrapper propio):
   así el auto-fit de .filters los reparte en la MISMA fila junto con Local/Vendedor, igual que ya
   hace con Mes/Semana en Métricas vendedores/Accesorios — un wrapper con grid-column:1/-1 los
   forzaba a su propia fila aparte, rompiendo esa regla (ver [[vdh-filters-layout-rule]]). El
   trigger ya tiene min-width fijo en vez de width:100%, así que no hace falta el wrapper para
   evitar que se estire de más ni para separarlo del campo de al lado.
   Cada .period-field es "position:relative" — su ancla para el .period-dropdown propio. */
/* .period-field se estira para llenar su columna (comportamiento default de grid-item, sin
   overrides) — mismo criterio que Local/Vendedor (<select> con width:100%). La causa real del
   amontonamiento nunca fue el estiramiento en sí: era que .filters calculaba columnas más
   angostas (140px min) que lo que el trigger necesitaba (190px) — ya arreglado en .filters de
   arriba. Con las columnas bien anchas, dejar que TODO se estire parejo (en vez de compactar
   Período/Período seleccionado con justify-self:start) es lo que da el mismo gap visual entre
   los 3-4 campos de la fila, sea cual sea el tipo de campo. */
.period-field{position:relative;display:grid;gap:5px;color:var(--muted);font-size:11px}
.period-field-label{color:var(--muted)}
.period-trigger{display:flex;align-items:center;gap:8px;width:100%;min-width:190px;height:36px;background:var(--ink);border:1px solid var(--line);border-radius:var(--radius-sm);color:var(--white);padding:0 12px;font:600 12px var(--sans);cursor:pointer;transition:.2s}
.period-trigger:hover,.period-trigger:focus-visible{border-color:var(--coral)}
.period-trigger .icon-svg{width:15px;height:15px;flex-shrink:0;color:var(--muted)}
.period-trigger-chevron{margin-left:auto}
.period-trigger span{flex:1;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* min-width calza con el min-width:190px del trigger (+ margen chico) para que el desplegable no
   quede más ancho que su propio botón y termine invadiendo el campo de al lado. */
.period-dropdown{position:absolute;top:calc(100% + 8px);left:0;z-index:40;min-width:210px;width:max-content;max-width:260px;display:flex;flex-direction:column;gap:1px;background:var(--card);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow-pop);padding:8px}
.period-preset{text-align:left;background:none;border:0;color:var(--soft);font:600 12px var(--sans);padding:9px 10px;border-radius:var(--radius-sm);cursor:pointer;transition:.15s}
.period-preset:hover{background:var(--ink)}
.period-preset:active{transform:scale(.97)}
.period-preset.active{background:var(--coral);color:#1b120b}
/* "Período actual" agrupa Semana/Mes/Trimestre actual bajo una etiqueta no clickeable, con
   sangría — Hoy/Ayer sueltos arriba y el grupo "a la fecha" abajo, visualmente distinto.
   "Personalizado" ya no vive acá: ese modo se entra directo por el campo "Período seleccionado",
   que está siempre visible al lado — tenerlo repetido en esta lista no cumplía función. */
.period-group-label{padding:10px 10px 2px;color:var(--muted);font-size:10px;text-transform:uppercase;letter-spacing:.4px}
.period-preset-indent{padding-left:18px}
.period-calendar{display:flex;justify-content:center;padding-top:2px}
/* El calendario de Flatpickr necesita ~308px de ancho fijo (7 columnas LUN-DOM) — el max-width:260px
   de .period-dropdown es para la LISTA de presets, no le entra al calendario y recortaba sábado/
   domingo. Esta variante se libera del límite y crece a lo que el calendario realmente necesita. */
.period-calendar-dropdown{width:auto;max-width:none}
.period-custom-actions{display:flex;justify-content:flex-end;gap:14px;padding:8px 6px 2px;align-items:center}
.period-apply-btn{height:32px;border:0;border-radius:var(--radius-pill);background:var(--coral);color:#1b120b;padding:0 16px;font:700 12px var(--sans);cursor:pointer;transition:.2s}
.period-apply-btn:active{transform:scale(.95)}
.period-apply-btn:disabled{opacity:.4;cursor:not-allowed}

/* Flatpickr (CDN) — tema oscuro corporativo para calzar con el resto del panel, en vez del tema
   claro por defecto de la librería. Los !important pisan el flatpickr.min.css cargado antes. */
.flatpickr-calendar{background:transparent!important;box-shadow:none!important;width:auto!important}
.flatpickr-months{padding:2px 0 6px}
.flatpickr-month{color:var(--white)!important;fill:var(--white)!important}
.flatpickr-current-month{font:600 13px var(--display)!important}
.flatpickr-current-month input.cur-year{color:var(--white)!important;background:transparent!important}
.flatpickr-current-month .flatpickr-monthDropdown-months{background:transparent!important;color:var(--white)!important}
.flatpickr-prev-month,.flatpickr-next-month{fill:var(--muted)!important;color:var(--muted)!important}
.flatpickr-prev-month:hover svg,.flatpickr-next-month:hover svg{fill:var(--coral)!important}
.flatpickr-weekdays{background:transparent!important}
span.flatpickr-weekday{background:transparent!important;color:var(--muted)!important;font:600 10px var(--sans)!important;text-transform:uppercase}
.flatpickr-day{color:var(--soft)!important;border-radius:var(--radius-sm)!important}
.flatpickr-day.today{border-color:var(--coral)!important}
.flatpickr-day.flatpickr-disabled,.flatpickr-day.prevMonthDay,.flatpickr-day.nextMonthDay{color:var(--line)!important}
.flatpickr-day:hover{background:var(--ink)!important}
.flatpickr-day.selected,.flatpickr-day.startRange,.flatpickr-day.endRange{background:var(--coral)!important;border-color:var(--coral)!important;color:#1b120b!important}
.flatpickr-day.inRange{background:rgba(249,115,22,.18)!important;box-shadow:-5px 0 0 rgba(249,115,22,.18),5px 0 0 rgba(249,115,22,.18)!important;border-color:transparent!important}
/* Flatpickr rellena el hueco entre 2 días SELECCIONADOS CONSECUTIVOS (ej. 4 y 5) con un box-shadow
   propio en vez de reusar .inRange — sin pisar esto quedaba el azul de fábrica de la librería
   asomando entre las dos celdas naranjas, que es el "tono raro" reportado. */
.flatpickr-day.selected.startRange+.endRange:not(.startRange){box-shadow:-10px 0 0 rgba(249,115,22,.18)!important}

/* ── VIEWS ────────────────────────────────────────────────── */
.view{display:none;animation:rise .35s ease both}
.active-view{display:block}
@keyframes rise{from{opacity:0;transform:translateY(5px)}to{opacity:1;transform:none}}
.view-heading{display:flex;justify-content:space-between;align-items:flex-end;gap:20px;margin-bottom:26px}
.view-heading h1{font:600 clamp(25px,3vw,38px) var(--display);letter-spacing:0;margin:6px 0 7px}
.view-heading p{margin:0;color:var(--muted);max-width:640px}
.period-badge,.roas-badge{border-left:3px solid var(--coral);padding:10px 16px;background:var(--card);color:var(--soft);font-size:12px;white-space:nowrap;border-radius:0 var(--radius-pill) var(--radius-pill) 0;box-shadow:var(--shadow-card)}
/* Confirmación de rango exacto al filtrar por Mes/Semana en 04 y 05 (ver updatePeriodRangeBadge) */
.period-range-badge{grid-column:1/-1;justify-self:start;display:inline-flex;align-items:center;gap:7px;border-left:3px solid var(--coral);padding:8px 14px;background:var(--card);color:var(--soft);font-size:12px;white-space:nowrap;border-radius:0 var(--radius-pill) var(--radius-pill) 0}
.badge-icon{width:14px;height:14px;flex-shrink:0;color:var(--coral)}
.roas-badge strong{color:var(--amber);font:700 20px var(--display);margin-left:7px}

/* ── METRICS ──────────────────────────────────────────────── */
.metric-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-bottom:18px}
/* Locales y Métricas vendedores bajaron a 6 KPI cards (donut/barra de progreso reemplazan cards
   sueltas): 3 columnas cierra parejo en 2 filas en vez de dejar huecos con la grilla de 4 general.
   Acotado a escritorio (min-width) para no pisar los breakpoints de tablet/mobile de más abajo. */
@media(min-width:1051px){#storeMetrics,#sellerDetailMetrics{grid-template-columns:repeat(3,1fr)}}
.metric-card{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);padding:18px 20px 16px;min-height:110px;position:relative;overflow:hidden;box-shadow:var(--shadow-card);transition:transform .18s ease,box-shadow .18s ease}
.metric-card:hover{transform:translateY(-3px);box-shadow:var(--shadow-pop)}
.metric-card:before{content:'';position:absolute;left:0;top:0;width:100%;height:3px;background:linear-gradient(90deg,var(--coral),transparent 75%);opacity:.7}
.metric-card:after{content:'';position:absolute;right:-20px;bottom:-30px;width:100px;height:100px;border:1px solid #ffffff0a;border-radius:50%}
.metric-label{color:var(--muted);font-size:10px;letter-spacing:1.2px;text-transform:uppercase}
.metric-value{font:600 27px var(--display);margin:8px 0 4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.metric-value .good{color:var(--mint)}
.metric-value .bad{color:var(--red)}
.metric-detail{font-size:11px;color:var(--muted)}
.metric-detail.good{color:var(--mint)}
.metric-detail.bad{color:var(--red)}
.kpi-card{padding-bottom:38px}
.kpi-trend{display:inline-flex;align-items:center;gap:5px;margin-top:10px;padding:4px 10px;border-radius:var(--radius-pill);font:600 11px var(--sans)}
.kpi-trend.pill-up{background:rgba(34,197,94,.15)}
.kpi-trend.pill-down{background:rgba(239,68,68,.15)}
.kpi-trend.pill-flat{background:rgba(148,163,184,.12)}
.trend-arrow{font-size:10px;line-height:1}
.trend-arrow.up{color:#22C55E}
.trend-arrow.down{color:#EF4444}
.trend-arrow.flat{color:var(--muted)}
.pill-up .trend-text{color:#22C55E}
.pill-down .trend-text{color:#EF4444}
.pill-flat .trend-text{color:var(--muted)}
.kpi-subtrend{font-size:10px;color:var(--muted);margin-top:3px}
.live-updated{display:inline-flex;align-items:center;gap:5px;margin-left:10px;font:600 10px var(--sans);color:var(--muted);letter-spacing:.3px}
.live-updated:empty{display:none}
.live-updated:before{content:'';width:6px;height:6px;border-radius:50%;background:var(--mint);flex-shrink:0}
.chart-note{margin-top:10px;font-size:10.5px;color:var(--muted);font-style:italic}

/* ── PANELS / GRIDS ───────────────────────────────────────── */
.split-grid{display:grid;grid-template-columns:1.45fr .75fr;gap:14px;margin-bottom:14px}
.lower-grid{grid-template-columns:1fr 1fr}
.panel{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);padding:22px;min-width:0;box-shadow:var(--shadow-card)}
/* Un panel fuera de un .split-grid (que es quien normalmente pone el margin-bottom:14px de separación
   entre filas) se queda sin ningún espacio debajo si no lleva esta clase — así quedaron "Día a día" y
   "Tendencia semestral" pegados a la fila de abajo hasta que se detectó. */
.panel-standalone{margin-bottom:14px}
.panel-note-inline{margin:10px 2px 0;font-size:11.5px;color:var(--muted);line-height:1.4}
.sprint-picker{display:flex;align-items:center;gap:10px;margin-bottom:16px}
.sprint-picker label{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.6px;font-weight:700}
.sprint-picker select{height:36px;background:var(--card);border:1px solid var(--line);border-radius:var(--radius-sm);color:var(--white);padding:0 12px;font:600 13px var(--sans)}
.panel-head{display:flex;justify-content:space-between;align-items:flex-start;gap:15px;margin-bottom:19px}
.panel-head h2{font:600 17px var(--display);margin:4px 0 0}
.panel-note{color:var(--muted);font-size:11px;padding-top:3px}

/* ── LINE CHART (acumulado real vs. objetivo) ────────────────── */
/* padding-top:32px reserva una franja limpia para .chart-legend (position:absolute;top:0) — antes
   era 6px, insuficiente: la barra más alta de cada gráfico escala cerca del techo del contenedor y
   terminaba pasando por detrás del texto de la leyenda en vez de quedar claramente separada arriba. */
.bar-chart{min-height:218px;padding:32px 2px 0;position:relative}
/* Volumen vertical reducido específicamente para "Día a día" — el gráfico acumulado (#salesBars) no
   se toca, sigue con su altura original; esta clase es aparte para no afectarlo. */
.bar-chart-compact{min-height:0;max-height:300px}
.bar-chart-compact .daily-chart{height:150px}
.bar-chart-compact .line-axis{margin-top:6px}
.line-chart{width:100%;height:190px;display:block;overflow:visible}
.line-area{fill:var(--coral);opacity:1}
/* Ritmo objetivo: línea de referencia limpia, guiones parejos (4 4) en gris tenue — no compite con
   Real (sólida) ni con Proyección (guiones más largos, color naranja pleno). */
.line-target{fill:none;stroke:#64748b;stroke-width:2;stroke-dasharray:4 4;stroke-linecap:round}
.line-actual{fill:none;stroke:var(--coral);stroke-width:3;stroke-linecap:round;stroke-linejoin:round}
/* Proyección: mismo naranja de "Real" (misma serie, a futuro), guiones más largos y espaciados que
   "Ritmo objetivo" para que las dos líneas punteadas del chart nunca se confundan entre sí. */
.line-projection{fill:none;stroke:var(--coral);stroke-width:2;stroke-dasharray:6 4;stroke-linecap:round}
/* Semestre anterior: color neutro (no naranja/verde/rojo) para que se lea como referencia de fondo,
   no como un valor que pide una reacción como las líneas de real/objetivo. */
.line-prior{fill:none;stroke:var(--muted);stroke-width:2;stroke-linecap:round;stroke-linejoin:round;opacity:.75}
/* Banda de confianza: wash translúcido (no un color saturado) entre los dos escenarios de proyección
   — misma familia de naranja que "Real"/"Proyección", nunca un tercer color nuevo para esta serie. */
.line-band{fill:rgba(249,115,22,.14);stroke:none}
/* Línea "HOY": anotación, no serie de datos — por eso un color aparte (mint) en vez de sumar un
   cuarto tono a la paleta naranja/gris ya establecida para las series reales. */
.hoy-line{stroke:var(--mint);stroke-width:1.5;stroke-dasharray:3 3;opacity:.85}
.hoy-label{fill:var(--mint);font:700 9px var(--sans);letter-spacing:.6px;text-transform:uppercase}
/* Etiqueta flotante con el monto de la meta, pegada al extremo derecho de .line-target — mismo
   color que la línea (#64748b / #9CB3C9 en modo claro, ver arriba), tamaño chico como .hoy-label
   para no competir con los números grandes de las KPI cards de arriba. */
.target-label{fill:#64748b;font:700 9px var(--sans);letter-spacing:.2px}
.line-dot{fill:var(--coral);stroke:var(--card);stroke-width:2}
.line-axis{display:flex;justify-content:space-between;color:#64748B;font-size:10px;margin-top:10px;font-family:var(--display)}
.line-axis span:nth-child(2){color:var(--soft)}
.chart-legend{position:absolute;top:0;right:2px;display:flex;gap:12px;color:var(--muted);font-size:10px}
/* Variante "abajo": chart con más de 3 series y labels largos (Tendencia Real vs Proyectado) — se
   saca del position:absolute para no pisar el trazado, pasa a flujo normal debajo del eje con wrap. */
.chart-legend-bottom{position:static;flex-wrap:wrap;row-gap:6px;column-gap:14px;margin-top:20px;padding-top:15px}
.legend-swatch{display:inline-block;width:8px;height:8px;margin-right:4px;border-radius:2px}
.legend-swatch-dashed{background:repeating-linear-gradient(90deg,var(--coral) 0 3px,transparent 3px 5px)!important}
/* "Avance del mes": franja al pie del panel del gráfico — separada por un divisor, mismo patrón que
   ya usan las tarjetas KPI (kpi-divider) para no inventar un segundo lenguaje visual de separador. */
.month-progress{margin-top:18px;padding-top:16px;border-top:1px solid var(--line)}
.month-progress-head{display:flex;justify-content:space-between;align-items:baseline;margin-bottom:9px}
.month-progress-stat{font:700 11.5px var(--display);color:var(--soft)}
.month-progress-track{height:8px;border-radius:var(--radius-pill);background:var(--line);overflow:hidden}
.month-progress-fill{height:100%;border-radius:var(--radius-pill);background:linear-gradient(90deg,var(--coral),#FFB37A)}
.month-progress-foot{display:flex;justify-content:space-between;margin-top:9px;font-size:11px;color:var(--muted)}
/* "Día a día": dos barras por día, Venta real (semáforo por estado contra el objetivo de ESE día,
   no un color fijo de serie) + Objetivo (gris neutro, siempre igual, sin semáforo). El grupo entero
   se resalta al pasar el mouse — ver daily-bar-hover — con un anillo en el color de superficie
   (spacer estándar del sistema de diseño para separar/destacar una marca sin sumarle un borde). */
.daily-bar{cursor:crosshair;transition:filter .1s ease}
.daily-bar-good{fill:var(--mint)}
.daily-bar-bad{fill:var(--red)}
.daily-bar-none{fill:var(--muted);opacity:.5}
.daily-bar-target{fill:var(--muted)}
.daily-bar-hover{filter:brightness(1.18);stroke:var(--card);stroke-width:2}
.daily-chart{width:100%;height:190px;display:block;overflow:visible;cursor:crosshair}
/* Tendencia semestral (Informe de Temporada): mismo par Real/Objetivo que el resto del dashboard,
   como barras agrupadas en vez de línea — comparación mes a mes, no día a día. */
.season-chart{width:100%;height:190px;display:block;overflow:visible;cursor:crosshair}
.season-bar-actual{fill:var(--coral)}
.season-bar-target{fill:#52657d}
.season-chart-axis{position:relative;height:16px;margin-top:6px}
.season-chart-axis span{position:absolute;transform:translateX(-50%);color:#64748B;font-size:9.5px;font-family:var(--display);white-space:nowrap}
/* Nodos visibles en Objetivo/Real: sin esto, un tramo real de 1-2 días queda invisible al lado de
   una proyección que se estira meses hacia adelante (ver renderBars/nodesFor). */
.line-node{opacity:.9;cursor:crosshair}
.line-node-target{fill:#52657d}
.line-node-actual{fill:var(--coral)}
.line-node-prior{fill:var(--muted)}
/* Guía + puntos de hover: ocultos por default (display:none inline), attachChartHover los prende
   y reposiciona al mover el mouse/dedo sobre el gráfico. */
.line-chart{cursor:crosshair}
.hover-line{stroke:var(--line);stroke-width:1}
.hover-dot{stroke:var(--card);stroke-width:2}
.chart-tooltip{position:absolute;top:4px;transform:translateX(-50%);background:var(--card);border:1px solid var(--line);border-radius:var(--radius-sm);padding:8px 10px;box-shadow:var(--shadow-pop);pointer-events:none;z-index:5;white-space:nowrap}
.chart-tooltip-date{font:600 11px var(--display);margin-bottom:5px;color:var(--white)}
.chart-tooltip-row{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--muted)}
.chart-tooltip-row+.chart-tooltip-row{margin-top:3px}
.chart-tooltip-row i{width:8px;height:8px;border-radius:2px;flex-shrink:0}
.chart-tooltip-row strong{margin-left:16px;padding-left:6px;font-family:var(--display);color:var(--white)}
.empty-state{color:var(--muted);font-size:12px;display:flex;align-items:center;justify-content:center;min-height:120px}

/* ── DEVIATION ────────────────────────────────────────────── */
.panel-fill{display:flex;flex-direction:column}
.panel-fill .deviation-card{flex:1}
.deviation-card{min-height:218px;display:flex;flex-direction:column;align-items:flex-start;justify-content:center}
.deviation-number{font:600 53px var(--display);line-height:1;margin:10px 0}
.deviation-number.good{color:var(--mint)}
.deviation-number.bad{color:var(--red)}
.deviation-copy{color:var(--muted);max-width:220px}
/* "Resumen Ejecutivo" (#deviationCard): override puntual por id, no toca la clase .deviation-card
   compartida con #ecomProjection (esa sigue con un solo bloque centrado, sin split-en-dos). */
/* 4 filas apiladas a todo el ancho, cada una flex:1 (el banner un poco más chico) — se reparten la
   altura completa del panel entre todas, sin huecos, en vez de un solo bloque centrado. */
#deviationCard{display:flex;flex-direction:column;gap:10px;height:100%;align-items:stretch;justify-content:flex-start}
.resumen-row{flex:1;min-height:0;display:flex;flex-direction:column;justify-content:center;background:var(--ink);border:1px solid var(--line);border-radius:var(--radius-sm);padding:12px 16px;min-width:0}
/* Font-size chico y ajustado con getBoundingClientRect(): "Ritmo Necesario" ($1.872.372 /día) es el
   valor más largo de las 3 filas hero y tiene que entrar en una sola línea en el ancho real del panel. */
.resumen-row .deviation-number{font-size:26px;margin:4px 0 0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.resumen-row-banner{flex:.7;align-items:center;justify-content:center;text-align:center;background:rgba(148,163,184,.1)}
.resumen-row-banner.bad{background:rgba(239,68,68,.12);border-color:rgba(239,68,68,.35)}
.resumen-row-banner.good{background:rgba(34,197,94,.12);border-color:rgba(34,197,94,.35)}
.resumen-banner-text{font:700 13.5px var(--sans);color:var(--muted)}
.resumen-row-banner.bad .resumen-banner-text{color:var(--red)}
.resumen-row-banner.good .resumen-banner-text{color:var(--mint)}
.projection-alt{margin-top:6px;font-size:11px;color:var(--muted)}

/* ── RANKING LIST ─────────────────────────────────────────── */
/* Una sola definición limpia — sin colisión */
.ranking-list{display:flex;flex-direction:column;gap:0}
.ranking-list .rank-row{
  display:grid;
  grid-template-columns:26px 1fr auto;
  align-items:center;
  gap:10px;
  padding:11px 0;
  border-bottom:1px solid var(--line);
  min-width:0;
}
.ranking-list .rank-row:last-child{border-bottom:0}
.ranking-list .rank-main{display:flex;flex-direction:column;gap:4px;min-width:0;overflow:hidden}
.ranking-list .rank-heading{display:flex;align-items:center;gap:8px;min-width:0}
.ranking-list .rank-name{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ranking-list .rank-sub{display:block;color:var(--muted);font-size:10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ranking-list .rank-bar{height:5px;background:#304257;margin-top:4px;border-radius:var(--radius-pill);overflow:hidden}
.ranking-list .rank-fill{height:100%;background:var(--coral);border-radius:var(--radius-pill)}
.ranking-list .rank-value{white-space:nowrap;text-align:right;font:700 13px var(--display)}
.ranking-list .rank-number{color:var(--coral);font:600 12px var(--display)}
.missing-value{font-size:11px;color:var(--muted);font-weight:600}

/* ── TABLE ────────────────────────────────────────────────── */
/* overflow-x (no overflow:auto a secas): así el único eje que scrollea DENTRO de .table-wrap es el
   horizontal (tablas anchas en mobile) — el vertical lo sigue haciendo la página entera, que es lo
   que necesita position:sticky en los th de abajo para pegarse al techo del VIEWPORT en vez de a
   un contenedor interno sin scroll propio (auditoría 2026-09-06). */
.table-wrap{overflow-x:auto;overflow-y:visible;margin:0 -22px -22px;border-radius:0 0 var(--radius) var(--radius)}
.table-wrap table{border-collapse:collapse;width:100%;text-align:left;font-size:12px}
.table-wrap table.table-wide{min-width:720px}
.table-wrap th{background:var(--sub);color:#D8E4F2;font-size:10px;letter-spacing:.5px;font-weight:700;text-transform:uppercase;padding:11px 12px;white-space:nowrap;position:sticky;top:0;z-index:2}
.table-wrap th[data-sort]{cursor:pointer;user-select:none}
/* :hover/:active reales solo se enganchan en dispositivos con mouse de verdad (hover:hover). En
   touch (tablets/celus, donde se usa este dashboard en el piso de venta) esos pseudo-clases no
   tienen un mouseleave que los saque — el header tocado para ordenar quedaba "pegado" en su estado
   de hover/active, más oscuro, hasta el próximo tap en cualquier otro lado de la pantalla (bug real
   reportado 2026-09-13: "cada vez que selecciono una métrica se vuelve azul o oscuro y no se logra
   ver bien"). Qué columna está ordenada ya no depende de esto — se marca aparte, abajo, con
   [aria-sort] (ese sí refleja el estado real de state.sort, no un pseudo-clase que puede quedar
   pegado). color acá es #FFFFFF fijo, NUNCA var(--white): el fondo de este header queda siempre
   oscuro en los dos temas (ver línea de arriba y el override de modo claro más arriba en este
   archivo), pero var(--white) SÍ cambia de significado entre temas — en modo claro vale #0F1F33
   (texto oscuro para fondos claros). Con var(--white) acá, pasar el mouse en modo claro pintaba el
   header en texto casi negro sobre su propio fondo casi negro — ilegible (bug real reportado
   2026-09-13: "cuando paso el cursor se oscurecen las letras"). */
@media (hover:hover){
  .table-wrap th[data-sort]:hover{color:#FFFFFF}
  .table-wrap th[data-sort]:active{background:#16283d}
}
/* Columna realmente ordenada (headerCell/renderTable ya escriben aria-sort acorde a state.sort) —
   mismo coral que el resto del dashboard usa para "esto está activo/seleccionado"
   (.nav-item.active, .rank-tab.active, .store-kpi-card.active): a diferencia de :hover/:active de
   arriba, esto nunca queda "pegado" porque sale del estado real, no de un pseudo-clase del browser. */
.table-wrap th[data-sort][aria-sort="ascending"],
.table-wrap th[data-sort][aria-sort="descending"]{color:var(--coral)}
/* Foco de teclado real en los headers ordenables (antes solo funcionaban con mouse — ver
   sortSellerDetail/renderTable, ahora enganchan Enter/Espacio además de click). outline propio en
   vez del default del navegador: con position:sticky + fondo oscuro, el outline azul de sistema
   quedaba parcialmente tapado por las celdas de al lado al hacer scroll horizontal. */
.table-wrap th[data-sort]:focus-visible{outline:2px solid var(--coral);outline-offset:-2px}
.table-wrap td{padding:11px 12px;border-bottom:1px solid var(--line);color:var(--soft);white-space:nowrap}
.table-wrap tbody tr:nth-child(even){background:var(--row2)}
.table-wrap tbody tr:nth-child(odd){background:var(--row)}
.table-wrap tbody tr:hover td{background:#20344b;color:var(--white)}
/* Primera columna (siempre el nombre/fecha/local — la identidad de la fila) fija al scrollear una
   tabla ancha de costado en mobile: sin esto, al scrollear para ver "% objetivo" se pierde de vista
   A QUIÉN corresponde esa fila (mismo patrón que Google Sheets/Notion). th:first-child es además el
   único header con top Y left sticky a la vez (la esquina), por eso necesita más z-index que el
   resto — si no, el resto de los th (solo top) le pasarían por encima al hacer scroll horizontal.
   Los td:first-child necesitan un fondo PROPIO (no heredan el de su <tr>): position:sticky los saca
   del flujo de pintado normal, así que sin esto se veían las columnas de atrás transparentando
   detrás de la columna fija al scrollear. */
.table-wrap th:first-child{left:0;z-index:3}
.table-wrap td:first-child{position:sticky;left:0;z-index:1}
.table-wrap tbody tr:nth-child(even) td:first-child{background:var(--row2)}
.table-wrap tbody tr:nth-child(odd) td:first-child{background:var(--row)}
.table-wrap tbody tr:hover td:first-child{background:#20344b}
/* Números a la derecha, no centrados ni a la izquierda — convención estándar de cualquier tabla de
   datos (Excel, Sheets, Notion): así las unidades/decenas/centenas quedan alineadas entre filas y
   se puede comparar magnitudes de un vistazo, algo que ni centrado ni izquierda permiten (pedido
   explícito 2026-09-08). .align-right es la versión sin el resto de .num (blanco+Space Grotesk)
   para headers — un <th> no necesita ese tratamiento de número, solo la alineación. */
.table-wrap td.num{text-align:right}
.table-wrap th.align-right{text-align:right}
.num{font-family:var(--display);color:var(--white)!important}
.positive{color:var(--mint)!important}
.negative{color:var(--red)!important}
.warning{color:var(--amber)!important}
.seller-name{font-weight:600;color:var(--white)!important}
.seller-location{color:var(--muted)!important;font-size:11px}

/* ── RANKING / GAMIFICACIÓN ───────────────────────────────── */
.rank-tabs{display:flex;gap:6px;margin:-4px 0 22px;flex-wrap:wrap}
.rank-tab{height:34px;padding:0 16px;border:1px solid var(--line);border-radius:var(--radius-pill);background:var(--card);color:var(--muted);font:600 12px var(--sans);cursor:pointer;transition:.2s}
.rank-tab:hover{color:var(--white);border-color:var(--coral)}
.rank-tab:active{transform:scale(.96)}
.rank-tab.active{background:var(--coral);border-color:var(--coral);color:#1b120b}
.panel-head-right{display:flex;align-items:center;gap:12px}
.rank-sort-toggle{display:flex;gap:3px;background:var(--ink);border:1px solid var(--line);border-radius:var(--radius-pill);padding:3px}
.rank-tab-sm{height:24px;padding:0 10px;border:0;border-radius:var(--radius-pill);background:transparent;color:var(--muted);font:600 10px var(--sans);cursor:pointer;transition:.2s}
.rank-tab-sm:hover{color:var(--white)}
.rank-tab-sm:active{transform:scale(.94)}
.rank-tab-sm.active{background:var(--coral);color:#1b120b}
.rank-pos{display:inline-flex;align-items:center;gap:4px;font-family:var(--display);font-weight:700}
.rank-medal{font-size:15px;line-height:1}
.trend-up{color:var(--mint)}
.trend-down{color:var(--red)}
.trend-flat{color:var(--muted)}
.badge-panel{display:flex;flex-direction:column;gap:2px}
.badge-row{display:grid;grid-template-columns:26px 1fr auto;align-items:center;gap:12px;padding:9px 0;border-bottom:1px solid var(--line);font-size:12px}
.badge-row:last-child{border-bottom:0}
.badge-icon{font-size:16px;text-align:center;line-height:1}
.badge-info{display:flex;flex-direction:column;gap:1px;overflow:hidden}
.badge-info strong{font-weight:700;color:var(--white);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.badge-info span{color:var(--muted);font-size:11px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.badge-value{font:700 12px var(--display);color:var(--coral);white-space:nowrap}
#evolutionScopeToggle{display:inline-flex;margin-bottom:20px}

/* ── SEASON REPORT ────────────────────────────────────────── */
.season-focus{display:flex;flex-direction:column;gap:2px;min-height:150px}
.focus-row{display:flex;justify-content:space-between;align-items:center;padding:10px 0;border-bottom:1px solid var(--line);font-size:12px}
.focus-row:last-child{border-bottom:0}
.focus-label{color:var(--muted)}
.focus-value{font:700 13px var(--display);color:var(--white)}
.focus-value.positive{color:var(--mint)}
.focus-value.negative{color:var(--red)}
.season-total td{font-weight:700;border-top:2px solid var(--line);background:transparent!important}

/* ── TEAM HEALTH ──────────────────────────────────────────── */
.team-health{display:flex;flex-direction:column;gap:16px;min-height:150px}
.health-summary{display:flex;gap:10px}
.health-chip{flex:1;border-radius:var(--radius-sm);padding:12px 10px;text-align:center;background:#101c2d;border:1px solid var(--line)}
.health-chip strong{display:block;font:700 22px var(--display)}
.health-chip span{font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:.5px}
.health-chip.ok strong{color:var(--mint)}
.health-chip.warn strong{color:var(--amber)}
.health-chip.danger strong{color:var(--red)}
.health-list{display:flex;flex-direction:column;gap:2px}
.health-row{display:grid;grid-template-columns:10px 1fr auto auto;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid var(--line);font-size:12px}
.health-row:last-child{border-bottom:0}
.health-name{font-weight:600;color:var(--white);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.health-local{color:var(--muted);font-size:11px}
.health-ratio{font-family:var(--display);font-weight:700}
.health-empty{color:var(--muted);font-size:12px;text-align:center;padding:10px 0}
.health-empty-icon{width:13px;height:13px;vertical-align:-2px;margin-right:5px}

/* ── TRAFFIC LIGHTS ───────────────────────────────────────── */
.traffic-light{display:inline-flex;align-items:center;justify-content:center;width:28px;height:22px;border-radius:var(--radius-sm);font-size:12px}
.traffic-light.ok{background:#34d3991c;color:var(--mint)}
.traffic-light.warn{background:#fbbf241c;color:var(--amber)}
.traffic-light.danger{background:#f871711c;color:var(--red)}
.traffic-light.empty{background:#ffffff08;color:#64748B}
.seller-summary{font-size:11px;color:var(--muted)}
.seller-summary strong{color:var(--white);font-family:var(--display)}
.legend{display:flex;gap:14px;color:var(--muted);font-size:11px}
.legend span{display:flex;align-items:center;gap:5px}
.dot{display:inline-block;width:8px;height:8px;border-radius:50%}
.dot.ok{background:var(--mint)}.dot.warn{background:var(--amber)}.dot.danger{background:var(--red)}

/* ── ECOMMERCE ────────────────────────────────────────────── */
.funnel{display:grid;gap:2px}
/* Los paneles de embudo/diagnóstico viven en un split-grid junto a un hermano que suele ser más alto
   (el diagnóstico con su frase de foco, o viceversa) — la grilla estira igual la tarjeta más corta,
   dejando un hueco vacío abajo si el contenido no acompaña esa altura. .panel-flex centra el
   contenido en el alto disponible en vez de dejarlo pegado arriba con aire de más debajo. */
.panel-flex{display:flex;flex-direction:column}
.panel-flex .funnel,.panel-flex .store-diagnosis{flex:1;display:flex;flex-direction:column;justify-content:center;gap:14px}
.funnel-row{display:grid;grid-template-columns:86px 1fr 70px;gap:10px;align-items:center;font-size:11px;padding:5px 0}
.funnel-step{padding-left:96px;color:var(--coral);font-size:10px;font-weight:700}
.funnel-label{color:var(--muted);display:flex;flex-direction:column;gap:2px;line-height:1.3}
.funnel-step-inline{color:var(--coral);font-size:9px;font-weight:700}
.funnel-track{background:#101a28;height:14px;border-radius:var(--radius-pill);overflow:hidden}
.funnel-fill{height:100%;background:var(--coral);border-radius:var(--radius-pill)}
.funnel-fill-negative{background:var(--red)}
.funnel-value{text-align:right;font-family:var(--display)}

/* ── LOCALES · TRÁFICO / DIAGNÓSTICO ─────────────────────────── */
.donut-chart svg{display:block;flex-shrink:0}
.progress-card .metric-detail{margin-bottom:2px}
.progress-track{background:#101a28;height:10px;border-radius:var(--radius-pill);overflow:hidden;margin-top:12px}
.progress-fill{height:100%;border-radius:var(--radius-pill);background:var(--muted)}
.progress-fill.good{background:var(--mint)}
.progress-fill.warning{background:var(--amber)}
.progress-fill.bad{background:var(--red)}
.store-diagnosis{display:flex;flex-direction:column;gap:16px}
.diagnosis-row{display:flex;flex-direction:column;gap:2px}
.diagnosis-label{color:var(--muted);font-size:10px;letter-spacing:1.2px;text-transform:uppercase}
.diagnosis-value{font:600 22px var(--display)}
.diagnosis-note{font-size:11px;color:var(--muted)}
.diagnosis-focus{margin-top:2px;padding-top:12px;border-top:1px solid var(--line);font-size:12px;font-weight:600;color:var(--soft)}
.ads-summary{display:grid;gap:14px;min-height:170px;align-content:center}
/* gap:12px además de space-between: space-between solo reparte el espacio SOBRANTE — con la fila
   "ROAS / BE ROAS" (la etiqueta más larga de la tarjeta) casi no quedaba sobrante y el valor
   terminaba pegado al texto. gap fuerza una separación mínima aunque no sobre espacio. */
.ads-line{display:flex;justify-content:space-between;gap:12px;color:var(--muted);font-size:12px;border-bottom:1px solid var(--line);padding-bottom:9px}
.ads-line span{flex-shrink:1;min-width:0}
.ads-line strong{flex-shrink:0;white-space:nowrap}
.ads-line strong{color:var(--white);font:600 15px var(--display)}
.ads-line strong.good{color:var(--mint)}
.ads-line strong.bad{color:var(--red)}

/* ── SELLER PERIOD FILTERS ────────────────────────────────── */
.seller-period-filters{display:flex;gap:10px;align-items:end;margin:-4px 0 22px}
.seller-period-filters label{display:flex;flex-direction:column;gap:6px;color:var(--muted);font-size:11px}
.seller-period-filters select{height:36px;min-width:150px;background:var(--card);border:1px solid var(--line);border-radius:var(--radius-sm);color:var(--soft);padding:0 12px;font:12px var(--sans);box-shadow:var(--shadow-card)}

/* ── ACCESSORIES ──────────────────────────────────────────── */
.accessory-panel{margin-top:22px}
.accessory-panel .panel-head p{margin:5px 0 0;color:var(--muted);font-size:12px}
.accessory-cell{display:grid;grid-template-columns:auto auto;gap:2px 12px;min-width:150px}
.accessory-cell strong{font:600 14px var(--display);color:var(--white)}
.accessory-cell span,.accessory-cell small{color:var(--muted);font-size:10px}
.accessory-cell em{font-style:normal;font-size:11px;font-weight:700}
.accessory-cell small{grid-column:1/-1}
.accessory-cell .positive{color:var(--mint)!important}
.accessory-cell .negative{color:var(--red)!important}
.accessory-cell .warning{color:var(--amber)!important}

/* ── FOOTER ───────────────────────────────────────────────── */
.app-footer{padding:28px 0 0;border-top:1px solid var(--line);margin-top:32px;color:#64748B;font-size:10px;display:flex;justify-content:space-between}
.app-footer span{color:var(--muted)}

/* ── RESPONSIVE ───────────────────────────────────────────── */
@media(max-width:1050px){
  .sidebar{width:190px}.main-content{padding:0 24px 30px}
  .metric-grid{grid-template-columns:repeat(2,1fr)}
}
@media(max-width:720px){
  .app-shell{display:block}.sidebar{width:100%;min-height:auto;padding:15px 14px 10px;border-right:0;border-bottom:1px solid var(--line)}
  .brand{padding:3px 5px 15px}.live-state{position:absolute;right:14px;top:15px;margin:0}
  /* El .nav horizontal-scroll (7 items apretados) queda reemplazado por bottom-nav + drawer — ya
     no hace falta convertirlo a fila, se oculta entero (junto con nav-index/sidebar-footer, que
     tampoco aplican: el toggle de tema se duplicó dentro del drawer, ver "Configuración"). */
  .nav{display:none}
  .sidebar-footer{display:none}
  .bottom-nav{display:grid}
  body{padding-bottom:76px}
  .main-content{padding:0 14px 25px}.topbar{height:58px}
  /* Objetivos táctiles más cerca del mínimo recomendado (44pt Apple / 48dp Material) — en desktop
     se quedan chicos y densos a propósito (34/28/36px), pero acá son controles que se tocan con el
     dedo: el toggle de tema vive en el drawer mobile, .icon-button es el refresh del topbar, y
     .rank-tab es la navegación principal de Locales/Vendedores/Ranking en el celular (auditoría
     2026-09-06). .icon-button llega a 44 exacto porque está solo en el topbar, con lugar de sobra;
     theme-btn/rank-tab suben a 40 (no a 44) para no inflar filas que ya conviven con otros
     elementos en el mismo ancho de pantalla. */
  .icon-button{width:44px;height:44px}
  .theme-btn{width:40px;height:40px}
  .rank-tab{height:40px;padding:0 15px}
  .rank-tab-sm{height:30px;padding:0 12px}
  .connection-strip{display:grid;grid-template-columns:1fr auto}
  .connection-copy{grid-column:1/-1}.connection-strip input{width:100%}
  .refresh-control{grid-column:1/-1;justify-content:space-between}
  .filters{padding:12px}.filter-heading{grid-column:1/-1}
  /* En mobile el dropdown anclado al trigger (position:absolute, min-width:270px) se sale de
     pantalla o queda apretado contra el borde — pasa a un panel fijo, centrado y con el mismo
     ancho táctil que ya usan los demás modales/drawer de la app en este breakpoint. */
  /* bottom:84px, no 14px — .bottom-nav es fixed;bottom:0 con z-index:60 (por encima del 40 de este
     desplegable), así que con solo 14px el "Aplicar" quedaba geométricamente en pantalla pero
     TAPADO debajo de la barra de navegación — no es que faltara espacio, estaba ahí pero invisible
     e inclickeable. 84px despeja la altura real de la barra (confirmado con el DOM: la barra ronda
     ~70px con el padding + safe-area). */
  .period-dropdown{position:fixed!important;left:14px!important;right:14px!important;top:auto!important;bottom:84px!important;min-width:0!important;width:auto!important;max-width:none!important;max-height:60vh!important;overflow-y:auto!important}
  .period-calendar{overflow-x:auto}
  /* Flatpickr trae tamaño de escritorio por defecto (celdas ~40px) — en un teléfono angosto eso
     empuja "Aplicar"/"Cancelar" fuera de lo visible, dando la sensación de que el calendario "no
     deja seleccionar". Celdas e íconos más chicos para que el mes completo + los botones entren
     sin depender de scroll. */
  .flatpickr-calendar{font-size:12px!important}
  .flatpickr-months{padding:0 0 4px!important}
  .flatpickr-current-month{font:600 12px var(--display)!important;height:auto!important}
  span.flatpickr-weekday{font-size:9px!important}
  .flatpickr-days,.dayContainer{width:100%!important;min-width:0!important}
  .flatpickr-day{height:28px!important;line-height:28px!important;max-width:none!important;width:14.2857%!important;font-size:11px!important}
  .period-apply-btn,#periodCancelBtn{height:30px}
  /* Sticky en vez de confiar en que el calendario entre completo en 70vh: así "Aplicar"/"Cancelar"
     quedan siempre visibles abajo del todo del desplegable mientras se scrollea el calendario
     arriba, en vez de quedar fuera de pantalla sin ninguna pista de que hay que bajar para verlos
     — que era exactamente el problema reportado ("no me deja seleccionar OK"). */
  .period-custom-actions{position:sticky;bottom:0;background:var(--card);padding:8px 4px 4px;margin:0 -8px -8px;box-shadow:0 -8px 10px -4px var(--card)}
  .view-heading{display:block}.period-badge,.roas-badge{display:inline-block;margin-top:14px}
  .metric-grid,.split-grid,.lower-grid{grid-template-columns:1fr}.metric-card{min-height:94px}
  /* "Resumen Ejecutivo" (#deviationCard) usaba height:100% para calzar contra la altura del gráfico
     vecino en la MISMA fila del grid de desktop — acá arriba .split-grid pasa a 1 columna, así que
     ya no hay una fila compartida de la que "100%" tenga sentido. Sin este override el panel se
     comprimía por debajo de lo que su propio contenido necesitaba y el número de "Faltante para la
     meta" quedaba cortado — bug real reportado desde un celular, esta regla lo confirma y corrige. */
  #deviationCard{height:auto}
  .resumen-row{flex:none;min-height:74px}
  .resumen-row-banner{flex:none;min-height:54px}
  .view-heading h1{font-size:27px}.panel{padding:15px}.table-wrap{margin:0 -15px -15px}
  .legend{margin-top:15px;flex-wrap:wrap}.app-footer{display:block}.app-footer span{display:block;margin-top:7px}
  .ranking-list .rank-row{grid-template-columns:22px 1fr auto}
}

/* ── LOCALES · CABECERA DE 6 TARJETAS SELECTORAS ─────────────── */
.store-kpi-grid{display:grid;grid-template-columns:repeat(3,1fr);grid-template-rows:repeat(2,1fr);gap:14px;margin-bottom:14px}
.store-kpi-card{
  background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
  padding:16px 18px;text-align:left;cursor:pointer;transition:.18s ease;
  display:flex;flex-direction:column;gap:5px;box-shadow:var(--shadow-card);
}
.store-kpi-card:hover{border-color:#3a4d66}
.store-kpi-card:active{transform:scale(.98)}
.store-kpi-card.active{
  border-color:var(--coral);background:linear-gradient(180deg,rgba(249,115,22,.14),var(--card) 65%);
  box-shadow:0 0 15px rgba(255,107,0,.25);
}
.store-kpi-index{font:700 10px var(--display);color:var(--muted);letter-spacing:1px}
.store-kpi-card.active .store-kpi-index{color:#FFD9B8}
.store-kpi-label{font-size:11px;letter-spacing:.6px;text-transform:uppercase;color:var(--muted);font-weight:700}
.store-kpi-card.active .store-kpi-label{color:#FFD9B8}
/* #FFD9B8 (durazno clarito) está pensado para el --card oscuro del tema dark, donde resalta bien
   sobre el degradé naranja de fondo — en tema claro --card es blanco (ver LIGHT MODE arriba) y ese
   mismo color casi no se distingue del fondo, dejando el índice/label de la tarjeta activa
   prácticamente ilegibles (bug real reportado con captura, 2026-09-06). Mismo tono que ya usa
   .warning en este archivo para texto ámbar/naranja legible sobre blanco. */
html[data-theme="light"] .store-kpi-card.active .store-kpi-index,
html[data-theme="light"] .store-kpi-card.active .store-kpi-label{color:#B45309}
.store-kpi-value{font:600 21px var(--display);color:var(--white);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.store-kpi-sub{font-size:10.5px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
@media(max-width:900px){.store-kpi-grid{grid-template-columns:repeat(2,1fr);grid-template-rows:repeat(3,1fr)}}
@media(max-width:560px){.store-kpi-grid{grid-template-columns:1fr;grid-template-rows:none}}

/* ── LOCALES · DESGLOSE FINANCIERO (tarjeta 06) — master-detail: dona con el total adentro a
   la izquierda, tarjetas KPI + barra de distribución ocupando todo el resto a la derecha. ── */
.payment-breakdown{display:grid;grid-template-columns:auto 1fr;gap:28px;align-items:center;width:100%}
.payment-breakdown-donut{display:flex;justify-content:center}
.donut-chart-large svg{width:190px;height:190px}
.donut-chart-center{position:relative;display:inline-flex}
.donut-total{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;pointer-events:none}
.donut-total-value{font:700 15px var(--display);color:var(--white);white-space:nowrap}
.donut-total-label{font-size:8.5px;color:var(--muted);text-transform:uppercase;letter-spacing:.5px;margin-top:2px}
.payment-breakdown-right{display:flex;flex-direction:column;gap:16px;min-width:0;width:100%}
.payment-kpi-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:14px}
.payment-kpi-card{background:var(--ink);border:1px solid var(--line);border-radius:var(--radius-sm);padding:14px 16px;display:flex;flex-direction:column;gap:4px}
.payment-kpi-dot{width:8px;height:8px;border-radius:50%;margin-bottom:2px}
.payment-kpi-label{font-size:10.5px;letter-spacing:.6px;text-transform:uppercase;color:var(--muted);font-weight:700}
.payment-kpi-value{font:600 19px var(--display);color:var(--white);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.payment-kpi-sub{font-size:11px;color:var(--muted)}
.payment-flow-bar{display:flex;width:100%;height:14px;border-radius:var(--radius-pill);overflow:hidden;background:var(--ink);gap:2px}
.payment-flow-seg{height:100%;min-width:2px}
@media(max-width:720px){.payment-breakdown{grid-template-columns:1fr}.payment-kpi-grid{grid-template-columns:1fr}}
