/* =============================================================================
   tokens.css — EL CONTRATO COMÚN
   -----------------------------------------------------------------------------
   Este archivo NO pinta nada. Declara qué variables DEBE definir todo tema.
   Los valores de aquí son un fallback neutro: si nadie setea [data-theme],
   la app se ve gris pero íntegra y accesible.

   REGLAS DEL CONTRATO (no negociables):
     1. Nombres SEMÁNTICOS, por ROL. Nunca por matiz.
        --surface-page  ✅      --color-white ❌ (miente al cambiar de tema)
        --accent        ✅      --em-purple   ❌ (fósil real de Execution Market:
                                 landing/styles.css:16 se llama --em-purple y vale #111111)
     2. Ningún componente escribe un color literal. Solo var(--token).
        Ni siquiera en style={{}} — un inline style esquiva el tema entero.
     3. Cuatro combinaciones válidas: 2 temas × claro/oscuro. Todo token existe
        en las cuatro. Los ratios AA están calculados, no estimados, y anotados
        en cada archivo de tema.
     4. "SIN DATOS" ≠ "SCORE CERO". La diferencia es ESTRUCTURAL, no cromática
        (ver bloque DOMINIO / SIN DATOS abajo). Así sobrevive al cambio de piel,
        al modo oscuro, a la impresión en B&W y al daltonismo.

   Uso:
     <link rel="stylesheet" href="tokens.css">
     <link rel="stylesheet" href="theme-describeme.css">
     <link rel="stylesheet" href="theme-execution-market.css">
     <html data-theme="describeme" data-mode="light">
   ============================================================================= */

