/* =============================================================================
   SubsTrackerPro — app.css
   Tokens + shell + componentes COMPARTIDOS. Nada de estilos por-vista aquí.
   Fuente: web/app/SPEC.md §2/§3 (traducción de docs/DESIGN_LANGUAGE.md).

   Para agentes de vista:
   - Solo estas clases y estas variables. Cero tamaños/radios/colores sueltos.
   - Si tu vista necesita una clase propia, prefija con el nombre de la vista
     (.dash-…, .subs-…) y ponla en tu módulo con un <style> NO — mejor: pide que
     se añada aquí. Este archivo es el contrato visual común.
   ========================================================================== */

/* ── Fuentes de marca (rutas absolutas: el sitio se sirve desde /) ────────── */
@font-face {
  font-family: 'Space Grotesk';
  /* format('truetype') a secas: Safari descarta 'truetype-variations'. */
  src: url('/fonts/SpaceGrotesk-var.ttf') format('truetype');
  font-weight: 300 700;
  font-display: swap;
}
@font-face {
  font-family: 'JetBrains Mono';
  src: url('/fonts/JetBrainsMono-Regular.woff2') format('woff2');
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: 'JetBrains Mono';
  src: url('/fonts/JetBrainsMono-Medium.woff2') format('woff2');
  font-weight: 500;
  font-display: swap;
}

