/* Fonts loaded via <link> in HTML <head> — see header.html, base.html.
   Design tokens: :root block below. Dark theme: [data-theme="dark"] block. */

/* ═══════════════════════════════════════════════════
   Tailwind v3 Preflight Overrides
   ───────────────────────────────────────────────────
   Tailwind v3 preflight is more aggressive than v2 normalize.
   These overrides restore sane defaults for our design system.
   Must load AFTER tailwind.output.css (cascade order).
   ═══════════════════════════════════════════════════ */

/* v3 preflight border-color override moved to src/tailwind-input.css @layer base */

/* v3 resets headings to font-size/weight: inherit.
   All headings in templates use explicit classes (.page-title,
   .dashboard-section-title, .refund-section__title, or Tailwind text-*).
   Only set color inheritance — sizing comes from component classes. */
h5, h6 {
    font-family: var(--font-heading);
    color: var(--color-text-primary);
}
h1 {
    font-family: var(--font-heading);
    color: var(--color-text-primary);
    font-size: clamp(1.75rem, 1.5rem + 1.25vw, 2.25rem);
    font-weight: var(--font-semibold);
    line-height: var(--leading-tight);
    letter-spacing: var(--tracking-tighter);
}
h2 {
    font-family: var(--font-heading);
    color: var(--color-text-primary);
    font-size: clamp(1.375rem, 1.2rem + 0.75vw, 1.5rem);
    font-weight: var(--font-semibold);
    line-height: var(--leading-tight);
    letter-spacing: var(--tracking-tight);
}
h3 {
    font-family: var(--font-heading);
    color: var(--color-text-primary);
    font-size: var(--text-xl);
    font-weight: var(--font-medium);
    line-height: var(--leading-snug);
}
h4 {
    font-family: var(--font-heading);
    color: var(--color-text-primary);
    font-size: var(--text-lg);
    font-weight: var(--font-medium);
    line-height: var(--leading-snug);
}

/* v3 strips list styling — only restore where explicitly needed via class.
   Most lists in this app are navigation/UI, not content lists.
   Use .list-disc / .list-decimal in templates for content lists. */

/* v3 sets img to display:block — keep it but ensure proper alignment */
img {
    vertical-align: middle;
    /* max-width: 100% from v3 preflight is kept — good for responsive */
    /* display: block from v3 preflight is kept — override per-element if needed */
}
/* Icons inside buttons/links/flex need to be inline */
button img,
a img,
.inline-flex img,
.flex img:where(:not(.block)) {
    display: inline-block;
}

/* v3 strips paragraph margins — spacing handled by Tailwind utilities (mb-*) in templates */

/* ═══════════════════════════════════════════════════
   Base Styles
   ═══════════════════════════════════════════════════ */

body {
    font-family: var(--font-body);
    color: var(--color-text-primary);
    line-height: var(--leading-normal);
    letter-spacing: var(--tracking-normal);
    /* height: 100% removed — caps body at 100vh, preventing content from growing */
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    background-color: var(--color-bg-page);
    overflow-x: clip; /* clip instead of hidden — prevents horizontal scroll without breaking position: sticky */
}
/* Form elements inherit body font */
input, select, textarea, button {
    font-family: inherit;
}

a {
	text-decoration: none;
	color: var(--color-link);
}
a:hover {
	color: var(--color-link-hover);
}

::placeholder {
    color: var(--color-text-placeholder);
    opacity: 1;
}

::selection {
    background-color: var(--brand-primary);
    color: var(--color-text-inverse);
}

/* Layout configuration */
html {
    height: 100%;
    scroll-behavior: smooth;
    overflow-x: hidden; /* Structural containment — prevents any descendant from causing horizontal scroll */
}

main {
    flex: 1 0 auto;
}
/* ═══════════════════════════════════════════════════
   Design Tokens — Zelebrix
   Source: main.css :root
   Apps: admin (zelebrix), cargaOnline
   ═══════════════════════════════════════════════════ */
:root {
    /* ═══ Layout ═══ */
    --container-max: clamp(1280px, 85vw, 2400px);
    --container-gutter: clamp(16px, 4vw, 32px);
    --container-radius: var(--radius-xl);
    --container-shadow: 0 6px 18px rgba(0, 0, 0, 0.06),
                        0 4px 10px rgba(51, 190, 255, 0.05);

    /* ═══ Brand ═══ */
    --brand-primary: #33BEFF;
    --brand-primary-dark: #0369a1;            /* HSL(201°, 96%, 32%) — hue-coherent with brand-primary */
    --brand-primary-hover: #00B3EF;          /* HSL(195°, 100%, 47%) */
    --brand-primary-active: #0099D6;         /* HSL(195°, 100%, 42%) */
    --brand-primary-light: #E0F7FF;          /* HSL(195°, 100%, 94%) */
    --brand-primary-shadow: rgba(51, 190, 255, 0.32);
    --brand-primary-shadow-strong: rgba(3, 105, 161, 0.35);
    --brand-focus-ring: rgba(51, 190, 255, 0.45);

    /* ═══ State Colors ═══ */
    --color-success: #16a34a;        /* green-600 */
    --color-success-hover: #15803d;  /* green-700 */
    --color-success-bg: #dcfce7;     /* green-100 */
    --color-error: #dc2626;          /* red-600 */
    --color-error-hover: #b91c1c;    /* red-700 */
    --color-error-light: #ef4444;    /* red-500 */
    --color-error-bg: #fee2e2;       /* red-100 */
    --color-info: #2563eb;           /* blue-600 */
    --color-info-hover: #1d4ed8;     /* blue-700 */
    --color-info-bg: #dbeafe;        /* blue-100 */
    --color-warn: #d97706;           /* amber-600 */
    --color-warn-hover: #b45309;     /* amber-700 */
    --color-warn-bg: #fef3c7;        /* amber-100 — pastel */
    --color-purple: #9333ea;         /* purple-600 */

    /* ═══ Gray Palette ═══ */
    --gray-50: #f9fafb;
    --gray-100: #f3f4f6;
    --gray-200: #e5e7eb;
    --gray-300: #d1d5db;
    --gray-400: #9ca3af;
    --gray-500: #6b7280;
    --gray-600: #4b5563;
    --gray-700: #374151;
    --gray-800: #1f2937;
    --gray-900: #111827;

    /* ═══ Blue Accent Palette ═══ */
    --blue-50: #eff6ff;
    --blue-300: #93c5fd;
    --blue-800: #1e40af;

    /* ═══ Toggle ═══ */
    --toggle-track-off: #d1d5db;     /* gray-300 */
    --toggle-knob-off: #E6F7FF;      /* subtle brand tint */
    --toggle-focus-ring: rgba(51, 190, 255, 0.35);

    /* ═══ Typography ═══ */
    --text-3xs: 0.5625rem; /* 9px  — T438: usar solo en badges ultra-compactos (CO labels legacy) */
    --text-2xs: 0.6875rem; /* 11px */
    --text-xs: 0.75rem;    /* 12px */
    --text-sm: 0.875rem;   /* 14px */
    --text-base: 1rem;     /* 16px */
    --text-lg: 1.125rem;   /* 18px */
    --text-xl: 1.25rem;    /* 20px */
    --text-2xl: 1.5rem;    /* 24px */

    /* ═══ Shadows ═══ */
    --shadow-color: 15, 23, 42; /* slate-900 RGB base */
    --shadow-xs: 0 1px 2px rgba(0,0,0,0.05), 0 1px 3px rgba(51, 190, 255, 0.04);
    --shadow-sm: 0 1px 3px rgba(0,0,0,0.08), 0 2px 6px rgba(51, 190, 255, 0.06);
    --shadow-md: 0 4px 6px -1px rgba(0,0,0,0.08), 0 4px 12px -2px rgba(51, 190, 255, 0.08);
    --shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.08), 0 8px 20px -4px rgba(51, 190, 255, 0.10);
    --shadow-brand-sm: 0 6px 12px var(--brand-primary-shadow);
    --shadow-brand-lg: 0 8px 16px var(--brand-primary-shadow-strong);
    --shadow-color-accent: 151, 65, 252; /* purple RGB for CTA buttons */

    /* ═══ Border Radius ═══ */
    --radius-xs: 2px;
    --radius-sm: 4px;      /* 0.25rem */
    --radius-md: 8px;      /* 0.5rem */
    --radius-lg: 12px;     /* 0.75rem */
    --radius-xl: 16px;
    --radius-2xl: 20px;
    --radius-full: 9999px; /* pills, toggles */

    /* ═══ Typography Scale — 4 niveles, fluid clamps ═══
       display: hero KPI numbers
       h2:      card titles
       body:    default text
       caption: labels, metadata, tooltips
    */
    --text-display-size:    clamp(36px, 5.5vw, 52px);
    --text-display-leading: 1.05;
    --text-display-tracking: -0.025em;
    --text-display-weight:  700;

    --text-h2-size:         clamp(18px, 2vw, 22px);
    --text-h2-leading:      1.25;
    --text-h2-tracking:     -0.01em;
    --text-h2-weight:       600;

    --text-body-size:       16px;
    --text-body-leading:    1.5;

    --text-caption-size:    13px;
    --text-caption-leading: 1.4;
    --text-caption-tracking: 0.02em;

    /* ═══ Semantic Aliases — Theme layer ═══
       Punto de enganche para tarea 034 (temas claro/oscuro).
       La 034 reasigna estos bajo [data-theme="dark"] sin tocar templates.
    */
    --color-text-primary: var(--gray-900);
    --color-text-secondary: var(--gray-600);
    --color-text-muted: var(--gray-500);
    --color-text-inverse: #ffffff;
    /* T174 P174-7 — Token intensificado para texto muted sobre superficies
       elevadas (slate-700 en dark). En light el muted estandar ya supera
       AA sobre bg-elevated, asi que aqui mantenemos el alias. */
    --color-text-muted-on-elevated: var(--color-text-muted);
    /* T174 P174-7 — fg intensificado para los chips de variation; sin
       esto el contraste 1.00 los vuelve invisibles en dark. En light se
       mantiene el semantic hover, que ya es AA sobre bg con alpha 12%. */
    --color-variation-success-fg: var(--color-success-hover);
    --color-variation-error-fg: var(--color-error-hover);
    --color-bg-page: var(--gray-50);
    --color-bg-surface: #ffffff;
    --color-bg-elevated: var(--gray-50);
    --color-bg-total-row: var(--gray-100);  /* #f3f4f6 — legend table TOTAL row, distinct from --color-bg-page */
    --color-bg-muted: var(--gray-200);
    --color-border-default: var(--gray-200);
    --color-border-strong: var(--gray-300);
    --color-primary-disabled: rgba(51, 190, 255, 0.55);

    /* ═══ shadcn-style aliases (T149 hero v2) — map to canonical tokens ═══
       The hero v2 redesign in T149 introduced shadcn-style names that did not
       exist in the zelebrix token system. The CSS already wrote `var(--name,
       fallback)` so runtime worked, but check_var_references_resolve flags
       the missing definitions. Map them here to the canonical equivalents. */
    --color-text: var(--color-text-primary);
    --color-surface: var(--color-bg-surface);
    --color-surface-subtle: var(--color-bg-page);
    --color-border-subtle: var(--color-border-default);
    --color-neutral-50: var(--gray-50);
    --color-neutral-100: var(--gray-100);
    --color-primary-50: var(--color-info-bg);
    --color-primary-100: var(--color-info-bg);
    --color-primary-700: var(--color-info-hover);

    /* ═══ Semantic Aliases — Extended (tarea 039) ═══ */
    --color-link: var(--brand-primary-dark);
    --color-link-hover: var(--brand-primary-dark); /* fallback for browsers without color-mix() */
    --color-link-hover: color-mix(in srgb, var(--color-link) 80%, black);
    --color-text-placeholder: var(--gray-400);
    --color-bg-input: var(--color-bg-surface);
    --color-overlay: rgba(0, 0, 0, 0.4);
    --color-bg-disabled: var(--gray-100);
    --color-text-disabled: var(--gray-400);

    /* ═══ Extended Color Palette — KPI badge backgrounds ═══ */
    --color-yellow-100: #fef9c3;
    --color-purple-100: #ede9fe;
    --color-indigo-100: #e0e7ff;
    --color-teal-100: #ccfbf1;
    --color-orange-100: #ffedd5;
    --color-cyan-100: #cffafe;
    --color-emerald-100: #d1fae5;

    /* ═══ Slate Palette ═══ */
    --slate-50: #f8fafc;
    --slate-100: #f1f5f9;
    --slate-200: #e2e8f0;
    --slate-300: #cbd5e1;
    --slate-400: #94a3b8;
    --slate-500: #64748b;
    --slate-600: #475569;
    --slate-700: #334155;
    --slate-800: #1e293b;
    --slate-900: #0f172a;

    /* ═══ Chart Palette — colorblind-safe, min 25° hue separation ═══
       Keyed by transaction type. Used by dashboard-charts.js via _css().
       Data-viz colors — NOT for UI elements. All values MUST be hex.
    */
    --chart-sin-asignar:       #F4A0A0;  /* 0° soft coral — unassigned transactions */
    --chart-tarjeta:           #7CB9E8;  /* 206° blue — anchor */
    --chart-efectivo:          #F6D89E;  /* 40° orange */
    --chart-carga-online:      #7ECBB4;  /* 162° green */
    --chart-invitacion:        #D4A8EA;  /* 280° lavender (was 196° — collision w/ Tarjeta) */
    --chart-taptopay:          var(--brand-primary);  /* brand-primary — TTP es canal financiero principal */
    --chart-cashback:          #E8D46A;  /* 48° saturated yellow (was #F5EDA6 — collision w/ Efectivo) */
    --chart-panel-de-control:  #9B8EC4;  /* 253° indigo */
    --chart-carga-masiva:      #C4A87E;  /* 30° sand (was 166° — collision w/ C.Online) */
    --chart-correccion:        #E88E8E;  /* 0° soft red (was 333° rose — aligned w/ semantic error) */
    --chart-tickets-app:       #B3DFF0;  /* 197° cyan */
    --chart-descarga:          #F4A582;  /* 18° vermillion */
    --chart-reembolso:         #F0C490;  /* 30° soft orange (was 331° rose — aligned w/ semantic refund) */
    --chart-envio:             #EDE8C3;  /* 53° sand */
    --chart-saldo-zelebrix:    #C0C0C0;  /* neutral grey */
    --chart-pre-carga:         #6BBF6B;  /* 120° green (was 140° — collision w/ Recargas) */
    --chart-recargas:          #8FBF9F;  /* 140° green-mint (was missing / duplicated Tarjeta) */

    /* Chart: Devoluciones — border = same color at full opacity, bg via withOpacity() in JS */
    --chart-devol-periodo:     #93C5FD;  /* blue-300 */
    --chart-devol-panel:       #FDBA74;  /* orange-300 */

    /* Chart: Ticket inventory stacked bar — hex for withOpacity()/applyFinishedOverlay() compat */
    --chart-ticket-disponibles: #F0E68C;  /* khaki 54° (was #E9F0A8 — better deuteranopia separation) */
    --chart-ticket-vendidos:    #7FD77F;  /* green 120° L:67% (was #A8F0A8 L:80% — higher contrast) */
    --chart-ticket-activados:   #2FC1FF;  /* sky 195° — safe, distinct hue */

    /* ═══ Semantic Metric Colors — delegate to state colors for coherence ═══ */
    --semantic-revenue:     var(--color-success);    /* green = income/recharges */
    --semantic-consumption: var(--color-info);       /* blue = activity/spend */
    --semantic-refund:      var(--color-warn);       /* amber = attention/returns */
    --semantic-correction:  var(--color-error);      /* red = requires review */

    /* ═══ Z-index Scale ═══ */
    --z-base: 0;
    --z-raised: 30;          /* T441 H1: elements above normal flow but below sticky (e.g. dashboard-filters) */
    --z-dropdown: 100;
    --z-sticky: 200;
    --z-header: 400;
    --z-sidebar-overlay: 450;
    --z-modal-backdrop: 500;
    --z-modal: 600;
    --z-popover: 700;
    --z-tooltip: 800;
    --z-toast: 900;
    --z-chatbot: 475;

    /* ═══ Layout ═══ */
    --header-height: 56px;             /* Desktop admin: py-2 (16px) + h-10 (40px). Mobile uses drawer top:0 */

    /* ═══ Spacing Scale (4px base) ═══ */
    --space-1: 0.25rem;    /* 4px */
    --space-1-5: 0.375rem; /* 6px */
    --space-2: 0.5rem;     /* 8px */
    --space-2-5: 0.625rem; /* 10px */
    --space-3: 0.75rem;    /* 12px */
    --space-4: 1rem;       /* 16px */
    --space-5: 1.25rem;    /* 20px */
    --space-6: 1.5rem;     /* 24px */
    --space-8: 2rem;       /* 32px */
    --space-10: 2.5rem;    /* 40px */
    --space-12: 3rem;      /* 48px */

    /* ═══ Table column sizing ═══ */
    --table-cell-max-id: 22ch;   /* Truncado para celdas con UUID/chipId/saldo */

    /* ═══ Transitions ═══ */
    --transition-fast: 150ms ease;
    --transition-ui: 160ms ease;       /* sidebar, toggle interactions */
    --transition-base: 200ms ease;
    --transition-normal: 200ms ease;   /* modal overlay + panel */
    --transition-slow: 300ms ease;

    /* Duration-only tokens — use in `animation` shorthand to avoid
       double-easing when combining with an explicit timing function.
       e.g. animation: fadeInUp var(--dur-slow) ease-out forwards; */
    --dur-fast: 150ms;
    --dur-base: 200ms;
    --dur-slow: 300ms;
    --dur-flash: 1200ms;

    /* ═══ Icon sizes ═══ */
    --icon-xs: 1.125rem;   /* 18px */
    --icon-sm: 16px;
    --icon-md: 20px;
    --icon-lg: 24px;

    /* ═══ Component sizes ═══ */
    --legend-swatch-size: 12px;
    --legend-color: var(--gray-200);   /* JS overrides per-swatch; fallback prevents invisible swatches */
    --touch-target-min: 2.75rem;       /* 44px — WCAG 2.5.8 minimum */
    --toggle-width: 2.25rem;
    --toggle-height: 1.25rem;

    /* ═══ Brand Opacity Tints — rgba(brand-primary, opacity) ═══ */
    --color-brand-tint-10: rgba(51, 190, 255, 0.10);
    --color-brand-tint-12: rgba(51, 190, 255, 0.12);
    --color-brand-tint-25: rgba(51, 190, 255, 0.25);
    --color-brand-tint-30: rgba(51, 190, 255, 0.30);
    --color-brand-tint-35: rgba(51, 190, 255, 0.35);
    --color-brand-tint-60: rgba(51, 190, 255, 0.60);
    --color-brand-tint-66: rgba(51, 190, 255, 0.66);
    --gradient-premium: linear-gradient(144deg, #AF40FF, #5B42F3 50%);  /* CargaOnline premium header */
    --gradient-btn-recarga: linear-gradient(144deg, #AF40FF, #5B42F3 50%, #00DDEB);
    --gradient-btn-envio: linear-gradient(120deg, #00FF00, #2f9673);
    --gradient-btn-tickets: linear-gradient(120deg, #FF0000, #FFFF00);
    --gradient-btn-recibir: linear-gradient(120deg, #f59e0b, #ea580c);

    /* ═══ Font Families ═══ */
    --font-heading: 'Poppins', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --font-body: 'Lato', system-ui, -apple-system, 'Segoe UI', sans-serif;

    /* ═══ Font Weight ═══ */
    --font-normal: 400;
    --font-medium: 500;
    --font-semibold: 600;
    --font-bold: 700;

    /* ═══ Line Height ═══ */
    --leading-tight: 1.2;     /* headings display (h1, h2) */
    --leading-snug: 1.3;      /* headings small, labels, buttons */
    --leading-normal: 1.5;    /* body text */
    --leading-relaxed: 1.6;   /* long-form text, paragraphs */

    /* ═══ Letter Spacing ═══ */
    --tracking-tighter: -0.02em;  /* h1 display */
    --tracking-tight: -0.01em;    /* h2 */
    --tracking-normal: 0;         /* body, medium headings */
    --tracking-wide: 0.02em;      /* buttons */
    --tracking-wider: 0.05em;     /* uppercase labels */
    --tracking-widest: 0.08em;    /* overline, micro-labels */

    /* ═══ APK Builder (Ionic/Capacitor preview palette) ═══ */
    --co-accent-secondary: #b3e5fc;
    --co-accent-success: #63ba6a;
    --co-accent-warning: #ffc409;
    --co-accent-danger: #bd2727;
    --co-accent-dark: #222428;

    /* ═══ Sidebar Layout ═══ */
    --sidebar-collapsed: 64px;
    --sidebar-expanded: 230px;
    --sidebar-item-size: 44px;
    --sidebar-icon-size: 24px;

    /* ═══ White Opacity (overlays, bullets, captions) ═══ */
    --color-white-22: rgba(255, 255, 255, 0.22);
    --color-white-50: rgba(255, 255, 255, 0.5);
    --color-white-80: rgba(255, 255, 255, 0.8);

    /* ── Additional tokens (task 108) ── */
    --icon-xl: 3rem;
    --touch-target: 2.75rem;
    --modal-max-sm: 30rem;
    --modal-max-md: 40rem;
    --border-width-thin: 1px;
}

@media (min-width: 1536px) {
    :root {
        --container-max: 1400px; /* Wider layout on large screens */
    }
}

/* ═══════════════════════════════════════════════════
   Dark Theme — Tarea 034
   Reasigna los alias semánticos de :root.
   No introduce nuevas variables ni cambia selectores.
   Se activa via data-theme="dark" en <html>.
   ═══════════════════════════════════════════════════ */
[data-theme="dark"] {
    /* ── Surfaces ── */
    --color-bg-page: #0f172a;              /* slate-900 */
    --color-bg-surface: #1e293b;           /* slate-800 */
    --color-bg-elevated: #334155;          /* slate-700 */
    --color-bg-total-row: var(--color-bg-elevated); /* already distinct in dark */
    --color-bg-muted: var(--slate-600);

    /* ── Text ── */
    --color-text-primary: #f1f5f9;         /* slate-100 */
    --color-text-secondary: #cbd5e1;       /* slate-300 */
    --color-text-muted: #94a3b8;           /* slate-400 — ratio ~5.4:1 vs slate-900 */
    --color-text-inverse: #0f172a;         /* slate-900 — texto sobre fondos claros */
    /* T174 P174-7 — slate-400 sobre bg-elevated (slate-700) cae a 4.04:1,
       justo por debajo de AA. slate-300 sube a 6.97:1. */
    --color-text-muted-on-elevated: #cbd5e1;  /* slate-300 */
    /* T174 P174-7 — fg intensificado para variation chips en dark:
       - success-fg #86efac (green-300) vs bg green-400 @12% ≈ 5.1:1 ✓
       - error-fg   #fca5a5 (red-300)   vs bg red-400 @12%   ≈ 4.9:1 ✓ */
    --color-variation-success-fg: #86efac;
    --color-variation-error-fg: #fca5a5;

    /* ── Extended tokens (tarea 039) ── */
    --color-link: var(--brand-primary);
    --color-link-hover: var(--brand-primary); /* fallback for browsers without color-mix() */
    --color-link-hover: color-mix(in srgb, var(--color-link) 80%, white);
    --color-text-placeholder: var(--slate-500);
    --color-bg-input: var(--slate-700);
    --color-overlay: rgba(0, 0, 0, 0.65);
    --color-bg-disabled: var(--slate-700);
    --color-text-disabled: var(--slate-500);

    /* ── Borders ── */
    --color-border-default: #334155;       /* slate-700 */
    --color-border-strong: #475569;        /* slate-600 */
    --color-border-subtle: var(--color-border-default);  /* shadcn alias */

    /* ── Brand adjustments ── */
    --brand-primary-light: #0c2d3f;        /* HSL(195°, 66%, 15%) — fondo sutil oscuro */
    --brand-primary-shadow: rgba(51, 190, 255, 0.20);
    --brand-primary-shadow-strong: rgba(51, 190, 255, 0.30);
    --brand-focus-ring: rgba(51, 190, 255, 0.50);
    --color-brand-tint-12: rgba(51, 190, 255, 0.15);
    --color-primary-disabled: rgba(51, 190, 255, 0.35);

    /* ── State colors — more luminous for dark backgrounds ── */
    --color-success: #4ade80;              /* green-400 */
    --color-success-hover: #22c55e;        /* green-500 */
    --color-success-bg: rgba(74, 222, 128, 0.12);
    --color-error: #f87171;                /* red-400 */
    --color-error-hover: #ef4444;          /* red-500 */
    --color-error-light: #fca5a5;          /* red-300 */
    --color-error-bg: rgba(248, 113, 113, 0.12);
    --color-warn: #fbbf24;                 /* amber-400 */
    --color-warn-hover: #f59e0b;           /* amber-500 */
    --color-warn-bg: rgba(251, 191, 36, 0.12);
    --color-info: #60a5fa;                 /* blue-400 */
    --color-info-hover: #3b82f6;           /* blue-500 */
    --color-info-bg: rgba(96, 165, 250, 0.12);
    --color-purple: #c084fc;               /* purple-400 */

    /* Badge KPI surface tints (dark) */
    --color-yellow-100: rgba(250, 204, 21, 0.12);   /* yellow-400 base */
    --color-purple-100: rgba(168, 85, 247, 0.14);   /* purple-500 base */
    --color-indigo-100: rgba(129, 140, 248, 0.14);  /* indigo-400 base */
    --color-teal-100:   rgba(45, 212, 191, 0.14);   /* teal-400 base */
    --color-orange-100: rgba(251, 146, 60, 0.14);   /* orange-400 base */
    --color-cyan-100:   rgba(34, 211, 238, 0.14);   /* cyan-400 base */
    --color-emerald-100: rgba(52, 211, 153, 0.14);  /* emerald-400 base */
    --color-neutral-50:  rgba(148, 163, 184, 0.08);  /* slate-400 base — dark variant for kpi neutral chips */
    --color-neutral-100: rgba(148, 163, 184, 0.15);  /* slate-400 base — variation chip neutro sin trend */

    /* ── Shadows — MD3: dark surfaces use surface-tint for elevation,
         shadows are subtle (lower opacity than light mode) ── */
    --shadow-xs: 0 1px 2px rgba(0,0,0,0.20), 0 1px 3px rgba(51, 190, 255, 0.06);
    --shadow-sm: 0 1px 3px rgba(0,0,0,0.25), 0 2px 8px rgba(51, 190, 255, 0.08);
    --shadow-md: 0 4px 6px -1px rgba(0,0,0,0.30), 0 4px 14px -2px rgba(51, 190, 255, 0.12);
    --shadow-lg: 0 10px 15px -3px rgba(0,0,0,0.30), 0 8px 24px -4px rgba(51, 190, 255, 0.15);
    --shadow-brand-sm: 0 6px 12px rgba(51, 190, 255, 0.12);
    --shadow-brand-lg: 0 8px 16px rgba(51, 190, 255, 0.18);

    /* ── Container ── */
    --container-shadow: 0 6px 18px rgba(0, 0, 0, 0.20),
                        0 4px 12px rgba(51, 190, 255, 0.08);

    /* ── Toggle ── */
    --toggle-track-off: #475569;           /* slate-600 */
    --toggle-knob-off: #1e293b;            /* slate-800 */
    --toggle-focus-ring: rgba(51, 190, 255, 0.40);

    /* ── Chart dark overrides — vivid palette matching generatePastelColors() style.
       Formula: keep original hue, set S≈70% L≈60% for vibrant look on slate-900.
       Neutrals (taptopay, saldo-zelebrix) use S≈18% to stay muted.
       Adjacent hues separated by lightness tiers (52/60/68%) to avoid collisions. ── */
    --chart-sin-asignar:       #EA4848;  /* hsl(0, 79%, 60%) */
    --chart-tarjeta:           #5299E0;  /* hsl(210, 70%, 60%) */
    --chart-efectivo:          #EEDD44;  /* hsl(54, 83%, 60%) */
    --chart-carga-online:      #52E0BD;  /* hsl(165, 70%, 60%) */
    --chart-invitacion:        #B152E0;  /* hsl(280, 70%, 60%) */
    --chart-taptopay:          var(--brand-primary);  /* brand-primary — TTP es canal financiero principal */
    --chart-cashback:          #E5E972;  /* hsl(62, 73%, 68%) */
    --chart-panel-de-control:  #7352E0;  /* hsl(254, 70%, 60%) */
    --chart-carga-masiva:      #DAB22F;  /* hsl(46, 70%, 52%) */
    --chart-correccion:        #DA2F51;  /* hsl(348, 70%, 52%) */
    --chart-tickets-app:       #74C0E7;  /* hsl(200, 70%, 68%) */
    --chart-descarga:          #EF7143;  /* hsl(16, 84%, 60%) */
    --chart-reembolso:         #EBBE6F;  /* hsl(38, 76%, 68%) */
    --chart-envio:             #B8DA2F;  /* hsl(72, 70%, 52%) */
    --chart-saldo-zelebrix:    #AB8787;  /* hsl(0, 18%, 60%) */
    --chart-pre-carga:         #69E052;  /* hsl(110, 70%, 60%) */
    --chart-recargas:          #2FDA7F;  /* hsl(148, 70%, 52%) */
    --chart-devol-periodo:     #0F56FA;  /* hsl(222, 96%, 52%) */
    --chart-devol-panel:       #FB7D0E;  /* hsl(28, 97%, 52%) */
    --chart-ticket-disponibles: #B3E84A; /* hsl(80, 77%, 60%) */
    --chart-ticket-vendidos:   #2FDA4B;  /* hsl(130, 70%, 52%) */
    --chart-ticket-activados:  #0AD6FF;  /* hsl(190, 100%, 52%) */
    --chart-ticket-finished-overlay-gray: 180;  /* light gray for dark bg overlay */

    /* ── Gradient overrides ── */
    --gradient-premium: linear-gradient(144deg, #7c3aed, #4338ca 50%);
    --gradient-btn-recarga: linear-gradient(144deg, #9333ea, #4338ca 50%, #06b6d4);
    --gradient-btn-envio: linear-gradient(120deg, #22c55e, #166534);
    --gradient-btn-tickets: linear-gradient(120deg, #ef4444, #eab308);
    --gradient-btn-recibir: linear-gradient(120deg, #d97706, #c2410c);
    --shadow-color-accent: 147, 51, 234;  /* purple-600 RGB — softer on dark */

    /* T438: --co-accent-* dark overrides — valores ajustados para contraste sobre fondos dark.
       NO aliasar a --color-error/warn/success: paleta APK diverge intencionalmente (ver apk.html:130-133).
       Luminosidad reducida ~70% vs valores light; ratio AA verificado visualmente contra --color-bg-surface dark. */
    --co-accent-secondary: #4fc3f7;  /* light: #b3e5fc → más saturado para contraste dark */
    --co-accent-success:   #4caf69;  /* light: #63ba6a → tono similar, AA sobre dark surface */
    --co-accent-warning:   #ffa726;  /* light: #ffc409 → naranja-ámbar, mejor contraste dark */
    --co-accent-danger:    #e53535;  /* light: #bd2727 → rojo más intenso sobre dark bg */
    --co-accent-dark:      #e8e8ea;  /* light: #222428 → invertido para ser visible en dark */
}

/* ═══════════════════════════════════════════════════
   Dark Theme — Component Overrides
   Only for components that cannot use semantic tokens
   (e.g. tooltips with intentionally dark bg in light mode).
   ═══════════════════════════════════════════════════ */

/* Dark override moved after base definition — .form-control, .form-select */

/* ── Event overdue ── */
:where(html[data-theme="dark"]) .event-overdue {
    color: var(--color-text-muted);
}

/* ── Theme toggle icon visibility ── */
[data-theme="light"] .theme-icon-light,
:where([data-theme="dark"]) .theme-icon-dark { display: none; }
[data-theme="light"] .theme-icon-dark,
/* stylelint-disable no-descending-specificity -- cross-component false positive */
:where([data-theme="dark"]) .theme-icon-light { display: block; }
/* stylelint-enable no-descending-specificity */
/* Fallback when data-theme not set yet (prevents FOUC of both icons) */
html:not([data-theme]) .theme-icon-light { display: none; }
html:not([data-theme]) .theme-icon-dark { display: block; }

/* ═══════════════════════════════════════════════════
   Dark Theme — Special Components (Fase 4)
   ═══════════════════════════════════════════════════ */

/* Dark override moved after base definition — .login-image */

/* ── Swiper (CargaOnline banners) ── */
/* Full-bleed banner: spans full width of parent without scrollbar gap */
.co-banner-bleed {
    width: 100%;
    margin: 0;
    padding: 0;
}

/* Swiper banner size variants + theme vars */
.swiper-banner {
    --swiper-theme-color: #fff;
    --swiper-pagination-bullet-inactive-color: var(--color-white-50);
    --swiper-pagination-bullet-inactive-opacity: 1;
    --swiper-pagination-bullet-size: 8px;
}
.swiper-banner .swiper-pagination {
    bottom: 12px;
    z-index: calc(var(--z-base) + 3);
}
.swiper-banner--sm { height: 140px; }
.swiper-banner--md { height: 220px; }
.swiper-banner--lg { height: 320px; }

/* Banner images: ensure crisp rendering */
.swiper-banner .swiper-slide img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

:where([data-theme="dark"]) .swiper {
    --swiper-theme-color: var(--color-text-secondary);
    --swiper-pagination-bullet-inactive-color: var(--color-text-muted);
}

/* ── Autofill: neutralize browser-imposed yellow/blue bg ── */
:where([data-theme="dark"]) input:-webkit-autofill,
:where([data-theme="dark"]) input:autofill,
:where([data-theme="dark"]) select:-webkit-autofill,
:where([data-theme="dark"]) textarea:-webkit-autofill {
    -webkit-box-shadow: 0 0 0 1000px var(--color-bg-surface) inset;
    -webkit-text-fill-color: var(--color-text-primary);
    transition: background-color 5000s ease-in-out 0s;
}

/* ── SVG icons using currentColor: adapt automatically ── */
/* SVGs with hardcoded fill/stroke (Google logo, brand marks) are untouched */
:where([data-theme="dark"]) .logo-mono {
    filter: brightness(0) invert(1);
}

/* Dark override moved after base definition — .modal-content */

/* ── Footer — uses slate palette (intentionally dark in both themes) ── */

/* ═══════════════════════════════════════════════════
   Dark Theme — Header & Navigation
   ═══════════════════════════════════════════════════ */

/* ── Header action buttons (theme toggle, etc.) ── */
.header-action-btn {
    display: grid;
    place-items: center;
    width: var(--touch-target-min);
    height: var(--touch-target-min);
    border-radius: var(--radius-full);
    border: none;
    background: transparent;
    color: var(--color-text-secondary);
    cursor: pointer;
    transition: color var(--transition-ui), background-color var(--transition-ui);
}
.header-action-btn:hover,
.header-action-btn:focus-visible {
    color: var(--brand-primary-dark);
    background: var(--color-bg-elevated);
}

/* ── Header responsive: hide elements on mobile ── */
.header-logo { height: 1.75rem; /* 28px mobile */ }
.header-action-btn--desktop-only { display: none; }
@media (min-width: 640px) {
    .header-logo { height: 2.5rem; /* 40px */ }
}
@media (min-width: 1024px) {
    .header-action-btn--desktop-only { display: grid; }
}

/* ── Sidebar mobile burger ── */
.sidebar-burger {
    display: grid;
    place-items: center;
    width: var(--touch-target-min);
    height: var(--touch-target-min);
    border: none;
    background: transparent;
    color: var(--color-text-primary);
    cursor: pointer;
    border-radius: var(--radius-md);
    transition: background-color var(--transition-ui);
}
.sidebar-burger:hover { background: var(--color-bg-elevated); }

/* Dark overrides moved after base definitions — header, .inverted-color */

/* Dark overrides moved after base definitions — KPI, chart tabs */

/* Dark override moved after base definition — .badge */

/* ── General text overrides for Tailwind direct colors in HTML ──
   html[data-theme] raises specificity (0,1,1,0) above Tailwind (0,1,0,0)
   so !important is not needed. */
:where(html[data-theme="dark"]) .text-gray-700,
:where(html[data-theme="dark"]) .text-gray-800,
:where(html[data-theme="dark"]) .text-gray-900 {
    color: var(--color-text-primary);
}
:where(html[data-theme="dark"]) .text-gray-500,
:where(html[data-theme="dark"]) .text-gray-600 {
    color: var(--color-text-secondary);
}
:where(html[data-theme="dark"]) .text-gray-400 {
    color: var(--color-text-muted);
}

/* ── Background overrides for Tailwind direct colors in HTML ── */
:where(html[data-theme="dark"]) .bg-white {
    background-color: var(--color-bg-surface);
}
:where(html[data-theme="dark"]) .bg-gray-50 {
    background-color: var(--color-bg-page);
}
:where(html[data-theme="dark"]) .bg-gray-100 {
    background-color: var(--color-bg-elevated);
}

/* ── Border overrides for Tailwind direct colors in HTML ── */
:where(html[data-theme="dark"]) .border-gray-200,
:where(html[data-theme="dark"]) .border-gray-300 {
    border-color: var(--color-border-default);
}

/* ── Shadow overrides: Tailwind shadow-md/lg on dark surfaces ── */
:where(html[data-theme="dark"]) .shadow-md {
    box-shadow: var(--shadow-md);
}
:where(html[data-theme="dark"]) .shadow-lg {
    box-shadow: var(--shadow-lg);
}

/* ── Dropdown/select menus ── */
/* stylelint-disable no-descending-specificity -- cross-component false positive */
:where([data-theme="dark"]) select {
/* stylelint-enable no-descending-specificity */
    background-color: var(--color-bg-surface);
    color: var(--color-text-primary);
    border-color: var(--color-border-default);
}

/* ── Table headers & borders ── */
:where([data-theme="dark"]) table th {
    color: var(--color-text-primary);
    border-color: var(--color-border-default);
}
:where([data-theme="dark"]) table td {
    color: var(--color-text-secondary);
    border-color: var(--color-border-default);
}
:where([data-theme="dark"]) table thead {
    background: var(--color-bg-elevated);
}

/* ── Backgrounds: gray-200/300, blue-50 ── */
:where(html[data-theme="dark"]) .bg-gray-200 {
    background-color: var(--color-bg-elevated);
}
:where(html[data-theme="dark"]) .bg-gray-300 {
    background-color: var(--slate-600);
}
:where(html[data-theme="dark"]) .bg-blue-50 {
    background-color: var(--color-brand-tint-10);
}

/* ── Links: Tailwind text-blue-* ── */
html[data-theme="dark"] a.text-blue-600,
html[data-theme="dark"] a.text-blue-700,
:where(html[data-theme="dark"]) .text-blue-500,
:where(html[data-theme="dark"]) .text-blue-600,
:where(html[data-theme="dark"]) .text-blue-700 {
    color: var(--brand-primary);
}

/* ── Text: gray-300 ── */
:where(html[data-theme="dark"]) .text-gray-300 {
    color: var(--color-text-muted);
}

/* ── Semantic color overrides for Tailwind direct classes (tarea 039 Fase 0.4) ── */

/* Text colors — error */
:where(html[data-theme="dark"]) .text-red-400,
:where(html[data-theme="dark"]) .text-red-500,
:where(html[data-theme="dark"]) .text-red-600,
:where(html[data-theme="dark"]) .text-red-700,
:where(html[data-theme="dark"]) .text-red-800 {
    color: var(--color-error);
}

/* Text colors — success */
:where(html[data-theme="dark"]) .text-green-500,
:where(html[data-theme="dark"]) .text-green-600,
:where(html[data-theme="dark"]) .text-green-700,
:where(html[data-theme="dark"]) .text-green-800 {
    color: var(--color-success);
}

/* Text colors — warn */
:where(html[data-theme="dark"]) .text-amber-700,
:where(html[data-theme="dark"]) .text-orange-500,
:where(html[data-theme="dark"]) .text-orange-600,
:where(html[data-theme="dark"]) .text-yellow-500,
:where(html[data-theme="dark"]) .text-yellow-600,
:where(html[data-theme="dark"]) .text-yellow-700,
:where(html[data-theme="dark"]) .text-yellow-800 {
    color: var(--color-warn);
}

/* Text colors — info */
:where(html[data-theme="dark"]) .text-blue-800 {
    color: var(--brand-primary);
}

:where(html[data-theme="dark"]) .text-purple-600 {
    color: var(--color-purple);
}

/* Background colors — light tints that blind in dark */
:where(html[data-theme="dark"]) .bg-red-50    { background-color: rgba(248, 113, 113, 0.12); }
:where(html[data-theme="dark"]) .bg-green-50  { background-color: rgba(74, 222, 128, 0.12); }
:where(html[data-theme="dark"]) .bg-orange-50 { background-color: rgba(251, 191, 36, 0.12); }
:where(html[data-theme="dark"]) .bg-amber-50,
:where(html[data-theme="dark"]) .bg-amber-50\/40 { background-color: rgba(251, 191, 36, 0.12); }
:where(html[data-theme="dark"]) .bg-yellow-50 { background-color: rgba(251, 191, 36, 0.10); }
:where(html[data-theme="dark"]) .bg-yellow-100 { background-color: rgba(251, 191, 36, 0.15); }

/* Borders — invisible light borders in dark */
:where(html[data-theme="dark"]) .border-red-200   { border-color: rgba(248, 113, 113, 0.30); }
:where(html[data-theme="dark"]) .border-red-300   { border-color: rgba(248, 113, 113, 0.35); }
:where(html[data-theme="dark"]) .border-red-400   { border-color: rgba(248, 113, 113, 0.40); }
:where(html[data-theme="dark"]) .border-green-200 { border-color: rgba(74, 222, 128, 0.25); }
:where(html[data-theme="dark"]) .border-green-300 { border-color: rgba(74, 222, 128, 0.30); }
:where(html[data-theme="dark"]) .border-blue-200  { border-color: var(--color-brand-tint-25); }
:where(html[data-theme="dark"]) .border-blue-300  { border-color: var(--color-brand-tint-30); }
:where(html[data-theme="dark"]) .border-yellow-200 { border-color: rgba(251, 191, 36, 0.25); }
:where(html[data-theme="dark"]) .border-amber-200 { border-color: rgba(251, 191, 36, 0.25); }
:where(html[data-theme="dark"]) .border-amber-300 { border-color: rgba(251, 191, 36, 0.30); }
:where(html[data-theme="dark"]) .border-orange-200 { border-color: rgba(251, 191, 36, 0.25); }
:where(html[data-theme="dark"]) .border-orange-400 { border-color: rgba(251, 191, 36, 0.40); }
:where(html[data-theme="dark"]) .border-orange-500 { border-color: rgba(251, 191, 36, 0.50); }

/* ═══════════════════════════════════════════════════
   Dark Theme — Transitions, Print & A11y (Fase 5)
   ═══════════════════════════════════════════════════ */

/* ── Smooth theme transition — MOVED to after base component definitions
   (see "Theme Transition Override" section below .form-control/.form-select) ── */

/* ── Print: force light theme ── */
@media print {
    :root {
        --color-bg-page: #ffffff;
        --color-bg-surface: #ffffff;
        --color-bg-elevated: #ffffff;
        --color-text-primary: #000000;
        --color-text-secondary: #333333;
        --color-text-muted: #666666;
        --color-border-default: #cccccc;
        --color-border-strong: #999999;
    }
}

/* ── Reduced motion: disable ALL animations and transitions (WCAG 2.3.3) ── */
@media (prefers-reduced-motion: reduce) {
    :root {
        --transition-fast: 0ms;
        --transition-ui: 0ms;
        --transition-base: 0ms;
        --transition-slow: 0ms;
        --dur-fast: 0ms;
        --dur-base: 0ms;
        --dur-slow: 0ms;
    }
    /* stylelint-disable declaration-no-important -- a11y: must override all animations */
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
    /* stylelint-enable declaration-no-important */
}

/* ═══════════════════════════════════════════════════
   Semantic Utility Classes
   Mapped to :root aliases for theme support (tarea 034)
   ═══════════════════════════════════════════════════ */

/* — Surface & Page — */
.bg-page { background-color: var(--color-bg-page); }
.hover\:bg-page:hover { background-color: var(--color-bg-page); }
.bg-surface { background-color: var(--color-bg-surface); }
.bg-elevated { background-color: var(--color-bg-elevated); }
.hover\:bg-elevated:hover { background-color: var(--color-bg-elevated); }
/* stylelint-disable-next-line declaration-no-important -- Tailwind ! convention */
.hover\:\!bg-elevated:hover { background-color: var(--color-bg-elevated) !important; }

/* — Text — */
/* Override Tailwind .text-primary — main.css must load after tailwind.output.css */
.text-primary { color: var(--color-text-primary); }
.text-secondary { color: var(--color-text-secondary); }
.text-muted { color: var(--color-text-muted); }
.text-inverse { color: var(--color-text-inverse); }
.hover\:text-primary:hover { color: var(--color-text-primary); }
/* stylelint-disable-next-line declaration-no-important -- Tailwind ! convention */
.hover\:\!text-inherit:hover { color: inherit !important; }

/* — Border — */
.border-default { border-color: var(--color-border-default); }
.border-strong { border-color: var(--color-border-strong); }

/* — Utility — */
.scroll-list {
  max-height: 200px;
  overflow-y: auto;
  display: grid;
  grid-template-columns: 1fr 1fr;
}

/* — Scroll-list checkbox/radio items — */
.scroll-list label {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  color: var(--color-text-secondary);
  cursor: pointer;
  user-select: none;
}
.scroll-list :where(label:hover) {
  color: var(--color-text-primary);
}

/* ═══ Color Picker Component ═══ */
.color-picker-popup {
    position: fixed;
    z-index: var(--z-popover);
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border-default);
    border-radius: var(--radius-md);
    padding: var(--space-2);
    box-shadow: var(--shadow-md);
}
.color-picker-grid {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: var(--space-1);
}
.color-picker-action {
    color: var(--color-text-muted);
    background: none;
    border: none;
    cursor: pointer;
    padding: var(--space-1);
    border-radius: var(--radius-xs);
    transition: color var(--transition-fast), background-color var(--transition-fast);
}
.color-picker-action:hover {
    color: var(--color-text-primary);
    background: var(--color-bg-elevated);
}
.color-picker-action--danger {
    color: var(--color-error-light);
}
.color-picker-action--danger:hover {
    color: var(--color-error);
    background: var(--color-error-bg);
}

/* ═══ Editable Items Table — utility classes for inline JS-generated elements ═══ */
.icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 36px;
    min-height: 36px;
    border-radius: var(--radius-sm);
    border: 2px solid transparent;
    background: transparent;
    cursor: pointer;
    transition: background-color var(--transition-fast);
}
@media (min-width: 640px) {
    .icon-btn { min-width: var(--touch-target-min); min-height: var(--touch-target-min); }
}
.icon-btn:hover {
    background: var(--color-bg-elevated);
}
.icon-btn--selected {
    border-color: var(--brand-primary-dark);
    background: var(--brand-primary-light);
}

.color-picker-btn {
    width: 28px;
    height: 28px;
    border-radius: var(--radius-md);
    border: 2px solid var(--color-border-strong);
    cursor: pointer;
    transition: transform var(--transition-fast), box-shadow var(--transition-fast);
}
@media (min-width: 640px) {
    .color-picker-btn { width: 36px; height: 36px; }
}
.color-picker-btn:hover {
    transform: scale(1.1);
}
.type-toggle-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: var(--radius-md);
    border: 1px solid var(--color-border-default);
    background: var(--color-bg-surface);
    color: var(--color-text-muted);
    cursor: pointer;
    transition: all var(--transition-fast);
}
.type-toggle-btn:hover {
    border-color: var(--color-border-strong);
    color: var(--color-text-primary);
}
.type-toggle-btn--active {
    background: var(--brand-primary);
    border-color: var(--brand-primary);
    color: var(--color-text-inverse);
}
.type-toggle-btn--active:hover {
    background: var(--brand-primary-dark);
    border-color: var(--brand-primary-dark);
    color: var(--color-text-inverse);
}
.input-suffix {
    position: absolute;
    right: var(--space-2);
    top: 50%;
    transform: translateY(-50%);
    pointer-events: none;
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    font-weight: var(--font-medium);
}

/* ═══ APK Builder Component ═══ */
.apk-input {
    width: 100%;
    border: 1px solid var(--color-border-default);
    border-radius: var(--radius-md);
    padding: var(--space-2) var(--space-3);
    font-size: var(--text-base);
    font-weight: var(--font-semibold);
    color: var(--color-text-muted);
    background: var(--color-bg-surface);
}
.apk-select {
    width: 100%;
    border: 1px solid var(--color-border-default);
    border-radius: var(--radius-sm);
    padding: var(--space-2);
    font-size: var(--text-sm);
    font-weight: var(--font-semibold);
    color: var(--color-text-primary);
    background: var(--color-bg-surface);
}
.apk-label {
    font-size: var(--text-xs);
    font-weight: var(--font-bold);
    text-transform: uppercase;
    letter-spacing: var(--tracking-wider);
    color: var(--color-text-primary);
    margin-bottom: var(--space-1);
}
.apk-empty-msg {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    text-align: center;
}
.apk-currency-suffix {
    position: absolute;
    right: var(--space-3);
    color: var(--color-text-secondary);
    font-weight: var(--font-semibold);
}

/* — CargaOnline config layout (apk.html) —
   The article lives in an xl:col-span-3 grid row that is ~1180px wide.
   Left column hosts controls + preset table, right column hosts the
   live preview. Without a cap the shared editable_items_table.html
   gives the Etiqueta column ~530px in wide viewports, which looks
   unbalanced against the 88px Importe column and detaches the live
   preview from the rest of the card. */
.co-config-layout {
    display: flex;
    flex-direction: column;
}
.co-config-preview {
    width: 100%;
}
@media (min-width: 1024px) {
    .co-config-layout {
        flex-direction: row;
        align-items: flex-start;
        gap: var(--space-8);
    }
    /* Left column is capped so the preset table stays at a readable
       width and the preview docks naturally next to it. */
    .co-config-layout > *:first-child {
        flex: 0 1 620px;
        min-width: 0;
    }
    .co-config-preview {
        width: 340px;
        flex-shrink: 0;
        position: sticky;
        top: calc(var(--header-height) + var(--space-4));
    }
    .co-config-preview #co-preview-wrap {
        padding: var(--space-3);
        min-height: 120px;
    }
}

/* — CargaOnline preset section desktop polish — */
@media (min-width: 640px) {
    /* The preset table fits comfortably in the capped left column;
       the shared .overflow-x-auto wrapper still forces a 6px
       horizontal scrollbar for rounding. Drop it in ≥sm so desktop
       renders clean. */
    #co-custom-section > .overflow-x-auto {
        overflow: visible;
    }
    /* Presets header row (title + "+ Añadir") shares the table's
       effective width so the button can't float into the aisle. */
    #co-custom-section > .flex.items-start {
        max-width: 620px;
    }
    /* The preset table width is bounded by the left column in lg+, but
       on sm/md it would still greedy-grow Etiqueta. Cap it so rows
       stay legible at tablet sizes too. */
    #co-custom-section table {
        max-width: 620px;
    }
    /* Etiqueta column explicit upper bound — short preset labels
       ("50€") don't need 500px of text space. */
    #co-custom-section th:nth-last-child(3),
    #co-custom-section td:nth-last-child(3) {
        max-width: 240px;
    }
}

/* — CargaOnline preset table → stacked cards on mobile (apk.html) —
   Tailwind table-fixed with 5 width-constrained columns collapses the
   ETIQUETA column to 0px on narrow viewports and stacks header labels on
   top of the inputs. In <sm we reformat each <tr> as a card with the
   inputs arranged in two rows (action row + full-width label) so every
   control stays reachable without horizontal scrolling. Selectors use
   :has() to be column-order-agnostic (TIPO may be absent when
   TICKETS_ENABLED is off). */
@media (max-width: 639.98px) {
    #co-custom-section .overflow-x-auto {
        overflow: visible;
        margin-left: calc(-1 * var(--space-2));
        margin-right: calc(-1 * var(--space-2));
    }
    #co-custom-section table {
        display: block;
        width: 100%;
        table-layout: auto;
    }
    #co-custom-section tbody {
        display: block;
        width: 100%;
    }
    #co-custom-section thead {
        display: none;
    }
    /* Grid avoids the flex-wrap DOM-order problem (label sits between
       value and color in the JS-rendered <tr>, which would force a wrap
       before color/actions). Grid areas decouple visual order from DOM
       order so we can keep the shared component untouched. */
    #co-custom-section tbody tr {
        display: grid;
        grid-template-columns: auto minmax(0, 1fr) auto auto;
        grid-template-areas:
            "type    importe color actions"
            "etiqueta etiqueta etiqueta etiqueta";
        align-items: center;
        gap: var(--space-2);
        padding: var(--space-3);
        margin-bottom: var(--space-2);
        background: var(--color-bg-surface);
        border: 1px solid var(--color-border-default);
        border-radius: var(--radius-md);
    }
    #co-custom-section tbody td {
        display: block;
        padding: 0;
        min-width: 0;
    }
    #co-custom-section tbody td:has([data-action="set-type"]) { grid-area: type; }
    #co-custom-section tbody td:has([data-field="value"]),
    #co-custom-section tbody td:has([data-field="event_id"]) {
        grid-area: importe;
        min-width: 0;
    }
    #co-custom-section tbody td:has([data-action="color"]) { grid-area: color; }
    #co-custom-section tbody td:has([data-action="del"]) {
        grid-area: actions;
        display: flex;
        gap: 1px;
    }
    #co-custom-section tbody td:has([data-field="label"]) { grid-area: etiqueta; }
    /* Force inputs/selects to shrink with their grid cell instead of
       pushing out the 1fr column to their min-content. */
    #co-custom-section tbody td > div,
    #co-custom-section tbody td input,
    #co-custom-section tbody td select {
        min-width: 0;
        max-width: 100%;
        width: 100%;
        box-sizing: border-box;
    }
    /* Input padding in the preset table: inputs use px-3 (12px) + a
       28px padding-right to accommodate the € suffix. In the narrow
       importe cell (≈90px) that leaves too little space for the value,
       so we tighten padding on mobile only. */
    #co-custom-section tbody td:has([data-field="value"]) input {
        padding-left: var(--space-2);
        padding-right: 18px;
    }
    #co-custom-section tbody td:has([data-field="value"]) .input-suffix {
        right: var(--space-1);
    }
    /* Tighter type toggles + action buttons so everything fits the
       single top row in a mobile card. !important overrides inline
       styles declared on the buttons by the shared component
       (editable_items_table.html) — the shared component can't know
       about the mobile compression we do here. */
    #co-custom-section .type-toggle-btn {
        width: 26px;
        height: 26px;
        min-width: 0;
        min-height: 0;
        padding: 2px;
    }
    #co-custom-section .color-picker-action.color-picker-action {
        padding: 3px 2px;
    }
    #co-custom-section .color-picker-btn {
        width: 28px;
        height: 28px;
    }
    #co-custom-section tbody tr.border-b {
        border-bottom-width: 1px;
    }
}