:root {
  /* ===========================================================================
     ROL: SUPERFICIES
     El lienzo. `page` es el fondo del documento; `raised` es todo lo que flota
     encima (tarjeta, fila, panel); `sunken` es lo que se hunde (track de barra,
     cabecera de tabla, input). `inverse` es tinta sólida — el chip protagonista
     y el botón primario, que en cada tema se resuelven invirtiendo la página.
     ======================================================================== */
  --surface-page: #ffffff;
  --surface-raised: #ffffff;
  --surface-sunken: #f4f4f5;
  --surface-inverse: #18181b;      /* fondo de chip "fill" / botón primario */
  --surface-accent-soft: #f4f4f5;  /* lavado del acento: panel informativo */
  --surface-overlay: rgb(0 0 0 / 0.55); /* scrim de modal */

  /* ===========================================================================
     ROL: TEXTO — tres niveles, no más.
     primary   = lo que se lee (títulos, valores)
     secondary = lo que acompaña (descripciones, prosa de apoyo)
     tertiary  = metadata (timestamps, contadores, micro-labels)
     Los tres cumplen AA 4.5:1 contra page, raised Y sunken. `tertiary` se usa
     a 10-11px, así que NO se le baja el contraste "porque es chiquito".
     ======================================================================== */
  --text-primary: #09090b;
  --text-secondary: #3f3f46;
  --text-tertiary: #6e6e77;
  --text-on-inverse: #fafafa;   /* sobre --surface-inverse */
  --text-on-accent: #ffffff;    /* sobre --accent */
  --text-on-action: #fafafa;    /* sobre --action */
  --text-link: #09090b;
  --text-link-hover: #000000;

  /* ===========================================================================
     ROL: LÍNEAS
     subtle = hairline decorativo, divide sin significar (sin requisito AA).
     strong = límite de un componente o de un control → AA 3:1 obligatorio.
     absent = el trazo PUNTEADO de "todavía no". Es un token semántico:
              punteado SIEMPRE significa ausencia, nunca decoración.
     ======================================================================== */
  --border-subtle: #e4e4e7;
  --border-strong: #8a8a94;
  --border-absent: #8a8a94;
  --border-absent-style: dashed;
  --border-width: 1px;
  --border-width-emphasis: 2px;   /* énfasis fuerte sin recurrir al matiz */
  --border-focus: #09090b;

  /* ===========================================================================
     ROL: ACENTO vs ACCIÓN — dos trabajos distintos, jamás el mismo color.
     accent  = ANOTA. Links, barra de cita, dato destacado. No se hace clic.
     action  = SE HACE CLIC. Un solo color de acción en todo el producto.
     Herencia directa: DescribeMe tenía el cian estructural y el lima
     `btn-big-lime` (site.css:114) como único CTA. Ese reparto se conserva.
     ======================================================================== */
  --accent: #3f3f46;
  --accent-hover: #27272a;
  --accent-support: #52525b;      /* segundo acento, subordinado */
  --action: #18181b;
  --action-hover: #000000;
  --action-edge: #18181b;         /* borde del control: AA 3:1 contra la página,
                                     obligatorio cuando el relleno es claro */

  /* ===========================================================================
     ROL: ESTADOS
     Semánticos, nunca nombrados por color. Cada uno trae su par tinta/superficie.
     Regla heredada de Execution Market (globals.css:454): la dirección la carga
     un GLIFO (flecha, check, guion), el color solo refuerza. Un estado nunca
     depende únicamente del matiz.
     ======================================================================== */
  --state-positive: #3f3f46;
  --state-positive-surface: #f4f4f5;
  --state-caution: #52525b;
  --state-caution-surface: #f4f4f5;
  --state-critical: #18181b;
  --state-critical-surface: #e4e4e7;
  --state-neutral: #6e6e77;
  --state-neutral-surface: #f4f4f5;

  /* ===========================================================================
     ROL: CARGA Y FRESCURA
     Un dashboard de reputación lee de varias cadenas: casi siempre hay algo
     cargando y algo viejo. Son DOS estados distintos y no se confunden:
       CARGANDO  → skeleton con la FORMA del contenido final. Nunca un spinner
                   centrado que borra el layout, y nunca sobre datos ya visibles.
       VIEJO     → el dato se sigue viendo, con superficie `stale` y su nota
                   ("hace 4 min"). No se atenúa con opacity: eso rompe AA.
     Y ninguno de los dos es "sin datos": eso tiene su propio bloque.
     El sheen es decorativo — no lleva requisito de contraste, pero tampoco
     puede tapar texto (el skeleton nunca convive con el texto que reemplaza).
     ======================================================================== */
  --skeleton-base: #ececee;
  --skeleton-sheen: #f7f7f8;
  --skeleton-duration: 1400ms;
  --surface-stale: #f4f4f5;
  --text-stale: #5c5c64;

  /* ===========================================================================
     DOMINIO: SCORE
     Tres anclas, no diez. La rampa de 10 pasos de DescribeMe
     (quick_rating.js:16) se interpola entre estas tres en tiempo de ejecución.
     Las anclas varían en TONO **y** en LUMINANCIA: así el score se lee sin
     percibir color (impresión B&W, daltonismo, piel monocroma).
     `--score-track` es la pista vacía; `--score-fill-neutral` es el relleno
     cuando NO se quiere semaforizar (el dashboard de EM hace exactamente eso).
     ======================================================================== */
  --score-low: #8a8a94;     /* 1-3   */
  --score-mid: #6e6e77;     /* 4-7   */
  --score-high: #18181b;    /* 8-10  */
  --score-fill-neutral: #18181b;
  --score-track: #f4f4f5;
  --score-track-border: #8a8a94;   /* AA 3:1 — la pista es un objeto gráfico */
  --score-track-height: 0.5rem;
  --score-scale-max: 100;          /* 0-100, NUNCA estrellas */
  --score-dot-size: 0.75rem;       /* el punto de 10 pasos: círculo, no estrella */
  --score-dot-gap: 0.25rem;

  /* ===========================================================================
     DOMINIO: SIN DATOS  🔴 EL TOKEN MÁS IMPORTANTE DEL ARCHIVO
     -------------------------------------------------------------------------
     "Nadie te calificó todavía" NO se parece a "te calificaron con 0".
     DescribeMe se equivocó acá: el punto sin calificar era #A8C366 (oliva
     pálido, dmrating.css:26) y el score 10 era #487401 (oliva oscuro) — la
     ausencia y la excelencia eran primas cromáticas.

     REGLA (la ejecutan los componentes, la garantizan estos tokens):
       SIN DATOS  → borde `--border-absent-style` (punteado), tinta
                    `--nodata-ink`, glifo `--nodata-glyph` (—), SIN relleno,
                    SIN numeral. Copy: "sin calificar todavía".
       SCORE CERO → borde SÓLIDO `--score-track-border`, pista llena de track,
                    relleno al 0%, y el numeral visible: "0/100".
     Ningún token de --nodata-* toma jamás un valor de la rampa de score.
     ======================================================================== */
  --nodata-ink: #6e6e77;
  --nodata-border: #8a8a94;
  --nodata-surface: transparent;
  --nodata-glyph: "—";
  --nodata-opacity: 1;   /* NO se resuelve bajando opacidad: eso rompe AA */

  /* ===========================================================================
     DOMINIO: FACETAS — 6 categorías fijas (las de DescribeMe)
     PERSONALITY · LOOKS · CAREER · LIFESTYLE · RELATIONSHIPS · SKILLS.
     Uso permitido: punto, subrayado de 2px o borde. Nunca relleno grande.

     🔴 REGLA DE CATEGÓRICAS (vale también para --series-*):
     Seis colores que TODOS deben cumplir 3:1 contra el MISMO fondo quedan
     encerrados en una banda de luminancia estrecha: la separación entre dos
     categorías vecinas no pasa de ~1.3:1. Eso es un techo matemático, no una
     mala elección de paleta. Consecuencia: **el color NO alcanza para
     identificar una categoría.** Toda serie categórica lleva obligatoriamente
     un segundo canal — etiqueta directa, glifo, o patrón de trazo — y la
     paleta se ordena por luminancia para que dos vecinas nunca empaten.
     ======================================================================== */
  --facet-1: #8b8b8b;   /* personality   */
  --facet-2: #787878;   /* looks         */
  --facet-3: #686868;   /* career        */
  --facet-4: #5a5a5a;   /* lifestyle     */
  --facet-5: #484848;   /* relationships */
  --facet-6: #333333;   /* skills        */

  /* ===========================================================================
     DOMINIO: SERIES — escala categórica para gráficos POR CADENA
     describe.net grafica reputación por red (Base, Ethereum, Polygon, …).
     Ocho pasos, ordenados por luminancia descendente, cada uno ≥3:1 contra la
     superficie del lienzo (`--surface-raised`) y contra `--surface-sunken`.
     🔴 Tope duro en 8: más de ocho categorías cromáticas no se leen en ningún
     tema. La novena y siguientes se agregan en "otras" con --series-other.
     Aplica la REGLA DE CATEGÓRICAS de arriba: color + etiqueta, siempre.
     ======================================================================== */
  --series-1: #8b8b8b;
  --series-2: #7b7b7b;
  --series-3: #6e6e6e;
  --series-4: #626262;
  --series-5: #555555;
  --series-6: #4b4b4b;
  --series-7: #3d3d3d;
  --series-8: #303030;
  --series-other: #8a8a94;
  --series-max: 8;               /* pasado este número: agregar, no inventar color */
  --series-stroke-width: 2px;

  /* ===========================================================================
     DOMINIO: TIER — el badge de nivel de reputación
     Cuatro niveles. El primero NO es el peor: es el que todavía no tiene datos,
     y por contrato se dibuja con la gramática de ausencia (borde punteado, sin
     relleno). "Una identidad con 0 reseñas está SIN PROBAR, no está mal"
     — es doctrina literal de Execution Market
     (dashboard/public/skill.md, sección de vetting), acá aplicada al CSS.
     El nivel más alto NO se distingue solo por color: suma
     --border-width-emphasis. El tono es refuerzo.
     ======================================================================== */
  --tier-unproven-ink: #6e6e77;
  --tier-unproven-surface: transparent;   /* + --border-absent-style */
  --tier-low-ink: #3f3f46;
  --tier-low-surface: #f4f4f5;
  --tier-mid-ink: #27272a;
  --tier-mid-surface: #ececee;
  --tier-high-ink: #09090b;
  --tier-high-surface: #e4e4e7;

  /* ===========================================================================
     DOMINIO: IDENTIDAD Y SELLOS
     "Todo lo que representa a una PERSONA o a un JUICIO es un círculo perfecto;
     todo lo que lo contiene es recto." Es la dicotomía más portable que tenía
     DescribeMe (profilesprites.css:1 — sellos de 50px, radio 30px).
     ======================================================================== */
  --seal-size: 3rem;
  --seal-radius: 50%;
  --avatar-radius: 50%;
  --avatar-size: 2.5rem;

  /* ===========================================================================
     TIPOGRAFÍA — cuatro roles, no cuatro gustos.
     body    = prosa de interfaz
     display = títulos
     data    = TODO dato: score, wallet, timestamp, id, chip de estado, código
     voice   = lo que dijo un HUMANO (una cita, un comentario de reseña)
     El reparto body/data viene de Execution Market (tailwind.config.js:157);
     el reparto data/voice viene de DescribeMe, que ya separaba dato de opinión.
     ======================================================================== */
  --font-body: ui-sans-serif, system-ui, sans-serif;
  --font-display: var(--font-body);
  --font-data: ui-monospace, "SF Mono", Menlo, monospace;
  --font-voice: Georgia, "Times New Roman", serif;

  --text-2xs: 0.625rem;   --leading-2xs: 0.875rem;  /* micro-label. AA obligatorio */
  --text-xs: 0.75rem;     --leading-xs: 1rem;
  --text-sm: 0.875rem;    --leading-sm: 1.25rem;
  --text-base: 1rem;      --leading-base: 1.5rem;
  --text-lg: 1.125rem;    --leading-lg: 1.75rem;
  --text-xl: 1.25rem;     --leading-xl: 1.75rem;
  --text-2xl: 1.5rem;     --leading-2xl: 2rem;
  --text-3xl: 1.875rem;   --leading-3xl: 2.25rem;
  --text-4xl: 2.25rem;    --leading-4xl: 2.5rem;
  --text-5xl: 3rem;       --leading-5xl: 1;

  --tracking-label: 0.12em;   /* micro-label en VERSALITAS */
  --tracking-normal: 0;
  --tracking-tight: -0.02em;  /* titulares grandes */

  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-bold: 700;
  --weight-heading: var(--weight-semibold); /* tope de peso para h1-h3 */
  --numeric-figures: tabular-nums;          /* los montos no bailan */

  /* ===========================================================================
     ESPACIADO — base 4px. DescribeMe no tenía escala (.padding-5/-8/-10 con
     !important); esto es invención nuestra, y es correcto que lo sea.
     ======================================================================== */
  --space-0: 0;
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;
  --space-16: 4rem;

  --density-cell: var(--space-3);  /* padding de fila densa (tabla de rasgos) */
  --density-card: var(--space-4);  /* padding de tarjeta */

  /* ===========================================================================
     DOMINIO: TABLA DENSA
     La pantalla central de DescribeMe era una tabla con seis datos por fila
     (ranking · rasgo · promedio · tendencia · cuántos · hace cuánto). La de
     describe.net va a ser peor: se le suma cadena y tier. Necesita tokens
     propios o cada tabla los improvisa.
     Cómo se separan las filas es una decisión de TEMA, no de componente:
     `--table-zebra` puede ser un tinte o `transparent` (y entonces manda la
     regla horizontal). El header pegajoso se separa con BORDE, no con sombra.
     Los números van con --numeric-figures y alineados a la derecha.
     ======================================================================== */
  --table-row-height: 2.5rem;
  --table-cell-x: var(--space-3);
  --table-rule: #e4e4e7;              /* hairline entre filas */
  --table-header-surface: #f4f4f5;
  --table-header-ink: #3f3f46;
  --table-row-hover: #f4f4f5;
  --table-zebra: transparent;
  --table-sticky-edge: #8a8a94;       /* borde bajo el header pegajoso, AA 3:1 */

  /* ===========================================================================
     RADIOS — el tema decide. Es justo la clase de decisión que distingue dos
     pieles sin tocar un componente.
     ======================================================================== */
  --radius-surface: 0.25rem;   /* tarjeta, panel */
  --radius-control: 0.25rem;   /* botón, input */
  --radius-chip: 0.125rem;     /* chip de estado */
  --radius-pill: 9999px;
  --radius-circle: 50%;        /* persona, punto de score, sello. Siempre. */

  /* ===========================================================================
     ELEVACIÓN Y FOCO
     El hover NO ilumina: OSCURECE EL BORDE (globals.css:235 de EM). Ese gesto
     se traduce a cualquier tema con una sola variable.
     ======================================================================== */
  --shadow-raised: none;
  --shadow-overlay: 0 8px 24px rgb(0 0 0 / 0.24);
  --border-hover: var(--text-primary);
  --focus-ring: 0 0 0 2px var(--surface-page), 0 0 0 4px var(--border-focus);

  /* ===========================================================================
     MOVIMIENTO — corto y desactivable.
     ======================================================================== */
  --duration-fast: 120ms;
  --duration-base: 200ms;
  --ease-standard: cubic-bezier(0.2, 0, 0.2, 1);

  /* ===========================================================================
     TEXTURA — opcional, define el "papel" de la piel.
     ======================================================================== */
  --texture-page: none;
  --texture-size: 24px 24px;
}

/* Respeto de accesibilidad transversal a los dos temas. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --duration-fast: 0ms;
    --duration-base: 0ms;
    /* El skeleton no deja de existir: deja de brillar. La superficie estática
       sigue comunicando "esto está cargando". */
    --skeleton-duration: 0ms;
    --skeleton-sheen: var(--skeleton-base);
  }
}
