Rafael Lopez

first commit

Showing 46 changed files with 5113 additions and 0 deletions
1 +node_modules
2 +
3 +# Output
4 +.output
5 +.vercel
6 +.netlify
7 +.wrangler
8 +/.svelte-kit
9 +/build
10 +
11 +# OS
12 +.DS_Store
13 +Thumbs.db
14 +
15 +# Env
16 +.env
17 +.env.*
18 +!.env.example
19 +!.env.test
20 +
21 +# Vite
22 +vite.config.js.timestamp-*
23 +vite.config.ts.timestamp-*
24 +
25 +# Claude
26 +claude.md
1 +engine-strict=true
1 +# Lógica del Buscador
2 +
3 +## Resumen
4 +Buscador instantáneo con Fuse.js en cliente. Busca en clasificadores presupuestarios y navega a vistas de detalle.
5 +
6 +## Decisiones de Diseño
7 +
8 +### Motor de búsqueda
9 +- **Tecnología**: Fuse.js (cliente)
10 +- **Razón**: ~2,000-4,000 registros totales, cabe en memoria, búsqueda instantánea sin latencia
11 +
12 +### Tolerancia a errores
13 +- Normalización de acentos ("andres" → "andrés")
14 +- Case-insensitive ("UMSA" = "umsa")
15 +- Fuzzy matching ("univercidad" → "universidad")
16 +
17 +### Comportamiento
18 +| Parámetro | Valor |
19 +|-----------|-------|
20 +| Debounce | 200-300ms |
21 +| Mínimo caracteres | 2 |
22 +| Máximo resultados | 10-30 |
23 +| Navegación | Flechas ↑↓ + Enter + scroll de mouse y loq ue corresponda para mobiles|
24 +
25 +## Estructura del Índice
26 +
27 +### Índice unificado (futuro)
28 +Todos los clasificadores en un solo array con `tipo`:
29 +
30 +```javascript
31 +// src/lib/data/index.js
32 +const indice = [
33 + {
34 + tipo: 'entidad',
35 + codigo: 139,
36 + nombre: 'Universidad Mayor De San Andrés',
37 + sigla: 'UMSA',
38 + contexto: 'Universidades Públicas',
39 + años: 20,
40 + // campos normalizados para búsqueda
41 + _nombre_normalizado: 'universidad mayor de san andres',
42 + _sigla_normalizada: 'umsa'
43 + },
44 + {
45 + tipo: 'objeto_gasto',
46 + codigo: 25100,
47 + nombre: 'Pasajes',
48 + contexto: 'Servicios',
49 + // ...
50 + }
51 +]
52 +```
53 +
54 +### Por ahora (MVP)
55 +Solo clasificador de entidades (`clas_institucional`).
56 +
57 +## Columnas de Búsqueda
58 +
59 +### Entidades (clas_institucional)
60 +| Columna | Buscar | Mostrar |
61 +|---------|--------|---------|
62 +| `desc_entidad` | ✓ | ✓ nombre principal |
63 +| `sigla_entidad` | ✓ | ✓ entre paréntesis |
64 +| `desc_area` | ✗ | ✓ contexto |
65 +| `n_gestiones` | ✗ | ✓ "X años de datos" |
66 +| `entidad` | ✗ | para URL |
67 +
68 +### Objetos de gasto (futuro)
69 +| Columna | Buscar | Mostrar |
70 +|---------|--------|---------|
71 +| `desc_objeto` | ✓ | ✓ nombre principal |
72 +| `codigo_objeto` | ✓ | ✓ código |
73 +| `desc_partida` | ✗ | ✓ contexto |
74 +
75 +## Flujo de Búsqueda
76 +
77 +```
78 +1. CARGA INICIAL
79 + App monta → descarga clasificadores → construye índice Fuse.js
80 +
81 +2. USUARIO ESCRIBE
82 + Input → debounce 250ms → si ≥2 chars → Fuse.search()
83 +
84 +3. RESULTADOS
85 + Fuse devuelve matches → renderizar lista con highlighting
86 +
87 +4. SELECCIÓN
88 + Click o Enter → navegar a /entidad/[codigo] o /gasto/[codigo]
89 +```
90 +
91 +## Estructura de URLs
92 +
93 +```
94 +/entidad/[codigo] → /entidad/139
95 +/gasto/[codigo] → /gasto/25100 (futuro)
96 +/area/[codigo] → /area/1.1.4 (futuro, opcional)
97 +```
98 +
99 +## Formato de Resultados
100 +
101 +```
102 +┌─────────────────────────────────────────────────────┐
103 +│ 🔍 [buscar entidad, objeto de gasto...] │
104 +├─────────────────────────────────────────────────────┤
105 +│ Universidad Mayor De San Andrés (UMSA) │
106 +│ Universidades Públicas · 20 años │
107 +├─────────────────────────────────────────────────────┤
108 +│ Universidad Pública De El Alto (UPEA) │
109 +│ Universidades Públicas · 21 años │
110 +├─────────────────────────────────────────────────────┤
111 +│ ... │
112 +└─────────────────────────────────────────────────────┘
113 +```
114 +
115 +## Estados del Buscador
116 +
117 +| Estado | Qué mostrar |
118 +|--------|-------------|
119 +| Vacío (< 2 chars) | Placeholder o sugerencias |
120 +| Cargando índice | Spinner / "Cargando..." |
121 +| Buscando | Nada (es instantáneo) |
122 +| Con resultados | Lista de resultados |
123 +| Sin resultados | "No se encontraron resultados para 'xyz'" |
124 +| Error | "Error al cargar datos" |
125 +
126 +## Estructura de Archivos
127 +
128 +```
129 +src/lib/
130 +├── components/
131 +│ └── search/
132 +│ ├── SearchBox.svelte ← Input + lógica de búsqueda
133 +│ ├── SearchResults.svelte ← Lista de resultados
134 +│ └── SearchResultItem.svelte ← Item individual
135 +├── services/
136 +│ ├── supabase.js ← Cliente Supabase
137 +│ └── search.js ← Inicialización Fuse.js
138 +├── stores/
139 +│ └── searchStore.js ← Estado: query, results, loading
140 +├── utils/
141 +│ └── normalize.js ← Normalización de texto
142 +└── data/
143 + └── index.js ← Carga y construcción del índice
144 +```
145 +
146 +## Trabajo Futuro
147 +
148 +### Índice normalizado
149 +Cuando haya múltiples clasificadores, crear un proceso que:
150 +1. Descargue todos los clasificadores
151 +2. Normalice campos de búsqueda (acentos, minúsculas)
152 +3. Genere un índice unificado optimizado
153 +4. Posiblemente pre-computar en servidor y servir como JSON estático
154 +
155 +### Migración a servidor
156 +Si el índice supera ~20,000 registros:
157 +1. Habilitar extensión `pg_trgm` en PostgreSQL
158 +2. Crear índices GIN en columnas de búsqueda
159 +3. Cambiar de Fuse.js a queries con `similarity()` o `%` operator
160 +4. El componente de UI se mantiene igual, solo cambia el servicio
161 +
162 +---
163 +
164 +*Documento de referencia para la implementación del buscador*
1 +# Reglas de Diseño - Presupuesto Público Bolivia
2 +
3 +## Identidad Visual
4 +
5 +Este proyecto sigue las directrices del Manual de Identidad Gráfica del MEFP, adaptadas para una experiencia web moderna y de primer nivel.
6 +
7 +## Paleta de Colores
8 +
9 +### Colores Principales (Institucionales)
10 +| Nombre | Hex | Uso |
11 +|--------|-----|-----|
12 +| **Dorado** | `#C9A751` | Acentos, títulos destacados, líneas divisorias |
13 +| **Rojo Institucional** | `#B91817` | Alertas, elementos de énfasis |
14 +| **Grafito** | `#363534` | Texto principal, fondos oscuros |
15 +
16 +### Colores de la Bandera Nacional
17 +| Nombre | Hex | Uso |
18 +|--------|-----|-----|
19 +| **Rojo Bandera** | `#DB281C` | Decorativo, acentos nacionales |
20 +| **Amarillo** | `#F4E410` | Highlights, estados activos |
21 +| **Verde** | `#007C38` | Estados de éxito, indicadores positivos |
22 +
23 +### Colores Secundarios / Neutros
24 +| Nombre | Hex | Uso |
25 +|--------|-----|-----|
26 +| **Crema (Eggshell)** | `#F3EAD8` | Fondos suaves, cards, secciones alternadas |
27 +| **Gris** | `#676767` | Texto secundario, iconos |
28 +
29 +### Escalas de Grises UI
30 +- Fondo página: `#FAFAFA` o `#F5F5F5`
31 +- Bordes: `#E5E5E5`
32 +- Texto muted: `#9CA3AF`
33 +
34 +## Tipografía
35 +
36 +### Tipografía Principal: Qanelas
37 +- **Uso**: Toda la interfaz (headings, body, UI)
38 +- **Pesos disponibles**: Light (300), Regular (400), Medium (500), SemiBold (600), Bold (700)
39 +- **Fallback**: system-ui, -apple-system, sans-serif
40 +
41 +### Tipografía Institucional: Archivo Condensed
42 +- **Uso**: Logo del producto, elementos de marca específicos
43 +- **Pesos disponibles**: SemiBold, Bold, Black
44 +- **Nota**: Usar con moderación, principalmente para branding
45 +
46 +### Escala Tipográfica
47 +```
48 +text-xs: 12px / 0.75rem
49 +text-sm: 14px / 0.875rem
50 +text-base: 16px / 1rem
51 +text-lg: 18px / 1.125rem
52 +text-xl: 20px / 1.25rem
53 +text-2xl: 24px / 1.5rem
54 +text-3xl: 30px / 1.875rem
55 +text-4xl: 36px / 2.25rem
56 +text-5xl: 48px / 3rem
57 +```
58 +
59 +## Logos
60 +
61 +### Ubicación de archivos
62 +```
63 +static/
64 +├── logos_claro/
65 +│ ├── 04_Imagotipo MEFP espacio positivo.png ← Fondos claros
66 +│ └── 06_Isologo MEFP escala de grises.png
67 +└── logos_oscuro/
68 + ├── 05_Imago MEFP horizontal espacio negativo.png ← Fondos oscuros
69 + └── 05_Imagotipo MEFP espacio negativo.png
70 +```
71 +
72 +### Uso del Logo
73 +- **Navbar fondo claro**: Logo positivo (colores originales)
74 +- **Footer fondo oscuro**: Logo negativo (blanco/dorado)
75 +- **Tamaño mínimo navbar**: altura 40-48px
76 +
77 +## Principios de Diseño
78 +
79 +### Modernidad
80 +- Espaciado generoso (padding, margins)
81 +- Bordes redondeados suaves (rounded-lg, rounded-xl)
82 +- Sombras sutiles (shadow-sm, shadow-md)
83 +- Transiciones suaves (transition-all duration-200)
84 +
85 +### Jerarquía Visual
86 +- Dorado para elementos de jerarquía (títulos, líneas, acentos)
87 +- Grafito para texto principal
88 +- Gris para texto secundario
89 +- Crema para secciones de fondo alternado
90 +
91 +### Accesibilidad
92 +- Contraste mínimo WCAG AA
93 +- Tamaño de texto base 16px
94 +- Áreas de toque mínimo 44x44px en móviles
95 +- Focus visible en elementos interactivos
96 +
97 +## Componentes Clave
98 +
99 +### Navbar
100 +- Fondo: blanco con borde dorado inferior sutil
101 +- Logo MEFP a la izquierda
102 +- Links con hover dorado
103 +- Menú móvil con transición suave
104 +
105 +### Buscador
106 +- Input con borde redondeado
107 +- Focus ring dorado
108 +- Resultados con fondo crema al hover
109 +
110 +### Cards
111 +- Fondo blanco
112 +- Borde sutil `border-gray-200`
113 +- Hover con sombra elevada
114 +- Padding generoso (p-6)
115 +
116 +### Botones
117 +- Primario: fondo dorado, texto grafito
118 +- Secundario: borde dorado, fondo transparente
119 +- Estados hover con oscurecimiento sutil
120 +
121 +### Footer
122 +- Fondo grafito (#363534)
123 +- Texto claro
124 +- Logo versión negativa
125 +- Franja tricolor (rojo, amarillo, verde) arriba
126 +
127 +## Responsividad
128 +
129 +### Breakpoints
130 +- `sm`: 640px
131 +- `md`: 768px
132 +- `lg`: 1024px
133 +- `xl`: 1280px
134 +
135 +### Mobile First
136 +- Diseño base para móviles
137 +- Mejoras progresivas en pantallas grandes
138 +- Navegación colapsable en móviles
139 +- Grids fluidos con `grid-cols-1 md:grid-cols-2 lg:grid-cols-3`
140 +
141 +## Iconografía
142 +- Usar Heroicons (outline) para consistencia
143 +- Tamaño base: `h-5 w-5`
144 +- Color: heredar del texto o usar gris
145 +
146 +## Animaciones
147 +- Duración estándar: 200ms
148 +- Easing: `ease-in-out`
149 +- Usar para: hover states, transiciones de página, aparición de modales
150 +- Evitar: animaciones excesivas que distraigan
151 +
152 +---
153 +
154 +*Documento de referencia para mantener consistencia visual*
1 +# sv
2 +
3 +Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli).
4 +
5 +## Creating a project
6 +
7 +If you're seeing this, you've probably already done this step. Congrats!
8 +
9 +```sh
10 +# create a new project
11 +npx sv create my-app
12 +```
13 +
14 +To recreate this project with the same configuration:
15 +
16 +```sh
17 +# recreate this project
18 +npx sv create --template minimal --no-types --install npm .
19 +```
20 +
21 +## Developing
22 +
23 +Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
24 +
25 +```sh
26 +npm run dev
27 +
28 +# or start the server and open the app in a new browser tab
29 +npm run dev -- --open
30 +```
31 +
32 +## Building
33 +
34 +To create a production version of your app:
35 +
36 +```sh
37 +npm run build
38 +```
39 +
40 +You can preview the production build with `npm run preview`.
41 +
42 +> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
1 +import { createClient } from '@supabase/supabase-js';
2 +import * as dotenv from 'dotenv';
3 +dotenv.config();
4 +
5 +const supabase = createClient(
6 + process.env.PUBLIC_SUPABASE_URL,
7 + process.env.PUBLIC_SUPABASE_ANON_KEY
8 +);
9 +
10 +const { count, error } = await supabase
11 + .schema('ppto')
12 + .from('clas_objetos')
13 + .select('*', { count: 'exact', head: true });
14 +
15 +console.log('Total registros:', count);
16 +if (error) console.log('Error:', error);
1 +{
2 + "extends": "./.svelte-kit/tsconfig.json",
3 + "compilerOptions": {
4 + "allowJs": true,
5 + "checkJs": false,
6 + "moduleResolution": "bundler"
7 + }
8 + // Path aliases are handled by https://svelte.dev/docs/kit/configuration#alias
9 + // except $lib which is handled by https://svelte.dev/docs/kit/configuration#files
10 + //
11 + // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
12 + // from the referenced tsconfig.json - TypeScript does not merge them in
13 +}
1 +{
2 + "name": "ppto",
3 + "version": "0.0.1",
4 + "lockfileVersion": 3,
5 + "requires": true,
6 + "packages": {
7 + "": {
8 + "name": "ppto",
9 + "version": "0.0.1",
10 + "dependencies": {
11 + "@supabase/supabase-js": "^2.98.0",
12 + "d3": "^7.9.0",
13 + "fuse.js": "^7.1.0"
14 + },
15 + "devDependencies": {
16 + "@sveltejs/adapter-auto": "^7.0.0",
17 + "@sveltejs/kit": "^2.50.2",
18 + "@sveltejs/vite-plugin-svelte": "^6.2.4",
19 + "@tailwindcss/vite": "^4.2.1",
20 + "svelte": "^5.51.0",
21 + "tailwindcss": "^4.2.1",
22 + "vite": "^7.3.1"
23 + }
24 + },
25 + "node_modules/@esbuild/aix-ppc64": {
26 + "version": "0.27.3",
27 + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz",
28 + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==",
29 + "cpu": [
30 + "ppc64"
31 + ],
32 + "dev": true,
33 + "license": "MIT",
34 + "optional": true,
35 + "os": [
36 + "aix"
37 + ],
38 + "engines": {
39 + "node": ">=18"
40 + }
41 + },
42 + "node_modules/@esbuild/android-arm": {
43 + "version": "0.27.3",
44 + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz",
45 + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==",
46 + "cpu": [
47 + "arm"
48 + ],
49 + "dev": true,
50 + "license": "MIT",
51 + "optional": true,
52 + "os": [
53 + "android"
54 + ],
55 + "engines": {
56 + "node": ">=18"
57 + }
58 + },
59 + "node_modules/@esbuild/android-arm64": {
60 + "version": "0.27.3",
61 + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz",
62 + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==",
63 + "cpu": [
64 + "arm64"
65 + ],
66 + "dev": true,
67 + "license": "MIT",
68 + "optional": true,
69 + "os": [
70 + "android"
71 + ],
72 + "engines": {
73 + "node": ">=18"
74 + }
75 + },
76 + "node_modules/@esbuild/android-x64": {
77 + "version": "0.27.3",
78 + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz",
79 + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==",
80 + "cpu": [
81 + "x64"
82 + ],
83 + "dev": true,
84 + "license": "MIT",
85 + "optional": true,
86 + "os": [
87 + "android"
88 + ],
89 + "engines": {
90 + "node": ">=18"
91 + }
92 + },
93 + "node_modules/@esbuild/darwin-arm64": {
94 + "version": "0.27.3",
95 + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz",
96 + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==",
97 + "cpu": [
98 + "arm64"
99 + ],
100 + "dev": true,
101 + "license": "MIT",
102 + "optional": true,
103 + "os": [
104 + "darwin"
105 + ],
106 + "engines": {
107 + "node": ">=18"
108 + }
109 + },
110 + "node_modules/@esbuild/darwin-x64": {
111 + "version": "0.27.3",
112 + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz",
113 + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==",
114 + "cpu": [
115 + "x64"
116 + ],
117 + "dev": true,
118 + "license": "MIT",
119 + "optional": true,
120 + "os": [
121 + "darwin"
122 + ],
123 + "engines": {
124 + "node": ">=18"
125 + }
126 + },
127 + "node_modules/@esbuild/freebsd-arm64": {
128 + "version": "0.27.3",
129 + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz",
130 + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==",
131 + "cpu": [
132 + "arm64"
133 + ],
134 + "dev": true,
135 + "license": "MIT",
136 + "optional": true,
137 + "os": [
138 + "freebsd"
139 + ],
140 + "engines": {
141 + "node": ">=18"
142 + }
143 + },
144 + "node_modules/@esbuild/freebsd-x64": {
145 + "version": "0.27.3",
146 + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz",
147 + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==",
148 + "cpu": [
149 + "x64"
150 + ],
151 + "dev": true,
152 + "license": "MIT",
153 + "optional": true,
154 + "os": [
155 + "freebsd"
156 + ],
157 + "engines": {
158 + "node": ">=18"
159 + }
160 + },
161 + "node_modules/@esbuild/linux-arm": {
162 + "version": "0.27.3",
163 + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz",
164 + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==",
165 + "cpu": [
166 + "arm"
167 + ],
168 + "dev": true,
169 + "license": "MIT",
170 + "optional": true,
171 + "os": [
172 + "linux"
173 + ],
174 + "engines": {
175 + "node": ">=18"
176 + }
177 + },
178 + "node_modules/@esbuild/linux-arm64": {
179 + "version": "0.27.3",
180 + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz",
181 + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==",
182 + "cpu": [
183 + "arm64"
184 + ],
185 + "dev": true,
186 + "license": "MIT",
187 + "optional": true,
188 + "os": [
189 + "linux"
190 + ],
191 + "engines": {
192 + "node": ">=18"
193 + }
194 + },
195 + "node_modules/@esbuild/linux-ia32": {
196 + "version": "0.27.3",
197 + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz",
198 + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==",
199 + "cpu": [
200 + "ia32"
201 + ],
202 + "dev": true,
203 + "license": "MIT",
204 + "optional": true,
205 + "os": [
206 + "linux"
207 + ],
208 + "engines": {
209 + "node": ">=18"
210 + }
211 + },
212 + "node_modules/@esbuild/linux-loong64": {
213 + "version": "0.27.3",
214 + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz",
215 + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==",
216 + "cpu": [
217 + "loong64"
218 + ],
219 + "dev": true,
220 + "license": "MIT",
221 + "optional": true,
222 + "os": [
223 + "linux"
224 + ],
225 + "engines": {
226 + "node": ">=18"
227 + }
228 + },
229 + "node_modules/@esbuild/linux-mips64el": {
230 + "version": "0.27.3",
231 + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz",
232 + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==",
233 + "cpu": [
234 + "mips64el"
235 + ],
236 + "dev": true,
237 + "license": "MIT",
238 + "optional": true,
239 + "os": [
240 + "linux"
241 + ],
242 + "engines": {
243 + "node": ">=18"
244 + }
245 + },
246 + "node_modules/@esbuild/linux-ppc64": {
247 + "version": "0.27.3",
248 + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz",
249 + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==",
250 + "cpu": [
251 + "ppc64"
252 + ],
253 + "dev": true,
254 + "license": "MIT",
255 + "optional": true,
256 + "os": [
257 + "linux"
258 + ],
259 + "engines": {
260 + "node": ">=18"
261 + }
262 + },
263 + "node_modules/@esbuild/linux-riscv64": {
264 + "version": "0.27.3",
265 + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz",
266 + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==",
267 + "cpu": [
268 + "riscv64"
269 + ],
270 + "dev": true,
271 + "license": "MIT",
272 + "optional": true,
273 + "os": [
274 + "linux"
275 + ],
276 + "engines": {
277 + "node": ">=18"
278 + }
279 + },
280 + "node_modules/@esbuild/linux-s390x": {
281 + "version": "0.27.3",
282 + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz",
283 + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==",
284 + "cpu": [
285 + "s390x"
286 + ],
287 + "dev": true,
288 + "license": "MIT",
289 + "optional": true,
290 + "os": [
291 + "linux"
292 + ],
293 + "engines": {
294 + "node": ">=18"
295 + }
296 + },
297 + "node_modules/@esbuild/linux-x64": {
298 + "version": "0.27.3",
299 + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz",
300 + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==",
301 + "cpu": [
302 + "x64"
303 + ],
304 + "dev": true,
305 + "license": "MIT",
306 + "optional": true,
307 + "os": [
308 + "linux"
309 + ],
310 + "engines": {
311 + "node": ">=18"
312 + }
313 + },
314 + "node_modules/@esbuild/netbsd-arm64": {
315 + "version": "0.27.3",
316 + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz",
317 + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==",
318 + "cpu": [
319 + "arm64"
320 + ],
321 + "dev": true,
322 + "license": "MIT",
323 + "optional": true,
324 + "os": [
325 + "netbsd"
326 + ],
327 + "engines": {
328 + "node": ">=18"
329 + }
330 + },
331 + "node_modules/@esbuild/netbsd-x64": {
332 + "version": "0.27.3",
333 + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz",
334 + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==",
335 + "cpu": [
336 + "x64"
337 + ],
338 + "dev": true,
339 + "license": "MIT",
340 + "optional": true,
341 + "os": [
342 + "netbsd"
343 + ],
344 + "engines": {
345 + "node": ">=18"
346 + }
347 + },
348 + "node_modules/@esbuild/openbsd-arm64": {
349 + "version": "0.27.3",
350 + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz",
351 + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==",
352 + "cpu": [
353 + "arm64"
354 + ],
355 + "dev": true,
356 + "license": "MIT",
357 + "optional": true,
358 + "os": [
359 + "openbsd"
360 + ],
361 + "engines": {
362 + "node": ">=18"
363 + }
364 + },
365 + "node_modules/@esbuild/openbsd-x64": {
366 + "version": "0.27.3",
367 + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz",
368 + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==",
369 + "cpu": [
370 + "x64"
371 + ],
372 + "dev": true,
373 + "license": "MIT",
374 + "optional": true,
375 + "os": [
376 + "openbsd"
377 + ],
378 + "engines": {
379 + "node": ">=18"
380 + }
381 + },
382 + "node_modules/@esbuild/openharmony-arm64": {
383 + "version": "0.27.3",
384 + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz",
385 + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==",
386 + "cpu": [
387 + "arm64"
388 + ],
389 + "dev": true,
390 + "license": "MIT",
391 + "optional": true,
392 + "os": [
393 + "openharmony"
394 + ],
395 + "engines": {
396 + "node": ">=18"
397 + }
398 + },
399 + "node_modules/@esbuild/sunos-x64": {
400 + "version": "0.27.3",
401 + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz",
402 + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==",
403 + "cpu": [
404 + "x64"
405 + ],
406 + "dev": true,
407 + "license": "MIT",
408 + "optional": true,
409 + "os": [
410 + "sunos"
411 + ],
412 + "engines": {
413 + "node": ">=18"
414 + }
415 + },
416 + "node_modules/@esbuild/win32-arm64": {
417 + "version": "0.27.3",
418 + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz",
419 + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==",
420 + "cpu": [
421 + "arm64"
422 + ],
423 + "dev": true,
424 + "license": "MIT",
425 + "optional": true,
426 + "os": [
427 + "win32"
428 + ],
429 + "engines": {
430 + "node": ">=18"
431 + }
432 + },
433 + "node_modules/@esbuild/win32-ia32": {
434 + "version": "0.27.3",
435 + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz",
436 + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==",
437 + "cpu": [
438 + "ia32"
439 + ],
440 + "dev": true,
441 + "license": "MIT",
442 + "optional": true,
443 + "os": [
444 + "win32"
445 + ],
446 + "engines": {
447 + "node": ">=18"
448 + }
449 + },
450 + "node_modules/@esbuild/win32-x64": {
451 + "version": "0.27.3",
452 + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz",
453 + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==",
454 + "cpu": [
455 + "x64"
456 + ],
457 + "dev": true,
458 + "license": "MIT",
459 + "optional": true,
460 + "os": [
461 + "win32"
462 + ],
463 + "engines": {
464 + "node": ">=18"
465 + }
466 + },
467 + "node_modules/@jridgewell/gen-mapping": {
468 + "version": "0.3.13",
469 + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
470 + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
471 + "dev": true,
472 + "license": "MIT",
473 + "dependencies": {
474 + "@jridgewell/sourcemap-codec": "^1.5.0",
475 + "@jridgewell/trace-mapping": "^0.3.24"
476 + }
477 + },
478 + "node_modules/@jridgewell/remapping": {
479 + "version": "2.3.5",
480 + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
481 + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
482 + "dev": true,
483 + "license": "MIT",
484 + "dependencies": {
485 + "@jridgewell/gen-mapping": "^0.3.5",
486 + "@jridgewell/trace-mapping": "^0.3.24"
487 + }
488 + },
489 + "node_modules/@jridgewell/resolve-uri": {
490 + "version": "3.1.2",
491 + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
492 + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
493 + "dev": true,
494 + "license": "MIT",
495 + "engines": {
496 + "node": ">=6.0.0"
497 + }
498 + },
499 + "node_modules/@jridgewell/sourcemap-codec": {
500 + "version": "1.5.5",
501 + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
502 + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
503 + "dev": true,
504 + "license": "MIT"
505 + },
506 + "node_modules/@jridgewell/trace-mapping": {
507 + "version": "0.3.31",
508 + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
509 + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
510 + "dev": true,
511 + "license": "MIT",
512 + "dependencies": {
513 + "@jridgewell/resolve-uri": "^3.1.0",
514 + "@jridgewell/sourcemap-codec": "^1.4.14"
515 + }
516 + },
517 + "node_modules/@polka/url": {
518 + "version": "1.0.0-next.29",
519 + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz",
520 + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==",
521 + "dev": true,
522 + "license": "MIT"
523 + },
524 + "node_modules/@rollup/rollup-android-arm-eabi": {
525 + "version": "4.59.0",
526 + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz",
527 + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==",
528 + "cpu": [
529 + "arm"
530 + ],
531 + "dev": true,
532 + "license": "MIT",
533 + "optional": true,
534 + "os": [
535 + "android"
536 + ]
537 + },
538 + "node_modules/@rollup/rollup-android-arm64": {
539 + "version": "4.59.0",
540 + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz",
541 + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==",
542 + "cpu": [
543 + "arm64"
544 + ],
545 + "dev": true,
546 + "license": "MIT",
547 + "optional": true,
548 + "os": [
549 + "android"
550 + ]
551 + },
552 + "node_modules/@rollup/rollup-darwin-arm64": {
553 + "version": "4.59.0",
554 + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz",
555 + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==",
556 + "cpu": [
557 + "arm64"
558 + ],
559 + "dev": true,
560 + "license": "MIT",
561 + "optional": true,
562 + "os": [
563 + "darwin"
564 + ]
565 + },
566 + "node_modules/@rollup/rollup-darwin-x64": {
567 + "version": "4.59.0",
568 + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz",
569 + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==",
570 + "cpu": [
571 + "x64"
572 + ],
573 + "dev": true,
574 + "license": "MIT",
575 + "optional": true,
576 + "os": [
577 + "darwin"
578 + ]
579 + },
580 + "node_modules/@rollup/rollup-freebsd-arm64": {
581 + "version": "4.59.0",
582 + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz",
583 + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==",
584 + "cpu": [
585 + "arm64"
586 + ],
587 + "dev": true,
588 + "license": "MIT",
589 + "optional": true,
590 + "os": [
591 + "freebsd"
592 + ]
593 + },
594 + "node_modules/@rollup/rollup-freebsd-x64": {
595 + "version": "4.59.0",
596 + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz",
597 + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==",
598 + "cpu": [
599 + "x64"
600 + ],
601 + "dev": true,
602 + "license": "MIT",
603 + "optional": true,
604 + "os": [
605 + "freebsd"
606 + ]
607 + },
608 + "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
609 + "version": "4.59.0",
610 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz",
611 + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==",
612 + "cpu": [
613 + "arm"
614 + ],
615 + "dev": true,
616 + "license": "MIT",
617 + "optional": true,
618 + "os": [
619 + "linux"
620 + ]
621 + },
622 + "node_modules/@rollup/rollup-linux-arm-musleabihf": {
623 + "version": "4.59.0",
624 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz",
625 + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==",
626 + "cpu": [
627 + "arm"
628 + ],
629 + "dev": true,
630 + "license": "MIT",
631 + "optional": true,
632 + "os": [
633 + "linux"
634 + ]
635 + },
636 + "node_modules/@rollup/rollup-linux-arm64-gnu": {
637 + "version": "4.59.0",
638 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz",
639 + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==",
640 + "cpu": [
641 + "arm64"
642 + ],
643 + "dev": true,
644 + "license": "MIT",
645 + "optional": true,
646 + "os": [
647 + "linux"
648 + ]
649 + },
650 + "node_modules/@rollup/rollup-linux-arm64-musl": {
651 + "version": "4.59.0",
652 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz",
653 + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==",
654 + "cpu": [
655 + "arm64"
656 + ],
657 + "dev": true,
658 + "license": "MIT",
659 + "optional": true,
660 + "os": [
661 + "linux"
662 + ]
663 + },
664 + "node_modules/@rollup/rollup-linux-loong64-gnu": {
665 + "version": "4.59.0",
666 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz",
667 + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==",
668 + "cpu": [
669 + "loong64"
670 + ],
671 + "dev": true,
672 + "license": "MIT",
673 + "optional": true,
674 + "os": [
675 + "linux"
676 + ]
677 + },
678 + "node_modules/@rollup/rollup-linux-loong64-musl": {
679 + "version": "4.59.0",
680 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz",
681 + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==",
682 + "cpu": [
683 + "loong64"
684 + ],
685 + "dev": true,
686 + "license": "MIT",
687 + "optional": true,
688 + "os": [
689 + "linux"
690 + ]
691 + },
692 + "node_modules/@rollup/rollup-linux-ppc64-gnu": {
693 + "version": "4.59.0",
694 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz",
695 + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==",
696 + "cpu": [
697 + "ppc64"
698 + ],
699 + "dev": true,
700 + "license": "MIT",
701 + "optional": true,
702 + "os": [
703 + "linux"
704 + ]
705 + },
706 + "node_modules/@rollup/rollup-linux-ppc64-musl": {
707 + "version": "4.59.0",
708 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz",
709 + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==",
710 + "cpu": [
711 + "ppc64"
712 + ],
713 + "dev": true,
714 + "license": "MIT",
715 + "optional": true,
716 + "os": [
717 + "linux"
718 + ]
719 + },
720 + "node_modules/@rollup/rollup-linux-riscv64-gnu": {
721 + "version": "4.59.0",
722 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz",
723 + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==",
724 + "cpu": [
725 + "riscv64"
726 + ],
727 + "dev": true,
728 + "license": "MIT",
729 + "optional": true,
730 + "os": [
731 + "linux"
732 + ]
733 + },
734 + "node_modules/@rollup/rollup-linux-riscv64-musl": {
735 + "version": "4.59.0",
736 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz",
737 + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==",
738 + "cpu": [
739 + "riscv64"
740 + ],
741 + "dev": true,
742 + "license": "MIT",
743 + "optional": true,
744 + "os": [
745 + "linux"
746 + ]
747 + },
748 + "node_modules/@rollup/rollup-linux-s390x-gnu": {
749 + "version": "4.59.0",
750 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz",
751 + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==",
752 + "cpu": [
753 + "s390x"
754 + ],
755 + "dev": true,
756 + "license": "MIT",
757 + "optional": true,
758 + "os": [
759 + "linux"
760 + ]
761 + },
762 + "node_modules/@rollup/rollup-linux-x64-gnu": {
763 + "version": "4.59.0",
764 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz",
765 + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==",
766 + "cpu": [
767 + "x64"
768 + ],
769 + "dev": true,
770 + "license": "MIT",
771 + "optional": true,
772 + "os": [
773 + "linux"
774 + ]
775 + },
776 + "node_modules/@rollup/rollup-linux-x64-musl": {
777 + "version": "4.59.0",
778 + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz",
779 + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==",
780 + "cpu": [
781 + "x64"
782 + ],
783 + "dev": true,
784 + "license": "MIT",
785 + "optional": true,
786 + "os": [
787 + "linux"
788 + ]
789 + },
790 + "node_modules/@rollup/rollup-openbsd-x64": {
791 + "version": "4.59.0",
792 + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz",
793 + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==",
794 + "cpu": [
795 + "x64"
796 + ],
797 + "dev": true,
798 + "license": "MIT",
799 + "optional": true,
800 + "os": [
801 + "openbsd"
802 + ]
803 + },
804 + "node_modules/@rollup/rollup-openharmony-arm64": {
805 + "version": "4.59.0",
806 + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz",
807 + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==",
808 + "cpu": [
809 + "arm64"
810 + ],
811 + "dev": true,
812 + "license": "MIT",
813 + "optional": true,
814 + "os": [
815 + "openharmony"
816 + ]
817 + },
818 + "node_modules/@rollup/rollup-win32-arm64-msvc": {
819 + "version": "4.59.0",
820 + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz",
821 + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==",
822 + "cpu": [
823 + "arm64"
824 + ],
825 + "dev": true,
826 + "license": "MIT",
827 + "optional": true,
828 + "os": [
829 + "win32"
830 + ]
831 + },
832 + "node_modules/@rollup/rollup-win32-ia32-msvc": {
833 + "version": "4.59.0",
834 + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz",
835 + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==",
836 + "cpu": [
837 + "ia32"
838 + ],
839 + "dev": true,
840 + "license": "MIT",
841 + "optional": true,
842 + "os": [
843 + "win32"
844 + ]
845 + },
846 + "node_modules/@rollup/rollup-win32-x64-gnu": {
847 + "version": "4.59.0",
848 + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz",
849 + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==",
850 + "cpu": [
851 + "x64"
852 + ],
853 + "dev": true,
854 + "license": "MIT",
855 + "optional": true,
856 + "os": [
857 + "win32"
858 + ]
859 + },
860 + "node_modules/@rollup/rollup-win32-x64-msvc": {
861 + "version": "4.59.0",
862 + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz",
863 + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==",
864 + "cpu": [
865 + "x64"
866 + ],
867 + "dev": true,
868 + "license": "MIT",
869 + "optional": true,
870 + "os": [
871 + "win32"
872 + ]
873 + },
874 + "node_modules/@standard-schema/spec": {
875 + "version": "1.1.0",
876 + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz",
877 + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==",
878 + "dev": true,
879 + "license": "MIT"
880 + },
881 + "node_modules/@supabase/auth-js": {
882 + "version": "2.98.0",
883 + "resolved": "https://registry.npmjs.org/@supabase/auth-js/-/auth-js-2.98.0.tgz",
884 + "integrity": "sha512-GBH361T0peHU91AQNzOlIrjUZw9TZbB9YDRiyFgk/3Kvr3/Z1NWUZ2athWTfHhwNNi8IrW00foyFxQD9IO/Trg==",
885 + "license": "MIT",
886 + "dependencies": {
887 + "tslib": "2.8.1"
888 + },
889 + "engines": {
890 + "node": ">=20.0.0"
891 + }
892 + },
893 + "node_modules/@supabase/functions-js": {
894 + "version": "2.98.0",
895 + "resolved": "https://registry.npmjs.org/@supabase/functions-js/-/functions-js-2.98.0.tgz",
896 + "integrity": "sha512-N/xEyiNU5Org+d+PNCpv+TWniAXRzxIURxDYsS/m2I/sfAB/HcM9aM2Dmf5edj5oWb9GxID1OBaZ8NMmPXL+Lg==",
897 + "license": "MIT",
898 + "dependencies": {
899 + "tslib": "2.8.1"
900 + },
901 + "engines": {
902 + "node": ">=20.0.0"
903 + }
904 + },
905 + "node_modules/@supabase/postgrest-js": {
906 + "version": "2.98.0",
907 + "resolved": "https://registry.npmjs.org/@supabase/postgrest-js/-/postgrest-js-2.98.0.tgz",
908 + "integrity": "sha512-v6e9WeZuJijzUut8HyXu6gMqWFepIbaeaMIm1uKzei4yLg9bC9OtEW9O14LE/9ezqNbSAnSLO5GtOLFdm7Bpkg==",
909 + "license": "MIT",
910 + "dependencies": {
911 + "tslib": "2.8.1"
912 + },
913 + "engines": {
914 + "node": ">=20.0.0"
915 + }
916 + },
917 + "node_modules/@supabase/realtime-js": {
918 + "version": "2.98.0",
919 + "resolved": "https://registry.npmjs.org/@supabase/realtime-js/-/realtime-js-2.98.0.tgz",
920 + "integrity": "sha512-rOWt28uGyFipWOSd+n0WVMr9kUXiWaa7J4hvyLCIHjRFqWm1z9CaaKAoYyfYMC1Exn3WT8WePCgiVhlAtWC2yw==",
921 + "license": "MIT",
922 + "dependencies": {
923 + "@types/phoenix": "^1.6.6",
924 + "@types/ws": "^8.18.1",
925 + "tslib": "2.8.1",
926 + "ws": "^8.18.2"
927 + },
928 + "engines": {
929 + "node": ">=20.0.0"
930 + }
931 + },
932 + "node_modules/@supabase/storage-js": {
933 + "version": "2.98.0",
934 + "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.98.0.tgz",
935 + "integrity": "sha512-tzr2mG+v7ILSAZSfZMSL9OPyIH4z1ikgQ8EcQTKfMRz4EwmlFt3UnJaGzSOxyvF5b+fc9So7qdSUWTqGgeLokQ==",
936 + "license": "MIT",
937 + "dependencies": {
938 + "iceberg-js": "^0.8.1",
939 + "tslib": "2.8.1"
940 + },
941 + "engines": {
942 + "node": ">=20.0.0"
943 + }
944 + },
945 + "node_modules/@supabase/supabase-js": {
946 + "version": "2.98.0",
947 + "resolved": "https://registry.npmjs.org/@supabase/supabase-js/-/supabase-js-2.98.0.tgz",
948 + "integrity": "sha512-Ohc97CtInLwZyiSASz7tT9/Abm/vqnIbO9REp+PivVUII8UZsuI3bngRQnYgJdFoOIwvaEII1fX1qy8x0CyNiw==",
949 + "license": "MIT",
950 + "dependencies": {
951 + "@supabase/auth-js": "2.98.0",
952 + "@supabase/functions-js": "2.98.0",
953 + "@supabase/postgrest-js": "2.98.0",
954 + "@supabase/realtime-js": "2.98.0",
955 + "@supabase/storage-js": "2.98.0"
956 + },
957 + "engines": {
958 + "node": ">=20.0.0"
959 + }
960 + },
961 + "node_modules/@sveltejs/acorn-typescript": {
962 + "version": "1.0.9",
963 + "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.9.tgz",
964 + "integrity": "sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA==",
965 + "dev": true,
966 + "license": "MIT",
967 + "peerDependencies": {
968 + "acorn": "^8.9.0"
969 + }
970 + },
971 + "node_modules/@sveltejs/adapter-auto": {
972 + "version": "7.0.1",
973 + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-7.0.1.tgz",
974 + "integrity": "sha512-dvuPm1E7M9NI/+canIQ6KKQDU2AkEefEZ2Dp7cY6uKoPq9Z/PhOXABe526UdW2mN986gjVkuSLkOYIBnS/M2LQ==",
975 + "dev": true,
976 + "license": "MIT",
977 + "peerDependencies": {
978 + "@sveltejs/kit": "^2.0.0"
979 + }
980 + },
981 + "node_modules/@sveltejs/kit": {
982 + "version": "2.53.3",
983 + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.53.3.tgz",
984 + "integrity": "sha512-tshOeBUid2v5LAblUpatIdFm5Cyykbw2EiKWOunAAX0A/oJaR7DOdC9wLR5Qqh9zUf3QUISA2m9A3suBdQSYQg==",
985 + "dev": true,
986 + "license": "MIT",
987 + "dependencies": {
988 + "@standard-schema/spec": "^1.0.0",
989 + "@sveltejs/acorn-typescript": "^1.0.5",
990 + "@types/cookie": "^0.6.0",
991 + "acorn": "^8.14.1",
992 + "cookie": "^0.6.0",
993 + "devalue": "^5.6.3",
994 + "esm-env": "^1.2.2",
995 + "kleur": "^4.1.5",
996 + "magic-string": "^0.30.5",
997 + "mrmime": "^2.0.0",
998 + "set-cookie-parser": "^3.0.0",
999 + "sirv": "^3.0.0"
1000 + },
1001 + "bin": {
1002 + "svelte-kit": "svelte-kit.js"
1003 + },
1004 + "engines": {
1005 + "node": ">=18.13"
1006 + },
1007 + "peerDependencies": {
1008 + "@opentelemetry/api": "^1.0.0",
1009 + "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.0",
1010 + "svelte": "^4.0.0 || ^5.0.0-next.0",
1011 + "typescript": "^5.3.3",
1012 + "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0"
1013 + },
1014 + "peerDependenciesMeta": {
1015 + "@opentelemetry/api": {
1016 + "optional": true
1017 + },
1018 + "typescript": {
1019 + "optional": true
1020 + }
1021 + }
1022 + },
1023 + "node_modules/@sveltejs/vite-plugin-svelte": {
1024 + "version": "6.2.4",
1025 + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-6.2.4.tgz",
1026 + "integrity": "sha512-ou/d51QSdTyN26D7h6dSpusAKaZkAiGM55/AKYi+9AGZw7q85hElbjK3kEyzXHhLSnRISHOYzVge6x0jRZ7DXA==",
1027 + "dev": true,
1028 + "license": "MIT",
1029 + "dependencies": {
1030 + "@sveltejs/vite-plugin-svelte-inspector": "^5.0.0",
1031 + "deepmerge": "^4.3.1",
1032 + "magic-string": "^0.30.21",
1033 + "obug": "^2.1.0",
1034 + "vitefu": "^1.1.1"
1035 + },
1036 + "engines": {
1037 + "node": "^20.19 || ^22.12 || >=24"
1038 + },
1039 + "peerDependencies": {
1040 + "svelte": "^5.0.0",
1041 + "vite": "^6.3.0 || ^7.0.0"
1042 + }
1043 + },
1044 + "node_modules/@sveltejs/vite-plugin-svelte-inspector": {
1045 + "version": "5.0.2",
1046 + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-5.0.2.tgz",
1047 + "integrity": "sha512-TZzRTcEtZffICSAoZGkPSl6Etsj2torOVrx6Uw0KpXxrec9Gg6jFWQ60Q3+LmNGfZSxHRCZL7vXVZIWmuV50Ig==",
1048 + "dev": true,
1049 + "license": "MIT",
1050 + "dependencies": {
1051 + "obug": "^2.1.0"
1052 + },
1053 + "engines": {
1054 + "node": "^20.19 || ^22.12 || >=24"
1055 + },
1056 + "peerDependencies": {
1057 + "@sveltejs/vite-plugin-svelte": "^6.0.0-next.0",
1058 + "svelte": "^5.0.0",
1059 + "vite": "^6.3.0 || ^7.0.0"
1060 + }
1061 + },
1062 + "node_modules/@tailwindcss/node": {
1063 + "version": "4.2.1",
1064 + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.1.tgz",
1065 + "integrity": "sha512-jlx6sLk4EOwO6hHe1oCGm1Q4AN/s0rSrTTPBGPM0/RQ6Uylwq17FuU8IeJJKEjtc6K6O07zsvP+gDO6MMWo7pg==",
1066 + "dev": true,
1067 + "license": "MIT",
1068 + "dependencies": {
1069 + "@jridgewell/remapping": "^2.3.5",
1070 + "enhanced-resolve": "^5.19.0",
1071 + "jiti": "^2.6.1",
1072 + "lightningcss": "1.31.1",
1073 + "magic-string": "^0.30.21",
1074 + "source-map-js": "^1.2.1",
1075 + "tailwindcss": "4.2.1"
1076 + }
1077 + },
1078 + "node_modules/@tailwindcss/oxide": {
1079 + "version": "4.2.1",
1080 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.1.tgz",
1081 + "integrity": "sha512-yv9jeEFWnjKCI6/T3Oq50yQEOqmpmpfzG1hcZsAOaXFQPfzWprWrlHSdGPEF3WQTi8zu8ohC9Mh9J470nT5pUw==",
1082 + "dev": true,
1083 + "license": "MIT",
1084 + "engines": {
1085 + "node": ">= 20"
1086 + },
1087 + "optionalDependencies": {
1088 + "@tailwindcss/oxide-android-arm64": "4.2.1",
1089 + "@tailwindcss/oxide-darwin-arm64": "4.2.1",
1090 + "@tailwindcss/oxide-darwin-x64": "4.2.1",
1091 + "@tailwindcss/oxide-freebsd-x64": "4.2.1",
1092 + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.1",
1093 + "@tailwindcss/oxide-linux-arm64-gnu": "4.2.1",
1094 + "@tailwindcss/oxide-linux-arm64-musl": "4.2.1",
1095 + "@tailwindcss/oxide-linux-x64-gnu": "4.2.1",
1096 + "@tailwindcss/oxide-linux-x64-musl": "4.2.1",
1097 + "@tailwindcss/oxide-wasm32-wasi": "4.2.1",
1098 + "@tailwindcss/oxide-win32-arm64-msvc": "4.2.1",
1099 + "@tailwindcss/oxide-win32-x64-msvc": "4.2.1"
1100 + }
1101 + },
1102 + "node_modules/@tailwindcss/oxide-android-arm64": {
1103 + "version": "4.2.1",
1104 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.1.tgz",
1105 + "integrity": "sha512-eZ7G1Zm5EC8OOKaesIKuw77jw++QJ2lL9N+dDpdQiAB/c/B2wDh0QPFHbkBVrXnwNugvrbJFk1gK2SsVjwWReg==",
1106 + "cpu": [
1107 + "arm64"
1108 + ],
1109 + "dev": true,
1110 + "license": "MIT",
1111 + "optional": true,
1112 + "os": [
1113 + "android"
1114 + ],
1115 + "engines": {
1116 + "node": ">= 20"
1117 + }
1118 + },
1119 + "node_modules/@tailwindcss/oxide-darwin-arm64": {
1120 + "version": "4.2.1",
1121 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.2.1.tgz",
1122 + "integrity": "sha512-q/LHkOstoJ7pI1J0q6djesLzRvQSIfEto148ppAd+BVQK0JYjQIFSK3JgYZJa+Yzi0DDa52ZsQx2rqytBnf8Hw==",
1123 + "cpu": [
1124 + "arm64"
1125 + ],
1126 + "dev": true,
1127 + "license": "MIT",
1128 + "optional": true,
1129 + "os": [
1130 + "darwin"
1131 + ],
1132 + "engines": {
1133 + "node": ">= 20"
1134 + }
1135 + },
1136 + "node_modules/@tailwindcss/oxide-darwin-x64": {
1137 + "version": "4.2.1",
1138 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.2.1.tgz",
1139 + "integrity": "sha512-/f/ozlaXGY6QLbpvd/kFTro2l18f7dHKpB+ieXz+Cijl4Mt9AI2rTrpq7V+t04nK+j9XBQHnSMdeQRhbGyt6fw==",
1140 + "cpu": [
1141 + "x64"
1142 + ],
1143 + "dev": true,
1144 + "license": "MIT",
1145 + "optional": true,
1146 + "os": [
1147 + "darwin"
1148 + ],
1149 + "engines": {
1150 + "node": ">= 20"
1151 + }
1152 + },
1153 + "node_modules/@tailwindcss/oxide-freebsd-x64": {
1154 + "version": "4.2.1",
1155 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.2.1.tgz",
1156 + "integrity": "sha512-5e/AkgYJT/cpbkys/OU2Ei2jdETCLlifwm7ogMC7/hksI2fC3iiq6OcXwjibcIjPung0kRtR3TxEITkqgn0TcA==",
1157 + "cpu": [
1158 + "x64"
1159 + ],
1160 + "dev": true,
1161 + "license": "MIT",
1162 + "optional": true,
1163 + "os": [
1164 + "freebsd"
1165 + ],
1166 + "engines": {
1167 + "node": ">= 20"
1168 + }
1169 + },
1170 + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
1171 + "version": "4.2.1",
1172 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.2.1.tgz",
1173 + "integrity": "sha512-Uny1EcVTTmerCKt/1ZuKTkb0x8ZaiuYucg2/kImO5A5Y/kBz41/+j0gxUZl+hTF3xkWpDmHX+TaWhOtba2Fyuw==",
1174 + "cpu": [
1175 + "arm"
1176 + ],
1177 + "dev": true,
1178 + "license": "MIT",
1179 + "optional": true,
1180 + "os": [
1181 + "linux"
1182 + ],
1183 + "engines": {
1184 + "node": ">= 20"
1185 + }
1186 + },
1187 + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
1188 + "version": "4.2.1",
1189 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.2.1.tgz",
1190 + "integrity": "sha512-CTrwomI+c7n6aSSQlsPL0roRiNMDQ/YzMD9EjcR+H4f0I1SQ8QqIuPnsVp7QgMkC1Qi8rtkekLkOFjo7OlEFRQ==",
1191 + "cpu": [
1192 + "arm64"
1193 + ],
1194 + "dev": true,
1195 + "license": "MIT",
1196 + "optional": true,
1197 + "os": [
1198 + "linux"
1199 + ],
1200 + "engines": {
1201 + "node": ">= 20"
1202 + }
1203 + },
1204 + "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
1205 + "version": "4.2.1",
1206 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.2.1.tgz",
1207 + "integrity": "sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==",
1208 + "cpu": [
1209 + "arm64"
1210 + ],
1211 + "dev": true,
1212 + "license": "MIT",
1213 + "optional": true,
1214 + "os": [
1215 + "linux"
1216 + ],
1217 + "engines": {
1218 + "node": ">= 20"
1219 + }
1220 + },
1221 + "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
1222 + "version": "4.2.1",
1223 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.2.1.tgz",
1224 + "integrity": "sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==",
1225 + "cpu": [
1226 + "x64"
1227 + ],
1228 + "dev": true,
1229 + "license": "MIT",
1230 + "optional": true,
1231 + "os": [
1232 + "linux"
1233 + ],
1234 + "engines": {
1235 + "node": ">= 20"
1236 + }
1237 + },
1238 + "node_modules/@tailwindcss/oxide-linux-x64-musl": {
1239 + "version": "4.2.1",
1240 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.2.1.tgz",
1241 + "integrity": "sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==",
1242 + "cpu": [
1243 + "x64"
1244 + ],
1245 + "dev": true,
1246 + "license": "MIT",
1247 + "optional": true,
1248 + "os": [
1249 + "linux"
1250 + ],
1251 + "engines": {
1252 + "node": ">= 20"
1253 + }
1254 + },
1255 + "node_modules/@tailwindcss/oxide-wasm32-wasi": {
1256 + "version": "4.2.1",
1257 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.2.1.tgz",
1258 + "integrity": "sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==",
1259 + "bundleDependencies": [
1260 + "@napi-rs/wasm-runtime",
1261 + "@emnapi/core",
1262 + "@emnapi/runtime",
1263 + "@tybys/wasm-util",
1264 + "@emnapi/wasi-threads",
1265 + "tslib"
1266 + ],
1267 + "cpu": [
1268 + "wasm32"
1269 + ],
1270 + "dev": true,
1271 + "license": "MIT",
1272 + "optional": true,
1273 + "dependencies": {
1274 + "@emnapi/core": "^1.8.1",
1275 + "@emnapi/runtime": "^1.8.1",
1276 + "@emnapi/wasi-threads": "^1.1.0",
1277 + "@napi-rs/wasm-runtime": "^1.1.1",
1278 + "@tybys/wasm-util": "^0.10.1",
1279 + "tslib": "^2.8.1"
1280 + },
1281 + "engines": {
1282 + "node": ">=14.0.0"
1283 + }
1284 + },
1285 + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
1286 + "version": "4.2.1",
1287 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.2.1.tgz",
1288 + "integrity": "sha512-YlUEHRHBGnCMh4Nj4GnqQyBtsshUPdiNroZj8VPkvTZSoHsilRCwXcVKnG9kyi0ZFAS/3u+qKHBdDc81SADTRA==",
1289 + "cpu": [
1290 + "arm64"
1291 + ],
1292 + "dev": true,
1293 + "license": "MIT",
1294 + "optional": true,
1295 + "os": [
1296 + "win32"
1297 + ],
1298 + "engines": {
1299 + "node": ">= 20"
1300 + }
1301 + },
1302 + "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
1303 + "version": "4.2.1",
1304 + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.2.1.tgz",
1305 + "integrity": "sha512-rbO34G5sMWWyrN/idLeVxAZgAKWrn5LiR3/I90Q9MkA67s6T1oB0xtTe+0heoBvHSpbU9Mk7i6uwJnpo4u21XQ==",
1306 + "cpu": [
1307 + "x64"
1308 + ],
1309 + "dev": true,
1310 + "license": "MIT",
1311 + "optional": true,
1312 + "os": [
1313 + "win32"
1314 + ],
1315 + "engines": {
1316 + "node": ">= 20"
1317 + }
1318 + },
1319 + "node_modules/@tailwindcss/vite": {
1320 + "version": "4.2.1",
1321 + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.2.1.tgz",
1322 + "integrity": "sha512-TBf2sJjYeb28jD2U/OhwdW0bbOsxkWPwQ7SrqGf9sVcoYwZj7rkXljroBO9wKBut9XnmQLXanuDUeqQK0lGg/w==",
1323 + "dev": true,
1324 + "license": "MIT",
1325 + "dependencies": {
1326 + "@tailwindcss/node": "4.2.1",
1327 + "@tailwindcss/oxide": "4.2.1",
1328 + "tailwindcss": "4.2.1"
1329 + },
1330 + "peerDependencies": {
1331 + "vite": "^5.2.0 || ^6 || ^7"
1332 + }
1333 + },
1334 + "node_modules/@types/cookie": {
1335 + "version": "0.6.0",
1336 + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz",
1337 + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==",
1338 + "dev": true,
1339 + "license": "MIT"
1340 + },
1341 + "node_modules/@types/estree": {
1342 + "version": "1.0.8",
1343 + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
1344 + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
1345 + "dev": true,
1346 + "license": "MIT"
1347 + },
1348 + "node_modules/@types/node": {
1349 + "version": "25.3.2",
1350 + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.2.tgz",
1351 + "integrity": "sha512-RpV6r/ij22zRRdyBPcxDeKAzH43phWVKEjL2iksqo1Vz3CuBUrgmPpPhALKiRfU7OMCmeeO9vECBMsV0hMTG8Q==",
1352 + "license": "MIT",
1353 + "dependencies": {
1354 + "undici-types": "~7.18.0"
1355 + }
1356 + },
1357 + "node_modules/@types/phoenix": {
1358 + "version": "1.6.7",
1359 + "resolved": "https://registry.npmjs.org/@types/phoenix/-/phoenix-1.6.7.tgz",
1360 + "integrity": "sha512-oN9ive//QSBkf19rfDv45M7eZPi0eEXylht2OLEXicu5b4KoQ1OzXIw+xDSGWxSxe1JmepRR/ZH283vsu518/Q==",
1361 + "license": "MIT"
1362 + },
1363 + "node_modules/@types/trusted-types": {
1364 + "version": "2.0.7",
1365 + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
1366 + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==",
1367 + "dev": true,
1368 + "license": "MIT"
1369 + },
1370 + "node_modules/@types/ws": {
1371 + "version": "8.18.1",
1372 + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
1373 + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
1374 + "license": "MIT",
1375 + "dependencies": {
1376 + "@types/node": "*"
1377 + }
1378 + },
1379 + "node_modules/acorn": {
1380 + "version": "8.16.0",
1381 + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz",
1382 + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
1383 + "dev": true,
1384 + "license": "MIT",
1385 + "bin": {
1386 + "acorn": "bin/acorn"
1387 + },
1388 + "engines": {
1389 + "node": ">=0.4.0"
1390 + }
1391 + },
1392 + "node_modules/aria-query": {
1393 + "version": "5.3.1",
1394 + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.1.tgz",
1395 + "integrity": "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==",
1396 + "dev": true,
1397 + "license": "Apache-2.0",
1398 + "engines": {
1399 + "node": ">= 0.4"
1400 + }
1401 + },
1402 + "node_modules/axobject-query": {
1403 + "version": "4.1.0",
1404 + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
1405 + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
1406 + "dev": true,
1407 + "license": "Apache-2.0",
1408 + "engines": {
1409 + "node": ">= 0.4"
1410 + }
1411 + },
1412 + "node_modules/clsx": {
1413 + "version": "2.1.1",
1414 + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
1415 + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
1416 + "dev": true,
1417 + "license": "MIT",
1418 + "engines": {
1419 + "node": ">=6"
1420 + }
1421 + },
1422 + "node_modules/commander": {
1423 + "version": "7.2.0",
1424 + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
1425 + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
1426 + "license": "MIT",
1427 + "engines": {
1428 + "node": ">= 10"
1429 + }
1430 + },
1431 + "node_modules/cookie": {
1432 + "version": "0.6.0",
1433 + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
1434 + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
1435 + "dev": true,
1436 + "license": "MIT",
1437 + "engines": {
1438 + "node": ">= 0.6"
1439 + }
1440 + },
1441 + "node_modules/d3": {
1442 + "version": "7.9.0",
1443 + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz",
1444 + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==",
1445 + "license": "ISC",
1446 + "dependencies": {
1447 + "d3-array": "3",
1448 + "d3-axis": "3",
1449 + "d3-brush": "3",
1450 + "d3-chord": "3",
1451 + "d3-color": "3",
1452 + "d3-contour": "4",
1453 + "d3-delaunay": "6",
1454 + "d3-dispatch": "3",
1455 + "d3-drag": "3",
1456 + "d3-dsv": "3",
1457 + "d3-ease": "3",
1458 + "d3-fetch": "3",
1459 + "d3-force": "3",
1460 + "d3-format": "3",
1461 + "d3-geo": "3",
1462 + "d3-hierarchy": "3",
1463 + "d3-interpolate": "3",
1464 + "d3-path": "3",
1465 + "d3-polygon": "3",
1466 + "d3-quadtree": "3",
1467 + "d3-random": "3",
1468 + "d3-scale": "4",
1469 + "d3-scale-chromatic": "3",
1470 + "d3-selection": "3",
1471 + "d3-shape": "3",
1472 + "d3-time": "3",
1473 + "d3-time-format": "4",
1474 + "d3-timer": "3",
1475 + "d3-transition": "3",
1476 + "d3-zoom": "3"
1477 + },
1478 + "engines": {
1479 + "node": ">=12"
1480 + }
1481 + },
1482 + "node_modules/d3-array": {
1483 + "version": "3.2.4",
1484 + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz",
1485 + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==",
1486 + "license": "ISC",
1487 + "dependencies": {
1488 + "internmap": "1 - 2"
1489 + },
1490 + "engines": {
1491 + "node": ">=12"
1492 + }
1493 + },
1494 + "node_modules/d3-axis": {
1495 + "version": "3.0.0",
1496 + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz",
1497 + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==",
1498 + "license": "ISC",
1499 + "engines": {
1500 + "node": ">=12"
1501 + }
1502 + },
1503 + "node_modules/d3-brush": {
1504 + "version": "3.0.0",
1505 + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz",
1506 + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==",
1507 + "license": "ISC",
1508 + "dependencies": {
1509 + "d3-dispatch": "1 - 3",
1510 + "d3-drag": "2 - 3",
1511 + "d3-interpolate": "1 - 3",
1512 + "d3-selection": "3",
1513 + "d3-transition": "3"
1514 + },
1515 + "engines": {
1516 + "node": ">=12"
1517 + }
1518 + },
1519 + "node_modules/d3-chord": {
1520 + "version": "3.0.1",
1521 + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz",
1522 + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==",
1523 + "license": "ISC",
1524 + "dependencies": {
1525 + "d3-path": "1 - 3"
1526 + },
1527 + "engines": {
1528 + "node": ">=12"
1529 + }
1530 + },
1531 + "node_modules/d3-color": {
1532 + "version": "3.1.0",
1533 + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
1534 + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
1535 + "license": "ISC",
1536 + "engines": {
1537 + "node": ">=12"
1538 + }
1539 + },
1540 + "node_modules/d3-contour": {
1541 + "version": "4.0.2",
1542 + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz",
1543 + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==",
1544 + "license": "ISC",
1545 + "dependencies": {
1546 + "d3-array": "^3.2.0"
1547 + },
1548 + "engines": {
1549 + "node": ">=12"
1550 + }
1551 + },
1552 + "node_modules/d3-delaunay": {
1553 + "version": "6.0.4",
1554 + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz",
1555 + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==",
1556 + "license": "ISC",
1557 + "dependencies": {
1558 + "delaunator": "5"
1559 + },
1560 + "engines": {
1561 + "node": ">=12"
1562 + }
1563 + },
1564 + "node_modules/d3-dispatch": {
1565 + "version": "3.0.1",
1566 + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz",
1567 + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==",
1568 + "license": "ISC",
1569 + "engines": {
1570 + "node": ">=12"
1571 + }
1572 + },
1573 + "node_modules/d3-drag": {
1574 + "version": "3.0.0",
1575 + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz",
1576 + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==",
1577 + "license": "ISC",
1578 + "dependencies": {
1579 + "d3-dispatch": "1 - 3",
1580 + "d3-selection": "3"
1581 + },
1582 + "engines": {
1583 + "node": ">=12"
1584 + }
1585 + },
1586 + "node_modules/d3-dsv": {
1587 + "version": "3.0.1",
1588 + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz",
1589 + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==",
1590 + "license": "ISC",
1591 + "dependencies": {
1592 + "commander": "7",
1593 + "iconv-lite": "0.6",
1594 + "rw": "1"
1595 + },
1596 + "bin": {
1597 + "csv2json": "bin/dsv2json.js",
1598 + "csv2tsv": "bin/dsv2dsv.js",
1599 + "dsv2dsv": "bin/dsv2dsv.js",
1600 + "dsv2json": "bin/dsv2json.js",
1601 + "json2csv": "bin/json2dsv.js",
1602 + "json2dsv": "bin/json2dsv.js",
1603 + "json2tsv": "bin/json2dsv.js",
1604 + "tsv2csv": "bin/dsv2dsv.js",
1605 + "tsv2json": "bin/dsv2json.js"
1606 + },
1607 + "engines": {
1608 + "node": ">=12"
1609 + }
1610 + },
1611 + "node_modules/d3-ease": {
1612 + "version": "3.0.1",
1613 + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
1614 + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
1615 + "license": "BSD-3-Clause",
1616 + "engines": {
1617 + "node": ">=12"
1618 + }
1619 + },
1620 + "node_modules/d3-fetch": {
1621 + "version": "3.0.1",
1622 + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz",
1623 + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==",
1624 + "license": "ISC",
1625 + "dependencies": {
1626 + "d3-dsv": "1 - 3"
1627 + },
1628 + "engines": {
1629 + "node": ">=12"
1630 + }
1631 + },
1632 + "node_modules/d3-force": {
1633 + "version": "3.0.0",
1634 + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
1635 + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==",
1636 + "license": "ISC",
1637 + "dependencies": {
1638 + "d3-dispatch": "1 - 3",
1639 + "d3-quadtree": "1 - 3",
1640 + "d3-timer": "1 - 3"
1641 + },
1642 + "engines": {
1643 + "node": ">=12"
1644 + }
1645 + },
1646 + "node_modules/d3-format": {
1647 + "version": "3.1.2",
1648 + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz",
1649 + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==",
1650 + "license": "ISC",
1651 + "engines": {
1652 + "node": ">=12"
1653 + }
1654 + },
1655 + "node_modules/d3-geo": {
1656 + "version": "3.1.1",
1657 + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz",
1658 + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==",
1659 + "license": "ISC",
1660 + "dependencies": {
1661 + "d3-array": "2.5.0 - 3"
1662 + },
1663 + "engines": {
1664 + "node": ">=12"
1665 + }
1666 + },
1667 + "node_modules/d3-hierarchy": {
1668 + "version": "3.1.2",
1669 + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz",
1670 + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==",
1671 + "license": "ISC",
1672 + "engines": {
1673 + "node": ">=12"
1674 + }
1675 + },
1676 + "node_modules/d3-interpolate": {
1677 + "version": "3.0.1",
1678 + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
1679 + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
1680 + "license": "ISC",
1681 + "dependencies": {
1682 + "d3-color": "1 - 3"
1683 + },
1684 + "engines": {
1685 + "node": ">=12"
1686 + }
1687 + },
1688 + "node_modules/d3-path": {
1689 + "version": "3.1.0",
1690 + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz",
1691 + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==",
1692 + "license": "ISC",
1693 + "engines": {
1694 + "node": ">=12"
1695 + }
1696 + },
1697 + "node_modules/d3-polygon": {
1698 + "version": "3.0.1",
1699 + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz",
1700 + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==",
1701 + "license": "ISC",
1702 + "engines": {
1703 + "node": ">=12"
1704 + }
1705 + },
1706 + "node_modules/d3-quadtree": {
1707 + "version": "3.0.1",
1708 + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz",
1709 + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==",
1710 + "license": "ISC",
1711 + "engines": {
1712 + "node": ">=12"
1713 + }
1714 + },
1715 + "node_modules/d3-random": {
1716 + "version": "3.0.1",
1717 + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz",
1718 + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==",
1719 + "license": "ISC",
1720 + "engines": {
1721 + "node": ">=12"
1722 + }
1723 + },
1724 + "node_modules/d3-scale": {
1725 + "version": "4.0.2",
1726 + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
1727 + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
1728 + "license": "ISC",
1729 + "dependencies": {
1730 + "d3-array": "2.10.0 - 3",
1731 + "d3-format": "1 - 3",
1732 + "d3-interpolate": "1.2.0 - 3",
1733 + "d3-time": "2.1.1 - 3",
1734 + "d3-time-format": "2 - 4"
1735 + },
1736 + "engines": {
1737 + "node": ">=12"
1738 + }
1739 + },
1740 + "node_modules/d3-scale-chromatic": {
1741 + "version": "3.1.0",
1742 + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz",
1743 + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==",
1744 + "license": "ISC",
1745 + "dependencies": {
1746 + "d3-color": "1 - 3",
1747 + "d3-interpolate": "1 - 3"
1748 + },
1749 + "engines": {
1750 + "node": ">=12"
1751 + }
1752 + },
1753 + "node_modules/d3-selection": {
1754 + "version": "3.0.0",
1755 + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
1756 + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
1757 + "license": "ISC",
1758 + "engines": {
1759 + "node": ">=12"
1760 + }
1761 + },
1762 + "node_modules/d3-shape": {
1763 + "version": "3.2.0",
1764 + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz",
1765 + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==",
1766 + "license": "ISC",
1767 + "dependencies": {
1768 + "d3-path": "^3.1.0"
1769 + },
1770 + "engines": {
1771 + "node": ">=12"
1772 + }
1773 + },
1774 + "node_modules/d3-time": {
1775 + "version": "3.1.0",
1776 + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz",
1777 + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==",
1778 + "license": "ISC",
1779 + "dependencies": {
1780 + "d3-array": "2 - 3"
1781 + },
1782 + "engines": {
1783 + "node": ">=12"
1784 + }
1785 + },
1786 + "node_modules/d3-time-format": {
1787 + "version": "4.1.0",
1788 + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
1789 + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
1790 + "license": "ISC",
1791 + "dependencies": {
1792 + "d3-time": "1 - 3"
1793 + },
1794 + "engines": {
1795 + "node": ">=12"
1796 + }
1797 + },
1798 + "node_modules/d3-timer": {
1799 + "version": "3.0.1",
1800 + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
1801 + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
1802 + "license": "ISC",
1803 + "engines": {
1804 + "node": ">=12"
1805 + }
1806 + },
1807 + "node_modules/d3-transition": {
1808 + "version": "3.0.1",
1809 + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz",
1810 + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==",
1811 + "license": "ISC",
1812 + "dependencies": {
1813 + "d3-color": "1 - 3",
1814 + "d3-dispatch": "1 - 3",
1815 + "d3-ease": "1 - 3",
1816 + "d3-interpolate": "1 - 3",
1817 + "d3-timer": "1 - 3"
1818 + },
1819 + "engines": {
1820 + "node": ">=12"
1821 + },
1822 + "peerDependencies": {
1823 + "d3-selection": "2 - 3"
1824 + }
1825 + },
1826 + "node_modules/d3-zoom": {
1827 + "version": "3.0.0",
1828 + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz",
1829 + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==",
1830 + "license": "ISC",
1831 + "dependencies": {
1832 + "d3-dispatch": "1 - 3",
1833 + "d3-drag": "2 - 3",
1834 + "d3-interpolate": "1 - 3",
1835 + "d3-selection": "2 - 3",
1836 + "d3-transition": "2 - 3"
1837 + },
1838 + "engines": {
1839 + "node": ">=12"
1840 + }
1841 + },
1842 + "node_modules/deepmerge": {
1843 + "version": "4.3.1",
1844 + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
1845 + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
1846 + "dev": true,
1847 + "license": "MIT",
1848 + "engines": {
1849 + "node": ">=0.10.0"
1850 + }
1851 + },
1852 + "node_modules/delaunator": {
1853 + "version": "5.0.1",
1854 + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.1.tgz",
1855 + "integrity": "sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==",
1856 + "license": "ISC",
1857 + "dependencies": {
1858 + "robust-predicates": "^3.0.2"
1859 + }
1860 + },
1861 + "node_modules/detect-libc": {
1862 + "version": "2.1.2",
1863 + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
1864 + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
1865 + "dev": true,
1866 + "license": "Apache-2.0",
1867 + "engines": {
1868 + "node": ">=8"
1869 + }
1870 + },
1871 + "node_modules/devalue": {
1872 + "version": "5.6.3",
1873 + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.3.tgz",
1874 + "integrity": "sha512-nc7XjUU/2Lb+SvEFVGcWLiKkzfw8+qHI7zn8WYXKkLMgfGSHbgCEaR6bJpev8Cm6Rmrb19Gfd/tZvGqx9is3wg==",
1875 + "dev": true,
1876 + "license": "MIT"
1877 + },
1878 + "node_modules/enhanced-resolve": {
1879 + "version": "5.19.0",
1880 + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz",
1881 + "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==",
1882 + "dev": true,
1883 + "license": "MIT",
1884 + "dependencies": {
1885 + "graceful-fs": "^4.2.4",
1886 + "tapable": "^2.3.0"
1887 + },
1888 + "engines": {
1889 + "node": ">=10.13.0"
1890 + }
1891 + },
1892 + "node_modules/esbuild": {
1893 + "version": "0.27.3",
1894 + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz",
1895 + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==",
1896 + "dev": true,
1897 + "hasInstallScript": true,
1898 + "license": "MIT",
1899 + "bin": {
1900 + "esbuild": "bin/esbuild"
1901 + },
1902 + "engines": {
1903 + "node": ">=18"
1904 + },
1905 + "optionalDependencies": {
1906 + "@esbuild/aix-ppc64": "0.27.3",
1907 + "@esbuild/android-arm": "0.27.3",
1908 + "@esbuild/android-arm64": "0.27.3",
1909 + "@esbuild/android-x64": "0.27.3",
1910 + "@esbuild/darwin-arm64": "0.27.3",
1911 + "@esbuild/darwin-x64": "0.27.3",
1912 + "@esbuild/freebsd-arm64": "0.27.3",
1913 + "@esbuild/freebsd-x64": "0.27.3",
1914 + "@esbuild/linux-arm": "0.27.3",
1915 + "@esbuild/linux-arm64": "0.27.3",
1916 + "@esbuild/linux-ia32": "0.27.3",
1917 + "@esbuild/linux-loong64": "0.27.3",
1918 + "@esbuild/linux-mips64el": "0.27.3",
1919 + "@esbuild/linux-ppc64": "0.27.3",
1920 + "@esbuild/linux-riscv64": "0.27.3",
1921 + "@esbuild/linux-s390x": "0.27.3",
1922 + "@esbuild/linux-x64": "0.27.3",
1923 + "@esbuild/netbsd-arm64": "0.27.3",
1924 + "@esbuild/netbsd-x64": "0.27.3",
1925 + "@esbuild/openbsd-arm64": "0.27.3",
1926 + "@esbuild/openbsd-x64": "0.27.3",
1927 + "@esbuild/openharmony-arm64": "0.27.3",
1928 + "@esbuild/sunos-x64": "0.27.3",
1929 + "@esbuild/win32-arm64": "0.27.3",
1930 + "@esbuild/win32-ia32": "0.27.3",
1931 + "@esbuild/win32-x64": "0.27.3"
1932 + }
1933 + },
1934 + "node_modules/esm-env": {
1935 + "version": "1.2.2",
1936 + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz",
1937 + "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==",
1938 + "dev": true,
1939 + "license": "MIT"
1940 + },
1941 + "node_modules/esrap": {
1942 + "version": "2.2.3",
1943 + "resolved": "https://registry.npmjs.org/esrap/-/esrap-2.2.3.tgz",
1944 + "integrity": "sha512-8fOS+GIGCQZl/ZIlhl59htOlms6U8NvX6ZYgYHpRU/b6tVSh3uHkOHZikl3D4cMbYM0JlpBe+p/BkZEi8J9XIQ==",
1945 + "dev": true,
1946 + "license": "MIT",
1947 + "dependencies": {
1948 + "@jridgewell/sourcemap-codec": "^1.4.15"
1949 + }
1950 + },
1951 + "node_modules/fdir": {
1952 + "version": "6.5.0",
1953 + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
1954 + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
1955 + "dev": true,
1956 + "license": "MIT",
1957 + "engines": {
1958 + "node": ">=12.0.0"
1959 + },
1960 + "peerDependencies": {
1961 + "picomatch": "^3 || ^4"
1962 + },
1963 + "peerDependenciesMeta": {
1964 + "picomatch": {
1965 + "optional": true
1966 + }
1967 + }
1968 + },
1969 + "node_modules/fsevents": {
1970 + "version": "2.3.3",
1971 + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
1972 + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
1973 + "dev": true,
1974 + "hasInstallScript": true,
1975 + "license": "MIT",
1976 + "optional": true,
1977 + "os": [
1978 + "darwin"
1979 + ],
1980 + "engines": {
1981 + "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
1982 + }
1983 + },
1984 + "node_modules/fuse.js": {
1985 + "version": "7.1.0",
1986 + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.1.0.tgz",
1987 + "integrity": "sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==",
1988 + "license": "Apache-2.0",
1989 + "engines": {
1990 + "node": ">=10"
1991 + }
1992 + },
1993 + "node_modules/graceful-fs": {
1994 + "version": "4.2.11",
1995 + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
1996 + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
1997 + "dev": true,
1998 + "license": "ISC"
1999 + },
2000 + "node_modules/iceberg-js": {
2001 + "version": "0.8.1",
2002 + "resolved": "https://registry.npmjs.org/iceberg-js/-/iceberg-js-0.8.1.tgz",
2003 + "integrity": "sha512-1dhVQZXhcHje7798IVM+xoo/1ZdVfzOMIc8/rgVSijRK38EDqOJoGula9N/8ZI5RD8QTxNQtK/Gozpr+qUqRRA==",
2004 + "license": "MIT",
2005 + "engines": {
2006 + "node": ">=20.0.0"
2007 + }
2008 + },
2009 + "node_modules/iconv-lite": {
2010 + "version": "0.6.3",
2011 + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
2012 + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
2013 + "license": "MIT",
2014 + "dependencies": {
2015 + "safer-buffer": ">= 2.1.2 < 3.0.0"
2016 + },
2017 + "engines": {
2018 + "node": ">=0.10.0"
2019 + }
2020 + },
2021 + "node_modules/internmap": {
2022 + "version": "2.0.3",
2023 + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
2024 + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
2025 + "license": "ISC",
2026 + "engines": {
2027 + "node": ">=12"
2028 + }
2029 + },
2030 + "node_modules/is-reference": {
2031 + "version": "3.0.3",
2032 + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz",
2033 + "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==",
2034 + "dev": true,
2035 + "license": "MIT",
2036 + "dependencies": {
2037 + "@types/estree": "^1.0.6"
2038 + }
2039 + },
2040 + "node_modules/jiti": {
2041 + "version": "2.6.1",
2042 + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
2043 + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
2044 + "dev": true,
2045 + "license": "MIT",
2046 + "bin": {
2047 + "jiti": "lib/jiti-cli.mjs"
2048 + }
2049 + },
2050 + "node_modules/kleur": {
2051 + "version": "4.1.5",
2052 + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
2053 + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
2054 + "dev": true,
2055 + "license": "MIT",
2056 + "engines": {
2057 + "node": ">=6"
2058 + }
2059 + },
2060 + "node_modules/lightningcss": {
2061 + "version": "1.31.1",
2062 + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.31.1.tgz",
2063 + "integrity": "sha512-l51N2r93WmGUye3WuFoN5k10zyvrVs0qfKBhyC5ogUQ6Ew6JUSswh78mbSO+IU3nTWsyOArqPCcShdQSadghBQ==",
2064 + "dev": true,
2065 + "license": "MPL-2.0",
2066 + "dependencies": {
2067 + "detect-libc": "^2.0.3"
2068 + },
2069 + "engines": {
2070 + "node": ">= 12.0.0"
2071 + },
2072 + "funding": {
2073 + "type": "opencollective",
2074 + "url": "https://opencollective.com/parcel"
2075 + },
2076 + "optionalDependencies": {
2077 + "lightningcss-android-arm64": "1.31.1",
2078 + "lightningcss-darwin-arm64": "1.31.1",
2079 + "lightningcss-darwin-x64": "1.31.1",
2080 + "lightningcss-freebsd-x64": "1.31.1",
2081 + "lightningcss-linux-arm-gnueabihf": "1.31.1",
2082 + "lightningcss-linux-arm64-gnu": "1.31.1",
2083 + "lightningcss-linux-arm64-musl": "1.31.1",
2084 + "lightningcss-linux-x64-gnu": "1.31.1",
2085 + "lightningcss-linux-x64-musl": "1.31.1",
2086 + "lightningcss-win32-arm64-msvc": "1.31.1",
2087 + "lightningcss-win32-x64-msvc": "1.31.1"
2088 + }
2089 + },
2090 + "node_modules/lightningcss-android-arm64": {
2091 + "version": "1.31.1",
2092 + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.31.1.tgz",
2093 + "integrity": "sha512-HXJF3x8w9nQ4jbXRiNppBCqeZPIAfUo8zE/kOEGbW5NZvGc/K7nMxbhIr+YlFlHW5mpbg/YFPdbnCh1wAXCKFg==",
2094 + "cpu": [
2095 + "arm64"
2096 + ],
2097 + "dev": true,
2098 + "license": "MPL-2.0",
2099 + "optional": true,
2100 + "os": [
2101 + "android"
2102 + ],
2103 + "engines": {
2104 + "node": ">= 12.0.0"
2105 + },
2106 + "funding": {
2107 + "type": "opencollective",
2108 + "url": "https://opencollective.com/parcel"
2109 + }
2110 + },
2111 + "node_modules/lightningcss-darwin-arm64": {
2112 + "version": "1.31.1",
2113 + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.31.1.tgz",
2114 + "integrity": "sha512-02uTEqf3vIfNMq3h/z2cJfcOXnQ0GRwQrkmPafhueLb2h7mqEidiCzkE4gBMEH65abHRiQvhdcQ+aP0D0g67sg==",
2115 + "cpu": [
2116 + "arm64"
2117 + ],
2118 + "dev": true,
2119 + "license": "MPL-2.0",
2120 + "optional": true,
2121 + "os": [
2122 + "darwin"
2123 + ],
2124 + "engines": {
2125 + "node": ">= 12.0.0"
2126 + },
2127 + "funding": {
2128 + "type": "opencollective",
2129 + "url": "https://opencollective.com/parcel"
2130 + }
2131 + },
2132 + "node_modules/lightningcss-darwin-x64": {
2133 + "version": "1.31.1",
2134 + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.31.1.tgz",
2135 + "integrity": "sha512-1ObhyoCY+tGxtsz1lSx5NXCj3nirk0Y0kB/g8B8DT+sSx4G9djitg9ejFnjb3gJNWo7qXH4DIy2SUHvpoFwfTA==",
2136 + "cpu": [
2137 + "x64"
2138 + ],
2139 + "dev": true,
2140 + "license": "MPL-2.0",
2141 + "optional": true,
2142 + "os": [
2143 + "darwin"
2144 + ],
2145 + "engines": {
2146 + "node": ">= 12.0.0"
2147 + },
2148 + "funding": {
2149 + "type": "opencollective",
2150 + "url": "https://opencollective.com/parcel"
2151 + }
2152 + },
2153 + "node_modules/lightningcss-freebsd-x64": {
2154 + "version": "1.31.1",
2155 + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.31.1.tgz",
2156 + "integrity": "sha512-1RINmQKAItO6ISxYgPwszQE1BrsVU5aB45ho6O42mu96UiZBxEXsuQ7cJW4zs4CEodPUioj/QrXW1r9pLUM74A==",
2157 + "cpu": [
2158 + "x64"
2159 + ],
2160 + "dev": true,
2161 + "license": "MPL-2.0",
2162 + "optional": true,
2163 + "os": [
2164 + "freebsd"
2165 + ],
2166 + "engines": {
2167 + "node": ">= 12.0.0"
2168 + },
2169 + "funding": {
2170 + "type": "opencollective",
2171 + "url": "https://opencollective.com/parcel"
2172 + }
2173 + },
2174 + "node_modules/lightningcss-linux-arm-gnueabihf": {
2175 + "version": "1.31.1",
2176 + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.31.1.tgz",
2177 + "integrity": "sha512-OOCm2//MZJ87CdDK62rZIu+aw9gBv4azMJuA8/KB74wmfS3lnC4yoPHm0uXZ/dvNNHmnZnB8XLAZzObeG0nS1g==",
2178 + "cpu": [
2179 + "arm"
2180 + ],
2181 + "dev": true,
2182 + "license": "MPL-2.0",
2183 + "optional": true,
2184 + "os": [
2185 + "linux"
2186 + ],
2187 + "engines": {
2188 + "node": ">= 12.0.0"
2189 + },
2190 + "funding": {
2191 + "type": "opencollective",
2192 + "url": "https://opencollective.com/parcel"
2193 + }
2194 + },
2195 + "node_modules/lightningcss-linux-arm64-gnu": {
2196 + "version": "1.31.1",
2197 + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.31.1.tgz",
2198 + "integrity": "sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==",
2199 + "cpu": [
2200 + "arm64"
2201 + ],
2202 + "dev": true,
2203 + "license": "MPL-2.0",
2204 + "optional": true,
2205 + "os": [
2206 + "linux"
2207 + ],
2208 + "engines": {
2209 + "node": ">= 12.0.0"
2210 + },
2211 + "funding": {
2212 + "type": "opencollective",
2213 + "url": "https://opencollective.com/parcel"
2214 + }
2215 + },
2216 + "node_modules/lightningcss-linux-arm64-musl": {
2217 + "version": "1.31.1",
2218 + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.31.1.tgz",
2219 + "integrity": "sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==",
2220 + "cpu": [
2221 + "arm64"
2222 + ],
2223 + "dev": true,
2224 + "license": "MPL-2.0",
2225 + "optional": true,
2226 + "os": [
2227 + "linux"
2228 + ],
2229 + "engines": {
2230 + "node": ">= 12.0.0"
2231 + },
2232 + "funding": {
2233 + "type": "opencollective",
2234 + "url": "https://opencollective.com/parcel"
2235 + }
2236 + },
2237 + "node_modules/lightningcss-linux-x64-gnu": {
2238 + "version": "1.31.1",
2239 + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.31.1.tgz",
2240 + "integrity": "sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==",
2241 + "cpu": [
2242 + "x64"
2243 + ],
2244 + "dev": true,
2245 + "license": "MPL-2.0",
2246 + "optional": true,
2247 + "os": [
2248 + "linux"
2249 + ],
2250 + "engines": {
2251 + "node": ">= 12.0.0"
2252 + },
2253 + "funding": {
2254 + "type": "opencollective",
2255 + "url": "https://opencollective.com/parcel"
2256 + }
2257 + },
2258 + "node_modules/lightningcss-linux-x64-musl": {
2259 + "version": "1.31.1",
2260 + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.31.1.tgz",
2261 + "integrity": "sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==",
2262 + "cpu": [
2263 + "x64"
2264 + ],
2265 + "dev": true,
2266 + "license": "MPL-2.0",
2267 + "optional": true,
2268 + "os": [
2269 + "linux"
2270 + ],
2271 + "engines": {
2272 + "node": ">= 12.0.0"
2273 + },
2274 + "funding": {
2275 + "type": "opencollective",
2276 + "url": "https://opencollective.com/parcel"
2277 + }
2278 + },
2279 + "node_modules/lightningcss-win32-arm64-msvc": {
2280 + "version": "1.31.1",
2281 + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.31.1.tgz",
2282 + "integrity": "sha512-aJReEbSEQzx1uBlQizAOBSjcmr9dCdL3XuC/6HLXAxmtErsj2ICo5yYggg1qOODQMtnjNQv2UHb9NpOuFtYe4w==",
2283 + "cpu": [
2284 + "arm64"
2285 + ],
2286 + "dev": true,
2287 + "license": "MPL-2.0",
2288 + "optional": true,
2289 + "os": [
2290 + "win32"
2291 + ],
2292 + "engines": {
2293 + "node": ">= 12.0.0"
2294 + },
2295 + "funding": {
2296 + "type": "opencollective",
2297 + "url": "https://opencollective.com/parcel"
2298 + }
2299 + },
2300 + "node_modules/lightningcss-win32-x64-msvc": {
2301 + "version": "1.31.1",
2302 + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.31.1.tgz",
2303 + "integrity": "sha512-I9aiFrbd7oYHwlnQDqr1Roz+fTz61oDDJX7n9tYF9FJymH1cIN1DtKw3iYt6b8WZgEjoNwVSncwF4wx/ZedMhw==",
2304 + "cpu": [
2305 + "x64"
2306 + ],
2307 + "dev": true,
2308 + "license": "MPL-2.0",
2309 + "optional": true,
2310 + "os": [
2311 + "win32"
2312 + ],
2313 + "engines": {
2314 + "node": ">= 12.0.0"
2315 + },
2316 + "funding": {
2317 + "type": "opencollective",
2318 + "url": "https://opencollective.com/parcel"
2319 + }
2320 + },
2321 + "node_modules/locate-character": {
2322 + "version": "3.0.0",
2323 + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
2324 + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
2325 + "dev": true,
2326 + "license": "MIT"
2327 + },
2328 + "node_modules/magic-string": {
2329 + "version": "0.30.21",
2330 + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
2331 + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
2332 + "dev": true,
2333 + "license": "MIT",
2334 + "dependencies": {
2335 + "@jridgewell/sourcemap-codec": "^1.5.5"
2336 + }
2337 + },
2338 + "node_modules/mrmime": {
2339 + "version": "2.0.1",
2340 + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
2341 + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==",
2342 + "dev": true,
2343 + "license": "MIT",
2344 + "engines": {
2345 + "node": ">=10"
2346 + }
2347 + },
2348 + "node_modules/nanoid": {
2349 + "version": "3.3.11",
2350 + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
2351 + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
2352 + "dev": true,
2353 + "funding": [
2354 + {
2355 + "type": "github",
2356 + "url": "https://github.com/sponsors/ai"
2357 + }
2358 + ],
2359 + "license": "MIT",
2360 + "bin": {
2361 + "nanoid": "bin/nanoid.cjs"
2362 + },
2363 + "engines": {
2364 + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
2365 + }
2366 + },
2367 + "node_modules/obug": {
2368 + "version": "2.1.1",
2369 + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz",
2370 + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==",
2371 + "dev": true,
2372 + "funding": [
2373 + "https://github.com/sponsors/sxzz",
2374 + "https://opencollective.com/debug"
2375 + ],
2376 + "license": "MIT"
2377 + },
2378 + "node_modules/picocolors": {
2379 + "version": "1.1.1",
2380 + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
2381 + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
2382 + "dev": true,
2383 + "license": "ISC"
2384 + },
2385 + "node_modules/picomatch": {
2386 + "version": "4.0.3",
2387 + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
2388 + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
2389 + "dev": true,
2390 + "license": "MIT",
2391 + "engines": {
2392 + "node": ">=12"
2393 + },
2394 + "funding": {
2395 + "url": "https://github.com/sponsors/jonschlinkert"
2396 + }
2397 + },
2398 + "node_modules/postcss": {
2399 + "version": "8.5.6",
2400 + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
2401 + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
2402 + "dev": true,
2403 + "funding": [
2404 + {
2405 + "type": "opencollective",
2406 + "url": "https://opencollective.com/postcss/"
2407 + },
2408 + {
2409 + "type": "tidelift",
2410 + "url": "https://tidelift.com/funding/github/npm/postcss"
2411 + },
2412 + {
2413 + "type": "github",
2414 + "url": "https://github.com/sponsors/ai"
2415 + }
2416 + ],
2417 + "license": "MIT",
2418 + "dependencies": {
2419 + "nanoid": "^3.3.11",
2420 + "picocolors": "^1.1.1",
2421 + "source-map-js": "^1.2.1"
2422 + },
2423 + "engines": {
2424 + "node": "^10 || ^12 || >=14"
2425 + }
2426 + },
2427 + "node_modules/robust-predicates": {
2428 + "version": "3.0.2",
2429 + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz",
2430 + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==",
2431 + "license": "Unlicense"
2432 + },
2433 + "node_modules/rollup": {
2434 + "version": "4.59.0",
2435 + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz",
2436 + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==",
2437 + "dev": true,
2438 + "license": "MIT",
2439 + "dependencies": {
2440 + "@types/estree": "1.0.8"
2441 + },
2442 + "bin": {
2443 + "rollup": "dist/bin/rollup"
2444 + },
2445 + "engines": {
2446 + "node": ">=18.0.0",
2447 + "npm": ">=8.0.0"
2448 + },
2449 + "optionalDependencies": {
2450 + "@rollup/rollup-android-arm-eabi": "4.59.0",
2451 + "@rollup/rollup-android-arm64": "4.59.0",
2452 + "@rollup/rollup-darwin-arm64": "4.59.0",
2453 + "@rollup/rollup-darwin-x64": "4.59.0",
2454 + "@rollup/rollup-freebsd-arm64": "4.59.0",
2455 + "@rollup/rollup-freebsd-x64": "4.59.0",
2456 + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0",
2457 + "@rollup/rollup-linux-arm-musleabihf": "4.59.0",
2458 + "@rollup/rollup-linux-arm64-gnu": "4.59.0",
2459 + "@rollup/rollup-linux-arm64-musl": "4.59.0",
2460 + "@rollup/rollup-linux-loong64-gnu": "4.59.0",
2461 + "@rollup/rollup-linux-loong64-musl": "4.59.0",
2462 + "@rollup/rollup-linux-ppc64-gnu": "4.59.0",
2463 + "@rollup/rollup-linux-ppc64-musl": "4.59.0",
2464 + "@rollup/rollup-linux-riscv64-gnu": "4.59.0",
2465 + "@rollup/rollup-linux-riscv64-musl": "4.59.0",
2466 + "@rollup/rollup-linux-s390x-gnu": "4.59.0",
2467 + "@rollup/rollup-linux-x64-gnu": "4.59.0",
2468 + "@rollup/rollup-linux-x64-musl": "4.59.0",
2469 + "@rollup/rollup-openbsd-x64": "4.59.0",
2470 + "@rollup/rollup-openharmony-arm64": "4.59.0",
2471 + "@rollup/rollup-win32-arm64-msvc": "4.59.0",
2472 + "@rollup/rollup-win32-ia32-msvc": "4.59.0",
2473 + "@rollup/rollup-win32-x64-gnu": "4.59.0",
2474 + "@rollup/rollup-win32-x64-msvc": "4.59.0",
2475 + "fsevents": "~2.3.2"
2476 + }
2477 + },
2478 + "node_modules/rw": {
2479 + "version": "1.3.3",
2480 + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
2481 + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==",
2482 + "license": "BSD-3-Clause"
2483 + },
2484 + "node_modules/safer-buffer": {
2485 + "version": "2.1.2",
2486 + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
2487 + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
2488 + "license": "MIT"
2489 + },
2490 + "node_modules/set-cookie-parser": {
2491 + "version": "3.0.1",
2492 + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.0.1.tgz",
2493 + "integrity": "sha512-n7Z7dXZhJbwuAHhNzkTti6Aw9QDDjZtm3JTpTGATIdNzdQz5GuFs22w90BcvF4INfnrL5xrX3oGsuqO5Dx3A1Q==",
2494 + "dev": true,
2495 + "license": "MIT"
2496 + },
2497 + "node_modules/sirv": {
2498 + "version": "3.0.2",
2499 + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz",
2500 + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==",
2501 + "dev": true,
2502 + "license": "MIT",
2503 + "dependencies": {
2504 + "@polka/url": "^1.0.0-next.24",
2505 + "mrmime": "^2.0.0",
2506 + "totalist": "^3.0.0"
2507 + },
2508 + "engines": {
2509 + "node": ">=18"
2510 + }
2511 + },
2512 + "node_modules/source-map-js": {
2513 + "version": "1.2.1",
2514 + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
2515 + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
2516 + "dev": true,
2517 + "license": "BSD-3-Clause",
2518 + "engines": {
2519 + "node": ">=0.10.0"
2520 + }
2521 + },
2522 + "node_modules/svelte": {
2523 + "version": "5.53.5",
2524 + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.53.5.tgz",
2525 + "integrity": "sha512-YkqERnF05g8KLdDZwZrF8/i1eSbj6Eoat8Jjr2IfruZz9StLuBqo8sfCSzjosNKd+ZrQ8DkKZDjpO5y3ht1Pow==",
2526 + "dev": true,
2527 + "license": "MIT",
2528 + "dependencies": {
2529 + "@jridgewell/remapping": "^2.3.4",
2530 + "@jridgewell/sourcemap-codec": "^1.5.0",
2531 + "@sveltejs/acorn-typescript": "^1.0.5",
2532 + "@types/estree": "^1.0.5",
2533 + "@types/trusted-types": "^2.0.7",
2534 + "acorn": "^8.12.1",
2535 + "aria-query": "5.3.1",
2536 + "axobject-query": "^4.1.0",
2537 + "clsx": "^2.1.1",
2538 + "devalue": "^5.6.3",
2539 + "esm-env": "^1.2.1",
2540 + "esrap": "^2.2.2",
2541 + "is-reference": "^3.0.3",
2542 + "locate-character": "^3.0.0",
2543 + "magic-string": "^0.30.11",
2544 + "zimmerframe": "^1.1.2"
2545 + },
2546 + "engines": {
2547 + "node": ">=18"
2548 + }
2549 + },
2550 + "node_modules/tailwindcss": {
2551 + "version": "4.2.1",
2552 + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.2.1.tgz",
2553 + "integrity": "sha512-/tBrSQ36vCleJkAOsy9kbNTgaxvGbyOamC30PRePTQe/o1MFwEKHQk4Cn7BNGaPtjp+PuUrByJehM1hgxfq4sw==",
2554 + "dev": true,
2555 + "license": "MIT"
2556 + },
2557 + "node_modules/tapable": {
2558 + "version": "2.3.0",
2559 + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
2560 + "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==",
2561 + "dev": true,
2562 + "license": "MIT",
2563 + "engines": {
2564 + "node": ">=6"
2565 + },
2566 + "funding": {
2567 + "type": "opencollective",
2568 + "url": "https://opencollective.com/webpack"
2569 + }
2570 + },
2571 + "node_modules/tinyglobby": {
2572 + "version": "0.2.15",
2573 + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
2574 + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
2575 + "dev": true,
2576 + "license": "MIT",
2577 + "dependencies": {
2578 + "fdir": "^6.5.0",
2579 + "picomatch": "^4.0.3"
2580 + },
2581 + "engines": {
2582 + "node": ">=12.0.0"
2583 + },
2584 + "funding": {
2585 + "url": "https://github.com/sponsors/SuperchupuDev"
2586 + }
2587 + },
2588 + "node_modules/totalist": {
2589 + "version": "3.0.1",
2590 + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
2591 + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
2592 + "dev": true,
2593 + "license": "MIT",
2594 + "engines": {
2595 + "node": ">=6"
2596 + }
2597 + },
2598 + "node_modules/tslib": {
2599 + "version": "2.8.1",
2600 + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
2601 + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
2602 + "license": "0BSD"
2603 + },
2604 + "node_modules/undici-types": {
2605 + "version": "7.18.2",
2606 + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
2607 + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
2608 + "license": "MIT"
2609 + },
2610 + "node_modules/vite": {
2611 + "version": "7.3.1",
2612 + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz",
2613 + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
2614 + "dev": true,
2615 + "license": "MIT",
2616 + "dependencies": {
2617 + "esbuild": "^0.27.0",
2618 + "fdir": "^6.5.0",
2619 + "picomatch": "^4.0.3",
2620 + "postcss": "^8.5.6",
2621 + "rollup": "^4.43.0",
2622 + "tinyglobby": "^0.2.15"
2623 + },
2624 + "bin": {
2625 + "vite": "bin/vite.js"
2626 + },
2627 + "engines": {
2628 + "node": "^20.19.0 || >=22.12.0"
2629 + },
2630 + "funding": {
2631 + "url": "https://github.com/vitejs/vite?sponsor=1"
2632 + },
2633 + "optionalDependencies": {
2634 + "fsevents": "~2.3.3"
2635 + },
2636 + "peerDependencies": {
2637 + "@types/node": "^20.19.0 || >=22.12.0",
2638 + "jiti": ">=1.21.0",
2639 + "less": "^4.0.0",
2640 + "lightningcss": "^1.21.0",
2641 + "sass": "^1.70.0",
2642 + "sass-embedded": "^1.70.0",
2643 + "stylus": ">=0.54.8",
2644 + "sugarss": "^5.0.0",
2645 + "terser": "^5.16.0",
2646 + "tsx": "^4.8.1",
2647 + "yaml": "^2.4.2"
2648 + },
2649 + "peerDependenciesMeta": {
2650 + "@types/node": {
2651 + "optional": true
2652 + },
2653 + "jiti": {
2654 + "optional": true
2655 + },
2656 + "less": {
2657 + "optional": true
2658 + },
2659 + "lightningcss": {
2660 + "optional": true
2661 + },
2662 + "sass": {
2663 + "optional": true
2664 + },
2665 + "sass-embedded": {
2666 + "optional": true
2667 + },
2668 + "stylus": {
2669 + "optional": true
2670 + },
2671 + "sugarss": {
2672 + "optional": true
2673 + },
2674 + "terser": {
2675 + "optional": true
2676 + },
2677 + "tsx": {
2678 + "optional": true
2679 + },
2680 + "yaml": {
2681 + "optional": true
2682 + }
2683 + }
2684 + },
2685 + "node_modules/vitefu": {
2686 + "version": "1.1.2",
2687 + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.2.tgz",
2688 + "integrity": "sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw==",
2689 + "dev": true,
2690 + "license": "MIT",
2691 + "workspaces": [
2692 + "tests/deps/*",
2693 + "tests/projects/*",
2694 + "tests/projects/workspace/packages/*"
2695 + ],
2696 + "peerDependencies": {
2697 + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0"
2698 + },
2699 + "peerDependenciesMeta": {
2700 + "vite": {
2701 + "optional": true
2702 + }
2703 + }
2704 + },
2705 + "node_modules/ws": {
2706 + "version": "8.19.0",
2707 + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
2708 + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
2709 + "license": "MIT",
2710 + "engines": {
2711 + "node": ">=10.0.0"
2712 + },
2713 + "peerDependencies": {
2714 + "bufferutil": "^4.0.1",
2715 + "utf-8-validate": ">=5.0.2"
2716 + },
2717 + "peerDependenciesMeta": {
2718 + "bufferutil": {
2719 + "optional": true
2720 + },
2721 + "utf-8-validate": {
2722 + "optional": true
2723 + }
2724 + }
2725 + },
2726 + "node_modules/zimmerframe": {
2727 + "version": "1.1.4",
2728 + "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz",
2729 + "integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==",
2730 + "dev": true,
2731 + "license": "MIT"
2732 + }
2733 + }
2734 +}
1 +{
2 + "name": "ppto",
3 + "private": true,
4 + "version": "0.0.1",
5 + "type": "module",
6 + "scripts": {
7 + "dev": "vite dev",
8 + "build": "vite build",
9 + "preview": "vite preview",
10 + "prepare": "svelte-kit sync || echo ''"
11 + },
12 + "devDependencies": {
13 + "@sveltejs/adapter-auto": "^7.0.0",
14 + "@sveltejs/kit": "^2.50.2",
15 + "@sveltejs/vite-plugin-svelte": "^6.2.4",
16 + "@tailwindcss/vite": "^4.2.1",
17 + "svelte": "^5.51.0",
18 + "tailwindcss": "^4.2.1",
19 + "vite": "^7.3.1"
20 + },
21 + "dependencies": {
22 + "@supabase/supabase-js": "^2.98.0",
23 + "d3": "^7.9.0",
24 + "fuse.js": "^7.1.0"
25 + }
26 +}
1 +@import "tailwindcss";
2 +
3 +/* ============================================
4 + TIPOGRAFÍAS INSTITUCIONALES
5 + ============================================ */
6 +
7 +@font-face {
8 + font-family: 'Qanelas';
9 + src: url('/tipografia/Qanelas-Light.ttf') format('truetype');
10 + font-weight: 300;
11 + font-style: normal;
12 + font-display: swap;
13 +}
14 +
15 +@font-face {
16 + font-family: 'Qanelas';
17 + src: url('/tipografia/Qanelas-Regular.ttf') format('truetype');
18 + font-weight: 400;
19 + font-style: normal;
20 + font-display: swap;
21 +}
22 +
23 +@font-face {
24 + font-family: 'Qanelas';
25 + src: url('/tipografia/Qanelas-Medium.ttf') format('truetype');
26 + font-weight: 500;
27 + font-style: normal;
28 + font-display: swap;
29 +}
30 +
31 +@font-face {
32 + font-family: 'Qanelas';
33 + src: url('/tipografia/Qanelas-SemiBold.ttf') format('truetype');
34 + font-weight: 600;
35 + font-style: normal;
36 + font-display: swap;
37 +}
38 +
39 +@font-face {
40 + font-family: 'Qanelas';
41 + src: url('/tipografia/Qanelas-Bold.ttf') format('truetype');
42 + font-weight: 700;
43 + font-style: normal;
44 + font-display: swap;
45 +}
46 +
47 +@font-face {
48 + font-family: 'Archivo Condensed';
49 + src: url('/tipografia/Archivo_Condensed-SemiBold.ttf') format('truetype');
50 + font-weight: 600;
51 + font-style: normal;
52 + font-display: swap;
53 +}
54 +
55 +@font-face {
56 + font-family: 'Archivo Condensed';
57 + src: url('/tipografia/Archivo_Condensed-Bold.ttf') format('truetype');
58 + font-weight: 700;
59 + font-style: normal;
60 + font-display: swap;
61 +}
62 +
63 +@font-face {
64 + font-family: 'Archivo Condensed';
65 + src: url('/tipografia/Archivo_Condensed-Black.ttf') format('truetype');
66 + font-weight: 900;
67 + font-style: normal;
68 + font-display: swap;
69 +}
70 +
71 +/* ============================================
72 + TEMA PERSONALIZADO - TAILWIND v4
73 + ============================================ */
74 +
75 +@theme {
76 + /* Tipografía */
77 + --font-sans: 'Qanelas', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
78 + --font-display: 'Archivo Condensed', 'Qanelas', system-ui, sans-serif;
79 +
80 + /* Colores Institucionales MEFP */
81 + --color-gold: #C9A751;
82 + --color-gold-light: #D4B76A;
83 + --color-gold-dark: #A88A3D;
84 +
85 + --color-wine: #B91817;
86 + --color-wine-light: #D42625;
87 + --color-wine-dark: #8F1211;
88 +
89 + --color-graphite: #363534;
90 + --color-graphite-light: #4A4948;
91 + --color-graphite-dark: #252423;
92 +
93 + /* Colores Bandera Nacional */
94 + --color-flag-red: #DB281C;
95 + --color-flag-yellow: #F4E410;
96 + --color-flag-green: #007C38;
97 +
98 + /* Colores Secundarios */
99 + --color-cream: #F3EAD8;
100 + --color-cream-light: #FAF6EE;
101 + --color-cream-dark: #E8DCC4;
102 +
103 + --color-muted: #676767;
104 + --color-muted-light: #8A8A8A;
105 + --color-muted-dark: #4A4A4A;
106 +}
107 +
108 +/* ============================================
109 + ESTILOS BASE
110 + ============================================ */
111 +
112 +html {
113 + scroll-behavior: smooth;
114 +}
115 +
116 +body {
117 + font-family: var(--font-sans);
118 + color: var(--color-graphite);
119 + background-color: #FAFAFA;
120 + -webkit-font-smoothing: antialiased;
121 + -moz-osx-font-smoothing: grayscale;
122 +}
123 +
124 +/* Focus ring consistente con identidad */
125 +*:focus-visible {
126 + outline: 2px solid var(--color-gold);
127 + outline-offset: 2px;
128 +}
129 +
130 +/* Selección de texto */
131 +::selection {
132 + background-color: var(--color-gold);
133 + color: white;
134 +}
135 +
136 +/* ============================================
137 + UTILIDADES PERSONALIZADAS
138 + ============================================ */
139 +
140 +/* Gradiente de bandera (horizontal) */
141 +.bg-flag-gradient {
142 + background: linear-gradient(
143 + to right,
144 + var(--color-flag-red) 33.33%,
145 + var(--color-flag-yellow) 33.33%,
146 + var(--color-flag-yellow) 66.66%,
147 + var(--color-flag-green) 66.66%
148 + );
149 +}
150 +
151 +/* Línea decorativa dorada */
152 +.border-gold-accent {
153 + border-bottom: 3px solid var(--color-gold);
154 +}
155 +
156 +/* Texto con acento dorado */
157 +.text-gold-accent {
158 + color: var(--color-gold);
159 +}
160 +
161 +/* Fuente display (Archivo) */
162 +.font-display {
163 + font-family: var(--font-display);
164 +}
1 +<!doctype html>
2 +<html lang="en">
3 + <head>
4 + <meta charset="utf-8" />
5 + <meta name="viewport" content="width=device-width, initial-scale=1" />
6 + %sveltekit.head%
7 + </head>
8 + <body data-sveltekit-preload-data="hover">
9 + <div style="display: contents">%sveltekit.body%</div>
10 + </body>
11 +</html>
1 +<svg xmlns="http://www.w3.org/2000/svg" width="107" height="128" viewBox="0 0 107 128"><title>svelte-logo</title><path d="M94.157 22.819c-10.4-14.885-30.94-19.297-45.792-9.835L22.282 29.608A29.92 29.92 0 0 0 8.764 49.65a31.5 31.5 0 0 0 3.108 20.231 30 30 0 0 0-4.477 11.183 31.9 31.9 0 0 0 5.448 24.116c10.402 14.887 30.942 19.297 45.791 9.835l26.083-16.624A29.92 29.92 0 0 0 98.235 78.35a31.53 31.53 0 0 0-3.105-20.232 30 30 0 0 0 4.474-11.182 31.88 31.88 0 0 0-5.447-24.116" style="fill:#ff3e00"/><path d="M45.817 106.582a20.72 20.72 0 0 1-22.237-8.243 19.17 19.17 0 0 1-3.277-14.503 18 18 0 0 1 .624-2.435l.49-1.498 1.337.981a33.6 33.6 0 0 0 10.203 5.098l.97.294-.09.968a5.85 5.85 0 0 0 1.052 3.878 6.24 6.24 0 0 0 6.695 2.485 5.8 5.8 0 0 0 1.603-.704L69.27 76.28a5.43 5.43 0 0 0 2.45-3.631 5.8 5.8 0 0 0-.987-4.371 6.24 6.24 0 0 0-6.698-2.487 5.7 5.7 0 0 0-1.6.704l-9.953 6.345a19 19 0 0 1-5.296 2.326 20.72 20.72 0 0 1-22.237-8.243 19.17 19.17 0 0 1-3.277-14.502 17.99 17.99 0 0 1 8.13-12.052l26.081-16.623a19 19 0 0 1 5.3-2.329 20.72 20.72 0 0 1 22.237 8.243 19.17 19.17 0 0 1 3.277 14.503 18 18 0 0 1-.624 2.435l-.49 1.498-1.337-.98a33.6 33.6 0 0 0-10.203-5.1l-.97-.294.09-.968a5.86 5.86 0 0 0-1.052-3.878 6.24 6.24 0 0 0-6.696-2.485 5.8 5.8 0 0 0-1.602.704L37.73 51.72a5.42 5.42 0 0 0-2.449 3.63 5.79 5.79 0 0 0 .986 4.372 6.24 6.24 0 0 0 6.698 2.486 5.8 5.8 0 0 0 1.602-.704l9.952-6.342a19 19 0 0 1 5.295-2.328 20.72 20.72 0 0 1 22.237 8.242 19.17 19.17 0 0 1 3.277 14.503 18 18 0 0 1-8.13 12.053l-26.081 16.622a19 19 0 0 1-5.3 2.328" style="fill:#fff"/></svg>
...\ No newline at end of file ...\ No newline at end of file
1 +<script>
2 + import { onMount } from 'svelte';
3 + import { goto } from '$app/navigation';
4 + import SearchResults from './SearchResults.svelte';
5 + import {
6 + query,
7 + results,
8 + isLoading,
9 + indexLoaded,
10 + error,
11 + selectedIndex,
12 + showResults,
13 + initIndex,
14 + performSearch,
15 + clearSearch,
16 + navigateResults
17 + } from '$lib/stores/searchStore';
18 +
19 + let inputRef;
20 + let debounceTimer;
21 + let isFocused = $state(false);
22 +
23 + onMount(() => {
24 + initIndex();
25 + });
26 +
27 + function handleInput(e) {
28 + const value = e.target.value;
29 + clearTimeout(debounceTimer);
30 + debounceTimer = setTimeout(() => {
31 + performSearch(value);
32 + }, 250);
33 + }
34 +
35 + function handleKeydown(e) {
36 + if (!$showResults) return;
37 +
38 + switch (e.key) {
39 + case 'ArrowDown':
40 + e.preventDefault();
41 + navigateResults('down', $results.length);
42 + break;
43 + case 'ArrowUp':
44 + e.preventDefault();
45 + navigateResults('up', $results.length);
46 + break;
47 + case 'Enter':
48 + e.preventDefault();
49 + if ($selectedIndex >= 0 && $results[$selectedIndex]) {
50 + const item = $results[$selectedIndex];
51 + if (item.tipo === 'entidad') {
52 + goto(`/entidad/${item.codigo}`);
53 + } else if (item.tipo === 'objeto_gasto') {
54 + goto(`/objeto/${item.codigo}`);
55 + }
56 + clearSearch();
57 + inputRef.value = '';
58 + }
59 + break;
60 + case 'Escape':
61 + clearSearch();
62 + inputRef.value = '';
63 + inputRef.blur();
64 + break;
65 + }
66 + }
67 +
68 + function handleClickOutside(e) {
69 + if (!e.target.closest('.search-container')) {
70 + isFocused = false;
71 + }
72 + }
73 +</script>
74 +
75 +<svelte:window onclick={handleClickOutside} />
76 +
77 +<div class="search-container relative">
78 + <input
79 + bind:this={inputRef}
80 + type="text"
81 + placeholder={$indexLoaded ? "Buscar entidad u objeto de gasto..." : "Cargando..."}
82 + disabled={!$indexLoaded}
83 + class="w-full p-2 border rounded"
84 + oninput={handleInput}
85 + onkeydown={handleKeydown}
86 + onfocus={() => isFocused = true}
87 + />
88 +
89 + {#if $isLoading}
90 + <span class="absolute right-2 top-2 text-sm text-gray-400">...</span>
91 + {/if}
92 +
93 + {#if isFocused && $showResults}
94 + <SearchResults
95 + results={$results}
96 + query={$query}
97 + selectedIndex={$selectedIndex}
98 + />
99 + {/if}
100 +
101 + {#if $error}
102 + <p class="text-red-500 text-sm mt-1">{$error}</p>
103 + {/if}
104 +</div>
1 +<script>
2 + let { item, isSelected = false, onclick } = $props();
3 +</script>
4 +
5 +<button
6 + type="button"
7 + class="w-full text-left px-3 py-2 text-sm hover:bg-gray-100 {isSelected ? 'bg-gray-100' : ''}"
8 + {onclick}
9 +>
10 + <div>{item.nombre} {item.sigla ? `(${item.sigla})` : ''}</div>
11 + <div class="text-xs text-gray-500">{item.contexto}</div>
12 +</button>
1 +<script>
2 + import { goto } from '$app/navigation';
3 + import { clearSearch } from '$lib/stores/searchStore';
4 +
5 + let { results = [], query = '', selectedIndex = -1 } = $props();
6 +
7 + function handleSelect(item) {
8 + if (item.tipo === 'entidad') {
9 + goto(`/entidad/${item.codigo}`);
10 + } else if (item.tipo === 'objeto_gasto') {
11 + goto(`/objeto/${item.codigo}`);
12 + }
13 + clearSearch();
14 + }
15 +</script>
16 +
17 +{#if results.length > 0}
18 + <div class="absolute top-full left-0 right-0 mt-1 bg-white border rounded shadow-lg max-h-80 overflow-y-auto z-50">
19 + {#each results as item, index}
20 + <button
21 + type="button"
22 + class="w-full text-left px-3 py-2 text-sm hover:bg-gray-100 {index === selectedIndex ? 'bg-gray-100' : ''}"
23 + onclick={() => handleSelect(item)}
24 + >
25 + <div class="flex items-center gap-2">
26 + {#if item.tipo === 'objeto_gasto'}
27 + <span class="font-mono text-xs text-slate-400">{item.codigo}</span>
28 + {/if}
29 + <span>{item.nombre}</span>
30 + {#if item.sigla}
31 + <span class="text-slate-400">({item.sigla})</span>
32 + {/if}
33 + </div>
34 + <div class="text-xs text-gray-500">{item.contexto}</div>
35 + </button>
36 + {/each}
37 + </div>
38 +{:else if query.length >= 2}
39 + <div class="absolute top-full left-0 right-0 mt-1 bg-white border rounded p-3 text-sm text-gray-500">
40 + Sin resultados para "{query}"
41 + </div>
42 +{/if}
1 +<script>
2 + import { page } from '$app/stores';
3 +</script>
4 +
5 +<nav class="border-b p-4">
6 + <div class="max-w-4xl mx-auto flex items-center justify-between">
7 + <a href="/">Presupuesto Público Bolivia</a>
8 + <div class="flex gap-4 text-sm">
9 + <a href="/">Inicio</a>
10 + <a href="/clasificadores">Clasificadores</a>
11 + </div>
12 + </div>
13 +</nav>
1 +// place files you want to import through the `$lib` alias in this folder.
1 +import Fuse from 'fuse.js';
2 +import { supabase } from '$lib/supabase';
3 +import { normalizeText } from '$lib/utils/normalize';
4 +
5 +let fuseInstance = null;
6 +let searchData = [];
7 +
8 +/**
9 + * Configuración de Fuse.js
10 + */
11 +const fuseOptions = {
12 + keys: [
13 + { name: 'nombre_normalizado', weight: 0.6 },
14 + { name: 'sigla_normalizada', weight: 0.2 },
15 + { name: 'codigo_normalizado', weight: 0.2 }
16 + ],
17 + threshold: 0.4, // 0 = exacto, 1 = muy fuzzy
18 + distance: 100,
19 + includeScore: true,
20 + includeMatches: true,
21 + minMatchCharLength: 2,
22 + ignoreLocation: true
23 +};
24 +
25 +/**
26 + * Carga las entidades y objetos de gasto desde Supabase y construye el índice
27 + */
28 +export async function initSearchIndex() {
29 + if (fuseInstance) return fuseInstance;
30 +
31 + // Cargar entidades
32 + const { data: entidades, error: errorEntidades } = await supabase
33 + .schema('ppto')
34 + .from('clas_institucional')
35 + .select('entidad, desc_entidad, sigla_entidad, desc_area, n_gestiones');
36 +
37 + if (errorEntidades) {
38 + console.error('Error cargando entidades:', errorEntidades);
39 + throw errorEntidades;
40 + }
41 +
42 + // Cargar objetos de gasto
43 + const { data: objetos, error: errorObjetos } = await supabase
44 + .schema('ppto')
45 + .from('clas_objetos')
46 + .select('objeto, desc_objeto, nivel');
47 +
48 + if (errorObjetos) {
49 + console.error('Error cargando objetos:', errorObjetos);
50 + throw errorObjetos;
51 + }
52 +
53 + // Transformar entidades para el índice
54 + const entidadesIndex = entidades.map(item => ({
55 + tipo: 'entidad',
56 + codigo: item.entidad,
57 + nombre: item.desc_entidad,
58 + sigla: item.sigla_entidad,
59 + contexto: item.desc_area,
60 + años: item.n_gestiones,
61 + nombre_normalizado: normalizeText(item.desc_entidad),
62 + sigla_normalizada: normalizeText(item.sigla_entidad),
63 + codigo_normalizado: item.entidad?.toString() || ''
64 + }));
65 +
66 + // Transformar objetos de gasto para el índice
67 + const nivelLabels = { grupo: 'Grupo', subgrupo: 'Subgrupo', partida: 'Partida', subpartida: 'Subpartida' };
68 + const objetosIndex = objetos.map(item => ({
69 + tipo: 'objeto_gasto',
70 + codigo: item.objeto,
71 + nombre: item.desc_objeto,
72 + sigla: null,
73 + contexto: `Objeto del Gasto · ${nivelLabels[item.nivel] || item.nivel}`,
74 + nivel: item.nivel,
75 + nombre_normalizado: normalizeText(item.desc_objeto),
76 + sigla_normalizada: '',
77 + codigo_normalizado: item.objeto || ''
78 + }));
79 +
80 + // Combinar ambos conjuntos
81 + searchData = [...entidadesIndex, ...objetosIndex];
82 +
83 + fuseInstance = new Fuse(searchData, fuseOptions);
84 +
85 + return fuseInstance;
86 +}
87 +
88 +/**
89 + * Busca en el índice
90 + * @param {string} query - Texto de búsqueda
91 + * @param {number} limit - Máximo de resultados (default 30)
92 + * @returns {Array} Resultados de búsqueda
93 + */
94 +export function search(query, limit = 30) {
95 + if (!fuseInstance) {
96 + console.warn('Índice no inicializado. Llama initSearchIndex() primero.');
97 + return [];
98 + }
99 +
100 + if (!query || query.length < 2) {
101 + return [];
102 + }
103 +
104 + const normalizedQuery = normalizeText(query);
105 + const results = fuseInstance.search(normalizedQuery, { limit });
106 +
107 + return results.map(result => ({
108 + ...result.item,
109 + score: result.score,
110 + matches: result.matches
111 + }));
112 +}
113 +
114 +/**
115 + * Obtiene todas las entidades (sin búsqueda)
116 + */
117 +export function getAllEntidades() {
118 + return searchData.filter(item => item.tipo === 'entidad');
119 +}
120 +
121 +/**
122 + * Obtiene todos los objetos de gasto (sin búsqueda)
123 + */
124 +export function getAllObjetos() {
125 + return searchData.filter(item => item.tipo === 'objeto_gasto');
126 +}
127 +
128 +/**
129 + * Verifica si el índice está cargado
130 + */
131 +export function isIndexReady() {
132 + return fuseInstance !== null;
133 +}
1 +import { writable, derived } from 'svelte/store';
2 +import { initSearchIndex, search, isIndexReady } from '$lib/services/search';
3 +
4 +// Estado del buscador
5 +export const query = writable('');
6 +export const results = writable([]);
7 +export const isLoading = writable(false);
8 +export const indexLoaded = writable(false);
9 +export const error = writable(null);
10 +export const selectedIndex = writable(-1);
11 +
12 +// Estado derivado: si está mostrando resultados
13 +export const showResults = derived(
14 + [query, results, indexLoaded],
15 + ([$query, $results, $indexLoaded]) => $indexLoaded && $query.length >= 2
16 +);
17 +
18 +/**
19 + * Inicializa el índice de búsqueda
20 + */
21 +export async function initIndex() {
22 + if (isIndexReady()) {
23 + indexLoaded.set(true);
24 + return;
25 + }
26 +
27 + isLoading.set(true);
28 + error.set(null);
29 +
30 + try {
31 + await initSearchIndex();
32 + indexLoaded.set(true);
33 + } catch (e) {
34 + error.set('Error al cargar el índice de búsqueda');
35 + console.error(e);
36 + } finally {
37 + isLoading.set(false);
38 + }
39 +}
40 +
41 +/**
42 + * Realiza la búsqueda
43 + */
44 +export function performSearch(searchQuery) {
45 + query.set(searchQuery);
46 + selectedIndex.set(-1);
47 +
48 + if (searchQuery.length < 2) {
49 + results.set([]);
50 + return;
51 + }
52 +
53 + const searchResults = search(searchQuery, 30);
54 + results.set(searchResults);
55 +}
56 +
57 +/**
58 + * Limpia la búsqueda
59 + */
60 +export function clearSearch() {
61 + query.set('');
62 + results.set([]);
63 + selectedIndex.set(-1);
64 +}
65 +
66 +/**
67 + * Navegación por teclado
68 + */
69 +export function navigateResults(direction, totalResults) {
70 + selectedIndex.update(current => {
71 + if (direction === 'down') {
72 + return current < totalResults - 1 ? current + 1 : 0;
73 + } else if (direction === 'up') {
74 + return current > 0 ? current - 1 : totalResults - 1;
75 + }
76 + return current;
77 + });
78 +}
1 +import { createClient } from '@supabase/supabase-js';
2 +import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public';
3 +
4 +export const supabase = createClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY);
1 +/**
2 + * Normaliza texto para búsqueda:
3 + * - Convierte a minúsculas
4 + * - Elimina acentos/diacríticos
5 + * - Elimina espacios extra
6 + */
7 +export function normalizeText(text) {
8 + if (!text) return '';
9 +
10 + return text
11 + .toLowerCase()
12 + .normalize('NFD')
13 + .replace(/[\u0300-\u036f]/g, '') // Elimina diacríticos
14 + .replace(/\s+/g, ' ') // Espacios múltiples a uno
15 + .trim();
16 +}
17 +
18 +/**
19 + * Resalta coincidencias en el texto
20 + * @param {string} text - Texto original
21 + * @param {string} query - Búsqueda del usuario
22 + * @returns {string} HTML con <mark> en coincidencias
23 + */
24 +export function highlightMatch(text, query) {
25 + if (!query || !text) return text;
26 +
27 + const normalizedQuery = normalizeText(query);
28 + const normalizedText = normalizeText(text);
29 +
30 + // Encontrar posición en texto normalizado
31 + const index = normalizedText.indexOf(normalizedQuery);
32 +
33 + if (index === -1) return text;
34 +
35 + // Aplicar highlight en texto original (misma posición)
36 + const before = text.slice(0, index);
37 + const match = text.slice(index, index + query.length);
38 + const after = text.slice(index + query.length);
39 +
40 + return `${before}<mark class="bg-yellow-200 rounded px-0.5">${match}</mark>${after}`;
41 +}
1 +<script>
2 + import '../app.css';
3 + import favicon from '$lib/assets/favicon.svg';
4 + import Navbar from '$lib/components/ui/Navbar.svelte';
5 +
6 + let { children } = $props();
7 +</script>
8 +
9 +<svelte:head>
10 + <link rel="icon" href={favicon} />
11 +</svelte:head>
12 +
13 +<div class="min-h-screen flex flex-col">
14 + <Navbar />
15 + <main class="flex-1">
16 + {@render children()}
17 + </main>
18 +</div>
1 +<script>
2 + import SearchBox from '$lib/components/search/SearchBox.svelte';
3 +</script>
4 +
5 +<svelte:head>
6 + <title>Presupuesto Público Bolivia</title>
7 +</svelte:head>
8 +
9 +<div class="max-w-4xl mx-auto p-4">
10 + <h1 class="text-2xl mb-2">Presupuesto Público de Bolivia</h1>
11 + <p class="mb-6 text-gray-600">
12 + 20 años de datos fiscales · 600+ entidades · Actualización diaria
13 + </p>
14 +
15 + <div class="mb-8">
16 + <SearchBox />
17 + </div>
18 +
19 + <div class="grid grid-cols-2 gap-4 text-sm">
20 + <a href="/clasificadores" class="p-4 border rounded hover:bg-gray-50">
21 + <strong>Clasificadores</strong>
22 + <p class="text-gray-600">Navegar por instituciones, objetos de gasto, etc.</p>
23 + </a>
24 + <div class="p-4 border rounded opacity-50">
25 + <strong>Historias</strong>
26 + <p class="text-gray-600">Próximamente</p>
27 + </div>
28 + </div>
29 +</div>
1 +import { supabase } from '$lib/supabase';
2 +import { json } from '@sveltejs/kit';
3 +
4 +export async function GET() {
5 + const { data, error } = await supabase
6 + .schema('ppto')
7 + .from('clas_institucional')
8 + .select('*')
9 + .limit(5);
10 +
11 + if (error) {
12 + return json({ error: error.message }, { status: 500 });
13 + }
14 +
15 + return json({
16 + success: true,
17 + count: data.length,
18 + columns: data.length > 0 ? Object.keys(data[0]) : [],
19 + sample: data
20 + });
21 +}
1 +<script>
2 + const clasificadores = [
3 + { id: 'institucional', nombre: 'Institucional', descripcion: 'Ministerios, universidades, municipios, empresas públicas', disponible: true },
4 + { id: 'objeto-gasto', nombre: 'Objeto del Gasto', descripcion: 'Servicios personales, bienes, inversiones', disponible: true },
5 + { id: 'fuente', nombre: 'Fuente de Financiamiento', descripcion: 'Tesoro, créditos externos, recursos propios', disponible: false },
6 + { id: 'organismo', nombre: 'Organismo Financiador', descripcion: 'BID, Banco Mundial, CAF', disponible: false },
7 + { id: 'geografico', nombre: 'Geográfico', descripcion: 'Departamentos, provincias, municipios', disponible: false },
8 + { id: 'funcional', nombre: 'Funcional', descripcion: 'Educación, salud, defensa', disponible: false },
9 + { id: 'economico', nombre: 'Económico', descripcion: 'Corrientes, de capital', disponible: false },
10 + { id: 'programatico', nombre: 'Programático', descripcion: 'Programas y proyectos', disponible: false },
11 + ];
12 +</script>
13 +
14 +<svelte:head>
15 + <title>Clasificadores | Presupuesto Público</title>
16 +</svelte:head>
17 +
18 +<div class="max-w-4xl mx-auto p-4">
19 + <p class="text-sm text-gray-500 mb-4">
20 + <a href="/">Inicio</a> / Clasificadores
21 + </p>
22 +
23 + <h1 class="text-2xl mb-6">Clasificadores</h1>
24 +
25 + <div class="space-y-2">
26 + {#each clasificadores as item}
27 + {#if item.disponible}
28 + <a href="/clasificadores/{item.id}" class="block p-4 border rounded hover:bg-gray-50">
29 + <strong>{item.nombre}</strong>
30 + <p class="text-sm text-gray-600">{item.descripcion}</p>
31 + </a>
32 + {:else}
33 + <div class="p-4 border rounded opacity-50">
34 + <strong>{item.nombre}</strong>
35 + <span class="text-xs text-gray-400 ml-2">(próximamente)</span>
36 + <p class="text-sm text-gray-600">{item.descripcion}</p>
37 + </div>
38 + {/if}
39 + {/each}
40 + </div>
41 +</div>
1 +<script>
2 + import { supabase } from '$lib/supabase';
3 + import { onMount } from 'svelte';
4 +
5 + let loading = $state(true);
6 + let searchQuery = $state('');
7 + let areas = $state([]);
8 + let allEntidades = $state([]);
9 + let selectedArea = $state(null);
10 + let highlightedEntidad = $state(null);
11 +
12 + onMount(async () => {
13 + const { data, error } = await supabase
14 + .schema('ppto')
15 + .from('clas_institucional')
16 + .select('*')
17 + .order('desc_area')
18 + .order('desc_entidad');
19 +
20 + if (!error && data) {
21 + allEntidades = data;
22 +
23 + // Agrupar por área (segundo nivel)
24 + const areasMap = {};
25 +
26 + data.forEach(item => {
27 + const areaKey = item.area;
28 +
29 + if (!areasMap[areaKey]) {
30 + areasMap[areaKey] = {
31 + codigo: item.area,
32 + nombre: item.desc_area,
33 + sector: item.desc_sector,
34 + entidades: []
35 + };
36 + }
37 +
38 + areasMap[areaKey].entidades.push({
39 + codigo: item.entidad,
40 + nombre: item.desc_entidad,
41 + sigla: item.sigla_entidad,
42 + años: item.n_gestiones,
43 + gestiones: item.gestiones,
44 + subarea: item.desc_subarea
45 + });
46 + });
47 +
48 + areas = Object.values(areasMap).sort((a, b) => a.nombre.localeCompare(b.nombre));
49 +
50 + if (areas.length > 0) {
51 + selectedArea = areas[0];
52 + }
53 + }
54 +
55 + loading = false;
56 + });
57 +
58 + // Agrupar entidades por subárea dentro del área seleccionada
59 + function getSubareasForArea(areaEntidades) {
60 + if (!areaEntidades) return [];
61 +
62 + const subareasMap = {};
63 +
64 + areaEntidades.forEach(ent => {
65 + const subareaKey = ent.subarea || 'Sin subárea';
66 +
67 + if (!subareasMap[subareaKey]) {
68 + subareasMap[subareaKey] = {
69 + nombre: subareaKey,
70 + entidades: []
71 + };
72 + }
73 +
74 + subareasMap[subareaKey].entidades.push(ent);
75 + });
76 +
77 + return Object.values(subareasMap).sort((a, b) => a.nombre.localeCompare(b.nombre));
78 + }
79 +
80 + // Búsqueda global
81 + function searchGlobal(query) {
82 + if (!query || query.length < 2) return [];
83 + const q = query.toLowerCase();
84 +
85 + return allEntidades
86 + .filter(item =>
87 + item.entidad?.toString().includes(q) ||
88 + item.desc_entidad?.toLowerCase().includes(q) ||
89 + item.sigla_entidad?.toLowerCase().includes(q)
90 + )
91 + .slice(0, 20);
92 + }
93 +
94 + function selectArea(area) {
95 + selectedArea = area;
96 + searchQuery = '';
97 + highlightedEntidad = null;
98 + }
99 +
100 + function goToSearchResult(item) {
101 + const targetArea = areas.find(a => a.codigo === item.area);
102 +
103 + if (targetArea) {
104 + selectedArea = targetArea;
105 + highlightedEntidad = item.entidad;
106 + searchQuery = '';
107 +
108 + setTimeout(() => {
109 + const element = document.getElementById(`ent-${item.entidad}`);
110 + if (element) {
111 + element.scrollIntoView({ behavior: 'smooth', block: 'center' });
112 + }
113 + }, 100);
114 + }
115 + }
116 +
117 + // Convertir lista de años a rangos legibles
118 + function formatGestiones(gestiones) {
119 + if (!gestiones) return '';
120 +
121 + const years = gestiones.split(',').map(y => parseInt(y.trim())).sort((a, b) => a - b);
122 + if (years.length === 0) return '';
123 + if (years.length === 1) return years[0].toString();
124 +
125 + const ranges = [];
126 + let start = years[0];
127 + let end = years[0];
128 +
129 + for (let i = 1; i < years.length; i++) {
130 + if (years[i] === end + 1) {
131 + end = years[i];
132 + } else {
133 + ranges.push(start === end ? `${start}` : `${start}-${end}`);
134 + start = years[i];
135 + end = years[i];
136 + }
137 + }
138 + ranges.push(start === end ? `${start}` : `${start}-${end}`);
139 +
140 + return ranges.join(', ');
141 + }
142 +
143 + let areaSubareas = $derived(selectedArea ? getSubareasForArea(selectedArea.entidades) : []);
144 + let searchResults = $derived(searchGlobal(searchQuery));
145 + let isSearching = $derived(searchQuery.length >= 2);
146 + let totalEntidades = $derived(allEntidades.length);
147 +</script>
148 +
149 +<svelte:head>
150 + <title>Institucional | Presupuesto Público</title>
151 +</svelte:head>
152 +
153 +<div class="min-h-screen bg-white">
154 + <!-- Header -->
155 + <header class="border-b bg-slate-50">
156 + <div class="max-w-screen-2xl mx-auto px-6 py-4">
157 + <nav class="text-sm text-slate-500 mb-2">
158 + <a href="/" class="hover:text-slate-700">Inicio</a>
159 + <span class="mx-2">/</span>
160 + <a href="/clasificadores" class="hover:text-slate-700">Clasificadores</a>
161 + <span class="mx-2">/</span>
162 + <span class="text-slate-900">Institucional</span>
163 + </nav>
164 + <div class="flex items-center justify-between">
165 + <div>
166 + <h1 class="text-2xl font-light text-slate-900">Clasificador Institucional</h1>
167 + <p class="text-sm text-slate-500 mt-1">{totalEntidades || '...'} entidades públicas</p>
168 + </div>
169 + </div>
170 + </div>
171 + </header>
172 +
173 + {#if loading}
174 + <div class="flex items-center justify-center py-20">
175 + <p class="text-slate-500">Cargando clasificador...</p>
176 + </div>
177 + {:else}
178 + <div class="max-w-screen-2xl mx-auto flex">
179 + <!-- Sidebar izquierda: Áreas -->
180 + <aside class="w-64 flex-shrink-0 border-r bg-slate-50/50">
181 + <div class="sticky top-0 h-screen overflow-y-auto p-4">
182 + <!-- Buscador -->
183 + <div class="mb-6">
184 + <input
185 + type="text"
186 + bind:value={searchQuery}
187 + placeholder="Buscar entidad..."
188 + class="w-full px-3 py-2 text-sm border border-slate-200 rounded-md bg-white focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
189 + />
190 + </div>
191 +
192 + <!-- Resultados de búsqueda -->
193 + {#if isSearching}
194 + <div class="mb-4">
195 + <p class="text-xs text-slate-500 uppercase tracking-wide mb-2">
196 + {searchResults.length} resultados
197 + </p>
198 + <div class="space-y-1">
199 + {#each searchResults as result}
200 + <button
201 + class="w-full text-left px-2 py-2 text-sm rounded hover:bg-white hover:shadow-sm transition-all"
202 + onclick={() => goToSearchResult(result)}
203 + >
204 + <span class="text-xs text-slate-400 block">{result.desc_area}</span>
205 + <span class="text-slate-700">{result.desc_entidad}</span>
206 + {#if result.sigla_entidad}
207 + <span class="text-slate-400 text-xs ml-1">({result.sigla_entidad})</span>
208 + {/if}
209 + </button>
210 + {/each}
211 + {#if searchResults.length === 0}
212 + <p class="text-sm text-slate-400 px-2">Sin resultados</p>
213 + {/if}
214 + </div>
215 + </div>
216 + {:else}
217 + <!-- Lista de áreas -->
218 + <nav>
219 + <p class="text-xs text-slate-500 uppercase tracking-wide mb-3 px-2">Áreas</p>
220 + <ul class="space-y-1">
221 + {#each areas as area}
222 + <li>
223 + <button
224 + class="w-full text-left px-3 py-2 rounded-md text-sm transition-all
225 + {selectedArea?.codigo === area.codigo
226 + ? 'bg-blue-50 text-blue-900 font-medium border-l-2 border-blue-500'
227 + : 'text-slate-600 hover:bg-white hover:text-slate-900'}"
228 + onclick={() => selectArea(area)}
229 + >
230 + <span class="flex justify-between items-center">
231 + <span class="truncate">{area.nombre}</span>
232 + <span class="text-xs text-slate-400 ml-2 flex-shrink-0">{area.entidades.length}</span>
233 + </span>
234 + </button>
235 + </li>
236 + {/each}
237 + </ul>
238 + </nav>
239 + {/if}
240 + </div>
241 + </aside>
242 +
243 + <!-- Contenido principal -->
244 + <main class="flex-1 min-w-0">
245 + <div class="px-8 py-6">
246 + {#if selectedArea}
247 + <!-- Título del área -->
248 + <div class="mb-8 pb-6 border-b">
249 + <h2 class="text-xl font-medium text-slate-900 mb-1">{selectedArea.nombre}</h2>
250 + <p class="text-sm text-slate-500">{selectedArea.entidades.length} entidades</p>
251 + </div>
252 +
253 + <!-- Subáreas y entidades -->
254 + <div class="space-y-8">
255 + {#each areaSubareas as subarea}
256 + <section id="subarea-{subarea.nombre.replace(/\s+/g, '-')}" class="scroll-mt-4">
257 + {#if areaSubareas.length > 1 || subarea.nombre !== selectedArea.nombre}
258 + <div class="flex items-start gap-4 mb-4">
259 + <div class="flex-1">
260 + <h3 class="text-lg font-medium text-slate-900">{subarea.nombre}</h3>
261 + <p class="text-sm text-slate-500">{subarea.entidades.length} entidades</p>
262 + </div>
263 + </div>
264 + {/if}
265 +
266 + <!-- Entidades -->
267 + <div class="border rounded-lg divide-y">
268 + {#each subarea.entidades as entidad}
269 + <div
270 + id="ent-{entidad.codigo}"
271 + class="scroll-mt-4 {highlightedEntidad === entidad.codigo ? 'ring-2 ring-blue-200' : ''}"
272 + >
273 + <a
274 + href="/entidad/{entidad.codigo}"
275 + class="flex items-center justify-between px-4 py-3 hover:bg-slate-50 transition-colors"
276 + >
277 + <div class="flex-1 min-w-0">
278 + <div class="flex items-center gap-2">
279 + <span class="text-slate-900">{entidad.nombre}</span>
280 + {#if entidad.sigla}
281 + <span class="text-sm text-slate-400">({entidad.sigla})</span>
282 + {/if}
283 + </div>
284 + <p class="text-xs text-slate-400 mt-0.5">
285 + Código: {entidad.codigo} · {formatGestiones(entidad.gestiones)}
286 + </p>
287 + </div>
288 + <svg class="w-4 h-4 text-slate-300 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
289 + <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
290 + </svg>
291 + </a>
292 + </div>
293 + {/each}
294 + </div>
295 + </section>
296 + {/each}
297 + </div>
298 + {/if}
299 + </div>
300 + </main>
301 +
302 + <!-- Sidebar derecha: En esta página -->
303 + <aside class="w-56 flex-shrink-0 hidden xl:block">
304 + <div class="sticky top-0 h-screen overflow-y-auto p-4 border-l">
305 + <p class="text-xs text-slate-500 uppercase tracking-wide mb-3">En esta página</p>
306 + {#if selectedArea && !isSearching}
307 + <nav class="space-y-2">
308 + {#each areaSubareas as subarea}
309 + {#if areaSubareas.length > 1 || subarea.nombre !== selectedArea.nombre}
310 + <a
311 + href="#subarea-{subarea.nombre.replace(/\s+/g, '-')}"
312 + class="block text-sm text-slate-600 hover:text-blue-600 truncate"
313 + title={subarea.nombre}
314 + >
315 + {subarea.nombre}
316 + <span class="text-xs text-slate-400 ml-1">({subarea.entidades.length})</span>
317 + </a>
318 + {/if}
319 + {/each}
320 + {#if areaSubareas.length === 1 && areaSubareas[0].nombre === selectedArea.nombre}
321 + <p class="text-sm text-slate-400">{selectedArea.entidades.length} entidades</p>
322 + {/if}
323 + </nav>
324 + {/if}
325 + </div>
326 + </aside>
327 + </div>
328 + {/if}
329 +</div>
1 +<script>
2 + import { supabase } from '$lib/supabase';
3 + import { onMount } from 'svelte';
4 +
5 + let loading = $state(true);
6 + let searchQuery = $state('');
7 + let grupos = $state([]);
8 + let allItems = $state([]);
9 + let selectedGrupo = $state(null);
10 + let selectedItem = $state(null);
11 + let highlightedItem = $state(null);
12 +
13 + onMount(async () => {
14 + const { data, error } = await supabase
15 + .schema('ppto')
16 + .from('clas_objetos')
17 + .select('*')
18 + .order('objeto')
19 + .range(0, 9999);
20 +
21 + if (!error && data) {
22 + allItems = data;
23 +
24 + // Extraer grupos únicos
25 + grupos = data
26 + .filter(item => item.nivel === 'grupo')
27 + .reduce((acc, item) => {
28 + if (!acc.find(g => g.objeto === item.objeto)) {
29 + acc.push(item);
30 + }
31 + return acc;
32 + }, [])
33 + .sort((a, b) => a.objeto.localeCompare(b.objeto));
34 +
35 + if (grupos.length > 0) {
36 + selectedGrupo = grupos[0];
37 + }
38 + }
39 +
40 + loading = false;
41 + });
42 +
43 + function getItemsForGrupo(grupoCode) {
44 + if (!grupoCode) return { subgrupos: [] };
45 +
46 + const grupoNum = grupoCode.substring(0, 1);
47 +
48 + const subgruposUnicos = allItems
49 + .filter(item => item.nivel === 'subgrupo' && item.grupo == grupoNum)
50 + .reduce((acc, item) => {
51 + if (!acc.find(s => s.objeto === item.objeto)) {
52 + acc.push(item);
53 + }
54 + return acc;
55 + }, [])
56 + .sort((a, b) => a.objeto.localeCompare(b.objeto));
57 +
58 + const subgrupos = subgruposUnicos.map(sg => {
59 + const partidasUnicas = allItems
60 + .filter(item => item.nivel === 'partida' && item.grupo == grupoNum && item.subgrupo == sg.subgrupo)
61 + .reduce((acc, item) => {
62 + if (!acc.find(p => p.objeto === item.objeto)) {
63 + acc.push(item);
64 + }
65 + return acc;
66 + }, [])
67 + .sort((a, b) => a.objeto.localeCompare(b.objeto));
68 +
69 + const partidas = partidasUnicas.map(p => {
70 + const subpartidas = allItems
71 + .filter(item => item.nivel === 'subpartida' && item.grupo == grupoNum && item.subgrupo == sg.subgrupo && item.partida == p.partida)
72 + .reduce((acc, item) => {
73 + if (!acc.find(sp => sp.objeto === item.objeto)) {
74 + acc.push(item);
75 + }
76 + return acc;
77 + }, [])
78 + .sort((a, b) => a.objeto.localeCompare(b.objeto));
79 +
80 + return { ...p, subpartidas };
81 + });
82 +
83 + return { ...sg, partidas };
84 + });
85 +
86 + return { subgrupos };
87 + }
88 +
89 + // Búsqueda global
90 + function searchGlobal(query) {
91 + if (!query || query.length < 2) return [];
92 + const q = query.toLowerCase();
93 +
94 + return allItems
95 + .filter(item =>
96 + item.objeto.includes(q) ||
97 + item.desc_objeto?.toLowerCase().includes(q) ||
98 + item.descripciones?.toLowerCase().includes(q)
99 + )
100 + .reduce((acc, item) => {
101 + if (!acc.find(i => i.objeto === item.objeto)) {
102 + acc.push(item);
103 + }
104 + return acc;
105 + }, [])
106 + .slice(0, 20);
107 + }
108 +
109 + function parseDescripciones(descripcionesStr) {
110 + if (!descripcionesStr) return [];
111 + try {
112 + const parsed = JSON.parse(descripcionesStr);
113 + // Ordenar por año más reciente (extraer el máximo año de cada rango)
114 + return parsed.sort((a, b) => {
115 + const maxYearA = getMaxYear(a.rangos);
116 + const maxYearB = getMaxYear(b.rangos);
117 + return maxYearB - maxYearA; // Descendente, más reciente primero
118 + });
119 + } catch {
120 + return [];
121 + }
122 + }
123 +
124 + function getMaxYear(rangos) {
125 + if (!rangos) return 0;
126 + // Extraer todos los números de 4 dígitos (años) del string
127 + const years = rangos.match(/\d{4}/g);
128 + if (!years) return 0;
129 + return Math.max(...years.map(y => parseInt(y)));
130 + }
131 +
132 + function selectGrupo(grupo) {
133 + selectedGrupo = grupo;
134 + selectedItem = null;
135 + searchQuery = '';
136 + highlightedItem = null;
137 + }
138 +
139 + function openDetail(item) {
140 + selectedItem = item;
141 + }
142 +
143 + function closeDetail() {
144 + selectedItem = null;
145 + }
146 +
147 + function goToSearchResult(item) {
148 + // Encontrar el grupo correspondiente
149 + const grupoNum = item.grupo;
150 + const targetGrupo = grupos.find(g => g.objeto.startsWith(grupoNum));
151 +
152 + if (targetGrupo) {
153 + selectedGrupo = targetGrupo;
154 + highlightedItem = item.objeto;
155 + searchQuery = '';
156 +
157 + // Scroll al elemento después de un breve delay
158 + setTimeout(() => {
159 + const prefix = item.nivel === 'subgrupo' ? 'sg' : item.nivel === 'partida' ? 'p' : 'sp';
160 + const element = document.getElementById(`${prefix}-${item.objeto}`);
161 + if (element) {
162 + element.scrollIntoView({ behavior: 'smooth', block: 'center' });
163 + }
164 + }, 100);
165 + }
166 + }
167 +
168 + function getNivelLabel(nivel) {
169 + const labels = { grupo: 'Grupo', subgrupo: 'Subgrupo', partida: 'Partida', subpartida: 'Subpartida' };
170 + return labels[nivel] || nivel;
171 + }
172 +
173 + let grupoContent = $derived(selectedGrupo ? getItemsForGrupo(selectedGrupo.objeto) : { subgrupos: [] });
174 + let searchResults = $derived(searchGlobal(searchQuery));
175 + let isSearching = $derived(searchQuery.length >= 2);
176 +</script>
177 +
178 +<svelte:head>
179 + <title>Objeto del Gasto | Presupuesto Público</title>
180 +</svelte:head>
181 +
182 +<div class="min-h-screen bg-white">
183 + <!-- Header -->
184 + <header class="border-b bg-slate-50">
185 + <div class="max-w-screen-2xl mx-auto px-6 py-4">
186 + <nav class="text-sm text-slate-500 mb-2">
187 + <a href="/" class="hover:text-slate-700">Inicio</a>
188 + <span class="mx-2">/</span>
189 + <a href="/clasificadores" class="hover:text-slate-700">Clasificadores</a>
190 + <span class="mx-2">/</span>
191 + <span class="text-slate-900">Objeto del Gasto</span>
192 + </nav>
193 + <div class="flex items-center justify-between">
194 + <h1 class="text-2xl font-light text-slate-900">Clasificador por Objeto del Gasto</h1>
195 + </div>
196 + </div>
197 + </header>
198 +
199 + {#if loading}
200 + <div class="flex items-center justify-center py-20">
201 + <p class="text-slate-500">Cargando clasificador...</p>
202 + </div>
203 + {:else}
204 + <div class="max-w-screen-2xl mx-auto flex">
205 + <!-- Sidebar izquierda: Grupos -->
206 + <aside class="w-64 flex-shrink-0 border-r bg-slate-50/50">
207 + <div class="sticky top-0 h-screen overflow-y-auto p-4">
208 + <!-- Buscador -->
209 + <div class="mb-6">
210 + <input
211 + type="text"
212 + bind:value={searchQuery}
213 + placeholder="Buscar..."
214 + class="w-full px-3 py-2 text-sm border border-slate-200 rounded-md bg-white focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
215 + />
216 + </div>
217 +
218 + <!-- Resultados de búsqueda -->
219 + {#if isSearching}
220 + <div class="mb-4">
221 + <p class="text-xs text-slate-500 uppercase tracking-wide mb-2">
222 + {searchResults.length} resultados
223 + </p>
224 + <div class="space-y-1">
225 + {#each searchResults as result}
226 + <button
227 + class="w-full text-left px-2 py-2 text-sm rounded hover:bg-white hover:shadow-sm transition-all"
228 + onclick={() => goToSearchResult(result)}
229 + >
230 + <span class="text-xs text-slate-400 block">{getNivelLabel(result.nivel)}</span>
231 + <span class="font-mono text-xs text-blue-600">{result.objeto}</span>
232 + <span class="text-slate-700 ml-1">{result.desc_objeto}</span>
233 + </button>
234 + {/each}
235 + {#if searchResults.length === 0}
236 + <p class="text-sm text-slate-400 px-2">Sin resultados</p>
237 + {/if}
238 + </div>
239 + </div>
240 + {:else}
241 + <!-- Lista de grupos -->
242 + <nav>
243 + <p class="text-xs text-slate-500 uppercase tracking-wide mb-3 px-2">Grupos</p>
244 + <ul class="space-y-1">
245 + {#each grupos as grupo}
246 + <li>
247 + <button
248 + class="w-full text-left px-3 py-2 rounded-md text-sm transition-all
249 + {selectedGrupo?.objeto === grupo.objeto
250 + ? 'bg-blue-50 text-blue-900 font-medium border-l-2 border-blue-500'
251 + : 'text-slate-600 hover:bg-white hover:text-slate-900'}"
252 + onclick={() => selectGrupo(grupo)}
253 + >
254 + <span class="font-mono text-xs text-slate-400 block">{grupo.objeto}</span>
255 + {grupo.desc_objeto}
256 + </button>
257 + </li>
258 + {/each}
259 + </ul>
260 + </nav>
261 + {/if}
262 + </div>
263 + </aside>
264 +
265 + <!-- Contenido principal -->
266 + <main class="flex-1 min-w-0">
267 + <div class="px-8 py-6">
268 + {#if selectedGrupo}
269 + <!-- Título del grupo -->
270 + <div class="mb-8 pb-6 border-b">
271 + <p class="text-sm font-mono text-slate-400 mb-1">{selectedGrupo.objeto}</p>
272 + <h2 class="text-xl font-medium text-slate-900 mb-2 flex items-center gap-3">
273 + {selectedGrupo.desc_objeto}
274 + <a
275 + href="/objeto/{selectedGrupo.objeto}"
276 + class="text-slate-300 hover:text-blue-500 transition-colors"
277 + title="Ver detalle"
278 + >
279 + <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
280 + <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
281 + </svg>
282 + </a>
283 + </h2>
284 + {#if selectedGrupo.descripciones}
285 + {@const grupoDescs = parseDescripciones(selectedGrupo.descripciones)}
286 + {#if grupoDescs.length > 0}
287 + <p class="text-slate-600 leading-relaxed">{grupoDescs[0].descripcion}</p>
288 + {#if selectedGrupo.n_variaciones > 1}
289 + <button
290 + class="text-sm text-orange-500 hover:text-orange-700 mt-2 transition-colors underline decoration-dotted decoration-orange-300 hover:decoration-orange-500 cursor-pointer"
291 + onclick={() => openDetail(selectedGrupo)}
292 + >
293 + Ver {selectedGrupo.n_variaciones} variaciones históricas
294 + </button>
295 + {/if}
296 + {/if}
297 + {/if}
298 + </div>
299 +
300 + <!-- Subgrupos -->
301 + <div class="space-y-8">
302 + {#each grupoContent.subgrupos as subgrupo}
303 + {@const subgrupoDescs = parseDescripciones(subgrupo.descripciones)}
304 + <section
305 + id="sg-{subgrupo.objeto}"
306 + class="scroll-mt-4 {highlightedItem === subgrupo.objeto ? 'ring-2 ring-blue-200 rounded-lg' : ''}"
307 + >
308 + <div class="flex items-start gap-4 mb-3">
309 + <span class="font-mono text-sm text-slate-400 pt-1">{subgrupo.objeto}</span>
310 + <div class="flex-1">
311 + <h3 class="text-lg font-medium text-slate-900 flex items-center gap-2">
312 + <span class="text-left">{subgrupo.desc_objeto}</span>
313 + {#if subgrupo.n_variaciones > 1}
314 + <button
315 + class="text-xs font-normal text-orange-500 hover:text-orange-700 transition-colors underline decoration-dotted decoration-orange-300 hover:decoration-orange-500 cursor-pointer"
316 + onclick={() => openDetail(subgrupo)}
317 + title="Ver variaciones de descripción"
318 + >
319 + {subgrupo.n_variaciones} var.
320 + </button>
321 + {/if}
322 + <a
323 + href="/objeto/{subgrupo.objeto}"
324 + class="text-slate-300 hover:text-blue-500 transition-colors"
325 + title="Ver página de detalle"
326 + >
327 + <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
328 + <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
329 + </svg>
330 + </a>
331 + </h3>
332 + {#if subgrupoDescs.length > 0}
333 + <p class="text-sm text-slate-600 mt-1 leading-relaxed">{subgrupoDescs[0].descripcion}</p>
334 + {/if}
335 + </div>
336 + </div>
337 +
338 + <!-- Partidas -->
339 + {#if subgrupo.partidas?.length > 0}
340 + <div class="ml-16 space-y-4 border-l-2 border-slate-100 pl-6">
341 + {#each subgrupo.partidas as partida}
342 + {@const partidaDescs = parseDescripciones(partida.descripciones)}
343 + <div
344 + id="p-{partida.objeto}"
345 + class="scroll-mt-4 {highlightedItem === partida.objeto ? 'ring-2 ring-blue-200 rounded-lg p-2 -ml-2' : ''}"
346 + >
347 + <div class="flex items-start gap-3">
348 + <span class="font-mono text-xs text-slate-400 pt-0.5">{partida.objeto}</span>
349 + <div class="flex-1">
350 + <h4 class="text-sm font-medium text-slate-800 flex items-center gap-2">
351 + <span class="text-left">{partida.desc_objeto}</span>
352 + {#if partida.n_variaciones > 1}
353 + <button
354 + class="text-xs font-normal text-orange-500 hover:text-orange-700 transition-colors underline decoration-dotted decoration-orange-300 hover:decoration-orange-500 cursor-pointer"
355 + onclick={() => openDetail(partida)}
356 + title="Ver variaciones de descripción"
357 + >
358 + {partida.n_variaciones} var.
359 + </button>
360 + {/if}
361 + <a
362 + href="/objeto/{partida.objeto}"
363 + class="text-slate-300 hover:text-blue-500 transition-colors"
364 + title="Ver página de detalle"
365 + >
366 + <svg class="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
367 + <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
368 + </svg>
369 + </a>
370 + </h4>
371 + {#if partidaDescs.length > 0}
372 + <p class="text-xs text-slate-500 mt-1 leading-relaxed">{partidaDescs[0].descripcion}</p>
373 + {/if}
374 + </div>
375 + </div>
376 +
377 + <!-- Subpartidas -->
378 + {#if partida.subpartidas?.length > 0}
379 + <div class="ml-12 mt-3 space-y-2 border-l border-slate-100 pl-4">
380 + {#each partida.subpartidas as subpartida}
381 + {@const subpartidaDescs = parseDescripciones(subpartida.descripciones)}
382 + <div
383 + id="sp-{subpartida.objeto}"
384 + class="scroll-mt-4 {highlightedItem === subpartida.objeto ? 'ring-2 ring-blue-200 rounded p-1 -ml-1' : ''}"
385 + >
386 + <div class="flex items-start gap-2">
387 + <span class="font-mono text-xs text-slate-300">{subpartida.objeto}</span>
388 + <div class="flex-1">
389 + <span class="flex items-center gap-2">
390 + <span class="text-xs text-slate-700">{subpartida.desc_objeto}</span>
391 + {#if subpartida.n_variaciones > 1}
392 + <button
393 + class="text-xs text-orange-500 hover:text-orange-700 transition-colors underline decoration-dotted decoration-orange-300 hover:decoration-orange-500 cursor-pointer"
394 + onclick={() => openDetail(subpartida)}
395 + title="Ver variaciones de descripción"
396 + >
397 + {subpartida.n_variaciones} var.
398 + </button>
399 + {/if}
400 + <a
401 + href="/objeto/{subpartida.objeto}"
402 + class="text-slate-300 hover:text-blue-500 transition-colors"
403 + title="Ver página de detalle"
404 + >
405 + <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
406 + <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
407 + </svg>
408 + </a>
409 + </span>
410 + {#if subpartidaDescs.length > 0}
411 + <p class="text-xs text-slate-400 mt-0.5">{subpartidaDescs[0].descripcion}</p>
412 + {/if}
413 + </div>
414 + </div>
415 + </div>
416 + {/each}
417 + </div>
418 + {/if}
419 + </div>
420 + {/each}
421 + </div>
422 + {/if}
423 + </section>
424 + {/each}
425 + </div>
426 + {/if}
427 + </div>
428 + </main>
429 +
430 + <!-- Sidebar derecha: En esta página -->
431 + <aside class="w-56 flex-shrink-0 hidden xl:block">
432 + <div class="sticky top-0 h-screen overflow-y-auto p-4 border-l">
433 + <p class="text-xs text-slate-500 uppercase tracking-wide mb-3">En esta página</p>
434 + {#if selectedGrupo && !isSearching}
435 + <nav class="space-y-2">
436 + {#each grupoContent.subgrupos as subgrupo}
437 + <div>
438 + <a
439 + href="#sg-{subgrupo.objeto}"
440 + class="block text-sm text-slate-600 hover:text-blue-600 truncate"
441 + title="{subgrupo.desc_objeto}"
442 + >
443 + {subgrupo.desc_objeto}
444 + </a>
445 + {#if subgrupo.partidas?.length > 0}
446 + <div class="ml-3 mt-1 space-y-1 border-l border-slate-100 pl-2">
447 + {#each subgrupo.partidas.slice(0, 5) as partida}
448 + <a
449 + href="#p-{partida.objeto}"
450 + class="block text-xs text-slate-400 hover:text-blue-600 truncate"
451 + title="{partida.desc_objeto}"
452 + >
453 + {partida.desc_objeto}
454 + </a>
455 + {/each}
456 + {#if subgrupo.partidas.length > 5}
457 + <span class="text-xs text-slate-300">+{subgrupo.partidas.length - 5} más</span>
458 + {/if}
459 + </div>
460 + {/if}
461 + </div>
462 + {/each}
463 + </nav>
464 + {/if}
465 + </div>
466 + </aside>
467 + </div>
468 + {/if}
469 +</div>
470 +
471 +<!-- Modal de detalle -->
472 +{#if selectedItem}
473 + <div class="fixed inset-0 bg-black/40 flex items-center justify-center p-4 z-50" onclick={closeDetail}>
474 + <div
475 + class="bg-white rounded-xl shadow-2xl max-w-2xl w-full max-h-[85vh] overflow-hidden flex flex-col"
476 + onclick={(e) => e.stopPropagation()}
477 + >
478 + <div class="px-6 py-4 border-b bg-slate-50 flex justify-between items-start">
479 + <div>
480 + <p class="text-xs text-slate-500 uppercase tracking-wide">{getNivelLabel(selectedItem.nivel)}</p>
481 + <h3 class="text-lg font-medium text-slate-900 mt-1">
482 + <span class="font-mono text-slate-400">{selectedItem.objeto}</span>
483 + <span class="mx-2">·</span>
484 + {selectedItem.desc_objeto}
485 + </h3>
486 + </div>
487 + <button
488 + onclick={closeDetail}
489 + class="text-slate-400 hover:text-slate-600 text-2xl leading-none"
490 + >
491 + &times;
492 + </button>
493 + </div>
494 +
495 + <div class="p-6 overflow-y-auto flex-1">
496 + <h4 class="text-sm font-medium text-slate-700 mb-4">
497 + {#if selectedItem.n_variaciones > 1}
498 + Descripciones ({selectedItem.n_variaciones} variaciones)
499 + {:else}
500 + Descripción
501 + {/if}
502 + </h4>
503 +
504 + <div class="space-y-4">
505 + {#each parseDescripciones(selectedItem.descripciones) as desc, i}
506 + <div class="border-l-2 {i === 0 ? 'border-blue-500 bg-blue-50/50' : 'border-slate-200'} pl-4 py-2 rounded-r">
507 + <p class="text-xs text-slate-500 mb-2">
508 + {#if i === 0 && selectedItem.n_variaciones > 1}
509 + <span class="text-blue-600 font-medium">Vigente</span>
510 + <span class="mx-1">·</span>
511 + {/if}
512 + {desc.rangos}
513 + </p>
514 + <p class="text-sm text-slate-700 leading-relaxed">{desc.descripcion}</p>
515 + </div>
516 + {/each}
517 + </div>
518 + </div>
519 + </div>
520 + </div>
521 +{/if}
1 +import { supabase } from '$lib/supabase';
2 +import { error } from '@sveltejs/kit';
3 +
4 +export async function load({ params }) {
5 + const codigo = parseInt(params.codigo);
6 +
7 + if (isNaN(codigo)) {
8 + throw error(400, 'Código de entidad inválido');
9 + }
10 +
11 + const { data, error: dbError } = await supabase
12 + .schema('ppto')
13 + .from('clas_institucional')
14 + .select('*')
15 + .eq('entidad', codigo)
16 + .single();
17 +
18 + if (dbError || !data) {
19 + throw error(404, 'Entidad no encontrada');
20 + }
21 +
22 + return {
23 + entidad: data
24 + };
25 +}
1 +<script>
2 + let { data } = $props();
3 +
4 + const entidad = data.entidad;
5 + const gestiones = entidad.gestiones ? entidad.gestiones.split(',').map(g => g.trim()) : [];
6 +</script>
7 +
8 +<svelte:head>
9 + <title>{entidad.desc_entidad} | Presupuesto Público</title>
10 +</svelte:head>
11 +
12 +<div class="max-w-4xl mx-auto p-4">
13 + <p class="text-sm text-gray-500 mb-4">
14 + <a href="/">Inicio</a> / <a href="/clasificadores/institucional">Institucional</a> / {entidad.sigla_entidad || 'Entidad'}
15 + </p>
16 +
17 + <h1 class="text-2xl mb-1">{entidad.desc_entidad}</h1>
18 + {#if entidad.sigla_entidad}
19 + <p class="text-gray-600 mb-4">{entidad.sigla_entidad}</p>
20 + {/if}
21 +
22 + <p class="text-sm text-gray-500 mb-6">
23 + Código: {entidad.entidad} · {entidad.n_gestiones} años de datos
24 + </p>
25 +
26 + <div class="grid md:grid-cols-2 gap-4">
27 + <div class="border rounded p-4">
28 + <h2 class="font-bold mb-2">Clasificación</h2>
29 + <p class="text-sm"><span class="text-gray-500">Sector:</span> {entidad.desc_sector}</p>
30 + <p class="text-sm"><span class="text-gray-500">Subsector:</span> {entidad.desc_subsector}</p>
31 + <p class="text-sm"><span class="text-gray-500">Área:</span> {entidad.desc_area}</p>
32 + {#if entidad.desc_subarea !== entidad.desc_area}
33 + <p class="text-sm"><span class="text-gray-500">Subárea:</span> {entidad.desc_subarea}</p>
34 + {/if}
35 + </div>
36 +
37 + <div class="border rounded p-4">
38 + <h2 class="font-bold mb-2">Gestiones</h2>
39 + <div class="flex flex-wrap gap-1">
40 + {#each gestiones as gestion}
41 + <span class="text-xs bg-gray-100 px-2 py-1 rounded">{gestion}</span>
42 + {/each}
43 + </div>
44 + </div>
45 + </div>
46 +
47 + <div class="border rounded p-4 mt-4">
48 + <h2 class="font-bold mb-2">Historial de Ingresos y Gastos</h2>
49 + <p class="text-gray-500 text-sm">Visualizaciones próximamente</p>
50 + </div>
51 +</div>
1 +import { supabase } from '$lib/supabase';
2 +import { error } from '@sveltejs/kit';
3 +
4 +export async function load({ params }) {
5 + const { codigo } = params;
6 +
7 + const { data, error: dbError } = await supabase
8 + .schema('ppto')
9 + .from('clas_objetos')
10 + .select('*')
11 + .eq('objeto', codigo);
12 +
13 + if (dbError || !data || data.length === 0) {
14 + throw error(404, 'Objeto no encontrado');
15 + }
16 +
17 + // Tomar el primer resultado (puede haber duplicados)
18 + const objeto = data[0];
19 +
20 + // Obtener jerarquía (padres e hijos)
21 + let padres = [];
22 + let hijos = [];
23 +
24 + // Buscar padre según nivel
25 + if (objeto.nivel === 'subpartida') {
26 + // Padre es partida
27 + const { data: padreData } = await supabase
28 + .schema('ppto')
29 + .from('clas_objetos')
30 + .select('*')
31 + .eq('nivel', 'partida')
32 + .eq('grupo', objeto.grupo)
33 + .eq('subgrupo', objeto.subgrupo)
34 + .eq('partida', objeto.partida);
35 + if (padreData?.length) padres.push(padreData[0]);
36 + }
37 +
38 + if (objeto.nivel === 'partida' || objeto.nivel === 'subpartida') {
39 + // Padre es subgrupo
40 + const { data: padreData } = await supabase
41 + .schema('ppto')
42 + .from('clas_objetos')
43 + .select('*')
44 + .eq('nivel', 'subgrupo')
45 + .eq('grupo', objeto.grupo)
46 + .eq('subgrupo', objeto.subgrupo);
47 + if (padreData?.length) padres.unshift(padreData[0]);
48 + }
49 +
50 + if (objeto.nivel !== 'grupo') {
51 + // Padre es grupo
52 + const grupoCodigo = objeto.grupo + '0000';
53 + const { data: padreData } = await supabase
54 + .schema('ppto')
55 + .from('clas_objetos')
56 + .select('*')
57 + .eq('nivel', 'grupo')
58 + .eq('objeto', grupoCodigo);
59 + if (padreData?.length) padres.unshift(padreData[0]);
60 + }
61 +
62 + // Buscar hijos según nivel
63 + if (objeto.nivel === 'grupo') {
64 + const { data: hijosData } = await supabase
65 + .schema('ppto')
66 + .from('clas_objetos')
67 + .select('*')
68 + .eq('nivel', 'subgrupo')
69 + .eq('grupo', objeto.grupo)
70 + .order('objeto');
71 + hijos = hijosData?.reduce((acc, item) => {
72 + if (!acc.find(h => h.objeto === item.objeto)) acc.push(item);
73 + return acc;
74 + }, []) || [];
75 + } else if (objeto.nivel === 'subgrupo') {
76 + const { data: hijosData } = await supabase
77 + .schema('ppto')
78 + .from('clas_objetos')
79 + .select('*')
80 + .eq('nivel', 'partida')
81 + .eq('grupo', objeto.grupo)
82 + .eq('subgrupo', objeto.subgrupo)
83 + .order('objeto');
84 + hijos = hijosData?.reduce((acc, item) => {
85 + if (!acc.find(h => h.objeto === item.objeto)) acc.push(item);
86 + return acc;
87 + }, []) || [];
88 + } else if (objeto.nivel === 'partida') {
89 + const { data: hijosData } = await supabase
90 + .schema('ppto')
91 + .from('clas_objetos')
92 + .select('*')
93 + .eq('nivel', 'subpartida')
94 + .eq('grupo', objeto.grupo)
95 + .eq('subgrupo', objeto.subgrupo)
96 + .eq('partida', objeto.partida)
97 + .order('objeto');
98 + hijos = hijosData?.reduce((acc, item) => {
99 + if (!acc.find(h => h.objeto === item.objeto)) acc.push(item);
100 + return acc;
101 + }, []) || [];
102 + }
103 +
104 + return {
105 + objeto,
106 + padres,
107 + hijos
108 + };
109 +}
1 +<script>
2 + let { data } = $props();
3 +
4 + const objeto = data.objeto;
5 + const padres = data.padres;
6 + const hijos = data.hijos;
7 +
8 + function parseDescripciones(descripcionesStr) {
9 + if (!descripcionesStr) return [];
10 + try {
11 + const parsed = JSON.parse(descripcionesStr);
12 + // Ordenar por año más reciente (extraer el máximo año de cada rango)
13 + return parsed.sort((a, b) => {
14 + const maxYearA = getMaxYear(a.rangos);
15 + const maxYearB = getMaxYear(b.rangos);
16 + return maxYearB - maxYearA; // Descendente, más reciente primero
17 + });
18 + } catch {
19 + return [];
20 + }
21 + }
22 +
23 + function getMaxYear(rangos) {
24 + if (!rangos) return 0;
25 + const years = rangos.match(/\d{4}/g);
26 + if (!years) return 0;
27 + return Math.max(...years.map(y => parseInt(y)));
28 + }
29 +
30 + function getNivelLabel(nivel) {
31 + const labels = { grupo: 'Grupo', subgrupo: 'Subgrupo', partida: 'Partida', subpartida: 'Subpartida' };
32 + return labels[nivel] || nivel;
33 + }
34 +
35 + const descripciones = parseDescripciones(objeto.descripciones);
36 +</script>
37 +
38 +<svelte:head>
39 + <title>{objeto.desc_objeto} | Presupuesto Público</title>
40 +</svelte:head>
41 +
42 +<div class="min-h-screen bg-white">
43 + <header class="border-b bg-slate-50">
44 + <div class="max-w-4xl mx-auto px-6 py-4">
45 + <nav class="text-sm text-slate-500 mb-2 flex flex-wrap items-center gap-1">
46 + <a href="/" class="hover:text-slate-700">Inicio</a>
47 + <span>/</span>
48 + <a href="/clasificadores/objeto-gasto" class="hover:text-slate-700">Objeto del Gasto</a>
49 + {#each padres as padre}
50 + <span>/</span>
51 + <a href="/objeto/{padre.objeto}" class="hover:text-slate-700">{padre.desc_objeto}</a>
52 + {/each}
53 + <span>/</span>
54 + <span class="text-slate-900">{objeto.desc_objeto}</span>
55 + </nav>
56 + </div>
57 + </header>
58 +
59 + <main class="max-w-4xl mx-auto px-6 py-8">
60 + <!-- Encabezado -->
61 + <div class="mb-8">
62 + <p class="text-xs text-slate-500 uppercase tracking-wide mb-1">{getNivelLabel(objeto.nivel)}</p>
63 + <div class="flex items-baseline gap-4">
64 + <span class="font-mono text-2xl text-slate-400">{objeto.objeto}</span>
65 + <h1 class="text-2xl font-medium text-slate-900">{objeto.desc_objeto}</h1>
66 + </div>
67 + </div>
68 +
69 + <!-- Descripciones -->
70 + <section class="mb-10">
71 + <h2 class="text-sm font-medium text-slate-700 mb-4">
72 + {#if descripciones.length > 1}
73 + Descripciones ({descripciones.length} variaciones)
74 + {:else}
75 + Descripción
76 + {/if}
77 + </h2>
78 +
79 + <div class="space-y-4">
80 + {#each descripciones as desc, i}
81 + <div class="border-l-2 {i === 0 ? 'border-blue-500 bg-blue-50/50' : 'border-slate-200 bg-slate-50/50'} pl-4 py-3 rounded-r">
82 + <p class="text-xs text-slate-500 mb-2">
83 + {#if i === 0 && descripciones.length > 1}
84 + <span class="text-blue-600 font-medium">Vigente</span>
85 + <span class="mx-1">·</span>
86 + {/if}
87 + {desc.rangos}
88 + </p>
89 + <p class="text-slate-700 leading-relaxed">{desc.descripcion}</p>
90 + </div>
91 + {/each}
92 + </div>
93 + </section>
94 +
95 + <!-- Jerarquía -->
96 + {#if padres.length > 0}
97 + <section class="mb-10">
98 + <h2 class="text-sm font-medium text-slate-700 mb-4">Jerarquía</h2>
99 + <div class="space-y-2">
100 + {#each padres as padre, i}
101 + <div class="flex items-center gap-2" style="margin-left: {i * 1.5}rem">
102 + <span class="text-slate-300">└</span>
103 + <a
104 + href="/objeto/{padre.objeto}"
105 + class="text-sm text-slate-600 hover:text-blue-600"
106 + >
107 + <span class="font-mono text-xs text-slate-400">{padre.objeto}</span>
108 + {padre.desc_objeto}
109 + </a>
110 + </div>
111 + {/each}
112 + <div class="flex items-center gap-2" style="margin-left: {padres.length * 1.5}rem">
113 + <span class="text-blue-500">└</span>
114 + <span class="text-sm font-medium text-blue-600">
115 + <span class="font-mono text-xs">{objeto.objeto}</span>
116 + {objeto.desc_objeto}
117 + </span>
118 + </div>
119 + </div>
120 + </section>
121 + {/if}
122 +
123 + <!-- Hijos -->
124 + {#if hijos.length > 0}
125 + <section class="mb-10">
126 + <h2 class="text-sm font-medium text-slate-700 mb-4">
127 + {#if objeto.nivel === 'grupo'}
128 + Subgrupos ({hijos.length})
129 + {:else if objeto.nivel === 'subgrupo'}
130 + Partidas ({hijos.length})
131 + {:else if objeto.nivel === 'partida'}
132 + Subpartidas ({hijos.length})
133 + {/if}
134 + </h2>
135 +
136 + <div class="border rounded-lg divide-y">
137 + {#each hijos as hijo}
138 + {@const hijoDescs = parseDescripciones(hijo.descripciones)}
139 + <a
140 + href="/objeto/{hijo.objeto}"
141 + class="block px-4 py-3 hover:bg-slate-50 transition-colors"
142 + >
143 + <div class="flex items-baseline gap-3">
144 + <span class="font-mono text-sm text-slate-400">{hijo.objeto}</span>
145 + <span class="text-slate-900">{hijo.desc_objeto}</span>
146 + {#if hijo.n_variaciones > 1}
147 + <span class="text-xs text-orange-500">({hijo.n_variaciones} var.)</span>
148 + {/if}
149 + </div>
150 + {#if hijoDescs.length > 0}
151 + <p class="text-sm text-slate-500 mt-1 ml-16">{hijoDescs[0].descripcion}</p>
152 + {/if}
153 + </a>
154 + {/each}
155 + </div>
156 + </section>
157 + {/if}
158 +
159 + <!-- Volver -->
160 + <div class="pt-6 border-t">
161 + <a
162 + href="/clasificadores/objeto-gasto"
163 + class="text-sm text-blue-600 hover:underline"
164 + >
165 + Volver al clasificador
166 + </a>
167 + </div>
168 + </main>
169 +</div>
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
No preview for this file type
1 +import adapter from '@sveltejs/adapter-auto';
2 +
3 +/** @type {import('@sveltejs/kit').Config} */
4 +const config = {
5 + kit: {
6 + // adapter-auto only supports some environments, see https://svelte.dev/docs/kit/adapter-auto for a list.
7 + // If your environment is not supported, or you settled on a specific environment, switch out the adapter.
8 + // See https://svelte.dev/docs/kit/adapters for more information about adapters.
9 + adapter: adapter()
10 + }
11 +};
12 +
13 +export default config;
1 +import { sveltekit } from '@sveltejs/kit/vite';
2 +import tailwindcss from '@tailwindcss/vite';
3 +import { defineConfig } from 'vite';
4 +
5 +export default defineConfig({
6 + plugins: [tailwindcss(), sveltekit()]
7 +});