/* — CargaOnline preset preview cards (JS-generated in apk.html) — */
.co-preview-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(72px, auto));
    gap: var(--space-2);
}
.co-preview-card {
    position: relative;
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-md);
    border: 2px solid var(--color-border-default);
    padding: var(--space-3);
    min-height: 80px;
    background: var(--color-bg-surface);
    cursor: pointer;
    text-align: center;
}
.co-preview-value {
    font-size: var(--text-base);
    font-weight: var(--font-bold);
    color: var(--color-text-primary);
}
.co-preview-label {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    margin-top: var(--space-1);
    max-width: 80px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* — Preset card quantity badge + clear button (CargaOnline) — */
.card-badge {
    position: absolute;
    bottom: calc(-1 * var(--space-2));
    right: calc(-1 * var(--space-2));
    background: var(--brand-primary-dark);
    color: var(--color-text-inverse);
    border-radius: var(--radius-full);
    font-size: var(--text-xs);
    font-weight: var(--font-bold);
    min-width: var(--icon-md);
    height: var(--icon-md);
    line-height: var(--icon-md);
    text-align: center;
    padding: 0 var(--space-1);
    pointer-events: none;
    z-index: var(--z-dropdown);
}
/* Decrement (-1) button on preset & ticket cards. Top-right red affordance.
   Replaces the legacy .card-clear (×); bulk reset still available via the
   global "Vaciar" cart button. */
.card-minus {
    position: absolute;
    top: calc(-1 * var(--space-2-5));
    right: calc(-1 * var(--space-2-5));
    width: var(--icon-lg);
    height: var(--icon-lg);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: var(--radius-full);
    background: var(--color-error);
    color: var(--color-text-inverse);
    font-weight: var(--font-bold);
    font-size: var(--text-sm);
    line-height: var(--icon-lg);
    text-align: center;
    cursor: pointer;
    padding: 0;
    box-shadow: var(--shadow-xs);
    z-index: var(--z-dropdown);
    transition: background var(--transition-fast);
}
.card-minus:hover,
.card-minus:focus-visible {
    background: var(--color-error-hover);
}
/* WCAG 2.5.5 — touch area 44x44 without changing visual size */
.card-minus::before {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: var(--touch-target-min);
    height: var(--touch-target-min);
    border-radius: var(--radius-full);
}

/* — Global focus ring (WCAG 2.4.11 — replaces per-component repetitions) — */
:focus-visible {
    outline: 2px solid var(--brand-primary);
    outline-offset: 2px;
}
/* Opt-in enhanced focus ring — adds glow halo on top of the global :focus-visible outline */
.focus-ring:focus-visible {
    box-shadow: 0 0 0 4px var(--brand-focus-ring);
}
/* — Status: Success (replaces broken emerald-*) — */
.bg-status-success { background-color: var(--color-success); }
.bg-status-success-light { background-color: var(--color-success-bg); }
.text-status-success { color: var(--color-success); }

/* -- Status: Warning (replaces broken yellow/amber) -- */
.bg-status-warn { background-color: var(--color-warn); }
.bg-status-warn-light { background-color: var(--color-warn-bg); }
.text-status-warn { color: var(--color-warn); }
.text-status-warn-dark { color: var(--color-warn-hover); }
.border-status-warn { border-color: var(--color-warn); }
.border-status-warn-light { border-color: var(--color-warn-bg); }

/* — Status: Error — */
.bg-status-error { background-color: var(--color-error); }
.bg-status-error-light { background-color: var(--color-error-bg); }
.text-status-error { color: var(--color-error); }
/* — Brand (replaces broken sky-*) — */
.bg-brand { background-color: var(--brand-primary); }
.text-brand { color: var(--brand-primary); }
.border-brand { border-color: var(--brand-primary); }
.hover\:bg-brand-dark:hover { background-color: var(--brand-primary-dark); }

/* — Info (replaces broken indigo-*) — */
.bg-info { background-color: var(--color-info); }
.bg-info-light { background-color: var(--color-info-bg); }
.text-info { color: var(--color-info); }
.hover\:text-info:hover { color: var(--color-info-hover); }
.border-info { border-color: var(--color-info); }
.hover\:border-info:hover { border-color: var(--color-info); }

.text-success { color: var(--color-success); }
.text-error   { color: var(--color-error); }
.text-warn    { color: var(--color-warn); }

/* — Balance display gradients (tickets.html) — */
.balance-positive { background: var(--color-success-bg); border-color: var(--color-success); border-left-width: 3px; }
.balance-negative { background: var(--color-error-bg); border-color: var(--color-error); border-left-width: 3px; }
.balance-neutral  { background: var(--color-info-bg); border-color: var(--color-info); border-left-width: 3px; }

/* ═══════════════════════════════════════════════════
   Alert System
   ═══════════════════════════════════════════════════ */
.alert {
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
    border: 1px solid;
    font-size: var(--text-sm);
    line-height: var(--leading-normal);
}
.alert-success {
    background-color: var(--color-success-bg);
    border-color: var(--color-success);
    color: var(--color-success-hover);
}
.alert-error {
    background-color: var(--color-error-bg);
    border-color: var(--color-error);
    color: var(--color-error-hover);
}
.alert-info {
    background-color: var(--color-info-bg);
    border-color: var(--color-info);
    color: var(--color-info-hover);
}
:where([data-theme="dark"]) .alert-success { color: var(--color-success); }
:where([data-theme="dark"]) .alert-error { color: var(--color-error); }
:where([data-theme="dark"]) .alert-info { color: var(--color-info); }

/* ═══════════════════════════════════════════════════
   Badge System
   ═══════════════════════════════════════════════════ */
.badge {
    display: inline-flex;
    align-items: center;
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-full);
    font-size: var(--text-xs);
    font-weight: var(--font-medium);
    line-height: 1;
    white-space: nowrap;
}
.badge-success {
    background-color: var(--color-success-bg);
    color: var(--color-success-hover);
}
.badge-error {
    background-color: var(--color-error-bg);
    color: var(--color-error-hover);
}
.badge-info {
    background-color: var(--color-info-bg);
    color: var(--color-info-hover);
}
.badge-warning {
    background-color: var(--color-warn-bg);
    color: var(--color-warn-hover);
}
.badge-neutral {
    background-color: var(--color-bg-elevated);
    color: var(--color-text-secondary);
}
:where([data-theme="dark"]) .badge-success { color: var(--color-success); }
:where([data-theme="dark"]) .badge-error { color: var(--color-error); }
:where([data-theme="dark"]) .badge-info { color: var(--color-info); }
:where([data-theme="dark"]) .badge-warning { color: var(--color-warn); }
/* ── Badges & pills: background-color from Tailwind classes ── */
:where([data-theme="dark"]) .badge,
:where(html[data-theme="dark"]) .bg-blue-100,
:where(html[data-theme="dark"]) .bg-green-100,
:where(html[data-theme="dark"]) .bg-amber-100,
:where(html[data-theme="dark"]) .bg-orange-100,
:where(html[data-theme="dark"]) .bg-red-100 {
    background-color: var(--color-bg-elevated);
}

/* ═══════════════════════════════════════════════════
   Table Utilities
   ═══════════════════════════════════════════════════ */
.table-header {
    background-color: var(--color-bg-page);
    color: var(--color-text-muted);
    font-family: var(--font-heading);
    font-size: var(--text-xs);
    font-weight: var(--font-semibold);
    text-transform: uppercase;
    letter-spacing: var(--tracking-wider);
    padding: var(--space-2) var(--space-2);
    line-height: var(--leading-snug);
    vertical-align: middle;
}
/* Fixed-width column (e.g. status columns in refund tables) */
.col-fixed-120 { width: 120px; min-width: 120px; max-width: 120px; }

/* ═══════════════════════════════════════════════════
   Button Outline Variants
   ═══════════════════════════════════════════════════ */
.btn-danger-outline {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
    min-height: var(--touch-target-min);
    font-size: var(--text-sm);
    font-weight: var(--font-semibold);
    font-family: var(--font-heading);
    line-height: var(--leading-snug);
    letter-spacing: var(--tracking-wide);
    cursor: pointer;
    border-radius: var(--radius-sm);
    text-decoration: none;
    color: var(--color-error);
    background: var(--color-bg-surface);
    border: 1px solid var(--color-error);
    transition: background-color var(--transition-fast), color var(--transition-fast);
}
.btn-danger-outline:hover {
    background: var(--color-error-bg);
    color: var(--color-error-hover);
}
.btn-danger-outline:focus-visible {
    background: var(--color-error-bg);
    color: var(--color-error-hover);
    outline: 2px solid var(--color-error-light);
    outline-offset: 2px;
}

/* ═══════════════════════════════════════════════════
   Card System
   ═══════════════════════════════════════════════════ */
.card {
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border-default);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
}
/* ═══════════════════════════════════════════════════
   Input System — .input-base removed (0 usages in templates/JS)
   Inputs use .form-input/.form-control/.form-select instead.
   ═══════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════
   Button System
   ═══════════════════════════════════════════════════ */

/* Shared base for all button variants */
:is(.btn-primary, .btn-danger, .btn-success, .btn-neutral, .btn-ghost) {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-4);
    min-height: var(--touch-target-min); /* WCAG 2.1 SC 2.5.8 Target Size */
    font-size: var(--text-sm);
    font-weight: var(--font-semibold);
    font-family: var(--font-heading);
    line-height: var(--leading-snug);
    letter-spacing: var(--tracking-wide);
    cursor: pointer;
    border-radius: var(--radius-md);
    text-decoration: none;
    transition: background-color var(--transition-fast), box-shadow var(--transition-fast);
}

/* Filled variants share inverse text + no border */
:is(.btn-primary, .btn-danger, .btn-success) {
    border: 0;
    color: var(--color-text-inverse);
}
.btn-primary {
    background-color: var(--brand-primary);
}
.btn-primary:hover,
.btn-primary:focus-visible {
    background-color: var(--brand-primary-dark);
}
.btn-primary[disabled],
.btn-primary[aria-disabled="true"] {
    background-color: var(--color-primary-disabled);
    cursor: not-allowed;
    box-shadow: none;
}
.btn-primary[disabled]:hover,
.btn-primary[aria-disabled="true"]:hover {
    background-color: var(--color-primary-disabled);
}

.btn-neutral {
    color: var(--color-text-primary);
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border-default);
    transition: background-color var(--transition-fast), border-color var(--transition-fast);
}
.btn-neutral:hover,
.btn-neutral:focus-visible {
    background: var(--color-bg-elevated);
    border-color: var(--color-border-strong);
}

.btn-danger {
    background-color: var(--color-error);
}
.btn-danger:hover,
.btn-danger:focus-visible {
    background-color: var(--color-error-hover);
}

.btn-icon-danger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: var(--radius-full);
    background-color: var(--color-error);
    color: var(--color-text-inverse);
    cursor: pointer;
    transition: background-color var(--transition-fast);
}
.btn-icon-danger:hover,
.btn-icon-danger:focus-visible {
    background-color: var(--color-error-hover);
}

.btn-success {
    background-color: var(--color-success);
}
.btn-success:hover,
.btn-success:focus-visible {
    background-color: var(--color-success-hover);
}

/* Ghost button — for theme toggle (tarea 034) and tertiary actions */
.btn-ghost {
    border: none;
    background: transparent;
    color: var(--color-text-secondary);
    padding: var(--space-2) var(--space-3);
    font-size: var(--text-sm);
    font-weight: var(--font-medium);
    transition: color var(--transition-fast), background-color var(--transition-fast);
}
.btn-ghost:hover,
.btn-ghost:focus-visible {
    color: var(--color-text-primary);
    background: var(--color-bg-elevated);
}