/* ── §2 TOKENS ────────────────────────────────────────────────────────────── */
:root {
  /* Color — claro */
  --stp-primary: hsl(250 95% 65%);
  --stp-accent:  hsl(170 85% 45%);
  --stp-bg:      hsl(220 20% 97%);
  --stp-card:    hsl(0 0% 100%);
  --stp-border:  hsl(220 15% 88%);
  --stp-muted:   hsl(220 10% 45%);
  --stp-success: hsl(150 65% 38%);
  --stp-warning: hsl(38 92% 42%);
  --stp-error:   hsl(0 72% 48%);
  --stp-info:    hsl(205 90% 42%);

  /* Texto: NO está en la tabla de SPEC §2 (que sólo lista superficies).
     Se deriva del par card/bg de cada tema para garantizar AA. */
  --stp-text:      hsl(225 25% 12%);
  --stp-text-soft: hsl(225 12% 30%);
  --stp-on-brand:  #ffffff;
  /* Violeta de marca CUANDO ES TEXTO. En claro es el primario tal cual (4.9:1
     sobre blanco); en oscuro se aclara un punto porque el primario puro se
     queda en 4.43:1 sobre el sidebar y no llega a AA. Los rellenos, bordes y
     degradados siguen usando --stp-primary sin tocar. */
  --stp-primary-text: var(--stp-primary);
  /* Semánticos CUANDO SON TEXTO. Mismo criterio que --stp-primary-text: los
     tokens de arriba están calibrados como RELLENO (badge, punto, barra) y a
     11px sobre su propio tinte no llegan a AA — medido: «Activa» 3.13:1 y
     «Pausada» 2.81:1. Estos bajan (claro) o suben (oscuro) la claridad hasta
     cruzar 4.5:1 sin tocar tono ni saturación, así que el verde sigue siendo
     el mismo verde. Usa el token -text en `color:`, el otro en `background`. */
  --stp-success-text: hsl(150 65% 28%);
  --stp-warning-text: hsl(38 92% 29%);
  --stp-error-text:   hsl(0 72% 38%);
  --stp-info-text:    hsl(205 90% 36%);

  /* Degradado insignia y paleta de gradientes de stat cards (ver capturas).
     ── Contraste (compuerta §6.2) ─────────────────────────────────────────
     Sobre estos degradados SIEMPRE va texto blanco, y --fs-body-sm (13px) es
     texto normal: necesita 4.5:1. El insignia va TAL CUAL lo fija la SPEC §2
     (#6D51FA→#9E33F0, 4.99:1 y 5.02:1 — pasa). Los otros cinco NO están en la
     SPEC; se inventaron aquí, y sus versiones vivas medían 2.14:1 (accent),
     2.15:1 (warm) y 2.54:1 (green) — por debajo incluso del 3:1 de texto
     grande. Se bajó la claridad de cada parada lo MÍNIMO para cruzar 4.5:1
     conservando tono y saturación, así que la card sigue leyéndose «teal»,
     «ámbar», «verde». Ratio de blanco puro sobre cada parada, medido:
       primary 4.99 / 5.02   accent 4.60 / 5.51   cool 4.56 / 5.62
       warm    4.92 / 5.18   pink   5.46 / 5.31   green 5.07 / 5.42
     `warm` se quedó en la familia ÁMBAR→NARANJA QUEMADO a propósito: la
     primera versión oscurecida caía en rojo, y warm viste la card de
     «Pausadas» — un rojo ahí se lee como error, que es otro mensaje.
     Si tocas una parada, vuelve a medirla: el blanco no perdona. */
  --stp-grad-primary: linear-gradient(135deg, #6D51FA, #9E33F0);
  --stp-grad-accent:  linear-gradient(135deg, #0D8474, #0A7386);
  --stp-grad-cool:    linear-gradient(135deg, #1D6FF2, #4F53E8);
  --stp-grad-warm:    linear-gradient(135deg, #A16207, #C2410C);
  --stp-grad-pink:    linear-gradient(135deg, #C81C6E, #7B45F0);
  --stp-grad-green:   linear-gradient(135deg, #0B7E58, #0F7A3F);

  /* Tipografía — escala con nombre. Prohibido un tamaño suelto. */
  --font-display: 'Space Grotesk', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-body:    'Space Grotesk', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono:    'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  --fs-title1:  28px;
  --fs-title2:  22px;
  --fs-title3:  18px;
  --fs-headline:16px;
  --fs-body-md: 15px;
  --fs-body-sm: 13px;
  --fs-caption: 12px;
  --fs-label:   11px;

  /* Radios — 3 niveles, prohibido un cuarto */
  --r-card: 16px;
  --r-ctrl: 12px;
  --r-icon: 10px;
  --r-pill: 999px; /* excepción documentada: píldoras/chips = cápsula, no un radio nuevo */

  /* Sombras */
  --sh-sm:   0 2px 8px rgb(22 19 31 / .05);
  --sh-md:   0 6px 18px rgb(22 19 31 / .10);
  --sh-lg:   0 15px 40px rgb(22 19 31 / .10);
  --sh-glow: 0 0 20px rgb(109 81 250 / .30);

  /* Anchos con nombre (STPContentWidth) */
  --w-list:    400px;
  --w-reading: 640px;
  --w-hero:    680px;
  --w-detail:  760px;
  --w-canvas: 1100px;

  /* Espaciado */
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px; --sp-4: 16px;
  --sp-5: 20px; --sp-6: 24px; --sp-8: 32px; --sp-10: 40px;

  /* Shell */
  --sidebar-w: 248px;
  --tabbar-h: 62px;

  /* Movimiento */
  --dur: 200ms;
  --ease: cubic-bezier(.22,.61,.36,1);

  /* Wash de hover/pressable */
  --wash: rgb(109 81 250 / .06);
}

[data-theme="dark"] {
  --stp-primary: hsl(250 95% 70%);
  --stp-accent:  hsl(170 85% 50%);
  --stp-bg:      hsl(225 25% 8%);
  --stp-card:    hsl(225 25% 12%);
  --stp-border:  hsl(225 20% 20%);
  --stp-muted:   hsl(220 15% 60%);
  /* success/warning/error/info: +12% de claridad (SPEC §2) */
  --stp-success: hsl(150 65% 50%);
  --stp-warning: hsl(38 92% 54%);
  --stp-error:   hsl(0 72% 60%);
  --stp-info:    hsl(205 90% 54%);

  --stp-text:      hsl(220 20% 95%);
  --stp-text-soft: hsl(220 15% 78%);
  /* Mismo tono y saturación que --stp-primary, +4% de claridad: 5.4:1 sobre el
     sidebar oscuro (el primario puro se queda en 4.43:1 y no llega a AA). */
  --stp-primary-text: hsl(250 95% 74%);
  /* Mismos pares, subiendo claridad (en oscuro el texto va más claro que el relleno). */
  --stp-success-text: hsl(150 65% 60%);
  --stp-warning-text: hsl(38 92% 60%);
  --stp-error-text:   hsl(0 72% 66%);
  --stp-info-text:    hsl(205 90% 60%);

  /* D-C: sombra negra pura sobre --stp-bg casi negro (hsl(225 25% 8%)) no
     aporta elevación — se pierde contra el fondo. Se suma un halo claro de
     1px como segunda capa del propio token, mismo criterio que ya resuelve
     bien .receipt en styles.css con su borde rgba(255,255,255,.14). Como
     estos tokens se consumen directos (`box-shadow: var(--sh-md)`, sin
     prefijo de offset delante), cada capa lleva su propio offset/spread. */
  --sh-sm:   0 2px 8px rgb(0 0 0 / .35), 0 0 0 1px rgb(255 255 255 / .06);
  --sh-md:   0 6px 18px rgb(0 0 0 / .45), 0 0 0 1px rgb(255 255 255 / .08);
  --sh-lg:   0 15px 40px rgb(0 0 0 / .50), 0 0 0 1px rgb(255 255 255 / .10);
  --sh-glow: 0 0 22px rgb(139 108 255 / .38);

  --wash: rgb(155 130 255 / .10);
}

/* ── Reset mínimo ─────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; }
body {
  background: var(--stp-bg);
  color: var(--stp-text);
  font-family: var(--font-body);
  font-size: var(--fs-body-md);
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
h1, h2, h3, h4, p, figure { margin: 0; }
button { font: inherit; color: inherit; }
a { color: inherit; text-decoration: none; }
ul, ol { margin: 0; padding: 0; list-style: none; }
img, svg { max-width: 100%; }
:focus-visible {
  outline: 2px solid var(--stp-primary);
  outline-offset: 2px;
  border-radius: var(--r-icon);
}

.icon { width: 20px; height: 20px; flex: none; fill: none; stroke: currentColor;
        stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.icon--sm { width: 16px; height: 16px; }
.icon--lg { width: 24px; height: 24px; }

.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums;
        font-feature-settings: 'tnum' 1; letter-spacing: -.01em; }
.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;
}
.skip-link {
  position: fixed; top: -100px; left: var(--sp-4); z-index: 100;
  background: var(--stp-card); color: var(--stp-text);
  padding: var(--sp-2) var(--sp-4); border-radius: var(--r-ctrl);
  box-shadow: var(--sh-md);
}
.skip-link:focus { top: var(--sp-4); }

/* ── §2 Glass (traducción web) ────────────────────────────────────────────── */
.glass-base {
  background: color-mix(in srgb, var(--stp-card) 72%, transparent);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--stp-border);
}
.glass-elevated {
  background: color-mix(in srgb, var(--stp-card) 84%, transparent);
  backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px);
  border: 1px solid var(--stp-border);
  box-shadow: var(--sh-md);
}
.glass-pill {
  background: color-mix(in srgb, var(--stp-card) 60%, transparent);
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  border: 1px solid var(--stp-border);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .glass-base, .glass-elevated, .glass-pill { background: var(--stp-card); }
}

/* ── §3 SHELL ─────────────────────────────────────────────────────────────── */
.shell { min-height: 100vh; min-height: 100dvh; }

/* Sidebar: "mueble" — lista sobria, SIN glass. */
.sidebar {
  position: fixed; inset: 0 auto 0 0; width: var(--sidebar-w);
  display: none; flex-direction: column; gap: var(--sp-2);
  padding: var(--sp-5) var(--sp-3) var(--sp-4);
  background: var(--stp-card);
  border-right: 1px solid var(--stp-border);
  z-index: 20;
}
.sidebar__brand {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3) var(--sp-5);
}
.brand-mark {
  width: 30px; height: 30px; flex: none; border-radius: var(--r-icon);
  background: var(--stp-grad-primary); color: var(--stp-on-brand);
  display: grid; place-items: center;
  font-family: var(--font-display); font-weight: 700; font-size: var(--fs-headline);
}
.brand-name { font-family: var(--font-display); font-weight: 700; font-size: var(--fs-headline); }

.sidebar__nav { display: flex; flex-direction: column; gap: 2px; flex: 1; overflow-y: auto; }
.navitem {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: 9px var(--sp-3); border-radius: var(--r-ctrl);
  font-size: var(--fs-body-md); font-weight: 500; color: var(--stp-text-soft);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.navitem .icon { color: var(--stp-muted); transition: color var(--dur) var(--ease); }
.navitem:hover { background: var(--wash); color: var(--stp-text); }
.navitem[aria-current="page"] {
  background: color-mix(in srgb, var(--stp-primary) 12%, transparent);
  color: var(--stp-primary-text); font-weight: 600;
}
.navitem[aria-current="page"] .icon { color: var(--stp-primary-text); }

.sidebar__foot {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3); border-top: 1px solid var(--stp-border);
}
.sidebar__foot-text { display: flex; flex-direction: column; line-height: 1.2; min-width: 0; }
.sidebar__foot-text strong { font-size: var(--fs-body-sm); font-weight: 600; }
.sidebar__foot-text small { font-size: var(--fs-label); color: var(--stp-muted); }
.avatar {
  width: 34px; height: 34px; flex: none; border-radius: var(--r-pill);
  background: var(--stp-grad-primary); color: var(--stp-on-brand);
  display: grid; place-items: center;
  font-family: var(--font-display); font-weight: 600; font-size: var(--fs-body-sm);
}

/* Main */
.view {
  --view-max: var(--w-canvas);
  width: 100%; max-width: var(--view-max);
  margin: 0 auto;
  padding: var(--sp-5) var(--sp-4)
           calc(var(--tabbar-h) + var(--sp-8) + env(safe-area-inset-bottom));
  outline: none;
}
.view[data-width="list"]    { --view-max: var(--w-list); }
.view[data-width="reading"] { --view-max: var(--w-reading); }
.view[data-width="hero"]    { --view-max: var(--w-hero); }
.view[data-width="detail"]  { --view-max: var(--w-detail); }
.view[data-width="canvas"]  { --view-max: var(--w-canvas); }
.view__boot { color: var(--stp-muted); font-size: var(--fs-body-sm); }

/* Tabbar: píldora flotante de glass (espejo del TabView de iPhone). */
.tabbar {
  position: fixed; z-index: 20;
  left: var(--sp-2); right: var(--sp-2);
  bottom: calc(var(--sp-3) + env(safe-area-inset-bottom));
  /* Flex, no grid de 5 iguales: con 5 columnas idénticas «Suscripciones» no
     cabe a 390px y se cortaba. Así cada pestaña toma su ancho y el sobrante
     se reparte por igual. */
  display: flex;
  border-radius: var(--r-pill);
  padding: var(--sp-2) 2px;
  background: color-mix(in srgb, var(--stp-card) 60%, transparent);
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  border: 1px solid var(--stp-border);
  box-shadow: var(--sh-md);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .tabbar { background: var(--stp-card); }
}
.tabitem {
  flex: 1 1 auto; min-width: 0;
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: var(--sp-1) 3px; border-radius: var(--r-pill);
  font-size: var(--fs-label); font-weight: 500; color: var(--stp-muted);
  letter-spacing: -.01em; text-align: center;
}
.tabitem span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tabitem[aria-current="page"] {
  color: var(--stp-primary-text); font-weight: 600;
  background: color-mix(in srgb, var(--stp-primary) 12%, transparent);
}

@media (min-width: 900px) {
  .sidebar { display: flex; }
  .tabbar  { display: none; }
  /* El shell cede el espacio de la sidebar fija; .view centra dentro del resto. */
  .shell { padding-left: var(--sidebar-w); }
  .view  { padding: var(--sp-8) var(--sp-6) var(--sp-10); }
}

/* ── Cabecera de página (compartida) ──────────────────────────────────────── */
.page-header { margin-bottom: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-2); }
.page-header__top { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }
.page-title { font-family: var(--font-display); font-size: var(--fs-title1); font-weight: 700; letter-spacing: -.02em; }
.page-sub   { color: var(--stp-muted); font-size: var(--fs-body-md); }
.section-title {
  font-family: var(--font-display); font-size: var(--fs-title3); font-weight: 600;
  margin-bottom: var(--sp-3); display: flex; align-items: center; gap: var(--sp-2);
}
.section-title__action { margin-left: auto; font-size: var(--fs-body-sm); font-weight: 500; color: var(--stp-primary-text); }
.eyebrow { font-size: var(--fs-label); font-weight: 600; letter-spacing: .06em;
           text-transform: uppercase; color: var(--stp-muted); }
.stack   { display: flex; flex-direction: column; gap: var(--sp-4); }
.stack--sm { gap: var(--sp-2); }
.stack--lg { gap: var(--sp-6); }
.row-inline { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.spacer { flex: 1; }
.muted { color: var(--stp-muted); }
.text-sm { font-size: var(--fs-body-sm); }
.text-caption { font-size: var(--fs-caption); }

/* Rejillas compartidas — cuál usar:
   .grid-2      KPIs y accesos rápidos: SIEMPRE 2 columnas, también en móvil
                (es lo que hace el TabView de iPhone en las capturas).
   .grid-cards  tarjetas de contenido (gráficos, secciones): 2+ columnas en
                ancho, se apilan solas en móvil.
   .grid-auto   mosaico de tiles anchas (hub de Finanzas). */
.grid-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-3); }
.grid-3 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-3); }
@media (min-width: 900px) { .grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.grid-cards { display: grid; gap: var(--sp-4);
              grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); }
