/* =========================================================================
   QUOMYA — CANONICAL DESIGN TOKENS V1
   Wave: S4.1 (design system foundation)
   Authority: 10_REFERENCE/STITCH/QUOMYA_UI_STITCH_DESIGN_LOCK_V1.md
              04_ARCHITECTURE/QUOMYA_UI_STITCH_IMPLEMENTATION_ARCHITECTURE_V1.md §4

   This file is the SINGLE canonical source of truth for Quomya design values.
   It is loaded LAST so that its :root block is the final authority in the
   cascade over styles.css, brand-phase-1-v15-14.css, compact-visual-v15-14-2.css
   and quomya-visual-system.css.

   NO BUSINESS LOGIC. NO LAYOUT RESTRUCTURING. VISUAL FOUNDATION ONLY.

   ------------------------------------------------------------------------
   LAYER MODEL
   ------------------------------------------------------------------------
   L1  CANONICAL SEMANTIC TOKENS        --qy-color-*, --qy-text-*, --qy-space-*
       The Stitch dark contract. Additive: nothing in the legacy product
       consumes these yet, so declaring them changes zero pixels.

   L2  NEUTRAL CONVERGENCE (GLOBAL)     value-identical re-points
       Legacy primitives whose current value is BYTE-IDENTICAL to a canonical
       token are re-pointed at that token. Provably zero visual delta; it
       collapses four duplicate scales into one source of truth.

   L3  DARK ACTIVATION (SCOPED)         [data-qy-theme="stitch"]
       The colour re-points that actually invert light -> dark. Inert until a
       migrated surface opts in. See THEME MIGRATION STRATEGY below.

   ------------------------------------------------------------------------
   THEME MIGRATION STRATEGY: SCOPED_PROGRESSIVE
   ------------------------------------------------------------------------
   Global inversion was evaluated and REJECTED for S4.1. Evidence:
     - 26 stylesheets consume the unprefixed legacy palette;
     - 14 stylesheets consume --rt-*;
     - 5 stylesheets (beta-candidate-v15-15-c, beta-runtime-guard-v15-15-b,
       legal-beta-v15-18-5, tutorial-inicial-p0, session-chrome-v15-21-1)
       carry hardcoded light colours and consume no tokens at all, so they
       CANNOT follow a global inversion and would render dark-on-dark or
       light-on-dark the moment the page background flipped.
   Flipping :root globally would therefore leave gating overlays, the legal
   consent gate and the onboarding tutorial unreadable between S4.1 and S4.8.

   Instead the dark contract activates per-scope. S4.2+ opts a migrated
   subtree in with:

       <html data-qy-theme="stitch">      (whole app, once every screen moved)
       <div class="qy-theme">             (one migrated subtree)

   Legacy screens outside the scope keep their present light values byte for
   byte. This is the mechanism that lets S4.2-S4.8 migrate one surface at a
   time without shipping an unusable intermediate build.
   ========================================================================= */

/* =========================================================================
   L1 — CANONICAL SEMANTIC TOKENS
   ========================================================================= */