/* Size modifiers */
.btn-sm {
    padding: var(--space-1) var(--space-3);
    min-height: 2rem; /* 32px — compact context */
    font-size: var(--text-sm);
}
.btn-lg {
    padding: var(--space-4) var(--space-6);
    min-height: 3.25rem; /* 52px — prominent CTA */
    font-size: var(--text-base);
}
/* ═══════════════════════════════════════════════════
   Refund Period Filters (moved from period_list.html <style>)
   ═══════════════════════════════════════════════════ */
.filter-card {
    flex: 1;
    min-width: 150px;
    padding: var(--space-4);
    border: 2px solid var(--color-border-default);
    border-radius: var(--radius-md);
    background: var(--color-bg-surface);
    cursor: pointer;
    transition: border-color var(--transition-base), box-shadow var(--transition-base), background-color var(--transition-base), transform var(--transition-fast);
    text-align: left;
}
.filter-card:hover {
    border-color: var(--brand-primary);
    box-shadow: var(--shadow-lg);
    transform: translateY(-2px);
}
.filter-card.active {
    border-color: var(--brand-primary);
    background: var(--color-brand-tint-12);
    box-shadow: 0 2px 8px var(--brand-primary-shadow);
}
.period-table { display: block; }
.period-table.hidden { display: none; }

/* Generic container utility (optional) */
.container {
    width: 100%;
    max-width: var(--container-max);
    margin-inline: auto;
    padding-inline: var(--container-gutter);
}
/* Inside #main, the gutter is already provided by #main itself */
#main:not(.co-main) > .container {
    padding-inline: 0;
}
/* CargaOnline: main has no padding, so glass panel keeps its own gutter */
#main.co-main > .container {
    padding-inline: var(--container-gutter);
}

/* Vertical rhythm for stacked sections (prevents margin stacking) */
.stack > * + * {
    margin-top: clamp(12px, 2.5vw, 28px);
}

/* Neutral semantic helper for panels using stack spacing */
.section-block {
    /* No reset for vertical margins to allow utilities like my-2 */
    margin-left: 0;
    margin-right: 0;
}


@media (min-width: 768px) {
    /* NOTE: .md\:grid-cols-2 was duplicated here and overrode Tailwind's own
       .xl\:grid-cols-3 because main.css loads after tailwind.output.css
       (cargaOnline/templates/header.html: tailwind, then main). Tailwind
       already generates an identical rule in tailwind.output.css, so the
       override is removed to let xl:* breakpoints win at ≥1280px. */

    .md\:items-start {
        align-items: flex-start;
    }

    .md\:gap-6 {
        gap: var(--space-6);
    }
}

/* Primary content container depth and gutters */
#main {
    width: 100%;
    max-width: var(--container-max);
    margin-inline: auto;
    margin-top: clamp(12px, 2vw, 20px);
    padding-inline: var(--container-gutter);
    padding-top: clamp(20px, 3vw, 32px);
    padding-bottom: clamp(12px, 3vw, 24px);
    margin-bottom: var(--space-8);
    background: var(--color-bg-surface);
    border-radius: var(--container-radius);
    box-shadow: var(--container-shadow);
    animation: fadeInSimple var(--dur-base) ease-out;
}

/* CargaOnline: reset admin card styling — glass panel handles the visual container */
#main.co-main {
    margin: 0;
    padding: 0;
    background: transparent;
    border-radius: 0;
    box-shadow: none;
    max-width: none;
    width: 100%;
    overflow: clip; /* clip prevents horizontal overflow without creating a scroll container (unlike hidden), so position:sticky works correctly */
}

/* ── Dashboard responsive helpers ── */
.dashboard-section-title {
    font-size: var(--text-xl);
    font-weight: var(--font-bold);
}
@media (min-width: 640px) {
    .dashboard-section-title {
        font-size: var(--text-2xl);
    }
}

/* ── Dashboard section cards ── */
.dashboard-card {
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border-default);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    padding: var(--space-2);
    min-width: 0;
}
@media (min-width: 640px) {
    .dashboard-card { padding: var(--space-4); }
}

.dashboard-card__title {
    font-size: var(--text-h2-size);
    font-weight: var(--text-h2-weight);
    line-height: var(--text-h2-leading);
    letter-spacing: var(--text-h2-tracking);
    color: var(--color-text-secondary);
    padding-bottom: var(--space-2);
    margin-bottom: var(--space-3);
    border-bottom: 1px solid var(--color-border-default);
}

/* ── KPI Hero card (Card 1: Resumen) ── */
.kpi-hero {
    grid-column: 1 / -1;
    /* Mobile-first: compact padding */
    padding: var(--space-6) var(--space-4);
    background: linear-gradient(
        135deg,
        var(--color-brand-tint-10),
        var(--color-brand-tint-25)
    );
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-brand-lg);
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
    animation: kpi-hero-fade-in var(--transition-slow) ease-out;
}

@media (min-width: 768px) {
    .kpi-hero {
        padding: var(--space-8) var(--space-10);
    }
}

/* Top section: mobile-first 1-col, scales to 3-col on desktop */
.kpi-hero__top {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-6);
    align-items: start;
}

@media (min-width: 768px) {
    .kpi-hero__top {
        grid-template-columns: auto 1fr 1fr;
    }
}
.kpi-hero__breakdown-col {
    min-width: 0;
}

.kpi-hero__primary {
    display: flex;
    align-items: flex-start;
    gap: var(--space-4);
}

.kpi-hero__content {
    flex: 1;
    min-width: 0;
}

.kpi-hero__label {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    font-weight: var(--font-medium);
    letter-spacing: var(--tracking-wider);
    text-transform: uppercase;
    color: var(--color-text-secondary);
    margin-bottom: var(--space-1);
}

.kpi-hero__value {
    font-family: var(--font-heading);
    font-size: clamp(2.5rem, 6vw, 4.5rem);
    font-weight: var(--font-bold);
    line-height: var(--leading-tight);
    letter-spacing: var(--tracking-tighter);
    font-variant-numeric: tabular-nums slashed-zero;
    color: var(--color-text-primary);
    margin: 0;
}

.kpi-hero__currency {
    font-size: 0.5em;
    font-weight: var(--font-semibold);
    color: var(--color-text-secondary);
    vertical-align: super;
    margin-left: var(--space-1);
}

.kpi-hero__detail {
    margin-top: var(--space-2);
}

.kpi-hero__detail--clickable {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    cursor: pointer;
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-md);
    transition: background var(--transition-fast);
}
.kpi-hero__detail--clickable:hover {
    background: var(--color-brand-tint-10);
}
.kpi-hero__detail--clickable:active {
    background: var(--color-brand-tint-25);
}

.kpi-hero__detail-arrow {
    color: var(--color-text-muted);
}

.kpi-hero__detail-label {
    color: var(--color-text-secondary);
}

.kpi-hero__detail-value {
    font-weight: var(--font-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--semantic-revenue);
}
.kpi-hero__trend {
    margin-top: var(--space-1);
}


.kpi-hero__breakdown {
    flex: 1;
    padding: var(--space-4) var(--space-5);
    background: var(--color-bg-surface);
    border-radius: var(--radius-lg);
    border: 1px solid var(--color-border-default);
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

.kpi-hero__breakdown-col--highlight .kpi-hero__breakdown {
    border-color: var(--brand-primary);
    box-shadow: var(--shadow-brand-sm);
    transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.kpi-hero__breakdown-title {
    font-size: var(--text-xs);
    font-weight: var(--font-semibold);
    letter-spacing: var(--tracking-wider);
    text-transform: uppercase;
    color: var(--color-text-muted);
    margin: 0;
}

.kpi-hero__breakdown-table {
    width: auto;
    font-size: var(--text-sm);
}
:where(.kpi-hero__breakdown-table) td:last-child {
    padding-left: var(--space-3);
    white-space: nowrap;
}

/* Clickable breakdown rows (center column → opens detail slot) */
.kpi-hero__breakdown-row--clickable {
    cursor: pointer;
    transition: background-color 0.15s ease;
}
.kpi-hero__breakdown-row--clickable:hover {
    background-color: color-mix(in srgb, var(--color-success) 8%, transparent);
}
.kpi-hero__breakdown-row--active {
    background-color: color-mix(in srgb, var(--color-success) 12%, transparent);
}
.kpi-hero__breakdown-chevron {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    margin-left: var(--space-1);
    transition: transform 0.15s ease;
}
.kpi-hero__breakdown-row--active .kpi-hero__breakdown-chevron {
    transform: rotate(90deg);
}

/* Detail slot transition */
#hero-detail-slot {
    transition: opacity 0.2s ease;
}
#hero-detail-slot:not([hidden]) {
    animation: fadeIn 0.2s ease;
}

/* Empty state for detail slot */
.kpi-hero__breakdown-empty {
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    padding: var(--space-2) 0;
    font-style: italic;
}

.kpi-hero__breakdown-label {
    color: var(--color-text-secondary);
    padding: var(--space-1) 0;
}

.kpi-hero__breakdown-value {
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-weight: var(--font-medium);
    color: var(--color-text-secondary);
    padding: var(--space-1) 0;
}
.kpi-hero__breakdown-value--positive { color: var(--color-success); }
.kpi-hero__breakdown-value--negative { color: var(--semantic-refund); }

.kpi-hero__breakdown-total {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    padding-top: var(--space-3);
    margin-top: auto;
    border-top: 2px solid var(--color-border-strong);
    font-size: var(--text-sm);
    font-weight: var(--font-bold);
    color: var(--color-text-primary);
}

.kpi-hero__breakdown-total-value {
    font-size: var(--text-base);
    font-variant-numeric: tabular-nums;
    color: var(--semantic-revenue);
}

/* Cortesías card — start label & total label */
.kpi-hero__breakdown-label--start {
    font-weight: var(--font-semibold);
    color: var(--color-text-primary);
}
.kpi-hero__breakdown-total-label {
    font-size: var(--text-sm);
    color: var(--color-text-primary);
}

/* Secondary KPIs with staggered slide-up — mobile-first */
.kpi-hero__secondary-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-4);
}
.kpi-hero__secondary-grid--centered {
    grid-template-columns: 1fr;
}

@media (min-width: 481px) {
    .kpi-hero__secondary-grid {
        grid-template-columns: repeat(2, 1fr);
    }
    .kpi-hero__secondary-grid--centered {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (min-width: 768px) {
    .kpi-hero__secondary-grid {
        grid-template-columns: repeat(4, 1fr);
    }
    .kpi-hero__secondary-grid--centered {
        grid-template-columns: repeat(3, 1fr);
    }
}

.kpi-hero__secondary-item {
    animation: kpi-hero-slide-up 0.4s ease-out backwards;
}

.kpi-hero__secondary-item--delay-1 { animation-delay: 0.1s; }
.kpi-hero__secondary-item--delay-2 { animation-delay: 0.2s; }
.kpi-hero__secondary-item--delay-3 { animation-delay: 0.3s; }

@keyframes kpi-hero-fade-in {
    from { opacity: 0; transform: translateY(12px); }
    to   { opacity: 1; transform: translateY(0); }
}

@keyframes kpi-hero-slide-up {
    from { opacity: 0; transform: translateY(16px); }
    to   { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
    .kpi-hero,
    .kpi-hero__secondary-item { animation: none; }
}

/* Out-of-scope responsive rules for hero inner elements (font sizes).
   Kept as max-width because they target typography, not the 3 layout
   rules being inverted in T149 Fase E.1. */
@media (max-width: 768px) {
    .kpi-hero__value {
        font-size: clamp(1.75rem, 8vw, 2.5rem);
    }
    .kpi-hero__secondary-grid .kpi-card__value {
        font-size: var(--text-xl);
    }
}

@media (max-width: 480px) {
    .kpi-hero__secondary-grid .kpi-card__value {
        font-size: var(--text-lg);
    }
}

/* ── KPI row: grid wrap ── */
/* `.kpi-row-wrap` and `.kpi-arrow--left/--right` kept as no-op shells so
 * legacy markup and ARIA regions degrade gracefully. */
.kpi-row-wrap {
    position: relative;
    min-width: 0;
    margin-bottom: var(--space-5);
    padding-bottom: var(--space-1);
    border-bottom: 1px solid var(--color-border-default);
}
.kpi-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: var(--space-3);
    padding: var(--space-1) 0 var(--space-2);
}
:where(.kpi-row) .kpi-card {
    min-width: 0;
    height: auto;
    align-self: stretch;
    box-sizing: border-box;
}
.kpi-row .kpi-card [data-kpi-label] {
    min-height: 2em;
}
/* Legacy scroll arrows are visually suppressed (and JS handler dropped).
   Doubled selector bumps specificity above single-class Tailwind utilities
   (`.inline-flex`, `.block`) so the hidden state wins without !important. */
.kpi-arrow.kpi-arrow { display: none; }

/* Prevent KPI numbers from wrapping onto multiple lines */
.kpi-value {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.kpi-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-2);
  position: relative;
  padding: var(--space-2);
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border-default);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-xs);
  transition: box-shadow var(--transition-fast);
}
:where(html[data-theme="dark"]) .kpi-card {
  border-color: var(--color-border-strong);
  box-shadow: 0 2px 8px rgba(var(--shadow-color), 0.3);
}
@media (min-width: 640px) {
  .kpi-card { padding: var(--space-3); }
}
.kpi-card__body {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 0;
  width: 100%;
}
.kpi-card__label {
  font-size: var(--text-xs);
  font-weight: var(--font-medium);
  color: var(--color-text-secondary);
  line-height: var(--leading-snug);
}
.kpi-card__value {
  font-size: var(--text-lg);
  font-weight: var(--font-semibold);
  color: var(--color-text-primary);
  margin-top: var(--space-1);
  line-height: var(--leading-snug);
}
/* Hero bottom KPI cards: bigger values for visual prominence */
.kpi-hero__secondary-grid .kpi-card__value {
  font-size: var(--text-2xl);
}
/* T191 P191-D: inline detail row — replaces the old click-to-reveal
   toggle. Both the primary value (Bruto) and the detail value (Neto /
   Cobros / Importe …) are visible at the same time; no interaction
   required. Hierarchy: label 2xs muted / value xs semibold primary. */
.kpi-card__detail {
  display: flex;
  align-items: baseline;
  gap: var(--space-1-5);
  margin-top: var(--space-1);
  font-size: var(--text-xs);
  line-height: var(--leading-snug);
  color: var(--color-text-secondary);
  font-variant-numeric: tabular-nums;
}
.kpi-card__detail:empty { display: none; }
.kpi-card__detail-label {
  font-size: var(--text-2xs);
  font-weight: var(--font-medium);
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.kpi-card__detail-value {
  font-weight: var(--font-semibold);
  color: var(--color-text-primary);
}
.kpi-card__variation {
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  margin-top: var(--space-1);
  line-height: var(--leading-snug);
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}
.kpi-card__variation:empty { display: none; }
.kpi-card__trend {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--text-xs);
  font-weight: var(--font-medium);
  margin-top: var(--space-1);
  padding: 2px var(--space-1-5);
  border-radius: var(--radius-full);
  line-height: 1;
  white-space: nowrap;
}
.kpi-card__trend:empty { display: none; }
.kpi-card__trend--up   { color: var(--color-success); background: var(--color-success-bg); }
.kpi-card__trend--down { color: var(--color-error);   background: var(--color-error-bg); }
.kpi-card__trend--neutral { color: var(--color-text-muted); background: var(--color-bg-elevated); }
.kpi-card__trend--new  { color: var(--color-info);    background: var(--color-info-bg); }
.kpi-info-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--touch-target-min);  /* WCAG 2.5.5 touch target */
  height: var(--touch-target-min);
  font-size: var(--text-sm);
  font-weight: var(--font-semibold);
  line-height: 1;
  border-radius: var(--radius-full);
  border: 1px solid var(--color-border-strong);
  background: var(--color-bg-surface);
  color: var(--brand-primary);
  cursor: pointer;
  transition: background-color var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
}
.kpi-info-button--abs {
  position: absolute;
  top: var(--space-1);
  right: var(--space-1);
  width: 1rem;
  height: 1rem;
  font-size: var(--text-2xs);
  z-index: calc(var(--z-base) + 1); /* local stacking only — must NOT compete with dropdowns */
}
@media (min-width: 640px) {
  .kpi-info-button--abs {
    width: 1.375rem;
    height: 1.375rem;
    font-size: var(--text-xs);
  }
}
.kpi-info-button:hover {
  background: var(--color-bg-elevated);
  border-color: var(--brand-primary);
  color: var(--brand-primary-dark);
}
.kpi-info-button:focus-visible {
  background: var(--color-bg-elevated);
  border-color: var(--brand-primary);
  color: var(--brand-primary-dark);
}
.kpi-info-button[aria-expanded="true"] {
  background: var(--brand-primary);
  border-color: var(--brand-primary);
  color: var(--color-text-inverse);
}
/* T191 P191-D: static info button — pure hover-only tooltip affordance
   (no toggle). Cursor stays as `help` so the user knows it's informational
   and not actionable. Focus ring identical to the toggle variant. */
.kpi-info-button--static {
  cursor: help;
}
.kpi-info-button--static:hover,
.kpi-info-button--static:focus-visible {
  background: var(--color-info-bg);
  color: var(--color-info);
  border-color: var(--color-info);
}
.kpi-card[data-kpi-clickable] {
  cursor: pointer;
}

.manual-amount-field {
  position: relative;
  display: inline-flex;
  width: 100%;
  min-width: calc(6ch + 3.1rem);
  max-width: 100%;
  flex: 1 1 auto;
}

.manual-amount-input {
  padding-right: 2.1rem;
  border: 1px solid var(--brand-primary);
  box-shadow: inset 0 2px 4px rgba(var(--shadow-color), 0.08);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
  -moz-appearance: textfield;
}

.manual-amount-input:focus {
  border-color: var(--brand-primary-dark);
  box-shadow: 0 0 0 3px var(--toggle-focus-ring);
}

.manual-amount-field__suffix {
  position: absolute;
  top: 50%;
  right: var(--space-2);
  transform: translateY(-54%);
  font-weight: var(--font-semibold);
  color: var(--color-text-secondary);
  pointer-events: none;
  z-index: var(--z-base);
}

.manual-amount-input::-webkit-outer-spin-button,
.manual-amount-input::-webkit-inner-spin-button {
  margin: 0;
  -webkit-appearance: none;
}

.kpi-tooltip-content {
  margin-top: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-lg);
  border: 1px solid var(--color-border-default);
  background: var(--color-bg-page);
  color: var(--color-text-secondary);
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
  box-shadow: 0 8px 16px rgba(var(--shadow-color), 0.08);
}
.kpi-tooltip-content[hidden] {
  display: none;
}
.kpi-tooltip-content a {
  color: var(--brand-primary);
  text-decoration: underline;
}
.kpi-tooltip-content :where(a:hover) {
  color: var(--brand-primary-dark);
}

/* Reusable badge for KPI icons with pastel backgrounds */
.kpi-icon-badge {
  --kpi-accent-bg: var(--color-info-bg); /* default blue-100 */
  /* Icon ink filter defaults (tuned for white-line PNGs) */
  --icon-invert: 1;        /* invert white to dark */
  --icon-brightness: .28;  /* darkness of the ink */
  --icon-contrast: 1.2;    /* pop on pastel */
  background: var(--kpi-accent-bg);
  border: 1px solid var(--color-border-default);
  box-shadow: var(--shadow-sm);
}
.kpi-icon-badge--blue { --kpi-accent-bg: var(--color-info-bg); }      /* blue-100 */
.kpi-icon-badge--green { --kpi-accent-bg: var(--color-success-bg); } /* green-100 */
.kpi-icon-badge--yellow { --kpi-accent-bg: var(--color-yellow-100); --icon-brightness: .24; }
.kpi-icon-badge--purple { --kpi-accent-bg: var(--color-purple-100); }
.kpi-icon-badge--red { --kpi-accent-bg: var(--color-error-bg); --icon-brightness: .26; }
.kpi-icon-badge--indigo { --kpi-accent-bg: var(--color-indigo-100); }
.kpi-icon-badge--teal { --kpi-accent-bg: var(--color-teal-100); }
.kpi-icon-badge--orange { --kpi-accent-bg: var(--color-orange-100); --icon-brightness: .26; }
.kpi-icon-badge--cyan { --kpi-accent-bg: var(--color-cyan-100); }
.kpi-icon-badge--emerald { --kpi-accent-bg: var(--color-emerald-100); }

/* KPI icon wrapper – for hover detection */
.kpi-icon-wrap {
  flex-shrink: 0;
}

.kpi-icon {
  width: var(--icon-lg); height: var(--icon-lg);
  /* Make white-line icons stand out over pastel badges */
  filter: invert(var(--icon-invert)) brightness(var(--icon-brightness)) contrast(var(--icon-contrast));
  mix-blend-mode: multiply; /* subtle tint with background */
}

/* ── KPI cards: icon circle backgrounds (pastel in light, subtle dark in dark) ──
 * v15-fix: limitado a wraps SIN badge — si hay badge, --kpi-accent-bg manda. */
:where(html[data-theme="dark"]) .kpi-icon-wrap:not(.kpi-icon-badge) {
    background: var(--color-bg-elevated);
}
/* KPI icon badges: dark tints via tokens — each --color-*-100 overrides in
 * [data-theme="dark"] (L542-548, L532, L538) make per-class dark overrides redundant. */
:where([data-theme="dark"]) .kpi-icon-badge {
    border-color: var(--color-border-default);
    --icon-invert: 0;
    --icon-brightness: 1;
    --icon-contrast: 1;
}
/* In dark mode, white PNGs must NOT be multiplied against the dark bg */
:where([data-theme="dark"]) .kpi-icon {
    mix-blend-mode: normal;
    filter: invert(0) brightness(1) contrast(1);
}
/* KPI card bg itself */
:where([data-theme="dark"]) .kpi-card,
:where([data-theme="dark"]) .kpi-value,
:where([data-theme="dark"]) .kpi-label {
    color: var(--color-text-primary);
}

/* Wrapper for page content to ensure full height */
.content-wrapper {
    flex: 1 0 auto;
    display: flex;
    flex-direction: column;
}
.content-wrapper > main:not(.co-main) {
    overflow-x: hidden;
}

/* Cards border */

.border-shadow {
	box-shadow: var(--shadow-md);
}

/* Intentional: custom shadow-lg override of Tailwind */
.shadow-lg {
    box-shadow: var(--shadow-lg);
}

/* Header Button */


.img-button {
    display: inline-block;
    width: var(--icon-md);
    height: var(--icon-md);
    margin-right: var(--space-1);
}


/* .btn-primary — duplicate removed, single definition kept above. */

/* .btn-primary.hidden specificity (0,2,0) > .btn-primary (0,1,0) — no !important needed */
.btn-primary.hidden,
button.hidden {
        display: none;
}


/* Brand-tinted icon filter for raster <img> elements.
   TODO: migrate to inline SVG to use CSS color tokens (color: var(--brand-primary)) */
.inverted-color {
  filter: brightness(0) saturate(100%) invert(54%) sepia(76%) saturate(2500%) hue-rotate(170deg);
}

/* ── Header: override bg-white/text-purple from Tailwind in HTML ── */
:where([data-theme="dark"]) header {
    background: var(--color-bg-surface);
    border-bottom: 1px solid var(--color-border-default);
}
/* Override Tailwind text-purple-600 on header container */
/* stylelint-disable no-descending-specificity -- cross-component false positive */
:where([data-theme="dark"]) header .container {
/* stylelint-enable no-descending-specificity */
    color: var(--color-text-primary);
}
/* ── Logo: ensure visibility on dark bg ── */
:where([data-theme="dark"]) header img.w-48 {
    filter: brightness(0) invert(1);
}
/* ── Menu button icon (.inverted-color) — already brand-tinted, lighten for dark ── */
:where([data-theme="dark"]) .inverted-color {
    filter: brightness(0) saturate(100%) invert(100%);
}

/* Botones azules en panel: con etiqueta (icono + palabra) o solo icono */
.header-actions .panel-action-wrap.btn-primary {
  box-sizing: border-box;
  flex-shrink: 0;
  justify-content: center;
  align-items: center;
  gap: var(--space-1);
}
/* Solo icono (refunds u otros): tamaño fijo — WCAG 2.5.8 mín 44px */
.header-actions .panel-action-wrap.btn-primary:where(:not(:has(.panel-action-label))) {
  padding: 0;
  min-width: var(--touch-target-min);
  min-height: var(--touch-target-min);
  width: var(--touch-target-min);
  height: var(--touch-target-min);
  line-height: 0;
}
/* Con etiqueta: WCAG 2.5.8 mín 44px de alto */
.header-actions .panel-action-wrap.btn-primary:where(:has(.panel-action-label)),
.header-actions .panel-action-wrap.panel-action-with-label {
  min-height: var(--touch-target-min);
  padding: var(--space-2) var(--space-4);
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
  gap: var(--space-2);
  border-radius: var(--radius-md);
}
.header-actions .panel-action-wrap.btn-primary:where(:has(.panel-action-label)) .panel-btn-icon {
  width: var(--icon-sm);
  height: var(--icon-sm);
  min-width: var(--icon-sm);
  min-height: var(--icon-sm);
}
.header-actions .panel-action-wrap.panel-action-with-label img {
  width: var(--icon-sm);
  height: var(--icon-sm);
  min-width: var(--icon-sm);
  min-height: var(--icon-sm);
  object-fit: contain;
  flex-shrink: 0;
}

/* Iconos dentro del botón azul: tamaño fijo y filtro para blanco.
   filter: brightness(0) invert(1) turns raster icons white — kept because
   .panel-btn-icon and .inverted-color are <img> elements, not inline SVGs.
   For inline SVGs, use .panel-btn-icon-svg instead (see below). */
.btn-primary .inverted-color,
/* stylelint-disable no-descending-specificity -- cross-component false positive */
.btn-primary .panel-btn-icon {
/* stylelint-enable no-descending-specificity */
  width: var(--icon-sm);
  height: var(--icon-sm);
  min-width: var(--icon-sm);
  min-height: var(--icon-sm);
  display: block;
  object-fit: contain;
  flex-shrink: 0;
  filter: brightness(0) invert(1);
}

/* SVG dentro de botón azul: trazo blanco */
.btn-primary .panel-btn-icon-svg {
  width: var(--icon-sm);
  height: var(--icon-sm);
  min-width: var(--icon-sm);
  min-height: var(--icon-sm);
  flex-shrink: 0;
  stroke: var(--color-text-inverse);
  color: var(--color-text-inverse);
}

/* Tooltip globo en botones de acción del panel (no depende de Tailwind) */
.header-actions .panel-action-wrap {
  position: relative;
  overflow: visible;
}

/* Globo único para todos los botones de acción (Crear, Exportar, CSV, Limpiar): no heredar del botón */
/* Base tooltip for panel action buttons (shared between header and refund pages) */
.panel-action-tooltip {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  top: 100%;
  margin-top: var(--space-2);
  padding: var(--space-1-5) var(--space-3);
  min-width: 8rem;
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  line-height: var(--leading-tight);
  color: var(--color-text-inverse);
  background: var(--gray-900);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  white-space: nowrap;
  text-align: center;
  z-index: var(--z-tooltip);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--transition-fast), visibility var(--transition-fast);
  pointer-events: none;
  display: inline-block;
  box-sizing: border-box;
}

.panel-action-wrap:hover .panel-action-tooltip {
  opacity: 1;
  visibility: visible;
}

/* Floating variant — viewport-anchored to escape ancestor stacking contexts.
   JS positions top/left on pointer/focus events. Do NOT set top/left here:
   the initial 0/0 would cause a one-frame flicker before JS repositions. */
.panel-action-tooltip--floating {
  position: fixed;
  left: 0;
  top: 0;
  transform: none;
  margin-top: 0;
}

/* Refund pages: mismo tooltip y botón azul solo icono */
.refund-page__actions .panel-action-wrap,
.refund-page .panel-action-wrap {
  position: relative;
  overflow: visible;
}

.refund-page__actions .panel-action-wrap.btn-primary,
.refund-page .panel-action-wrap.btn-primary {
  padding: 0;
  min-width: var(--touch-target-min);
  min-height: var(--touch-target-min);
  width: var(--touch-target-min);
  height: var(--touch-target-min);
  box-sizing: border-box;
  flex-shrink: 0;
  line-height: 0;
  justify-content: center;
  align-items: center;
}

/* Refund: botones con palabra (mismo ancho fijo que en el panel) */
.refund-page__actions .panel-action-wrap.panel-action-with-label,
.refund-page .panel-action-wrap.panel-action-with-label {
  min-height: var(--touch-target-min);
  padding: var(--space-1) var(--space-3);
  font-size: var(--text-sm);
  line-height: var(--leading-tight);
  gap: var(--space-1);
  justify-content: center;
  align-items: center;
}
.refund-page__actions .panel-action-wrap.panel-action-with-label .panel-btn-icon,
.refund-page .panel-action-wrap.panel-action-with-label .panel-btn-icon,
.refund-page__actions .panel-action-wrap.panel-action-with-label img,
.refund-page .panel-action-wrap.panel-action-with-label img {
  width: var(--icon-sm);
  height: var(--icon-sm);
  min-width: var(--icon-sm);
  min-height: var(--icon-sm);
  flex-shrink: 0;
  object-fit: contain;
}

/* Refund page tooltip: inherits all styles from base .panel-action-tooltip above */

/* Outlined variant for secondary panel actions (Exportar, Importar, Limpiar) */
.panel-action-btn--outlined {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--touch-target-min); /* WCAG 2.1 SC 2.5.8 */
  padding: var(--space-2) var(--space-4);
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  font-family: var(--font-heading);
  line-height: var(--leading-snug);
  cursor: pointer;
  background: var(--color-bg-elevated);
  color: var(--color-text-primary);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  transition: background-color var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
}
.panel-action-btn--outlined:hover,
.panel-action-btn--outlined:focus-visible {
  background: var(--color-brand-tint-12);
  border-color: var(--brand-primary);
  color: var(--brand-primary-dark);
}
/* stylelint-disable no-descending-specificity -- cross-component false positive */
:where(html[data-theme="dark"]) .panel-action-btn--outlined img {
/* stylelint-enable no-descending-specificity */
  filter: invert(1) brightness(1.1);
}

/* Layout for action controls */
.header-actions {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        justify-content: flex-start; /* asegura alineación a la izquierda */
}


/* Refund experience styling */
.refund-page {
  display: flex;
  flex-direction: column;
  gap: clamp(20px, 3vw, 32px);
  width: 100%;
}

/* Cabecera y botones de acción en móvil (period_detail: volver, XML SEPA, exportar, etc.) */
@media (max-width: 640px) {
  .refund-page__header {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-3);
  }
  .refund-page__header > a:first-child {
    align-self: flex-start;
  }
  .refund-page__actions {
    width: 100%;
    justify-content: flex-start;
  }
  .refund-page__btn-sepa {
    white-space: nowrap;
  }
}


.refund-section {
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border-default);
  border-radius: var(--radius-xl);
  box-shadow: 0 10px 24px rgba(var(--shadow-color), 0.08);
  padding: clamp(22px, 3.6vw, 38px);
}

.refund-section--plain {
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border-default);
  box-shadow: 0 6px 18px rgba(var(--shadow-color), 0.06);
}

.refund-section__header {
  display: flex;
  flex-direction: column;
  gap: clamp(8px, 1.5vw, 14px);
  margin-bottom: clamp(14px, 2.8vw, 22px);
}

.refund-section__title {
  font-size: clamp(1.5rem, 2.6vw, 2.2rem);
  font-weight: var(--font-bold);
  color: var(--color-text-primary);
}

.refund-section__subtitle {
  font-size: var(--text-sm);
  color: var(--color-text-secondary);
  max-width: 62ch;
}

.refund-summary-grid {
  display: grid;
  gap: clamp(14px, 2.4vw, 26px);
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  margin-bottom: clamp(18px, 3vw, 30px);
}

.refund-summary-card {
  position: relative;
  padding: clamp(18px, 3vw, 26px);
  border-radius: var(--radius-xl);
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border-default);
  box-shadow: 0 6px 18px rgba(var(--shadow-color), 0.06);
}

.refund-summary-card__label {
  display: block;
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
  color: var(--color-text-muted);
  margin-bottom: var(--space-3);
}

.refund-summary-card__value {
  display: block;
  font-size: clamp(1.35rem, 2.4vw, 1.9rem);
  font-weight: var(--font-bold);
  color: var(--color-text-primary);
}

.refund-summary-card__caption {
  display: block;
  margin-top: var(--space-2);
  font-size: var(--text-sm);
  color: var(--color-text-secondary);
}

.refund-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  justify-content: flex-end;
  align-items: center;
}

/* Refund guide card: dos cards (mensaje + qué hacer), horizontal en escritorio, apiladas en móvil */
.refund-guide-card__header {
  margin-bottom: 0;
}

.refund-guide-card__title {
  font-size: clamp(1.35rem, 2.2vw, 1.75rem);
  font-weight: var(--font-bold);
  color: var(--color-text-primary);
  margin-bottom: var(--space-3);
}

.refund-guide-card__cards {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(14px, 2.4vw, 26px);
  margin-top: var(--space-2);
}