.grid-auto { display: grid; gap: var(--sp-3);
             grid-template-columns: repeat(auto-fill, minmax(min(100%, 220px), 1fr)); }
.grid-auto--wide { grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr)); }

/* ── Superficies ──────────────────────────────────────────────────────────── */
.card {
  background: color-mix(in srgb, var(--stp-card) 72%, transparent);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--stp-border);
  border-radius: var(--r-card);
  padding: var(--sp-4);
  box-shadow: var(--sh-sm);
}
.card--elevated {
  background: color-mix(in srgb, var(--stp-card) 84%, transparent);
  backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px);
  box-shadow: var(--sh-md);
}
.card--flush { padding: 0; overflow: hidden; }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .card { background: var(--stp-card); }
}

/* Aviso permanente de modo demostración (P6 de la auditoría). Vive DENTRO
   de #view, insertado por main.js como primer bloque de cada vista — no es
   position:fixed a propósito: el shell ya tiene sidebar/tabbar fijos, y
   apilar un tercer elemento fijo arriba de todo obliga a recalcular offsets
   de los otros dos en cada breakpoint. En flujo normal, el aviso simplemente
   empuja el contenido de la vista hacia abajo, sin taparlo, y se comporta
   igual a 390px que a 1280px sin media queries propias. */