:root {
  /* ---- surface ramp (dark; never inverted, never a light surface) ------ */
  --qy-color-bg: #071a26;
  --qy-color-surface-1: #0b1d29;
  --qy-color-surface-2: #122533;
  --qy-color-surface-3: #1a2e3d;
  --qy-color-surface-highlight: rgba(255, 255, 255, 0.065);
  --qy-color-surface-brand-wash: rgba(18, 191, 166, 0.08);

  /* ---- border ---------------------------------------------------------
     -border / -border-strong are DECORATIVE separators and are exempt from
     WCAG 1.4.11. -border-interactive is the minimum that reaches 3:1 on
     every surface in the ramp and MUST be used wherever a border is the only
     indication of a control boundary (inputs, selects, unfilled buttons). */
  --qy-color-border: #1e293b;
  --qy-color-border-strong: #2c3e4e;
  --qy-color-border-interactive: #667e92;

  /* ---- text -----------------------------------------------------------
     -text-tertiary is #8494A8, NOT the #64748B drafted in the architecture
     doc: #64748B measures 2.94:1 on --qy-color-surface-3 and fails AA.
     Documented accessibility adjustment; see §ACCESSIBILITY below. */
  --qy-color-text-primary: #ffffff;
  --qy-color-text-secondary: #94a3b8;
  --qy-color-text-tertiary: #8494a8;
  --qy-color-text-on-brand: #04241f;

  /* ---- brand ----------------------------------------------------------
     #12BFA6 is the LOCKED brand anchor and is not adjusted for contrast.
     It is reserved for brand, primary action and projected financials.
     It is NOT a generic success colour -- collected is #10B981.
     White on brand measures 2.33:1, so text on a brand fill is always
     --qy-color-text-on-brand (7.07:1). */
  --qy-color-brand: #12bfa6;
  --qy-color-brand-hover: #0eaf98;
  --qy-color-brand-deep: #078d7e;
  --qy-color-brand-soft: rgba(18, 191, 166, 0.14);

  /* Rol de TEXTO de la marca (S4.11A).
     La marca ya tenía anclaje, hover, profundidad y relleno tenue, pero no un
     rol de texto propio, porque en oscuro no le hacía falta: #12BFA6 mide
     >= 6:1 sobre las cuatro superficies de la rampa. En claro no existe ningún
     turquesa que siga leyéndose como Quomya y alcance 4.5:1 sobre blanco -- el
     ancla mide 2.33:1 -- así que el texto de marca necesita variante tonal,
     exactamente igual que collected / pending / closure / cancelled ya la
     tienen. Aquí vale el ancla, de modo que el tema oscuro no cambia ni un
     pixel; qy-appearance-v1.css es quien le da valor propio en claro.
     El ANCLA SE PRESERVA para rellenos, iconos, marcas y bordes. */
  --qy-color-brand-text: var(--qy-color-brand);

  /* ---- semantic status (never decorative, never a chart ramp) ---------
     Each status carries three roles:
       <name>       canonical anchor  - fills, icons, marks, indicators
       <name>-soft  tinted background - badge / chip surfaces
       <name>-text  AA-safe foreground - label text on any surface or on
                    its own -soft fill. Equals the anchor where the anchor
                    already clears 4.5:1 everywhere. */
  --qy-color-collected: #10b981;
  --qy-color-collected-soft: rgba(16, 185, 129, 0.14);
  --qy-color-collected-text: #34d399;

  --qy-color-pending: #f59e0b;
  --qy-color-pending-soft: rgba(245, 158, 11, 0.14);
  --qy-color-pending-text: #f59e0b;

  --qy-color-closure: #3b82f6;
  --qy-color-closure-soft: rgba(59, 130, 246, 0.14);
  --qy-color-closure-text: #60a5fa;

  --qy-color-cancelled: #ef4444;
  --qy-color-cancelled-soft: rgba(239, 68, 68, 0.14);
  --qy-color-cancelled-text: #f87171;

  /* Alias: the design lock names this role "error"; the app's own domain
     vocabulary names it "cancelled". Same value, both names supported. */
  --qy-color-error: var(--qy-color-cancelled);
  --qy-color-error-soft: var(--qy-color-cancelled-soft);
  --qy-color-error-text: var(--qy-color-cancelled-text);

  --qy-color-projected: var(--qy-color-brand);

  /* ---- rampa de INTENSIDAD de gráfico (S4.11E) -------------------------
     Cuatro pesos de la MISMA marca, no cuatro colores. La usan el mapa de
     actividad de comisiones y el degradado del área acumulada.

     No es una escala categórica ni una escala de estado: significa
     "cuánto", y por eso ordena por peso y no por tono. Un usuario con
     dificultad para distinguir colores sigue leyendo la progresión, y
     ninguna celda depende del color para tener nombre accesible.

     Se declara como TOKEN y no con `color-mix()` porque ninguna hoja de este
     proyecto usa todavía esa función, y el tema claro necesita además una
     base más profunda: sobre off-white el ancla al 16 % es indistinguible
     del fondo. La capa L4 la reapunta; el SVG no se entera. */
  --qy-chart-intensity-1: rgba(18, 191, 166, 0.16);
  --qy-chart-intensity-2: rgba(18, 191, 166, 0.32);
  --qy-chart-intensity-3: rgba(18, 191, 166, 0.56);
  --qy-chart-intensity-4: rgba(18, 191, 166, 0.85);

  /* Paradas del degradado del área. La última es TRANSPARENTE a propósito:
     un corte de color sobre la superficie dibujaría una línea horizontal
     donde el dato no tiene ningún límite. */
  --qy-chart-area-top: rgba(18, 191, 166, 0.34);
  --qy-chart-area-mid: rgba(18, 191, 166, 0.13);
  --qy-chart-area-bottom: rgba(18, 191, 166, 0);

  /* ---- interactive states --------------------------------------------- */
  --qy-color-hover: rgba(255, 255, 255, 0.06);
  --qy-color-active: rgba(255, 255, 255, 0.1);
  --qy-color-focus: var(--qy-color-brand);
  --qy-color-selected: var(--qy-color-brand-soft);
  --qy-color-disabled-text: #55697c;

  /* ---- categorical ramp (CHARTS ONLY) ---------------------------------
     Exists so concept-distribution charts never borrow a status colour.
     Resolves finding SU-04. Do not use for state. */
  --qy-cat-1: #12bfa6;
  --qy-cat-2: #5eead4;
  --qy-cat-3: #7dd3fc;
  --qy-cat-4: #a5b4fc;
  --qy-cat-5: #c4b5fd;
  --qy-cat-6: #94a3b8;

  /* ---- typography -----------------------------------------------------
     DELIVERY: self-hosted woff2, declared in qy-fonts-v1.css. No CDN, no
     third-party origin, no render-blocking request -- `font-display: swap`
     paints immediately in the fallback and swaps when the file arrives.
     The system chain behind Plus Jakarta Sans is what an engine without
     woff2 or variable-font support falls back to; on any supported runtime
     Plus Jakarta Sans is what actually renders. */
  --qy-font-family: "Plus Jakarta Sans", system-ui, -apple-system,
    BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --qy-font-numeric: tabular-nums;

  --qy-text-headline-xl: 700 36px / 44px var(--qy-font-family);
  --qy-text-headline-lg: 700 28px / 36px var(--qy-font-family);
  --qy-text-headline-md: 600 20px / 28px var(--qy-font-family);
  --qy-text-body-lg: 400 16px / 24px var(--qy-font-family);
  --qy-text-body-md: 400 14px / 20px var(--qy-font-family);
  --qy-text-body-sm: 400 12px / 18px var(--qy-font-family);
  --qy-text-label-md: 600 12px / 16px var(--qy-font-family);
  --qy-text-financial: 500 14px / 20px var(--qy-font-family);
  --qy-tracking-tight: -0.02em;
  --qy-tracking-label: 0.05em;

  /* ---- spacing --------------------------------------------------------
     Values identical to the existing --rt-space-* / --qy-space-* scales, so
     L2 can converge those onto this one with zero visual delta. */
  --qy-space-1: 4px;
  --qy-space-2: 8px;
  --qy-space-3: 12px;
  --qy-space-4: 16px;
  --qy-space-5: 20px;
  --qy-space-6: 24px;
  --qy-space-8: 32px;
  --qy-space-10: 40px;
  --qy-space-12: 48px;
  --qy-space-16: 64px;

  /* ---- radius (values identical to existing scales) -------------------- */
  --qy-radius-sm: 8px;
  --qy-radius-md: 12px;
  --qy-radius-lg: 16px;
  --qy-radius-xl: 20px;
  --qy-radius-2xl: 28px;
  --qy-radius-pill: 999px;

  /* ---- elevation (dark-appropriate; light shadows are invisible on ink) --
     S4.11D — RAMPA PROGRESIVA, NO MANCHA RECTANGULAR.

     Antes cada nivel eran DOS capas: un contacto de 2-4px y un salto directo
     a 24-48px de desenfoque con alfa alta (0.28-0.36). Dos capas separadas
     por semejante hueco no describen una caída de luz: describen un borde.
     Sobre el fondo oscuro esa segunda capa se lee como un rectángulo teñido
     bajo la tarjeta, con un corte visible donde el desenfoque termina. Es
     exactamente lo que el propietario describió en la revisión móvil.

     Ahora cada nivel son TRES capas con desenfoque creciente y alfa
     decreciente. La suma de alfas baja respecto a la versión anterior -- la
     sombra pesa menos -- pero la transición es continua y no deja canto.
     ---------------------------------------------------------------------- */
  --qy-elevation-card: 0 1px 2px rgba(0, 0, 0, 0.18),
    0 4px 10px rgba(0, 0, 0, 0.14),
    0 12px 28px rgba(0, 0, 0, 0.12);
  --qy-elevation-panel: 0 1px 2px rgba(0, 0, 0, 0.2),
    0 6px 16px rgba(0, 0, 0, 0.16),
    0 20px 44px rgba(0, 0, 0, 0.14);
  --qy-elevation-raised: 0 1px 0 var(--qy-color-surface-highlight) inset,
    0 2px 6px rgba(0, 0, 0, 0.16),
    0 10px 24px rgba(0, 0, 0, 0.14),
    0 24px 48px rgba(0, 0, 0, 0.1);
  --qy-elevation-modal: 0 2px 8px rgba(0, 0, 0, 0.28),
    0 12px 32px rgba(0, 0, 0, 0.26),
    0 32px 80px rgba(0, 0, 0, 0.24);

  /* ---- motion (values identical to existing scales) -------------------- */
  --qy-motion-fast: 160ms;
  --qy-motion-base: 220ms;
  --qy-motion-slow: 320ms;
  --qy-motion-ease: cubic-bezier(0.22, 1, 0.36, 1);

  /* ---- movimiento direccional de ruta (S4.11G) -------------------------
     Duración y recorrido del cambio lateral de pantalla: menú inferior y
     conmutador Hoy / Resumen financiero. Van juntos y aparte de la escala
     general porque describen UN gesto concreto -- "el contenido ha llegado
     de este lado" -- y se ajustan como pareja: subir la distancia sin subir
     la duración convierte la pista en un tirón. */
  --qy-motion-route: 200ms;
  --qy-motion-route-travel: 16px;

  /* ---- focus ----------------------------------------------------------
     Two-stop ring: an inset the colour of the surface behind it, then the
     brand ring. Readable on every surface in the ramp (brand measures
     >= 6:1 against all four) and on light legacy surfaces alike. */
  --qy-focus-ring-width: 2px;
  --qy-focus-ring-offset: 2px;
  --qy-focus-ring: 0 0 0 var(--qy-focus-ring-offset) var(--qy-color-bg),
    0 0 0 calc(var(--qy-focus-ring-offset) + var(--qy-focus-ring-width))
      var(--qy-color-focus);

  /* ---- touch / layout / safe area -------------------------------------- */
  --qy-touch-min: 48px;

  /* ---- caja de icono (S4.11D) -----------------------------------------
     Un icono enmascarado se centra bien solo si su CAJA es cuadrada y no
     puede encogerse. Cuando la caja se estrecha por presión del flex, la
     máscara `contain` reduce el dibujo y lo deja descentrado dentro de un
     rectángulo: ese es el defecto que el propietario vio en el icono de
     exportar de Resumen. Estos dos valores fijan la caja y el dibujo por
     separado para que ningún control los reinvente. */
  --qy-icon-box: 20px;
  --qy-icon-glyph: 18px;
  --qy-safe-top: env(safe-area-inset-top, 0px);
  --qy-safe-bottom: env(safe-area-inset-bottom, 0px);
  --qy-safe-left: env(safe-area-inset-left, 0px);
  --qy-safe-right: env(safe-area-inset-right, 0px);

  --qy-sidebar-width: 280px;
  --qy-content-max: 1280px;
  --qy-bottom-nav-h: 72px;
  --qy-pad-desktop: 32px;
  --qy-pad-mobile: 20px;

  /* ---- z-index -------------------------------------------------------- */
  --qy-z-base: 0;
  --qy-z-sticky: 100;
  --qy-z-nav: 200;
  --qy-z-drawer: 300;
  --qy-z-modal: 400;
  --qy-z-toast: 500;
  --qy-z-gate: 600;
}