.refund-guide-card__msg-card,
.refund-guide-card__steps-card {
  flex: 1 1 min(100%, 280px);
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.refund-guide-card__msg-card .refund-guide-card__lead {
  margin: 0;
  font-size: var(--text-base);
  line-height: var(--leading-relaxed);
  color: var(--color-text-secondary);
}

.refund-guide-card__steps-list {
  list-style: decimal;
  list-style-position: outside;
  padding-left: var(--space-5);
  font-size: var(--text-base);
  line-height: var(--leading-relaxed);
  color: var(--color-text-secondary);
  margin: 0;
}

.refund-guide-card__steps-list li {
  margin-bottom: var(--space-1);
  padding-left: var(--space-1);
}

.refund-guide-card__steps-list :where(li:last-child) {
  margin-bottom: 0;
}

/* IBAN input width constraint — #793: 2-col grid made the field disproportionately wide */
.iban-field-wrapper {
    max-width: 30ch;
}

/* Refund tooltip (CargaOnline request form) */
.refund-tooltip-panel {
  z-index: var(--z-tooltip);
  min-width: 280px;
  max-width: min(400px, calc(100vw - var(--space-4)));
  max-height: min(500px, calc(100vh - var(--space-4)));
  white-space: normal;
}

/* Page title subtle counter and indentation */
.page-title {
  margin-left: var(--space-1);
}
.page-title .results-count {
  margin-left: var(--space-1);
  color: var(--color-text-muted);
  font-weight: var(--font-medium);
}

/* Data table refinements */
.data-table {
  border-collapse: separate;
  border-spacing: 0;
}
/* T440: sticky thead so column headers remain visible on vertical scroll */
.table-sticky-thead,
.data-table .table-sticky-thead {
    position: sticky;
    top: 0;
    z-index: var(--z-sticky, 200);
    background: var(--color-bg-elevated, var(--color-surface));
}
.data-table thead :where(tr.header-row) th {
  vertical-align: bottom;
  font-weight: var(--font-semibold);
  color: var(--color-text-primary);
  border-bottom: 1px solid var(--color-border-default);
}
.data-table thead :where(tr.filter-row) th {
  padding-top: var(--space-2);
  padding-bottom: var(--space-2);
}
/* stylelint-disable no-descending-specificity -- cross-component false positive */
:where(table).data-table th,
/* stylelint-enable no-descending-specificity */
:where(table).data-table td {
  border-left: none;
  border-right: none;
}
/* Zebra striping: handled by {% cycle 'bg-elevated' '' %} in templates.
   nth-child rule removed to avoid double-striping conflict. */
.data-table tbody :where(tr:hover) {
  background-color: var(--color-bg-elevated);
}
/* Sticky first column — keeps identifier visible on horizontal scroll.
   Same pattern as .chart-legend-table--with-label (DRY token usage). */
.data-table thead :where(th:first-child),
.data-table tbody :where(td:first-child) {
  position: sticky;
  left: 0;
  z-index: calc(var(--z-base) + 1);
  background: var(--color-bg-surface);
  border-right: 1px solid var(--color-border-default);
}
.data-table thead :where(tr.header-row) th:first-child {
  z-index: calc(var(--z-base) + 3);
}
.data-table thead :where(tr.filter-row) th:first-child {
  z-index: calc(var(--z-base) + 2);
}
.data-table tbody :where(td:first-child).bg-elevated {
  background: var(--color-bg-elevated);
}
.data-table tbody :where(tr:hover) td:first-child {
  background: var(--color-bg-elevated);
}
.actions-col {
  text-align: center;
  white-space: nowrap;
  min-width: max-content; /* prevent action buttons from wrapping */
}

.table-actions {
  display: flex;
  flex-wrap: nowrap;
  justify-content: center;
  gap: var(--space-2);
}

.table-action-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  width: var(--touch-target-min);
  height: var(--touch-target-min);
  min-width: var(--touch-target-min);
  min-height: var(--touch-target-min);
  padding: var(--space-1);
  font-size: var(--text-xs);
  line-height: 1;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  transition: background-color var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast), box-shadow var(--transition-fast);
}

.table-action-button:hover {
  box-shadow: var(--shadow-brand-sm);
}
.table-action-button:focus-visible {
  box-shadow: var(--shadow-brand-sm);
}

.table-action-button .img-button {
  float: none;
  width: var(--icon-sm);
  height: var(--icon-sm);
  margin: 0;
  display: block;
}
.table-action-button img.img-button,
.table-action-button svg.img-button {
  flex-shrink: 0;
}

.table-action-button--outlined {
  background-color: var(--color-bg-surface);
  color: var(--brand-primary);
  border-color: var(--brand-primary);
}

.table-action-button--outlined:hover,
.table-action-button--outlined:focus-visible {
  background-color: var(--color-brand-tint-12);
  border-color: var(--brand-primary-dark);
  color: var(--brand-primary);
}

.table-action-button--brand {
  background-color: var(--brand-primary);
  border-color: var(--brand-primary-dark);
  color: var(--color-text-inverse);
}

.table-action-button--brand:hover,
.table-action-button--brand:focus-visible {
  background-color: var(--brand-primary-dark);
  border-color: var(--brand-primary-dark);
  color: var(--color-text-inverse);
}

.table-action-button--danger {
  background-color: var(--color-error-bg);
  border-color: var(--color-error-light);
  color: var(--color-error-hover);
}

.table-action-button--danger:hover,
.table-action-button--danger:focus-visible {
  background-color: var(--color-error-bg);
  border-color: var(--color-error-light);
  color: var(--color-error-hover);
}

.table-action-button--success {
  background-color: var(--color-success-bg);
  border-color: var(--color-success);
  color: var(--color-success-hover);
}
.table-action-button--success:hover,
.table-action-button--success:focus-visible {
  background-color: var(--color-success-bg);
  border-color: var(--color-success);
  color: var(--color-success-hover);
}

.table-action-button--disabled {
  background-color: var(--color-bg-elevated);
  border-color: var(--color-border-default);
  color: var(--color-text-muted);
  cursor: not-allowed;
  pointer-events: none;
}

.table-action-button--text {
  width: auto;
  height: auto;
  padding: var(--space-1) var(--space-3);
  min-height: 2rem;
}

/* Reuses .inverted-color filter — raster <img>, cannot use CSS color.
   TODO: add class .inverted-color in HTML and remove this rule */
.table-action-button--outlined .img-button {
  filter: brightness(0) saturate(100%) invert(54%) sepia(76%) saturate(2500%) hue-rotate(170deg);
}

/* Table footer compact style */
.table-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  padding-block: var(--space-3);
  font-size: var(--text-sm);
}
@media (min-width: 640px) {
  .table-footer { justify-content: space-between; }
}
.table-footer .footer-left {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: var(--space-2);
}
.table-footer .footer-left a {
  margin-right: 0;
  min-width: 2.25rem;
  min-height: 2.25rem;
  justify-content: center;
}
.table-footer .page-indicator {
  color: var(--color-text-secondary);
  margin-inline: var(--space-1);
  white-space: nowrap;
}

/* === Toggle (Tailwind-like) helpers ===
   Peer-based toggles — rely on:
   <label class="inline-flex ...">
     <input type="checkbox" class="sr-only peer"> <div></div>
   </label>
   .sr-only defined by Tailwind v3 preflight — no duplicate needed.
*/

label.inline-flex > input.sr-only.peer + div {
  position: relative;
  width: var(--toggle-width);
  height: var(--toggle-height);
  background: var(--toggle-track-off); /* más contraste */
  border-radius: var(--radius-full);
  transition: background-color var(--transition-ui), box-shadow var(--transition-ui);
}
label.inline-flex > input.sr-only.peer + div::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: var(--icon-sm);
  height: var(--icon-sm);
  background: var(--toggle-knob-off);
  border: 1px solid var(--brand-primary-light);
  box-shadow: var(--shadow-xs), 0 0 0 1px rgba(var(--shadow-color), 0.06);
  border-radius: var(--radius-full);
  transition: transform var(--transition-ui), border-color var(--transition-ui);
}
label.inline-flex > input.sr-only.peer:focus + div {
  outline: none;
  box-shadow: 0 0 0 4px var(--toggle-focus-ring);
}
label.inline-flex > input.sr-only.peer:checked + div {
  background: var(--brand-primary);
}
label.inline-flex > input.sr-only.peer:checked + div::after {
  transform: translateX(var(--space-5));
  background: var(--color-bg-surface);
  border-color: rgba(var(--shadow-color), 0.12);
  box-shadow: var(--shadow-xs);
}

.header-actions .actions {
        margin-left: 0;
}

/* Transacciones (y otras sin botón Crear): .actions vacío no ocupa espacio y Export alineado a la izquierda */
.header-actions-no-primary .actions {
        width: 0;
        min-width: 0;
        overflow: hidden;
        padding: 0;
        margin: 0;
}
.header-actions-no-primary .filters {
        margin-left: calc(-1 * var(--space-2)); /* compensar gap del contenedor */
}
.header-actions-no-primary .filters .header-actions-export-link {
        margin-left: 0;
}

/* Con botón Crear, el espacio entre Crear y Export lo da el gap-3 del .header-actions; sin margen extra en el primer botón de .filters */
.header-actions .filters .header-actions-export-link {
        margin-left: 0;
}

/* En el área de filtros/acciones de tabla, los botones no flotan a la derecha */
.header-actions .btn-primary {
        float: none;
}

/* Hacer que el bloque de filtros ocupe el espacio restante y permita empujar toggles */
.header-actions .filters {
        display: flex;
        align-items: center;
        flex-wrap: wrap;
        flex: 1 1 auto; /* ocupa el ancho disponible */
}

@media (max-width: 640px) {
        .btn-primary {
                margin: 1%;
        }
        .buttonText {
                display: none;
        }


        /* Panel: botones de acción con wrap vertical en móvil */
        .header-actions {
                flex-wrap: wrap;
                gap: var(--space-2);
        }
        .header-actions .actions,
        .header-actions .filters {
                width: 100%;
                flex-wrap: wrap;
                margin-left: 0;
                margin-top: 0;
        }
}

@media (min-width: 640px) {
        .btn-primary .buttonText {
                display: inline;
        }
}

/* Footer estilos */

.footer-distributed {
        background-color: var(--slate-900);
        box-shadow: var(--shadow-xs);
        box-sizing: border-box;
        width: 100%;
        text-align: left;
        padding: var(--space-6) var(--space-8);
        margin-top: auto;
}

/* === Header Nav — responsive layout ===
   - Desktop (>=1024px): horizontal icon row in header bar
   - Mobile (<1024px): hidden dropdown toggled by hamburger
*/

/* Lock background scroll when mobile menu is open */
html.menu-open, body.menu-open {
  overflow: hidden !important; /* stylelint-disable-line declaration-no-important -- must override inline/cascade */
  height: 100vh;
  height: 100dvh; /* progressive enhancement — overrides vh in supporting browsers */
}

/* ═══════════════════════════════════════════════════
   Collapsible Sidebar Navigation
   States: collapsed (60px icons), expanded (220px icons+labels),
           mobile drawer (slide-in overlay)
   ═══════════════════════════════════════════════════ */

/* ── Base (shared mobile/desktop) ── */
.sidebar {
  background: var(--color-bg-surface);
  border-right: 1px solid var(--color-border-default);
  display: flex;
  flex-direction: column;
}

.sidebar__nav {
  flex: 1;
  min-height: 0; /* allow flex child to shrink below content height, preventing spurious scroll */
  display: flex;
  flex-direction: column;
  padding: var(--space-2) 0;
  overflow-y: auto;
  overflow-x: hidden;
  scrollbar-width: thin;
}

.sidebar__list {
  list-style: none;
  margin: 0;
  padding: 0 var(--space-2);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.sidebar__link {
  display: grid;
  grid-template-columns: var(--sidebar-item-size) 1fr;
  align-items: center;
  min-height: var(--sidebar-item-size);
  border-radius: var(--radius-md);
  color: var(--color-text-secondary);
  text-decoration: none;
  font-family: var(--font-heading);
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  transition: background-color var(--transition-ui),
              color var(--transition-ui),
              box-shadow var(--transition-ui);
  overflow: hidden;
  white-space: nowrap;
}

/* Button reset for sidebar__link applied to <button> elements (theme toggle, logout),
   so icon+label grid alignment matches the <a> items. */
button.sidebar__link {
  background: transparent;
  border: 0;
  padding: 0;
  font: inherit;
  text-align: left;
  cursor: pointer;
  width: 100%;
}

.sidebar__icon {
  width: var(--sidebar-icon-size);
  height: var(--sidebar-icon-size);
  justify-self: center;
  flex-shrink: 0;
  transition: transform var(--transition-ui), filter var(--transition-ui);
}

.sidebar__label {
  opacity: 0;
  transition: opacity var(--transition-fast);
  pointer-events: none;
  padding-right: var(--space-2);
  overflow: hidden;
  text-overflow: ellipsis;
}

.sidebar__link:hover,
.sidebar__link:focus-visible {
  background: var(--brand-primary-light);
  color: var(--color-text-primary);
}

.sidebar__link--active {
  background: var(--brand-primary);
  color: var(--color-text-inverse);
  box-shadow: var(--shadow-brand-sm);
}

.sidebar__link--active .sidebar__icon {
  filter: invert(1) brightness(1.05) contrast(1.05);
}

.sidebar__link:hover .sidebar__icon {
  transform: scale(1.08);
}

.sidebar__separator {
  height: 1px;
  background: var(--color-border-default);
  margin: var(--space-3) var(--space-4);
}

.sidebar__toggle {
  display: none; /* visible only on desktop */
}

/* ── Sidebar icon: white-source PNGs (e.g. logout.png) need opposite treatment ── */
.sidebar__icon--inverted {
  filter: brightness(0) saturate(100%) invert(54%) sepia(76%) saturate(2500%) hue-rotate(170deg);
}

/* ── Dark mode: sidebar ── */
/* stylelint-disable no-descending-specificity -- cross-component false positive */
:where([data-theme="dark"]) .sidebar__icon {
/* stylelint-enable no-descending-specificity */
  filter: invert(1) brightness(1.1);
}
:where([data-theme="dark"]) .sidebar__icon--inverted {
  filter: none; /* white source is already correct for dark backgrounds */
}
/* stylelint-disable no-descending-specificity -- cross-component false positive */
:where([data-theme="dark"]) .sidebar__link--active .sidebar__icon {
/* stylelint-enable no-descending-specificity */
  filter: invert(1) brightness(1.05) contrast(1.05);
}
:where([data-theme="dark"]) .sidebar__link--active .sidebar__icon--inverted {
  filter: none; /* active bg is brand-colored, white icon is already visible */
}
:where([data-theme="dark"]) .sidebar__link:hover {
  background: var(--color-bg-elevated);
}

/* ── Sidebar SVG icon modifier ──
   SVGs use stroke="currentColor", not filter:invert() like PNGs.
   This modifier overrides the PNG filter strategy with color-based theming. */
.sidebar__icon--svg {
  color: var(--color-text-primary);
  filter: none;
}
.sidebar__link--active .sidebar__icon--svg {
  color: var(--color-text-inverse);
  filter: none;
}
/* stylelint-disable-next-line no-descending-specificity -- intentional: dark base < active override */
:where([data-theme="dark"]) .sidebar__icon--svg {
  color: var(--color-text-primary);
  filter: none;
}
:where([data-theme="dark"]) .sidebar__link--active .sidebar__icon--svg {
  color: var(--color-text-inverse);
  filter: none;
}

/* ── Sidebar overlay (mobile backdrop) ── */
.sidebar-overlay {
  position: fixed;
  inset: 0;
  background: var(--color-overlay);
  z-index: calc(var(--z-sidebar-overlay) - 1);
  opacity: 0;
  transition: opacity var(--transition-slow);
  pointer-events: none;
}
.sidebar-overlay--visible {
  opacity: 1;
  pointer-events: auto;
}

/* ── Mobile (<1024px): slide-in drawer ── */
@media (max-width: 1023.98px) {
  .sidebar {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: min(var(--sidebar-expanded), 85vw);
    transform: translateX(-100%);
    transition: transform var(--transition-slow);
    z-index: var(--z-sidebar-overlay);
    padding-top: var(--space-6);
  }
  .sidebar.sidebar--open {
    transform: translateX(0);
  }
  .sidebar__label {
    opacity: 1;
    pointer-events: auto;
  }
  .sidebar__link {
    grid-template-columns: var(--sidebar-item-size) 1fr;
    padding: 0 var(--space-1);
  }
  body .sidebar__toggle { display: none; }
  .sidebar__theme-toggle {
    padding: 0 var(--space-2);
  }
  .sidebar__logout {
    margin-top: auto;
    padding: var(--space-2);
    border-top: 1px solid var(--color-border-default);
  }
}

/* ── Header sticky — all viewports (085 HR-01) ── */
.header-sticky {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  transition: box-shadow var(--transition-fast);
}
.header-sticky.is-scrolled {
  box-shadow: var(--shadow-sm);
}

/* ── Desktop (>=1024px): collapsible rail ── */
@media (min-width: 1024px) {

  .app-shell {
    display: grid;
    grid-template-columns: var(--sidebar-collapsed) minmax(0, 1fr);
    grid-template-rows: auto 1fr auto;
    grid-template-areas:
      "header header"
      "nav    main"
      "footer footer";
    min-height: 100vh;
  }

  /* Sidebar overlays content on expand (no grid reflow). Sidebar z-index > content
     keeps labels legible above. Main content stays at collapsed-column width. */

  header { grid-area: header; }

  .sidebar {
    grid-area: nav;
    width: var(--sidebar-collapsed);
    position: sticky;
    top: var(--header-height);
    height: calc(100vh - var(--header-height));
    transition: width var(--transition-base);
    z-index: var(--z-sticky);
    overflow: hidden;
  }
  /* Collapsed: no padding so icons center in the full 64px column */
  .sidebar__list {
    padding: 0;
  }

  .sidebar__link {
    grid-template-columns: var(--sidebar-collapsed) 1fr;
    padding: 0;
    border-radius: 0;
  }

  /* Expand on hover (unless suspended after explicit collapse) OR when pinned.
     Pinned (.sidebar--expanded) selectors listed first so lower specificity
     appears before higher specificity (stylelint no-descending-specificity). */
  .sidebar.sidebar--expanded,
  .sidebar:hover:not(.sidebar--suspend-hover) {
    width: var(--sidebar-expanded);
    overflow: visible;
  }
  .sidebar.sidebar--expanded .sidebar__list,
  .sidebar:hover:not(.sidebar--suspend-hover) .sidebar__list {
    padding: 0 var(--space-2);
  }
  .sidebar.sidebar--expanded .sidebar__link,
  .sidebar:hover:not(.sidebar--suspend-hover) .sidebar__link {
    border-radius: var(--radius-md);
  }
  .sidebar.sidebar--expanded .sidebar__label,
  .sidebar:hover:not(.sidebar--suspend-hover) .sidebar__label {
    opacity: 1;
    pointer-events: auto;
  }

  /* Pin toggle button at bottom — height matches sidebar link items for consistent hit area */
  .sidebar__toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    min-height: var(--sidebar-item-size);
    background: none;
    border: none;
    border-top: 1px solid var(--color-border-default);
    color: var(--color-text-muted);
    cursor: pointer;
    transition: color var(--transition-ui), background-color var(--transition-ui);
    flex-shrink: 0;
  }
  .sidebar__toggle:hover,
  .sidebar__toggle:focus-visible {
    background: var(--color-bg-elevated);
    color: var(--color-text-primary);
    outline: none;
  }
  .sidebar__toggle-icon {
    width: var(--icon-sm);
    height: var(--icon-sm);
    transition: transform var(--transition-base);
  }
  .sidebar--expanded .sidebar__toggle-icon {
    transform: rotate(180deg);
  }

  /* Sidebar bottom items — logout always visible, theme toggle mobile-only.
     Padding mirror .sidebar__list (L3233-3253): collapsed=0, expanded=0 var(--space-2).
     Sin esto, el hover del boton "Cerrar sesion" no llena el ancho del sidebar. */
  .sidebar__logout {
    margin-top: auto;
    padding: 0;
    border-top: 1px solid var(--color-border-default);
  }
  .sidebar.sidebar--expanded .sidebar__logout,
  .sidebar:hover:not(.sidebar--suspend-hover) .sidebar__logout {
    padding: var(--space-2) var(--space-2) 0;
  }
  .sidebar__theme-toggle {
    padding: var(--space-2);
  }
  .sidebar__link--logout {
    width: 100%;
  }
  .sidebar__link--logout:hover {
    color: var(--color-error);
    background: var(--color-error-bg);
  }
  .sidebar__mobile-only:not(.sidebar__logout) { display: none; }

  .app-shell .content-wrapper {
    grid-area: main;
    position: relative;
    z-index: var(--z-base);
    padding-left: var(--space-6);
    padding-right: var(--space-2);
  }

  /* Footer aligned with main content (collapsed column offset).
     Sidebar overlays on expand so no sync is needed. */
  footer.footer-distributed {
    grid-area: footer;
    padding-left: calc(var(--sidebar-collapsed) + var(--space-6));
    transition: padding-left var(--transition-base);
  }
  /* Footer follows sidebar state: pinned OR hovered (mirror del :has() de .app-shell L3215).
     Sin esto, el logo del footer queda tapado cuando el sidebar se expande. */
  .app-shell:has(.sidebar.sidebar--expanded) footer.footer-distributed,
  .app-shell:has(.sidebar:hover:not(.sidebar--suspend-hover)) footer.footer-distributed {
    padding-left: calc(var(--sidebar-expanded) + var(--space-6));
  }

  #sidebarOverlay { display: none; }
  #sidebarMobileToggle { display: none; }
}

.footer-distributed .footer-left p {
	color: var(--slate-400);
	font-size: var(--text-sm);
	margin: 0;
}

/* Chart legend table styling */
.chart-legend-table-wrapper {
  display: flex;
  flex-wrap: nowrap;
  gap: var(--space-4);
  width: 100%;
  justify-content: center;
}
@media (min-width: 1280px) {
  .chart-legend-table-wrapper {
    width: max-content;
    min-width: 100%;
  }
}

.chart-legend-table {
  width: max-content;  /* shrink to content — prevents white gap in label column */
  max-width: 100%;     /* never exceed container */
  table-layout: auto;
  margin-inline: auto;
  border-collapse: separate;
  border-spacing: 0;
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border-default);
  border-radius: var(--radius-md);
  overflow: clip; /* clip instead of hidden — preserves border-radius clipping without breaking position: sticky */
}

.chart-legend-table-wrapper .chart-legend-table--with-label {
  flex: 0 0 auto;
}

/* NOTE: Add class .table-header to <th> elements in chart-legend-table templates.
   Base styling (bg, color, font-weight, uppercase, letter-spacing, padding,
   line-height, vertical-align) is provided by .table-header.
   Only sticky positioning and border (specific to chart legends) are kept here. */
/* stylelint-disable no-descending-specificity -- cross-component false positive */
.chart-legend-table thead th {
/* stylelint-enable no-descending-specificity */
  border-bottom: 1px solid var(--color-border-default);
  position: sticky;
  top: 0;
  z-index: calc(var(--z-base) + 2); /* Chart legend sticky — local stacking */
  background: var(--color-bg-surface);
  white-space: normal;
  text-wrap: balance;
  overflow-wrap: break-word;
  word-break: keep-all;
  hyphens: manual;
  text-align: right;
}

/* Table body cells - base styles */
/* stylelint-disable no-descending-specificity -- cross-component false positive */
.chart-legend-table tbody td {
/* stylelint-enable no-descending-specificity */
  padding: var(--space-1) var(--space-2);
  text-align: right;
  color: var(--color-text-secondary);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  vertical-align: middle;
  height: 36px;
}

/* Tablet responsive adjustments */
@media (max-width: 1023.98px) {
  .chart-legend-table thead th:not(:first-child),
  .chart-legend-table tbody td:not(:first-child) {
    max-width: clamp(9rem, 45vw, 14rem);
  }

  .chart-legend-table--with-label thead th:first-child,
  .chart-legend-table--with-label tbody td:first-child {
    max-width: none;
  }
}

/* ── Chart mobile (max-width: 767px) — consolidated ── */
@media (max-width: 768px) {
  /* Table readability */
  .chart-legend-table {
    font-size: var(--text-sm);
    min-width: max-content;
  }
  .chart-legend-table thead th {
    padding: var(--space-2);
    font-size: var(--text-xs);
    white-space: nowrap;
  }
  .chart-legend-table tbody td {
    padding: var(--space-2);
    min-height: 40px;
  }
  .chart-legend-table tfoot td {
    padding: var(--space-2);
    font-weight: var(--font-bold);
  }
  .chart-legend-table tbody tr { cursor: pointer; }

  /* Grid overflow prevention */
  .chart-section-grid > * {
    max-width: 100%;
    overflow-x: hidden;
  }

  /* Legend panel height constraint */
  .chart-section-grid__legend-panel {
    max-height: clamp(300px, 60vh, 500px);
  }

  /* Chart canvas height optimization */
  .chart-section-grid__chart-inner > .relative {
    max-height: clamp(280px, 50vh, 400px);
  }
  .chart-section-grid__chart-inner > .relative.h-64 {
    max-height: clamp(200px, 35vh, 16rem);
    height: clamp(200px, 35vh, 16rem);
  }

  /* Legend scroll row limit */
  .chart-legend-scroll {
    max-height: calc(40px + 5 * var(--legend-row-height, 32px));
  }

  /* Touch targets */
  .legend-ds-th {
    min-height: var(--touch-target-min);
    padding: var(--space-2) var(--space-2);
    white-space: nowrap;
    vertical-align: middle;
  }
}
.chart-legend-table tbody tr:nth-child(even) td { background-color: var(--color-bg-page); }
.chart-legend-table tbody tr:hover td { background: var(--color-bg-elevated); }
/* stylelint-disable no-descending-specificity -- cross-component false positive */
.chart-legend-table--with-label td:first-child {
/* stylelint-enable no-descending-specificity */
  font-weight: var(--font-medium);
  text-align: left;
  white-space: nowrap;
  max-width: clamp(12rem, 25vw, 20rem);
  position: sticky;
  left: 0;
  z-index: calc(var(--z-base) + 1);
  background: var(--color-bg-surface);
}
/* Truncate label text inside flex cells (clickable-x-label is display:flex) */
.chart-legend-table--with-label td:first-child .legend-label-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
/* stylelint-disable no-descending-specificity -- cross-component false positive */
.chart-legend-table--with-label th:first-child { text-align: left; }
.chart-legend-table tfoot td { text-align: right; }
.chart-legend-table--with-label tfoot td:first-child {
/* stylelint-enable no-descending-specificity */
  text-align: left;
  z-index: calc(var(--z-base) + 1);
}
/* th:first-child is sticky on BOTH axes (top + left) — needs highest z-index to cover other th and td */
.chart-legend-table--with-label thead th:first-child {
  white-space: nowrap;
  position: sticky;
  left: 0;
  z-index: calc(var(--z-base) + 3);
  background: var(--color-bg-surface);
}
.chart-legend-table tbody tr:nth-child(even) td:first-child { background-color: var(--color-bg-page); }
.chart-legend-table tbody tr:hover td:first-child { background: var(--color-bg-elevated); }

/* Specificity must beat .chart-legend-table--with-label td:first-child (0,2,1) */
/* stylelint-disable-next-line no-descending-specificity */
.chart-legend-table .chart-legend-total td {
  font-weight: var(--font-bold);
  background-color: var(--color-bg-total-row);
}

/* % consumed column: centered number only (bar removed in T422 Fix 2) */
.chart-legend-table .num-cell--pct {
  text-align: center;
}
.legend-pct-text {
  font-variant-numeric: tabular-nums;
  vertical-align: middle;
}



/* Base class for all chart section grids */
.chart-section-grid {
  --legend-min: 320;      /* px — minimum legend column width */
  --legend-max: 520;      /* px — maximum legend column width */
  --legend-vw: 30;        /* vw — preferred legend column width (viewport-relative) */
  --legend-squeeze: 1.15; /* table can be up to 1.15× the container before stacking */
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-content: flex-start;
  gap: clamp(0.75rem, 2vw, 1.25rem);
  padding-top: clamp(16px, 3vw, 24px);
  padding-bottom: clamp(24px, 5vw, 40px);
  overflow-x: clip;
}

.chart-section-grid > * {
  min-width: 0;
  min-height: 0;
}

@media (max-width: 1280px) {
  .chart-section-grid {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto;
    gap: clamp(12px, 2vw, 20px);
  }
}

/* ── Chart desktop (min-width: 1200px) — consolidated ── */
@media (min-width: 1280px) {
  .chart-section-grid {
    grid-template-columns: minmax(320px, clamp(320px, 30vw, 520px)) minmax(0, 1fr);
    align-items: stretch;
    gap: clamp(1rem, 2vw, 1.5rem);
  }
  .chart-section-grid--legend-top {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(8px, 1.5vw, 1rem);
  }
  .chart-section-grid .chart-legend-scroll { overflow-x: auto; }
  .chart-section-grid:not(.chart-section-grid--legend-top) .chart-legend-table { width: 100%; max-width: 100%; }
  .chart-section-grid__legend { justify-content: flex-start; }
  .chart-section-grid__legend-panel {
    max-height: clamp(24rem, 80vh, 44rem);
    overflow-y: auto;
    overflow-x: clip;
    scrollbar-gutter: stable both-edges;
  }
}

/* Estado de los Tickets (#tickets-estado): this tab surfaces a very dense
   table (evento / aforo / vendidos / activados / % vendido / % activado)
   alongside a horizontal-bar chart. The default grid (320-520px legend +
   1fr chart, stacked below 1280px) wastes the chart column and stacks
   on common laptop viewports. Override to 2 equal columns from 1024px so
   table and chart live side-by-side with matched widths. Scoped by ID to
   keep the other ticket tabs on the default layout. */
@media (min-width: 1024px) {
  #tickets-estado .chart-section-grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-rows: auto;
    align-items: stretch;
    gap: clamp(1rem, 2vw, 1.5rem);
  }
  #tickets-estado .chart-section-grid__legend-panel {
    width: 100%;
    max-width: 100%;
  }
}

/* Base legend and chart styles */
.chart-section-grid__legend {
  display: flex;
  justify-content: center;
  align-items: center;
}

.chart-section-grid__legend-panel {
  width: min(100%, clamp(320px, 30vw, 520px));
  max-width: 100%;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin-inline: auto;
  overflow-x: clip; /* clip instead of hidden — preserves clipping without breaking position: sticky in children */
}

/* Legend-top variant: full width legend for horizontal list layout */
.chart-section-grid--legend-top .chart-section-grid__legend-panel {
  width: 100%;
  max-width: 100%;
}

.chart-section-grid__legend-panel .chart-legend-container {
  width: 100%;
}

@media (max-width: 1280px) {
  .chart-section-grid__legend {
    width: 100%;
    max-width: none;
    justify-content: center;
  }

  .chart-section-grid__legend-panel {
    width: 100%;
    max-width: 100%;
    max-height: clamp(400px, calc(100vh - 12rem), 600px);
    overflow-y: auto;
    overflow-x: auto;
    scrollbar-gutter: stable both-edges;
  }

  .chart-legend-container {
    width: 100%;
    max-width: 100%;
    overflow-x: auto;
    scrollbar-width: thin;
  }
  .chart-legend-container::-webkit-scrollbar { height: 6px; }
  .chart-legend-container::-webkit-scrollbar-track {
    background: var(--color-bg-elevated);
    border-radius: var(--radius-xs);
  }
  .chart-legend-container::-webkit-scrollbar-thumb {
    background: var(--color-text-muted);
    border-radius: var(--radius-xs);
  }
  .chart-legend-container::-webkit-scrollbar-thumb:hover {
    background: var(--color-text-secondary);
  }
}

/* Must come AFTER all .chart-section-grid rules so source-order wins */
.chart-section-grid[hidden],
.chart-section-grid.hidden { display: none; }

.chart-section-grid__chart {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: stretch;
  min-height: clamp(200px, 40vh, 300px);
}

.chart-section-grid__chart-inner {
  width: 100%;
  max-width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  flex: 1;
}

.chart-section-grid__chart-inner > .relative {
  width: 100%;
  max-height: 400px;
  display: flex;
  flex-direction: column;
}

/* Pie charts need limited height */
.chart-section-grid__chart-inner > .relative.h-64 {
  max-height: 16rem;
  height: 16rem;
  flex: 0 0 auto;
}


tr.event-finished {
  opacity: 0.6;
  font-style: italic;
  color: var(--color-text-muted);
}

/* stylelint-disable no-descending-specificity -- cross-component false positive */
.event-finished td {
/* stylelint-enable no-descending-specificity */
  background-color: var(--color-bg-page);
}

/* Legend container responsive scroll */
div.chart-legend-scroll {
  display: block;
  max-height: 25rem;
  max-width: calc(100% - 2rem);
  overflow-x: auto;
  overflow-y: auto;
}

.chart-legend-scroll--active .chart-legend-table-wrapper {
  justify-content: flex-start;
}
.chart-legend-scroll--active .chart-legend-table {
  margin-inline: 0;
}
.chart-legend { width: 100%; }

/* Clickable X labels - consolidated definition */
.clickable-x-label {
  display: flex;
  align-items: center;
  gap: var(--space-1-5);
  color: var(--brand-primary);
  cursor: pointer;
  text-decoration: none;
  border-radius: var(--radius-sm);
  -webkit-tap-highlight-color: transparent;
}

.clickable-x-label:hover {
  text-decoration: underline;
  background: var(--color-brand-tint-12);
  color: var(--brand-primary-dark);
}

/* Legend filter button — click to apply dashboard filter */
.legend-filter-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--color-text-muted);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: color var(--transition-fast), background-color var(--transition-fast);
}
.legend-filter-btn:hover {
  color: var(--brand-primary-dark);
  background: var(--color-brand-tint-12);
}
.legend-filter-btn:active {
  transform: scale(0.9);
}
.legend-filter-btn--active {
  color: var(--brand-primary);
  background: var(--color-brand-tint-12);
}