.demo-banner {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4); margin-bottom: var(--sp-5);
  border-radius: var(--r-card);
  border: 1px solid color-mix(in srgb, var(--stp-info) 35%, var(--stp-border));
  background: color-mix(in srgb, var(--stp-info) 12%, transparent);
}
.demo-banner__text { flex: 1 1 220px; min-width: 0; font-size: var(--fs-body-sm); color: var(--stp-info-text); }
.demo-banner .btn { flex: none; }

/* Hero card del Dashboard — degradado insignia */
.hero-card {
  border-radius: var(--r-card); padding: var(--sp-6);
  background: var(--stp-grad-primary); color: var(--stp-on-brand);
  box-shadow: var(--sh-md);
}
/* .94 y no .82: sobre el degradado insignia, un blanco al 82% da 3.89:1 y el
   .eyebrow de la hero (11px, «PROYECCIÓN ANUAL») es texto normal → 4.5:1.
   Al 94% mide 4.60:1 en las dos paradas y se sigue leyendo más suave que el
   blanco puro del monto. No lo bajes sin volver a medir. */
.hero-card .muted, .hero-card .page-sub, .hero-card .eyebrow { color: rgb(255 255 255 / .94); }

/* ── Pressable + hover wash ───────────────────────────────────────────────── */
.pressable { transition: transform var(--dur) var(--ease), opacity var(--dur) var(--ease),
                          background var(--dur) var(--ease); cursor: pointer; }
.pressable:hover { background-color: var(--wash); }
.pressable:active { transform: scale(.97); opacity: .92; }

/* ── Stat card ────────────────────────────────────────────────────────────── */
.stat-card {
  position: relative; display: flex; flex-direction: column; gap: var(--sp-2);
  border-radius: var(--r-card); padding: var(--sp-4);
  color: var(--stp-on-brand); background: var(--stp-grad-primary);
  border: 0; text-align: left; width: 100%;
  box-shadow: var(--sh-sm); overflow: hidden;
  transition: transform var(--dur) var(--ease), opacity var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease);
}
.stat-card--primary { background: var(--stp-grad-primary); }
.stat-card--accent  { background: var(--stp-grad-accent); }
.stat-card--cool    { background: var(--stp-grad-cool); }
.stat-card--warm    { background: var(--stp-grad-warm); }
.stat-card--pink    { background: var(--stp-grad-pink); }
.stat-card--green   { background: var(--stp-grad-green); }
.stat-card--plain {
  background: color-mix(in srgb, var(--stp-card) 72%, transparent);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--stp-border); color: var(--stp-text);
}
button.stat-card { cursor: pointer; }
button.stat-card:hover { box-shadow: var(--sh-md); }
button.stat-card:active { transform: scale(.97); opacity: .92; }
.stat-card__head { display: flex; align-items: center; justify-content: space-between; }
.stat-card__glyph {
  width: 34px; height: 34px; border-radius: var(--r-icon);
  display: grid; place-items: center; background: rgb(255 255 255 / .22);
}
.stat-card--plain .stat-card__glyph { background: var(--wash); color: var(--stp-primary-text); }
.stat-card__chev { opacity: .85; }
.stat-card__value {
  font-family: var(--font-mono); font-variant-numeric: tabular-nums;
  font-weight: 500; font-size: var(--fs-title1); letter-spacing: -.02em; line-height: 1.1;
}
.stat-card__label { font-size: var(--fs-body-md); font-weight: 600; }
/* Sin opacidad sobre degradado: a 13px esto es texto normal (4.5:1) y un
   .82 de opacidad tumbaba hasta el degradado insignia (4.99 → 4.36). El aire
   visual lo da el peso, no la transparencia. */