/* Breakpoint constants are documented, not declared: CSS media queries
   cannot consume custom properties.
     --qy-bp-sm  480px
     --qy-bp-md  768px
     --qy-bp-lg  1024px
     --qy-bp-xl  1280px */

@media (prefers-reduced-motion: reduce) {
  :root {
    --qy-motion-fast: 0ms;
    --qy-motion-base: 0ms;
    --qy-motion-slow: 0ms;

    /* El recorrido lateral se anula en el origen: cualquier regla que lo
       consuma deja de trasladar nada sin tener que declararlo otra vez. */
    --qy-motion-route: 0ms;
    --qy-motion-route-travel: 0px;
  }
}

/* =========================================================================
   L2 — NEUTRAL CONVERGENCE (GLOBAL, ZERO VISUAL DELTA)

   Every re-point below replaces a literal whose current computed value is
   byte-identical to the canonical token it now references. Verified by
   scripts/test-ui-redesign-s4-1-token-foundation-v1.mjs.

   Deliberately NOT converged here:
     --rt-nav-height / --rt-nav-width / --rt-nav-bottom / --rt-page-x
       -> redefined inside @media in viewport-fix.css; a later :root
          declaration at equal specificity would silently beat the responsive
          overrides and break the mobile navigation.
     every colour-bearing legacy variable
       -> would invert the light product; belongs to L3.
   ========================================================================= */