/* Dataset header cell + swatch */
.legend-ds-th {
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
}

.chart-section-grid__legend-panel .legend-ds-th {
  white-space: normal;
  line-height: var(--leading-snug);
}

.legend-ds-th.is-hidden { opacity: .55; }

.legend-swatch {
  display: inline-block;
  width: var(--legend-swatch-size);
  height: var(--legend-swatch-size);
  min-width: var(--legend-swatch-size);
  min-height: var(--legend-swatch-size);
  border-radius: var(--radius-xs);
  border: 1px solid var(--color-border-strong);
  background-color: var(--legend-color);
  flex-shrink: 0;
  vertical-align: middle;
}

.legend-swatch.legend-row-swatch { min-width: var(--space-2-5); }
.legend-row-swatch {
    margin-right: var(--space-2);
}
.legend-info-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 14px;
    height: 14px;
    margin-left: var(--space-1);
    border-radius: 50%;
    background: var(--color-bg-muted);
    color: var(--color-text-muted);
    font-size: var(--text-3xs);
    font-weight: 700;
    cursor: help;
    vertical-align: middle;
}
/* Info bubble — reuses kpi-bubble visuals but lives on <body> (escapes overflow) */
.info-bubble {
    display: none;
    position: fixed;
    z-index: var(--z-tooltip);
    width: max-content;
    max-width: 260px;
    padding: var(--space-2) var(--space-3);
    border-radius: var(--radius-md);
    background: var(--color-bg-elevated);
    color: var(--color-text-primary);
    font-size: var(--text-xs);
    font-weight: var(--font-normal);
    line-height: var(--leading-snug);
    box-shadow: 0 4px 12px rgba(var(--shadow-color), 0.2);
    pointer-events: none;
}
.info-bubble::before {
    content: '';
    position: absolute;
    top: 100%;
    left: var(--arrow-left, 1.25rem);
    border: 6px solid transparent;
    border-top-color: var(--color-bg-elevated);
}
.info-bubble.kpi-bubble--below::before {
    top: auto;
    bottom: 100%;
    border-top-color: transparent;
    border-bottom-color: var(--color-bg-elevated);
}
.info-bubble.kpi-bubble--visible {
    display: block;
    animation: fadeInUp var(--dur-fast) ease-out;
}

/* Empty state icon for charts with no data */
.empty-state-icon {
  width: 202px;
  height: 202px;
}

/* Chart control actions (Ver Todo, Restaurar) — secondary, understated */
.btn-reset-columns {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1-5);
  font-size: var(--text-xs);
  line-height: 1;
  padding: var(--space-1-5) var(--space-2-5);
  border-radius: var(--radius-full);
  border: 1px solid var(--color-border-default);
  color: var(--color-text-secondary);
  background: transparent;
  transition: background-color var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
}
.btn-reset-columns:hover {
  border-color: var(--brand-primary);
  color: var(--brand-primary-dark);
  background: var(--color-brand-tint-12);
}
.btn-reset-columns:active { transform: translateY(1px); }
.btn-reset-columns + .btn-reset-columns {
  margin-left: var(--space-2);
}

/* 085 HR-05: removed float:right — .footer-container uses flexbox */
.footer-distributed .footer-right {
	margin-top: var(--space-2);
	max-width: 180px;
}

.footer-distributed .footer-right a {
	display: inline-block;
	border-radius: var(--radius-xs);
	font-size: var(--text-xl);
	color: var(--color-text-inverse);
	text-align: center;
	line-height: 1.75;
	margin-left: var(--space-1);
	transition: color var(--transition-slow), transform var(--transition-slow);
}

.footer-distributed .footer-right a:hover {
	transform: scale(1.1);
}

/* Media Queries */

@media (max-width: 640px) {

	.footer-distributed .footer-left {
		text-align: center;
	}

	.footer-distributed .footer-right {
		text-align: center;
		float: none;
		margin: 0 auto var(--space-5);
	}

	.co-btn-premium {
		font-size: var(--text-lg);
		min-height: 48px;
		max-width: 100%;
		padding: var(--space-3) var(--space-4);
		border-radius: var(--radius-md);
	}
}

/* ── CargaOnline premium button system ── */
.co-btn-premium--recarga  { --_btn-gradient: var(--gradient-btn-recarga); }
.co-btn-premium--envio    { --_btn-gradient: var(--gradient-btn-envio); }

.co-btn-premium {
    display: flex;
    align-items: center;
    justify-content: center;
    background-image: var(--_btn-gradient, none);
    background-color: var(--slate-900);
    border: 0;
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    color: var(--color-text-inverse);
    font-size: var(--text-lg);
    font-weight: var(--font-semibold);
    line-height: var(--leading-tight);
    max-width: 480px;
    margin-inline: auto;
    width: 100%;
    min-height: 52px;
    padding: var(--space-4) var(--space-6);
    text-decoration: none;
    touch-action: manipulation;
    cursor: pointer;
    transition: opacity var(--transition-fast), box-shadow var(--transition-fast);
}
.co-btn-premium:hover {
    opacity: 0.9;
    box-shadow: var(--shadow-md);
}
.co-btn-premium:focus-visible {
    outline: 2px solid var(--brand-focus-ring);
    outline-offset: 2px;
}
.co-btn-premium:disabled,
.co-btn-premium[aria-disabled="true"] {
    opacity: 0.5;
    cursor: not-allowed;
}
.co-btn-premium:active:not(:disabled) {
    opacity: 0.85;
}
/* stylelint-disable no-descending-specificity -- cross-component false positive */
:where([data-theme="dark"]) .co-btn-premium {
/* stylelint-enable no-descending-specificity */
    box-shadow: var(--shadow-md);
}

/* Estilos para los inputs del modal envio a un amigo*/
.modal-content label {
	display: block;
	margin-bottom: var(--space-1);
	font-weight: var(--font-bold);
	color: var(--color-text-primary);
}

.modal-content select,
.modal-content input[type="text"],
.modal-content input[type="email"],
.modal-content input[type="number"],
.modal-content input[type="password"],
.modal-content input[type="date"],
.modal-content input[type="datetime-local"],
.modal-content textarea {
	width: 100%;
	padding: var(--space-2) var(--space-3);
	min-height: var(--touch-target-min);
	border: 1px solid var(--color-border-default);
	border-radius: var(--radius-md);
	margin-bottom: var(--space-4);
	font-size: var(--text-base);
	background-color: var(--color-bg-surface);
	color: var(--color-text-primary);
}

.modal-content :where(input[type="text"]:read-only),
.modal-content :where(input[type="email"]:read-only),
.modal-content :where(input[type="number"]:read-only),
.modal-content :where(input[type="password"]:read-only),
.modal-content :where(input[type="date"]:read-only),
.modal-content :where(input[type="datetime-local"]:read-only),
.modal-content :where(textarea:read-only),
.modal-content :where(select:disabled) {
	background-color: var(--color-bg-page);
	color: var(--color-text-muted);
	border-color: var(--color-border-default);
	cursor: not-allowed; /* Cursor para indicar que no se puede editar */
}

/* Estilos para el botón de enviar en el modal */

.modal-content button[type="submit"]:hover {
	background-color: var(--brand-primary-active);
}

/* Estilos para el fondo y el contenido del modal */
.modal {
	position: fixed;
	z-index: var(--z-modal);
	inset: 0;
	overflow: auto;
	background-color: var(--color-overlay);
	padding: calc(var(--header-height) + var(--space-4)) var(--space-4) var(--space-4);
	box-sizing: border-box;
}

.modal-content {
	background-color: var(--color-bg-surface);
	margin: 0 auto;
	padding: var(--space-5);
	border-radius: var(--radius-lg);
	max-width: 640px;
	box-shadow: var(--shadow-md);
	display: flex;
	flex-direction: column;
	width: 100%;
	box-sizing: border-box;
	color: var(--color-text-primary);
	border-color: var(--color-border-default);
}

/* ---------------------------------------------------------------------------
   MODAL-DARK (T156): explicit dark-mode overrides for admin modals
   ---------------------------------------------------------------------------
   Although many tokens already flip via :root [data-theme="dark"], admin
   modals (mainModalHeader.html / mainModalFooter.html and friends) were
   reported as washed-out in dark mode because --color-bg-surface (slate-800)
   has insufficient contrast against --color-overlay (0.65 black) and the
   page background. We promote the modal surface to --color-bg-elevated
   (slate-700) and re-assert text + border tokens so header/body/footer
   sections render consistently. These rules are scoped to [data-theme="dark"]
   and therefore have zero effect on the light theme.

   NOTE (stylelint): the dark overrides below are declared BEFORE the base
   layout rules for narrative reasons (dark-surface fix, then layout).
   Swapping them would break the section's storytelling without changing
   the effective cascade, so this block suppresses no-descending-specificity.
   --------------------------------------------------------------------------- */
/* stylelint-disable no-descending-specificity */
[data-theme="dark"] .modal {
	background-color: var(--color-overlay);
}
[data-theme="dark"] .modal .modal-content {
	background-color: var(--color-bg-elevated);
	color: var(--color-text-primary);
	border: 1px solid var(--color-border-default);
}
[data-theme="dark"] .modal .modal-header,
[data-theme="dark"] .modal .modal-header h2 {
	color: var(--color-text-primary);
	border-color: var(--color-border-default);
}
[data-theme="dark"] .modal .modal-body {
	color: var(--color-text-primary);
	background-color: transparent;
}
[data-theme="dark"] .modal .modal-footer {
	border-top-color: var(--color-border-default);
	color: var(--color-text-primary);
}

/* Modal header layout */
.modal-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}
.modal-header h2 {
  font-size: var(--text-xl);
  font-weight: var(--font-bold);
  color: var(--color-text-primary);
  margin: 0;
  line-height: var(--leading-tight);
}

/* Modal size modifiers — use for content-heavy modals (mass operations, multi-column forms) */
.modal-content--lg {
  max-width: 900px;
}
@media (min-width: 768px) {
  .modal-content--lg {
    min-width: min(700px, 95vw);
  }
}

/* Modal body — scrollable content area */
.modal-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}

/* Modal footer — actions row, right-aligned, wraps on mobile */
.modal-footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
  margin-top: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-border-default);
}
/* stylelint-enable no-descending-specificity */

/* Destructive action (Eliminar) docks to the left of the modal footer
   so it sits away from the primary action. Keeps justify-content
   flex-end intact for the common 1-button case. */
.modal-footer #deleteBtn,
.modal-footer .btn-danger-outline {
  margin-right: auto;
}

/* Modal close button — visible, accessible, 44px touch target */
.close-modal {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: var(--touch-target-min);
  height: var(--touch-target-min);
  min-width: var(--touch-target-min);
  font-size: var(--text-xl);
  font-weight: var(--font-bold);
  line-height: 1;
  color: var(--color-text-muted);
  background: var(--color-bg-elevated);
  border: 1px solid var(--color-border-default);
  border-radius: var(--radius-full);
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
}
.close-modal:hover,
.close-modal:focus-visible {
  color: var(--color-text-primary);
  background: var(--color-bg-page);
  border-color: var(--color-border-strong);
}

@media (max-width: 640px) {
    .modal {
        padding: var(--space-3) var(--space-2);
    }
    .modal-content {
        width: 100%;
        max-width: none;
        max-height: calc(100vh - 1.5rem);
        max-height: calc(100dvh - 1.5rem);
        overflow-y: auto;
    }
}

.modal-form-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-4);
}
.modal-checkbox-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-3);
}
.modal-checkbox-grid label {
    min-height: var(--touch-target-min);
    width: 100%;
    display: inline-flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    cursor: pointer;
}
@media (max-width: 640px) {
    .modal-form-grid,
    .modal-checkbox-grid {
        grid-template-columns: 1fr;
    }
}

/* ── Body scroll lock for open modals ── */
/* Simple overflow:hidden preserves scrollY naturally.
 * Avoids position:fixed + JS body.style.top race that caused scroll jump
 * on modal close (#442 bug 2 + #553). */
body.modal-open {
    overflow: hidden;
}

.login-image {
        background-image: linear-gradient(to bottom,
                        rgba(255, 255, 255, 0.95),
                        var(--color-brand-tint-35),
                        var(--color-brand-tint-66),
                        rgba(3, 105, 161, 0.50)), url('../images/login.jpg');
        background-size: cover;
        background-position: center;
        background-repeat: no-repeat;
        min-height: 100%;
        backdrop-filter: blur(100px);
}
/* ── Login gradient (GAP-1: not extracted to token by 033) ── */
:where([data-theme="dark"]) .login-image {
    background-image: linear-gradient(to bottom,
        rgba(15, 23, 42, 0.95),
        rgba(30, 41, 59, 0.85),
        var(--color-brand-tint-25),
        rgba(15, 23, 42, 0.92)), url('../images/login.jpg');
}

.form-control, .form-select {
    border: 1px solid var(--color-border-default);
    padding: var(--space-1);
    border-radius: var(--radius-sm);
}
/* ── Forms: browser defaults inputs to white bg ── */
:where([data-theme="dark"]) .form-control,
:where([data-theme="dark"]) .form-select {
    background-color: var(--color-bg-surface);
    border-color: var(--color-border-default);
    color: var(--color-text-primary);
}

/* ── Theme Transition Override ──
   Smooth theme transition (applied only during toggle, not on load).
   Must appear AFTER all base component definitions to satisfy
   no-descending-specificity (compound selectors reference bases above). */
:where(html.theme-transitioning),
:where(html.theme-transitioning) > body,
:where(html.theme-transitioning) .card,
/* stylelint-disable no-descending-specificity -- cross-component false positive */
:where(html.theme-transitioning) .btn-primary,
:where(html.theme-transitioning) .btn-ghost,
:where(html.theme-transitioning) .btn-neutral,
/* stylelint-enable no-descending-specificity */
html.theme-transitioning header,
html.theme-transitioning nav,
/* stylelint-disable no-descending-specificity -- cross-component false positive */
:where(html.theme-transitioning) main,
/* stylelint-enable no-descending-specificity */
:where(html.theme-transitioning) .data-table,
:where(html.theme-transitioning) .form-control,
:where(html.theme-transitioning) .form-select {
    transition: background-color var(--transition-base) ease,
                color var(--transition-base) ease,
                border-color var(--transition-base) ease,
                box-shadow var(--transition-base) ease !important; /* stylelint-disable-line declaration-no-important -- force transitions during theme switch */
}

/* Standard form input — WCAG-compliant, token-based, dark-mode ready */
.form-input {
    width: 100%;
    padding: var(--space-2) var(--space-3); /* 8px 12px — ~40px height with text-sm */
    min-height: var(--touch-target-min); /* WCAG touch target */
    font-size: var(--text-sm);
    font-family: inherit;
    color: var(--color-text-primary);
    background-color: var(--color-bg-input);
    border: 1px solid var(--color-border-default);
    border-radius: var(--radius-md);
    transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.form-input:focus-visible {
    border-color: var(--brand-primary);
    box-shadow: 0 0 0 2px var(--brand-focus-ring);
    outline: none; /* override global :focus-visible since we use box-shadow here */
}
.form-input:disabled {
    background-color: var(--color-bg-disabled);
    color: var(--color-text-disabled);
    cursor: not-allowed;
}
.form-input::placeholder {
    color: var(--color-text-placeholder);
}

/* Multiple-select dropdown bottom spacing */
.table-scroll-container {
    margin-bottom: var(--space-4);
}

.triangle-asc:before {
    content: "\25B2";  /* Black up-pointing triangle */
}

.triangle-desc:before {
    content: "\25BC";  /* Black down-pointing triangle */
}

.sortable {
    cursor: pointer;
    user-select: none;
}

.sortable:focus-visible {
    outline: 2px solid var(--brand-primary-dark);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}

.fill-content {
	min-width: 100%; /* fallback */
	min-width: stretch;
}


/* ——— Agrupación “Usuarios” ——— */
.fieldset-users {
  padding: var(--space-4);
  margin-bottom: var(--space-6);
  border: 1px solid var(--color-border-default);
  border-radius: var(--radius-md);
  background-color: var(--color-bg-page);
}

/* Ensure search inputs span the full width of the fieldset */
.fieldset-users input[type="text"] {
  width: 100%;
}

/* ——— Form-check inline ——— */
.form-check {
  display: flex;
  align-items: center;
  gap: var(--space-2);         /* espaciado interno */
  margin-bottom: var(--space-3);
}
.form-check input[type="checkbox"] {
  width: 1.25rem;
  height: 1.25rem;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  accent-color: var(--brand-primary);
  cursor: pointer;
}
.form-check label {
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  color: var(--color-text-secondary);
  cursor: pointer;
  user-select: none;
}
.form-check:where(:hover) label {
  color: var(--color-text-primary);
}

/* Footer responsive container */
.footer-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-between;
}

.footer-container .footer-left,
.footer-container .footer-right {
    float: none;
}

@media (min-width: 640px) {
    .footer-container {
        flex-direction: row;
    }
}

/* T441 follow-up: SSR fallback hide for kpi_card.html .kpi-bubble divs.
 * kpi_card.html renders TWO .kpi-bubble divs: one as a direct child of .kpi-card
 * (data-original-tooltip) and one nested inside .kpi-card__body > [data-kpi-primary]
 * (data-detail-tooltip). A child combinator only hid the first; the second leaked
 * its tooltip text inline (e.g. "Cobros directos sin dispositivo: …" on Tap to Pay).
 * Descendant combinator covers both. The .info-bubble.kpi-bubble-portal in <body>
 * handles the actual surface-on-hover (see dashboard.js KpiToggleManager). */
.kpi-card .kpi-bubble { display: none; }


/* ── Chart Card Tabs ── */
.chart-card__tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  margin-bottom: var(--space-4);
  border-bottom: 1px solid var(--color-border-default);
  padding-bottom: var(--space-3);
}
.chart-card__tab {
  padding: var(--space-1-5) var(--space-3);
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  color: var(--color-text-muted);
  background: none;
  border: 1px solid transparent;
  border-radius: 0;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px; /* overlap parent border-bottom */
  cursor: pointer;
  transition: color var(--transition-fast), border-color var(--transition-fast);
  white-space: nowrap;
}
.chart-card__tab:hover {
  color: var(--color-text-primary);
}
.chart-card__tab--active {
  color: var(--brand-primary-dark);
  border-bottom-color: var(--brand-primary);
  font-weight: var(--font-semibold);
}
.chart-card__panel[hidden] { display: none; }
/* ── Chart tabs dark ── */
:where([data-theme="dark"]) .chart-card__tab--active,
:where([data-theme="dark"]) .chart-card__tab[aria-selected="true"] {
    color: var(--brand-primary);
    border-bottom-color: var(--brand-primary);
}

/* ── Dashboard Export FAB ── */
.dashboard-fab {
  position: fixed;
  bottom: 1.5rem;
  right: 1.5rem;
  z-index: var(--z-sticky);
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--space-2);
}
.dashboard-fab__trigger {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  height: 3rem;
  padding: 0 var(--space-4) 0 var(--space-3);
  border-radius: var(--radius-full);
  background: var(--brand-primary);
  color: var(--color-text-inverse);
  border: none;
  cursor: pointer;
  box-shadow: var(--shadow-brand-sm);
  transition: background var(--transition-base), transform var(--transition-base);
}
.dashboard-fab__label {
  font-size: var(--text-xs);
  font-weight: var(--font-semibold);
  white-space: nowrap;
}
@media (max-width: 480px) {
  .dashboard-fab__trigger { width: 3rem; padding: 0; justify-content: center; }
  .dashboard-fab__label { display: none; }
}
.dashboard-fab__trigger:hover {
  background: var(--brand-primary-dark);
  transform: scale(1.02);
}
.dashboard-fab__trigger--active {
  background: var(--brand-primary-dark);
}
.dashboard-fab__menu {
  display: flex;
  flex-direction: column;
  gap: var(--space-1-5);
  position: absolute;
  bottom: 3.75rem;
  right: 0;
}
.dashboard-fab__menu[hidden] {
  display: none;
}
.dashboard-fab__item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-md);
  font-size: var(--text-xs);
  font-weight: var(--font-medium);
  color: var(--color-text-inverse);
  text-decoration: none;
  white-space: nowrap;
  box-shadow: var(--shadow-sm);
  transition: transform var(--transition-fast), box-shadow var(--transition-fast);
}
.dashboard-fab__item:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-md);
}
.dashboard-fab__item--green {
  background: var(--color-success);
}
.dashboard-fab__item--green:hover {
  background: var(--color-success-hover);
}
.dashboard-fab__item--red {
  background: var(--color-error);
}
.dashboard-fab__item--red:hover {
  background: var(--color-error-hover);
}

/* ═══════════════════════════════════════════════════
   Responsive Mobile Fixes (≤640px)
   ═══════════════════════════════════════════════════ */

/* Dashboard mobile adjustments (KPI, charts, legend, FAB) */
@media (max-width: 640px) {
    .kpi-row { gap: var(--space-2); }

    /* Chart container heights */
    .chart-section-grid .relative.h-48 { height: 12rem; }
    .articulos-chart-wrapper { height: 180px; }

    /* Legend tables — tighter padding and smaller text */
    .chart-legend-table { font-size: var(--text-xs); }
    .chart-legend-table td,
    .chart-legend-table th {
        padding-left: var(--space-1);
        padding-right: var(--space-1);
    }

    /* FAB — tighter position */
    .dashboard-fab {
        bottom: var(--space-3);
        right: var(--space-3);
    }
}

/* 10. Touch targets — WCAG AA minimum 44px (kpi-info-button now 44px globally) */
@media (max-width: 768px) {
    .dashboard-fab__item {
        min-height: var(--touch-target-min);
        padding-top: var(--space-2);
        padding-bottom: var(--space-2);
    }
}

/* ═══════════════════════════════════════════════════════════════════
   Dashboard Filters Panel
   ═══════════════════════════════════════════════════════════════════ */

.dashboard-filters {
    background: var(--color-bg-surface);
    border-radius: var(--radius-lg);
    padding: var(--space-3);
}
@media (min-width: 640px) {
    .dashboard-filters { padding: var(--space-3) var(--space-4); }
}

.dashboard-filters__header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    margin-bottom: var(--space-3);
}
.dashboard-filters__header-left {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
    max-width: 100%;
}
@media (min-width: 640px) {
    .dashboard-filters__header-left { gap: var(--space-3); }
}
.dashboard-filters__grid--dates {
    min-width: 0;
}

.dashboard-filters__reset-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--touch-target-min);
    height: var(--touch-target-min);
    flex-shrink: 0;
    border-radius: var(--radius-sm);
    color: var(--color-text-inverse);
    background: var(--brand-primary);
    transition: background-color var(--transition-fast);
    position: relative;
}
.dashboard-filters__reset-btn svg {
    width: var(--icon-sm);
    height: var(--icon-sm);
}
.dashboard-filters__reset-btn:hover {
    background: var(--brand-primary-hover);
}
@media (min-width: 640px) {
    .dashboard-filters__reset-btn { width: 32px; height: 32px; }
}

.dashboard-filters__export-btn {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    font-size: var(--text-xs);
    font-weight: var(--font-semibold);
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-sm);
    border: 1px solid var(--brand-primary);
    color: var(--brand-primary-dark);
    background: var(--color-bg-surface);
    cursor: pointer;
    transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
    min-height: var(--touch-target-min);
}
@media (min-width: 640px) {
    .dashboard-filters__export-btn { min-height: 2.25rem; }
    .dashboard-filters__compare-select { min-height: 2.25rem; }
}
.dashboard-filters__export-btn:hover {
    background: var(--brand-primary);
    color: var(--color-text-inverse);
}

.dashboard-filters__separator {
    width: 1px;
    align-self: stretch; /* match height of adjacent items instead of fixed px */
    background: var(--color-border-default);
    flex-shrink: 0;
}
@media (max-width: 640px) {
    .dashboard-filters__separator { display: none; }
    .dashboard-filters__label--inline { display: none; }
}
.dashboard-filters__compare-group {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
}
.dashboard-filters__compare-select {
    font-size: var(--text-xs);
    font-weight: var(--font-medium);
    padding: var(--space-1) var(--space-6) var(--space-1) var(--space-2);
    min-height: var(--touch-target-min);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-sm);
    background: var(--color-bg-surface) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E") no-repeat right var(--space-2) center;
    color: var(--color-text-secondary);
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
    transition: border-color var(--transition-fast), color var(--transition-fast), opacity var(--transition-fast);
}
.dashboard-filters__compare-select:hover {
    border-color: var(--brand-primary);
    color: var(--brand-primary-dark);
}
.dashboard-filters__compare-select:focus {
    outline: 2px solid var(--brand-focus-ring);
    outline-offset: 1px;
    border-color: var(--brand-primary);
}
.dashboard-filters__compare-select:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}
@media (max-width: 640px) {
    .dashboard-filters__compare-group {
        width: 100%;
    }
    .dashboard-filters__compare-select {
        flex: 1 1 auto;
        min-width: 0;
    }
}

.dashboard-filters__grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-3);
}
@media (min-width: 640px) {
    .dashboard-filters__grid { grid-template-columns: 1fr 1fr; gap: var(--space-3) var(--space-4); }
}
@media (min-width: 1024px) {
    .dashboard-filters__grid { grid-template-columns: repeat(3, 1fr); }
}
@media (min-width: 1280px) {
    .dashboard-filters__grid { grid-template-columns: repeat(4, 1fr); }
}

.dashboard-filters__label {
    display: block;
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: var(--tracking-wider);
    font-weight: var(--font-medium);
    margin-bottom: 2px;
}

.dashboard-filters__input {
    width: 100%;
    font-size: var(--text-sm);
    color: var(--color-text-primary);
    background-color: var(--color-bg-input);
    border: 1px solid var(--color-border-default);
    border-radius: var(--radius-sm);
    padding: var(--space-1-5) var(--space-2);
    color-scheme: light;
}
:where([data-theme="dark"]) .dashboard-filters__input {
    color-scheme: dark;
}
.dashboard-filters__input:focus {
    border-color: var(--brand-primary);
    outline: none;
    box-shadow: 0 0 0 2px var(--brand-focus-ring);
}

.dashboard-filters__multi-select {
    width: 100%;
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border-default);
    border-radius: var(--radius-sm);
    display: flex;
    align-items: center;
    padding: var(--space-1) var(--space-2);
    min-height: var(--touch-target-min);
}
@media (min-width: 640px) {
    .dashboard-filters__multi-select { min-height: 36px; }
}

.dashboard-filters__multi-select input[type="text"] {
    width: 100%;
    font-size: var(--text-sm);
    padding: 0;
    border: 0;
    background: transparent;
    outline: none;
}
/* .dashboard-filters__multi-select focus — inherited from global :focus-visible */

.dashboard-filters__dropdown {
    position: absolute;
    margin-top: var(--space-1);
    width: 100%;
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border-default);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-md);
    z-index: var(--z-dropdown);
}

.dashboard-filters__dropdown-item {
    padding: var(--space-1-5) var(--space-2);
    border-bottom: 1px solid var(--gray-50);
}
.dashboard-filters__dropdown-item:hover {
    background: var(--gray-50);
}
.dashboard-filters__dropdown-item label {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    width: 100%;
    cursor: pointer;
    font-size: var(--text-sm);
}
.dashboard-filters__dropdown-scroll { max-height: min(200px, 50vh); overflow-y: auto; }
.dashboard-filters__section { margin-top: var(--space-3); }
.dashboard-filters__label--inline { margin-bottom: 0; line-height: 2.25rem; /* match preset button height */ }

/* Top row: two equal buttons side by side on mobile */
.dashboard-filters__top-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-2);
  width: 100%;
}
@media (min-width: 640px) {
  .dashboard-filters__top-row {
    display: contents; /* dissolve wrapper on desktop — children flow normally */
  }
}
/* Presets toggle — mobile only */
.dashboard-filters__presets-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  min-height: var(--touch-target-min);
  padding: var(--space-1) var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--font-medium);
  color: var(--color-text-secondary);
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border-default);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: background-color var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
}
/* Presets container: hidden on mobile, flex on desktop */
.dashboard-filters__presets-container { display: none; align-items: center; }
@media (min-width: 640px) {
  .dashboard-filters__presets-toggle { display: none; }
  .dashboard-filters__presets-container { display: flex; }
}
.dashboard-filters__presets-toggle[aria-expanded="true"] [data-chevron] {
  transform: rotate(180deg);
}
.dashboard-filters__preset-badge {
  font-size: var(--text-xs);
  padding: 0 var(--space-1-5);
  border-radius: var(--radius-full);
  background: var(--brand-primary);
  color: var(--color-text-inverse);
}

/* Dashboard loading states */
@keyframes dashboard-spin {
  to { transform: rotate(360deg); }
}
@keyframes dashboard-pulse {
  0%, 100% { opacity: 0.5; }
  50% { opacity: 1; }
}
.dashboard-loading-blur {
  position: absolute;
  inset: 0;
  background: var(--color-bg-page);
  opacity: 0.7;
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  z-index: var(--z-sticky);
  pointer-events: none;
}
.dashboard-loading-spinner {
  position: absolute;
  inset: 0;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  z-index: calc(var(--z-sticky) + 1);
  pointer-events: none;
}
.dashboard-loading-spinner:not(.hidden) {
  display: flex;
}
.dashboard-spinner__icon {
  width: 2rem;
  height: 2rem;
  color: var(--brand-primary);
  animation: dashboard-spin 0.75s linear infinite;
  will-change: transform;
  filter: drop-shadow(0 0 3px var(--brand-primary-shadow));
}
.dashboard-spinner__track { opacity: 0.15; }
.dashboard-spinner__head { opacity: 0.85; }
.dashboard-spinner__text {
  margin-top: var(--space-3);
  font-size: var(--text-sm);
  font-weight: var(--font-medium);
  color: var(--color-text-secondary);
  animation: dashboard-pulse 1.8s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .dashboard-spinner__icon { animation: none; }
  .dashboard-spinner__text { animation: none; }
}

.dashboard-filters__preset {
    font-size: var(--text-xs);
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-sm);
    border: 1px solid var(--color-border-strong);
    color: var(--color-text-secondary);
    background: var(--color-bg-surface);
    cursor: pointer;
    transition: border-color var(--transition-fast), color var(--transition-fast);
    min-height: var(--touch-target-min);
}
@media (min-width: 640px) {
    .dashboard-filters__preset { min-height: 2.25rem; /* 36px */ }
    .dashboard-filters__toggle { min-height: 2.25rem; }
}
.dashboard-filters__preset:hover {
    border-color: var(--brand-primary);
    color: var(--brand-primary-dark);
}
.dashboard-filters__preset[aria-pressed="true"] {
    background-color: var(--brand-primary);
    border-color: var(--brand-primary);
    color: var(--color-text-inverse);
    font-weight: var(--font-semibold);
    box-shadow: 0 0 0 2px var(--brand-focus-ring);
}

/* ── Event selector (reuses compare-select style) ── */
.dashboard-filters__event-select {
    font-size: var(--text-xs);
    font-weight: var(--font-medium);
    padding: var(--space-1) var(--space-6) var(--space-1) var(--space-2);
    min-height: 2.75rem;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-sm);
    background: var(--color-bg-surface) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E") no-repeat right var(--space-2) center;
    color: var(--color-text-secondary);
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
    transition: border-color var(--transition-fast), color var(--transition-fast);
}
.dashboard-filters__event-select:hover { border-color: var(--brand-primary); color: var(--brand-primary-dark); }
.dashboard-filters__event-select:focus { outline: 2px solid var(--brand-focus-ring); outline-offset: 1px; border-color: var(--brand-primary); }
.dashboard-filters__event-select:disabled { opacity: 0.5; cursor: not-allowed; }
@media (min-width: 640px) {
    /* R1 T422: override declared after base rule (min-height: 2.75rem above)
       so it wins at ≥640px and aligns event-select with __preset / __drawer-trigger. */
    .dashboard-filters__event-select { min-height: 2.25rem; }
}

