@tailwind base;
@tailwind components;
@tailwind utilities;

/* ============================================================================
   SARAPE DESIGN SYSTEM — tokens y componentes (fuente única, ADR-011)
   Derivado 1:1 de la identidad oficial (Plantillas de Presentación, SEP 2026)
   Especificación: docs/design-system-v2.md · evidencia: docs/referencias-ui-motion.md
   Catálogo vivo: /sistema (solo desarrollo)
   ========================================================================= */

:root {
  /* Marca: paleta sarape */
  --sarape-pink:   #EA4F8D;
  --sarape-orange: #EF7620;
  --sarape-amber:  #F7A129;
  --sarape-blue:   #008CCC;
  --sarape-teal:   #00AF8A;
  --sarape-olive:  #6B725B;
  --sarape-tan:    #CABA98;
  --sarape-cyan:   #22C3D6;

  /* Color por línea de negocio (solo fondo/borde; nunca texto) */
  --line-estrategicos_integrales: var(--sarape-teal);
  --line-acompanamiento_estrategico: var(--sarape-blue);
  --line-campanas_accion_social: var(--sarape-orange);
  --line-pedagogia_formacion: var(--sarape-amber);
  --line-igualas_comunicacion: var(--sarape-olive);
  --line-productos_comunicacion: var(--sarape-pink);

  /* Neutrales editoriales */
  --black: #050505;
  --ink:   #161616;
  --paper: #F4F4F4;
  --white: #FFFFFF;

  /* Semánticos (tema claro por defecto) */
  --background:       var(--paper);
  --foreground:       var(--ink);
  --surface:          var(--white);
  --muted:            #E9E9E7;
  --muted-foreground: #686864;   /* ≥ 4.5:1 también sobre --muted (#3, hallazgo 8) */
  --border:           #DEDEDC;
  --input:            #A1A19C;   /* 2.6:1 sobre blanco: el control se ve sin pedir foco */
  --ring:             var(--ink);

  /* Funcionales (paleta sarape ajustada a WCAG AA) */
  --success: #077A5F;            --success-soft: #DDF4EC;  --success-edge: #7FD6BC;
  --warning: #9A5A0B;            --warning-soft: #FCEFD8;  --warning-edge: #F2C377;
  --destructive: #BE3455;        --destructive-soft: #FBE3EB; --destructive-edge: #F0A3BE;
  --info: #026A99;               --info-soft: #DDF0FA;     --info-edge: #7FC6E8;

  /* Paleta categórica (audiencias, líneas, series de gráfica): misma
     luminosidad y croma, cambia el matiz. Cada color ≥ 3:1 contra la
     superficie, el lienzo y el papel (WCAG 1.4.11): 3.18 el más bajo en
     claro, 6.12 en oscuro. Sin ámbar, que queda para "devuelto". Nunca va
     sola: el color acompaña al nombre (.s-categoria) o a una leyenda. */
  --cat-l: 56%; --cat-c: 40;

  /* Tipografía única: Archivo (next/font inyecta --font-archivo) */
  --font-display: var(--font-archivo), "Helvetica Neue", Arial, sans-serif;
  --font-body: var(--font-archivo), "Helvetica Neue", Arial, sans-serif;

  /* Piso tipográfico 12 px (HIG): --fs-2xs y --fs-xs coinciden a propósito */
  --fs-2xs: 0.75rem; --fs-xs: 0.75rem; --fs-caption: 0.8125rem; --fs-sm: 0.875rem; --fs-md: 1rem;
  --fs-lg: 1.1875rem;  --fs-xl: 1.5rem;  --fs-2xl: 2rem;
  --fs-3xl: clamp(2.25rem, 1.4rem + 2.6vw, 3.25rem);
  --fs-4xl: clamp(2.75rem, 1.6rem + 4vw, 4.5rem);
  --fs-display: clamp(3.25rem, 1.8rem + 6vw, 6.5rem);
  --fs-stat: clamp(2.25rem, 1.4rem + 2.8vw, 3.75rem);
  /* Valor dentro de una fila de 4: debe caber un número largo ("+32,232") */
  --fs-stat-row: clamp(1.5rem, 0.9rem + 1.9vw, 2.5rem);

  --lh-tight: 0.98; --lh-heading: 1.08; --lh-base: 1.55;

  /* Espaciado */
  --s-1: 0.25rem; --s-2: 0.5rem; --s-3: 0.75rem; --s-4: 1rem;
  --s-5: 1.5rem;  --s-6: 2rem;   --s-7: 3rem;    --s-8: 4rem; --s-9: 6rem;

  /* Radios (decisión 2026-09-10): --r-1 lo que se teclea · --r-2 contenedores ·
     pill acciones y estados · recto solo la firma editorial (numerales, chips
     de conteo, stepper). --r-3 para el bloque de marca del login. */
  --r-0: 0; --r-1: 0.375rem; --r-2: 0.75rem; --r-3: 1rem; --r-pill: 999px;

  /* Sombras */
  --sh-1: 0 1px 2px rgba(5,5,5,0.06), 0 1px 1px rgba(5,5,5,0.04);
  --sh-2: 0 6px 24px -8px rgba(5,5,5,0.18);
  --sh-3: 0 24px 64px -24px rgba(5,5,5,0.35);

  /* Capas: una sola escala (regla 41). Contenido < pegado (encabezado de
     tabla, barra de guardar) < barras (superior e inferior) < menú < aviso
     (tooltip) < ventana (diálogo, slide-over). Un mapa, una gráfica o un
     lienzo van en .s-lienzo: sus capas internas no salen de él. */
  --z-contenido: 0; --z-pegado: 20; --z-barra: 30; --z-menu: 50; --z-aviso: 60; --z-ventana: 70;

  /* Motion — dos regímenes (ADR-010): producto ≤ 300 ms · marca ≤ 900 ms */
  --t-instant: 0ms;    /* ⌘K, pestañas, foco, tooltips repetidos */
  --t-micro:   120ms;  /* hover, :active, toggles */
  --t-ui:      200ms;  /* tooltip, dropdown, popover, cross-fade de badge */
  --t-panel:   260ms;  /* slide-over, diálogo (entrada) */
  --t-panel-out: 200ms;
  --t-page:    360ms;  /* entrada de contenido; stagger 60 ms, máx. 8 */
  --t-brand:   900ms;  /* brocha, count-up, título por líneas — solo marca */
  --stagger:   60ms;
  --ease-out:  cubic-bezier(0.23, 1, 0.32, 1);        /* entrar y salir */
  --ease-move: cubic-bezier(0.645, 0.045, 0.355, 1);  /* desplazar en pantalla */
  --ease-in-out: var(--ease-move);
  --ease-spring: cubic-bezier(0.34, 1.4, 0.64, 1);    /* solo momentos poco frecuentes (una ceremonia); nunca hover, foco, selección ni pulsar */
  /* Alias de compatibilidad (se retiran al terminar la homologación) */
  --t-fast: var(--t-micro); --t-base: var(--t-ui); --t-slow: var(--t-page); --t-hero: var(--t-brand);
}

[data-theme="dark"] {
  --background:       var(--black);
  --foreground:       var(--paper);
  --surface:          #0E0E0E;
  --muted:            #1A1A1A;
  --muted-foreground: #9C9C97;
  --border:           #2A2A2A;
  --input:            #3A3A3A;
  --ring:             var(--paper);
  /* Funcionales en oscuro (#3, hallazgo 2): el tono de texto pasa a su
     -edge (≥ 8.8:1 sobre el fondo, la superficie y --muted) y el fondo suave
     es el -edge al 16 % sobre negro. Los -edge no cambian. */
  --success: var(--success-edge);  --success-soft: color-mix(in lch, var(--success-edge) 16%, var(--black));
  --warning: var(--warning-edge);  --warning-soft: color-mix(in lch, var(--warning-edge) 16%, var(--black));
  --destructive: var(--destructive-edge); --destructive-soft: color-mix(in lch, var(--destructive-edge) 16%, var(--black));
  --info: var(--info-edge);        --info-soft: color-mix(in lch, var(--info-edge) 16%, var(--black));
  --cat-l: 70%; --cat-c: 34;
  --sh-1: 0 1px 2px rgba(0,0,0,0.5);
  --sh-2: 0 6px 24px -8px rgba(0,0,0,0.6);
  --sh-3: 0 24px 64px -24px rgba(0,0,0,0.8);
  color-scheme: dark;
}

/* La paleta categórica se declara donde cambia el tema, para que var() se
   resuelva con su luminosidad (como los derivados del operativo). */
:root, [data-theme] {
  --cat-1: lch(var(--cat-l) var(--cat-c) 252);   /* azul */
  --cat-2: lch(var(--cat-l) var(--cat-c) 172);   /* teal */
  --cat-3: lch(var(--cat-l) var(--cat-c) 300);   /* violeta */
  --cat-4: lch(var(--cat-l) var(--cat-c) 2);     /* rosa */
  --cat-5: lch(var(--cat-l) var(--cat-c) 205);   /* cian */
  --cat-6: lch(var(--cat-l) var(--cat-c) 130);   /* oliva */
}
/* Un bloque claro dentro de una página oscura vuelve a los valores claros
   (los del :root); sin esto heredaba los oscuros del <html>. */
[data-theme="light"] {
  --background:       var(--paper);
  --foreground:       var(--ink);
  --surface:          var(--white);
  --muted:            #E9E9E7;
  --muted-foreground: #686864;
  --border:           #DEDEDC;
  --input:            #A1A19C;
  --ring:             var(--ink);
  --success: #077A5F;            --success-soft: #DDF4EC;
  --warning: #9A5A0B;            --warning-soft: #FCEFD8;
  --destructive: #BE3455;        --destructive-soft: #FBE3EB;
  --info: #026A99;               --info-soft: #DDF0FA;
  --cat-l: 56%; --cat-c: 40;
  --sh-1: 0 1px 2px rgba(5,5,5,0.06), 0 1px 1px rgba(5,5,5,0.04);
  --sh-2: 0 6px 24px -8px rgba(5,5,5,0.18);
  --sh-3: 0 24px 64px -24px rgba(5,5,5,0.35);
  color-scheme: light;
}

/* Preferencia de más contraste (HIG): bordes y texto secundario más firmes */
@media (prefers-contrast: more) {
  :root, [data-theme="light"] {
    --border: #B8B8B4;
    --input: #8F8F8A;
    --muted-foreground: #4A4A46;
  }
  [data-theme="dark"] {
    --border: #5A5A5A;
    --input: #7A7A7A;
    --muted-foreground: #C9C9C4;
  }
}

/* ======================================= Registro operativo: tema (ADR-004)
   Solo bajo .s-operativo (la app, en <body>) o .s-page (la página); el
   narrativo conserva el papel y sus valores. Tres variables de diseño
   —base, contraste, acento— y todo lo demás derivado en LCH (método del
   rediseño de Linear). El tema oscuro solo cambia la base; --op-signo
   (hacia dónde está la tinta) y --op-elev (cuánto sube la superficie 1
   sobre el lienzo) se siguen de ella. Va fuera de capa para ganarle, por
   orden, a [data-theme] cuando un bloque cambia de tema dentro de la app. */
:where(.s-operativo, .s-page) {
  --op-base: lch(98.5% 1.5 75);   /* lienzo casi blanco, matiz cálido al mínimo */
  --op-contraste: 1;
  --op-acento: var(--sarape-blue);
  --op-signo: -1;
  --op-elev: 1.5;                 /* superficie 1 = L 100: blanco */
  --op-tono-l: 52%;               /* íconos de estado */
  --fs-page: 1.75rem;             /* 28 px, título de página de trabajo */
}
/* Teléfono: título de 24 px; la cabecera ocupa menos alto (0.6.0) */
@media (max-width: 640px) {
  :where(.s-operativo, .s-page) { --fs-page: 1.5rem; }
}
[data-theme="dark"] :where(.s-operativo, .s-page),
:where(.s-operativo, .s-page)[data-theme="dark"],
:where(.s-operativo, .s-page) [data-theme="dark"] {
  --op-base: lch(11% 0.8 75);     /* profundo y neutro, no negro plano */
  --op-signo: 1;
  --op-elev: 3;
  --op-tono-l: 72%;
}
:where(.s-operativo, .s-page) [data-theme="light"] { --op-base: lch(98.5% 1.5 75); --op-signo: -1; --op-elev: 1.5; --op-tono-l: 52%; }
@media (prefers-contrast: more) {
  :where(.s-operativo, .s-page) { --op-contraste: 1.25; }
}
/* Derivados: se declaran en cada elemento donde cambia la base, para que
   var() se resuelva ahí. Distancias en L*: superficies a 3.5 una de otra;
   tintas a 82, 58 y 55 del lienzo (AA medido sobre las tres superficies y
   el lienzo, en claro y oscuro); bordes a 7 % de la tinta; borde de
   control a 40. */
:where(.s-operativo, .s-page),
:where(.s-operativo, .s-page) [data-theme] {
  --op-lienzo: var(--op-base);
  --op-sup-1: lch(from var(--op-base) calc(l + var(--op-elev)) c h);
  --op-sup-2: lch(from var(--op-base) calc(l + var(--op-elev) + var(--op-signo) * 3.5 * var(--op-contraste)) c h);
  --op-sup-3: lch(from var(--op-base) calc(l + var(--op-elev) + var(--op-signo) * 7 * var(--op-contraste)) c h);
  --op-tinta: lch(from var(--op-base) calc(l + var(--op-signo) * 82 * var(--op-contraste)) calc(c * 2) h);
  --op-tinta-media: lch(from var(--op-base) calc(l + var(--op-signo) * 58 * var(--op-contraste)) calc(c * 2) h);
  --op-tinta-tenue: lch(from var(--op-base) calc(l + var(--op-signo) * 55 * var(--op-contraste)) calc(c * 2) h);
  --op-borde: color-mix(in lch, var(--op-tinta) calc(7% * var(--op-contraste)), transparent);
  /* Borde de control editable (WCAG 2.2, 1.4.11): a 40 de L* del lienzo,
     ≥ 3:1 contra superficie 1, lienzo y superficie 2. El hairline de arriba
     queda para tablas, tarjetas y separadores. */
  --op-borde-control: lch(from var(--op-base) calc(l + var(--op-signo) * 40 * var(--op-contraste)) calc(c * 2) h);
  /* Color de los íconos de estado (regla 30): misma luminosidad, cambia el
     matiz; ≥ 3:1 contra las superficies en claro y oscuro (no es texto: el
     texto del estado va en tinta). */
  --op-estado-info: lch(var(--op-tono-l) 48 252);
  --op-estado-success: lch(var(--op-tono-l) 46 155);
  --op-estado-warning: lch(var(--op-tono-l) 58 68);
  --op-estado-destructive: lch(var(--op-tono-l) 56 15);
  /* Los componentes del sistema toman el tema sin cambiar de clase */
  --background: var(--op-lienzo);
  --surface: var(--op-sup-1);
  --muted: var(--op-sup-2);
  --border: var(--op-borde);
  --input: var(--op-borde-control);
  --foreground: var(--op-tinta);
  --muted-foreground: var(--op-tinta-media);
  --ring: var(--op-acento);
}

/* ================================================================== Base */
@layer base {
  /* `hidden` gana siempre: un componente que fija su display (un panel en
     grid) no debe dejar a la vista lo que la app ocultó. until-found se
     respeta (lo resuelve el navegador). */
  [hidden]:not([hidden="until-found"]) { display: none !important; }

  /* CSS le da `min-width: auto` a los hijos de grid y flex: no se encogen por
     debajo de su contenido mínimo. Una tabla de cinco columnas o una barra de
     ocho pestañas ensancha entonces a su contenedor, y el contenedor a la
     página: scroll horizontal en pantalla chica.
     `overflow-x: auto` en el componente no basta — sin esto no puede encoger.
     Se revierte al valor útil. `:where` deja especificidad 0, así que cualquier
     regla posterior gana sin pelear. */
  :where(.grid, .flex, .inline-flex, .s-stats, .s-segmented, .s-tabs, .s-likert) > * {
    min-inline-size: 0;
  }

  /* Un bloque con otro tema (data-theme) toma su tinta y su fondo: `color`
     se hereda ya resuelto del <body> y, sin esto, el texto salía con la
     tinta del otro tema (1.07:1 medido en Impacto). Especificidad 0 y en la
     capa base: el fondo propio de un componente (la aurora) sigue ganando.
     La raíz no: ahí el <body> ya pone tinta y fondo, y un fondo en <html>
     le quitaría al <body> el lienzo de toda la ventana. */
  :where([data-theme]:not(:root)) { color: var(--foreground); background-color: var(--background); }

  body {
    font-family: var(--font-body);
    font-size: var(--fs-md);
    line-height: var(--lh-base);
    color: var(--foreground);
    background: var(--background);
    text-rendering: optimizeLegibility;
    -webkit-font-smoothing: antialiased;
    font-feature-settings: "kern", "liga", "calt";
  }

  h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-display);
    font-weight: 600;
    font-variation-settings: "wdth" 112;
    text-wrap: balance;
    letter-spacing: -0.02em;
    line-height: var(--lh-heading);
  }
  h1 { font-size: var(--fs-4xl); letter-spacing: -0.028em; line-height: var(--lh-tight); }
  h2 { font-size: var(--fs-3xl); letter-spacing: -0.024em; }
  h3 { font-size: var(--fs-2xl); }
  h4 { font-size: var(--fs-xl); }
  h5 { font-size: var(--fs-lg); }
  h6 {
    font-size: var(--fs-xs);
    letter-spacing: 0.1em;
    text-transform: uppercase;
    font-variation-settings: "wdth" 100;
  }
  p { text-wrap: pretty; }

  :focus-visible { outline: 2px solid var(--ring); outline-offset: 3px; border-radius: 2px; }
  ::selection { background: var(--sarape-amber); color: var(--black); }
}