:root {
  /* brand anchor: one literal #12BFA6 for the whole codebase */
  --rt-turquoise: var(--qy-color-brand);
  --rt-turquoise-hover: var(--qy-color-brand-hover);
  --rt-turquoise-deep: var(--qy-color-brand-deep);
  --qy-turquoise: var(--qy-color-brand);
  --qy-turquoise-hover: var(--qy-color-brand-hover);
  --qy-turquoise-deep: var(--qy-color-brand-deep);

  /* ---- typography family (S4.1F) -------------------------------------
     `html` and `body` render through --qy-font / --rt-font, which both
     named "Inter" -- a family with no @font-face and no file behind it, so
     the app actually rendered system-ui. Re-pointing them at the canonical
     chain is what makes Plus Jakarta Sans the real runtime font instead of
     a declaration nothing resolves to.

     This is NOT value-identical like the scales below it: it is the
     intended, measured metric change the S4.1F gate exists to land before
     S4.2 builds the shell. If qy-tokens-v1.css ever fails to load, these
     re-points vanish and the earlier "Inter" declarations take over, which
     degrades to exactly today's system-ui rendering. */
  --rt-font: var(--qy-font-family);
  --qy-font: var(--qy-font-family);

  /* spacing scale */
  --rt-space-1: var(--qy-space-1);
  --rt-space-2: var(--qy-space-2);
  --rt-space-3: var(--qy-space-3);
  --rt-space-4: var(--qy-space-4);
  --rt-space-5: var(--qy-space-5);
  --rt-space-6: var(--qy-space-6);
  --rt-space-8: var(--qy-space-8);
  --rt-space-10: var(--qy-space-10);
  --rt-space-12: var(--qy-space-12);
  --rt-space-16: var(--qy-space-16);

  /* radius scale */
  --rt-radius-sm: var(--qy-radius-sm);
  --rt-radius-md: var(--qy-radius-md);
  --rt-radius-lg: var(--qy-radius-lg);
  --rt-radius-xl: var(--qy-radius-xl);
  --rt-radius-2xl: var(--qy-radius-2xl);
  --rt-radius-pill: var(--qy-radius-pill);

  /* motion scale */
  --rt-motion-fast: var(--qy-motion-fast);
  --rt-motion-base: var(--qy-motion-base);
  --rt-motion-slow: var(--qy-motion-slow);
  --rt-motion-ease: var(--qy-motion-ease);
}