/* ── Saved preset pills ── */
.dashboard-filters__saved-presets { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.dashboard-filters__preset-pills { display: flex; flex-wrap: wrap; gap: var(--space-1); }
.preset-pill {
    display: inline-flex; align-items: center; gap: var(--space-1);
    padding: var(--space-1) var(--space-2);
    font-size: var(--text-xs); font-weight: var(--font-medium);
    background: var(--color-bg-elevated); color: var(--color-text-secondary);
    border-radius: var(--radius-full); border: 1px solid var(--color-border-default);
    cursor: pointer; transition: background var(--transition-fast), border-color var(--transition-fast);
}
.preset-pill:hover { background: var(--brand-primary-light); border-color: var(--brand-primary); color: var(--brand-primary-dark); }
.preset-pill__delete {
    display: inline-flex; padding: 1px; border-radius: 50%;
    color: var(--color-text-muted); cursor: pointer; transition: color var(--transition-fast);
}
.preset-pill__delete:hover { color: var(--color-error); }
.preset-pill__shared { color: var(--color-text-muted); }

/* ── Preset save modal ── */
.preset-save-modal { position: fixed; inset: 0; z-index: var(--z-modal-backdrop); display: none; align-items: center; justify-content: center; }
.preset-save-modal:not(.hidden) { display: flex; }
.preset-save-modal__backdrop { position: absolute; inset: 0; background: var(--color-overlay); }
.preset-save-modal__content {
    position: relative; z-index: var(--z-modal);
    background: var(--color-bg-surface); border-radius: var(--radius-lg);
    padding: var(--space-6); width: 100%; max-width: 380px;
    box-shadow: var(--shadow-lg);
}

/* ── Dual-pie grid: legend + 2 pies in a row on desktop ── */
.dual-pie-grid {
    --legend-ratio: 0.4286;  /* 1.5 / 3.5 — legend share of available width */
    --legend-gaps: 2;        /* number of column gaps in 3-col mode */
    --legend-squeeze: 1.15;  /* table can be up to 1.15× the container before stacking */
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-4);
    align-items: start;
}
@media (min-width: 768px) {
    .dual-pie-grid {
        grid-template-columns: minmax(220px, 1.5fr) minmax(0, 1fr) minmax(0, 1fr);
    }
    /* JS-driven: legend overflows → move it full-width on top, charts side-by-side */
    .dual-pie-grid--legend-top {
        grid-template-columns: 1fr 1fr;
    }
    .dual-pie-grid--legend-top > .dual-pie-grid__legend {
        grid-column: 1 / -1;
    }
}
.dual-pie-grid__legend {
    min-width: 0;
    overflow: auto;
}
.dual-pie-grid__chart {
    display: flex;
    flex-direction: column;
    align-items: center;
}
.dual-pie-grid__canvas-wrap {
    width: 100%;
    max-width: 260px;
    aspect-ratio: 1;
    /* No position:relative/absolute on canvas — Chart.js responsive mode
       reads this container's dimensions and sizes the canvas internally.
       Forcing canvas size via CSS breaks Chart.js pixel buffer → wrong colors. */
}
.dual-pie-grid__chart-label {
    text-align: center;
    font-size: var(--text-sm);
    font-weight: var(--font-medium);
    color: var(--color-text-secondary);
    margin-bottom: var(--space-3);
}

/* ── Chart toggle buttons (source / metric) ── */
/* Chart toggle pills — state toggles (Unidades/Facturado, Vendidos/Validados) */
.chart-source-toggle,
.chart-metric-toggle {
    font-size: var(--text-xs);
    font-weight: var(--font-medium);
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-full);
    border: 1px solid var(--color-border-strong);
    background: transparent;
    color: var(--color-text-secondary);
    cursor: pointer;
    transition: background-color var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
}
.chart-source-toggle:hover,
.chart-metric-toggle:hover {
    background: var(--color-brand-tint-12);
    border-color: var(--brand-primary);
    color: var(--brand-primary-dark);
}
.chart-source-toggle--validated,
.chart-metric-toggle--revenue {
    background: var(--brand-primary);
    border-color: var(--brand-primary);
    color: var(--color-text-inverse);
    font-weight: var(--font-semibold);
}
.chart-source-toggle--validated:hover,
.chart-metric-toggle--revenue:hover {
    background: var(--brand-primary-dark);
    border-color: var(--brand-primary-dark);
    color: var(--color-text-inverse);
}
/* stylelint-disable no-descending-specificity -- cross-component false positive */
:where([data-theme="dark"]) .chart-source-toggle--validated,
:where([data-theme="dark"]) .chart-metric-toggle--revenue {
/* stylelint-enable no-descending-specificity */
    color: var(--color-text-inverse);
}

.dashboard-filters__toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-1);
    font-size: var(--text-xs);
    font-weight: var(--font-medium);
    color: var(--color-text-inverse);
    background: var(--brand-primary);
    border: 1px solid var(--brand-primary);
    border-radius: var(--radius-md);
    cursor: pointer;
    padding: var(--space-1) var(--space-3);
    transition: background-color var(--transition-fast);
    min-height: var(--touch-target-min);
}
@media (min-width: 640px) {
    .dashboard-filters__toggle { flex-shrink: 0; }
}
.dashboard-filters__toggle:hover {
    background: var(--brand-primary-hover);
}
.dashboard-filters__toggle svg { flex-shrink: 0; }

.dashboard-filters__apply {
    font-size: var(--text-xs);
    font-weight: var(--font-semibold);
    padding: var(--space-1) var(--space-4);
    border-radius: var(--radius-sm);
    background: var(--brand-primary);
    color: var(--color-text-inverse);
    border: none;
    cursor: pointer;
    transition: background-color var(--transition-fast);
    min-height: var(--touch-target-min);
}
@media (min-width: 640px) {
    .dashboard-filters__apply { min-height: 0; }
}
.dashboard-filters__apply:hover { background: var(--brand-primary-hover); }
.dashboard-filters__apply:active { transform: scale(0.97); }

/* Status bar — compact info strip below filter card */
.dashboard-filters__status-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    margin-top: var(--space-2);
    padding: 0 var(--space-1);
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    min-height: 0;
    overflow: hidden;
}
.dashboard-filters__status-left {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
    overflow: hidden;
}
.dashboard-filters__status-left > * { white-space: nowrap; }
.dashboard-filters__status-right {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-shrink: 0;
    white-space: nowrap;
}
.dashboard-filters__refresh-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-1);
    border: none;
    background: transparent;
    color: var(--color-text-muted);
    cursor: pointer;
    border-radius: var(--radius-sm);
    transition: color var(--transition-fast);
}
.dashboard-filters__refresh-btn:hover {
    color: var(--brand-primary-dark);
}
/* ── Live-polling badge (pulsing dot, same pattern as log viewer) ── */
.dashboard-live-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.35em;
    font-size: 0.65rem;
    font-weight: 700;
    color: var(--color-success);
    padding: 0.15em 0.5em;
    background: var(--color-success-bg);
    border: 1px solid var(--color-success-bg);
    border-radius: 3px;
    letter-spacing: 0.05em;
}
:where([data-theme="dark"]) .dashboard-live-badge {
    color: var(--color-success);
    background: var(--color-success-bg);
    border-color: var(--color-success-bg);
}
.dashboard-live-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--color-success);
    flex-shrink: 0;
    animation: dashboard-live-pulse 1.5s ease-in-out infinite;
}
@keyframes dashboard-live-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.25; }
}

/* Polling interval selector */
.dashboard-filters__poll-select {
    font-family: var(--font-body);
    font-size: var(--text-xs);
    padding: var(--space-1) var(--space-5) var(--space-1) var(--space-1-5);
    border: 1px solid var(--color-border-default);
    border-radius: var(--radius-sm);
    background: var(--color-bg-surface);
    color: var(--color-text-muted);
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%239ca3af'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right var(--space-1-5) center;
    min-height: var(--touch-target-min);
    transition: border-color var(--transition-fast), color var(--transition-fast);
}
.dashboard-filters__poll-select:hover {
    border-color: var(--brand-primary);
    color: var(--color-text-primary);
}
.dashboard-filters__poll-select:focus-visible {
    outline: 2px solid var(--brand-focus-ring);
    outline-offset: 2px;
}

.dashboard-filters__tag {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    font-size: var(--text-xs);
    padding: var(--space-1) var(--space-1-5);
    border-radius: var(--radius-sm);
    background: var(--brand-primary-light);
    color: var(--brand-primary-dark);
    line-height: var(--leading-normal);
    max-width: 150px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.dashboard-filters__tag-remove {
    font-size: var(--text-sm);
    line-height: 1;
    color: var(--brand-primary);
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
    flex-shrink: 0;
}
.dashboard-filters__tag-remove:hover { color: var(--brand-primary-dark); }

/* Tooltips for [data-tooltip] elements.
 * Rendering is delegated to a single portal element attached to <body>
 * (see dashboard.js Block 2b) so the tooltip escapes `overflow: hidden`
 * parents (filter drawer panel / body) and all stacking contexts.
 */
[data-tooltip] { cursor: help; }

.data-tooltip-portal {
    position: fixed;
    top: 0;
    left: 0;
    max-width: 260px;
    padding: var(--space-1-5) var(--space-2-5);
    font-size: var(--text-xs);
    font-weight: var(--font-normal);
    line-height: var(--leading-normal);
    color: var(--color-text-inverse);
    background: var(--gray-900);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-md);
    white-space: normal;
    text-transform: none;
    letter-spacing: normal;
    pointer-events: none;
    z-index: var(--z-tooltip);
    animation: fadeInUp var(--dur-fast) ease-out;
}
.data-tooltip-portal[hidden] { display: none; }

/* 11. Legend panel — cap height on small phones */
@media (max-width: 640px) {
    .chart-section-grid__legend-panel {
        max-height: clamp(180px, 40vh, 300px);
    }
}
/* ═══════════════════════════════════════════════════════════════════
   ANIMATIONS & TRANSITIONS UX (tarea 039 Fase 5)
   ═══════════════════════════════════════════════════════════════════ */

/* ── Modal open/close ── */
/* Templates use .modal.hidden (Tailwind display:none toggle).
   When .hidden is removed the modal is visible — animate content only.
   Use --dur-slow (just duration) en lugar de --transition-slow (duración +
   timing-function): el shorthand `animation:` sólo permite UNA timing-function
   y `var(--transition-slow)` expandía a `300ms ease`, dejando la declaración
   con dos functions (`ease` + `cubic-bezier(...)`) → CSS inválido, browser la
   descartaba entera, animation-name caía a `none`. Token convention en línea
   ~385: "animation usa --dur-*, transition usa --transition-*". */
.modal:not(.hidden) .modal-content {
    animation: modalIn var(--dur-slow) cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes modalIn {
    from { opacity: 0; transform: scale(0.96) translateY(6px); }
    to   { opacity: 1; transform: scale(1) translateY(0); }
}

/* ── Page content fade-in ── */
@keyframes fadeInUp {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: translateY(0); }
}
/* Use opacity-only fade for #main to avoid transform creating a containing block
   that breaks position:fixed tooltips inside (KPI bubbles). */
@keyframes fadeInSimple {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* ── Event-card staggered entrance — migrated to .co-stagger-enter (077) ── */
/* Legacy nth-child system removed. Cards now use .co-stagger-enter with
   --card-index custom property via template forloop.counter0. */

/* ── Card hover lift ── */
.kpi-card:hover {
    box-shadow: var(--shadow-lg);
}
:where(html[data-theme="dark"]) .filter-card:hover {
    box-shadow: 0 6px 20px rgba(var(--shadow-color), 0.45);
    border-color: var(--brand-primary);
}
:where(html[data-theme="dark"]) .kpi-card:hover {
    box-shadow: 0 6px 20px rgba(var(--shadow-color), 0.45);
    border-color: var(--brand-primary);
}

/* ── Button press feedback ── */
.btn-primary:active,
.btn-neutral:active,
.btn-danger:active,
.btn-success:active,
.btn-ghost:active,
.btn-danger-outline:active {
    transform: scale(0.97);
}

/* ═══════════════════════════════════════════════════════════════════
   DATA TABLE ENHANCEMENTS (from 032 style unification)
   ═══════════════════════════════════════════════════════════════════ */

/* NOTE: Add class .table-header to <th> elements in data-table templates.
   Base styling (bg, color, font-weight, uppercase, letter-spacing, padding,
   line-height, vertical-align) is provided by .table-header.
   Only overrides that differ from the base are kept here. */
/* stylelint-disable no-descending-specificity -- cross-component false positive */
.data-table thead th {
/* stylelint-enable no-descending-specificity */
    font-size: var(--text-sm);
}

/* Unified column title styling */
.data-table .column-title {
    font-size: var(--text-sm);
    padding: var(--space-1);
    line-height: var(--leading-snug);
}

/* stylelint-disable no-descending-specificity -- cross-component false positive */
.data-table tbody td {
/* stylelint-enable no-descending-specificity */
    padding: var(--space-1-5) var(--space-2);
    font-size: var(--text-sm);
    white-space: nowrap;
}

/* Superuser shortcut: chipId cell becomes a link to CargaOnline (new tab).
   Keep the value visually anchored to the row (no extra color) and surface
   the affordance only on hover/focus so it does not shout on the table. */
.data-table td.chipId .chipId-link {
    color: inherit;
    text-decoration: none;
}
.data-table td.chipId .chipId-link:hover,
.data-table td.chipId .chipId-link:focus-visible {
    color: var(--color-link);
    text-decoration: underline;
    text-underline-offset: 2px;
}

/* Force actions cell to always lay out buttons horizontally */
/* stylelint-disable no-descending-specificity -- cross-component false positive */
.data-table td:last-child {
/* stylelint-enable no-descending-specificity */
    white-space: nowrap;
}

/* ── Clickable rows ── */
/* Clickable rows — only when JS adds [data-href] */
.data-table tbody tr[data-href] {
    cursor: pointer;
}
.data-table tbody tr[data-href]:focus-visible {
    outline: 2px solid var(--brand-primary-dark);
    outline-offset: -2px;
}
.data-table tbody tr.empty-state:hover {
    background: transparent;
}
/* stylelint-disable-next-line no-descending-specificity
   -- empty-state td is lower specificity than .chart-legend-table
   :nth-child patterns at L3758; no effective cascade conflict since
   selectors target disjoint tables. */
.data-table tbody tr.empty-state td {
    border-left: 0;
    border-right: 0;
    color: var(--color-text-secondary);
}
.data-table tbody tr {
    transition: background-color var(--transition-fast);
}

/* ── Hide secondary columns to reduce horizontal scroll ── */

/* Dispositivos: billingPermission, creationDate */
.data-table td.billingPermission,
.data-table th[data-field="billingPermission"],
.data-table .filter-row th:has(> [name="billingPermission"]),
.data-table td.creationDate,
.data-table th[data-field="creationDate"],
.data-table .filter-row th:has(> [name="creationDate"]) {
    display: none;
}

/* Tickets: transactionPoint_validation, responsable_validation */
.data-table td.transactionPoint_validation,
.data-table th[data-field="transactionPoint_validation"],
.data-table .filter-row th:has(> [name="transactionPoint_validation"]),
.data-table td.responsable_validation,
.data-table th[data-field="responsable_validation"],
.data-table .filter-row th:has(> [name="responsable_validation"]) {
    display: none;
}

/* Eventos: creator, permitirMultiplesAccesos, description, limitPerDevice */
.data-table td.creator,
.data-table th[data-field="creator"],
.data-table .filter-row th:has(> [name="creator"]),
.data-table td.permitirMultiplesAccesos,
.data-table th[data-field="permitirMultiplesAccesos"],
.data-table .filter-row th:has(> [name="permitirMultiplesAccesos"]),
.data-table td.description,
.data-table th[data-field="description"],
.data-table .filter-row th:has(> [name="description"]),
.data-table td.limitPerDevice,
.data-table th[data-field="limitPerDevice"],
.data-table .filter-row th:has(> [name="limitPerDevice"]) {
    display: none;
}

/* Transacciones: destinationBrazalet (Chip ID) */
.data-table td.destinationBrazalet,
.data-table th[data-field="destinationBrazalet"],
.data-table .filter-row th:has(> [name="destinationBrazalet"]) {
    display: none;
}

/* Narrow columns con UUID-like content — truncar con tooltip nativo (#688, T431).
   Selector tbody td evita colisión con la regla de visibilidad arriba.
   T431: añadidas .responsable y .ticketId (follow-up #688 — scope original era más amplio). */
.data-table tbody td.chipId,
.data-table tbody td.user,
.data-table tbody td.balance,
.data-table tbody td.transactionPoint,
.data-table tbody td.destinationBrazalet,
.data-table tbody td.responsable,
.data-table tbody td.ticketId {
    padding-inline: var(--space-3);
    max-width: var(--table-cell-max-id);
    overflow: hidden;
    text-overflow: ellipsis;
}

/* ═══════════════════════════════════════════════════════════════════
   SEMANTIC INTERACTION CLASSES (tarea 039 Fase 4)
   Replace Tailwind color classes toggled in JS with semantic alternatives.
   ═══════════════════════════════════════════════════════════════════ */

/* Card selection state (stripePayment, tickets) */
.card-selected {
    background-color: var(--color-brand-tint-12);
    border-color: var(--brand-primary);
    box-shadow: var(--shadow-md);
}

/* Tab active state (CO tickets, stripePayment tabs) */
.tab--active {
    border-color: var(--brand-primary);
    color: var(--brand-primary-dark);
    background-color: var(--color-brand-tint-12);
    font-weight: var(--font-bold);
    border-bottom-width: 2px;
}
:where([data-theme="dark"]) .tab--active {
    color: var(--brand-primary);
}
/* ── CargaOnline header ─────────────────────────────────────────── */
/* 085 HR-03: max-width instead of width so logo can shrink on narrow viewports */
.co-logo { max-width: 96px; min-width: 48px; width: auto; height: auto; }
@media (min-width: 640px) { .co-logo { max-width: 128px; } }

.co-avatar-trigger {
  width: var(--touch-target-min); height: var(--touch-target-min); min-width: var(--touch-target-min);
  border-radius: var(--radius-full);
  background: var(--brand-primary); color: var(--color-text-inverse);
  font-weight: var(--font-semibold); font-size: var(--text-lg);
  border: none; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.co-avatar-icon {
  width: var(--icon-md); height: var(--icon-md);
  color: var(--color-text-inverse);
}

/* T176 F3 — fused capsule for balance + account trigger. Cluster keeps
   both elements visually paired while preserving independent click
   targets (balance → recarga, avatar → menu).

   `overflow: clip visible` keeps horizontal clipping so the rounded
   capsule corners still trim child hover backgrounds, while letting the
   `.co-session-dropdown` (absolute, below the trigger) escape vertically
   instead of being chopped off — restores the account menu functionality
   that regressed after T176 F3 introduced the cluster wrapper. */
.co-header-cluster {
  display: inline-flex; align-items: stretch;
  background: var(--color-bg-elevated);
  border: 1px solid var(--color-border-default);
  border-radius: var(--radius-full);
  overflow: clip visible;
}
.co-header-cluster > .co-header-stat {
  border: 0; background: transparent;
  border-radius: 0;
}
:where([data-theme="dark"]) .co-header-cluster {
  background: var(--color-bg-elevated);
  border-color: var(--color-border-default);
}

.co-avatar-mini {
  width: 32px; height: 32px; min-width: 32px;
  border-radius: var(--radius-full);
  background: var(--brand-primary); color: var(--color-text-inverse);
  font-weight: var(--font-semibold); font-size: var(--text-sm);
  display: inline-flex; align-items: center; justify-content: center;
}

/* stylelint-disable-next-line no-descending-specificity
   -- T176 F3 cluster variant declared earlier via .co-header-cluster >;
   base .co-header-stat ships after but specificity is strictly lower so
   cascade remains correct. */
.co-header-stat {
  display: inline-flex; align-items: center; gap: var(--space-1-5);
  padding: var(--space-1-5) var(--space-3);
  border-radius: var(--radius-full);
  background: var(--color-bg-elevated);
  border: 1px solid var(--color-border-default);
  text-decoration: none; color: var(--color-text-primary);
  font-size: var(--text-sm); font-weight: var(--font-semibold);
  transition: background var(--transition-fast), box-shadow var(--transition-fast);
  white-space: nowrap; min-height: 32px;
}
.co-header-stat:hover {
  background: var(--brand-primary-light);
  box-shadow: var(--shadow-brand-sm);
}
.co-header-stat__value {
  color: var(--brand-primary-dark); font-weight: var(--font-bold);
}
.co-header-stat__label {
  color: var(--color-text-secondary); font-weight: var(--font-medium);
}
:where([data-theme="dark"]) .co-header-stat__value {
  color: var(--brand-primary);
}
:where([data-theme="dark"]) .co-header-stat:hover {
  background: var(--color-brand-tint-10, rgba(51, 190, 255, 0.1));
}
@media (max-width: 639px) {
  .co-header-stat { padding: var(--space-1) var(--space-2); font-size: var(--text-xs); }
  .co-header-stat__label { display: none; }
}

.co-session-dropdown {
  position: absolute; right: 0; top: calc(100% + 4px);
  z-index: var(--z-dropdown); min-width: 220px;
  /* Constrain to viewport so more than 4 items stay reachable on short mobile. */
  max-height: calc(100vh - var(--header-height) - var(--space-4));
  overflow-y: auto;
  background: var(--color-bg-surface); border: 1px solid var(--color-border-default);
  border-radius: var(--radius-lg);
  box-shadow: var(--container-shadow);
  padding: var(--space-2) 0;
  opacity: 0;
  transform: translateY(-4px) scale(0.98);
  transition: opacity var(--transition-fast),
              transform var(--transition-fast),
              visibility var(--transition-fast);
  visibility: hidden;
  pointer-events: none;
}
.co-session-dropdown__item {
  padding: var(--space-2) var(--space-4); display: flex; align-items: center; gap: var(--space-2);
  min-height: var(--touch-target-min);
}
.co-session-dropdown__logout {
  width: 100%; background: none; border: none; cursor: pointer;
  font: inherit; color: inherit; text-align: left;
  padding: var(--space-2) var(--space-4); display: flex; align-items: center;
  min-height: var(--touch-target-min);
  transition: background-color var(--transition-fast);
}
.co-session-dropdown__logout:hover { background: var(--color-bg-page); }
.co-session-dropdown__login {
  display: flex; align-items: center;
  width: 100%;
  padding: var(--space-2) var(--space-4);
  font-weight: var(--font-semibold);
  color: var(--brand-primary-dark);
  background: transparent;
  border: 0;
  text-align: left;
  cursor: pointer;
  text-decoration: none;
  transition: background var(--transition-fast);
  min-height: var(--touch-target-min);
}
:where([data-theme="dark"]) .co-session-dropdown__login { color: var(--brand-primary); }
.co-session-dropdown__login:hover { background: var(--color-bg-page); }
.co-session-dropdown__divider { border-top: 1px solid var(--color-border-default); margin: var(--space-1) 0; }
.co-copy-btn {
  background: none; border: none; cursor: pointer;
  color: var(--color-text-muted); display: inline-flex; align-items: center;
  justify-content: center;
  min-height: var(--touch-target-min); min-width: 44px;
  transition: color var(--transition-fast);
}
.co-copy-btn:hover { color: var(--brand-primary); }
.co-wa-link {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: var(--touch-target-min); min-width: 44px;
  transition: transform var(--transition-fast), color var(--transition-fast);
}
.co-wa-link:hover {
  transform: scale(1.1);
  color: var(--color-success);
}

/* Focus-visible for CargaOnline elements — inherited from global :focus-visible rule */

.co-chip-id-label { font-size: var(--text-xs); color: var(--color-text-secondary); flex: 1; min-width: 0; }
.co-session-dropdown__chip-row { flex-wrap: nowrap; }

/* ═══════════════════════════════════════════════════
   CargaOnline — Landing UX Utilities
   ═══════════════════════════════════════════════════ */

/* Number input spinner hide */
.no-arrow::-webkit-inner-spin-button,
.no-arrow::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin: 0;
}
.no-arrow { -moz-appearance: textfield; }

/* Line clamp for consistent text truncation */
.line-clamp-2 {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* Product card — enhanced for high-value landing pages */
.co-product-card {
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border-default);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    padding: var(--space-5);
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    position: relative;
    transition: box-shadow var(--transition-base), transform var(--transition-base), border-color var(--transition-base);
}
[data-theme="dark"] .co-product-card {
    background: var(--color-bg-elevated);
    border-color: var(--color-border-strong);
}
@media (hover: hover) {
    .co-product-card:hover {
        box-shadow: var(--shadow-md);
        transform: translateY(-2px);
    }
}

/* Price display — prominent */
.co-price {
    font-size: var(--text-2xl);
    font-weight: var(--font-bold);
    color: var(--brand-primary-dark);
}
.co-price-strike {
    font-size: var(--text-sm);
    color: var(--color-text-placeholder);
    text-decoration: line-through;
    margin-right: var(--space-2);
}

/* CTA button — primary purchase action */
.co-cta-primary {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    min-height: 48px;
    padding: var(--space-3) var(--space-6);
    font-size: var(--text-base);
    font-weight: var(--font-semibold);
    color: var(--color-text-inverse);
    background: var(--brand-primary-dark);
    border: none;
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: background var(--transition-fast), box-shadow var(--transition-fast),
                border-color var(--transition-fast), opacity var(--transition-fast),
                transform var(--transition-fast);
    box-shadow: var(--shadow-brand-sm);
}
.co-cta-primary:hover {
    background: var(--brand-primary-hover);
    box-shadow: var(--shadow-brand-lg);
}
.co-cta-primary:disabled {
    background: var(--color-text-placeholder);
    cursor: not-allowed;
    box-shadow: none;
    opacity: 0.7;
}
.co-cta-primary:active:not(:disabled) {
    transform: scale(0.98);
    box-shadow: var(--shadow-sm);
}

/* CTA button — secondary (login, back) */
.co-cta-secondary {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    min-height: 48px;
    padding: var(--space-3) var(--space-6);
    font-size: var(--text-sm);
    font-weight: var(--font-medium);
    color: var(--color-text-primary);
    background: var(--color-bg-surface);
    border: 2px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: background var(--transition-fast), border-color var(--transition-fast),
                box-shadow var(--transition-fast), opacity var(--transition-fast),
                transform var(--transition-fast);
    text-decoration: none;
}
.co-cta-secondary:hover {
    background: var(--color-bg-page);
    border-color: var(--color-text-placeholder);
}
.co-cta-secondary:disabled {
    background: var(--color-bg-disabled);
    border-color: var(--color-border-default);
    color: var(--color-text-disabled);
    cursor: not-allowed;
}
.co-cta-secondary:active:not(:disabled) {
    background: var(--color-bg-disabled);
    transform: scale(0.98);
}

/* Quantity selector — touch-optimized */
.co-qty-selector {
    display: inline-flex;
    align-items: center;
    border: 2px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    overflow: hidden;
}
.co-qty-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: var(--touch-target-min);
    min-height: var(--touch-target-min);
    padding: var(--space-2);
    background: transparent;
    border: none;
    cursor: pointer;
    color: var(--color-text-secondary);
    transition: background var(--transition-fast), box-shadow var(--transition-fast),
                border-color var(--transition-fast), opacity var(--transition-fast),
                transform var(--transition-fast);
}
.co-qty-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}
.co-qty-btn:hover:not(:disabled) {
    background: var(--color-bg-disabled);
}
.co-qty-btn:active:not(:disabled) {
    background: var(--color-border-default);
}
.co-qty-input {
    width: 3rem;
    text-align: center;
    font-size: var(--text-base);
    font-weight: var(--font-semibold);
    border: none;
    background: transparent;
}
.co-qty-input:focus {
    outline: 2px solid var(--brand-primary);
    outline-offset: -2px;
    background: var(--color-bg-page);
}
.co-qty-input:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

/* Badges */
.co-badge {
    display: inline-flex;
    align-items: center;
    padding: var(--space-1) var(--space-2-5);
    font-size: var(--text-xs);
    font-weight: var(--font-bold);
    border-radius: var(--radius-full);
    line-height: var(--leading-tight);
}
.co-badge--savings {
    background: var(--color-success-bg);
    color: var(--color-success);
    opacity: 0;
    animation: fadeInUp var(--dur-slow) ease 200ms forwards;
}
.co-badge--extra {
    background: var(--color-info-bg);
    color: var(--brand-primary-dark);
    opacity: 0;
    animation: fadeInUp var(--dur-slow) ease 200ms forwards;
}
.co-badge--soldout {
    background: var(--color-error-bg);
    color: var(--color-error);
}
.co-badge--low-stock {
    background: var(--color-warn-bg);
    color: var(--color-warn);
    animation: co-pulse-subtle 3s ease-in-out infinite;
}
@keyframes co-pulse-subtle {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.7; }
}

@media (prefers-reduced-motion: reduce) {
    .co-badge--low-stock { animation: none; }
}
.co-badge--cashback {
    background: var(--color-success-bg);
    color: var(--color-success);
    opacity: 0;
    animation: fadeInUp var(--dur-slow) ease 200ms forwards;
}
.co-badge--neutral {
    background: var(--color-bg-elevated);
    color: var(--color-text-secondary);
}
.co-badge--error {
    background: var(--color-error-bg);
    color: var(--color-error);
}
.co-badge--bundle {
    background: var(--color-info-bg);
    color: var(--color-info);
    border: 1px solid var(--color-border-default);
}

/* ── Secondary navigation ── */
.co-secondary-nav {
    position: sticky;
    top: var(--header-height, 56px);
    z-index: var(--z-sticky);
    background: rgba(255, 255, 255, 0.85);
    backdrop-filter: blur(12px) saturate(1.2);
    -webkit-backdrop-filter: blur(12px) saturate(1.2);
    padding: var(--space-1) var(--container-gutter);
    margin-bottom: var(--space-2);
}
:where([data-theme="dark"]) .co-secondary-nav {
    background: rgba(15, 23, 42, 0.85);
}
.co-nav-pills {
    display: flex;
    justify-content: center;
    gap: var(--space-2);
    overflow-x: auto;
    scrollbar-width: none;
    padding: var(--space-2) 0 var(--space-1);
}
.co-nav-pills::-webkit-scrollbar { display: none; }
.co-nav-pill {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-1-5);
    flex: 1;
    max-width: 160px;
    padding: var(--space-2) var(--space-4);
    border-radius: var(--radius-full);
    font-size: var(--text-sm);
    font-weight: var(--font-semibold);
    color: var(--color-text-secondary);
    background: var(--color-bg-surface);
    border: 1px solid var(--color-border-default);
    white-space: nowrap;
    text-decoration: none;
    transition: all var(--transition-fast);
    min-height: 40px;
}
.co-nav-pill:hover {
    color: var(--color-text-primary);
    border-color: var(--color-border-strong);
    background: var(--color-bg-elevated);
}
.co-nav-pill.is-active {
    color: var(--brand-primary-dark);
    background: var(--brand-primary-light);
    border-color: var(--brand-primary);
    font-weight: var(--font-bold);
}
:where([data-theme="dark"]) .co-nav-pill.is-active {
    color: var(--brand-primary);
    background: var(--color-brand-tint-10);
}
.co-nav-pill__icon {
    width: 18px;
    height: 18px;
    flex-shrink: 0;
}
/* Trust section */
.co-trust-bar {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-6);
    padding: var(--space-3) var(--space-4);
    margin-bottom: var(--space-3);
    border-bottom: 1px solid var(--color-border-default);
}
.co-trust-item {
    display: flex;
    align-items: center;
    gap: var(--space-1-5);
    font-size: var(--text-xs);
    font-weight: var(--font-medium, 500);
    color: var(--color-text-secondary);
    opacity: 0;
    animation: fadeInUp var(--transition-base) forwards;
}
.co-trust-item svg {
    width: var(--icon-sm);
    height: var(--icon-sm);
    flex-shrink: 0;
    color: var(--brand-primary);
}

/* Inline price preview */
.co-inline-total {
    font-size: var(--text-lg);
    font-weight: var(--font-bold);
    color: var(--brand-primary-dark);
    transition: color var(--transition-base);
}

/* Balance warning in modal */
.co-balance-warning {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2-5) var(--space-3);
    background: var(--color-warn-bg);
    border: 1px solid var(--color-warn);
    border-radius: var(--radius-md);
    font-size: var(--text-sm);
    color: var(--color-warn-hover);
}
/* stylelint-disable no-descending-specificity -- cross-component false positive */
.co-balance-warning a {
/* stylelint-enable no-descending-specificity */
    color: var(--brand-primary-dark);
    font-weight: var(--font-semibold);
    text-decoration: underline;
}

/* ── .modal--co modifier (T239+T243) ─────────────────────────────────────
   CargaOnline modal family. All templates use .modal.modal--co + .modal-content.
   Differs from admin .modal / .modal-content in three key ways:
     1. Visibility: .is-open toggle (opacity/visibility transition) vs
        .hidden toggle (Tailwind display:none + @keyframes modalIn).
        JS activation: .is-open toggle (not .hidden toggle like admin).
     2. Animation: bidirectional CSS transition (enter + exit) vs
        unidirectional @keyframes (enter only).
     3. Backdrop: overlay IS the backdrop (flex container); admin .modal is
        the scrollable backdrop wrapper.
   .co-modal-close remains as the close-button utility class.
   ──────────────────────────────────────────────────────────────────────── */
/* Close button — shared by all CO modals */
.co-modal-close {
    position: absolute;
    top: var(--space-3);
    right: var(--space-3);
    display: flex;
    align-items: center;
    justify-content: center;
    width: var(--touch-target-min);
    height: var(--touch-target-min);
    border: none;
    background: transparent;
    border-radius: var(--radius-full);
    cursor: pointer;
    color: var(--color-text-muted);
    transition: background var(--transition-fast);
}
.co-modal-close:hover {
    background: var(--color-bg-disabled);
}
.co-modal-close svg {
    width: var(--icon-md);
    height: var(--icon-md);
}
/* Inputs inside CO modal panels: WCAG 44px touch target */
.modal.modal--co .modal-content input:not([type="hidden"]),
.modal.modal--co .modal-content select,
.modal.modal--co .modal-content textarea {
    min-height: var(--touch-target-min);
}
.modal.modal--co {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    /* Override admin's overflow:auto + padding */
    overflow: visible;
    padding: var(--space-4);
    display: flex;
    align-items: center;
    justify-content: center;
    transition: opacity var(--transition-normal) ease,
                visibility var(--transition-normal) ease;
}
.modal.modal--co.is-open {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
}
.modal.modal--co .modal-content {
    /* CO panel dimensions */
    max-width: 480px;
    padding: var(--space-6);
    /* Entry: slide-up + scale (bidirectional) */
    transform: translateY(12px) scale(0.97);
    opacity: 0;
    transition: transform var(--transition-normal) cubic-bezier(0.16, 1, 0.3, 1),
                opacity var(--transition-normal) ease;
    /* Override admin's scroll behaviour — panel handles its own overflow */
    overflow-y: auto;
    max-height: 90vh;
}
.modal.modal--co.is-open .modal-content {
    transform: translateY(0) scale(1);
    opacity: 1;
}
.modal.modal--co .modal-content--wide {
    max-width: 640px;
}
/* CO mobile: bottom-sheet */
@media (max-width: 640px) {
    .modal.modal--co {
        align-items: flex-end;
        padding: 0;
    }
    .modal.modal--co .modal-content {
        border-radius: var(--radius-lg) var(--radius-lg) 0 0;
        max-width: 100%;
        max-height: 85vh;
        padding: var(--space-4);
        transform: translateY(100%);
    }
    .modal.modal--co.is-open .modal-content {
        transform: translateY(0);
    }
}
/* CO tablet — rules merged into the shared tablet block below (line ~6849)
   to avoid fragmenting the min-width:640px media query beyond the quality baseline. */