.stat-card__sub { font-size: var(--fs-body-sm); font-weight: 400; }
.stat-card--plain .stat-card__sub { opacity: 1; color: var(--stp-muted); }

/* ── Fila de lista ────────────────────────────────────────────────────────── */
.list { display: flex; flex-direction: column; gap: var(--sp-2); }
.list--flush { gap: 0; }
.list--flush .row { border-radius: 0; border-width: 0 0 1px; }
.list--flush .row:last-child { border-bottom-width: 0; }

.row {
  display: flex; align-items: center; gap: var(--sp-3);
  width: 100%; text-align: left;
  padding: var(--sp-3); border-radius: var(--r-card);
  background: color-mix(in srgb, var(--stp-card) 72%, transparent);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--stp-border);
  color: inherit;
  transition: transform var(--dur) var(--ease), opacity var(--dur) var(--ease),
              background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .row { background: var(--stp-card); }
}
button.row, a.row { cursor: pointer; }
button.row:hover, a.row:hover { background-color: var(--wash); }
button.row:active, a.row:active { transform: scale(.97); opacity: .92; }
.row[aria-selected="true"], .row.is-selected {
  border-color: var(--stp-primary);
  background-color: color-mix(in srgb, var(--stp-primary) 10%, transparent);
}
.row__icon {
  width: 40px; height: 40px; flex: none; border-radius: var(--r-icon);
  display: grid; place-items: center; color: #fff;
  font-family: var(--font-display); font-weight: 700; font-size: var(--fs-headline);
  background: var(--row-color, var(--stp-primary));
}
.row__icon--sm { width: 30px; height: 30px; font-size: var(--fs-body-sm); }
.row__body { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 2px; }
.row__title { font-size: var(--fs-headline); font-weight: 600; letter-spacing: -.01em;
              overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.row__meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1);
             font-size: var(--fs-body-sm); color: var(--stp-muted); }
.row__meta > * { display: inline-flex; align-items: center; gap: 4px; }
.row__sep { opacity: .55; }
.row__tail { display: flex; flex-direction: column; align-items: flex-end; gap: var(--sp-1); flex: none; }
.row__amount { font-family: var(--font-mono); font-variant-numeric: tabular-nums;
               font-weight: 500; font-size: var(--fs-headline); }
.row__chev { color: var(--stp-muted); flex: none; }

/* Fila de métrica (clave/valor) */
.metric-row {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-3) 0; border-bottom: 1px solid var(--stp-border);
}
.metric-row:last-child { border-bottom: 0; }
.metric-row__label { font-size: var(--fs-body-md); color: var(--stp-text-soft); }
.metric-row__value { font-family: var(--font-mono); font-variant-numeric: tabular-nums;
                     font-weight: 500; font-size: var(--fs-body-md); }

/* ── Badges de estado ─────────────────────────────────────────────────────── */
.badge {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px var(--sp-2); border-radius: var(--r-icon);
  font-size: var(--fs-label); font-weight: 600; letter-spacing: .01em;
  border: 1px solid transparent; white-space: nowrap;
}
.badge--activa {
  color: var(--stp-success-text);
  background: color-mix(in srgb, var(--stp-success) 14%, transparent);
  border-color: color-mix(in srgb, var(--stp-success) 30%, transparent);
}
.badge--pausada {
  color: var(--stp-warning-text);
  background: color-mix(in srgb, var(--stp-warning) 16%, transparent);
  border-color: color-mix(in srgb, var(--stp-warning) 32%, transparent);
}
.badge--cancelada {
  color: var(--stp-muted);
  background: color-mix(in srgb, var(--stp-muted) 14%, transparent);
  border-color: color-mix(in srgb, var(--stp-muted) 28%, transparent);
}
.badge--info {
  color: var(--stp-info-text);
  background: color-mix(in srgb, var(--stp-info) 14%, transparent);
  border-color: color-mix(in srgb, var(--stp-info) 30%, transparent);
}
.badge--brand {
  color: var(--stp-primary-text);
  background: color-mix(in srgb, var(--stp-primary) 14%, transparent);
  border-color: color-mix(in srgb, var(--stp-primary) 30%, transparent);
}
.badge--demo {
  color: var(--stp-muted);
  background: color-mix(in srgb, var(--stp-muted) 12%, transparent);
  border-color: color-mix(in srgb, var(--stp-muted) 26%, transparent);
  text-transform: uppercase; letter-spacing: .06em;
}