/* =========================================================================
   L3 — DARK ACTIVATION (SCOPED, PROGRESSIVE)

   INERT until a subtree opts in. This is the whole convergence payload: the
   26 legacy-palette consumers and the 14 --rt-* consumers inherit the Stitch
   semantics here without any of the 47 stylesheets being edited individually.

   Opt in with either:
     <html data-qy-theme="stitch">   whole-app activation (S4.2+ only)
     <div class="qy-theme">          one migrated subtree

   No legacy alias is deleted in this wave. Compatibility aliases are
   intentionally retained until every consuming surface has migrated.
   ========================================================================= */

:root[data-qy-theme="stitch"],
.qy-theme {
  color-scheme: dark;

  /* ---- --rt-* family (14 consumer stylesheets) ----------------------- */
  --rt-ink: var(--qy-color-text-primary);
  --rt-ink-secondary: var(--qy-color-text-secondary);
  --rt-slate: var(--qy-color-text-secondary);
  --rt-muted: var(--qy-color-text-tertiary);

  --rt-background: var(--qy-color-bg);
  --rt-surface: var(--qy-color-surface-1);
  --rt-surface-soft: var(--qy-color-surface-2);
  --rt-border: var(--qy-color-border);

  --rt-turquoise-light: var(--qy-color-brand);
  --rt-turquoise-mist: var(--qy-color-brand-soft);

  --rt-pending: var(--qy-color-pending);
  --rt-pending-soft: var(--qy-color-pending-soft);
  --rt-alert: var(--qy-color-cancelled);
  --rt-alert-soft: var(--qy-color-cancelled-soft);
  --rt-danger: var(--qy-color-cancelled);
  --rt-danger-soft: var(--qy-color-cancelled-soft);

  --rt-primary: var(--qy-color-brand);
  --rt-primary-hover: var(--qy-color-brand-hover);
  --rt-primary-deep: var(--qy-color-brand-deep);
  --rt-accent: var(--qy-color-brand);
  --rt-brand: var(--qy-color-brand);
  --rt-success: var(--qy-color-collected);
  --rt-success-soft: var(--qy-color-collected-soft);

  /* --rt-font is converged globally in L2 since S4.1F: the family is the
     same in both themes, so it does not belong to the scoped layer. */
  --rt-shadow-card: var(--qy-elevation-card);
  --rt-shadow-panel: var(--qy-elevation-panel);

  /* ---- --qy-* legacy primitives -------------------------------------
     These predate the semantic contract and mean the OPPOSITE of what
     their names now suggest: --qy-ink was TEXT, --qy-background was a
     LIGHT surface. They are re-pointed, not renamed, so the existing
     quomya-visual-system.css rules keep resolving. */
  --qy-ink: var(--qy-color-text-primary);
  --qy-ink-secondary: var(--qy-color-text-secondary);
  --qy-slate: var(--qy-color-text-secondary);
  --qy-muted: var(--qy-color-text-tertiary);
  --qy-background: var(--qy-color-bg);
  --qy-surface: var(--qy-color-surface-1);
  --qy-surface-soft: var(--qy-color-surface-2);
  --qy-border: var(--qy-color-border);
  --qy-turquoise-light: var(--qy-color-brand);
  --qy-turquoise-mist: var(--qy-color-brand-soft);
  --qy-pending: var(--qy-color-pending);
  --qy-pending-soft: var(--qy-color-pending-soft);
  --qy-alert: var(--qy-color-cancelled);
  --qy-alert-soft: var(--qy-color-cancelled-soft);
  /* --qy-font is converged globally in L2 since S4.1F (see --rt-font). */
  --qy-shadow-card: var(--qy-elevation-card);
  --qy-shadow-panel: var(--qy-elevation-panel);
  --qy-shadow-modal: var(--qy-elevation-modal);

  /* ---- unprefixed legacy palette (26 consumer stylesheets) ----------- */
  --bg: var(--qy-color-bg);
  --bg-deep: var(--qy-color-bg);
  --background: var(--qy-color-bg);
  --surface: var(--qy-color-surface-1);
  --surface-solid: var(--qy-color-surface-1);
  --surface-soft: var(--qy-color-surface-2);
  --text: var(--qy-color-text-primary);
  --text-soft: var(--qy-color-text-secondary);
  --ink: var(--qy-color-text-primary);
  --muted: var(--qy-color-text-secondary);
  --muted-2: var(--qy-color-text-tertiary);
  --border: var(--qy-color-border);
  --border-strong: var(--qy-color-border-strong);
  --primary: var(--qy-color-brand);
  --primary-2: var(--qy-color-brand-deep);
  --primary-soft: var(--qy-color-brand-soft);
  --accent: var(--qy-color-brand);
  --accent-soft: var(--qy-color-brand-soft);
  --success: var(--qy-color-collected);
  --success-bg: var(--qy-color-collected-soft);
  --warning: var(--qy-color-pending);
  --warning-bg: var(--qy-color-pending-soft);
  --danger: var(--qy-color-cancelled);
  --danger-bg: var(--qy-color-cancelled-soft);
  --radius-sm: var(--qy-radius-md);
  --radius-md: var(--qy-radius-lg);
  --radius-lg: var(--qy-radius-xl);
  --radius-xl: var(--qy-radius-2xl);
  --shadow-card: var(--qy-elevation-card);
  --shadow-soft: var(--qy-elevation-panel);
  --shadow-button: var(--qy-elevation-card);
  --ease-out: var(--qy-motion-ease);
}