/* ============================================================ Componentes */
@layer components {

  /* Logo oficial (SVG currentColor vía CSS mask, recoloreable) */
  .s-logo {
    display: inline-block;
    aspect-ratio: 913.47 / 241.12;
    background: currentColor;
    -webkit-mask: url("/sarape-logo.svg") 0 0 / 100% 100% no-repeat;
            mask: url("/sarape-logo.svg") 0 0 / 100% 100% no-repeat;
  }

  /* Display hero */
  .s-display {
    font-family: var(--font-display);
    font-variation-settings: "wdth" 112;
    font-size: var(--fs-display);
    font-weight: 500;
    line-height: var(--lh-tight);
    letter-spacing: -0.03em;
    text-wrap: balance;
  }

  .s-kicker {
    font-family: var(--font-display);
    font-size: var(--fs-xs);
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--muted-foreground);
  }

  /* Subrayado de brocha (firma de títulos) */
  .s-brush { position: relative; display: inline-block; padding-bottom: 0.18em; }
  .s-brush::after {
    content: "";
    position: absolute;
    left: -0.02em; right: -0.04em; bottom: 0;
    height: 0.16em;
    background: currentColor;
    -webkit-mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 22" preserveAspectRatio="none"><path d="M3 12 C40 8 90 7 150 8 C230 9 300 7 397 9 L396 12 C310 11 240 13 160 12 C90 11 50 14 12 16 C60 15 130 15 210 16 C290 17 340 15 390 14 L388 17 C320 18 240 19 150 18 C90 17 40 18 4 16 Z" fill="black"/></svg>') 0 0 / 100% 100% no-repeat;
            mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 22" preserveAspectRatio="none"><path d="M3 12 C40 8 90 7 150 8 C230 9 300 7 397 9 L396 12 C310 11 240 13 160 12 C90 11 50 14 12 16 C60 15 130 15 210 16 C290 17 340 15 390 14 L388 17 C320 18 240 19 150 18 C90 17 40 18 4 16 Z" fill="black"/></svg>') 0 0 / 100% 100% no-repeat;
    transform-origin: left center;
  }
  .s-brush--draw::after {
    transform: scaleX(0);
    animation: s-brush-draw 900ms var(--ease-out) forwards;
    animation-delay: var(--brush-delay, 500ms);
  }

  /* Botones */
  .s-btn {
    display: inline-flex; align-items: center; justify-content: center;
    gap: var(--s-2);
    padding: 0.78em 1.7em;
    border-radius: var(--r-pill);
    font-family: var(--font-display);
    font-size: var(--fs-sm);
    font-weight: 600;
    line-height: 1;
    border: 1.5px solid transparent;
    position: relative; overflow: hidden;
    cursor: pointer;
    transition:
      transform var(--t-fast) var(--ease-out),
      background-color var(--t-fast) var(--ease-out),
      color var(--t-fast) var(--ease-out),
      border-color var(--t-fast) var(--ease-out),
      box-shadow var(--t-base) var(--ease-out);
  }
  .s-btn:active { transform: scale(0.97); }
  /* Deshabilitado, una sola vez para todas las apps: sin hover ni pulsación, y
     el primario pasa a pastilla gris con tinta atenuada (legible, no lavado). */
  .s-btn:disabled, .s-btn[aria-disabled="true"] {
    cursor: not-allowed;
    transform: none;
    box-shadow: none;
    opacity: 0.55;
  }
  .s-btn--primary:disabled, .s-btn--primary[aria-disabled="true"] {
    opacity: 1;
    background: var(--muted);
    border-color: var(--muted);
    color: color-mix(in srgb, var(--foreground) 70%, transparent);
  }
  .s-btn--primary:disabled::after { display: none; }
  .s-btn--primary { background: var(--foreground); color: var(--background); }
  /* Hover solo en botones activos (#3, hallazgo 5) */
  .s-btn--primary:not(:disabled, [aria-disabled="true"]):hover { box-shadow: var(--sh-2); transform: translateY(-1px); }
  .s-btn--primary::after {
    content: "";
    position: absolute; inset: 0;
    background: linear-gradient(105deg, transparent 35%, rgba(255,255,255,0.22) 50%, transparent 65%);
    transform: translateX(-110%);
  }
  .s-btn--primary:not(:disabled, [aria-disabled="true"]):hover::after { transform: translateX(110%); transition: transform 700ms var(--ease-out); }
  .s-btn--outline { border-color: var(--foreground); color: var(--foreground); background: transparent; }
  .s-btn--outline:not(:disabled, [aria-disabled="true"]):hover { background: var(--foreground); color: var(--background); }
  .s-btn--ghost { color: var(--foreground); }
  .s-btn--ghost:not(:disabled, [aria-disabled="true"]):hover { background: color-mix(in srgb, var(--foreground) 8%, transparent); }
  .s-btn--sm { padding: 0.55em 1.2em; font-size: var(--fs-xs); }
  /* Destructivo (eliminar, quitar, rechazar): contorno con el tono; el
     relleno suave solo en hover. Nunca primario de una pantalla. */
  .s-btn--destructive { border-color: var(--destructive-edge); color: var(--destructive); background: transparent; }
  .s-btn--destructive:not(:disabled, [aria-disabled="true"]):hover { background: var(--destructive-soft); }
  /* Botón de bloque (ancho completo en un formulario): radio de contenedor,
     no pastilla, para que forme familia con el campo y con el botón OAuth. */
  .s-btn--bloque { border-radius: var(--r-2); height: 3.25rem; }
  .s-btn--lg { padding: 0.95em 2.2em; font-size: var(--fs-md); }
  .s-btn .s-btn__arrow { transition: transform var(--t-micro) var(--ease-out); }
  .s-btn:not(:disabled, [aria-disabled="true"]):hover .s-btn__arrow { transform: translateX(4px); }

  /* Badge pill outline */
  .s-badge {
    display: inline-flex; align-items: center; gap: var(--s-2);
    padding: 0.45em 1.1em;
    border: 1px solid color-mix(in srgb, var(--foreground) 55%, transparent);
    border-radius: var(--r-pill);
    font-family: var(--font-display);
    font-size: var(--fs-2xs);
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    white-space: nowrap;
  }
  .s-badge--success { border-color: var(--success-edge); background: var(--success-soft); color: var(--success); }
  .s-badge--warning { border-color: var(--warning-edge); background: var(--warning-soft); color: var(--warning); }
  .s-badge--destructive { border-color: var(--destructive-edge); background: var(--destructive-soft); color: var(--destructive); }
  .s-badge--info { border-color: var(--info-edge); background: var(--info-soft); color: var(--info); }

  /* Etiqueta suave: metadato de una fila (tipo de respuesta, etiqueta
     metodológica). Minúsculas y sin borde: acompaña, no compite con el badge
     de estado. */
  .s-tag {
    display: inline-flex; align-items: center; gap: 0.35em;
    padding: 0.3em 0.75em;
    border-radius: var(--r-pill);
    background: var(--muted);
    /* Tinta, no gris: muted-foreground sobre muted se queda en 3.9:1 y axe lo
       marca en cada etiqueta (Coordinación, Captura, Relato abierto). El tono
       "secundario" lo da la pastilla, no el texto. */
    color: var(--foreground);
    font-size: var(--fs-xs);
    font-weight: 500;
    line-height: 1.4;
    white-space: nowrap;
  }
  .s-tag--info { background: var(--info-soft); color: var(--info); }

  /* Chip de dato sólido */
  .s-chip {
    display: inline-flex; align-items: center; justify-content: center;
    padding: 0.35em 0.9em;
    background: var(--foreground);
    color: var(--background);
    border-radius: var(--r-0);
    font-family: var(--font-display);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
  }

  /* Stat */
  .s-stat { display: grid; gap: var(--s-1); }
  .s-stat__value {
    font-family: var(--font-display);
    font-variation-settings: "wdth" 112;
    font-size: var(--fs-stat);
    font-weight: 500;
    letter-spacing: -0.03em;
    line-height: 1;
    font-variant-numeric: tabular-nums;
  }
  .s-stat__label { font-family: var(--font-display); font-size: var(--fs-sm); font-weight: 600; }
  .s-stat__hint { font-size: var(--fs-xs); color: var(--muted-foreground); }
  /* Sobre la aurora el gris atenuado cae a 3:1 en las zonas claras (medido
     sobre captura compuesta, 21 sep); papel al 78 % se queda arriba de 4.5:1. */
  [data-theme="dark"] .s-stat__hint { color: color-mix(in srgb, var(--paper) 78%, transparent); }

  /* --------------------------------------------- Fila de estadísticas
     Los números tienen anchos muy distintos ("+32,232" vs. "36"), así que
     la estructura no puede depender de ellos: una regla vertical marca la
     columna y el subgrid alinea valor/etiqueta/nota entre todas. */
  .s-stats {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 0;
    row-gap: var(--s-6);
    align-items: start;
  }
  .s-stats > * {
    min-width: 0;
    padding-inline: var(--s-5);
    border-left: 1px solid var(--s-stats-rule, color-mix(in srgb, var(--foreground) 15%, transparent));
  }
  /* Primer elemento de cada fila: sin regla ni sangría (2 columnas) */
  .s-stats > :nth-child(2n + 1) { border-left: 0; padding-left: 0; }

  /* El valor baja un escalón: en fila de 4 el tamaño hero no cabe */
  .s-stats .s-stat__value { font-size: var(--fs-stat-row); }
  /* Dentro de una tarjeta el espacio es menor */
  .s-stats--sm .s-stat__value { font-size: clamp(1.25rem, 0.7rem + 1.4vw, 2rem); }
  .s-stats--sm > * { padding-inline: var(--s-4); }

  @media (min-width: 1024px) {
    .s-stats--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
    .s-stats--4 > :nth-child(2n + 1) {
      border-left: 1px solid var(--s-stats-rule, color-mix(in srgb, var(--foreground) 15%, transparent));
      padding-left: var(--s-5);
    }
    .s-stats--4 > :nth-child(4n + 1) { border-left: 0; padding-left: 0; }
  }

  /* Progreso pill */
  .s-progress { display: flex; align-items: center; gap: var(--s-2); }
  .s-progress__track {
    flex: 1; height: 0.8rem;
    background: color-mix(in srgb, var(--foreground) 12%, transparent);
    border-radius: var(--r-pill);
    overflow: hidden;
  }
  .s-progress__fill {
    height: 100%;
    width: var(--value, 0%);
    background: var(--foreground);
    border-radius: var(--r-pill);
    transition: width var(--t-hero) var(--ease-out);
  }
  /* Semáforo (acuerdo PM): >80 éxito · 60–80 advertencia · <60 riesgo */
  .s-progress__fill--success { background: var(--success); }
  .s-progress__fill--warning { background: var(--warning); }
  .s-progress__fill--destructive { background: var(--destructive); }
  .s-progress__label {
    font-family: var(--font-display);
    font-size: var(--fs-2xs);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--muted-foreground);
  }
  /* --compacto (progreso visible, regla 22): barra de 4 px en el acento,
     "x de y" a 14 y, debajo, lo que falta con un enlace a cada lugar
     (.s-progress__pendientes) */
  .s-progress--compacto { gap: var(--s-3); }
  .s-progress--compacto .s-progress__track { flex: 0 1 8rem; height: var(--s-1); background: var(--op-sup-3, var(--muted)); }
  .s-progress--compacto .s-progress__fill { background: var(--op-acento, var(--foreground)); transition: width var(--t-ui) var(--ease-out), background-color var(--t-ui) var(--ease-out); }
  /* Al 100 %, en verde éxito (regla 46): la app pone --success en el relleno */
  .s-progress--compacto .s-progress__fill--success { background: var(--success); }
  .s-progress--compacto .s-progress__label { font-family: var(--font-body); font-size: var(--fs-sm); font-weight: 500; color: var(--foreground); white-space: nowrap; }
  .s-progress__pendientes { display: flex; flex-wrap: wrap; gap: 0 var(--s-3); margin: var(--s-1) 0 0; padding: 0; list-style: none; color: var(--muted-foreground); }
  .s-progress__pendientes a { color: var(--foreground); text-decoration: underline; text-decoration-color: var(--input); text-underline-offset: 0.2em; }
  @media (hover: hover) and (pointer: fine) { .s-progress__pendientes a:hover { text-decoration-color: currentColor; } }

  /* Card */
  .s-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-2);
    padding: var(--s-5);
    transition: transform var(--t-base) var(--ease-out), box-shadow var(--t-base) var(--ease-out);
  }
  .s-card--hover:hover { transform: translateY(-3px); box-shadow: var(--sh-2); }
  /* Tarjeta editorial del deck: recta, sin borde ni sombra */
  .s-card--editorial { border-radius: var(--r-0); border: none; }

  /* Numeral editorial 01 / 02 (deck: 24 pt junto al título de bloque) */
  .s-numeral {
    font-family: var(--font-display);
    font-size: var(--fs-2xl);
    font-weight: 500;
    letter-spacing: -0.02em;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    color: var(--foreground);
  }

  /* Cuadro de tinta (firma de Sarape): cifra de 12 px en papel sobre un
     cuadro de 24 en tinta, radio de 3. Solo numerales de secuencia y avance
     (etapas, pasos, capítulos, la cifra clave de una bandeja); nunca
     estados, tipos, códigos, etiquetas ni botones, y una familia por
     pantalla. --contorno para lo que falta. */
  .s-numeral--cuadro {
    display: inline-grid; place-items: center;
    min-inline-size: var(--s-5); block-size: var(--s-5);
    flex-shrink: 0;
    padding-inline: var(--s-1);
    border-radius: calc(var(--r-1) / 2);
    background: var(--foreground);
    color: var(--background);
    font-size: var(--fs-xs);
    font-weight: 600;
    letter-spacing: 0;
    line-height: 1;
  }
  .s-numeral--contorno { background: transparent; color: var(--foreground); box-shadow: inset 0 0 0 1.5px var(--foreground); }
  /* Progreso que se siente (regla 46): la tinta es el número de secuencia;
     el verde con palomita es completado, y solo lo completado. En progreso,
     --contorno (y su barra en el acento); pendiente, --pendiente (contorno
     tenue). El verde es --success: la palomita, en el fondo de la página,
     mide ≥ 4.5:1 sobre él en claro y oscuro, y él ≥ 3:1 sobre la superficie. */
  .s-numeral--hecho { position: relative; background: var(--success); color: transparent; box-shadow: none; }
  .s-numeral--hecho::after {
    content: ""; position: absolute; inset: 0; margin: auto;
    inline-size: 0.75rem; block-size: 0.75rem;
    background: var(--background);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='m2.5 6.2 2.3 2.3 4.7-5' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
            mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='m2.5 6.2 2.3 2.3 4.7-5' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
  }
  .s-numeral--pendiente { background: transparent; color: var(--muted-foreground); box-shadow: inset 0 0 0 1px var(--muted-foreground); }

  /* Etiqueta de categoría: cuadro de 8 px con el color y el nombre al lado.
     --1 a --6 toman la paleta categórica (--cat-*). */
  .s-categoria { display: inline-flex; align-items: center; gap: var(--s-2); white-space: nowrap; }
  .s-categoria::before {
    content: "";
    inline-size: var(--s-2); block-size: var(--s-2);
    flex-shrink: 0;
    border-radius: calc(var(--r-1) / 3);
    background: var(--s-categoria, var(--muted-foreground));
  }
  .s-categoria--1 { --s-categoria: var(--cat-1); }
  .s-categoria--2 { --s-categoria: var(--cat-2); }
  .s-categoria--3 { --s-categoria: var(--cat-3); }
  .s-categoria--4 { --s-categoria: var(--cat-4); }
  .s-categoria--5 { --s-categoria: var(--cat-5); }
  .s-categoria--6 { --s-categoria: var(--cat-6); }

  /* Texto de apoyo */
  .s-lead { font-size: var(--fs-lg); color: var(--muted-foreground); text-wrap: pretty; }
  .s-caption { font-size: var(--fs-caption); color: var(--muted-foreground); }

  /* Reglas hairline en vez de cajas */
  .s-divider { border: none; border-top: 1px solid var(--border); margin: var(--s-6) 0; }
  .s-divider--ink { border-top-color: var(--foreground); }

  /* Error de campo (HIG: en línea, al perder foco, sin bloquear el tecleo) */
  .s-field--error .s-field__input, .s-field--error .s-numfield__input { border-color: var(--destructive-edge); }
  .s-field--error .s-field__label, .s-field--error .s-numfield__label { color: var(--destructive); }
  .s-field__error { margin-top: var(--s-1); font-size: var(--fs-xs); color: var(--destructive); }

  /* Field (texto): caja de 44 px con etiqueta arriba. Un solo estilo de campo
     en toda la app (decisión 2026-09-09): el mismo contrato que s-numfield,
     tipografía de lectura y alineación a la izquierda. La etiqueta va antes
     del control aunque en el DOM vaya después (order), para que el label
     siga asociado por htmlFor y el error quede al final. */
  .s-field { display: grid; gap: 0.3rem; }
  .s-field__label {
    order: -1;
    font-family: var(--font-display);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--muted-foreground);
  }
  .s-field__input {
    height: 2.75rem;
    width: 100%;
    border: 1px solid var(--input);
    /* Relleno blanco en cualquier fondo (papel o tarjeta): el campo siempre se lee como campo */
    background: var(--surface);
    padding: 0 0.75rem;
    font-size: var(--fs-sm);
    font-weight: 500;
    color: var(--foreground);
    outline: none;
    border-radius: var(--r-1);
    transition: border-color var(--t-fast) var(--ease-out), box-shadow var(--t-fast) var(--ease-out);
  }
  .s-field__input::placeholder { color: var(--muted-foreground); font-weight: 400; }
  .s-field__input:hover:not(:focus) { border-color: color-mix(in srgb, var(--foreground) 60%, var(--input)); }
  .s-field__input:focus {
    border-color: var(--foreground);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--foreground) 10%, transparent);
  }
  /* Safari en iOS amplía la página al enfocar un campo de menos de 16 px y no
     la devuelve; en táctil el texto del campo sube a 16 px (§3.5). */
  @media (max-width: 767px), (pointer: coarse) {
    .s-field__input { font-size: var(--fs-md); }
  }
  textarea.s-field__input { height: auto; min-height: 5.5rem; padding: 0.6rem 0.75rem; resize: vertical; line-height: var(--lh-base); }
  /* Fecha nativa: hereda caja, radio y el icono en tinta */
  .s-field__input[type="date"], .s-numfield__input[type="date"] { padding-right: 0.6rem; }
  .s-field__input[type="date"]::-webkit-calendar-picker-indicator,
  .s-numfield__input[type="date"]::-webkit-calendar-picker-indicator {
    opacity: 0.55; cursor: pointer; transition: opacity var(--t-micro) var(--ease-out);
  }
  .s-field__input[type="date"]::-webkit-calendar-picker-indicator:hover,
  .s-numfield__input[type="date"]::-webkit-calendar-picker-indicator:hover { opacity: 1; }

  /* ---------------------------------------- Primitivas de formulario
     Una sola fuente de alineación: alturas, anchos y ritmo idénticos. */

  /* Campo numérico alineado (etiqueta arriba, número tabular a la derecha) */
  .s-numfield { display: grid; gap: 0.3rem; }
  .s-numfield__label {
    font-family: var(--font-display);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--muted-foreground);
  }
  .s-numfield__input {
    height: 2.75rem;
    width: 100%;
    border: 1px solid var(--input);
    background: var(--surface);
    border-radius: var(--r-1);
    padding: 0 0.75rem;
    text-align: right;
    font-family: var(--font-display);
    font-size: var(--fs-lg);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--foreground);
    outline: none;
    transition: border-color var(--t-fast) var(--ease-out), box-shadow var(--t-fast) var(--ease-out);
  }
  .s-numfield__input::placeholder { color: var(--muted-foreground); font-weight: 400; }
  /* Variante texto: misma altura y foco, tipografía de lectura (selects, fechas, texto corto) */
  .s-numfield__input--text {
    text-align: left;
    font-size: var(--fs-sm);
    font-weight: 500;
    font-variant-numeric: normal;
  }
  /* La flecha son dos trazos de 1.5 px en --muted-foreground (gradientes,
     no un SVG con color fijo): sigue al tema (#3, hallazgo 6). */
  select.s-numfield__input {
    -webkit-appearance: none;
    appearance: none;
    cursor: pointer;
    padding-right: 2.25rem;
    background-image:
      linear-gradient(to top right, transparent calc(50% - 0.75px), var(--muted-foreground) calc(50% - 0.75px) calc(50% + 0.75px), transparent calc(50% + 0.75px)),
      linear-gradient(to top left, transparent calc(50% - 0.75px), var(--muted-foreground) calc(50% - 0.75px) calc(50% + 0.75px), transparent calc(50% + 0.75px));
    background-size: var(--s-1) var(--s-1);
    background-repeat: no-repeat;
    background-position: right calc(0.875rem + var(--s-1)) center, right 0.875rem center;
  }
  select.s-numfield__input:invalid,
  select.s-numfield__input option[value=""] {
    color: var(--muted-foreground);
  }
  .s-numfield__input:hover:not(:focus) { border-color: color-mix(in srgb, var(--foreground) 60%, var(--input)); }
  .s-numfield__input:focus {
    border-color: var(--foreground);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--foreground) 10%, transparent);
  }
  /* Táctil: 16 px como .s-field__input, también en la variante de texto y
     el select (iOS amplía al enfocar un campo de menos de 16, #3, 6) */
  @media (max-width: 767px), (pointer: coarse) {
    .s-numfield__input--text, select.s-numfield__input { font-size: var(--fs-md); }
  }
  /* Variante estrecha para pares meta / línea base en tablas y listas */
  .s-numfield__input--corto { width: 6rem; height: 2.5rem; font-size: var(--fs-md); }
  .s-numfield__unit { font-size: 11px; color: var(--muted-foreground); }

  /* Botón OAuth (login): blanco, alto generoso, logo a la izquierda */
  .s-oauth {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    height: 3.25rem;
    width: 100%;
    border: 1px solid var(--input);
    border-radius: var(--r-2);
    background: var(--surface);
    font-family: var(--font-display);
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--foreground);
    transition:
      border-color var(--t-fast) var(--ease-out),
      box-shadow var(--t-fast) var(--ease-out),
      transform var(--t-fast) var(--ease-out);
  }
  .s-oauth:hover {
    border-color: var(--foreground);
    box-shadow: var(--sh-1);
    transform: translateY(-1px);
  }
  .s-oauth:active {
    transform: translateY(0);
    box-shadow: none;
  }
  /* Mientras abre el consentimiento: sin elevación y sin segundo envío */
  .s-oauth:disabled { cursor: progress; transform: none; box-shadow: none; border-color: var(--input); }
  .s-oauth:focus-visible {
    outline: none;
    border-color: var(--foreground);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--foreground) 12%, transparent);
  }

  /* Desplegable discreto (alternativas secundarias que no compiten con la acción principal) */
  /* Un .s-btn como summary conserva su estilo (#3, hallazgo 4) */
  .s-disclosure summary:not(.s-btn) {
    list-style: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    font-size: 12px;
    color: var(--muted-foreground);
    transition: color var(--t-fast) var(--ease-out);
  }
  .s-disclosure summary { list-style: none; }
  .s-disclosure summary::-webkit-details-marker { display: none; }
  .s-disclosure summary:not(.s-btn):hover { color: var(--foreground); }
  /* El chevron estándar (lucide chevron-down) dibujado con máscara: el
     texto que traiga el span ("▾") no se ve, así el marcador es el mismo
     en todas las apps */
  .s-disclosure__chevron {
    flex: none;
    inline-size: 1rem; block-size: 1rem;
    font-size: 0;
    background: currentColor;
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") center / contain no-repeat;
            mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") center / contain no-repeat;
    transition: transform var(--t-fast) var(--ease-out);
  }
  .s-disclosure[open] .s-disclosure__chevron { transform: rotate(180deg); }
  .s-disclosure__content { padding-top: 1.75rem; }
  .s-disclosure[open] .s-disclosure__content {
    animation: s-disclosure-in 420ms var(--ease-out) both;
  }
  @keyframes s-disclosure-in {
    from { opacity: 0; transform: translateY(-6px); }
  }
  /* --ayuda: las instrucciones largas de una página, plegadas bajo la
     cabecera (regla 23); a la izquierda, a 14 / 500 */
  .s-disclosure--ayuda summary:not(.s-btn) { justify-content: flex-start; inline-size: fit-content; min-block-size: 2rem; font-size: var(--fs-sm); font-weight: 500; }
  .s-disclosure--ayuda summary:focus-visible { outline-offset: 2px; border-radius: var(--r-1); }
  .s-disclosure--ayuda .s-disclosure__content { display: grid; gap: var(--s-2); max-inline-size: 44rem; padding-top: var(--s-2); color: var(--muted-foreground); }
  @media (max-width: 767px), (pointer: coarse) { .s-disclosure--ayuda summary:not(.s-btn) { min-block-size: 2.75rem; } }

  /* Slide-over (glosario): el panel entra con easing expo y el fondo funde;
     la salida es más corta para que el cierre se sienta inmediato. */
  .s-slideover__backdrop {
    /* El velo vive aquí: Tailwind no puede aplicar /30 a un color en variable. */
    background: color-mix(in srgb, var(--black) 30%, transparent);
    -webkit-backdrop-filter: blur(2px);
            backdrop-filter: blur(2px);
    opacity: 0;
    transition: opacity 480ms var(--ease-out);
  }
  .s-slideover__panel {
    transform: translateX(102%);
    transition: transform 560ms cubic-bezier(0.16, 1, 0.3, 1);
    will-change: transform;
  }
  .s-slideover--visible .s-slideover__backdrop { opacity: 1; }
  .s-slideover--visible .s-slideover__panel { transform: translateX(0); }
  .s-slideover--cerrando .s-slideover__backdrop { transition-duration: 300ms; }
  .s-slideover--cerrando .s-slideover__panel {
    transition: transform 340ms cubic-bezier(0.4, 0, 1, 1);
  }
  @media (prefers-reduced-motion: reduce) {
    .s-slideover__backdrop,
    .s-slideover__panel {
      transition-duration: 0.01ms !important;
    }
  }

  /* Chip de elección (toggle) — respuesta táctil generosa, estado inequívoco */
  .s-choice {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 2.75rem;
    padding: 0 1.1rem;
    border: 1px solid var(--input);
    border-radius: var(--r-pill);
    background: var(--surface);
    font-family: var(--font-display);
    font-size: var(--fs-sm);
    font-weight: 500;
    color: var(--foreground);
    cursor: pointer;
    transition:
      border-color var(--t-fast) var(--ease-out),
      background-color var(--t-fast) var(--ease-out),
      color var(--t-fast) var(--ease-out),
      transform var(--t-fast) var(--ease-out);
  }
  .s-choice:hover { border-color: var(--foreground); }
  /* Escala Likert 1–5: cuadrada con radio corto — se lee como escala, no como toggle */
  .s-likert { display: inline-flex; gap: 0.5rem; }
  .s-likert__opcion {
    display: grid;
    place-items: center;
    width: 2.5rem; height: 2.5rem;
    border: 1px solid var(--input);
    border-radius: var(--r-1);
    background: var(--surface);
    font-family: var(--font-display);
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--foreground);
    transition: border-color var(--t-micro) var(--ease-out), background-color var(--t-micro) var(--ease-out),
      color var(--t-micro) var(--ease-out), transform var(--t-micro) var(--ease-out);
  }
  .s-likert__opcion:hover:not([aria-checked="true"]) { border-color: var(--foreground); }
  .s-likert__opcion[aria-checked="true"] {
    background: var(--foreground);
    border-color: var(--foreground);
    color: var(--background);
    transform: scale(1.08);
  }
  .s-likert__opcion:disabled { opacity: 0.5; cursor: default; }
  /* --compacto (operativo: escalas de captura, 1 a 10): el patrón de
     s-segmented. Un objeto con borde y esquinas concéntricas, opciones de
     32 px de alto (44 en táctil) y la elegida en tinta, sin escala ni
     rebote. Radios reales dentro (<label class="s-likert__opcion"><input
     type="radio">) o botones con aria-checked. En teléfono las opciones se
     reparten el ancho para que la escala completa quepa sin desplazarse. */
  .s-likert--compacto {
    gap: 0.125rem;
    padding: 0.125rem;
    max-inline-size: 100%;
    border: 1px solid var(--border);
    border-radius: var(--r-1);
    background: var(--surface);
    vertical-align: middle;
    justify-self: start;   /* en una rejilla no se estira: mide sus opciones */
  }
  .s-likert--compacto .s-likert__opcion {
    position: relative;
    inline-size: auto; min-inline-size: 2rem;
    block-size: 1.625rem;
    padding-inline: var(--s-1);
    border: 0;
    border-radius: calc(var(--r-1) - 0.125rem - 1px);
    background: transparent;
    font-family: var(--font-body);
    font-size: var(--fs-sm);
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    color: var(--muted-foreground);
    cursor: pointer;
    transition: color var(--t-micro) var(--ease-out), background-color var(--t-micro) var(--ease-out);
  }
  .s-likert--compacto .s-likert__opcion > input[type="radio"] { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
  @media (hover: hover) and (pointer: fine) { .s-likert--compacto .s-likert__opcion:hover { color: var(--foreground); } }
  .s-likert--compacto .s-likert__opcion:is([aria-checked="true"], :has(> input:checked)) { background: var(--foreground); color: var(--background); transform: none; }
  .s-likert--compacto .s-likert__opcion:has(> input:focus-visible) { outline: 2px solid var(--ring); outline-offset: 1px; }
  .s-likert--compacto .s-likert__opcion:has(> input:disabled) { opacity: 0.5; cursor: default; }
  @media (max-width: 767px), (pointer: coarse) {
    .s-likert--compacto { display: flex; inline-size: 100%; justify-self: stretch; }
    .s-likert--compacto .s-likert__opcion { flex: 1 1 0; min-inline-size: 0; block-size: 2.375rem; padding-inline: 0; }
  }

  /* Casilla (checkbox) del sistema: el cuadro y la palomita los dibuja la
     etiqueta (::before y ::after), el input real queda encima, invisible:
     funciona igual en todos los navegadores y la palomita toma el color del
     tema. <label class="s-check"><input type="checkbox">Texto</label>.
     Foco visible en el cuadro; deshabilitado; error con aria-invalid y el
     mensaje en .s-field__error. Toda la etiqueta es el blanco del toque. */
  .s-check {
    --s-check-pad: 0.375rem;
    position: relative;
    display: flex; align-items: flex-start; gap: var(--s-2);
    min-block-size: 2rem;
    padding-block: var(--s-check-pad);
    font-size: var(--fs-sm);
    line-height: 1.25rem;
    color: var(--foreground);
    cursor: pointer;
  }
  .s-check > input[type="checkbox"] { position: absolute; inset: 0; inline-size: 100%; block-size: 100%; margin: 0; opacity: 0; cursor: inherit; }
  .s-check::before {
    content: "";
    flex: none;
    box-sizing: border-box;
    inline-size: 1rem; block-size: 1rem;
    margin-block-start: 0.125rem;
    border: 1px solid var(--input);
    border-radius: calc(var(--r-1) / 2);
    background: var(--surface);
    transition: background-color var(--t-micro) var(--ease-out), border-color var(--t-micro) var(--ease-out);
  }
  .s-check::after {
    content: "";
    position: absolute;
    inset-inline-start: 0; inset-block-start: calc(var(--s-check-pad) + 0.125rem);
    inline-size: 1rem; block-size: 1rem;
    background: var(--background);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='m3.5 8.2 3 3 6-6.4' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 0.75rem no-repeat;
            mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='m3.5 8.2 3 3 6-6.4' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 0.75rem no-repeat;
    opacity: 0;
    transition: opacity var(--t-micro) var(--ease-out);
    pointer-events: none;
  }
  @media (hover: hover) and (pointer: fine) { .s-check:hover::before { border-color: var(--foreground); } }
  .s-check:has(> input:checked)::before { background: var(--foreground); border-color: var(--foreground); }
  .s-check:has(> input:checked)::after { opacity: 1; }
  .s-check:has(> input:focus-visible)::before { outline: 2px solid var(--ring); outline-offset: 2px; }
  .s-check:has(> input[aria-invalid="true"])::before { border-color: var(--destructive); }
  .s-check:has(> input:disabled) { color: var(--muted-foreground); cursor: not-allowed; }
  .s-check:has(> input:disabled)::before { border-color: var(--border); background: var(--muted); }
  .s-check:has(> input:disabled:checked)::before { border-color: var(--muted-foreground); background: var(--muted-foreground); }
  @media (max-width: 767px), (pointer: coarse) { .s-check { --s-check-pad: 0.75rem; min-block-size: 2.75rem; } }
  .s-choice:active { transform: scale(0.97); }
  .s-choice[aria-pressed="true"], .s-choice[aria-current="page"], .s-choice[aria-current="true"] {
    background: var(--foreground);
    border-color: var(--foreground);
    color: var(--background);
  }
  /* La palomita no reserva espacio: sin marcar mide 0 (el margen negativo
     anula el gap) y al marcar entra en 150 ms, ancho y opacidad, sin rebote:
     es una acción frecuente. Con reduced-motion solo funde. */
  .s-choice__check {
    display: inline-grid;
    place-items: center;
    inline-size: 0;
    margin-inline-end: -0.5rem;
    overflow: hidden;
    opacity: 0;
    font-size: 11px;
    transition: inline-size 150ms var(--ease-out), margin-inline-end 150ms var(--ease-out), opacity 150ms var(--ease-out);
  }
  .s-choice:is([aria-pressed="true"], [aria-current="page"], [aria-current="true"]) .s-choice__check {
    inline-size: 1rem;
    margin-inline-end: 0;
    opacity: 1;
    @starting-style { inline-size: 0; margin-inline-end: -0.5rem; opacity: 0; }
  }

  /* Slider editorial (distribución de porcentajes) */
  .s-range {
    -webkit-appearance: none;
    appearance: none;
    width: 100%;
    height: 2.75rem; /* zona táctil = misma altura que los campos */
    background: transparent;
    cursor: pointer;
  }
  .s-range::-webkit-slider-runnable-track {
    height: 4px;
    border-radius: 999px;
    background: linear-gradient(
      to right,
      var(--foreground) 0%,
      var(--foreground) var(--p, 0%),
      color-mix(in srgb, var(--foreground) 14%, transparent) var(--p, 0%),
      color-mix(in srgb, var(--foreground) 14%, transparent) 100%
    );
  }
  .s-range::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    margin-top: -7px;
    height: 18px;
    width: 18px;
    border-radius: 999px;
    background: var(--background);
    border: 2.5px solid var(--foreground);
    box-shadow: var(--sh-1);
    transition: transform var(--t-fast) var(--ease-out);
  }
  .s-range:hover::-webkit-slider-thumb { transform: scale(1.15); }
  .s-range:focus-visible { outline: none; }
  .s-range:focus-visible::-webkit-slider-thumb {
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--foreground) 15%, transparent);
  }
  .s-range::-moz-range-track {
    height: 4px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--foreground) 14%, transparent);
  }
  .s-range::-moz-range-progress {
    height: 4px;
    border-radius: 999px;
    background: var(--foreground);
  }
  .s-range::-moz-range-thumb {
    height: 13px;
    width: 13px;
    border-radius: 999px;
    background: var(--background);
    border: 2.5px solid var(--foreground);
  }

  /* Término con tooltip (glosario) */
  .s-term { position: relative; display: inline-block; }
  .s-term__trigger {
    color: inherit;
    text-decoration: underline dotted color-mix(in srgb, var(--foreground) 45%, transparent);
    text-decoration-thickness: 1px;
    text-underline-offset: 0.22em;
    cursor: help;
  }
  /* Término suelto (un rótulo, el nombre de un indicador en una celda): el
     disparador mide al menos 24 px de alto (WCAG 2.5.8). En una frase no. */
  .s-term__trigger--aislado { display: inline-flex; align-items: center; min-block-size: var(--s-5); text-align: start; }
  /* Ayuda en un ícono (etiquetas de cifras: sin subrayado, regla 27): 14 px
     en tinta tenue, área de 24 */
  .s-term__trigger--icono {
    display: inline-grid; place-items: center;
    inline-size: var(--s-5); block-size: var(--s-5);
    margin-block: calc((var(--s-5) - 1lh) / -2);
    vertical-align: middle;
    border-radius: var(--r-pill);
    color: var(--op-tinta-tenue, var(--muted-foreground));
    text-decoration: none;
    cursor: help;
  }
  .s-term__trigger--icono > .s-icono { inline-size: 0.875rem; block-size: 0.875rem; }
  @media (hover: hover) and (pointer: fine) { .s-term__trigger--icono:hover { color: var(--foreground); } }
  .s-term__tip {
    position: absolute;
    left: 50%;
    bottom: calc(100% + 0.6rem);
    z-index: var(--z-aviso);
    width: max-content;
    max-width: 20rem;
    transform: translateX(-50%) translateY(4px);
    display: grid;
    gap: 0.35rem;
    background: var(--ink);
    color: var(--paper);
    font-size: var(--fs-2xs);
    font-family: var(--font-body);
    font-weight: 400;
    letter-spacing: 0;
    text-transform: none;
    line-height: 1.45;
    text-align: left;
    padding: var(--s-3) var(--s-4);
    border-radius: var(--r-1);
    box-shadow: var(--sh-2);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity var(--t-fast) var(--ease-out), transform var(--t-fast) var(--ease-out);
  }
  .s-term__tip::after {
    content: "";
    position: absolute;
    top: 100%; left: 50%;
    transform: translateX(-50%);
    border: 5px solid transparent;
    border-top-color: var(--ink);
  }
  .s-term:hover .s-term__tip,
  .s-term__trigger:focus-visible + .s-term__tip {
    opacity: 1;
    visibility: visible;
    transform: translateX(-50%) translateY(0);
  }
  /* Se deja leer (regla 52, WCAG 1.4.13): abierto recibe el cursor, y un
     puente invisible cubre el hueco con el término para que no se cierre
     en el trayecto. Escape lo cierra sin mover el foco (lo hace la app). */
  .s-term__tip::before { content: ""; position: absolute; inset-inline: 0; top: 100%; block-size: 0.75rem; }
  .s-term__tip--abajo::before { top: auto; bottom: 100%; }
  .s-term:hover .s-term__tip,
  .s-term__trigger:focus-visible + .s-term__tip,
  .s-term__tip--flotante.s-term__tip--visible { pointer-events: auto; }
  /* Variante flotante (portal en body, posición fija): la coloca el componente
     y la flecha sigue al término con --flecha. No hereda el anclaje absoluto. */
  .s-term__tip--flotante {
    position: fixed;
    left: 0; bottom: auto;
    z-index: var(--z-aviso);
    transform: translateY(4px);
  }
  .s-term__tip--flotante.s-term__tip--visible { opacity: 1; visibility: visible; transform: translateY(0); }
  .s-term__tip--flotante::after { left: var(--flecha, 50%); }
  .s-term__tip--abajo::after {
    top: auto; bottom: 100%;
    border-top-color: transparent;
    border-bottom-color: var(--ink);
  }
  .s-term__tip-title {
    font-family: var(--font-display);
    font-size: var(--fs-xs);
    display: block;
  }
  .s-term__tip-formula {
    font-family: var(--font-display);
    font-weight: 600;
    background: color-mix(in srgb, var(--paper) 14%, transparent);
    padding: 0.2em 0.5em;
    width: fit-content;
  }
  .s-term__tip-fuente { opacity: 0.65; font-size: 0.95em; }

  /* Tabla */
  .s-table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
  .s-table th {
    font-family: var(--font-display);
    font-size: var(--fs-2xs);
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    text-align: left;
    color: var(--muted-foreground);
    padding: var(--s-3);
    border-bottom: 1.5px solid var(--foreground);
  }
  /* Columnas numéricas: el título se alinea con su contenido */
  .s-table th.text-right { text-align: right; }
  .s-table th.text-center { text-align: center; }
  .s-table td { padding: var(--s-3); border-bottom: 1px solid var(--border); }
  .s-table tbody tr { transition: background-color var(--t-fast) var(--ease-out); }
  .s-table tbody tr:hover { background: color-mix(in srgb, var(--foreground) 4%, transparent); }

  /* Aurora sarape (CSS puro) */
  .s-aurora {
    position: relative;
    overflow: hidden;
    background: var(--black);
    isolation: isolate;
  }
  .s-aurora::before,
  .s-aurora::after {
    content: "";
    position: absolute;
    inset: -30%;
    z-index: -1;
    filter: blur(48px) saturate(1.15);
    pointer-events: none;
  }
  .s-aurora::before {
    background:
      radial-gradient(38% 42% at 22% 28%, var(--sarape-orange) 0%, transparent 70%),
      radial-gradient(30% 36% at 68% 18%, var(--sarape-amber) 0%, transparent 70%),
      radial-gradient(34% 40% at 82% 66%, var(--sarape-pink) 0%, transparent 70%),
      radial-gradient(46% 48% at 38% 78%, var(--sarape-cyan) 0%, transparent 72%),
      radial-gradient(36% 42% at 62% 92%, var(--sarape-teal) 0%, transparent 70%);
    animation: s-aurora-drift 60s var(--ease-in-out) infinite alternate;
  }
  .s-aurora::after {
    background:
      radial-gradient(42% 46% at 50% 45%, rgba(5,5,5,0.85) 0%, transparent 68%),
      radial-gradient(30% 34% at 12% 80%, rgba(5,5,5,0.7) 0%, transparent 70%);
    animation: s-aurora-drift 76s var(--ease-in-out) infinite alternate-reverse;
  }
  .s-aurora--panel { border-radius: var(--r-0); min-height: 16rem; }
  /* Seda WebGL (AuroraCanvas): entre los radiales CSS y los pliegues oscuros (::after) */
  .s-aurora__canvas {
    position: absolute; inset: -6%; z-index: -1;
    width: 112%; height: 112%;
    display: block; pointer-events: none;
    /* El "diluido" de las referencias: desenfoque real sobre un lienzo a media resolución (barato) */
    filter: blur(clamp(10px, 1.6vw, 22px)) saturate(1.12);
    opacity: 0;
    transition: opacity var(--t-brand) var(--ease-out);
  }
  .s-aurora__canvas[data-estado="animado"], .s-aurora__canvas[data-estado="estatico"] { opacity: 1; }
  /* Con la seda activa, los pliegues oscuros CSS se atenúan: el shader ya trae los suyos */
  .s-aurora:has(.s-aurora__canvas[data-estado="animado"])::after,
  .s-aurora:has(.s-aurora__canvas[data-estado="estatico"])::after { opacity: 0.85; }
  /* v2 es clara por definición: los pliegues oscuros del CSS la apagarían */
  .s-aurora:has(.s-aurora__canvas[data-variante="v2"])::after { opacity: 0.15; }

  /* Protección de legibilidad (scrim): el degradado tiene zonas claras donde el
     texto blanco caía a 2.3:1. Un velo oscuro anclado a la esquina del
     contenido lo sube por encima de 4.5:1 sin apagar el color del resto.
     Medido sobre captura compuesta, no con axe (axe no evalúa un canvas). */
  .s-aurora__scrim {
    position: absolute;
    inset: 0;
    /* Encima del canvas (que va en -1 y antes en el DOM) y debajo del contenido,
       incluso cuando el contenido no crea contexto de apilamiento propio. */
    z-index: -1;
    pointer-events: none;
    /* Dos capas: la columna del contenido (izquierda) y el pie donde van las
       cifras. La esquina superior derecha queda limpia para el color. */
    background:
      linear-gradient(to right, rgba(5,5,5,0.80) 0%, rgba(5,5,5,0.52) 42%, rgba(5,5,5,0.10) 78%, transparent 100%),
      linear-gradient(to top, rgba(5,5,5,0.55) 0%, rgba(5,5,5,0.18) 45%, transparent 80%);
  }
  /* En teléfono el texto ocupa todo el ancho del bloque: la esquina limpia
     quedaba detrás del final de cada línea (título a 2.0:1 medido a 375 px).
     El velo cubre el ancho completo y se aclara hacia la derecha. */
  @media (max-width: 639px) {
    .s-aurora__scrim {
      background:
        linear-gradient(to right, rgba(5,5,5,0.78) 0%, rgba(5,5,5,0.64) 55%, rgba(5,5,5,0.56) 100%),
        linear-gradient(to top, rgba(5,5,5,0.55) 0%, transparent 70%);
    }
  }
  /* Píldoras sobre el degradado: por encima del grano (que las ensuciaba,
     "Corte oficial" a 4.2:1) y, las neutras (periodo, producto), con fondo
     propio: la esquina superior derecha queda sin velo y el texto caía a
     2.0:1. Las de estado (--success, …) ya traen el suyo. */
  .s-aurora .s-badge { position: relative; z-index: 1; }
  .s-aurora .s-badge:not([class*="s-badge--"]) {
    background: color-mix(in srgb, var(--black) 60%, transparent);
  }
  /* Tinte por línea de negocio (HIG/Tide Guide: la paleta sigue al contexto) */
  .s-aurora[style*="--aurora-tint"]::before {
    background:
      radial-gradient(60% 55% at 50% 50%, color-mix(in srgb, var(--aurora-tint) 55%, transparent) 0%, transparent 72%),
      radial-gradient(38% 42% at 22% 28%, var(--sarape-orange) 0%, transparent 70%),
      radial-gradient(30% 36% at 68% 18%, var(--sarape-amber) 0%, transparent 70%),
      radial-gradient(34% 40% at 82% 66%, var(--sarape-pink) 0%, transparent 70%),
      radial-gradient(46% 48% at 38% 78%, var(--sarape-cyan) 0%, transparent 72%),
      radial-gradient(36% 42% at 62% 92%, var(--sarape-teal) 0%, transparent 70%);
  }

  /* Zona: regla vertical de 2 px para marcar naturaleza distinta de bloque */
  .s-zone { border-left: 2px solid var(--foreground); padding-left: var(--s-4); }

  /* Barra de secciones (pestañas de página): subrayado, sin animación al cambiar */
  /* `min-inline-size: 0` es lo que hace efectivo el scroll: sin ello, dentro
     de un grid el elemento se dimensiona al contenido mínimo (pestañas sin
     cortar) y empuja el ancho de toda la página. */
  .s-tabs { display: flex; gap: var(--s-1); overflow-x: auto; min-inline-size: 0; border-bottom: 1px solid var(--border); }
  .s-tabs__tab {
    position: relative;
    /* No se encogen: con más pestañas de las que caben, la barra se desplaza */
    flex-shrink: 0;
    padding: var(--s-3) var(--s-3);
    font-family: var(--font-display);
    font-size: var(--fs-sm);
    font-weight: 600;
    color: var(--muted-foreground);
    white-space: nowrap;
    transition: color var(--t-micro) var(--ease-out);
  }
  .s-tabs__tab:hover { color: var(--foreground); }
  .s-tabs__tab[aria-current="true"], .s-tabs__tab[aria-current="page"], .s-tabs__tab[aria-current="step"] { color: var(--foreground); }
  .s-tabs__tab[aria-current="true"]::after, .s-tabs__tab[aria-current="page"]::after, .s-tabs__tab[aria-current="step"]::after {
    content: ""; position: absolute; left: var(--s-3); right: var(--s-3); bottom: -1px;
    height: 2px; background: var(--foreground);
  }

  /* --motion: un solo indicador que se desliza en 150 ms a la pestaña
     activa (la app fija --s-tabs-x y --s-tabs-ancho al cambiar). */
  .s-tabs--motion { position: relative; }
  .s-tabs--motion .s-tabs__tab::after { content: none !important; }
  .s-tabs__indicador {
    position: absolute; inset-block-end: 0; inset-inline-start: 0;
    inline-size: var(--s-tabs-ancho, 0px); block-size: 2px;
    translate: var(--s-tabs-x, 0px) 0;
    background: var(--foreground);
    pointer-events: none;
    transition: translate 150ms var(--ease-out), inline-size 150ms var(--ease-out);
  }
  :where(.s-operativo, .s-page) .s-tabs__indicador { background: var(--op-acento); }

  /* Control segmentado: un solo objeto para 2–4 opciones excluyentes
     (Activos/Históricos, línea de negocio, periodo). Sin JS: el estado vive
     en aria-pressed (botón) o aria-current (enlace). */
  .s-segmented {
    display: inline-flex;
    gap: 0.125rem;
    padding: 0.2rem;
    border: 1px solid var(--border);
    border-radius: var(--r-pill);
    background: var(--surface);
    max-width: 100%;
    overflow-x: auto;
  }
  .s-segmented__item {
    display: inline-flex;
    /* Sin encogerse: con más opciones de las que caben, el grupo se desplaza
       (overflow-x arriba). Encogido, el texto sin corte invadía al vecino. */
    flex-shrink: 0;
    align-items: center;
    gap: 0.4rem;
    padding: 0.5em 1.1em;
    border-radius: var(--r-pill);
    font-family: var(--font-display);
    font-size: var(--fs-xs);
    font-weight: 600;
    white-space: nowrap;
    color: var(--muted-foreground);
    transition: color var(--t-micro) var(--ease-out), background-color var(--t-micro) var(--ease-out);
  }
  /* Táctil: 44 px por debajo de 640 px, el mismo corte que los controles con
     `min-h-11 sm:min-h-0` (HIG, design-system §3.5). Escritorio sin cambio. */
  @media (max-width: 639.98px) {
    .s-segmented__item { min-height: 2.75rem; }
  }
  .s-segmented__item:hover { color: var(--foreground); }
  .s-segmented__item[aria-pressed="true"],
  .s-segmented__item[aria-current="true"],
  .s-segmented__item[aria-current="page"] { background: var(--foreground); color: var(--background); }
  /* Variante con pastilla deslizante (motion): el fondo lo pone la pastilla, no el ítem */
  .s-segmented--motion .s-segmented__item { position: relative; background: transparent; }
  .s-segmented--motion .s-segmented__item[aria-pressed="true"] { background: transparent; color: var(--background); }
  .s-segmented__pill { position: absolute; inset: 0; border-radius: var(--r-pill); background: var(--foreground); }

  /* Segmentado con radios reales dentro (flechas y foco del navegador):
     la opción marcada se pinta como la presionada */
  .s-segmented__item:has(> input) { position: relative; cursor: pointer; }
  .s-segmented__item > input[type="radio"] { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
  .s-segmented__item:has(> input:checked) { background: var(--foreground); color: var(--background); }
  .s-segmented__item:has(> input:focus-visible) { outline: 2px solid var(--ring); outline-offset: 1px; }
  .s-segmented--motion .s-segmented__item:has(> input:checked) { background: transparent; color: var(--background); }
  /* La pastilla va detrás del texto del ítem. Se desliza en 150 ms con
     --ease-out: la app la mueve (motion en React; en HTML, FLIP: la pone
     en la opción nueva con translate y scale de la posición anterior y los
     quita) y con prefers-reduced-motion no se anima (regla 42). */
  .s-segmented--motion .s-segmented__item { isolation: isolate; }
  .s-segmented__pill { z-index: -1; transform-origin: 0 50%; transition: translate 150ms var(--ease-out), scale 150ms var(--ease-out); }

  /* En el operativo el segmentado conserva su pastilla, su color y su
     animación; cambian las esquinas (regla 25): radio de control y
     concéntricas, interior = exterior − (borde + margen) = 6 − 3 = 3. 32 px de alto,
     44 en táctil. --compacto para tablas: 28 px, texto de 13, ancho del
     contenido; lo que se repite por fila es discreto (regla 37): la
     pastilla es superficie con borde, no tinta. --iconos: solo ícono, con
     aria-label y title. */
  :where(.s-operativo, .s-page) .s-segmented { padding: 0.125rem; border-radius: var(--r-1); vertical-align: middle; }
  :where(.s-operativo, .s-page) :is(.s-segmented__item, .s-segmented__pill) { border-radius: calc(var(--r-1) - 0.125rem - 1px); }
  :where(.s-operativo, .s-page) .s-segmented__item { justify-content: center; min-block-size: 1.625rem; padding-block: 0; }
  @media (max-width: 767px), (pointer: coarse) { :where(.s-operativo, .s-page) .s-segmented__item { min-block-size: 2.375rem; } }
  .s-segmented--compacto { background: var(--op-sup-2, var(--muted)); }
  :where(.s-operativo, .s-page) .s-segmented--compacto .s-segmented__item {
    min-block-size: 1.375rem;
    padding-inline: var(--s-2);
    font-family: var(--font-body);
    font-size: var(--fs-caption);
    font-weight: 500;
  }
  @media (max-width: 767px), (pointer: coarse) { :where(.s-operativo, .s-page) .s-segmented--compacto .s-segmented__item { min-block-size: 2.375rem; } }
  .s-segmented--compacto .s-segmented__pill,
  .s-segmented--compacto .s-segmented__item:is([aria-pressed="true"], [aria-current="true"], [aria-current="page"], :has(> input:checked)) { background: var(--surface); color: var(--foreground); box-shadow: 0 0 0 1px var(--border), var(--sh-1); }
  .s-segmented--compacto.s-segmented--motion .s-segmented__item:is([aria-pressed="true"], [aria-current="true"], [aria-current="page"], :has(> input:checked)) { background: transparent; box-shadow: none; color: var(--foreground); }
  .s-segmented--iconos .s-segmented__item { inline-size: 1.75rem; padding-inline: 0; }
  @media (max-width: 767px), (pointer: coarse) { .s-segmented--iconos .s-segmented__item { inline-size: 2.375rem; } }

  /* Enlace de navegación principal (topbar): texto, activo con línea inferior */
  .s-nav__link {
    position: relative;
    display: inline-flex;
    align-items: center;
    padding: 0.5rem 0.75rem;
    font-family: var(--font-display);
    font-size: var(--fs-sm);
    font-weight: 500;
    color: var(--muted-foreground);
    transition: color var(--t-micro) var(--ease-out);
  }
  .s-nav__link:hover { color: var(--foreground); }
  .s-nav__link[aria-current="page"] { color: var(--foreground); font-weight: 600; }
  .s-nav__link[aria-current="page"]::after {
    content: ""; position: absolute; left: 0.75rem; right: 0.75rem; bottom: -1.05rem;
    height: 2px; background: var(--foreground);
  }

  /* Contador de un destino de la barra superior (#3, hallazgo 1): la misma
     cápsula de 16 px que .s-tabbar__badge, en línea tras la etiqueta. */
  .s-nav__badge {
    display: inline-grid; place-items: center;
    min-inline-size: 1rem; block-size: 1rem;
    margin-inline-start: var(--s-2);
    padding-inline: var(--s-1);
    border-radius: var(--r-pill);
    background: var(--foreground);
    color: var(--background);
    font-size: var(--fs-2xs);
    font-weight: 600;
    line-height: 1;
    font-variant-numeric: tabular-nums;
  }

  /* Barra superior (#3, hallazgo 9): pegajosa, mide --topbar-h, así el
     encabezado pegajoso de las tablas y la regla del activo de
     .s-nav__link coinciden con ella sin cuadrar a mano. Va dentro de
     .s-shell, que define la variable; superficie .s-glass. */
  .s-topbar {
    position: sticky;
    inset-block-start: 0;
    z-index: var(--z-barra);
    display: flex; align-items: center; gap: var(--s-4);
    block-size: var(--topbar-h, 4.3125rem);
    padding-inline: var(--s-5);
    border-block-end: 1px solid var(--border);
  }
  .s-topbar .s-nav__link[aria-current="page"]::after { bottom: calc((100% - var(--topbar-h, 100%)) / 2); }
  @media (max-width: 640px) { .s-topbar { padding-inline: var(--s-4); } }

  /* Luz ambiental (páginas claras): la aurora entra por la esquina superior
     derecha del VIEWPORT y se desvanece por máscara antes de cualquier borde
     interior; solo el borde derecho de la ventana la corta, como en el deck.
     Regla del sistema: un degradado nunca se recorta con el contenedor de
     contenido (se ve como un parche); se ancla al marco de la página
     (.s-shell) y se apaga con máscara. Estática, sin filter: blur. Mezcla
     ≤ 10 % con el papel donde pueda haber texto (AA se mantiene). */
  .s-shell { position: relative; isolation: isolate; overflow-x: clip; }
  /* Altura de la barra pegajosa: lo que las pestañas y las barras del editor
     necesitan para pegarse justo debajo y no meterse bajo ella. Impacto mide
     69 px en teléfono (py-3) y 77 px desde sm (py-4); una app con otra barra
     sobreescribe la variable en su .s-shell. */
  .s-shell { --topbar-h: 4.3125rem; }
  @media (min-width: 640px) { .s-shell { --topbar-h: 4.8125rem; } }
  /* Superficie translúcida de las barras pegajosas (topbar, pestañas, barras del
     editor): papel al 90 % con desenfoque, para que el texto negro y el logo
     sigan legibles sobre un hero oscuro o una imagen. Vive aquí y no como
     `bg-[--background]/90` porque Tailwind no puede aplicar un modificador de
     opacidad a un color que viene en variable: esa clase compilaba a nada y
     las barras quedaban transparentes. La barra inferior (.s-tabbar) es la
     misma superficie. */
  .s-glass, .s-tabbar, .s-topbar {
    background: color-mix(in srgb, var(--background) 90%, transparent);
    -webkit-backdrop-filter: blur(8px);
            backdrop-filter: blur(8px);
  }
  .s-glass--opaco { background: color-mix(in srgb, var(--background) 96%, transparent); }
  .s-ambient-light {
    position: absolute;
    top: 0; right: 0;
    width: min(64vw, 58rem); height: 42rem;
    z-index: -1;
    pointer-events: none;
    background:
      radial-gradient(42% 46% at 78% 22%, color-mix(in srgb, var(--sarape-pink) 26%, transparent) 0%, transparent 70%),
      radial-gradient(40% 44% at 92% 48%, color-mix(in srgb, var(--sarape-orange) 22%, transparent) 0%, transparent 70%),
      radial-gradient(38% 42% at 60% 12%, color-mix(in srgb, var(--sarape-cyan) 24%, transparent) 0%, transparent 70%),
      radial-gradient(34% 40% at 46% 40%, color-mix(in srgb, var(--sarape-amber) 14%, transparent) 0%, transparent 72%);
    /* La elipse de la máscara llega a transparente antes del borde izquierdo e inferior de la caja */
    -webkit-mask-image: radial-gradient(58% 62% at 86% 18%, #000 0%, rgba(0,0,0,0.55) 48%, transparent 100%);
            mask-image: radial-gradient(58% 62% at 86% 18%, #000 0%, rgba(0,0,0,0.55) 48%, transparent 100%);
  }
  @media (max-width: 767px), (prefers-contrast: more) {
    .s-ambient-light { display: none; }
  }

  /* --------------------------------------------- Navegación en tres niveles
     1 barra superior (.s-shell + .s-nav__link) · 2 pestañas de la entidad
     (.s-tabs) · 3 hub de configuración (.s-sidenav). En teléfono los destinos
     de la barra superior pasan a .s-tabbar (ADR-003). El activo nunca es solo
     color: peso 600 y una regla de 2 px, como en .s-tabs. */

  /* Barra lateral del hub de configuración (Linear, Stripe): grupos por
     intención con título, activo por aria-current="page". Columna fija y
     pegajosa desde 768 px; debajo, lista a todo el ancho con reglas hairline
     (mismo corte que .s-field__input). 15rem es el ancho de las referencias
     (240 px): el único valor nuevo, no hay token de ancho de columna. */
  .s-sidenav { display: grid; gap: var(--s-5); align-content: start; }
  .s-sidenav__grupo { display: grid; gap: var(--s-1); }
  .s-sidenav ul, .s-sidenav ol { display: grid; gap: 0.125rem; margin: 0; padding: 0; list-style: none; }
  .s-sidenav__titulo {
    margin: 0;
    padding-inline: var(--s-3);
    font-family: var(--font-display);
    font-size: var(--fs-xs);
    font-weight: 700;
    font-variation-settings: "wdth" 100;
    line-height: var(--lh-base);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--muted-foreground);
  }
  .s-sidenav__link {
    position: relative;
    display: flex; align-items: center; gap: var(--s-2);
    min-block-size: 2.5rem;
    padding: var(--s-2) var(--s-3);
    border-radius: var(--r-1);
    font-family: var(--font-display);
    font-size: var(--fs-sm);
    font-weight: 500;
    color: var(--muted-foreground);
    text-decoration: none;
    transition: color var(--t-micro) var(--ease-out), background-color var(--t-micro) var(--ease-out);
  }
  .s-sidenav__link:hover { color: var(--foreground); background: color-mix(in srgb, var(--foreground) 4%, transparent); }
  .s-sidenav__link[aria-current="page"] {
    color: var(--foreground);
    font-weight: 600;
    background: color-mix(in srgb, var(--foreground) 8%, transparent);
  }
  .s-sidenav__link[aria-current="page"]::before {
    content: ""; position: absolute; inset-block: var(--s-2); inset-inline-start: 0;
    inline-size: 2px; border-radius: var(--r-pill); background: var(--foreground);
  }
  /* Anillo hacia dentro: en una lista con scroll el de 3 px hacia fuera se corta */
  .s-sidenav__link:focus-visible { outline-offset: -2px; border-radius: var(--r-1); }
  /* Táctil: 44 px (HIG), como .s-segmented__item; escritorio con puntero fino, 40 */
  @media (max-width: 767px), (pointer: coarse) {
    .s-sidenav__link { min-block-size: 2.75rem; }
  }
  @media (max-width: 767px) {
    .s-sidenav ul, .s-sidenav ol { gap: 0; }
    .s-sidenav__link { border-radius: 0; border-bottom: 1px solid var(--border); }
    .s-sidenav li:last-child > .s-sidenav__link { border-bottom: 0; }
  }
  @media (min-width: 768px) {
    .s-sidenav {
      inline-size: 15rem;
      flex-shrink: 0;
      align-self: start;
      position: sticky;
      inset-block-start: calc(var(--topbar-h, 0px) + var(--s-5));
      max-block-size: calc(100dvh - var(--topbar-h, 0px) - var(--s-6));
      overflow-y: auto;
      overscroll-behavior: contain;
    }
  }

  /* Barra de pestañas inferior (Apple HIG, tab bar): solo en teléfono (hasta
     639.98 px; desde 640 la barra superior muestra sus destinos, igual que
     `sm:`). Hasta cinco destinos, icono y etiqueta corta; superficie .s-glass.
     Libera su alto al final de .s-shell con --tabbar-h, incluida la zona
     segura del iPhone (requiere viewport-fit=cover). */
  .s-tabbar { display: none; }
  @media (max-width: 639.98px) {
    .s-shell { --tabbar-h: calc(3.25rem + 1px + env(safe-area-inset-bottom, 0px)); }
    .s-shell:has(.s-tabbar) { padding-block-end: var(--tabbar-h); }
    .s-tabbar {
      position: fixed;
      inset-inline: 0; inset-block-end: 0;
      /* Encima del contenido, debajo de los tooltips (60/70) y del slide-over */
      z-index: var(--z-barra);
      display: grid;
      grid-auto-flow: column;
      grid-auto-columns: minmax(0, 1fr);
      padding-block-end: env(safe-area-inset-bottom, 0px);
      padding-inline: max(var(--s-1), env(safe-area-inset-left, 0px)) max(var(--s-1), env(safe-area-inset-right, 0px));
      border-block-start: 1px solid var(--border);
    }
  }
  .s-tabbar__item {
    position: relative;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 0.125rem;
    min-block-size: 3.25rem;
    padding: var(--s-1) 0.125rem;
    font-family: var(--font-display);
    font-size: var(--fs-2xs);
    font-weight: 500;
    /* Archivo estrecha (eje wdth de la identidad): con cinco destinos a 375 px
       "Configuración" cabe completa (67.5 de 69 px); a 320 entra la elipsis. */
    font-variation-settings: "wdth" 88;
    letter-spacing: -0.01em;
    line-height: var(--lh-heading);
    color: var(--muted-foreground);
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;
    transition: color var(--t-micro) var(--ease-out);
  }
  .s-tabbar__icono {
    inline-size: var(--s-5); block-size: var(--s-5);
    flex-shrink: 0;
    transition: transform var(--t-micro) var(--ease-out);
  }
  .s-tabbar__item:active .s-tabbar__icono { transform: scale(0.9); }
  /* Etiqueta corta; si una no cabe en 75 px, se corta con elipsis y no empuja al vecino */
  .s-tabbar__etiqueta { max-inline-size: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .s-tabbar__item[aria-current="page"], .s-tabbar__item[aria-current="true"] { color: var(--foreground); font-weight: 600; }
  .s-tabbar__item[aria-current="page"]::before, .s-tabbar__item[aria-current="true"]::before {
    content: ""; position: absolute; inset-block-start: -1px; inset-inline: 30%;
    block-size: 2px; background: var(--foreground);
  }
  .s-tabbar__item:focus-visible { outline-offset: -2px; border-radius: var(--r-1); }
  /* Contador: cápsula de 16 px en la esquina superior derecha del ícono,
     con aro de 2 px del color de la barra. Va en el marcado entre el ícono y
     la etiqueta: los márgenes la suben al ícono sin mover la etiqueta
     (−30 + 16 + 12 + el gap de 2 = 0), y translateX la lleva a 4 px a la
     derecha del centro del ícono, crezca lo que crezca la cifra. */
  .s-tabbar__badge {
    position: relative;
    z-index: 1;
    display: inline-grid; place-items: center;
    align-self: center;
    min-inline-size: 1rem; block-size: 1rem;
    margin-block: -1.875rem 0.75rem;
    padding-inline: 0.25rem;
    border-radius: var(--r-pill);
    background: var(--foreground);
    color: var(--background);
    box-shadow: 0 0 0 2px var(--background);
    font-size: var(--fs-2xs);
    font-weight: 600;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0;
    transform: translateX(calc(50% + 0.25rem));
  }
  /* Más contraste o menos transparencia: barra opaca, sin desenfoque */
  @media (prefers-contrast: more), (prefers-reduced-transparency: reduce) {
    .s-tabbar { background: var(--background); -webkit-backdrop-filter: none; backdrop-filter: none; }
  }

  /* Tabla contenida en superficie (homes: pocas filas, fila = enlace) */
  .s-table-surface {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--r-2);
    padding: 0 var(--s-5);
    overflow-x: auto;
    min-inline-size: 0;
  }
  .s-table-surface .s-table td { padding: var(--s-4) var(--s-3); }
  .s-table-surface .s-table tbody tr:last-child td { border-bottom: 0; }
  .s-table-surface .s-table tbody tr:hover { background: transparent; }
  /* Zona punteada: solo donde se sueltan archivos (carga de evidencia).
     Un estado vacío no es una zona de arrastre: es .s-vacio (0.6.0). */
  .s-dashed {
    border: 1.5px dashed var(--input);
    border-radius: var(--r-2);
    background: var(--surface);
    transition: border-color var(--t-micro) var(--ease-out), background-color var(--t-micro) var(--ease-out);
  }
  .s-dashed:hover, .s-dashed[aria-pressed="true"], .s-dashed[data-activo="true"] { border-color: var(--foreground); }

  /* Bloque auxiliar dentro de un editor (ayuda plegable, panel de distribución) */
  .s-inset {
    border: 1px solid var(--border);
    border-radius: var(--r-1);
    background: var(--surface);
  }

  /* La flecha se ve pequeña pero su área táctil no lo es: en un teléfono es la
     forma de entrar a un proyecto desde la tabla, y a 14 px no se atina
     (WCAG 2.5.8 pide 24; aquí se da el 44 de la HIG). */
  .s-table__arrow {
    display: inline-grid;
    place-items: center;
    min-inline-size: 44px;
    min-block-size: 44px;
    margin-block: -11px;
    transition: transform var(--t-micro) var(--ease-out), opacity var(--t-micro) var(--ease-out);
  }
  .s-table tbody tr:hover .s-table__arrow { transform: translateX(4px); }

  /* Título de editor: un paso por debajo del de detalle (spec §4.3) */
  .s-title-editor { font-size: var(--fs-3xl); letter-spacing: -0.024em; }

  /* Skeleton (Geist): misma forma que el contenido; aparece tras 200 ms; sin shimmer con reduced-motion */
  .s-skeleton {
    background: color-mix(in srgb, var(--foreground) 8%, transparent);
    border-radius: var(--r-1);
    opacity: 0;
    animation: s-skeleton-in var(--t-micro) linear 200ms forwards, s-shimmer 1.2s linear 200ms infinite;
    background-image: linear-gradient(90deg, transparent 0%, color-mix(in srgb, var(--foreground) 6%, transparent) 50%, transparent 100%);
    background-size: 200% 100%;
  }
  .s-skeleton--text { height: 0.9em; width: 100%; }
  .s-skeleton--pill { border-radius: var(--r-pill); }
  .s-grain {
    position: absolute; inset: 0; z-index: 0;
    pointer-events: none;
    opacity: 0.5;
    mix-blend-mode: overlay;
    background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="160" height="160"><filter id="n"><feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2"/><feColorMatrix type="saturate" values="0"/></filter><rect width="160" height="160" filter="url%28%23n%29" opacity="0.35"/></svg>');
  }

  /* ================================================== Registro operativo
     Pantallas de trabajo: listas, detalles, administración, tableros
     (ADR-004; análisis en docs/analisis-registro-operativo.md). Tema arriba,
     fuera de capa. Todo lo que ajusta clases existentes se limita a
     .s-operativo o .s-page: fuera de ahí nada cambia de valor.
     Reglas: base 14 px; jerarquía por peso y tinta; controles de 32–36 px
     con radio de 6; filas de 48 (44 en --compacta) con 24 (16) de aire;
     un solo acento (activo, foco); retícula de 8. Táctil: 44 px con
     puntero grueso o por debajo de 768. */

  /* Ícono de trazo (lucide, viewBox 24): 16 px, trazo 1.5, color del texto.
     Marcado: <svg class="s-icono" viewBox="0 0 24 24" fill="none"
     stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
     aria-hidden="true">. */
  /* inline-block: el preflight de Tailwind pone los svg en block y el ícono
     junto a texto saltaba de línea. */
  .s-icono { display: inline-block; inline-size: 1rem; block-size: 1rem; flex-shrink: 0; stroke-width: 1.5; vertical-align: -0.1875em; }

  /* Etiquetas de campo en sentence case, 13 px / 500, sin tracking: en el
     operativo no van en mayúsculas espaciadas (eran casi todas las que le
     quedaban a Foros). Siguen en tinta media. */
  :where(.s-operativo, .s-page) :is(.s-field__label, .s-numfield__label) {
    font-family: var(--font-body);
    font-size: var(--fs-caption);
    font-weight: 500;
    letter-spacing: 0;
    text-transform: none;
  }
  /* El chip es metadato (tipo, adjuntos, conteo): gris de 12 px, no
     bloque de tinta. Con title, cursor de ayuda; --success y
     --destructive para una variación con tono. */
  :where(.s-operativo, .s-page) .s-chip {
    gap: var(--s-1);
    block-size: 1.25rem;
    padding: 0 0.375rem;
    border-radius: var(--r-1);
    background: var(--op-sup-2);
    color: var(--muted-foreground);
    font-family: var(--font-body);
    font-size: var(--fs-xs);
    font-weight: 500;
    line-height: 1;
    white-space: nowrap;
  }
  :where(.s-operativo, .s-page) .s-chip[title] { cursor: help; }
  /* Chip de selección (s-choice) en el operativo: esquinas de control, no
     pastilla; 32 px (44 en táctil); la palomita de la regla 20. */
  :where(.s-operativo, .s-page) .s-choice {
    min-block-size: 2rem;
    padding: 0 var(--s-3);
    border-radius: var(--r-1);
    font-family: var(--font-body);
    font-size: var(--fs-sm);
    font-weight: 500;
  }
  @media (max-width: 767px), (pointer: coarse) { :where(.s-operativo, .s-page) .s-choice { min-block-size: 2.75rem; } }
  /* Elegido sin tinta llena (regla 37): fondo tenue de superficie, borde
     en tinta, palomita y texto en tinta. La tinta llena queda para el
     primario y los numerales. */
  :where(.s-operativo, .s-page) .s-choice:is([aria-pressed="true"], [aria-current="page"], [aria-current="true"]) {
    background: var(--op-sup-3, var(--muted));
    border-color: var(--foreground);
    color: var(--foreground);
  }
  :where(.s-operativo, .s-page) .s-chip > .s-icono { inline-size: 0.875rem; block-size: 0.875rem; }
  :where(.s-operativo, .s-page) .s-chip--success { background: var(--success-soft); color: var(--success); }
  :where(.s-operativo, .s-page) .s-chip--destructive { background: var(--destructive-soft); color: var(--destructive); }
  /* La barra superior se alinea con el margen de .s-page */
  :where(.s-operativo) .s-topbar { padding-inline: var(--s-7); }
  @media (max-width: 640px) { :where(.s-operativo) .s-topbar { padding-inline: var(--s-4); } }

  /* Avatar: inicial en tinta sobre superficie, borde hairline */
  .s-avatar {
    display: inline-grid; place-items: center;
    inline-size: var(--s-6); block-size: var(--s-6); flex-shrink: 0;
    border: 1px solid var(--border);
    border-radius: var(--r-pill);
    background: var(--surface);
    color: var(--foreground);
    font-family: var(--font-display);
    font-size: var(--fs-sm);
    font-weight: 600;
    line-height: 1;
  }
  /* Avatar junto al nombre en una celda: 24 px */
  .s-avatar--sm { inline-size: var(--s-5); block-size: var(--s-5); background: var(--op-sup-2, var(--muted)); border-color: transparent; font-size: var(--fs-2xs); }

  /* Barra superior de 56 px (48–56 en el análisis): --topbar-h y el
     subrayado activo se anclan a ella; el activo lleva el acento. */
  :where(.s-operativo) .s-shell, .s-shell:where(.s-operativo) { --topbar-h: 3.5rem; }
  :where(.s-operativo, .s-page) .s-nav__link { gap: var(--s-2); }
  :where(.s-operativo, .s-page) .s-nav__link[aria-current="page"]::after {
    bottom: calc((100% - var(--topbar-h, 100%)) / 2);
    background: var(--op-acento);
  }
  :where(.s-operativo, .s-page) .s-tabs__tab[aria-current]::after { background: var(--op-acento); }
  :where(.s-operativo, .s-page) .s-tabbar__item[aria-current]::before { background: var(--op-acento); }
  /* Barra lateral del hub: títulos en sentence case (sin mayúsculas
     espaciadas), enlaces de 36 px con ícono, activo en superficie 3 con la
     regla del acento. */
  :where(.s-operativo, .s-page) .s-sidenav__titulo {
    font-size: var(--fs-sm);
    font-weight: 600;
    font-variation-settings: normal;
    letter-spacing: 0;
    text-transform: none;
    color: var(--muted-foreground);
  }
  :where(.s-operativo, .s-page) .s-sidenav__link { min-block-size: 2.25rem; padding-block: var(--s-1); }
  :where(.s-operativo, .s-page) .s-sidenav__link:hover { background: transparent; }
  :where(.s-operativo, .s-page) .s-sidenav__link[aria-current="page"] { background: var(--op-sup-3); }
  :where(.s-operativo, .s-page) .s-sidenav__link[aria-current="page"]::before { background: var(--op-acento); }
  @media (hover: hover) and (pointer: fine) {
    :where(.s-operativo, .s-page) .s-sidenav__link:not([aria-current="page"]):hover { background: var(--op-sup-2); }
  }
  @media (max-width: 767px), (pointer: coarse) {
    :where(.s-operativo, .s-page) .s-sidenav__link { min-block-size: 2.75rem; }
  }
  /* Nada queda bajo la barra ni bajo el encabezado pegajoso al enfocar */
  :root:has(.s-operativo) { scroll-padding-block: 7rem 1rem; }
  @media (max-width: 639.98px) {
    :root:has(.s-operativo) { scroll-padding-block-end: calc(3.25rem + 1px + env(safe-area-inset-bottom, 0px) + 1rem); }
  }
  /* Con barra de guardar, el documento reserva su alto para que el foco
     nunca quede debajo (WCAG 2.4.11). --s-guardar-alto es un alto holgado
     de una línea; una app que mide su barra puede fijarlo en :root. En
     teléfono la barra ocupa hasta dos renglones (≈ 153 px medido en la
     maqueta) y va sobre .s-tabbar. */
  :root:has(.s-guardar) { scroll-padding-block-end: calc(var(--s-guardar-alto, 4.5rem) + 1rem); }
  @media (max-width: 639.98px) {
    :root:has(.s-guardar) { scroll-padding-block-end: calc(var(--s-guardar-alto, 10rem) + 3.25rem + 1px + env(safe-area-inset-bottom, 0px) + 1rem); }
  }
  :where(.s-operativo, .s-page) :is(a, button, summary) { -webkit-tap-highlight-color: transparent; touch-action: manipulation; }

  /* Botones: 36 px (32 en --sm), radio de 6, sin pastilla, sin brillo ni
     elevación en hover. Presionar escala 0.97 en 160 ms; el hover solo
     cambia color y solo con puntero fino. Un primario por pantalla. */
  :where(.s-operativo, .s-page) .s-btn {
    block-size: 2.25rem;
    padding: 0 var(--s-4);
    border-width: 1px;
    border-radius: var(--r-1);
    font-family: var(--font-body);
    font-size: var(--fs-sm);
    font-weight: 500;
    transition: transform 160ms var(--ease-out), background-color var(--t-micro) var(--ease-out), border-color var(--t-micro) var(--ease-out), color var(--t-micro) var(--ease-out);
  }
  :where(.s-operativo, .s-page) .s-btn--sm { block-size: 2rem; padding: 0 var(--s-3); font-size: var(--fs-sm); }
  :where(.s-operativo, .s-page) .s-btn--primary::after { display: none; }
  /* Con el mismo :not() que el hover base (0.5.0): si no, la base gana por
     especificidad y el contorno quedaba con texto claro sobre fondo claro
     (1.05:1) y el primario recuperaba sombra y elevación. */
  :where(.s-operativo, .s-page) .s-btn--primary:not(:disabled, [aria-disabled="true"]):hover { box-shadow: none; transform: none; }
  :where(.s-operativo, .s-page) .s-btn--outline { border-color: var(--border); background: var(--surface); color: var(--foreground); }
  :where(.s-operativo, .s-page) .s-btn--outline:not(:disabled, [aria-disabled="true"]):hover { background: var(--surface); color: var(--foreground); }
  :where(.s-operativo, .s-page) .s-btn:focus-visible { outline-offset: 2px; border-radius: var(--r-1); }
  :where(.s-operativo, .s-page) .s-btn--destructive { background: var(--surface); }
  /* Táctil: 44 px también en --sm (HIG); con puntero fino, 36 y 32 */
  @media (max-width: 767px), (pointer: coarse) {
    :where(.s-operativo, .s-page) .s-btn { block-size: 2.75rem; }
  }
  @media (hover: hover) and (pointer: fine) {
    :where(.s-operativo, .s-page) .s-btn--primary:not(:disabled):hover { background: color-mix(in lch, var(--foreground) 86%, var(--background)); }
    :where(.s-operativo, .s-page) .s-btn--outline:not(:disabled, [aria-disabled="true"]):hover { background: var(--op-sup-2); color: var(--foreground); }
  }
  /* Pastilla de identidad (unidad, producto, "ENBE"), no de estado: 20 px */
  :where(.s-operativo, .s-page) .s-badge {
    block-size: 1.25rem;
    padding: 0 var(--s-2);
    border: 1px solid var(--border);
    background: transparent;
    color: var(--muted-foreground);
    font-family: var(--font-body);
    font-size: var(--fs-2xs);
    font-weight: 500;
    letter-spacing: 0;
    line-height: 1;
    text-transform: none;
  }

  /* Página de trabajo: cabecera (título de 28 px en Archivo al 112 %,
     descripción en tinta media, acciones), bloques con aire de B. */
  .s-page {
    display: grid; gap: var(--s-7); align-content: start;
    min-inline-size: 0; max-inline-size: 80rem;
    margin-inline: auto;
    padding: var(--s-6) var(--s-7) var(--s-8);
    font-size: var(--fs-sm);
    line-height: 1.5rem;
  }
  @media (max-width: 640px) { .s-page { gap: var(--s-5); padding: var(--s-5) var(--s-4) var(--s-7); } }
  .s-page__header { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: var(--s-2) var(--s-4); }
  .s-page__texto { display: grid; min-inline-size: 0; }
  .s-page__titulo {
    margin: 0;
    font-family: var(--font-display);
    font-size: var(--fs-page);
    font-weight: 600;
    /* font-stretch y no font-variation-settings: la base de h1 fija wdth 112
       con variation-settings, que ganaría; se anula para usar el eje por nombre */
    font-variation-settings: normal;
    font-stretch: 112%;
    letter-spacing: -0.02em;
    line-height: 2rem;
    text-wrap: balance;
  }
  .s-page__descripcion { margin: 0; color: var(--muted-foreground); }
  /* Cabecera de una pieza. --entidad (regla 27, como el proyecto de Linear
     o el cliente de Stripe): migas; fila del título con su estado y tipo
     junto a él y las acciones a la derecha; UNA línea de metadatos
     (.s-page__meta: Cliente · Línea · Periodo, íconos de 14) a 8 px del
     título; pestañas a 24 px. Sin caja (el degradado estático vive en el
     marco, .s-ambient-light) y sin cifras: las cifras son la primera
     sección de la pestaña Resumen. --marca con la aurora, solo en el
     inicio de un rol. */
  .s-page__header--entidad, .s-page__header--marca { display: grid; align-items: initial; justify-content: initial; gap: var(--s-3); }
  .s-page__header--entidad { gap: var(--s-2); }
  .s-page__header--entidad > :is(.s-tabs, .s-pasos) { margin-block-start: var(--s-4); }
  .s-page__header--marca { padding: var(--s-6) var(--s-6) var(--s-5); border-radius: var(--r-2); color: var(--foreground); }
  .s-page__header--marca .s-indicadores { padding-block-start: var(--s-4); border-block-start: 1px solid var(--border); }
  .s-page__header--marca .s-page__descripcion { max-inline-size: 40rem; }
  .s-page__meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-1) var(--s-4); margin: 0; padding: 0; list-style: none; color: var(--muted-foreground); }
  .s-page__meta > li { display: inline-flex; align-items: center; gap: 0.375rem; min-inline-size: 0; }
  .s-page__meta .s-icono { inline-size: 0.875rem; block-size: 0.875rem; }
  @media (max-width: 640px) {
    .s-page__header--marca { padding: var(--s-5) var(--s-4) var(--s-4); }
    .s-page__header--marca { gap: var(--s-2); }
    .s-page__titulo { line-height: 1.75rem; }
    .s-page__header .s-indicadores { row-gap: var(--s-3); }
    .s-page__header .s-indicadores__cifra { font-size: var(--fs-lg); line-height: 1.75rem; }
    .s-page__header .s-indicadores__etiqueta { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    .s-page__header .s-page__principal .s-page__descripcion { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1; overflow: hidden; }
    .s-page__header--entidad > :is(.s-tabs, .s-pasos) { margin-block-start: var(--s-2); }
  }
  .s-page__ruta { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--s-2) var(--s-3); margin: 0; color: var(--muted-foreground); }
  .s-page__ruta a { color: inherit; text-underline-offset: 0.2em; }
  .s-page__contexto { color: var(--muted-foreground); }
  .s-page__titular { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2) var(--s-3); }
  /* Lo que acompaña al título (estado, tipo de corte, "Historia
     ilustrativa") va junto a él, no flotando en una esquina */
  .s-page__titular > :not(.s-page__titulo) { flex: none; }
  .s-page__principal { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--s-3); }
  .s-page__acciones { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); }
  .s-page__bloque { display: grid; gap: var(--s-4); min-inline-size: 0; }
  .s-page__seccion {
    display: flex; align-items: baseline; gap: var(--s-2);
    margin: 0;
    font-family: var(--font-display);
    font-size: var(--fs-sm);
    font-weight: 600;
    font-variation-settings: normal;
    letter-spacing: 0;
    line-height: 1.5rem;
    text-transform: none;
  }
  .s-page__contador { font-weight: 500; color: var(--muted-foreground); font-variant-numeric: tabular-nums; }
  /* Superficie 1 con borde hairline: panel (cifras, formularios) y objeto
     (tabla; `clip` redondea sin volverse contenedor de scroll, así el
     encabezado sigue pegándose bajo la barra). */
  .s-page__panel { padding: var(--s-5); background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-2); }
  .s-page__objeto { min-inline-size: 0; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-2); overflow: clip; }
  @media (max-width: 640px) { .s-page__panel { padding: var(--s-4); } }

  /* Indicadores: la cifra de 32 px al 112 % es el único momento expresivo.
     Variación a 12 px (§5), en tinta media o con tono; en oscuro, -edge. */
  .s-indicadores { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); margin: 0; }
  .s-indicadores__celda {
    display: grid; align-content: start;
    min-inline-size: 0;
    padding-inline: var(--s-5);
    border-inline-start: 1px solid var(--border);
  }
  .s-indicadores__celda:first-child { padding-inline-start: 0; border-inline-start: 0; }
  .s-indicadores__celda > dd { margin: 0; }
  @media (max-width: 640px) {
    .s-indicadores { grid-auto-flow: row; grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: var(--s-5); }
    .s-indicadores__celda { padding-inline: var(--s-4); }
    .s-indicadores__celda:nth-child(odd) { padding-inline-start: 0; border-inline-start: 0; }
  }
  .s-indicadores__etiqueta { font-weight: 500; color: var(--muted-foreground); }
  .s-indicadores__cifra {
    font-family: var(--font-display);
    font-size: var(--fs-2xl);
    font-weight: 600;
    font-variation-settings: normal;
    font-stretch: 112%;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.02em;
    line-height: 2.5rem;
  }
  .s-indicadores__variacion { font-size: var(--fs-xs); font-weight: 500; line-height: 1rem; color: var(--muted-foreground); font-variant-numeric: tabular-nums; }
  .s-indicadores__variacion--success { color: var(--success); }
  .s-indicadores__variacion--warning { color: var(--warning); }
  .s-indicadores__variacion--destructive { color: var(--destructive); }
  [data-theme="dark"] .s-indicadores__variacion--success { color: var(--success-edge); }
  [data-theme="dark"] .s-indicadores__variacion--warning { color: var(--warning-edge); }
  [data-theme="dark"] .s-indicadores__variacion--destructive { color: var(--destructive-edge); }

  /* Barra de filtros de una línea (Linear): búsqueda de 36 px con borde
     hairline, disparadores de 32, chips rellenos de 28 con quitar,
     "Limpiar" y resultados en vivo. En teléfono, "Filtros (n)". */
  .s-filtros { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); }
  .s-filtros__lista { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); }
  .s-filtros__buscar { position: relative; flex: 0 1 20rem; color: var(--muted-foreground); }
  .s-filtros__buscar > .s-icono { position: absolute; inset-block: 0; inset-inline-start: var(--s-3); margin-block: auto; pointer-events: none; }
  .s-filtros__busqueda {
    /* El preflight de Tailwind 3 lo pone en textfield y el de 4 no: se fija aquí */
    -webkit-appearance: none;
    appearance: none;
    inline-size: 100%;
    block-size: 2.25rem;
    padding: 0 var(--s-3) 0 calc(var(--s-3) + 1rem + var(--s-2));
    border: 1px solid var(--input);
    border-radius: var(--r-1);
    background: var(--surface);
    color: var(--foreground);
    font: inherit;
    font-size: var(--fs-sm);
    transition: border-color var(--t-micro) var(--ease-out);
  }
  .s-filtros__busqueda::placeholder { color: var(--muted-foreground); }
  .s-filtros__busqueda:focus-visible { outline: 2px solid var(--ring); outline-offset: -1px; border-radius: var(--r-1); }
  .s-filtros__boton, .s-filtros__movil, .s-filtros__limpiar {
    display: inline-flex; align-items: center; gap: var(--s-1);
    block-size: 2rem;
    padding-inline: var(--s-3) var(--s-2);
    border-radius: var(--r-1);
    font-family: var(--font-body);
    font-size: var(--fs-sm);
    font-weight: 500;
    color: var(--foreground);
    white-space: nowrap;
    cursor: pointer;
    transition: background-color var(--t-micro) var(--ease-out), color var(--t-micro) var(--ease-out);
  }
  .s-filtros__boton, .s-filtros__movil { border: 1px solid var(--border); background: var(--surface); }
  .s-filtros__boton > .s-icono, .s-filtros__movil > .s-icono { color: var(--muted-foreground); }
  .s-filtros__boton[aria-expanded="true"] { background: var(--op-sup-2, var(--muted)); }
  .s-filtros__limpiar { padding-inline: var(--s-2); color: var(--muted-foreground); }
  .s-filtros__chip {
    display: inline-flex; align-items: center; gap: var(--s-1);
    block-size: 1.75rem;
    padding-inline-start: var(--s-2);
    border-radius: var(--r-1);
    background: var(--op-sup-3, var(--muted));
    font-size: var(--fs-sm);
    color: var(--foreground);
    white-space: nowrap;
  }
  .s-filtros__quitar {
    position: relative;
    display: inline-grid; place-items: center;
    inline-size: 1.75rem; block-size: 100%;
    border-radius: var(--r-1);
    color: var(--muted-foreground);
    cursor: pointer;
    transition: color var(--t-micro) var(--ease-out);
  }
  .s-filtros__quitar:focus-visible, .s-filtros__boton:focus-visible, .s-filtros__movil:focus-visible, .s-filtros__limpiar:focus-visible {
    outline-offset: 2px; border-radius: var(--r-1);
  }
  .s-filtros__resultados { margin: 0 0 0 auto; color: var(--muted-foreground); font-variant-numeric: tabular-nums; white-space: nowrap; }
  .s-filtros__movil { display: none; }
  @media (hover: hover) and (pointer: fine) {
    .s-filtros__busqueda:hover:not(:focus) { border-color: var(--foreground); }
    .s-filtros__boton:hover, .s-filtros__movil:hover { background: var(--op-sup-2, var(--muted)); }
    .s-filtros__quitar:hover, .s-filtros__limpiar:hover { color: var(--foreground); }
  }
  @media (max-width: 767px), (pointer: coarse) {
    .s-filtros__busqueda, .s-filtros__boton, .s-filtros__movil, .s-filtros__limpiar { block-size: 2.75rem; }
    /* Safari en iOS amplía al enfocar un campo de menos de 16 px (§3.5) */
    .s-filtros__busqueda { font-size: var(--fs-md); }
    /* El chip se ve de 28; el área de quitar crece a 44 sin moverlo */
    .s-filtros__quitar::after { content: ""; position: absolute; inset: -0.5rem; }
  }
  @media (max-width: 640px) {
    .s-filtros__buscar { flex-basis: 100%; }
    .s-filtros__movil { display: inline-flex; }
    .s-filtros__lista { display: none; flex-basis: 100%; }
    .s-filtros:has(.s-filtros__movil[aria-expanded="true"]) .s-filtros__lista { display: flex; }
  }

  /* Tabla densa (variante de .s-table), dentro de .s-page__objeto: filas
     de 48 con 24 de aire (--compacta: 44 y 16; en teléfono 16), encabezado
     en tinta media y pegajoso bajo la barra, cifras tabulares, hover en
     superficie 2 (solo puntero fino, sin transición), fila clicable con
     foco del acento en la fila entera. Va después de .s-table-surface para
     ganarle en empate. */
  .s-table.s-table--densa {
    --s-table-fila: 3rem;
    --s-table-celda: var(--s-5);
    font-size: var(--fs-sm);
    /* 20 px para 14 (18 para 13, 16 para 12): la fila mide 48 por su alto,
       no por el interlineado (regla 40) */
    line-height: 1.25rem;
  }
  /* Ancho mínimo por tipo de columna (regla 40): en th y td */
  .s-table__correo { min-inline-size: 14rem; }
  .s-table__rol { min-inline-size: 8rem; }
  .s-table__fecha { min-inline-size: 7rem; white-space: nowrap; }
  .s-table__importe { min-inline-size: 8rem; text-align: end; font-variant-numeric: tabular-nums; white-space: nowrap; }
  /* Lista en una celda (regla 38): hasta dos chips y "+n" con la lista en
     title; la fila nunca crece por chips */
  .s-chips { display: inline-flex; align-items: center; gap: var(--s-1); max-inline-size: 100%; overflow: hidden; white-space: nowrap; vertical-align: middle; }
  .s-table.s-table--compacta { --s-table-fila: 2.75rem; --s-table-celda: var(--s-4); }
  @media (max-width: 640px) { .s-table.s-table--densa { --s-table-celda: var(--s-4); } }
  .s-table.s-table--densa th {
    position: sticky;
    inset-block-start: var(--topbar-h, 0px);
    z-index: var(--z-pegado);
    block-size: var(--s-table-fila);
    padding: 0 var(--s-table-celda);
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    font-family: var(--font-body);
    font-size: var(--fs-sm);
    font-weight: 500;
    letter-spacing: 0;
    text-transform: none;
    color: var(--muted-foreground);
    white-space: nowrap;
  }
  .s-table.s-table--densa td {
    block-size: var(--s-table-fila);
    padding: 0 var(--s-table-celda);
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
  }
  .s-page__objeto .s-table.s-table--densa tbody:last-child > tr:last-child > td { border-bottom: 0; }
  .s-table--densa .s-table__num { text-align: end; font-variant-numeric: tabular-nums; white-space: nowrap; }
  .s-table.s-table--densa tbody tr { position: relative; transition: none; }
  .s-table.s-table--densa tbody tr:hover { background: transparent; }
  @media (hover: hover) and (pointer: fine) {
    /* Solo se resalta la fila que responde al clic (regla 34) */
    .s-table.s-table--densa tbody tr:not(.s-table__fila-expandida, .s-grupo__encabezado):has(.s-table__enlace, .s-table__expandir):hover { background: var(--op-sup-2, var(--muted)); }
  }
  .s-table__enlace { color: var(--foreground); font-weight: 500; text-decoration: none; }
  .s-table__enlace::after { content: ""; position: absolute; inset: 0; }
  .s-table__enlace:focus-visible { outline: none; }
  .s-table--densa tbody tr:has(.s-table__enlace:focus-visible) { outline: 2px solid var(--ring); outline-offset: -2px; }
  .s-table--densa td :is(button, input, select, a:not(.s-table__enlace)) { position: relative; z-index: 1; }
  /* Una celda, un renglón (regla 17): lo que no cabe se corta con "…" y el
     texto completo va en el tooltip del término o en title. Dentro, el
     término suelto pierde su alto mínimo de 24 px: la fila de 48 ya da el
     área.
     En una tabla de ancho automático, la celda lleva s-table__flexible para
     ceder el espacio que sobra (con s-table--fija no hace falta). */
  .s-table__trunca { display: flex; align-items: center; gap: 0.3em; min-inline-size: 0; white-space: nowrap; }
  /* Lo que se corta es el nombre (el término, el enlace o .s-table__texto);
     el código, el chip o el botón de expandir se quedan completos. Un
     <button> es siempre una caja entera: el corte va dentro de él. */
  .s-table__trunca > * { flex-shrink: 0; }
  .s-table__trunca > :is(.s-term, .s-table__enlace, .s-table__texto) { flex-shrink: 1; min-inline-size: 0; overflow: hidden; text-overflow: ellipsis; }
  .s-table__trunca .s-term { display: flex; }
  .s-table__trunca .s-term__trigger { display: block; min-inline-size: 0; min-block-size: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .s-table td.s-table__flexible { inline-size: 100%; max-inline-size: 0; }
  /* En teléfono queda una columna de texto: la celda que se trunca es la flexible */
  @media (max-width: 640px) { .s-table td:has(> .s-table__trunca) { inline-size: 100%; max-inline-size: 0; } }
  /* Una celda, un dato: lo secundario va en su columna o en la misma línea,
     en tinta media (p. ej. el código junto al nombre). */
  .s-table__secundario { margin-inline-start: var(--s-2); color: var(--muted-foreground); font-weight: 400; }
  /* Verbo de la fila: cuando la fila entera es el enlace (s-table__enlace)
     y tiene una acción concreta, el verbo la dice al final ("Revisar y
     publicar →") sin ser otro control: un solo destino, una parada de
     tabulador. La flecha avanza con el hover de la fila. */
  .s-table__verbo { display: inline-flex; align-items: center; gap: var(--s-2); color: var(--foreground); font-weight: 500; white-space: nowrap; }
  .s-table__verbo::after { content: "→"; transition: transform var(--t-micro) var(--ease-out); }
  /* Una sola flecha: si el verbo ya trae la suya (un ícono, .s-btn__arrow)
     o envuelve otro verbo, no agrega otra. La flecha nunca va escrita en el
     texto: la pone el paquete. */
  .s-table__verbo:has(svg, .s-btn__arrow, .s-table__verbo)::after { content: none; }
  @media (hover: hover) and (pointer: fine) { .s-table--densa tbody tr:hover .s-table__verbo::after { transform: translateX(4px); } }
  /* Tarea en una lista de trabajo: ícono lucide por tipo (forma, sin
     color) y el nombre. El color es solo de la urgencia (s-plazo) y de
     "devuelto". */
  .s-tarea { display: inline-flex; align-items: center; gap: var(--s-2); }
  /* El ícono en un cuadro de 24 con esquinas de 6, en superficie 2, a 14 px
     en tinta media (regla 31, como la bandeja de Linear) */
  .s-tarea > .s-icono {
    box-sizing: border-box;
    inline-size: var(--s-5); block-size: var(--s-5);
    padding: 0.3125rem;
    border-radius: var(--r-1);
    background: var(--op-sup-2, var(--muted));
    color: var(--muted-foreground);
    stroke-width: 2;
  }
  /* Ancho fijo de columnas: nada salta al decidir (un "—" que pasa a campo,
     un estado que cambia de largo). Los anchos van en <col>; --s-table-ancho
     es el mínimo de la tabla (debajo, se desplaza dentro de su región). */
  .s-table--fija { table-layout: fixed; inline-size: max(100%, var(--s-table-ancho, 0px)); }
  /* El dato que se lee primero en la fila (el valor del mes): tinta y 600 */
  .s-table__dato { color: var(--foreground); font-weight: 600; }
  /* Fila enlace sin acción propia: chevron de 16 px al final, en tinta
     tenue; con hover de la fila, en tinta. Nunca "Ir". */
  .s-table__ir { inline-size: 1%; text-align: end; color: var(--op-tinta-tenue, var(--muted-foreground)); }
  @media (hover: hover) and (pointer: fine) { .s-table--densa tbody tr:hover > .s-table__ir { color: var(--foreground); } }
  /* Campo editable dentro de una celda (tarifas, metas): compacto, 112 px
     de ancho y 32 de alto, con el borde de control (≥ 3:1), cifra tabular a
     la derecha; 16 px en táctil. Ocupa el mismo lugar que el "—" al que
     reemplaza (.s-table__marcador): decidir no mueve la fila. --texto para
     un texto corto a todo el ancho de la columna. */
  .s-table__campo {
    -webkit-appearance: none;
    appearance: none;
    inline-size: 7rem;
    max-inline-size: 100%;
    text-align: end;
    font-variant-numeric: tabular-nums;
    block-size: 2rem;
    padding: 0 var(--s-2);
    border: 1px solid var(--input);
    border-radius: var(--r-1);
    background: var(--surface);
    color: var(--foreground);
    font: inherit;
    font-size: var(--fs-sm);
    transition: border-color var(--t-micro) var(--ease-out), box-shadow var(--t-micro) var(--ease-out);
  }
  .s-table__campo--texto { inline-size: 100%; min-inline-size: 8rem; text-align: start; font-variant-numeric: normal; }
  .s-table__marcador { display: inline-block; inline-size: 7rem; max-inline-size: 100%; padding-inline: calc(var(--s-2) + 1px); text-align: end; color: var(--muted-foreground); font-variant-numeric: tabular-nums; }
  .s-table__campo::placeholder { color: var(--muted-foreground); }
  .s-table__campo:focus-visible { outline: 2px solid var(--ring); outline-offset: -1px; border-radius: var(--r-1); }
  .s-table__campo[aria-invalid="true"] { border-color: var(--destructive); }
  @media (hover: hover) and (pointer: fine) { .s-table__campo:hover:not(:focus) { border-color: var(--foreground); } }
  @media (max-width: 767px), (pointer: coarse) { .s-table__campo { block-size: 2.75rem; font-size: var(--fs-md); } }
  /* Contenedor con scroll: recibe foco (tabindex="0" en el marcado) y lo muestra */
  .s-table-surface:focus-visible { outline-offset: 2px; border-radius: var(--r-2); }
  /* Tabla ancha dentro de una región con desplazamiento (role="region" o
     .s-table__scroll): el encabezado se ancla a la región, no a la barra.
     Con --topbar-h bajaba 56 px dentro de ella y tapaba una fila, la última
     en una tabla corta. */
  .s-table__scroll { overflow-x: auto; overscroll-behavior-x: contain; }
  :is(.s-table__scroll, [role="region"]) > .s-table.s-table--densa th { inset-block-start: 0; }
  :is(.s-table__scroll, [role="region"]):focus-visible { outline-offset: -2px; }
  /* Fila de grupo sin plegar (un mes, un cliente, una sección): la misma
     .s-grupo__encabezado de los grupos que se pliegan, sin botón */
  .s-grupo__encabezado .s-page__contador { margin-inline-start: var(--s-2); }
  .s-table.s-table--densa .s-grupo__encabezado th { white-space: normal; }

  /* Prioridad de columnas (§5): prio-2 se oculta a ≤ 1024 px y prio-3 a
     ≤ 640. En teléfono, lo esencial en dos líneas (.s-table__solo-movil). */
  @media (max-width: 1024px) { .s-table__prio-2 { display: none; } }
  @media (max-width: 640px) { .s-table__prio-3 { display: none; } }
  /* En escritorio nunca se ve, aunque el elemento lleve una clase de
     disposición (flex, una utilidad): sin !important, una utilidad de
     Tailwind lo mostraba y la fila repetía sus datos (0.6.0). */
  @media (min-width: 641px) { .s-table__solo-movil { display: none !important; } }
  @media (max-width: 640px) {
    /* Flex y no bloque: la segunda línea no suma el descendente de una caja de línea */
    .s-table__solo-movil { display: flex; }
    .s-table__num > .s-table__solo-movil { justify-content: flex-end; }
    .s-table.s-table--densa td { padding-block: var(--s-2); }
  }

  /* Expandir: chevron dentro de la celda principal, sin columna vacía; gira
     90° en 160 ms. La fila cerrada lleva `hidden`. En teléfono la fila lleva
     al detalle y no se expande. */
  .s-table__expandir {
    position: relative;
    display: inline-grid; place-items: center;
    inline-size: 1.75rem; block-size: 1.75rem;
    margin-inline: calc(var(--s-1) * -1) var(--s-2);
    vertical-align: middle;
    border-radius: var(--r-1);
    color: var(--muted-foreground);
    cursor: pointer;
  }
  .s-table__expandir .s-icono, .s-grupo__titulo .s-icono { transition: transform 160ms var(--ease-out); }
  /* La fila que se despliega abre y cierra entera (la app lo conecta: el
     clic en la fila acciona s-table__expandir; los otros controles de la
     fila detienen la propagación) */
  .s-table.s-table--densa tbody tr:has(> td .s-table__expandir) { cursor: pointer; }
  .s-table__expandir[aria-expanded="true"] .s-icono,
  .s-grupo__titulo[aria-expanded="true"] .s-icono,
  details.s-grupo[open] > .s-grupo__titulo .s-icono { transform: rotate(90deg); }
  .s-table__expandir:focus-visible { outline-offset: 0; }
  @media (hover: hover) and (pointer: fine) { .s-table__expandir:hover { color: var(--foreground); } }
  @media (max-width: 767px), (pointer: coarse) { .s-table__expandir::after { content: ""; position: absolute; inset: -0.5rem; } }
  @media (max-width: 640px) { .s-table__expandir, .s-table.s-table--densa .s-table__fila-expandida { display: none; } }
  /* En teléfono la fila expandida se muestra si la tabla no tiene página
     de detalle (--movil) o si una acción de la fila abrió su nota
     (.s-table__nota): ahí está la función, no solo el dato. */
  @media (max-width: 640px) {
    .s-table.s-table--densa .s-table__fila-expandida--movil:not([hidden]),
    .s-table.s-table--densa .s-table__fila-expandida:not([hidden]):has(.s-table__nota:not([hidden])) { display: table-row; }
    .s-table.s-table--densa :is(.s-table__fila-expandida--movil, .s-table__fila-expandida:has(.s-table__nota:not([hidden]))) td { padding-inline-start: var(--s-table-celda); }
  }
  /* Fila abierta: la fila y su detalle en una superficie apenas distinta,
     entre la 1 y la 2, para que se lean como una pieza. */
  .s-table.s-table--densa tbody tr:has(> td > .s-table__expandir[aria-expanded="true"]),
  .s-table.s-table--densa tbody tr:has(> td > .s-table__expandir[aria-expanded="true"]) + .s-table__fila-expandida {
    background: color-mix(in lch, var(--op-sup-1, var(--surface)), var(--op-sup-2, var(--muted)));
  }
  .s-table.s-table--densa tr:has(+ .s-table__fila-expandida:not([hidden])) td { border-bottom-color: transparent; }
  .s-table.s-table--densa .s-table__fila-expandida td {
    block-size: auto;
    padding: 0 var(--s-table-celda) var(--s-4) calc(var(--s-table-celda) + 1.75rem + var(--s-1));
  }
  .s-table__fila-expandida:not([hidden]) {
    transition: opacity 160ms var(--ease-out), transform 160ms var(--ease-out);
    @starting-style { opacity: 0; transform: translateY(-0.25rem); }
  }
  .s-table__detalle {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 9rem), 1fr));
    gap: var(--s-2) var(--s-5);
    margin: 0;
  }
  .s-table__detalle > div { display: grid; align-content: start; min-inline-size: 0; }
  .s-table__detalle dt { color: var(--muted-foreground); }
  .s-table__detalle dd { margin: 0; font-variant-numeric: tabular-nums; }
  /* Nota de una acción de fila (Devolver, Rechazar): bloque aparte bajo el
     detalle, solo cuando la acción lo abre. Título a 14 / 600 en sentence
     case, campo de tres renglones que crece, acciones a la derecha. */
  .s-table__nota { display: grid; gap: var(--s-2); max-inline-size: 44rem; margin-block-start: var(--s-4); padding-block-start: var(--s-4); border-block-start: 1px solid var(--border); }
  .s-table__nota-titulo { font-family: var(--font-display); font-size: var(--fs-sm); font-weight: 600; }
  .s-table__nota textarea { field-sizing: content; min-block-size: calc(3lh + 1.2rem); max-block-size: 12rem; }
  .s-table__nota-ayuda { margin: 0; color: var(--muted-foreground); font-size: var(--fs-xs); }
  .s-table__nota-acciones { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: var(--s-2); }

  /* Lista de pares (detalle de fila): etiqueta de 12 px en tinta media en
     una columna de 128, valor de 14 al lado; en teléfono, uno bajo otro. */
  .s-pares { display: grid; grid-template-columns: 8rem minmax(0, 1fr); gap: var(--s-2) var(--s-4); max-inline-size: 44rem; margin: 0; }
  .s-pares > dt { color: var(--muted-foreground); font-size: var(--fs-xs); line-height: 1.5rem; }
  .s-pares > dd { min-inline-size: 0; margin: 0; }
  @media (max-width: 640px) {
    .s-pares { grid-template-columns: minmax(0, 1fr); gap: 0; }
    .s-pares > dd { margin-block-end: var(--s-2); }
  }

  /* Lista de archivos (evidencia, como Vanta y Drata): ícono por tipo,
     nombre en una línea con elipsis (completo en title), tamaño · fecha y
     la acción a la derecha. En teléfono, tamaño y fecha bajo el nombre. */
  .s-archivos { display: grid; margin: 0; padding: 0; list-style: none; border: 1px solid var(--border); border-radius: var(--r-1); background: var(--surface); }
  .s-archivo { display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto; align-items: center; gap: var(--s-3); min-block-size: 2.5rem; padding: 0 var(--s-1) 0 var(--s-3); }
  .s-archivo + .s-archivo { border-block-start: 1px solid var(--border); }
  .s-archivo > .s-icono { color: var(--muted-foreground); }
  .s-archivo__texto { display: contents; }
  .s-archivo__nombre { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .s-archivo__meta { color: var(--muted-foreground); font-size: var(--fs-xs); font-variant-numeric: tabular-nums; white-space: nowrap; }
  @media (max-width: 640px) {
    .s-archivo { grid-template-columns: auto minmax(0, 1fr) auto; padding-block: var(--s-1); }
    .s-archivo__texto { display: grid; min-inline-size: 0; }
  }
  /* --miniatura: una imagen muestra su vista previa (criterio 16) en el
     lugar del ícono: cuadro de 40 px recortado (object-fit: cover), radio de
     control y el nombre en una línea. La miniatura es decorativa (alt="")
     porque el nombre va al lado. Sin archivos: s-vacio dentro del mismo
     marco (<p class="s-archivos s-vacio">). */
  .s-archivo--miniatura { min-block-size: 3.5rem; padding-block: var(--s-2); }
  .s-archivo__miniatura {
    display: block;
    inline-size: 2.5rem; block-size: 2.5rem;
    object-fit: cover;
    border-radius: var(--r-1);
    background: var(--muted);
    box-shadow: inset 0 0 0 1px var(--border);
  }
  /* En una lista con miniaturas, el ícono de los demás archivos ocupa el
     mismo ancho: los nombres empiezan en la misma x (regla 28) */
  .s-archivos:has(.s-archivo__miniatura) > .s-archivo > .s-icono { box-sizing: content-box; padding-inline: 0.75rem; }
  /* Sin archivos, el vacío en el mismo marco y con el margen de un renglón */
  .s-archivos.s-vacio { padding-inline: var(--s-3); }

  /* Lista de renglones con regla hairline (material de un capítulo,
     requisitos): texto a la izquierda, conteo o estado a la derecha, 44 px. */
  .s-lista { display: grid; margin: 0; padding: 0; list-style: none; }
  .s-lista > li { display: flex; align-items: center; justify-content: space-between; gap: var(--s-4); min-block-size: 2.75rem; padding-block: var(--s-2); border-block-start: 1px solid var(--border); }

  /* Avance en celda: barra corta y cifra; el acento es el único color de la
     columna. En teléfono la barra va bajo la cifra. */
  .s-avance { display: inline-flex; align-items: center; justify-content: flex-end; gap: var(--s-2); font-variant-numeric: tabular-nums; }
  .s-avance__barra { inline-size: var(--s-8); block-size: var(--s-1); border-radius: var(--r-pill); background: var(--op-sup-3, var(--muted)); overflow: hidden; }
  .s-avance__barra > span { display: block; block-size: 100%; inline-size: var(--s-avance, 0%); border-radius: inherit; background: var(--op-acento, var(--foreground)); }
  @media (max-width: 640px) { .s-avance { flex-direction: column-reverse; align-items: flex-end; gap: var(--s-1); } }
  /* Barra en su columna (regla 28): en una tabla, la barra va en su celda
     (.s-table__barra, ancho fijo, alineada a la izquierda) y la cifra en la
     suya (.s-table__num): la barra no se mueve por el largo del texto. */
  .s-table__barra { inline-size: 1%; white-space: nowrap; }
  .s-table__barra > .s-avance__barra { display: block; }
  /* Minibarras (seis meses en una celda): el periodo en curso, el último,
     con el acento. El dato va en aria-label del contenedor (role="img"). */
  .s-barras { display: inline-flex; align-items: flex-end; gap: 0.1875rem; block-size: 1.25rem; vertical-align: middle; }
  .s-barras > span { inline-size: 0.375rem; min-block-size: 0.125rem; block-size: var(--s-barra, 0%); border-radius: 1px; background: var(--op-sup-3, var(--muted)); }
  .s-barras > span:last-child { background: var(--op-acento, var(--foreground)); }
  /* Acciones de fila: botones de ícono de 32 px en tinta media */
  .s-table__acciones { inline-size: 1%; text-align: end; white-space: nowrap; }
  .s-table__accion {
    position: relative;
    display: inline-grid; place-items: center;
    inline-size: 2rem; block-size: 2rem;
    vertical-align: middle;
    border-radius: var(--r-1);
    color: var(--muted-foreground);
    cursor: pointer;
    transition: color var(--t-micro) var(--ease-out), background-color var(--t-micro) var(--ease-out);
  }
  .s-table__accion:focus-visible { outline-offset: 0; }
  @media (hover: hover) and (pointer: fine) { .s-table__accion:hover { color: var(--foreground); background: var(--op-sup-3, var(--muted)); } }
  @media (max-width: 767px), (pointer: coarse) { .s-table__accion::after { content: ""; position: absolute; inset: -0.375rem; } }

  /* Respuesta al presionar en los botones de ícono y de filtro (como .s-btn) */
  .s-table__accion, .s-table__expandir, .s-filtros__quitar, .s-filtros__boton, .s-filtros__movil, .s-filtros__limpiar {
    transition-property: color, background-color, transform;
    transition-duration: var(--t-micro), var(--t-micro), 160ms;
    transition-timing-function: var(--ease-out);
  }
  :is(.s-table__accion, .s-table__expandir, .s-filtros__quitar, .s-filtros__boton, .s-filtros__movil, .s-filtros__limpiar):active { transform: scale(0.97); }

  /* Estado: punto de 8 px con el tono, o el ícono en su lugar (forma
     además de color); texto en tinta. En oscuro el tono pasa a -edge. */
  /* align-items: baseline: la línea base de la caja es la del texto, la
     misma que el resto de las celdas; el ícono y el punto se centran en ella. */
  .s-estado {
    --s-estado-tono: var(--muted-foreground);
    display: inline-flex; align-items: baseline; gap: var(--s-2);
    font-size: var(--fs-sm);
    font-weight: 400;
    line-height: 1.5rem;
    color: var(--foreground);
    white-space: nowrap;
  }
  .s-estado::before {
    content: "";
    inline-size: var(--s-2); block-size: var(--s-2);
    align-self: center;
    flex-shrink: 0;
    border-radius: var(--r-pill);
    background: var(--s-estado-tono);
  }
  .s-estado:has(> .s-icono)::before { display: none; }
  .s-estado > .s-icono { align-self: center; color: var(--s-estado-tono); }
  .s-estado--neutro::before, .s-estado:not([class*="s-estado--"])::before {
    background: transparent;
    box-shadow: inset 0 0 0 1.5px var(--s-estado-tono);
  }
  .s-estado--info { --s-estado-tono: var(--info); }
  .s-estado--warning { --s-estado-tono: var(--warning); }
  .s-estado--success { --s-estado-tono: var(--success); }
  .s-estado--destructive { --s-estado-tono: var(--destructive); }
  [data-theme="dark"] .s-estado--info { --s-estado-tono: var(--info-edge); }
  [data-theme="dark"] .s-estado--warning { --s-estado-tono: var(--warning-edge); }
  [data-theme="dark"] .s-estado--success { --s-estado-tono: var(--success-edge); }
  [data-theme="dark"] .s-estado--destructive { --s-estado-tono: var(--destructive-edge); }

  /* Estado por forma (regla 30, como Linear): la forma dice el avance y el
     color el tono, solo en el ícono; el texto va siempre en tinta.
     Punteado = sin abrir, vacío = pendiente, pastel = en progreso (la
     fracción es el avance real con --s-estado-avance, de 0 a 1; sin él,
     medio), lleno con palomita = hecho u oficial, flecha de regreso =
     devuelto (con --warning: el ámbar es solo para "devuelto"). Todas a
     14 px con trazo de 1.5. En el operativo el color sale del método LCH
     (--op-estado-*), ≥ 3:1 en claro y oscuro. Las máscaras son SVG sin
     url() anidado (build de Tailwind 4 con la optimización probado). */
  .s-estado:is(.s-estado--punteado, .s-estado--vacio, .s-estado--medio, .s-estado--lleno, .s-estado--regreso)::before {
    box-sizing: border-box;
    inline-size: 1em; block-size: 1em;
    border-radius: 0;
    background: var(--s-estado-tono);
    box-shadow: none;
    -webkit-mask: var(--s-estado-forma) center / contain no-repeat;
            mask: var(--s-estado-forma) center / contain no-repeat;
  }
  .s-estado--punteado { --s-estado-forma: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Ccircle cx='7' cy='7' r='6.25' fill='none' stroke='black' stroke-width='1.5' stroke-dasharray='2.2 1.9'/%3E%3C/svg%3E"); }
  .s-estado--vacio { --s-estado-forma: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Ccircle cx='7' cy='7' r='6.25' fill='none' stroke='black' stroke-width='1.5'/%3E%3C/svg%3E"); }
  .s-estado--lleno { --s-estado-forma: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath fill-rule='evenodd' d='M7 0a7 7 0 1 0 0 14A7 7 0 0 0 7 0Zm-2.4 6.47 1.4 1.4 3.15-3.4 1.1 1.02-4.22 4.56-2.53-2.53Z'/%3E%3C/svg%3E"); }
  .s-estado--regreso { --s-estado-forma: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14' fill='none' stroke='black' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='7' cy='7' r='6.25' stroke-width='1.5'/%3E%3Cpath d='M8.6 9H6.4a1.85 1.85 0 0 1 0-3.7h2.1M7.2 4 5.9 5.3l1.3 1.3' stroke-width='1.3'/%3E%3C/svg%3E"); }
  /* Pastel: anillo de 1.5 y la fracción del avance dentro, a 2 px */
  .s-estado.s-estado--medio::before {
    -webkit-mask: none;
            mask: none;
    border: 1.5px solid var(--s-estado-tono);
    border-radius: var(--r-pill);
    padding: 2px;
    background: conic-gradient(var(--s-estado-tono) calc(var(--s-estado-avance, 0.5) * 1turn), transparent 0) content-box;
  }
  /* En el operativo, el tono del ícono por el método LCH */
  :where(.s-operativo, .s-page) .s-estado.s-estado--info { --s-estado-tono: var(--op-estado-info); }
  :where(.s-operativo, .s-page) .s-estado.s-estado--success { --s-estado-tono: var(--op-estado-success); }
  :where(.s-operativo, .s-page) .s-estado.s-estado--warning { --s-estado-tono: var(--op-estado-warning); }
  :where(.s-operativo, .s-page) .s-estado.s-estado--destructive { --s-estado-tono: var(--op-estado-destructive); }
  /* Pastilla: solo el estado único de la cabecera de una entidad; en una
     tabla el estado va sin caja (ADR-004, punto 3). Fondo = el tono al 8 %
     (al 12 el verde medía 4.49:1; al 8, el tono más bajo da 4.75). */
  .s-estado--pastilla {
    align-items: center;
    block-size: 1.5rem;
    padding: 0 var(--s-2) 0 0.375rem;
    border-radius: var(--r-1);
    background: color-mix(in lch, var(--s-estado-tono) 8%, var(--surface));
    line-height: 1;
  }

  /* Plazo (§5): 12 px, peso 500, con el tono warning o destructive; el texto
     dice el tiempo. En oscuro, -edge. AA medido en claro y oscuro. */
  .s-plazo {
    display: inline-flex; align-items: baseline; gap: var(--s-1);
    font-size: var(--fs-xs);
    font-weight: 500;
    line-height: 1rem;
    font-variant-numeric: tabular-nums;
    color: var(--muted-foreground);
    white-space: nowrap;
  }
  .s-plazo > .s-icono { align-self: center; inline-size: 0.875rem; block-size: 0.875rem; }
  .s-plazo--warning { color: var(--warning); }
  .s-plazo--destructive { color: var(--destructive); }
  [data-theme="dark"] .s-plazo--warning { color: var(--warning-edge); }
  [data-theme="dark"] .s-plazo--destructive { color: var(--destructive-edge); }

  /* Grupo colapsable: <details class="s-grupo"> con <summary
     class="s-grupo__titulo"> en listas, o <tbody class="s-grupo"> con un
     botón .s-grupo__titulo (aria-expanded) en su fila .s-grupo__encabezado.
     Sin banda: tipografía, contador y chevron. Recordar el estado es de la app. */
  .s-grupo__titulo {
    display: flex; align-items: center; gap: var(--s-2);
    inline-size: 100%;
    min-block-size: 2.75rem;
    padding: 0;
    border: 0;
    background: none;
    font-family: var(--font-body);
    font-size: var(--fs-sm);
    font-weight: 600;
    letter-spacing: 0;
    text-align: start;
    text-transform: none;
    color: var(--foreground);
    list-style: none;
    cursor: pointer;
  }
  .s-grupo__titulo::-webkit-details-marker { display: none; }
  .s-grupo__titulo .s-icono { color: var(--muted-foreground); }
  .s-grupo__titulo:focus-visible { outline-offset: -2px; border-radius: var(--r-1); }
  .s-grupo__contador { font-weight: 500; color: var(--muted-foreground); font-variant-numeric: tabular-nums; }
  .s-table.s-table--densa .s-grupo__encabezado th {
    position: static;
    padding: 0 var(--s-table-celda);
    background: transparent;
    color: var(--foreground);
  }
  tbody.s-grupo:has(.s-grupo__titulo[aria-expanded="false"]) > tr:not(.s-grupo__encabezado) { display: none; }

  /* Pasos (regla 35, como Stripe Checkout): un componente compacto de 32 px,
     alineado a la izquierda, nunca tercios a todo el ancho. Numerales en
     cuadro de 24 unidos por una línea de 1 px: hecho = verde con palomita
     (regla 46), actual = tinta con la etiqueta a 600, siguiente = contorno
     en tinta media. El actual lleva aria-current="step" (en el <li> o en
     su .s-pasos__boton, si los pasos se pueden abrir: capítulos de una
     historia, pasos de una captura). A lo ancho se desplazan los pasos,
     nunca la página. */
  .s-pasos { display: flex; align-items: center; min-block-size: 2rem; margin: 0; padding: 0; list-style: none; overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none; }
  .s-pasos__paso { flex: none; display: flex; align-items: center; gap: var(--s-2); font-size: var(--fs-sm); line-height: 1.5rem; color: var(--muted-foreground); white-space: nowrap; }
  .s-pasos__paso + .s-pasos__paso::before { content: ""; flex: none; inline-size: var(--s-5); block-size: 1px; margin-inline-start: var(--s-2); background: var(--input); }
  .s-pasos__paso--hecho + .s-pasos__paso::before { background: var(--foreground); }
  .s-pasos__marca {
    position: relative;
    display: inline-grid; place-items: center;
    box-sizing: border-box;
    inline-size: var(--s-5); block-size: var(--s-5);
    flex-shrink: 0;
    border: 1px solid var(--muted-foreground);
    border-radius: calc(var(--r-1) / 2);
    color: var(--muted-foreground);
    font-family: var(--font-display);
    font-size: var(--fs-xs);
    font-weight: 600;
    line-height: 1;
    font-variant-numeric: tabular-nums;
  }
  .s-pasos__etiqueta { min-inline-size: 0; }
  .s-pasos__paso--hecho { color: var(--foreground); }
  .s-pasos__paso--hecho .s-pasos__marca { border-color: var(--success); background: var(--success); color: transparent; }
  .s-pasos__paso--hecho .s-pasos__marca::after {
    content: ""; position: absolute; inset: 0; margin: auto;
    inline-size: 0.75rem; block-size: 0.75rem;
    background: var(--background);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='m2.5 6.2 2.3 2.3 4.7-5' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
            mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='m2.5 6.2 2.3 2.3 4.7-5' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / contain no-repeat;
  }
  .s-pasos__paso:is([aria-current="step"], :has(> [aria-current="step"])) { color: var(--foreground); }
  .s-pasos__paso:is([aria-current="step"], :has(> [aria-current="step"])) .s-pasos__etiqueta { font-weight: 600; }
  .s-pasos__paso:is([aria-current="step"], :has(> [aria-current="step"])) .s-pasos__marca { border-color: var(--foreground); background: var(--foreground); color: var(--background); }
  .s-pasos a, .s-pasos__boton { color: inherit; text-decoration: none; }
  .s-pasos__boton {
    display: flex; align-items: center; gap: var(--s-2);
    min-block-size: 2rem;
    padding: 0 var(--s-1);
    margin-inline: calc(var(--s-1) * -1);
    border-radius: var(--r-1);
    font: inherit;
    cursor: pointer;
    transition: color var(--t-micro) var(--ease-out);
  }
  @media (hover: hover) and (pointer: fine) { .s-pasos__boton:hover { color: var(--foreground); } }
  .s-pasos__boton:focus-visible { outline-offset: -2px; }
  @media (max-width: 767px), (pointer: coarse) { .s-pasos__boton { min-block-size: 2.75rem; } }
  /* En teléfono, unos pasos que no se pueden abrir no se desplazan (nada
     enfocable dentro): los que no son el actual muestran solo su número y
     la etiqueta queda para lectores de pantalla */
  @media (max-width: 640px) {
    .s-pasos:not(:has(.s-pasos__boton)) .s-pasos__paso:not([aria-current="step"]) .s-pasos__etiqueta {
      position: absolute; inline-size: 1px; block-size: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
    }
    .s-pasos:not(:has(.s-pasos__boton)) .s-pasos__paso + .s-pasos__paso::before { inline-size: var(--s-3); }
  }
  /* Pasos que abren un panel en el mismo objeto (capítulos): arriba, con
     su línea */
  .s-page__objeto > .s-pasos { padding: var(--s-2) var(--s-5); border-block-end: 1px solid var(--border); }
  @media (max-width: 640px) { .s-page__objeto > .s-pasos { padding-inline: var(--s-4); } }

  /* (0.5.0, reemplazada por .s-pasos con .s-pasos__boton desde 0.6.0; se
     retira en 1.0) Pista de pasos (maestro-detalle, capítulos de una
     historia): una fila de .s-tabs; cada paso es un .s-tabs__tab con el numeral (cuadro de
     tinta, relleno si está hecho y contorno si falta), el nombre y un
     estado por forma, unidos por una línea. Se abre un paso a la vez
     (aria-current="step", aria-controls) y su panel (.s-pista__panel) va
     debajo, en el mismo objeto. A lo ancho se desplaza la pista, nunca la
     página; el activo se centra (la app lo hace con scrollIntoView). */
  .s-pista { gap: 0; margin: 0; padding: 0 var(--s-2); list-style: none; overscroll-behavior-x: contain; scroll-snap-type: x proximity; scrollbar-width: none; }
  .s-pista > li { position: relative; flex: 1 0 9.5rem; scroll-snap-align: center; }
  .s-pista > li:not(:last-child)::after {
    content: ""; position: absolute; z-index: 0;
    inset-block-start: calc(var(--s-4) + var(--s-5) / 2);
    inset-inline: calc(var(--s-3) + var(--s-5) + var(--s-2)) 0;
    block-size: 1px; background: var(--input);
  }
  .s-pista__paso {
    z-index: 1;
    display: grid; justify-items: start; gap: var(--s-1);
    inline-size: 100%;
    padding: var(--s-4) var(--s-3);
    font-family: var(--font-body);
    font-weight: 400;
    text-align: start;
    white-space: normal;
    cursor: pointer;
  }
  .s-pista__paso .s-numeral--cuadro { box-shadow: 0 0 0 4px var(--surface); }
  .s-pista__paso .s-numeral--contorno { box-shadow: 0 0 0 4px var(--surface), inset 0 0 0 1.5px var(--foreground); }
  .s-pista__nombre { font-weight: 500; color: var(--muted-foreground); transition: color var(--t-micro) var(--ease-out); }
  .s-pista__paso[aria-current="step"] .s-pista__nombre { font-weight: 600; color: var(--foreground); }
  @media (hover: hover) and (pointer: fine) { .s-pista__paso:hover .s-pista__nombre { color: var(--foreground); } }
  .s-pista__paso:focus-visible { outline-offset: -2px; border-radius: var(--r-1); }
  .s-estado.s-pista__estado { --s-estado-tono: var(--muted-foreground); font-size: var(--fs-xs); font-weight: 400; line-height: 1rem; color: var(--muted-foreground); }
  .s-pista__panel { display: grid; gap: var(--s-5); padding: var(--s-5); }
  @media (max-width: 640px) { .s-pista__panel { padding: var(--s-4); } }

  /* Mapa, gráfica o lienzo (regla 41): un contexto propio de capas; sus
     controles internos (z-index de MapLibre) nunca tapan la barra */
  .s-lienzo { position: relative; isolation: isolate; z-index: var(--z-contenido); }

  /* Estado vacío (regla 33): dentro del área de la tabla o la tarjeta, un
     ícono tenue, una línea y la acción si la hay. Sin borde punteado: el
     punteado (.s-dashed) es solo para zonas donde se sueltan archivos. */
  /* Proceso completo (regla 46): una confirmación breve y única (la app
     recuerda que ya se mostró): la palomita verde, una línea y el
     siguiente paso. La aurora sutil de las ceremonias entra y se apaga una
     vez, por la derecha y lejos del texto; sin confeti. Con reduced-motion,
     quieta. role="status" en el contenedor. */
  .s-logro {
    position: relative; isolation: isolate;
    display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2) var(--s-3);
    padding: var(--s-3) var(--s-3) var(--s-3) var(--s-4);
    border: 1px solid var(--border);
    border-radius: var(--r-2);
    background: var(--surface);
    font-size: var(--fs-sm); line-height: 1.25rem;
    color: var(--foreground);
    animation: s-logro-entra var(--t-ui) var(--ease-out) both;
  }
  .s-logro::before {
    content: ""; position: absolute; inset: 0; z-index: -1;
    border-radius: inherit; pointer-events: none;
    background:
      radial-gradient(34% 140% at 86% 50%, color-mix(in srgb, var(--sarape-pink) 16%, transparent) 0%, transparent 70%),
      radial-gradient(26% 120% at 70% 20%, color-mix(in srgb, var(--sarape-cyan) 14%, transparent) 0%, transparent 70%),
      radial-gradient(24% 120% at 98% 90%, color-mix(in srgb, var(--sarape-amber) 14%, transparent) 0%, transparent 70%);
    opacity: 0.45;
    animation: s-logro-aurora 1.8s var(--ease-out) both;
  }
  .s-logro > .s-numeral--hecho { animation: s-logro-palomita 400ms var(--ease-spring) 120ms both; }
  /* Alineación óptica (regla 29): la mayúscula de Archivo a 14/20 queda 1 px
     sobre el centro de la caja; medio pixel abajo la iguala con la palomita */
  .s-logro__titulo { padding-block-start: 1px; font-weight: 600; }
  .s-logro__siguiente { margin-inline-start: auto; }
  .s-vacio { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2) var(--s-3); min-block-size: 3.5rem; margin: 0; padding: var(--s-3) var(--s-5); color: var(--muted-foreground); }
  .s-vacio > .s-icono { color: var(--op-tinta-tenue, var(--muted-foreground)); }
  .s-vacio > .s-btn { margin-inline-start: auto; }
  @media (max-width: 640px) { .s-vacio { padding-inline: var(--s-4); } }

  /* Barra de guardar: pegada abajo mientras su contenido está en pantalla,
     con el progreso a la izquierda (aria-live) y un solo primario a la
     derecha. Un primario deshabilitado dice por qué (.s-guardar__motivo,
     enlazado con aria-describedby). En teléfono se pega sobre .s-tabbar.
     Va al final de .s-page y llega a sus bordes. */
  .s-guardar {
    position: sticky;
    inset-block-end: 0;
    z-index: var(--z-pegado);
    display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
    gap: var(--s-2) var(--s-4);
    padding-block: var(--s-3);
    border-block-start: 1px solid var(--border);
    background: color-mix(in srgb, var(--background) 96%, transparent);
    -webkit-backdrop-filter: blur(8px);
            backdrop-filter: blur(8px);
  }
  .s-shell:has(.s-tabbar) .s-guardar { inset-block-end: var(--tabbar-h, 0px); }
  .s-guardar__estado { flex: 1 1 18rem; min-inline-size: 0; }
  .s-guardar__acciones { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: var(--s-2) var(--s-3); }
  .s-guardar__motivo { margin: 0; color: var(--muted-foreground); font-size: var(--fs-xs); }
  /* Hija directa de .s-page: llega a los bordes de la página */
  .s-page > .s-guardar { margin-inline: calc(var(--s-7) * -1); padding-inline: var(--s-7); }
  @media (max-width: 640px) { .s-page > .s-guardar { margin-inline: calc(var(--s-4) * -1); padding-inline: var(--s-4); } }
  @media (prefers-contrast: more), (prefers-reduced-transparency: reduce) {
    .s-guardar { background: var(--background); -webkit-backdrop-filter: none; backdrop-filter: none; }
  }

  /* Grupo de campos: <fieldset class="s-page__bloque"> con
     <legend class="s-page__seccion"> (el encabezado de sección de siempre) */
  fieldset.s-page__bloque { min-inline-size: 0; margin: 0; padding: 0; border: 0; }
  fieldset.s-page__bloque > legend.s-page__seccion { margin-block-end: var(--s-1); padding: 0; }

  /* Menú de cuenta: se abre desde el avatar de .s-topbar (popover nativo:
     Escape y clic fuera lo cierran) y reúne quién eres, el tema y "Salir".
     La barra queda con destinos, avisos y cuenta. */
  .s-cuenta__boton { border-radius: var(--r-pill); cursor: pointer; }
  .s-cuenta__boton:focus-visible { outline-offset: 2px; }
  .s-cuenta {
    position: fixed;
    inset: calc(var(--topbar-h, 3.5rem) + var(--s-1)) var(--s-4) auto auto;
    margin: 0;
    inline-size: min(16rem, calc(100vw - var(--s-6)));
    padding: 0;
    overflow: hidden;
    border: 1px solid var(--border);
    border-radius: var(--r-2);
    background: var(--surface);
    color: var(--foreground);
    font-size: var(--fs-sm);
    box-shadow: var(--sh-2);
  }
  .s-cuenta:popover-open { display: grid; }
  /* Alineado con el margen de la barra del operativo */
  @media (min-width: 641px) { :where(.s-operativo) .s-cuenta { inset-inline-end: var(--s-7); } }
  @media (prefers-reduced-motion: no-preference) {
    .s-cuenta:popover-open {
      transition: opacity var(--t-ui) var(--ease-out), translate var(--t-ui) var(--ease-out);
      @starting-style { opacity: 0; translate: 0 -4px; }
    }
  }
  /* Márgenes iguales de 12 px; los separadores van de lado a lado */
  .s-cuenta__encabezado { display: grid; padding: var(--s-3); }
  .s-cuenta__encabezado > :last-child { color: var(--muted-foreground); font-size: var(--fs-xs); }
  .s-cuenta > * + * { border-block-start: 1px solid var(--border); }
  .s-cuenta__item {
    display: flex; align-items: center; gap: var(--s-2);
    inline-size: 100%; min-block-size: 2.25rem;
    padding: 0 var(--s-3);
    color: var(--foreground);
    font: inherit;
    text-align: start;
    text-decoration: none;
    cursor: pointer;
    transition: background-color var(--t-micro) var(--ease-out);
  }
  .s-cuenta__item > .s-icono { color: var(--muted-foreground); }
  @media (hover: hover) and (pointer: fine) { .s-cuenta__item:hover { background: var(--op-sup-2, var(--muted)); } }
  .s-cuenta__item:focus-visible { outline-offset: -2px; }
  @media (max-width: 767px), (pointer: coarse) { .s-cuenta__item { min-block-size: 2.75rem; } }

  /* Tema (regla 24): una fila, la etiqueta a la izquierda y a la derecha un
     segmentado compacto de solo íconos (monitor, sol, luna) con title y
     aria-label: Sistema · Claro · Oscuro, Sistema por omisión. Solo en el
     operativo; el narrativo se queda claro. El tema se aplica antes del
     primer pintado con el script del README. */
  .s-tema { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); min-block-size: 2.75rem; padding: var(--s-1) var(--s-3); }
  .s-tema__titulo { color: var(--foreground); }

  /* Más contraste: el tema ya sube con --op-contraste; el anillo neutro
     pasa a tinta plena. */
  @media (prefers-contrast: more) {
    .s-estado--neutro::before, .s-estado:not([class*="s-estado--"])::before { box-shadow: inset 0 0 0 1.5px var(--foreground); }
  }
}

/* ================================================================ Motion */
@keyframes s-logro-entra { from { opacity: 0; translate: 0 0.5rem; } }
@keyframes s-logro-aurora { 0% { opacity: 0; } 35% { opacity: 1; } 100% { opacity: 0.45; } }
@keyframes s-logro-palomita { from { scale: 0.6; opacity: 0; } }
@keyframes s-aurora-drift {
  0%   { transform: translate3d(-4%, -3%, 0) rotate(0deg) scale(1); }
  50%  { transform: translate3d(3%, 4%, 0) rotate(4deg) scale(1.06); }
  100% { transform: translate3d(-2%, 2%, 0) rotate(-3deg) scale(1.02); }
}
@keyframes s-rise {
  from { opacity: 0; transform: translateY(22px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes s-brush-draw {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}
@keyframes s-blink { 50% { opacity: 0; } }
@keyframes s-skeleton-in { to { opacity: 1; } }
@keyframes s-shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }

.anim [data-rise] {
  opacity: 0;
  animation: s-rise var(--t-page) var(--ease-out) forwards;
  animation-delay: calc(var(--stagger) * var(--i, 0));
}
.anim .s-brush--draw::after { animation-delay: var(--brush-delay, 900ms); }

.type-caret::after {
  content: "";
  display: inline-block;
  width: 0.08em; height: 0.9em;
  margin-left: 0.12em;
  background: currentColor;
  vertical-align: -0.08em;
  animation: s-blink 1.1s steps(1) infinite;
}

/* Reduced motion por elemento (HIG: sustituir por fundidos; sin escala,
   desenfoque ni resortes). Se conserva un cross-fade de 120 ms para no
   perder el "qué cambió". */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  /* Solo fundidos breves: ninguna transición supera 120 ms */
  *, *::before, *::after { transition-duration: var(--t-micro) !important; transition-property: opacity, background-color, color, border-color !important; }
  .anim [data-rise] { animation: none; opacity: 1; transform: none; }
  .s-brush--draw::after { animation: none; transform: scaleX(1); }
  .s-aurora::before, .s-aurora::after { animation: none; }
  .type-caret::after { animation: none; }
  .s-btn, .s-btn:active, .s-btn--primary:hover { transform: none; }
  .s-btn--primary::after { display: none; }
  .s-btn .s-btn__arrow, .s-btn:hover .s-btn__arrow { transform: none; }
  .s-table__verbo::after, .s-table--densa tbody tr:hover .s-table__verbo::after { transform: none; }
  .s-table__arrow, .s-table tbody tr:hover .s-table__arrow { transform: none; }
  .s-tabbar__icono, .s-tabbar__item:active .s-tabbar__icono { transform: none; }
  .s-table__expandir .s-icono, .s-grupo__titulo .s-icono, .s-table__fila-expandida { transition: none; }
  :is(.s-table__accion, .s-table__expandir, .s-filtros__quitar, .s-filtros__boton, .s-filtros__movil, .s-filtros__limpiar):active { transform: none; }
  .s-card--hover:hover { transform: none; }
  .s-choice, .s-choice:active { transform: none; transition: background-color var(--t-micro), color var(--t-micro), border-color var(--t-micro); }
  .s-range::-webkit-slider-thumb, .s-range:hover::-webkit-slider-thumb { transform: none; transition: none; }
  .s-progress__fill { transition: none; }
  .s-logro, .s-logro::before, .s-logro > .s-numeral--hecho { animation: none; }
  .s-slideover__backdrop { transition: opacity var(--t-micro) linear; }
  .s-slideover__panel { transform: none; opacity: 0; transition: opacity var(--t-micro) linear; }
  .s-slideover--visible .s-slideover__panel { opacity: 1; }
  .s-term__tip { transform: translateX(-50%); transition: opacity var(--t-micro) linear; }
  .s-disclosure[open] .s-disclosure__content { animation: none; }
  .s-disclosure__chevron { transition: none; }
  .s-skeleton { animation: s-skeleton-in var(--t-micro) linear 200ms forwards; background-image: none; }
}