/* ── Botones ──────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  padding: 10px var(--sp-4); border-radius: var(--r-ctrl);
  font-size: var(--fs-body-md); font-weight: 600; line-height: 1.2;
  border: 1px solid transparent; background: transparent; cursor: pointer;
  transition: transform var(--dur) var(--ease), opacity var(--dur) var(--ease),
              background var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.btn:active { transform: scale(.97); opacity: .92; }
.btn:disabled { opacity: .45; cursor: not-allowed; transform: none; }
.btn--primary {
  background: var(--stp-grad-primary); color: var(--stp-on-brand);
  box-shadow: var(--sh-glow);
}
.btn--primary:hover { box-shadow: var(--sh-glow), var(--sh-md); }
.btn--secondary {
  background: color-mix(in srgb, var(--stp-card) 72%, transparent);
  border-color: var(--stp-border); color: var(--stp-text);
}
.btn--secondary:hover { background-color: var(--wash); }
.btn--ghost { color: var(--stp-primary-text); }
.btn--ghost:hover { background-color: var(--wash); }
.btn--danger {
  color: var(--stp-error);
  background: color-mix(in srgb, var(--stp-error) 12%, transparent);
  border-color: color-mix(in srgb, var(--stp-error) 30%, transparent);
}
.btn--danger:hover { background: color-mix(in srgb, var(--stp-error) 20%, transparent); }
.btn--block { width: 100%; }
.btn--sm { padding: 6px var(--sp-3); font-size: var(--fs-body-sm); }
.btn--icon { padding: 8px; border-radius: var(--r-ctrl); }

/* Acceso rápido (rejilla del Dashboard) */
.quick {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-2);
  padding: var(--sp-4) var(--sp-2); border-radius: var(--r-card);
  background: color-mix(in srgb, var(--stp-card) 72%, transparent);
  border: 1px solid var(--stp-border);
  font-size: var(--fs-body-sm); font-weight: 600; text-align: center; cursor: pointer;
  transition: transform var(--dur) var(--ease), opacity var(--dur) var(--ease),
              background var(--dur) var(--ease);
}
.quick:hover { background-color: var(--wash); }
.quick:active { transform: scale(.97); opacity: .92; }
.quick .icon { color: var(--stp-primary-text); width: 22px; height: 22px; }

/* ── Chips / segmentado (filtros) ─────────────────────────────────────────── */
.chips { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.chips--scroll { flex-wrap: nowrap; overflow-x: auto; padding-bottom: var(--sp-1);
                 scrollbar-width: none; }
.chips--scroll::-webkit-scrollbar { display: none; }
.chip {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: 7px var(--sp-3); border-radius: var(--r-pill);
  font-size: var(--fs-body-sm); font-weight: 600; white-space: nowrap;
  background: color-mix(in srgb, var(--stp-muted) 12%, transparent);
  border: 1px solid transparent; color: var(--stp-text-soft); cursor: pointer;
  transition: transform var(--dur) var(--ease), background var(--dur) var(--ease),
              color var(--dur) var(--ease);
}
.chip:hover { background: var(--wash); }
.chip:active { transform: scale(.97); }
.chip[aria-pressed="true"], .chip.is-on {
  background: var(--stp-grad-primary); color: var(--stp-on-brand);
}
.segmented {
  display: inline-flex; gap: var(--sp-1); padding: var(--sp-1);
  border-radius: var(--r-pill); background: color-mix(in srgb, var(--stp-muted) 10%, transparent);
  border: 1px solid var(--stp-border);
}
.segmented .chip { background: transparent; border: 0; }
.segmented .chip[aria-pressed="true"] { background: var(--stp-grad-primary); }

/* ── Formularios ──────────────────────────────────────────────────────────── */
.field { display: flex; flex-direction: column; gap: var(--sp-2); }
.field__label { font-size: var(--fs-body-sm); font-weight: 600; color: var(--stp-text-soft); }
.field__hint  { font-size: var(--fs-caption); color: var(--stp-muted); }
.field__error { font-size: var(--fs-caption); color: var(--stp-error); font-weight: 600; }
.field.is-invalid .input, .field.is-invalid .select { border-color: var(--stp-error); }

.input, .select, .textarea {
  width: 100%; padding: 10px var(--sp-3); border-radius: var(--r-ctrl);
  background: var(--stp-card); color: var(--stp-text);
  border: 1px solid var(--stp-border);
  font-family: inherit; font-size: var(--fs-body-md);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.input::placeholder, .textarea::placeholder { color: var(--stp-muted); }
.input:focus, .select:focus, .textarea:focus {
  outline: none; border-color: var(--stp-primary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--stp-primary) 22%, transparent);
}
.input--mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
.textarea { min-height: 90px; resize: vertical; }
.select {
  appearance: none; -webkit-appearance: none; padding-right: var(--sp-8);
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 18px) 50%, calc(100% - 13px) 50%;
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat;
}
.search {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: 9px var(--sp-3); border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--stp-muted) 10%, transparent);
  border: 1px solid var(--stp-border);
}
.search .icon { color: var(--stp-muted); }
.search input {
  flex: 1; min-width: 0; border: 0; background: transparent; outline: none;
  font: inherit; color: inherit;
}