/* When the whole document is themed, paint the page itself. Scoped to the
   attribute form only: .qy-theme is a subtree opt-in and must not repaint
   the surrounding legacy page. */
:root[data-qy-theme="stitch"] {
  background: var(--qy-color-bg);
  color: var(--qy-color-text-primary);
}

:root[data-qy-theme="stitch"] body {
  background: var(--qy-color-bg);
  color: var(--qy-color-text-primary);
}

/* =========================================================================
   L4 — APARIENCIA CLARA (S4.11A)

   Segundo juego de valores para los MISMOS tokens L1. No es una segunda
   fuente de verdad: vive en este archivo precisamente porque el contrato
   semantico --qy-color-* debe declararse en uno solo, que es la invariante
   que S4.1 fijo y que test-ui-redesign-s4-1-token-foundation-v1.mjs vigila.
   Un tema claro es parte de la paleta, no una paleta aparte.

   Se declara DESPUES de L1 y de L3 y, como las propiedades personalizadas se
   resuelven en el momento de uso, los ~40 alias heredados de L3 -- las tres
   familias que consumen las 47 hojas -- cambian de tema sin editar ni una
   regla suya. Ese es todo el mecanismo.

   ACTIVACION: :root[data-qy-appearance-resolved="light"], que escriben
   appearanceBoot.js (antes del primer pintado) y appearance.js (al
   reconciliar con la cuenta y al cambiar el tema del sistema). El atributo
   lleva el tema EFECTIVO, ya resuelto; la preferencia del usuario --
   system / light / dark -- viaja aparte en data-qy-appearance.

   La mecanica no cromatica que acompana a esta capa -- correccion de
   color-scheme en los ambitos heredados, pintado de html/body y transicion
   de cambio de tema -- vive en qy-appearance-v1.css, que no declara ningun
   --qy-color-*.

   EL TEMA CLARO ESTA DISENADO, NO INVERTIDO. No es blanco en todas partes:
   la pagina se apoya en un off-white frio emparentado con Deep Ink, las
   tarjetas suben a blanco para separarse de ella por LUZ y no por otro
   borde, y la tipografia es el propio Deep Ink de la marca.

   El ancla #12BFA6 NO se toca: sigue siendo relleno, icono y marca en ambos
   temas. Lo que cambia es su rol de TEXTO, que sobre blanco mide 2.33:1 y
   necesita variante tonal -- el mismo tratamiento que la paleta ya daba a
   cobrado, pendiente, cierre y cancelado.

   Contrastes medidos y tabulados al final de qy-appearance-v1.css.
   ========================================================================= */