/* Touch targets — ensure minimum 44px for mobile (WCAG 2.1 AA) */
[role="tab"] {
    min-height: var(--touch-target-min);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

/* ══════════════════════════════════════════════════════════════
   TASK 110 — Unified Toast Notification System
   ══════════════════════════════════════════════════════════════ */

/* ── Container ── */
.toast-container {
    position: fixed;
    z-index: var(--z-toast);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    pointer-events: none;
    max-width: calc(100vw - var(--space-8));
    width: 24rem; /* 384px — comfortable reading width */
}
.toast-container--bottom-center {
    bottom: var(--space-6);
    left: 50%;
    transform: translateX(-50%);
}
/* top-right reserved for future use (control panel, admin) */

/* ── Individual toast ── */
.toast {
    pointer-events: auto;
    display: flex;
    border-radius: var(--radius-lg);
    padding: var(--space-3) var(--space-4);
    box-shadow: var(--shadow-lg);
    animation: toastIn var(--transition-slow) cubic-bezier(0.16, 1, 0.3, 1);
    will-change: transform, opacity;
}
.toast--exiting {
    animation: toastOut var(--dur-base) ease-in forwards;
}

/* ── Type variants ── */
.toast--success {
    background: var(--color-success-bg);
    color: var(--color-success);
    border: 1px solid var(--color-success);
}
.toast--error {
    background: var(--color-error-bg);
    color: var(--color-error);
    border: 1px solid var(--color-error);
}
.toast--warning {
    background: var(--color-warn-bg);
    color: var(--color-warn);
    border: 1px solid var(--color-warn);
}
.toast--info {
    background: var(--color-info-bg);
    color: var(--color-info);
    border: 1px solid var(--color-info);
}

/* ── Inner layout ── */
.toast__body {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    width: 100%;
    font-size: var(--text-sm);
    font-weight: 600;
    line-height: var(--leading-normal);
}
.toast__icon {
    flex-shrink: 0;
    width: 1.25rem;   /* 20px */
    height: 1.25rem;
}
.toast__message {
    flex: 1;
    margin: 0;
    overflow-wrap: break-word;
}
.toast__close {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-1);
    border-radius: var(--radius-sm);
    background: transparent;
    border: none;
    color: currentColor;
    opacity: 0.7;
    cursor: pointer;
    transition: opacity var(--transition-fast);
}
.toast__close:hover,
.toast__close:focus-visible {
    opacity: 1;
}

/* ── Animations ── */
@keyframes toastIn {
    from { transform: translateY(1rem); opacity: 0; }
    to   { transform: translateY(0); opacity: 1; }
}
@keyframes toastOut {
    to { transform: translateY(-0.5rem); opacity: 0; }
}
/* ── Reduced motion ── */
@media (prefers-reduced-motion: reduce) {
    .toast { animation: none; }
    .toast--exiting {
        animation: none;
        opacity: 0;
        transition: opacity var(--transition-fast);
    }
}

/* CTA success variant (e.g., "Pay with card" button) */
.co-cta-success {
    background: var(--color-success);
}
.co-cta-success:hover:not(:disabled) {
    background: var(--color-success-hover);
}

/* Compact variant for "My Bonos" and similar lists */
.co-product-card--compact {
    padding: var(--space-4);
}

/* Shimmer attention animation on CTA buttons (cascading, subtle) */
@keyframes co-shimmer {
    0%   { background-position: -200% 0; }
    100% { background-position: 200% 0; }
}
:is(.co-cta-primary, .co-btn-premium).co-shimmer-active {
    will-change: background-position;
    background-image: linear-gradient(
        110deg,
        transparent 30%,
        rgba(255, 255, 255, 0.12) 42%,
        rgba(255, 255, 255, 0.18) 50%,
        rgba(255, 255, 255, 0.12) 58%,
        transparent 70%
    );
    background-size: 200% 100%;
    animation: co-shimmer 1.6s ease-in-out 1;
}
/* Premium buttons: shimmer overlays the gradient — restore gradient after animation */
.co-btn-premium.co-shimmer-active {
    background-image: linear-gradient(
        110deg,
        transparent 30%,
        rgba(255, 255, 255, 0.15) 42%,
        rgba(255, 255, 255, 0.22) 50%,
        rgba(255, 255, 255, 0.15) 58%,
        transparent 70%
    ), var(--_btn-gradient, none);
}

/* Respect prefers-reduced-motion */
@media (prefers-reduced-motion: reduce) {
    :is(.co-cta-primary, .co-btn-premium).co-shimmer-active {
        animation: none;
        background-image: none;
    }
    .co-btn-premium.co-shimmer-active {
        background-image: var(--_btn-gradient, none);
    }
}

/* ── CargaOnline touch targets (all viewports) ──────────────────────── */
.modal-content .close-modal {
    min-height: var(--touch-target-min);
    min-width: var(--touch-target-min);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

/* Date format toggle: full by default, short on mobile */
.co-date-short { display: none; }

/* ── CargaOnline mobile ───────────────────────────────────── */
@media (max-width: 640px) {
    /* 085 HR-09: keep horizontal on mobile, tighter gap + smaller text; wrap on 320px */
    .co-trust-bar {
        flex-wrap: wrap;
        justify-content: center;
        gap: var(--space-2) var(--space-3);
        padding: var(--space-2) var(--space-3);
    }
    .co-cta-primary,
    .co-cta-secondary {
        min-height: var(--touch-target-min);
        padding: var(--space-2-5) var(--space-4);
        font-size: var(--text-sm);
    }
    .co-qty-selector { min-width: 110px; }
    .co-badge {
        font-size: var(--text-xs);
        padding: var(--space-1) var(--space-2);
    }
    .co-trust-item { font-size: var(--text-xs); min-width: 0; }
    /* 085 HR-04: fixed positioning on mobile for reliable full-width dropdown */
    .co-session-dropdown {
        position: fixed;
        top: var(--header-height, 56px);
        right: var(--space-4);
        left: var(--space-4);
        width: auto;
        min-width: 0;
        max-width: none;
        z-index: var(--z-header); /* above secondary-nav (--z-sticky) */
        border-radius: 0 0 var(--radius-lg) var(--radius-lg);
    }
    /* 085 HR-11: allow wrap on mobile so chip ID + actions don't overflow */
    .co-session-dropdown__chip-row { flex-wrap: wrap; }

    /* C4: Transaction tables — compact for mobile */
    .receipt-table {
        font-size: var(--text-xs);
    }
    .receipt-table td,
    .receipt-table th {
        padding: var(--space-1) var(--space-2);
    }
    .receipt-table .col-secondary {
        display: none;
    }
    .co-date-full { display: none; }
    .co-date-short { display: inline; }

    /* C6: Product cards — reduced padding on mobile */
    .co-product-card {
        padding: var(--space-4);
    }

    /* C6: Price — scale down on mobile */
    .co-price {
        font-size: var(--text-xl);
    }

    /* C6: Preset cards — slightly smaller on mobile */
    .preset-card,
    .ticket-preset-card {
        min-height: 70px;
        padding: var(--space-2);
    }

    /* C6: Orphan card in 2-col grid — span full width */
    #preset-cards > :last-child:nth-child(odd) {
        grid-column: 1 / -1;
    }

    /* C6: Preview grid — tighter on mobile */
    .co-preview-grid {
        grid-template-columns: repeat(auto-fill, minmax(64px, auto));
        gap: var(--space-1-5);
    }
    .co-preview-card {
        padding: var(--space-2);
        min-height: 64px;
    }
}

/* Tablet optimizations */
@media (min-width: 640px) and (max-width: 1023.98px) {
    .co-product-card {
        padding: var(--space-6);
    }
    /* T243 — .modal--co tablet overrides (keep @media count ≤25) */
    .modal.modal--co .modal-content {
        max-width: 520px;
    }
    .modal.modal--co .modal-content--wide {
        max-width: 640px;
    }
}

/* ── CargaOnline tabs ──────────────────────────────────────────────────── */
.co-tab {
    display: block; width: 100%; height: 100%;
    text-align: center; padding: var(--space-2) var(--space-4);
    color: var(--color-text-secondary);
    transition: color var(--transition-fast), background var(--transition-fast);
}
.co-tab:hover {
    color: var(--brand-primary-dark);
}
:where([data-theme="dark"]) .co-tab:hover {
    color: var(--brand-primary);
}

/* ═══════════════════════════════════════════════════════════════════════════
   CO MICRO-ANIMATIONS & VISUAL POLISH (tarea 077)
   ───────────────────────────────────────────────────────────────────────────
   CSS-only additions. All durations use design tokens. All animations respect
   prefers-reduced-motion via the global override at :root (L887-900).
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── A01: Staggered card entrance (unified system) ── */
.co-stagger-enter {
    opacity: 0;
    transform: translateY(8px);
    animation: fadeInUp var(--transition-slow) forwards;
    animation-delay: calc(min(var(--card-index, 0), 8) * 60ms);
}

/* ── A03: Trust bar item stagger ── */
.co-trust-item:nth-child(1) { animation-delay: 80ms; }
.co-trust-item:nth-child(2) { animation-delay: 160ms; }
.co-trust-item:nth-child(3) { animation-delay: 240ms; }

/* ── D01: Total pulse on value change ── */
@keyframes totalPulse {
    50% { transform: scale(1.08); color: var(--color-success); }
}
.co-inline-total.is-updating {
    animation: totalPulse var(--dur-slow) ease;
}

/* ── D02: Cart badge pop-in and bounce ── */
@keyframes badgePopIn {
    from { transform: scale(0); opacity: 0; }
    to   { transform: scale(1); opacity: 1; }
}
@keyframes badgeBounce {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-3px); }
}
.card-badge.is-appearing {
    animation: badgePopIn var(--dur-base) cubic-bezier(0.34, 1.56, 0.64, 1);
}
.card-badge.is-incrementing {
    animation: badgeBounce var(--dur-base) ease-out;
    will-change: transform;
}

/* ── D03: (Removed — purchase toast now via unified toast service, Task 110) ── */

/* ── D04: (Removed — alerts now via unified toast service, Task 110) ── */

/* ── D05: Limit flash improved exit ── */
@keyframes limitFlashOut {
    0%, 80% { opacity: 1; transform: translateY(0); }
    100%    { opacity: 0; transform: translateY(-4px); }
}
.limit-flash {
    animation: limitFlashOut 1200ms ease-out forwards;
}

/* ── D06: Copy checkmark pop-in ── */
.co-check-icon:not(.hidden) {
    animation: badgePopIn var(--dur-base) cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* ── D07: Bonus message entrance ── */
#bonus-message:not(.hidden) {
    animation: fadeInUp var(--dur-base) ease-out;
}

/* ── D08: Balance warning entrance ── */
.co-balance-warning:not(.hidden) {
    animation: fadeInUp var(--dur-base) ease-out;
}

/* ── D10: Page fade-out before navigation ── */
@keyframes pageFadeOut {
    to { opacity: 0.4; filter: blur(2px); }
}
body.is-navigating #main {
    animation: pageFadeOut var(--dur-slow) ease forwards;
    pointer-events: none;
}

/* ── D11: Empty state fade-in ── */
#noEventsMessage:not(.hidden) {
    animation: fadeInUp var(--dur-base) ease-out;
}

/* ── B02: Tab panel crossfade ── */
.co-tab-panel {
    opacity: 0;
    transform: translateY(4px);
    transition: opacity var(--transition-base), transform var(--transition-base);
    pointer-events: none;
    position: absolute;
    visibility: hidden;
    width: 100%;
}
.co-tab-panel.is-active {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
    position: relative;
    visibility: visible;
}

/* ── B05: Description expand/collapse ── */
.co-description-clamp {
    overflow: hidden;
    display: -webkit-box;
    /* stylelint-disable-next-line property-no-deprecated -- required for -webkit-line-clamp */
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    max-height: 3.2em;
    transition: max-height var(--transition-slow);
}
.co-description-clamp.is-expanded {
    display: block;
    -webkit-line-clamp: unset;
    /* stylelint-disable-next-line property-no-deprecated -- reset for expanded state */
    -webkit-box-orient: initial;
    max-height: 20em;
    overflow: visible;
}

/* ── B06: Accordion expand + arrow rotation ── */
.co-accordion-arrow {
    transition: transform var(--transition-fast);
}
.co-accordion-arrow.is-open {
    transform: rotate(180deg);
}
.co-accordion-body {
    max-height: 0;
    overflow: hidden;
    transition: max-height var(--transition-slow);
}
.co-accordion-body.is-open {
    max-height: 2000px;
}

/* ── C03: Session dropdown fade + slide ── */
.co-session-dropdown.is-open {
    opacity: 1;
    transform: translateY(0) scale(1);
    visibility: visible;
    pointer-events: auto;
}

/* ── C04: Language dropdown fade ── */
.lang-dropdown {
    opacity: 0;
    transform: translateY(-4px);
    transition: opacity var(--transition-fast),
                transform var(--transition-fast),
                visibility var(--transition-fast);
    visibility: hidden;
    pointer-events: none;
}
.lang-dropdown.is-open {
    opacity: 1;
    transform: translateY(0);
    visibility: visible;
    pointer-events: auto;
}

/* ── E05: Search form slide-down ── */
.co-search-form {
    max-height: 0;
    overflow: hidden;
    transition: max-height var(--transition-slow);
}
.co-search-form.is-open {
    max-height: 250px;
    overflow-y: auto;
}
@media (min-width: 768px) {
    /* Higher specificity to override mobile .co-search-form collapse without !important */
    .co-search-form,
    .co-search-form.is-open {
        display: block;
        max-height: none;
        opacity: 1;
        overflow: visible;
    }
}

/* ── B04: Sold-out / maxed card smooth transition ── */
/* Base transition for .ticket-preset-card is in B01 above (superset). */
.ticket-preset-card[data-js-maxed="true"] {
    opacity: 0.6;
    filter: grayscale(40%);
}

/* ── B07: Filter cards fade in/out ── */
.ticket-card {
    transition: opacity var(--transition-base), transform var(--transition-base);
}
.ticket-card.is-filtered-out {
    opacity: 0;
    transform: scale(0.95);
    pointer-events: none;
}

/* ── E03: Focus-visible smooth outline transition ── */
:is(.co-cta-primary, .co-cta-secondary, .co-qty-btn, .co-tab,
    .co-modal-close, .co-copy-btn):focus-visible {
    outline-offset: 4px;
    transition: outline-offset var(--transition-fast);
}

/* ── E04: Input validation glow ── */
.manual-amount-input.is-invalid {
    border-color: var(--color-error);
    box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.1);
}
.manual-amount-input.is-valid {
    border-color: var(--color-success);
    box-shadow: 0 0 0 3px rgba(22, 163, 74, 0.1);
}

/* ── B01: Card selection — smooth transition on preset/ticket cards ── */
.preset-card,
.ticket-preset-card {
    transition: border-color var(--transition-fast),
                background-color var(--transition-fast),
                box-shadow var(--transition-fast),
                transform var(--transition-fast),
                opacity var(--transition-base),
                filter var(--transition-base);
}

/* ── E01: Product card hover glow (extends existing hover with brand border) ── */
@media (hover: hover) {
    .co-product-card:hover {
        border-color: var(--brand-primary-light);
        box-shadow: var(--shadow-md), var(--shadow-brand-sm);
    }
}

/* ── F01: Safety net — prefers-reduced-motion (defense in depth) ──
   Redundant with global :root override (L887-900) but explicit for
   documentation and belt-and-suspenders safety. */
@media (prefers-reduced-motion: reduce) {
    .co-stagger-enter,
    .co-badge--savings,
    .co-badge--cashback,
    .co-badge--extra,
    .co-trust-item {
        animation: none;
        opacity: 1;
        transform: none;
    }
    .co-inline-total.is-updating,
    .card-badge.is-appearing,
    .card-badge.is-incrementing,
    .limit-flash,
    .co-check-icon:not(.hidden),
    #bonus-message:not(.hidden),
    .co-balance-warning:not(.hidden),
    #noEventsMessage:not(.hidden) {
        animation: none;
    }
    body.is-navigating #main {
        animation: none;
        opacity: 1;
        filter: none;
    }
    .co-tab-panel {
        transition: none;
        position: relative;
        visibility: visible;
        opacity: 1;
        transform: none;
    }
    .co-tab-panel:not(.is-active) {
        display: none;
    }
    .co-description-clamp,
    .co-accordion-body,
    .co-accordion-arrow,
    .co-search-form,
    .co-session-dropdown,
    .lang-dropdown,
    .preset-card,
    .ticket-preset-card,
    .ticket-card,
    .co-cta-primary,
    .co-cta-secondary,
    .co-qty-btn,
    .manual-amount-input {
        transition: none;
    }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Custom Class Variant Fallbacks
   ───────────────────────────────────────────────────────────────────────────
   Tailwind v3.4 JIT compiles all standard utility variants (sm:*, focus:*,
   group-hover:*, etc.). However, variants of CUSTOM classes defined in
   main.css (bg-surface, text-primary, etc.) are NOT compiled by Tailwind
   because they aren't Tailwind utilities. These fallbacks are necessary.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Custom class variants (Tailwind can't generate these) ── */
.odd\:bg-surface:nth-child(odd) { background-color: var(--color-bg-surface); }
.even\:bg-page:nth-child(even) { background-color: var(--color-bg-page); }
.focus\:bg-surface:focus { background-color: var(--color-bg-surface); }
.focus\:text-primary:focus { color: var(--color-text-primary); }
.focus\:rounded:focus { border-radius: var(--radius-sm); }
.focus\:shadow-lg:focus { box-shadow: var(--shadow-lg); }
.focus-within\:text-info:focus-within { color: var(--color-info); }

/* ═══════════════════════════════════════════════════════════════════════════
   CO GLASS & GRADIENT SYSTEM (tarea 095)
   ───────────────────────────────────────────────────────────────────────────
   Layered depth system: gradient mesh bg → glass panel → cards → header.
   CSS-only, 0 JS. Respects prefers-reduced-motion, dark mode, @supports.
   ═══════════════════════════════════════════════════════════════════════════ */

.co-gradient-mesh {
    position: fixed;
    inset: 0;
    z-index: -1; /* fondo decorativo, intencional */
    pointer-events: none;
    background:
        radial-gradient(ellipse at 20% 50%, rgba(51, 190, 255, 0.08) 0%, transparent 50%),
        radial-gradient(ellipse at 80% 20%, rgba(147, 51, 234, 0.06) 0%, transparent 50%),
        radial-gradient(ellipse at 50% 80%, rgba(34, 197, 94, 0.05) 0%, transparent 50%),
        var(--color-bg-page);
}
:where([data-theme="dark"]) .co-gradient-mesh {
    background:
        radial-gradient(ellipse at 20% 50%, rgba(51, 190, 255, 0.12) 0%, transparent 50%),
        radial-gradient(ellipse at 80% 20%, rgba(147, 51, 234, 0.10) 0%, transparent 50%),
        radial-gradient(ellipse at 50% 80%, rgba(34, 197, 94, 0.06) 0%, transparent 50%),
        var(--color-bg-page);
}

@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
    .co-glass-panel {
        background: rgba(255, 255, 255, 0.88);
        backdrop-filter: blur(20px) saturate(1.2);
        -webkit-backdrop-filter: blur(20px) saturate(1.2);
        border: none;
        border-radius: 0 0 var(--radius-xl) var(--radius-xl);
        box-shadow: var(--shadow-sm);
        padding: var(--space-3) var(--space-4) var(--space-6);
    }
    :where([data-theme="dark"]) .co-glass-panel {
        background: rgba(30, 41, 59, 0.88);
        box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
    }
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .co-glass-panel {
        background: var(--color-bg-surface);
        border: none;
        border-radius: 0 0 var(--radius-xl) var(--radius-xl);
        box-shadow: var(--shadow-sm);
        padding: var(--space-3) var(--space-4) var(--space-6);
    }
}

.header-sticky.co-header--transparent {
    background: transparent;
    box-shadow: none;
    transition: background var(--transition-slow), box-shadow var(--transition-slow), backdrop-filter var(--transition-slow);
}
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
    .header-sticky.co-header--transparent.is-scrolled {
        background: rgba(255, 255, 255, 0.82);
        backdrop-filter: blur(16px) saturate(1.3);
        -webkit-backdrop-filter: blur(16px) saturate(1.3);
        box-shadow: var(--shadow-sm);
    }
    :where([data-theme="dark"]) .header-sticky.co-header--transparent.is-scrolled {
        background: rgba(15, 23, 42, 0.82);
        box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
    }
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .header-sticky.co-header--transparent.is-scrolled {
        background: var(--color-bg-surface);
        box-shadow: var(--shadow-sm);
    }
}

.preset-card[data-count]:not([data-count="0"]) {
    border-color: var(--brand-primary);
    box-shadow: 0 0 0 3px rgba(51, 190, 255, 0.25), var(--shadow-md);
    transform: translateY(-2px);
}
:where([data-theme="dark"]) .preset-card[data-count]:not([data-count="0"]) {
    box-shadow: 0 0 0 3px rgba(51, 190, 255, 0.35), var(--shadow-md);
}

/* T206: card-badge / card-minus visibility derives from data-count.
   Reserves the 44×44 touch area (set by .card-minus::before) so that
   toggling does not change card width — keeps Cumulative Layout Shift
   at zero on mobile. visibility:hidden also removes the element from
   the tab order, equivalent to display:none for keyboard nav. */
.preset-card .card-badge,
.preset-card .card-minus,
.ticket-preset-card .card-badge,
.ticket-preset-card .card-minus {
    visibility: hidden;
    opacity: 0;
    transition: opacity var(--transition-fast);
}
.preset-card[data-count]:not([data-count="0"]) .card-badge,
.preset-card[data-count]:not([data-count="0"]) .card-minus,
.ticket-preset-card[data-count]:not([data-count="0"]) .card-badge,
.ticket-preset-card[data-count]:not([data-count="0"]) .card-minus {
    visibility: visible;
    opacity: 1;
}

@media (hover: hover) {
    .co-product-card {
        transition: transform var(--transition-base), box-shadow var(--transition-base), border-color var(--transition-base);
    }
    .co-product-card:hover {
        transform: translateY(-4px);
        box-shadow: var(--shadow-md);
        border-color: var(--brand-primary-light);
    }
    :where([data-theme="dark"]) .co-product-card:hover {
        box-shadow: 0 12px 24px rgba(0, 0, 0, 0.25);
    }
}

body.is-navigating .co-glass-panel {
    opacity: 0;
    transform: translateY(4px);
    transition: opacity 120ms ease-out, transform 120ms ease-out;
}

.co-product-card--sold-out,
.ticket-preset-card--sold-out {
    opacity: 0.55;
    filter: grayscale(0.4);
    cursor: not-allowed;
    transition: opacity var(--transition-base), filter var(--transition-base);
}
.co-product-card--sold-out:hover,
.ticket-preset-card--sold-out:hover {
    opacity: 0.75;
    filter: grayscale(0.2);
}

/* T207 B8 — Card maxed (cart already at max selectable). Replaces inline
   `style.opacity/cursor`, Tailwind `opacity-60 cursor-not-allowed`, and
   server-side inline `style="cursor: not-allowed;"` with a single token-driven
   class shared by recharge.js, stock-polling.js, and `_ticket_preset_cards.html`. */
.co-product-card--maxed,
.preset-card--maxed,
.ticket-preset-card--maxed {
    opacity: 0.6;
    cursor: not-allowed;
    transition: opacity var(--transition-base);
}

/* T208 A3 — Exhausted card (per-user 100% consumido). N4: border-left para indicador visual claro. */
.co-product-card--exhausted { opacity: 0.7; border-left: 3px solid var(--color-error); transition: opacity var(--transition-base); }
[data-theme="dark"] .co-product-card--exhausted { border-left-color: var(--color-error); }

.co-product-card > :last-child {
    margin-top: auto;
}

@media (prefers-reduced-motion: reduce) {
    .co-gradient-mesh { background: var(--color-bg-page); }
    .header-sticky.co-header--transparent { transition: none; }
    .preset-card { transition: none; }
    .co-product-card { transition: none; }
    body.is-navigating .co-glass-panel { transition: none; opacity: 1; transform: none; }
    .co-product-card--sold-out { transition: none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   Chatbot Widget (Felix)
   ───────────────────────────────────────────────────────────────────────────
   Migrated from inline <style> to main.css. Tokens for colors, shadows,
   transitions, radii. Fixed sizes (avatar, panel width) kept as px.
   ═══════════════════════════════════════════════════════════════════════════ */

#chatbot-widget {
  position: fixed;
  bottom: var(--space-6);
  right: var(--space-6);
  z-index: var(--z-chatbot);
  font-family: inherit;
}

#chatbot-widget.chatbot-widget--raised {
  bottom: 90px;
}

/* T441 H5: sidebar overlay (z-index:450) must cover chatbot (z-index:475) when open.
   Uses :has() (Chrome 105+/Safari 15.4+/Firefox 121+). Class confirmed in common.js:102,112,127. */
body:has(.sidebar--open) #chatbot-widget {
  z-index: var(--z-base);
}

.chatbot-toggle {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: var(--brand-primary);
  color: var(--color-text-inverse);
  border: none;
  cursor: pointer;
  box-shadow: var(--shadow-brand-sm);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--transition-fast), box-shadow var(--transition-fast), transform var(--transition-fast);
}
.chatbot-toggle:hover {
  background: var(--brand-primary-dark);
  box-shadow: var(--shadow-brand-lg);
}
.chatbot-toggle:focus-visible {
  outline: 2px solid var(--brand-primary);
  outline-offset: 2px;
}

.chatbot-panel {
  display: none;
  position: absolute;
  bottom: 60px;
  right: 0;
  max-width: min(340px, calc(100vw - 48px));
  width: 340px;
  background: var(--color-bg-surface);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  flex-direction: column;
  border: 1px solid var(--color-border-default);
  animation: chatbotSlideUp var(--dur-base) ease;
}

.chatbot-header {
  background: var(--brand-primary);
  padding: var(--space-3) var(--space-4);
  display: flex;
  align-items: center;
  gap: var(--space-2-5);
}

.chatbot-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--color-white-22);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  font-size: var(--text-base);
  line-height: 1;
}

.chatbot-avatar--sm {
  width: 26px;
  height: 26px;
  background: var(--brand-primary);
  font-size: var(--text-sm);
  margin-top: 2px;
}

.chatbot-header-title {
  color: var(--color-text-inverse);
  font-weight: var(--font-semibold);
  font-size: var(--text-sm);
  line-height: var(--leading-tight);
}

.chatbot-header-badge {
  background: var(--color-white-22);
  color: var(--color-text-inverse);
  font-size: var(--text-3xs);
  font-weight: var(--font-bold);
  letter-spacing: var(--tracking-wider);
  padding: 1px var(--space-1-5);
  border-radius: var(--radius-full);
  text-transform: uppercase;
  line-height: var(--leading-relaxed);
}

.chatbot-header-sub {
  color: var(--color-white-80);
  font-size: var(--text-2xs);
}

.chatbot-close {
  margin-left: auto;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--color-white-80);
  padding: var(--space-1);
  border-radius: var(--radius-sm);
  display: flex;
  min-width: var(--touch-target-min);
  min-height: var(--touch-target-min);
  align-items: center;
  justify-content: center;
}
.chatbot-close:hover { color: var(--color-text-inverse); }
.chatbot-close:focus-visible {
  outline: 2px solid var(--color-text-inverse);
  outline-offset: 2px;
}

.chatbot-messages {
  min-height: 200px;
  max-height: 50vh;
  overflow-y: auto;
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-2-5);
  background: var(--color-bg-page);
}

.chatbot-bubble-user {
  background: var(--brand-primary);
  color: var(--color-text-inverse);
  border-radius: var(--radius-lg) var(--radius-sm) var(--radius-lg) var(--radius-lg);
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-xs);
  line-height: var(--leading-normal);
  max-width: 80%;
  box-shadow: var(--shadow-brand-sm);
}

.chatbot-bubble-bot {
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border-default);
  border-radius: var(--radius-sm) var(--radius-lg) var(--radius-lg) var(--radius-sm);
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-xs);
  color: var(--color-text-primary);
  line-height: var(--leading-normal);
  max-width: calc(100% - 38px);
  box-shadow: var(--shadow-xs);
}

.chatbot-suggestions {
  padding: var(--space-2) var(--space-3);
  border-top: 1px solid var(--color-border-default);
  display: flex;
  gap: var(--space-1-5);
  flex-wrap: wrap;
  background: var(--color-bg-surface);
}

.cb-suggestion {
  font-size: var(--text-2xs);
  padding: var(--space-1) var(--space-2-5);
  border-radius: var(--radius-sm);
  border: 1px solid var(--brand-primary);
  background: var(--color-bg-surface);
  color: var(--brand-primary);
  cursor: pointer;
  transition: all var(--transition-fast);
}
.cb-suggestion:hover {
  background: var(--brand-primary);
  color: var(--color-text-inverse);
}
.cb-suggestion:focus-visible {
  outline: 2px solid var(--brand-primary);
  outline-offset: 2px;
}

.chatbot-input-area {
  padding: var(--space-2-5) var(--space-3);
  border-top: 1px solid var(--color-border-default);
  background: var(--color-bg-surface);
  display: flex;
  gap: var(--space-2);
  align-items: flex-end;
}

.chatbot-textarea {
  flex: 1;
  resize: none;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-xs);
  color: var(--color-text-primary);
  line-height: var(--leading-normal);
  max-height: 80px;
  overflow-y: auto;
  font-family: inherit;
  background: var(--color-bg-page);
  transition: border-color var(--transition-fast), background var(--transition-fast);
}
.chatbot-textarea:focus-visible {
  border-color: var(--brand-primary);
  background: var(--color-bg-surface);
  outline: 2px solid var(--brand-focus-ring);
  outline-offset: -2px;
}

.chatbot-send {
  min-width: var(--touch-target-min);
  min-height: var(--touch-target-min);
  border-radius: var(--radius-sm);
  flex-shrink: 0;
  background: var(--brand-primary);
  color: var(--color-text-inverse);
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background var(--transition-fast);
}
.chatbot-send:hover { background: var(--brand-primary-dark); }
.chatbot-send:focus-visible {
  outline: 2px solid var(--brand-primary);
  outline-offset: 2px;
}