/* Toggle */
.toggle-row {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-3) 0; border-bottom: 1px solid var(--stp-border);
}
.toggle-row:last-child { border-bottom: 0; }
.toggle-row__text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.toggle-row__text strong { font-size: var(--fs-body-md); font-weight: 600; }
.toggle-row__text small { font-size: var(--fs-caption); color: var(--stp-muted); }
.toggle { position: relative; flex: none; width: 48px; height: 28px; cursor: pointer; }
.toggle input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; }
.toggle__track {
  display: block; width: 48px; height: 28px; border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--stp-muted) 35%, transparent);
  transition: background var(--dur) var(--ease);
}
.toggle__track::after {
  content: ''; position: absolute; top: 3px; left: 3px;
  width: 22px; height: 22px; border-radius: var(--r-pill);
  background: #fff; box-shadow: var(--sh-sm);
  transition: transform var(--dur) var(--ease);
}
.toggle input:checked + .toggle__track { background: var(--stp-primary); }
.toggle input:checked + .toggle__track::after { transform: translateX(20px); }
.toggle input:focus-visible + .toggle__track {
  outline: 2px solid var(--stp-primary); outline-offset: 2px;
}

/* Muestra de color (formulario de suscripción) */
.swatches { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.swatch {
  width: 30px; height: 30px; border-radius: var(--r-icon); cursor: pointer;
  border: 2px solid transparent; background: var(--sw, var(--stp-primary));
  transition: transform var(--dur) var(--ease);
}
.swatch:active { transform: scale(.9); }
.swatch[aria-pressed="true"] { border-color: var(--stp-text); }

/* ── Split pane [lista | detalle] ─────────────────────────────────────────── */
.split { display: block; }
.split__list { min-width: 0; }
.split__detail { display: none; min-width: 0; }
@media (min-width: 900px) {
  .split { display: grid; grid-template-columns: var(--w-list) minmax(0, 1fr);
           gap: var(--sp-5); align-items: start; }
  .split__detail { display: block; }
  .split--stacked { display: block; }
}
.split__divider { display: none; }
@media (min-width: 900px) {
  .split--ruled { grid-template-columns: var(--w-list) 1px minmax(0, 1fr); }
  .split--ruled .split__divider { display: block; background: var(--stp-border);
                                   align-self: stretch; min-height: 200px; }
}

/* ── Drawer (lateral 380px / inferior en móvil) ───────────────────────────── */
.overlay-root { position: relative; z-index: 60; }
.scrim {
  position: fixed; inset: 0; background: rgb(10 8 20 / .45);
  opacity: 0; transition: opacity var(--dur) var(--ease);
}
.scrim.is-open { opacity: 1; }

.drawer { position: fixed; inset: 0; display: flex; pointer-events: none; }
.drawer__panel {
  pointer-events: auto; position: absolute;
  display: flex; flex-direction: column;
  /* Superficie modal: 92% en vez del 84% de .glass-elevated. Sobre un scrim y
     contenido arbitrario, el 84% dejaba pasar demasiado color de fondo. */
  background: color-mix(in srgb, var(--stp-card) 92%, transparent);
  backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px);
  border: 1px solid var(--stp-border);
  box-shadow: var(--sh-lg);
  transition: transform var(--dur) var(--ease);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .drawer__panel { background: var(--stp-card); }
}
/* Móvil (<900px): hoja inferior. */
.drawer__panel {
  left: 0; right: 0; bottom: 0; max-height: 88vh;
  border-radius: var(--r-card) var(--r-card) 0 0;
  transform: translateY(100%);
  padding-bottom: env(safe-area-inset-bottom);
}
.drawer.is-open .drawer__panel { transform: translateY(0); }
@media (min-width: 900px) {
  .drawer__panel {
    left: auto; top: 0; right: 0; bottom: 0; width: min(420px, 92vw); max-height: none;
    border-radius: var(--r-card) 0 0 var(--r-card);
    transform: translateX(100%);
  }
  .drawer.is-open .drawer__panel { transform: translateX(0); }
  /* Editor = inspector de 380px (espejo del .inspector de iPad/Mac) */
  .drawer--editor .drawer__panel { width: min(380px, 92vw); }
}
.drawer__grab {
  width: 38px; height: 4px; border-radius: var(--r-pill); margin: var(--sp-2) auto 0;
  background: color-mix(in srgb, var(--stp-muted) 40%, transparent);
}
@media (min-width: 900px) { .drawer__grab { display: none; } }
.drawer__head {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-4); border-bottom: 1px solid var(--stp-border);
}
.drawer__title { font-family: var(--font-display); font-size: var(--fs-title3);
                 font-weight: 600; flex: 1; min-width: 0; }
.drawer__body { padding: var(--sp-4); overflow-y: auto; flex: 1;
                display: flex; flex-direction: column; gap: var(--sp-4); }
.drawer__foot {
  display: flex; gap: var(--sp-2); padding: var(--sp-4);
  border-top: 1px solid var(--stp-border);
}
.drawer__foot .btn { flex: 1; }

/* ── Diálogo de confirmación ──────────────────────────────────────────────── */
.dialog { position: fixed; inset: 0; display: grid; place-items: center;
          padding: var(--sp-4); pointer-events: none; }
.dialog__panel {
  pointer-events: auto; width: min(400px, 100%);
  background: color-mix(in srgb, var(--stp-card) 92%, transparent);
  backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px);
  border: 1px solid var(--stp-border); border-radius: var(--r-card);
  box-shadow: var(--sh-lg); padding: var(--sp-5);
  display: flex; flex-direction: column; gap: var(--sp-3);
  transform: scale(.96); opacity: 0;
  transition: transform var(--dur) var(--ease), opacity var(--dur) var(--ease);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .dialog__panel { background: var(--stp-card); }
}
.dialog.is-open .dialog__panel { transform: scale(1); opacity: 1; }
.dialog__title { font-family: var(--font-display); font-size: var(--fs-title3); font-weight: 600; }
.dialog__body { font-size: var(--fs-body-md); color: var(--stp-text-soft); }
.dialog__actions { display: flex; gap: var(--sp-2); margin-top: var(--sp-2); }
.dialog__actions .btn { flex: 1; }