:root[data-qy-appearance-resolved="light"] {
  color-scheme: light;

  /* ---- rampa de superficies (claro) -----------------------------------
     Cuatro escalones reales, no blanco repetido. La página es la más
     apagada; la tarjeta es la más luminosa. Así una tarjeta se separa del
     fondo por diferencia tonal y una sombra suave, y deja de necesitar el
     rectángulo redondeado dentro del rectángulo redondeado que el propietario
     señaló. */
  --qy-color-bg: #eff3f5;
  --qy-color-surface-1: #ffffff;
  --qy-color-surface-2: #f2f5f7;
  --qy-color-surface-3: #e8edf0;
  --qy-color-surface-highlight: rgba(255, 255, 255, 0.92);
  --qy-color-surface-brand-wash: rgba(18, 191, 166, 0.08);

  /* ---- bordes ---------------------------------------------------------
     -border y -border-strong son separadores decorativos (exentos de
     1.4.11). -border-interactive es el mínimo que alcanza 3:1 sobre las
     CUATRO superficies de la rampa clara y es obligatorio allí donde el
     borde es la única señal del límite de un control. */
  --qy-color-border: #dfe6e9;
  --qy-color-border-strong: #c9d4d9;
  --qy-color-border-interactive: #5f7280;

  /* ---- texto ----------------------------------------------------------
     La tinta primaria es Deep Ink, el mismo #0B1D29 que en oscuro es la
     superficie-1. La identidad de Quomya sobrevive al cambio de tema. */
  --qy-color-text-primary: #0b1d29;
  --qy-color-text-secondary: #4a5c6a;
  --qy-color-text-tertiary: #556673;

  /* Sin cambio: #04241F mide 7.07:1 sobre el ancla de marca, y el ancla es
     la misma en los dos temas. */
  --qy-color-text-on-brand: #04241f;

  /* ---- marca ----------------------------------------------------------
     El ancla, el hover y la profundidad NO se ajustan. Solo el rol de texto,
     que sobre blanco necesita bajar a 6.41:1. */
  --qy-color-brand-text: #046b5f;
  --qy-color-brand-soft: rgba(18, 191, 166, 0.16);

  /* ---- estado ---------------------------------------------------------
     El ANCLA de cada estado se conserva para rellenos, iconos y bordes; solo
     el rol -text recibe la variante tonal, igual que hace el contrato oscuro
     en sentido contrario. */
  /*
     Cobrado y pendiente van UN escalón más oscuros de lo que exigiría la
     rampa de superficies. No es prudencia: es que estos dos roles se pintan
     casi siempre sobre su PROPIO relleno tenue, y varias hojas heredadas lo
     aplican al 20 % en lugar del 16 % de aquí. Medido sobre ese peor caso
     real -- rgb(206,235,228) y rgb(243,229,205) -- los valores de la rampa
     daban 4.35:1 y 4.37:1, justo por debajo de AA. Con estos, 5.16:1 y
     5.19:1. Los anclas #10B981 y #F59E0B no se tocan.
  */
  --qy-color-collected-soft: rgba(16, 185, 129, 0.16);
  --qy-color-collected-text: #046b4f;

  --qy-color-pending-soft: rgba(245, 158, 11, 0.18);
  --qy-color-pending-text: #8a5100;

  --qy-color-closure-soft: rgba(59, 130, 246, 0.14);
  --qy-color-closure-text: #1d4ed8;

  --qy-color-cancelled-soft: rgba(239, 68, 68, 0.14);
  --qy-color-cancelled-text: #b91c1c;

  /* ---- estados interactivos -------------------------------------------
     En oscuro se aclara con blanco translúcido; en claro hay que oscurecer
     con la propia tinta o el hover es invisible. */
  --qy-color-hover: rgba(11, 29, 41, 0.05);
  --qy-color-active: rgba(11, 29, 41, 0.09);
  --qy-color-selected: var(--qy-color-brand-soft);
  --qy-color-disabled-text: #8a99a5;

  /* El anillo de foco es el único uso de la marca donde 1.4.11 SÍ aplica:
     sobre blanco el ancla mide 2.33:1. Se usa el rol de texto (6.41:1).
     `--qy-focus-ring` se recompone solo, porque referencia este token y
     `--qy-color-bg`, que también acaba de cambiar. */
  --qy-color-focus: var(--qy-color-brand-text);

  /* ---- rampa categórica (SOLO GRÁFICOS) -------------------------------
     La rampa oscura es pastel por diseño y desaparece sobre blanco. Esta es
     su equivalente claro: seis tonos distinguibles entre sí y legibles sobre
     la rampa clara. Sigue sin ser una escala de estado. */
  --qy-cat-1: #0d9488;
  --qy-cat-2: #0369a1;
  --qy-cat-3: #4f46e5;
  --qy-cat-4: #7c3aed;
  --qy-cat-5: #b45309;
  --qy-cat-6: #475569;

  /* ---- rampa de INTENSIDAD de gráfico (claro) -------------------------
     Sobre off-white el ancla turquesa al 16 % es prácticamente el fondo. La
     rampa clara parte de `--qy-color-brand-deep` (#078D7E), que conserva la
     identidad y sí se despega del papel en el primer escalón. Los cuatro
     pesos mantienen la misma progresión relativa que en oscuro, de modo que
     "más intenso" significa lo mismo en los dos temas. */
  --qy-chart-intensity-1: rgba(7, 141, 126, 0.16);
  --qy-chart-intensity-2: rgba(7, 141, 126, 0.34);
  --qy-chart-intensity-3: rgba(7, 141, 126, 0.6);
  --qy-chart-intensity-4: rgba(7, 141, 126, 0.92);

  --qy-chart-area-top: rgba(7, 141, 126, 0.26);
  --qy-chart-area-mid: rgba(7, 141, 126, 0.1);
  --qy-chart-area-bottom: rgba(7, 141, 126, 0);

  /* ---- elevación ------------------------------------------------------
     La sombra oscura de la rampa Deep Ink es opaca a propósito: sobre tinta
     una sombra suave no existe. Sobre off-white pasa lo contrario, y la
     misma sombra ensuciaría la página. Se rebaja y se tiñe de Deep Ink en
     lugar de negro puro, que sobre azul frío se ve gris sucio.

     Esta es la herramienta con la que S4.11A sustituye jerarquía por
     profundidad en vez de por otro borde anidado.

     S4.11D aplica aquí la MISMA rampa de tres capas que en oscuro: mismo
     lenguaje de profundidad en los dos temas, sin islas. */
  --qy-elevation-card: 0 1px 2px rgba(11, 29, 41, 0.05),
    0 4px 10px rgba(11, 29, 41, 0.045),
    0 12px 26px rgba(11, 29, 41, 0.04);
  --qy-elevation-panel: 0 1px 2px rgba(11, 29, 41, 0.06),
    0 6px 16px rgba(11, 29, 41, 0.055),
    0 20px 42px rgba(11, 29, 41, 0.05);
  --qy-elevation-raised: 0 1px 0 var(--qy-color-surface-highlight) inset,
    0 2px 6px rgba(11, 29, 41, 0.06),
    0 10px 24px rgba(11, 29, 41, 0.05),
    0 24px 46px rgba(11, 29, 41, 0.045);
  --qy-elevation-modal: 0 2px 8px rgba(11, 29, 41, 0.12),
    0 12px 32px rgba(11, 29, 41, 0.11),
    0 32px 68px rgba(11, 29, 41, 0.1);
}