@keyframes chatbotSlideUp {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
.chatbot-messages::-webkit-scrollbar { width: 4px; }
.chatbot-messages::-webkit-scrollbar-track { background: transparent; }
.chatbot-messages::-webkit-scrollbar-thumb { background: var(--color-border-strong); border-radius: var(--radius-sm); }

.cb-msg-user { display: flex; justify-content: flex-end; }
.cb-msg-bot  { display: flex; gap: var(--space-2); align-items: flex-start; }

.cb-typing-dot {
  width: 6px; height: 6px; border-radius: 50%; background: var(--color-text-muted);
  animation: cbBounce 1.2s infinite ease-in-out; display: inline-block;
}
.cb-typing-dot:nth-child(2) { animation-delay: .2s; }
.cb-typing-dot:nth-child(3) { animation-delay: .4s; }
@keyframes cbBounce {
  0%, 80%, 100% { transform: translateY(0); opacity: .5; }
  40% { transform: translateY(-4px); opacity: 1; }
}

.cb-feedback-row {
  display: flex; gap: var(--space-1-5); align-items: center; margin-top: var(--space-1-5); justify-content: flex-end;
}
.cb-feedback-row > span {
  font-size: var(--text-2xs); color: var(--color-text-muted);
}
.cb-feedback-btn {
  background: none; border: 1px solid var(--color-border-default); border-radius: var(--radius-sm);
  cursor: pointer; padding: 2px var(--space-2); font-size: var(--text-xs); color: var(--color-text-muted);
  transition: all var(--transition-fast);
}
.cb-feedback-btn:hover { border-color: var(--brand-primary); color: var(--brand-primary); }
.cb-feedback-btn:focus-visible { outline: 2px solid var(--brand-primary); outline-offset: 1px; }
.cb-feedback-btn.active { border-color: var(--brand-primary); color: var(--brand-primary); background: var(--brand-primary-light); }

.cb-source-tag {
  display: inline-block; background: var(--color-bg-elevated); border: 1px solid var(--color-border-default);
  border-radius: var(--radius-sm); padding: 1px var(--space-1-5); font-size: var(--text-2xs); color: var(--color-text-secondary);
  margin-top: var(--space-1); margin-right: var(--space-1);
}

.cb-sources { margin-top: var(--space-1); }
.cb-typing-content { display: flex; gap: var(--space-1); align-items: center; }

.cb-md h1 { font-size: var(--text-base); font-weight: var(--font-bold); margin: var(--space-2) 0 var(--space-1); line-height: var(--leading-snug); }
/* stylelint-disable-next-line no-descending-specificity
   -- chatbot markdown h2 ships after the dark-mode modal header override;
   selectors target disjoint surfaces (chatbot vs modal) so there is no
   effective cascade conflict. */
.cb-md h2 { font-size: var(--text-sm); font-weight: var(--font-bold); margin: var(--space-2) 0 var(--space-1); line-height: var(--leading-snug); }
.cb-md h3 { font-size: var(--text-sm); font-weight: var(--font-bold); margin: var(--space-1-5) 0 2px; line-height: var(--leading-snug); }
.cb-md ul { margin: var(--space-1) 0; padding-left: var(--space-5); list-style-type: disc; }
.cb-md ol { margin: var(--space-1) 0; padding-left: var(--space-5); list-style-type: decimal; }
.cb-md li { margin: 2px 0; }
.cb-md code { background: var(--color-bg-elevated); padding: 1px var(--space-1); border-radius: var(--radius-sm); font-size: var(--text-xs); font-family: 'Courier New', monospace; }
.cb-md pre { background: var(--color-bg-elevated); border-radius: var(--radius-sm); padding: var(--space-2) var(--space-2-5); font-size: var(--text-xs); overflow-x: auto; font-family: 'Courier New', monospace; margin: var(--space-1-5) 0; white-space: pre-wrap; }
.cb-md pre code { background: none; padding: 0; font-size: inherit; }
.cb-md hr { border: none; border-top: 1px solid var(--color-border-default); margin: var(--space-2) 0; }

/* ── P2P QR Transfer ──────────────────────────────────────── */
.co-btn-premium--recibir { --_btn-gradient: var(--gradient-btn-recibir); }
.p2p-state.hidden { display: none; }
#p2pQrReader { border-radius: var(--radius-lg); overflow: hidden; min-height: 200px; }
#p2pQrReader video { width: 100%; border-radius: var(--radius-lg); }

/* ══════════════════════════════════════════════════════════════
   TASK 108 — Micro-interactions & wow animations
   ══════════════════════════════════════════════════════════════ */

/* ── Toast exit animation ── */
@keyframes slideOutUp {
    to { transform: translateY(-100%); opacity: 0; }
}
.status-message.is-exiting {
    animation: slideOutUp var(--transition-slow) ease-in forwards;
}

/* ── Form error shake ── */
@keyframes shake {
    0%, 100% { transform: translateX(0); }
    25% { transform: translateX(-4px); }
    75% { transform: translateX(4px); }
}
.input-error-shake {
    animation: shake var(--transition-base) ease-in-out;
}

/* ── Button hover lift ── */
.btn-primary:hover:not(:disabled),
.btn-success:hover:not(:disabled),
.btn-danger:hover:not(:disabled) {
    transform: translateY(-1px);
    box-shadow: var(--shadow-md);
}

/* ── Payment success celebration ── */
@keyframes co-checkmark-scale {
    0%   { transform: scale(0) rotate(-45deg); opacity: 0; }
    50%  { transform: scale(1.1) rotate(0deg); }
    100% { transform: scale(1) rotate(0deg); opacity: 1; }
}
.co-success-checkmark {
    animation: co-checkmark-scale 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}

@keyframes co-confetti-fall {
    0%   { transform: translateY(0) rotate(0deg); opacity: 1; }
    100% { transform: translateY(120px) rotate(360deg); opacity: 0; }
}
.co-confetti-container { position: fixed; inset: 0; pointer-events: none; z-index: var(--z-toast); overflow: hidden; }
.co-confetti { position: absolute; width: 8px; height: 8px; background: var(--brand-primary); left: var(--x); top: 40%; border-radius: var(--radius-xs); animation: co-confetti-fall 1.2s ease-out forwards; animation-delay: var(--delay); }
.co-confetti:nth-child(2n) { background: var(--color-success); border-radius: 50%; }
.co-confetti:nth-child(3) { background: var(--color-warn); width: 10px; height: 6px; }
.co-confetti:nth-child(5) { width: 6px; height: 10px; }

@keyframes co-amount-reveal { from { transform: scale(0.8) translateY(10px); opacity: 0; } }
.co-success-amount { animation: co-amount-reveal 0.5s ease-out 0.3s both; }

/* ── Card selection premium feedback ── */
.preset-card.is-selected,
.ticket-preset-card.is-selected {
    border-color: var(--brand-primary);
    background: var(--brand-primary-light);
}
.preset-card.is-selected::after,
.ticket-preset-card.is-selected::after {
    content: '\2713';
    position: absolute;
    top: -6px;
    right: -6px;
    width: 20px;
    height: 20px;
    background: var(--color-success);
    border-radius: var(--radius-full);
    color: var(--color-text-inverse);
    font-size: var(--text-xs);
    font-weight: var(--font-bold);
    display: flex;
    align-items: center;
    justify-content: center;
    animation: co-badge-pop 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes co-badge-pop {
    0%   { transform: scale(0); }
    100% { transform: scale(1); }
}

/* ── Trust bar lock pulse ── */
.co-trust-icon--animate {
    animation: co-lock-pulse 2.5s ease-in-out infinite;
}
@keyframes co-lock-pulse {
    0%, 100% { opacity: 0.7; transform: scale(1); }
    50%      { opacity: 1; transform: scale(1.08); }
}

/* ── View Transitions API ── */
::view-transition-old(root) {
    animation: co-vt-fade-out 0.15s ease-out forwards;
}
::view-transition-new(root) {
    animation: co-vt-fade-in 0.15s ease-out forwards;
}
@keyframes co-vt-fade-out { to { opacity: 0; } }
@keyframes co-vt-fade-in  { from { opacity: 0; } }

/* ── Payment overlay styles (replaces inline style) ── */
.co-payment-overlay {
    z-index: var(--z-modal-backdrop);
    opacity: 0.97;
}

/* Reduced-motion: all animations above are covered by the global
   @media(prefers-reduced-motion) override at L832 (duration: 0.01ms !important).
   No per-class overrides needed. */

/* ════════════════════════════════════════════════════════════════════
   DASHBOARD PREMIUM v1 — T149 v12 (2026-04-16)
   Scope: .kpi-hero, .kpi-card, dashboard chart sections.
   Rule: tokens only, no hardcoded values. Additive: overrides earlier
   dashboard rules only where needed to elevate visual quality without
   breaking narrative, information density, or dark mode.

   STYLELINT (T178 CSS-T149-LAYERED): the block below is a deliberate
   polish layer over the base rules defined earlier in the file. Each
   re-declared selector adds premium styling (shadows, gradients, hover
   transforms) without overriding the base's core behaviour. Consolidating
   these into the base definitions is scheduled in T178 §I.4 and requires
   a visual-regression pass; until then, suppress the layering warnings.
   ════════════════════════════════════════════════════════════════════ */
/* stylelint-disable no-duplicate-selectors, no-descending-specificity */

/* Hero: richer gradient + aurora glow + subtle grid texture */
.kpi-hero {
    position: relative;
    overflow: hidden;
    background:
        radial-gradient(1200px 400px at 10% -20%, var(--brand-primary-shadow) 0%, transparent 60%),
        radial-gradient(900px 300px at 110% 120%, var(--brand-primary-shadow-strong) 0%, transparent 55%),
        linear-gradient(135deg, var(--color-brand-tint-10), var(--color-brand-tint-25));
    box-shadow:
        0 1px 0 var(--color-white-50) inset,
        var(--shadow-brand-lg);
    border: 1px solid var(--color-border-subtle);
}
:where([data-theme="dark"]) .kpi-hero {
    box-shadow:
        0 1px 0 rgb(255 255 255 / 0.04) inset,
        0 12px 32px rgb(0 0 0 / 0.35);
    border-color: var(--color-border-default);
}
.kpi-hero::before {
    content: "";
    position: absolute;
    inset: 0;
    background-image: linear-gradient(var(--color-border-subtle) 1px, transparent 1px),
                      linear-gradient(90deg, var(--color-border-subtle) 1px, transparent 1px);
    background-size: 48px 48px;
    opacity: 0.25;
    pointer-events: none;
    mask-image: radial-gradient(ellipse at 50% 0%, black 0%, transparent 70%);
}
.kpi-hero > * { position: relative; z-index: calc(var(--z-base) + 1); }

/* Hero label: tighter, more confident */
.kpi-hero__label {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-xs);
    letter-spacing: var(--tracking-widest, 0.1em);
}

/* Hero primary value: tabular + gradient fill on brand */
.kpi-hero__value {
    letter-spacing: -0.035em;
    background: linear-gradient(180deg, var(--color-text-primary) 0%,
                                         color-mix(in srgb, var(--color-text-primary) 78%, var(--brand-primary-dark)) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}
:where([data-theme="dark"]) .kpi-hero__value {
    background: linear-gradient(180deg, var(--color-text-primary) 0%,
                                         color-mix(in srgb, var(--color-text-primary) 70%, var(--brand-primary)) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}

/* Live badge more prominent */
.dashboard-live-badge {
    padding: 2px var(--space-2);
    border-radius: var(--radius-full, 999px);
    background: color-mix(in srgb, var(--color-success, #16a34a) 12%, transparent);
    color: var(--color-success, #16a34a);
    font-size: var(--text-2xs, 0.625rem);
    font-weight: var(--font-bold);
    letter-spacing: 0.1em;
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-success, #16a34a) 30%, transparent);
}

/* Hero breakdown: elevate above hero gradient */
.kpi-hero__breakdown {
    background: var(--color-surface);
    border: 1px solid var(--color-border-subtle);
    border-radius: var(--radius-lg);
    padding: var(--space-5);
    box-shadow: var(--shadow-sm);
    transition: box-shadow var(--transition-fast), transform var(--transition-fast);
}
.kpi-hero__breakdown:hover {
    box-shadow: var(--shadow-md);
}
.kpi-hero__breakdown-row--clickable { transition: background var(--transition-fast); }
.kpi-hero__breakdown-row--clickable:hover td { background: var(--color-brand-tint-10); }

/* Cards: premium icon badge + refined shadow + hover lift */
.kpi-card {
    border: 1px solid var(--color-border-subtle);
    transition: transform var(--transition-fast), box-shadow var(--transition-fast), border-color var(--transition-fast);
    position: relative;
}
.kpi-card::before {
    content: "";
    position: absolute;
    inset-block-start: 0;
    inset-inline: var(--space-4);
    block-size: 2px;
    background: linear-gradient(90deg, transparent, var(--brand-primary), transparent);
    opacity: 0;
    transition: opacity var(--transition-fast);
}
.kpi-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
    border-color: var(--color-border-default);
}
.kpi-card:hover::before { opacity: 0.6; }

/* T149 v15-fix: la regla previa "premium icon badge brand tint" pisaba todas
 * las variantes --green/--orange/--teal/--purple/--blue/etc. con un gradient
 * uniforme brand-primary. Resultado: todos los iconos KPI igualados a azul cyan,
 * perdiendo la semantica de tema (verde=in, naranja=out, teal=saldo, etc.).
 * Eliminada — los temas individuales (L2206-2215 light, L2234-2243 dark) ya
 * aplican --kpi-accent-bg correctamente sobre la regla base L2196-2205. */

/* Numeric values: always tabular */
.kpi-card [data-kpi-value],
.kpi-card .kpi-value,
.kpi-hero [data-kpi-value] {
    font-variant-numeric: tabular-nums slashed-zero;
}

/* Section titles: stronger hierarchy with number prefix via CSS counter */
#dashboard-charts-container { counter-reset: dash-section; }
#dashboard-charts-container > section[data-card-title],
#dashboard-charts-container > .kpi-card {
    counter-increment: dash-section;
}

/* Chart tabs: animated underline on active */
.dashboard-tab[role="tab"],
[role="tablist"] > [role="tab"] {
    position: relative;
    transition: color var(--transition-fast);
}
/* v15.2 fix: underline gradient aplicado a HOVER de tabs no-seleccionadas
 * (antes estaba duplicado con el border-bottom del aria-selected, creando
 * doble barra visible en el mismo tab activo). KISS: una barra por estado. */
.dashboard-tab[role="tab"]:hover:not([aria-selected="true"])::after,
[role="tablist"] > [role="tab"]:hover:not([aria-selected="true"])::after {
    content: "";
    position: absolute;
    inset-inline: var(--space-3);
    inset-block-end: 0;
    block-size: 2px;
    background: linear-gradient(90deg, var(--brand-primary), var(--brand-primary-dark));
    border-radius: var(--radius-full, 999px);
    opacity: 0.5;
    animation: dash-tab-underline var(--transition-base) ease-out;
}
@keyframes dash-tab-underline {
    from { transform: scaleX(0.3); opacity: 0; }
    to { transform: scaleX(1); opacity: 1; }
}

/* Preset pills: brand filled when active */
.dashboard-filters__preset[aria-pressed="true"],
.dashboard-filters__preset.is-active,
button[data-preset].is-active {
    background: linear-gradient(135deg, var(--brand-primary), var(--brand-primary-active));
    color: var(--color-text-inverse);
    border-color: transparent;
    box-shadow: 0 2px 6px var(--brand-primary-shadow);
}

/* Empty state: softer background */
.dashboard-empty-state,
[data-empty-state] {
    background: radial-gradient(ellipse at center, var(--color-brand-tint-10) 0%, transparent 70%);
    border-radius: var(--radius-lg);
}

/* v15.2 fix: regla premium "crisp top border" eliminada — bordes de la
 * seccion de filtros retirados por consistencia visual (ver T149 Parte XXII). */

/* Section title: capital tracking + underline brand */
.dashboard-section-title {
    letter-spacing: -0.02em;
    position: relative;
    padding-bottom: var(--space-2);
}
.dashboard-section-title::after {
    content: "";
    position: absolute;
    inset-block-end: 0;
    inset-inline-start: 0;
    block-size: 3px;
    inline-size: var(--space-12, 3rem);
    background: linear-gradient(90deg, var(--brand-primary), transparent);
    border-radius: var(--radius-full, 999px);
}

/* Reduced motion honored by global override L832. */
/* stylelint-enable no-duplicate-selectors, no-descending-specificity */
/* ═════════════ end DASHBOARD PREMIUM v1 ═════════════ */

/* ═════════════ DASHBOARD HERO V2 — T154 ═════════════ */
/* Mobile-first 3-card grid with display KPI + variation chip + sparkline slot. */

.kpi-hero--v2 {
    background: var(--color-surface);
    border: 1px solid var(--color-border-subtle, rgba(15, 23, 42, 0.06));
    border-radius: var(--radius-2xl, 20px);
    padding: clamp(16px, 3vw, 24px);
    box-shadow: var(--shadow-sm, 0 1px 2px rgba(15, 23, 42, 0.04));
    margin-bottom: 1rem;
}

.kpi-hero--v2 .kpi-hero__grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-4);
}

@media (min-width: 768px) {
    .kpi-hero--v2 .kpi-hero__grid {
        grid-template-columns: repeat(3, 1fr);
        gap: var(--space-5);
    }
}

.kpi-hero-card {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    /* 18px sin token equivalente exacto — KISS: literal con justificación */
    padding: 18px var(--space-5) var(--space-4);
    border-radius: var(--radius-xl, 16px);
    background: var(--color-surface-subtle, #f8fafc);
    border: 1px solid transparent;
    transition: transform 150ms ease, box-shadow 150ms ease, border-color 150ms ease;
}

.kpi-hero-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md, 0 4px 12px rgba(15, 23, 42, 0.08));
    border-color: var(--color-border-subtle, rgba(15, 23, 42, 0.08));
}

.kpi-hero-card--primary {
    background: linear-gradient(135deg, var(--color-primary-50, #eff6ff) 0%, var(--color-surface-subtle, #f8fafc) 100%);
    border-color: var(--color-primary-100, rgba(59, 130, 246, 0.15));
}

.kpi-hero-card__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    margin: 0;
}

.kpi-hero-card__label {
    font-size: var(--text-caption-size);
    font-weight: var(--font-semibold);
    line-height: var(--text-caption-leading);
    letter-spacing: var(--text-caption-tracking);
    text-transform: uppercase;
    color: var(--color-text-muted, #64748b);
    margin: 0;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
}

.kpi-hero-card__value {
    font-size: clamp(32px, 5vw, 44px);
    font-weight: var(--text-display-weight);
    line-height: var(--text-display-leading);
    letter-spacing: var(--text-display-tracking);
    color: var(--color-text, #0f172a);
    margin: 0;
    display: flex;
    align-items: baseline;
    gap: var(--space-1-5);
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
}

.kpi-hero-card--primary .kpi-hero-card__value {
    font-size: var(--text-display-size);
    color: var(--color-primary-700, #1d4ed8);
}

.kpi-hero-card__currency {
    font-size: 0.55em;
    font-weight: var(--font-semibold);
    color: var(--color-text-muted, #64748b);
    letter-spacing: 0;
}

.kpi-hero-card__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px 14px; /* T443: 10px y 14px fuera del scale canónico (4/8/12/16/20) — defer a v4.1 */
    margin-top: 2px;
}

.kpi-hero-card__variation {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    /* 2px sin token equivalente — KISS: literal con justificación */
    padding: 2px var(--space-2);
    border-radius: var(--radius-full, 999px);
    font-size: var(--text-xs);
    font-weight: var(--font-semibold);
    line-height: 1.4;
    background: var(--color-neutral-100, rgba(148, 163, 184, 0.12));
    color: var(--color-text-muted, #64748b);
    font-variant-numeric: tabular-nums;
}
/* T174 P174-7 — variation chip readability on dark (ratio subía a 1.00 con
   color=bg). Los tokens nuevos se resuelven al fg intensificado en dark
   y mantienen el `-hover` semantic en light (cumple AA en ambos temas). */
.kpi-hero-card__variation[data-trend="up"]   { background: var(--color-success-bg); color: var(--color-variation-success-fg); }
.kpi-hero-card__variation[data-trend="down"] { background: var(--color-error-bg);   color: var(--color-variation-error-fg); }

.kpi-hero-card__sub {
    font-size: var(--text-caption-size);
    color: var(--color-text-muted, #64748b);
    line-height: 1.4;
}
.kpi-hero-card__sub strong {
    color: var(--color-text, #0f172a);
    font-weight: var(--font-semibold);
    font-variant-numeric: tabular-nums;
}

.kpi-hero-card__spark {
    height: 32px;
    margin-top: auto;
    border-radius: var(--radius-md, 8px);
    background: linear-gradient(180deg, transparent, var(--color-neutral-50, rgba(148, 163, 184, 0.04)));
    /* Sparkline canvas injected by JS — placeholder for now */
}

/* Plegable */
.kpi-hero__details {
    margin-top: var(--space-4);
    border-top: 1px solid var(--color-border-subtle, rgba(15, 23, 42, 0.06));
    padding-top: var(--space-3);
}
.kpi-hero__details-summary {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1-5);
    cursor: pointer;
    font-size: var(--text-caption-size);
    font-weight: var(--font-semibold);
    /* T174 P174-7 — `--color-link` resuelve a brand-primary-dark en light
       (contrast OK) y a brand-primary (#33BEFF) en dark (5.6:1 vs
       slate-800). El hardcode a #1d4ed8 caía a 2.18:1 en dark. */
    color: var(--color-link);
    list-style: none;
    user-select: none;
    padding: 4px var(--space-2); /* T443: 4px sin token canónico — defer a v4.1 */
    border-radius: var(--radius-md, 8px);
    transition: background 120ms ease;
}
.kpi-hero__details-summary::-webkit-details-marker { display: none; }
.kpi-hero__details-summary:hover { background: var(--color-primary-50, rgba(59, 130, 246, 0.08)); }
.kpi-hero__details-summary-arrow {
    display: inline-block;
    transition: transform 200ms ease;
    font-size: 1.25em;
    line-height: 1;
}
.kpi-hero__details[open] .kpi-hero__details-summary-arrow { transform: rotate(90deg); }

.kpi-hero__details-body {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-4);
    margin-top: var(--space-3);
}
@media (min-width: 768px) {
    .kpi-hero__details-body { grid-template-columns: repeat(2, 1fr); }
}

/* Dark mode */
[data-theme="dark"] .kpi-hero--v2 {
    background: var(--color-surface);
    border-color: var(--color-border-subtle, rgba(255, 255, 255, 0.08));
}
[data-theme="dark"] .kpi-hero-card {
    background: var(--color-surface-subtle, rgba(255, 255, 255, 0.03));
}
[data-theme="dark"] .kpi-hero-card--primary {
    background: linear-gradient(135deg, rgba(59, 130, 246, 0.12) 0%, rgba(255, 255, 255, 0.02) 100%);
    border-color: rgba(59, 130, 246, 0.25);
}
[data-theme="dark"] .kpi-hero-card__value { color: var(--color-text, #f1f5f9); }
[data-theme="dark"] .kpi-hero-card--primary .kpi-hero-card__value { color: var(--color-link); }

@media (prefers-reduced-motion: reduce) {
    .kpi-hero-card,
    .kpi-hero__details-summary-arrow { transition: none; }
}
/* ═════════════ end DASHBOARD HERO V2 ═════════════ */

/* Filters sticky top.
 * Quick presets + event filter siempre accesibles al hacer scroll.
 * Avanzados (toggle-filters) permanecen plegables.
 * NOTE: no `backdrop-filter` here — it would create a new containing block
 * that traps the descendant `#filters-drawer` (position:fixed + inset:0)
 * into the form's sticky 60px-tall bbox. Solid surface background is
 * already opaque enough without the blur. */
/* stylelint-disable-next-line no-duplicate-selectors
   -- sticky/scroll behaviour layer over base .dashboard-filters at L4835. */
.dashboard-filters {
    position: sticky;
    top: 0;
    /* sticky bajo header (--z-header: 400) y bajo sidebar overlay (--z-sidebar-overlay: 450).
       T441 H1: usa --z-raised (30) en lugar de literal para mantener convención de tokens. */
    z-index: var(--z-raised);
    background: var(--color-surface);
    margin-top: 0;
    padding: var(--space-2) 0;
    transition: box-shadow 200ms ease;
}
.dashboard-filters.is-stuck {
    box-shadow: 0 2px 8px rgba(15, 23, 42, 0.06);
}
[data-theme="dark"] .dashboard-filters {
    background: var(--color-surface);
}
@media (max-width: 639px) {
    /* En mobile el sticky puede comerse altura útil; baja a relative. */
    .dashboard-filters { position: relative; }
}

/* ═══════════════════════════════════════════════════════════════════
   Filters 2-level layout — primary row (sticky) + advanced drawer.
   Mobile-first: primary row presets scroll-snap horizontally; the
   drawer is a slide-in side panel on desktop and a full-screen modal
   on mobile.
   ═══════════════════════════════════════════════════════════════════ */

/* Primary row — always visible. Mobile-first. */
.dashboard-filters__primary {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    min-width: 0;
    flex-wrap: nowrap;
}
.dashboard-filters__primary-presets {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    overflow-x: auto;
    scroll-snap-type: x proximity;
    scrollbar-width: thin;
    -webkit-overflow-scrolling: touch;
    padding-block: var(--space-1);
    flex: 1 1 auto;
    min-width: 0;
}
.dashboard-filters__primary-presets::-webkit-scrollbar { height: 4px; }
.dashboard-filters__primary-presets::-webkit-scrollbar-thumb { background: var(--color-border-subtle); border-radius: var(--radius-full, 999px); }
.dashboard-filters__primary-presets .preset-btn,
.dashboard-filters__primary-presets .dashboard-filters__preset {
    flex-shrink: 0;
    scroll-snap-align: start;
}
.dashboard-filters__primary .dashboard-filters__event-select {
    flex: 0 1 180px;
    min-width: 0;
}
.dashboard-filters__drawer-trigger {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-1) var(--space-3);
    border-radius: var(--radius-sm);
    border: 1px solid var(--color-border-default);
    background: var(--color-bg-surface);
    color: var(--color-text-primary);
    font-size: var(--text-sm);
    font-weight: var(--font-semibold);
    min-height: 40px;
    cursor: pointer;
    flex-shrink: 0;
    transition: background var(--transition-fast), border-color var(--transition-fast);
}
.dashboard-filters__drawer-trigger:hover {
    background: var(--color-brand-tint-10);
    border-color: var(--brand-primary);
}
.dashboard-filters__drawer-trigger[aria-expanded="true"] {
    background: var(--color-brand-tint-10);
    border-color: var(--brand-primary);
    color: var(--brand-primary-dark);
}
.dashboard-filters__drawer-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.25rem;
    padding: 0 var(--space-1);
    font-size: var(--text-2xs, 0.625rem);
    font-weight: var(--font-bold);
    border-radius: var(--radius-full, 999px);
    background: var(--brand-primary);
    color: var(--color-text-inverse);
    line-height: 1.25rem;
}
.dashboard-filters__drawer-count.hidden { display: none; }

@media (min-width: 640px) {
    .dashboard-filters__primary .dashboard-filters__event-select { flex: 0 1 220px; }
    .dashboard-filters__drawer-trigger { min-height: 36px; }
}

/* Drawer — slide-in side panel (full-screen on narrow viewports). */
.dashboard-filters__drawer {
    position: fixed;
    inset: 0;
    z-index: var(--z-modal, 600);
    background: color-mix(in srgb, var(--color-text-primary) 40%, transparent);
    display: flex;
    justify-content: flex-end;
    animation: dash-drawer-fade 160ms ease-out;
}
.dashboard-filters__drawer[hidden] { display: none; }

/* Stacking-context fix (T169 NEW-P2-3): the drawer lives inside .content-wrapper
 * (z-index:0), which caps its z-index BELOW the sidebar (z:200, outside the
 * wrapper). While the drawer is open, lift the wrapper above the sidebar so
 * clicks on the dim overlay hit the drawer (not the sidebar underneath). */
body.dashboard-filters__drawer-open .content-wrapper { z-index: var(--z-modal, 600); }

/* Panel: header + scrollable body + footer — flex column so the scroll
 * region is isolated to the body (predictable behaviour for sticky
 * sub-headers and absolutely positioned dropdowns inside sections). */
.dashboard-filters__drawer-panel {
    background: var(--color-surface);
    inline-size: min(100%, 520px);
    block-size: 100%;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    box-shadow: -8px 0 24px rgba(15, 23, 42, 0.12);
    animation: dash-drawer-slide 200ms ease-out;
}
.dashboard-filters__drawer-header {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-4);
    border-bottom: 1px solid var(--color-border-subtle);
    background: var(--color-surface);
}
.dashboard-filters__drawer-title {
    margin: 0;
    font-size: var(--text-h2-size, var(--text-lg));
    font-weight: var(--font-semibold);
    color: var(--color-text-primary);
}
.dashboard-filters__drawer-close {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 36px;
    block-size: 36px;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--color-text-secondary);
    cursor: pointer;
    transition: background var(--transition-fast), color var(--transition-fast);
}
.dashboard-filters__drawer-close:hover {
    background: var(--color-brand-tint-10);
    color: var(--color-text-primary);
}
.dashboard-filters__drawer-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
}
.dashboard-filters__drawer-section {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}
.dashboard-filters__drawer-section-title {
    margin: 0;
    font-size: var(--text-xs);
    font-weight: var(--font-semibold);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-text-secondary);
}

/* Drawer-local overrides for existing filter widgets. The original styles
 * target a wide horizontal header; inside a narrow side panel they must
 * stack and expand to 100% to stay usable. */
.dashboard-filters__drawer .dashboard-filters__grid,
.dashboard-filters__drawer .dashboard-filters__grid--dates {
    grid-template-columns: 1fr;
    gap: var(--space-3);
}
@media (min-width: 480px) {
    .dashboard-filters__drawer .dashboard-filters__grid--dates {
        grid-template-columns: 1fr 1fr;
    }
}
.dashboard-filters__drawer .dashboard-filters__compare-group {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-2);
    width: 100%;
}
.dashboard-filters__drawer .dashboard-filters__compare-select,
.dashboard-filters__drawer .dashboard-filters__event-select {
    width: 100%;
}
/* Multi-select dropdowns: render in-flow inside the drawer so the scroll
 * region handles them naturally instead of clipping an absolutely
 * positioned overlay. */
.dashboard-filters__drawer .dashboard-filters__dropdown {
    position: static;
    width: 100%;
    margin-top: var(--space-1);
    box-shadow: none;
    border-color: var(--color-border-subtle);
}
.dashboard-filters__drawer .dashboard-filters__dropdown-scroll {
    max-height: 240px;
}

.dashboard-filters__refresh-group {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
}
.dashboard-filters__freshness {
    font-size: var(--text-xs);
    color: var(--color-text-muted);
    margin-inline-start: auto;
}

/* Body scroll lock while drawer is open. */
body.dashboard-filters__drawer-open { overflow: hidden; }

[data-theme="dark"] .dashboard-filters__drawer {
    background: var(--color-overlay);  /* T438: was color-mix(in srgb, #000 60%, transparent) */
}
[data-theme="dark"] .dashboard-filters__drawer-panel {
    background: var(--color-bg-elevated);
    box-shadow: -8px 0 24px rgba(0, 0, 0, 0.4);
}
[data-theme="dark"] .dashboard-filters__drawer-header {
    background: var(--color-bg-elevated);
}

@keyframes dash-drawer-fade {
    from { opacity: 0; }
    to { opacity: 1; }
}
@keyframes dash-drawer-slide {
    from { transform: translateX(100%); }
    to { transform: translateX(0); }
}

@media (prefers-reduced-motion: reduce) {
    .dashboard-filters__drawer,
    .dashboard-filters__drawer-panel { animation: none; }
}

/* ═══════════════════════════════════════════════════════════════════
   T174 P174-7 — Dark mode contrast polish
   Selectores donde `--color-text-muted` caía a ratios < 4.5:1 sobre
   superficies elevadas; con `--color-text-muted-on-elevated`
   (slate-300) el contraste sube a 6.97:1. El elemento específico de
   cada bloque se justifica con el ratio medido en Playwright live
   (tenant dev_local, 2026-04-18). Light mode hereda el alias al
   muted estandar, asi que este refactor es neutro en light.

   STYLELINT (T178 CSS-T174-DARK-CONTRAST): each re-declared selector
   adds a single `color:` layer on top of existing rules. Consolidating
   into the base definitions is scheduled in T178 §I.4; until then,
   suppress the layering warnings.
   ═══════════════════════════════════════════════════════════════════ */
/* stylelint-disable no-duplicate-selectors, no-descending-specificity */
.dashboard-filters__label,
.dashboard-filters__freshness,
.dashboard-filters__refresh-btn,
.chart-legend-table thead th,
.kpi-hero__breakdown-title,
.chart-card__tab:not(.chart-card__tab--active),
.legend-info-icon,
.kpi-hero-card__sub {
    color: var(--color-text-muted-on-elevated);
}

/* `--color-text-inverse` (slate-900) sobre `--color-bg-surface` en dark
   caía a 1.22:1 — el valor Facturado Neto dentro del desglose no se
   leía. Primary color mantiene AA en ambos temas. */
#hero-breakdown-neto {
    color: var(--color-text-primary);
}

/* Separador visual de la fila Total del legend-table: en dark el
   border-default coincide con el bg-elevated, asi que la linea
   desaparecia. Border-strong mantiene la jerarquia visual. */
.chart-legend-total {
    border-top-color: var(--color-border-strong);
}

/* Error banner en dark: rojo-on-rojo@12% dejaba el banner ilegible.
   Subimos el bg y bajamos el fg a red-200 para conseguir ~8:1. */
[data-theme="dark"] .alert-error {
    background: color-mix(in srgb, var(--color-error) 20%, var(--color-bg-page));
    color: var(--color-variation-error-fg);
    border: 1px solid color-mix(in srgb, var(--color-error) 45%, transparent);
}
/* Boton "Reintentar" dentro del banner usa la misma paleta. */
[data-theme="dark"] .alert-error .btn,
[data-theme="dark"] #dashboard-error-retry {
    color: var(--color-variation-error-fg);
    background: color-mix(in srgb, var(--color-error) 30%, transparent);
    border-color: color-mix(in srgb, var(--color-error) 55%, transparent);
}

/* "Exportar" label del FAB: el trigger tiene fondo brand-primary, asi
   que el label debe ser `--color-text-inverse` (slate-900 en dark,
   white en light) — igual patron que usa `.dashboard-fab__trigger`.
   Antes era brand-primary-dark (2.47:1 sobre slate-800 cuando el
   label quedaba junto al sidebar). */
.dashboard-fab__label {
    color: var(--color-text-inverse);
}

/* T204 B1 — modal-scoped sticky reinforcement for the admin receipt modal
   (#receipt-modal in zelebrix/zelebrix/templates/transacciones.html).
   The inner `order-details-table` inherits `.data-table` sticky rules
   from line ~2966, but the parent `.modal-content` animates with
   `transform: scale()` during `@keyframes modalIn` (line ~5651), briefly
   creating a stacking context that can let sibling cells paint over the
   sticky first column during open. Pinning `isolation: isolate` on the
   modal content keeps the sticky z-index scoped to the subtree; the
   dedicated rule inside #receipt-modal-content reinforces the cell bump.
   Kept inside the already-suppressed no-descending-specificity block
   because the generic `.modal-content` rules sit earlier in the file. */
#receipt-modal .modal-content {
    isolation: isolate;
}
#receipt-modal-content .order-details-table thead :where(th:first-child),
#receipt-modal-content .order-details-table tbody :where(td:first-child) {
    z-index: calc(var(--z-base) + 2);
}
/* stylelint-enable no-duplicate-selectors, no-descending-specificity */