/* ── Toast ────────────────────────────────────────────────────────────────── */
.toast-root {
  position: fixed; z-index: 90; left: 50%; transform: translateX(-50%);
  bottom: calc(var(--tabbar-h) + var(--sp-5) + env(safe-area-inset-bottom));
  display: flex; flex-direction: column; gap: var(--sp-2);
  width: min(420px, calc(100vw - var(--sp-8))); pointer-events: none;
}
/* Centrado también en escritorio: abajo a la derecha chocaba con el drawer. */
@media (min-width: 900px) { .toast-root { bottom: var(--sp-6); } }
.toast {
  pointer-events: auto; display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4); border-radius: var(--r-ctrl);
  background: color-mix(in srgb, var(--stp-card) 92%, transparent);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  border: 1px solid var(--stp-border); box-shadow: var(--sh-md);
  font-size: var(--fs-body-sm); font-weight: 500;
  opacity: 0; transform: translateY(8px);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .toast { background: var(--stp-card); }
}
.toast.is-open { opacity: 1; transform: translateY(0); }
.toast--success { border-color: color-mix(in srgb, var(--stp-success) 45%, transparent); }
.toast--success .icon { color: var(--stp-success); }
.toast--error { border-color: color-mix(in srgb, var(--stp-error) 45%, transparent); }
.toast--error .icon { color: var(--stp-error); }
.toast--info .icon { color: var(--stp-info); }

/* ── Estado vacío ─────────────────────────────────────────────────────────── */
.empty {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-3);
  padding: var(--sp-10) var(--sp-4); text-align: center;
  border-radius: var(--r-card); border: 1px dashed var(--stp-border);
  background: color-mix(in srgb, var(--stp-card) 50%, transparent);
}
.empty__glyph {
  width: 48px; height: 48px; border-radius: var(--r-icon);
  display: grid; place-items: center;
  background: var(--wash); color: var(--stp-primary-text);
}
.empty__title { font-family: var(--font-display); font-size: var(--fs-title3); font-weight: 600; }
.empty__body { font-size: var(--fs-body-sm); color: var(--stp-muted); max-width: 44ch; }
.empty__actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); justify-content: center; }

/* ── Gráficos SVG (los dibuja ui.js) ──────────────────────────────────────── */
.chart { display: block; width: 100%; height: auto; overflow: visible; }
.chart-donut { max-width: 280px; margin: 0 auto; }
.donut__track { fill: none; stroke: color-mix(in srgb, var(--stp-muted) 16%, transparent); }
.donut__seg {
  fill: none; stroke-linecap: butt; cursor: pointer;
  transition: opacity var(--dur) var(--ease), stroke-width var(--dur) var(--ease);
}
.donut__seg:hover, .donut__seg.is-active { opacity: .82; stroke-width: 26; }
.donut__center-label { fill: var(--stp-muted); font-family: var(--font-body);
                       font-size: var(--fs-body-sm); text-anchor: middle; }
.donut__center-value { fill: var(--stp-text); font-family: var(--font-mono);
                       font-variant-numeric: tabular-nums; font-weight: 500;
                       font-size: var(--fs-title2); text-anchor: middle; }
.legend { display: flex; flex-direction: column; gap: var(--sp-1); margin-top: var(--sp-4); }
.legend__item {
  display: flex; align-items: center; gap: var(--sp-2); width: 100%;
  padding: var(--sp-2); border-radius: var(--r-ctrl); border: 0; background: transparent;
  color: inherit; text-align: left; cursor: pointer;
  transition: background var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.legend__item:hover { background: var(--wash); }
.legend__item:active { transform: scale(.97); opacity: .92; }
.legend__dot { width: 10px; height: 10px; flex: none; border-radius: var(--r-pill);
               background: var(--legend-color, var(--stp-primary)); }
.legend__label { flex: 1; min-width: 0; font-size: var(--fs-body-sm);
                 overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.legend__value { font-family: var(--font-mono); font-variant-numeric: tabular-nums;
                 font-size: var(--fs-body-sm); font-weight: 500; }

.chart-bars { width: 100%; }
/* El relleno lo pone ui.js con un id de degradado único por gráfico. */
.bar__rect { transition: opacity var(--dur) var(--ease); }
.bar__rect:hover { opacity: .82; }
.bar__track { fill: color-mix(in srgb, var(--stp-muted) 12%, transparent); }
.bar__label { fill: var(--stp-muted); font-family: var(--font-body);
              font-size: var(--fs-label); text-anchor: middle; }
.bar__value { fill: var(--stp-text); font-family: var(--font-mono);
              font-variant-numeric: tabular-nums; font-size: var(--fs-label);
              font-weight: 500; text-anchor: middle; }
.chart-axis { stroke: var(--stp-border); stroke-width: 1; }

/* Barra de progreso (metas, gamificación) */
.progress { height: 8px; border-radius: var(--r-pill); overflow: hidden;
            background: color-mix(in srgb, var(--stp-muted) 18%, transparent); }
.progress__fill { height: 100%; border-radius: var(--r-pill);
                  background: var(--stp-grad-primary);
                  width: var(--p, 0%); transition: width var(--dur) var(--ease); }

/* ── Movimiento reducido ──────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .pressable:active, .btn:active, .row:active, .chip:active,
  button.stat-card:active, .legend__item:active { transform: none; }
}
