/* ══════════════════════════════════════════════════════════════
   APEX DASHBOARD V3 · TOKENS
   Fuente de verdad de color, espacio, tipografía, radio, sombra
   y movimiento. Derivados de la imagen canónica del cockpit.

   Regla: ningún componente define colores literales. Todo sale
   de acá. El cambio de tema ocurre sólo por reasignación de
   tokens en [data-theme="dark"].
   ══════════════════════════════════════════════════════════════ */

:root{
  /* ── Marca ───────────────────────────────────────────────────
     UN SOLO token de marca en todo V3. El valor sale del logo real:
     es el rojo de la A de Apex, muestreado de `icon-512.png`
     (hue 357°). Todo lo demás que necesite marca deriva de acá.

     Antes esto era naranja (#e8401c) y el naranja se había filtrado
     a siete lugares distintos —acento, serie de gastos, warnings,
     theme-color del navegador, manifest de la PWA, el fallback del
     hero— cada uno con su propio valor. Un token, un color. */
  --apex-red:           #ea0410;   /* el rojo de la A del logo */
  --apex-accent:        var(--apex-red);
  --apex-accent-ink:    #ffffff;
  --apex-accent-soft:   rgba(234,4,16,.10);
  --apex-accent-line:   rgba(234,4,16,.45);

  /* ── Semánticos ──────────────────────────────────────────────
     NINGUNO es cálido, salvo `danger`, que tiene que serlo: el rojo
     de peligro es convención universal y renunciar a él confundiría
     más de lo que ordenaría. Se lo separa de la marca bajándole la
     luminosidad y corriéndolo hacia el carmín, para que "destructivo"
     y "Apex" no se lean como lo mismo.

     `warn` dejó de ser ámbar. Un ámbar al lado de un rojo de marca y
     un rojo de peligro da tres tonos cálidos peleándose por la misma
     atención. Pasa a violeta: es frío, no colisiona con el verde de
     `ok` ni con el azul de `info`, y se lee como "mirá esto" sin
     gritar "error". */
  --ok:        #2faa6a;
  --ok-soft:   rgba(47,170,106,.12);
  --warn:      #6d5fe0;
  --warn-soft: rgba(109,95,224,.13);
  --danger:    #c81432;
  --danger-soft: rgba(200,20,50,.10);
  --info:      #3b82f6;
  --info-soft: rgba(59,130,246,.11);

  /* Series de datos (orden fijo: Ventas, Gastos, Ganancia) */
  --serie-1: #16181c;   /* Ventas   — negro */
  --serie-2: #6d5fe0;   /* Gastos   — violeta (era naranja) */
  --serie-3: #2faa6a;   /* Ganancia — verde */
  --serie-4: #3b82f6;
  --serie-5: #8b93a7;
  --serie-6: #c9ccd4;

  /* ── Superficies (LIGHT) ─────────────────────────────────── */
  --panel:      #ffffff;           /* panel principal flotante */
  --surface:    #ffffff;           /* cards */
  --surface-2:  #f6f6f8;           /* zonas hundidas, thumbs */
  --surface-3:  #eeeff2;           /* hover de fila, tracks */
  --line:       rgba(0,0,0,.085);  /* borde visible */
  --hair:       rgba(0,0,0,.055);  /* separador interno */

  --ink:        #0d0e10;           /* texto principal */
  --ink-2:      #5f6169;           /* secundario */
  --ink-3:      #9294a0;           /* terciario / labels */
  --ink-on-accent: #ffffff;

  /* ── Sidebar (siempre oscura, en ambos temas) ────────────── */
  --sb-bg:        #0b0b0d;
  --sb-ink:       #dcdde1;
  --sb-ink-2:     #85878f;
  --sb-ink-3:     #5d5f67;
  --sb-hover:       rgba(255,255,255,.055);
  --sb-hover-line:  rgba(255,255,255,.08);
  --sb-active:      rgba(255,255,255,.075);
  /* el activo se marca con material: borde blanco translúcido, sin acento */
  --sb-active-line: rgba(255,255,255,.16);
  --sb-hair:        rgba(255,255,255,.07);

  /* ── Liquid glass ────────────────────────────────────────── */
  --glass-bg:     rgba(255,255,255,.66);
  --glass-line:   rgba(255,255,255,.55);
  --glass-blur:   22px;
  --glass-sat:    180%;
  /* variante oscura, para glass sobre fotografía */
  --glass-dark-bg:   rgba(16,16,19,.52);
  --glass-dark-line: rgba(255,255,255,.14);
  /* controles de vidrio sobre foto (buscador, chip de fecha):
     misma receta para que se lean como una sola familia */
  --glass-ctl-bg:    rgba(255,255,255,.09);
  --glass-ctl-line:  rgba(255,255,255,.17);
  --glass-ctl-hi:    rgba(255,255,255,.18);   /* brillo superior interno */
  --glass-ctl-blur:  20px;

  /* ── Fondo ambiental ─────────────────────────────────────── */
  /* Lo asigna app.js con una foto REAL de producto de Apex.
     Hasta que cargue, este degradado es el placeholder. */
  --ambient-image: none;
  --ambient-fallback: radial-gradient(120% 100% at 78% 0%, #1b1d26 0%, #121318 45%, #0c0c0e 100%);
  --ambient-blur: 34px;
  /* El chrome de la app (fondo detrás del panel y placeholder del hero)
     es oscuro en los dos temas: es el marco, no el contenido. */
  /* ── Hero editorial ───────────────────────────────────────
     SLOT: acá va la fotografía definitiva del hero de Inicio.
     app.js prueba cargar `assets/hero.jpg` al arrancar y, si
     existe, la asigna a esta variable. Si no existe, queda el
     degradado de abajo, que está compuesto a propósito para que
     la zona IZQUIERDA quede limpia: ahí va el saludo.
     Ver assets/HERO.md para las especificaciones de la imagen. */
  /* ── Liquid Glass ─────────────────────────────────────────
     El vidrio no es "un rectángulo negro con opacidad". Son cuatro
     cosas juntas: el medio translúcido, el blur que refracta lo de
     atrás, un borde finísimo más claro arriba que abajo (la luz
     pega desde arriba), y un highlight interno de 1px que simula el
     canto del material. Sin las últimas dos se ve plano. */
  /* PREFIJO `lg-` a propósito. Estos tokens son del vidrio del LOGIN
     —oscuro, sobre fotografía— y antes se llamaban `--glass-bg`,
     `--glass-blur` y `--glass-sat`, que son los nombres del vidrio
     general del panel definidos más arriba.

     Como esto viene después en el mismo `:root`, los pisaba: el
     popover de cuenta, la paleta ⌘K y la barra inferior pasaron de
     un vidrio claro al 66% a uno al 5,5%. En modo claro eso deja
     texto gris sobre la fotografía del hero, que es exactamente el
     problema de contraste que apareció en Safari.

     Un token con nombre genérico definido dos veces en el mismo
     scope no es un detalle de estilo: es una colisión silenciosa. */
  --lg-bg:        rgba(255,255,255,.055);
  --lg-bg-fuerte: rgba(255,255,255,.085);
  --lg-borde:     rgba(255,255,255,.12);
  --lg-borde-luz: rgba(255,255,255,.22);
  --lg-highlight: rgba(255,255,255,.10);
  --lg-blur:      36px;
  --lg-sat:       165%;

  /* Login */
  --login-autofill-bg: #17171b;
  --login-error-ink:   #ffadb9;
  --login-ink:         rgba(255,255,255,.94);
  --login-ink-2:       rgba(255,255,255,.62);
  --login-ink-3:       rgba(255,255,255,.40);
  /* Foco del login: blanco/gris frío, sin una gota de color cálido.
     Están como tokens para que no haya forma de escribir un rgba
     naranja suelto en un estado interactivo sin que se note. */
  --login-focus-borde: rgba(255,255,255,.46);
  --login-focus-glow:  rgba(226,232,245,.13);
  /* SLOT: fondo de la pantalla de acceso. Lo asigna apariencia.js
     con la imagen configurada; si no hay ninguna, queda el fallback. */
  --login-image: none;
  --login-fallback:
    radial-gradient(120% 100% at 76% 8%, rgba(120,132,168,.26) 0%, rgba(120,132,168,0) 55%),
    radial-gradient(90% 120% at 22% 96%, rgba(40,44,60,.55) 0%, rgba(40,44,60,0) 62%),
    linear-gradient(168deg, #0a0a0c 0%, #101016 46%, #16161d 74%, #0d0d11 100%);

  --hero-image: none;
  /* Sin el halo naranja que tenía antes. El degradado ahora es frío
     y neutro: cuando haya una fotografía cargada esto no se ve, y
     mientras tanto no impone un color que ya no es el de la marca. */
  --hero-fallback:
    radial-gradient(140% 120% at 88% 18%, rgba(104,118,158,.30) 0%, rgba(104,118,158,0) 52%),
    radial-gradient(90% 140% at 72% 92%, rgba(60,72,110,.40) 0%, rgba(60,72,110,0) 60%),
    linear-gradient(104deg, #0b0b0d 0%, #101014 38%, #17171d 62%, #23232c 100%);

  --shell-bg:  #0c0c0e;
  --hero-bg:   #17171a;
  --avatar-g1: #3a3c44;
  --avatar-g2: #1b1c20;
  --ambient-dim: .52;

  /* ── Espaciado (escala de 4) ─────────────────────────────── */
  --sp-1:4px; --sp-2:6px; --sp-3:8px; --sp-4:10px; --sp-5:12px;
  --sp-6:16px; --sp-7:20px; --sp-8:24px; --sp-9:32px; --sp-10:40px;
  --sp-11:48px; --sp-12:64px;

  /* ── Radios ──────────────────────────────────────────────── */
  --r-xs:7px; --r-sm:10px; --r-md:13px; --r-lg:16px; --r-xl:20px; --r-2xl:24px;
  --r-full:999px;

  /* ── Sombras ─────────────────────────────────────────────── */
  --sh-1: 0 1px 2px rgba(0,0,0,.05);
  --sh-2: 0 1px 2px rgba(0,0,0,.04), 0 6px 18px -10px rgba(0,0,0,.16);
  --sh-3: 0 2px 6px rgba(0,0,0,.05), 0 18px 44px -20px rgba(0,0,0,.26);
  --sh-panel: 0 30px 80px -30px rgba(0,0,0,.55);

  /* ── Tipografía ──────────────────────────────────────────── */
  --font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display",
          "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-num: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;

  --fs-display: 30px;  /* saludo del cockpit */
  --fs-h1:      21px;  /* título de pantalla */
  --fs-kpi:     27px;  /* número KPI */
  --fs-metric:  19px;  /* número métrica operacional */
  --fs-h2:      15px;  /* título de card */
  --fs-body:    13.5px;
  --fs-sm:      12.5px;
  --fs-xs:      11.5px;
  --fs-2xs:     10.5px; /* labels de grupo, uppercase */

  /* ── Tamaño de los campos de formulario ──────────────────────
     CAUSA RAÍZ DEL BUG DE ESCALA EN iOS. iOS Safari hace zoom sobre
     la página entera al enfocar cualquier `input`, `select` o
     `textarea` cuyo `font-size` sea MENOR a 16px. No es configurable
     y no avisa.

     Todos los campos del panel usaban `--fs-sm` (12,5px) o
     `--fs-body` (13,5px). O sea: tocar el buscador de Stock, un
     filtro, o el login, zoomeaba la app. Y como V3 es una SPA que no
     recarga nunca, Safari CONSERVA esa escala al navegar a cualquier
     otra pantalla. De ahí que Marketplace → Publicar apareciera
     ampliado sin tener un solo campo de texto.

     Este token es el único lugar donde se decide: en escritorio el
     tamaño chico de siempre; en pantallas táctiles, 16px. No se
     bloquea el zoom del usuario —eso es accesibilidad— se le saca a
     Safari el motivo para aplicarlo. */
  --fs-input:   var(--fs-sm);
  /* El campo de la paleta de búsqueda es grande y protagonista: en
     escritorio no puede usar el tamaño de un filtro. Sigue el mismo
     mínimo táctil que el resto. */
  --fs-input-grande: 15px;

  --lh-tight: 1.15;
  --lh:       1.45;
  --ls-display: -.032em;
  --ls-num:     -.022em;
  --ls-label:   .12em;

  --fw-regular:400; --fw-medium:500; --fw-semi:600; --fw-bold:680;

  /* ── Movimiento ──────────────────────────────────────────── */
  --dur-fast: 180ms;
  --dur:      220ms;
  --dur-slow: 260ms;
  --ease:     cubic-bezier(.22,1,.36,1);
  /* `--ease-out` lo usan dos animaciones de entrada (la card del login
     y el cartel de error) y NO estaba definido. Un `var()` sin valor y
     sin fallback invalida la declaración entera: las dos animaciones
     simplemente no corrían. El elemento quedaba bien igual —por eso
     nadie lo vio—, pero la entrada no existía.

     Se define como alias de `--ease`, que ya es una curva de salida y
     es la que usa todo el sistema. No se inventa una curva nueva: eso
     sería una decisión de diseño, y acá sólo falta el token. */
  --ease-out: var(--ease);
  /* Alto de la bottom nav en el teléfono. Lo usaba `.pop` con un
     fallback de 64px y nadie lo definía, así que el fallback era el
     valor real. Queda explícito, con el mismo número: el resultado
     computado no cambia. */
  --bottomnav-h: 64px;

  /* ── Layout ──────────────────────────────────────────────── */
  --sidebar-w:  186px;
  --panel-gap:  8px;
  --topbar-h:   58px;
  --hero-h:     148px;           /* alto de la franja de saludo, expandida */
  --content-max: 1560px;

  /* Contextual Collapsing Header
     --hp: progreso de colapso 0→1. Lo escribe patterns.js sobre .panel
     leyendo el scroll del contenido. Todo el colapso se deriva de acá. */
  --hp: 0;
  --header-collapse-distance: 120px;  /* px de scroll para completar el colapso */
  --logo-h: 46px;

  /* ── Iconografía ─────────────────────────────────────────── */
  --icon:        18px;
  --icon-sm:     15px;
  --icon-stroke: 1.6;
}

/* ══════════════════════════════════════════════════════════════
   DARK — sólo se reasignan tokens. Ningún componente se duplica.
   La sidebar ya es oscura en light, así que casi no cambia:
   se hunde un paso más para mantener la separación con el panel.
   ══════════════════════════════════════════════════════════════ */
[data-theme="dark"]{
  --panel:      #141517;
  --surface:    #191a1e;
  --surface-2:  #1f2126;
  --surface-3:  #26282e;
  --line:       rgba(255,255,255,.10);
  --hair:       rgba(255,255,255,.065);

  --ink:        #f1f2f4;
  --ink-2:      #a2a4ac;
  --ink-3:      #6f717a;

  --sb-bg:      #08080a;
  --sb-hair:    rgba(255,255,255,.06);

  /* El rojo de marca sube de luminosidad sobre fondo oscuro: el
     #ea0410 puro se apaga contra el negro. Sigue siendo el mismo
     tono (hue 357°), no otro color. */
  --apex-red:         #ff2733;
  --apex-accent:      var(--apex-red);
  --apex-accent-soft: rgba(255,39,51,.14);
  --apex-accent-line: rgba(255,39,51,.5);

  --ok:        #43b97c;
  --ok-soft:   rgba(67,185,124,.14);
  --warn:      #8b7ff5;
  --warn-soft: rgba(139,127,245,.16);
  --danger:    #f2465f;
  --danger-soft: rgba(242,70,95,.14);
  --info:      #5b95f7;
  --info-soft: rgba(91,149,247,.15);

  --serie-1: #e8eaee;
  --serie-2: #8b7ff5;
  --serie-3: #43b97c;

  --glass-bg:   rgba(25,26,30,.62);
  --glass-line: rgba(255,255,255,.10);

  --ambient-dim: .68;

  --sh-2: 0 1px 2px rgba(0,0,0,.5), 0 8px 22px -12px rgba(0,0,0,.7);
  --sh-3: 0 2px 8px rgba(0,0,0,.5), 0 20px 50px -22px rgba(0,0,0,.85);
  --sh-panel: 0 30px 80px -30px rgba(0,0,0,.9);
}

/* ══════════════════════════════════════════════════════════════
   CAMPOS EN PANTALLAS TÁCTILES
   16px es el mínimo que iOS Safari no castiga con zoom automático.
   Va como token y no regla por regla para que no pueda volver a
   quedar un campo afuera.
   ══════════════════════════════════════════════════════════════ */
@media (max-width:860px){
  :root{
    --fs-input: 16px;
    --fs-input-grande: 16px;
  }
}

/* ══════════════════════════════════════════════════════════════
   NÚMERO GRANDE CUANDO LA TARJETA ES ANGOSTA
   27px es la medida del número de KPI en una tarjeta de 300px o más.
   Con la fila de KPI a dos columnas, la tarjeta mide (ancho − 42) / 2,
   y el número deja de entrar al lado del sparkline bastante antes de
   lo que parece. Medido con el peor monto realista:

     ancho   tarjeta   espacio para el número   27px (hasta 188px)
      440      199              97px            no entra
      600      279             177px            no entra
      640      299             197px            entra

   O sea que el límite real es 640, no 430. Esto estaba en
   `max-width:430px` y por eso NO entraba en el iPhone de Seba, que
   reporta 440px de viewport CSS: la tarjeta quedaba con el número a
   27px en 97px de ancho y, como `money()` devuelve «$ 20.000» con
   espacio, el renglón se partía en dos: el «$» arriba y los dígitos
   abajo, con `line-height:1`.

   22px sigue siendo por lejos el elemento más grande de la tarjeta y
   el primero que se lee: la jerarquía no cambia, cambia la escala. Va
   como token para que lo apliquen por igual el KPI de Inicio, el
   resumen de Stock y el número de la ficha, y no haya tres tamaños
   distintos de «número grande» en la misma pantalla.

   640 además ya existía como breakpoint en components.css: no se
   agrega un escalón nuevo al sistema.
   ══════════════════════════════════════════════════════════════ */
@media (max-width:640px){
  :root{ --fs-kpi: 22px; }
}

/* ══════════════════════════════════════════════════════════════
   SELLO DE VERSIÓN DE CADA HOJA — SÓLO INSTRUMENTACIÓN
   ──────────────────────────────────────────────────────────────
   No tiene ningún efecto visual. Existe para responder una sola
   pregunta, que ya nos costó dos rondas de validación: ¿el navegador
   está ejecutando la hoja que acabo de escribir, o una versión
   cacheada?

   Hace falta una por archivo: si la vieja es `components.css` y
   `tokens.css` es nueva, un sello único no lo detectaría. El panel de
   diagnóstico las lee y las muestra.

   Se sube la etiqueta cuando una ronda cambia esa hoja. Es manual a
   propósito: no hay proceso de build acá, y un sello que se actualiza
   solo no distingue «lo serví» de «lo recibí».
   ══════════════════════════════════════════════════════════════ */
:root{ --build-tokens: cierre-2; }