/* =========================================================================
   ACCESSIBILITY — measured, not asserted
   (contrast ratios against the full surface ramp bg / s1 / s2 / s3)

   text-primary   #FFFFFF   17.72 17.19 15.69 13.98   AA
   text-secondary #94A3B8    6.91  6.70  6.12  5.45   AA
   text-tertiary  #8494A8    5.72  5.55  5.07  4.52   AA   (adjusted)
   brand          #12BFA6    7.62  7.39  6.75  6.01   AA
   collected      #10B981    6.99  6.77  6.19  5.51   AA
   pending        #F59E0B    8.25  8.00  7.31  6.51   AA
   closure        #3B82F6    4.82  4.67  4.27  3.80   anchor only
   closure-text   #60A5FA    6.97  6.76  6.17  5.50   AA
   cancelled      #EF4444    4.71  4.57  4.17  3.72   anchor only
   cancelled-text #F87171    6.41  6.21  5.67  5.05   AA
   border-interactive #667E92 4.19 4.06  3.71  3.30   >= 3:1 (1.4.11)
   focus ring     #12BFA6    7.62 on bg                >= 3:1 (1.4.11)
   text-on-brand  #04241F    7.07 on #12BFA6           AA

   ADJUSTMENTS MADE, AND WHY:
     text-tertiary  #64748B -> #8494A8   #64748B is 2.94:1 on surface-3.
     closure text   #3B82F6 -> #60A5FA   anchor is 3.80:1 on surface-3.
     cancelled text #EF4444 -> #F87171   anchor is 3.72:1 on surface-3.
     collected text #10B981 -> #34D399   anchor is 4.38:1 on its own soft
                                         fill over surface-3.
   In every case the CANONICAL ANCHOR IS PRESERVED for fills, icons, marks
   and borders; only the text role receives the tonal variant. The brand
   anchor #12BFA6 is unchanged and was never a candidate for adjustment.
   ========================================================================= */
